@sideboard-ai/core 0.1.315 → 0.1.317

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-QQZWYJXC.js → abletime-NZ2ABWAL.js} +3 -3
  2. package/dist/{abletime-QK3KMRQD.js → abletime-TKAFNXCM.js} +3 -3
  3. package/dist/{abletime-oauth-CAHTMB4V.js → abletime-oauth-CBFFBINA.js} +2 -2
  4. package/dist/{abletime-oauth-I2RRPVKT.js → abletime-oauth-S4AXA4WR.js} +2 -2
  5. package/dist/{abletime-rest-5V4KGMSY.js → abletime-rest-NSOP72AI.js} +2 -2
  6. package/dist/{abletime-rest-W5TLQK7C.js → abletime-rest-ORBELZQO.js} +2 -2
  7. package/dist/{agents-Y3M3EKLY.js → agents-BJVSYC6Y.js} +4 -4
  8. package/dist/{agents-5XJ7EHGU.js → agents-KABJUDPI.js} +4 -4
  9. package/dist/{chunk-IODJCVMN.js → chunk-4XZJYBO2.js} +6 -34
  10. package/dist/{chunk-JRZTJ4F7.js → chunk-7SCVGGF6.js} +4 -4
  11. package/dist/{chunk-5CTG5W7S.js → chunk-A46CIARU.js} +1 -1
  12. package/dist/{chunk-PN32Z4JL.js → chunk-A6C67DY5.js} +2 -2
  13. package/dist/{chunk-CYPFOIUK.js → chunk-BXTISNKW.js} +16 -16
  14. package/dist/{chunk-7J2KOIYD.js → chunk-CCUGIVYN.js} +2 -2
  15. package/dist/{chunk-DV6ID6CK.js → chunk-ELBK34TY.js} +4 -4
  16. package/dist/{chunk-FVTR54LY.js → chunk-GH7UMULC.js} +4 -4
  17. package/dist/{chunk-MKGSMPWB.js → chunk-GXSV3X3L.js} +2 -2
  18. package/dist/{chunk-U35AHE2P.js → chunk-HOLB6ZFZ.js} +33 -2
  19. package/dist/{chunk-72OWKHFJ.js → chunk-I5CLCWUK.js} +2 -2
  20. package/dist/{chunk-YR7NZYUT.js → chunk-NRSC4N5X.js} +6 -34
  21. package/dist/{chunk-GFM63DTU.js → chunk-PX324N7P.js} +2 -2
  22. package/dist/{chunk-BMORGDYI.js → chunk-U53JICJ2.js} +18 -17
  23. package/dist/{chunk-NZVD5EVX.js → chunk-VVV7EI6T.js} +2 -1
  24. package/dist/{chunk-Y4WARKPW.js → chunk-VZAJVX36.js} +2 -1
  25. package/dist/{chunk-NKVNHBDB.js → chunk-XWUDFLBX.js} +3 -3
  26. package/dist/{chunk-CHUPIJP7.js → chunk-YEIHCSZS.js} +63 -2
  27. package/dist/{chunk-BPBDGJ43.js → chunk-YN6XONV5.js} +1 -1
  28. package/dist/{conductor-IMKNYQWZ.js → conductor-NIUBJLTS.js} +4 -4
  29. package/dist/{conductor-DKWTQADV.js → conductor-TP2NA44I.js} +4 -4
  30. package/dist/{coordinator-prompt-HUZC4DZ2.js → coordinator-prompt-3CT3D5UM.js} +3 -3
  31. package/dist/{coordinator-prompt-SPOYUZG5.js → coordinator-prompt-FQC2SZPP.js} +3 -3
  32. package/dist/{global-workspace-3NNDDTFD.js → global-workspace-72K6D354.js} +3 -3
  33. package/dist/{global-workspace-SK4JQBPN.js → global-workspace-BUWMRNW5.js} +3 -3
  34. package/dist/index.cjs +360 -42
  35. package/dist/index.d.cts +11 -5
  36. package/dist/index.d.ts +11 -5
  37. package/dist/index.js +301 -21
  38. package/dist/mcp/run-stdio.cjs +38 -34
  39. package/dist/mcp/run-stdio.js +9 -9
  40. package/dist/{orchestrator-4XFRK57E.js → orchestrator-E72HYGTB.js} +6 -6
  41. package/dist/{orchestrator-ZRMZ4TCL.js → orchestrator-N54V3B76.js} +6 -6
  42. package/dist/{thread-store-5OF6M6VZ.js → thread-store-7BBA63KV.js} +1 -1
  43. package/dist/{thread-store-GOVVXQV2.js → thread-store-PLNIWFZ4.js} +1 -1
  44. package/dist/{workspaces-EYNZDL45.js → workspaces-2V5UYPYC.js} +3 -3
  45. package/dist/{workspaces-52L6NZ3P.js → workspaces-GAUHXBUL.js} +3 -3
  46. package/dist/{worktree-BP5ICYQ2.js → worktree-6FUQ7FEF.js} +2 -2
  47. package/dist/{worktree-UCOSAI7J.js → worktree-XJKLDYOL.js} +2 -2
  48. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -118,6 +118,7 @@ import {
118
118
  isStaleLastErrorDuringTurn,
119
119
  isThisProcessDesktopHost,
120
120
  isUnclaimedRunScriptRequest,
121
+ issueBlockedByIds,
121
122
  issueMatchesUpdatedSince,
122
123
  issueNeedsWorkspacePick,
123
124
  issueTicketFromThread,
@@ -202,7 +203,7 @@ import {
202
203
  worktreeCleanupSettings,
203
204
  writeAgentBlock,
204
205
  writeWorktreeFile
205
- } from "./chunk-BMORGDYI.js";
206
+ } from "./chunk-U53JICJ2.js";
206
207
  import {
207
208
  LEGACY_PLAN_FILE_REL,
208
209
  PLAN_FILE_NAME,
@@ -292,7 +293,7 @@ import {
292
293
  userMcpNamesToDisable,
293
294
  worktreeMcpToolNames,
294
295
  writeInjectedMcpConfig
295
- } from "./chunk-NKVNHBDB.js";
296
+ } from "./chunk-XWUDFLBX.js";
296
297
  import {
297
298
  brightsyMcpServerName,
298
299
  connectBrightsyTeam,
@@ -423,7 +424,7 @@ import {
423
424
  workspaceAgentChatSummaries,
424
425
  worktreeRunPortsPath,
425
426
  wrapReviewSkillMarkdown
426
- } from "./chunk-IODJCVMN.js";
427
+ } from "./chunk-4XZJYBO2.js";
427
428
  import {
428
429
  STDERR_EVENT_MAX_CHARS,
429
430
  STDOUT_EVENT_MAX_CHARS,
@@ -489,7 +490,7 @@ import {
489
490
  parseAbleTimeOAuthCallbackUrl,
490
491
  resolveAbleTimeOAuthHost,
491
492
  startAbleTimeOAuth
492
- } from "./chunk-7J2KOIYD.js";
493
+ } from "./chunk-CCUGIVYN.js";
493
494
  import {
494
495
  ableTimeDependencyTarget,
495
496
  commentAbleTimeTask,
@@ -514,8 +515,10 @@ import {
514
515
  toAbleTimeIssueInfo,
515
516
  updateAbleTimeTask,
516
517
  verifyAbleTimeConnection
517
- } from "./chunk-MKGSMPWB.js";
518
- import "./chunk-NZVD5EVX.js";
518
+ } from "./chunk-GXSV3X3L.js";
519
+ import {
520
+ looksLikeAbleTimeUlid
521
+ } from "./chunk-VVV7EI6T.js";
519
522
  import {
520
523
  ABLETIME_MCP_PATH,
521
524
  ABLETIME_MCP_PM_PATH,
@@ -536,7 +539,7 @@ import {
536
539
  normalizeAbleTimeCredential,
537
540
  normalizeAbleTimeHost,
538
541
  rewriteAbleTimeError
539
- } from "./chunk-DV6ID6CK.js";
542
+ } from "./chunk-ELBK34TY.js";
540
543
  import {
541
544
  clearOptionalCliPresenceCache,
542
545
  detectOptionalServiceClis,
@@ -623,7 +626,7 @@ import {
623
626
  stageBuffersAsAttachments,
624
627
  syncWorkspacesFromThreads,
625
628
  takenTeamSlugsForOrchestration
626
- } from "./chunk-GFM63DTU.js";
629
+ } from "./chunk-PX324N7P.js";
627
630
  import {
628
631
  GITHUB_PR_BODY_MAX_CHARS,
629
632
  GITHUB_PR_BODY_SAFE_CHARS,
@@ -711,7 +714,7 @@ import {
711
714
  suggestSlug,
712
715
  switchWorktreeBranch,
713
716
  warmGithubAgentAuth
714
- } from "./chunk-BPBDGJ43.js";
717
+ } from "./chunk-YN6XONV5.js";
715
718
  import {
716
719
  FAMOUS_SOCCER_TEAMS,
717
720
  allocateTeamName,
@@ -739,12 +742,13 @@ import {
739
742
  withThreadLock,
740
743
  workspaceNameLabel,
741
744
  workspaceTagsFromGroup,
745
+ worktreeAnchorLabel,
742
746
  worktreeDisplayLabel,
743
747
  worktreeDisplayLabelForGroup,
744
748
  worktreeNameFromPath,
745
749
  worktreeSlugForTicket,
746
750
  writeThread
747
- } from "./chunk-CHUPIJP7.js";
751
+ } from "./chunk-YEIHCSZS.js";
748
752
  import "./chunk-2P4XKWV2.js";
749
753
  import {
750
754
  BRIGHTSY_OAUTH_CLIENT_ID,
@@ -2702,15 +2706,13 @@ function listPhoneSidebar(viewerLogin = phoneViewerLogin()) {
2702
2706
  path: path2,
2703
2707
  worktrees: groupHomeBoardWorktrees(repoThreads).map((group) => {
2704
2708
  const tags = workspaceTagsFromGroup(group);
2705
- const badge = classifyWorktreeListBadges(
2706
- group,
2707
- viewerLogin,
2708
- resolveProjectReviewLabel(settings, path2)
2709
- )[0];
2709
+ const badge = classifyWorktreeListBadges(group, viewerLogin, resolveProjectReviewLabel(settings, path2))[0];
2710
+ const blockedBy = issueBlockedByIds(group);
2710
2711
  return {
2711
- label: worktreeDisplayLabelForGroup(group),
2712
+ label: worktreeAnchorLabel(group).title,
2712
2713
  chats: group.map(summarize),
2713
2714
  ...tags.length > 0 ? { tags } : {},
2715
+ ...blockedBy.length > 0 ? { blockedBy } : {},
2714
2716
  ...badge ? { badge: { id: badge.id, label: badge.label, title: badge.title, ...badge.conflict ? { conflict: true } : {} } } : {}
2715
2717
  };
2716
2718
  })
@@ -2787,7 +2789,7 @@ function projectPlace(thread) {
2787
2789
  return {
2788
2790
  kind: "project",
2789
2791
  repoPath: thread.repoPath,
2790
- worktree: worktreeDisplayLabelForGroup(group.length > 0 ? group : [thread])
2792
+ worktree: worktreeAnchorLabel(group.length > 0 ? group : [thread]).title
2791
2793
  };
2792
2794
  }
2793
2795
  function assertKnownProject(repoPath) {
@@ -6076,7 +6078,7 @@ function phoneBoardKey(sidebar) {
6076
6078
  const orchestration = sidebar.orchestration.map(chatKey).join("\n");
6077
6079
  const projects = sidebar.projects.map((project) => {
6078
6080
  const trees = project.worktrees.map(
6079
- (tree) => `${tree.label} ${tree.badge?.id ?? ""} ${(tree.tags ?? []).join(",")} ${tree.chats.map(chatKey).join("\n")}`
6081
+ (tree) => `${tree.label} ${tree.badge?.id ?? ""} ${(tree.tags ?? []).join(",")} ${(tree.blockedBy ?? []).join(",")} ${tree.chats.map(chatKey).join("\n")}`
6080
6082
  ).join("\n");
6081
6083
  return `${project.path} ${project.name}
6082
6084
  ${trees}`;
@@ -8729,7 +8731,7 @@ async function startHeadlessHost(opts) {
8729
8731
  };
8730
8732
  const refreshRunning = async () => {
8731
8733
  try {
8732
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-4XFRK57E.js");
8734
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-E72HYGTB.js");
8733
8735
  agentsRunning = getOrchestrator2().getRuntime().running;
8734
8736
  } catch {
8735
8737
  agentsRunning = 0;
@@ -10662,7 +10664,7 @@ async function handleJobStop(params, _ctx) {
10662
10664
  return stopDetachedJob(jobCwd(rec), id, reason ? { reason } : void 0);
10663
10665
  }
10664
10666
  async function defaultTurnWait(ref, timeoutMs) {
10665
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-4XFRK57E.js");
10667
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-E72HYGTB.js");
10666
10668
  const orch = getOrchestrator2();
10667
10669
  const thread = await orch.waitForTurn(ref, timeoutMs, {
10668
10670
  resolveIfStillRunning: true
@@ -12424,6 +12426,283 @@ function getAgentRpcServer() {
12424
12426
  return running;
12425
12427
  }
12426
12428
 
12429
+ // src/integrations/abletime-blocked.ts
12430
+ function asRecord4(value) {
12431
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
12432
+ }
12433
+ function asString(value) {
12434
+ return typeof value === "string" ? value.trim() : "";
12435
+ }
12436
+ function firstString(record, keys) {
12437
+ if (!record) return "";
12438
+ for (const key of keys) {
12439
+ const value = asString(record[key]);
12440
+ if (value) return value;
12441
+ }
12442
+ return "";
12443
+ }
12444
+ function firstRecord(record, keys) {
12445
+ if (!record) return null;
12446
+ for (const key of keys) {
12447
+ const value = asRecord4(record[key]);
12448
+ if (value) return value;
12449
+ }
12450
+ return null;
12451
+ }
12452
+ function identifierFromUnknown(value) {
12453
+ if (typeof value === "string" || typeof value === "number") {
12454
+ const id2 = String(value).trim();
12455
+ return id2 ? [id2] : [];
12456
+ }
12457
+ if (Array.isArray(value)) return value.flatMap(identifierFromUnknown);
12458
+ const rec = asRecord4(value);
12459
+ if (!rec) return [];
12460
+ for (const key of ["nodes", "data", "tasks", "items"]) {
12461
+ if (Array.isArray(rec[key])) return identifierFromUnknown(rec[key]);
12462
+ }
12463
+ const id = firstString(rec, ["identifier", "reference", "ref", "key", "code", "number", "id"]);
12464
+ return id ? [id] : [];
12465
+ }
12466
+ function ableTimeBlockedByIdentifiers(raw) {
12467
+ const record = asRecord4(raw);
12468
+ const nested = firstRecord(record, ["task", "data"]) ?? record;
12469
+ if (!nested) return [];
12470
+ const value = nested.blocked_by ?? nested.blockedBy ?? nested.depends_on ?? nested.dependsOn ?? nested.dependencyParentTimeflowTaskId ?? nested.wait_on ?? nested.waitOn;
12471
+ const out = [];
12472
+ const seen = /* @__PURE__ */ new Set();
12473
+ for (const id of identifierFromUnknown(value)) {
12474
+ const key = id.toLowerCase();
12475
+ if (seen.has(key)) continue;
12476
+ seen.add(key);
12477
+ out.push(id);
12478
+ }
12479
+ return out;
12480
+ }
12481
+ function taskReference(raw) {
12482
+ const record = asRecord4(raw);
12483
+ const nested = firstRecord(record, ["task", "data"]) ?? record;
12484
+ return firstString(nested, ["taskRef", "reference", "identifier"]);
12485
+ }
12486
+ async function getAbleTimeIssueBlockedBy(id, opts) {
12487
+ const taskId = id.trim();
12488
+ if (!taskId) throw new Error("AbleTime task id is required");
12489
+ const raw = await callAbleTimeTool("get_task", { id: taskId, task_id: taskId }, opts);
12490
+ const out = [];
12491
+ for (const blockerId of ableTimeBlockedByIdentifiers(raw)) {
12492
+ if (!looksLikeAbleTimeUlid(blockerId)) {
12493
+ out.push(blockerId);
12494
+ continue;
12495
+ }
12496
+ const parent = await callAbleTimeTool("get_task", { id: blockerId, task_id: blockerId }, opts);
12497
+ const ref = taskReference(parent);
12498
+ if (!ref || looksLikeAbleTimeUlid(ref)) {
12499
+ throw new Error(`AbleTime blocker has no reference: ${blockerId}`);
12500
+ }
12501
+ out.push(ref);
12502
+ }
12503
+ return out;
12504
+ }
12505
+
12506
+ // src/integrations/github-blocked.ts
12507
+ function githubBlockedByIdentifiers(payload) {
12508
+ const root = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : null;
12509
+ const data = root?.data && typeof root.data === "object" && !Array.isArray(root.data) ? root.data : root;
12510
+ const repository = data?.repository && typeof data.repository === "object" ? data.repository : null;
12511
+ const issue = repository?.issue && typeof repository.issue === "object" ? repository.issue : null;
12512
+ const blocked = issue?.blockedBy && typeof issue.blockedBy === "object" ? issue.blockedBy : null;
12513
+ const nodes = Array.isArray(blocked?.nodes) ? blocked.nodes : Array.isArray(root?.blockedBy) ? root.blockedBy : [];
12514
+ const out = [];
12515
+ const seen = /* @__PURE__ */ new Set();
12516
+ for (const node of nodes) {
12517
+ const rec = node && typeof node === "object" && !Array.isArray(node) ? node : null;
12518
+ const number = Number(rec?.number ?? node);
12519
+ if (!Number.isFinite(number) || number <= 0) continue;
12520
+ const id = `#${number}`;
12521
+ const key = id.toLowerCase();
12522
+ if (seen.has(key)) continue;
12523
+ seen.add(key);
12524
+ out.push(id);
12525
+ }
12526
+ return out;
12527
+ }
12528
+ var GITHUB_BLOCKED_BY_QUERY = `
12529
+ query($owner: String!, $name: String!, $number: Int!) {
12530
+ repository(owner: $owner, name: $name) {
12531
+ issue(number: $number) {
12532
+ blockedBy(first: 25) { nodes { number } }
12533
+ }
12534
+ }
12535
+ }
12536
+ `;
12537
+ async function getGitHubIssueBlockedBy(id, opts) {
12538
+ const number = parseGitHubIssueNumber(id);
12539
+ const { cwd, slug } = await resolveGitHubIssueRepo(opts?.repoPath);
12540
+ const [owner, name] = (slug ?? "").split("/");
12541
+ if (!owner || !name) throw new Error("GitHub repo is not connected");
12542
+ const result = await gh(
12543
+ [
12544
+ "api",
12545
+ "graphql",
12546
+ "-f",
12547
+ `query=${GITHUB_BLOCKED_BY_QUERY}`,
12548
+ "-f",
12549
+ `owner=${owner}`,
12550
+ "-f",
12551
+ `name=${name}`,
12552
+ "-F",
12553
+ `number=${number}`
12554
+ ],
12555
+ cwd,
12556
+ { reject: false }
12557
+ );
12558
+ if (result.exitCode !== 0) {
12559
+ const detail = (result.stderr || result.stdout).trim() || "gh failed";
12560
+ throw new Error(`GitHub issue #${number} blocked-by: ${detail}`);
12561
+ }
12562
+ let parsed;
12563
+ try {
12564
+ parsed = JSON.parse(result.stdout);
12565
+ } catch {
12566
+ throw new Error(`GitHub issue #${number} blocked-by: gh returned non-JSON`);
12567
+ }
12568
+ const errors = parsed && typeof parsed === "object" && Array.isArray(parsed.errors) ? parsed.errors : [];
12569
+ if (errors.length > 0) {
12570
+ throw new Error(
12571
+ `GitHub issue #${number} blocked-by: ${errors.map((e) => e.message ?? "GitHub error").join("; ")}`
12572
+ );
12573
+ }
12574
+ const issue = parsed.data?.repository?.issue;
12575
+ if (!issue) throw new Error(`GitHub issue not found: #${number}`);
12576
+ return githubBlockedByIdentifiers(parsed);
12577
+ }
12578
+
12579
+ // src/integrations/linear-blocked.ts
12580
+ var ISSUE_BLOCKED_BY_QUERY = `
12581
+ query SideboardIssueBlockedBy($id: String!) {
12582
+ issue(id: $id) {
12583
+ identifier
12584
+ relations(first: 25) {
12585
+ nodes { id type relatedIssue { id identifier } }
12586
+ }
12587
+ inverseRelations(first: 25) {
12588
+ nodes { id type issue { id identifier } }
12589
+ }
12590
+ }
12591
+ }
12592
+ `;
12593
+ function linearBlockedByIdentifiers(relations) {
12594
+ const out = [];
12595
+ const seen = /* @__PURE__ */ new Set();
12596
+ for (const rel of relations) {
12597
+ const type = (rel.type ?? "").trim().toLowerCase().replace(/[\s_-]+/g, "");
12598
+ if (type !== "blockedby" && type !== "blocked") continue;
12599
+ const id = (rel.issue?.identifier || rel.issue?.id || "").trim();
12600
+ const key = id.toLowerCase();
12601
+ if (!id || seen.has(key)) continue;
12602
+ seen.add(key);
12603
+ out.push(id);
12604
+ }
12605
+ return out;
12606
+ }
12607
+ function linearBlockedByRelations(issue) {
12608
+ const out = [];
12609
+ for (const rel of issue.relations?.nodes ?? []) {
12610
+ out.push({ type: String(rel.type ?? "related"), issue: rel.relatedIssue });
12611
+ }
12612
+ for (const rel of issue.inverseRelations?.nodes ?? []) {
12613
+ out.push({
12614
+ type: flipLinearRelationType(String(rel.type ?? "related")),
12615
+ issue: rel.issue
12616
+ });
12617
+ }
12618
+ return out;
12619
+ }
12620
+ async function getLinearIssueBlockedBy(id, opts) {
12621
+ const issueId = id.trim();
12622
+ if (!issueId) throw new Error("Linear issue id is required (uuid or ENG-123)");
12623
+ const json = await linearGraphql(
12624
+ ISSUE_BLOCKED_BY_QUERY,
12625
+ { id: issueId },
12626
+ opts
12627
+ );
12628
+ if (!json.issue) throw new Error(`Linear issue not found: ${issueId}`);
12629
+ return linearBlockedByIdentifiers(linearBlockedByRelations(json.issue));
12630
+ }
12631
+
12632
+ // src/board/issue-blocked-sync.ts
12633
+ function sourceTicketRef(thread) {
12634
+ if (thread.sourceType !== "ticket") return null;
12635
+ const ref = (thread.sourceRef ?? "").trim();
12636
+ return ref || null;
12637
+ }
12638
+ function sameIssueBlockedBy(current, next) {
12639
+ const left = new Set(
12640
+ (current ?? []).map((id) => id.trim().toLowerCase()).filter(Boolean)
12641
+ );
12642
+ const right = [...new Set(next.map((id) => id.trim().toLowerCase()).filter(Boolean))];
12643
+ if (left.size !== right.length) return false;
12644
+ return right.every((id) => left.has(id));
12645
+ }
12646
+ var TRACKER_KEY = /^[A-Za-z][A-Za-z0-9]+-\d+$/;
12647
+ function isGitHubIssueRef(ref) {
12648
+ return /^#?\d+$/.test(ref) || /^gh-\d+$/i.test(ref) || /github\.com\/[^/]+\/[^/]+\/issues\/\d+/i.test(ref);
12649
+ }
12650
+ function trackerForSourceTicket(ref, preferred, connected) {
12651
+ const trimmed = ref.trim();
12652
+ if (!trimmed) return null;
12653
+ if (isGitHubIssueRef(trimmed)) return "github";
12654
+ if (TRACKER_KEY.test(trimmed)) {
12655
+ if (preferred === "abletime" && connected.abletime) return "abletime";
12656
+ if (connected.linear) return "linear";
12657
+ if (connected.abletime) return "abletime";
12658
+ return null;
12659
+ }
12660
+ if (preferred === "linear" && connected.linear) return "linear";
12661
+ if (preferred === "abletime" && connected.abletime) return "abletime";
12662
+ if (preferred === "github") return "github";
12663
+ return null;
12664
+ }
12665
+ function defaultIssueBlockedLookup() {
12666
+ return {
12667
+ preferredSource: () => resolveEffectiveIssueSource(),
12668
+ linearConnected: () => isLinearConnected(),
12669
+ abletimeConnected: () => isAbleTimeConnected(),
12670
+ linear: (id) => getLinearIssueBlockedBy(id),
12671
+ github: (id, repoPath) => getGitHubIssueBlockedBy(id, { repoPath }),
12672
+ abletime: (id) => getAbleTimeIssueBlockedBy(id)
12673
+ };
12674
+ }
12675
+ async function lookupIssueBlockedBy(thread, lookup = defaultIssueBlockedLookup()) {
12676
+ const ref = sourceTicketRef(thread);
12677
+ if (!ref) return null;
12678
+ const tracker = trackerForSourceTicket(ref, lookup.preferredSource(), {
12679
+ linear: lookup.linearConnected(),
12680
+ abletime: lookup.abletimeConnected()
12681
+ });
12682
+ if (!tracker) return null;
12683
+ try {
12684
+ if (tracker === "linear") return await lookup.linear(ref);
12685
+ if (tracker === "abletime") return await lookup.abletime(ref);
12686
+ const repo = (thread.repoPath || thread.worktreePath || "").trim();
12687
+ return await lookup.github(ref, repo);
12688
+ } catch {
12689
+ return null;
12690
+ }
12691
+ }
12692
+ async function refreshWorktreeIssueBlocked(threadRef) {
12693
+ const thread = readThread(threadRef) ?? findThreadByRef(threadRef);
12694
+ if (!thread) throw new Error(`Thread not found: ${threadRef}`);
12695
+ const ids = await lookupIssueBlockedBy(thread);
12696
+ if (ids == null) return null;
12697
+ const siblings = thread.worktreePath ? threadsSharingWorktree(thread.worktreePath) : [];
12698
+ const targets = siblings.length > 0 ? siblings : [thread];
12699
+ for (const t of targets) {
12700
+ if (sameIssueBlockedBy(t.issueBlockedBy, ids)) continue;
12701
+ updateThread(t.id, { issueBlockedBy: ids });
12702
+ }
12703
+ return ids;
12704
+ }
12705
+
12427
12706
  // src/brightsy/api.ts
12428
12707
  var formatBrightsyFetchError = formatFetchError;
12429
12708
  var BrightsySideboardApi = class {
@@ -14038,7 +14317,7 @@ async function continueSourceThread(threadId, prompt) {
14038
14317
  await continueOnReply(threadId, prompt);
14039
14318
  return;
14040
14319
  }
14041
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-4XFRK57E.js");
14320
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-E72HYGTB.js");
14042
14321
  await getOrchestrator2().send(threadId, prompt);
14043
14322
  } catch {
14044
14323
  }
@@ -15131,6 +15410,7 @@ export {
15131
15410
  recordSlackOutboundWatch,
15132
15411
  refreshBrightsyAccessToken,
15133
15412
  refreshGitHubAuth,
15413
+ refreshWorktreeIssueBlocked,
15134
15414
  registerBrightsyOAuthClient,
15135
15415
  registerPackagedUserMcpClients,
15136
15416
  releaseCaffeinateHoldForThread,
@@ -2653,6 +2653,38 @@ var init_run = __esm({
2653
2653
  }
2654
2654
  });
2655
2655
 
2656
+ // src/review/review-write-gate.ts
2657
+ function hasLiveReviewSibling(thread, siblings = []) {
2658
+ const selfId = thread.id;
2659
+ return siblings.some(
2660
+ (t) => t.id !== selfId && t.status !== "archived" && t.title.trim() === REVIEW_TAB_TITLE
2661
+ );
2662
+ }
2663
+ function isReviewWriteGatedThread(thread, siblings) {
2664
+ if (thread.sourceType === "pr" || thread.title.trim() === REVIEW_TAB_TITLE) {
2665
+ return true;
2666
+ }
2667
+ return hasLiveReviewSibling(thread, siblings);
2668
+ }
2669
+ function formatReviewWriteGateDirective() {
2670
+ return [
2671
+ "Review writes are public. The PR or ticket author sees GitHub/Linear/AbleTime comments, ticket updates, and submitted reviews immediately \u2014 a draft will confuse them.",
2672
+ "Write the recommendation in chat so the user can work through the feedback first. Do not call github_comment, linear_comment, abletime_comment, github_update_issue, linear_update_issue, abletime_update_task, or run `gh pr review` / `gh pr comment`, until they type a next step that asks you to post.",
2673
+ "After the review is in chat, stop. Do not call ask_user. The user needs time to read and will type the next steps. If they already asked you to post a specific comment or update in this turn, that is confirmation.",
2674
+ "Do not request reviewers, change labels, or assign yourself unless they asked \u2014 those also notify the author."
2675
+ ].join("\n");
2676
+ }
2677
+ function formatReviewWriteGateReminder() {
2678
+ return "Review writes: keep the review in chat. Do not ask_user after it \u2014 they read and type next steps. Do not github_comment / linear_comment / *_update_* / `gh pr review` on the PR or ticket until they ask. Authors see those immediately.";
2679
+ }
2680
+ var REVIEW_TAB_TITLE;
2681
+ var init_review_write_gate = __esm({
2682
+ "src/review/review-write-gate.ts"() {
2683
+ "use strict";
2684
+ REVIEW_TAB_TITLE = "Review";
2685
+ }
2686
+ });
2687
+
2656
2688
  // src/git/team-meta.ts
2657
2689
  var SOCCER_TEAM_META;
2658
2690
  var init_team_meta = __esm({
@@ -3524,11 +3556,12 @@ function branchDisplayLabel(branchName, worktreePath) {
3524
3556
  }
3525
3557
  function taskPurposeTitle(title) {
3526
3558
  const trimmed = title?.trim() ?? "";
3527
- if (!trimmed || teamSlugFromName(trimmed)) return null;
3559
+ if (!trimmed || teamSlugFromName(trimmed) || trimmed === REVIEW_TAB_TITLE) return null;
3528
3560
  return trimmed;
3529
3561
  }
3530
3562
  function threadDisplayLabel(thread) {
3531
- if (thread.userSetTitle && thread.title?.trim()) return thread.title.trim();
3563
+ const titled = thread.title?.trim() ?? "";
3564
+ if (thread.userSetTitle && titled && titled !== REVIEW_TAB_TITLE) return titled;
3532
3565
  if (thread.prTitle?.trim()) return thread.prTitle.trim();
3533
3566
  if (isPlaceholderBranch(thread.branchName, thread.worktreePath)) {
3534
3567
  const purpose = taskPurposeTitle(thread.title);
@@ -3584,6 +3617,7 @@ var WORKSPACE_TAG_LIMIT, WORKSPACE_TAG_MAX_LENGTH;
3584
3617
  var init_worktree_labels = __esm({
3585
3618
  "src/git/worktree-labels.ts"() {
3586
3619
  "use strict";
3620
+ init_review_write_gate();
3587
3621
  init_teams();
3588
3622
  WORKSPACE_TAG_LIMIT = 8;
3589
3623
  WORKSPACE_TAG_MAX_LENGTH = 32;
@@ -17136,6 +17170,7 @@ function worktreeBindingFrom(from) {
17136
17170
  prIsInMergeQueue: from.prIsInMergeQueue,
17137
17171
  prLabels: from.prLabels,
17138
17172
  prChecksFailed: from.prChecksFailed,
17173
+ issueBlockedBy: from.issueBlockedBy,
17139
17174
  skipAutoArchiveOnMerge: from.skipAutoArchiveOnMerge,
17140
17175
  stackId: from.stackId,
17141
17176
  stackLayer: from.stackLayer,
@@ -17247,38 +17282,6 @@ var init_chat_tabs = __esm({
17247
17282
  }
17248
17283
  });
17249
17284
 
17250
- // src/review/review-write-gate.ts
17251
- function hasLiveReviewSibling(thread, siblings = []) {
17252
- const selfId = thread.id;
17253
- return siblings.some(
17254
- (t) => t.id !== selfId && t.status !== "archived" && t.title.trim() === REVIEW_TAB_TITLE
17255
- );
17256
- }
17257
- function isReviewWriteGatedThread(thread, siblings) {
17258
- if (thread.sourceType === "pr" || thread.title.trim() === REVIEW_TAB_TITLE) {
17259
- return true;
17260
- }
17261
- return hasLiveReviewSibling(thread, siblings);
17262
- }
17263
- function formatReviewWriteGateDirective() {
17264
- return [
17265
- "Review writes are public. The PR or ticket author sees GitHub/Linear/AbleTime comments, ticket updates, and submitted reviews immediately \u2014 a draft will confuse them.",
17266
- "Write the recommendation in chat so the user can work through the feedback first. Do not call github_comment, linear_comment, abletime_comment, github_update_issue, linear_update_issue, abletime_update_task, or run `gh pr review` / `gh pr comment`, until they type a next step that asks you to post.",
17267
- "After the review is in chat, stop. Do not call ask_user. The user needs time to read and will type the next steps. If they already asked you to post a specific comment or update in this turn, that is confirmation.",
17268
- "Do not request reviewers, change labels, or assign yourself unless they asked \u2014 those also notify the author."
17269
- ].join("\n");
17270
- }
17271
- function formatReviewWriteGateReminder() {
17272
- return "Review writes: keep the review in chat. Do not ask_user after it \u2014 they read and type next steps. Do not github_comment / linear_comment / *_update_* / `gh pr review` on the PR or ticket until they ask. Authors see those immediately.";
17273
- }
17274
- var REVIEW_TAB_TITLE;
17275
- var init_review_write_gate = __esm({
17276
- "src/review/review-write-gate.ts"() {
17277
- "use strict";
17278
- REVIEW_TAB_TITLE = "Review";
17279
- }
17280
- });
17281
-
17282
17285
  // src/review/review-request-template.ts
17283
17286
  var REVIEW_REQUEST_TEMPLATE, REVIEW_SKILL_PATH, REVIEW_SKILL_NAME;
17284
17287
  var init_review_request_template = __esm({
@@ -21230,6 +21233,7 @@ function restTaskToRaw(raw, users) {
21230
21233
  projectId: asString(rec.projectId),
21231
21234
  categoryId: asString(rec.projectCategoryId) || asString(rec.categoryId),
21232
21235
  parentId: asString(rec.parentTaskId) || asString(rec.parentId),
21236
+ depends_on: rec.dependencyParentTimeflowTaskId ?? null,
21233
21237
  tags: rec.tags,
21234
21238
  comments,
21235
21239
  attachments: rec.attachments ?? rec.files ?? rec.media,
@@ -56,7 +56,7 @@ import {
56
56
  updateSchedule,
57
57
  workspaceTagTargetRef,
58
58
  writeAgentBlock
59
- } from "../chunk-CYPFOIUK.js";
59
+ } from "../chunk-BXTISNKW.js";
60
60
  import "../chunk-LX5R5JOR.js";
61
61
  import {
62
62
  commentAbleTimeTask,
@@ -76,9 +76,9 @@ import {
76
76
  searchAbleTimeTasks,
77
77
  toAbleTimeIssueInfo,
78
78
  updateAbleTimeTask
79
- } from "../chunk-72OWKHFJ.js";
80
- import "../chunk-Y4WARKPW.js";
81
- import "../chunk-JRZTJ4F7.js";
79
+ } from "../chunk-I5CLCWUK.js";
80
+ import "../chunk-VZAJVX36.js";
81
+ import "../chunk-7SCVGGF6.js";
82
82
  import {
83
83
  normalizeServiceOrigin
84
84
  } from "../chunk-MBYGWNLQ.js";
@@ -97,7 +97,7 @@ import {
97
97
  shouldRegisterMcpWaitForTurn,
98
98
  sideboardMcpProfile,
99
99
  worktreeMcpToolNames
100
- } from "../chunk-FVTR54LY.js";
100
+ } from "../chunk-GH7UMULC.js";
101
101
  import "../chunk-53OCOGND.js";
102
102
  import "../chunk-V5BTGQ6M.js";
103
103
  import "../chunk-E63AM3PW.js";
@@ -114,7 +114,7 @@ import {
114
114
  waitForDetachedJob,
115
115
  waitForTurnToolResult,
116
116
  workspaceAgentChatSummaries
117
- } from "../chunk-YR7NZYUT.js";
117
+ } from "../chunk-NRSC4N5X.js";
118
118
  import {
119
119
  HUGE_TOOL_RESULT_SUMMARY,
120
120
  clipToolResultForStore,
@@ -125,7 +125,7 @@ import {
125
125
  import {
126
126
  GLOBAL_WORKSPACE_ID,
127
127
  isCloudCoordinatorThread
128
- } from "../chunk-PN32Z4JL.js";
128
+ } from "../chunk-A6C67DY5.js";
129
129
  import {
130
130
  canonicalizeRepoPath,
131
131
  formatGhLandError,
@@ -136,7 +136,7 @@ import {
136
136
  resolveListPrsOptions,
137
137
  resolveRepoRoot,
138
138
  warmGithubAgentAuth
139
- } from "../chunk-5CTG5W7S.js";
139
+ } from "../chunk-A46CIARU.js";
140
140
  import {
141
141
  CLI_DIR
142
142
  } from "../chunk-N2WW62LF.js";
@@ -169,7 +169,7 @@ import {
169
169
  normalizeWorkspaceTags,
170
170
  readThread,
171
171
  updateThread
172
- } from "../chunk-U35AHE2P.js";
172
+ } from "../chunk-HOLB6ZFZ.js";
173
173
  import "../chunk-WMZIANPV.js";
174
174
  import "../chunk-KGZBYWZ3.js";
175
175
  import {
@@ -9,18 +9,18 @@ import {
9
9
  resolveSendFollowUp,
10
10
  startOrchestration,
11
11
  waitForPidExit
12
- } from "./chunk-BMORGDYI.js";
12
+ } from "./chunk-U53JICJ2.js";
13
13
  import "./chunk-PGPSIEMW.js";
14
- import "./chunk-NKVNHBDB.js";
14
+ import "./chunk-XWUDFLBX.js";
15
15
  import "./chunk-HH3VVTEC.js";
16
- import "./chunk-IODJCVMN.js";
16
+ import "./chunk-4XZJYBO2.js";
17
17
  import "./chunk-7Q327QF2.js";
18
18
  import "./chunk-7H655NEW.js";
19
19
  import "./chunk-OLYNM52B.js";
20
20
  import "./chunk-NXNNYY3Q.js";
21
- import "./chunk-GFM63DTU.js";
22
- import "./chunk-BPBDGJ43.js";
23
- import "./chunk-CHUPIJP7.js";
21
+ import "./chunk-PX324N7P.js";
22
+ import "./chunk-YN6XONV5.js";
23
+ import "./chunk-YEIHCSZS.js";
24
24
  import "./chunk-2P4XKWV2.js";
25
25
  import "./chunk-RSA47QYR.js";
26
26
  import "./chunk-JAT3JFOS.js";
@@ -11,20 +11,20 @@ import {
11
11
  resolveSendFollowUp,
12
12
  startOrchestration,
13
13
  waitForPidExit
14
- } from "./chunk-CYPFOIUK.js";
14
+ } from "./chunk-BXTISNKW.js";
15
15
  import "./chunk-LX5R5JOR.js";
16
16
  import "./chunk-MBYGWNLQ.js";
17
17
  import "./chunk-4GK32AYX.js";
18
18
  import "./chunk-DC3VZXMA.js";
19
- import "./chunk-FVTR54LY.js";
19
+ import "./chunk-GH7UMULC.js";
20
20
  import "./chunk-53OCOGND.js";
21
21
  import "./chunk-V5BTGQ6M.js";
22
22
  import "./chunk-E63AM3PW.js";
23
23
  import "./chunk-2GPQZZLY.js";
24
- import "./chunk-YR7NZYUT.js";
24
+ import "./chunk-NRSC4N5X.js";
25
25
  import "./chunk-I5TESHDN.js";
26
- import "./chunk-PN32Z4JL.js";
27
- import "./chunk-5CTG5W7S.js";
26
+ import "./chunk-A6C67DY5.js";
27
+ import "./chunk-A46CIARU.js";
28
28
  import "./chunk-N2WW62LF.js";
29
29
  import "./chunk-DD67JWTN.js";
30
30
  import "./chunk-2UG25RMK.js";
@@ -33,7 +33,7 @@ import "./chunk-NSTQ6QKD.js";
33
33
  import "./chunk-WWUABK6B.js";
34
34
  import "./chunk-FJZWM2ON.js";
35
35
  import "./chunk-J2LNLI4S.js";
36
- import "./chunk-U35AHE2P.js";
36
+ import "./chunk-HOLB6ZFZ.js";
37
37
  import "./chunk-WMZIANPV.js";
38
38
  import "./chunk-KGZBYWZ3.js";
39
39
  import "./chunk-WOU343SI.js";