syntaur 0.16.2 → 0.17.0

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 (77) hide show
  1. package/dashboard/dist/assets/{_basePickBy-DTuHiZCP.js → _basePickBy-Dek5-ACb.js} +1 -1
  2. package/dashboard/dist/assets/{_baseUniq-BjbISCNN.js → _baseUniq-BeLddDKU.js} +1 -1
  3. package/dashboard/dist/assets/{arc-D9mCa8If.js → arc-kotdj4Uh.js} +1 -1
  4. package/dashboard/dist/assets/{architectureDiagram-2XIMDMQ5-CLWheiZu.js → architectureDiagram-2XIMDMQ5-BaqFXQ-q.js} +1 -1
  5. package/dashboard/dist/assets/{blockDiagram-WCTKOSBZ-BBxrVTWB.js → blockDiagram-WCTKOSBZ-BSyGne6h.js} +1 -1
  6. package/dashboard/dist/assets/{c4Diagram-IC4MRINW-DnhDZ2W3.js → c4Diagram-IC4MRINW-iYjZFKOW.js} +1 -1
  7. package/dashboard/dist/assets/channel-eXdj7ayV.js +1 -0
  8. package/dashboard/dist/assets/{chunk-4BX2VUAB-DeAfVeDa.js → chunk-4BX2VUAB-DvY9Y7jB.js} +1 -1
  9. package/dashboard/dist/assets/{chunk-55IACEB6-cKEeGDNI.js → chunk-55IACEB6-2vCDm2cJ.js} +1 -1
  10. package/dashboard/dist/assets/{chunk-FMBD7UC4-7RuZ6HEq.js → chunk-FMBD7UC4-BVPaoRtV.js} +1 -1
  11. package/dashboard/dist/assets/{chunk-JSJVCQXG-B5dwG0bv.js → chunk-JSJVCQXG-B9uJpMzd.js} +1 -1
  12. package/dashboard/dist/assets/{chunk-KX2RTZJC-DeyQYDVj.js → chunk-KX2RTZJC-CHcjjGaq.js} +1 -1
  13. package/dashboard/dist/assets/{chunk-NQ4KR5QH-NYo4hSqA.js → chunk-NQ4KR5QH-B8n19pSs.js} +1 -1
  14. package/dashboard/dist/assets/{chunk-QZHKN3VN-CtJFICF8.js → chunk-QZHKN3VN-CF9ZYFGK.js} +1 -1
  15. package/dashboard/dist/assets/{chunk-WL4C6EOR-DZ3WYdab.js → chunk-WL4C6EOR-mY_1Vmdf.js} +1 -1
  16. package/dashboard/dist/assets/classDiagram-VBA2DB6C-B-bBQACr.js +1 -0
  17. package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-B-bBQACr.js +1 -0
  18. package/dashboard/dist/assets/clone-CL04pv9J.js +1 -0
  19. package/dashboard/dist/assets/{cose-bilkent-S5V4N54A-DaYOsf-M.js → cose-bilkent-S5V4N54A-DOYoG3gB.js} +1 -1
  20. package/dashboard/dist/assets/{dagre-KLK3FWXG-DzLc7ykF.js → dagre-KLK3FWXG-CZFrp-Yq.js} +1 -1
  21. package/dashboard/dist/assets/{diagram-E7M64L7V-kpjEdOqb.js → diagram-E7M64L7V-F3rF5YwM.js} +1 -1
  22. package/dashboard/dist/assets/{diagram-IFDJBPK2-D3EHoh6j.js → diagram-IFDJBPK2-BynWv-Vo.js} +1 -1
  23. package/dashboard/dist/assets/{diagram-P4PSJMXO-Cp6Un2ys.js → diagram-P4PSJMXO-NIyzhm_M.js} +1 -1
  24. package/dashboard/dist/assets/{erDiagram-INFDFZHY-DDjOUPWk.js → erDiagram-INFDFZHY-Ca9NbihE.js} +1 -1
  25. package/dashboard/dist/assets/{flowDiagram-PKNHOUZH-CfO51xge.js → flowDiagram-PKNHOUZH-YhS0MOu4.js} +1 -1
  26. package/dashboard/dist/assets/{ganttDiagram-A5KZAMGK-BDzAtkcp.js → ganttDiagram-A5KZAMGK-G7P3qq_2.js} +1 -1
  27. package/dashboard/dist/assets/{gitGraphDiagram-K3NZZRJ6-JPMFN2zF.js → gitGraphDiagram-K3NZZRJ6-BJAK7M7E.js} +1 -1
  28. package/dashboard/dist/assets/{graph-DXDryilu.js → graph-11geMy3f.js} +1 -1
  29. package/dashboard/dist/assets/index--qwybK3W.js +535 -0
  30. package/dashboard/dist/assets/index-DwrhlK8r.css +1 -0
  31. package/dashboard/dist/assets/{infoDiagram-LFFYTUFH-CYi5kkvz.js → infoDiagram-LFFYTUFH-COcQYcLf.js} +1 -1
  32. package/dashboard/dist/assets/{ishikawaDiagram-PHBUUO56-DQl_IUe8.js → ishikawaDiagram-PHBUUO56-B7Jjyw8J.js} +1 -1
  33. package/dashboard/dist/assets/{journeyDiagram-4ABVD52K-BXXGPcrS.js → journeyDiagram-4ABVD52K--snU-QAX.js} +1 -1
  34. package/dashboard/dist/assets/{kanban-definition-K7BYSVSG-BqJestUY.js → kanban-definition-K7BYSVSG-BucLoc89.js} +1 -1
  35. package/dashboard/dist/assets/{layout-D5VdYmWn.js → layout-Bcgxdz8A.js} +1 -1
  36. package/dashboard/dist/assets/{linear-dZA_O_GN.js → linear-CRF8xwvk.js} +1 -1
  37. package/dashboard/dist/assets/{mermaid.core-B0Ixd1yP.js → mermaid.core-D5JD5uYg.js} +4 -4
  38. package/dashboard/dist/assets/{mindmap-definition-YRQLILUH-CSJYdSMG.js → mindmap-definition-YRQLILUH-BqGcTcbk.js} +1 -1
  39. package/dashboard/dist/assets/{pieDiagram-SKSYHLDU-DmYrRZHN.js → pieDiagram-SKSYHLDU-CnQ2EkyX.js} +1 -1
  40. package/dashboard/dist/assets/{quadrantDiagram-337W2JSQ-La3ce5kE.js → quadrantDiagram-337W2JSQ-CKCfmTRc.js} +1 -1
  41. package/dashboard/dist/assets/{requirementDiagram-Z7DCOOCP-DPitIZQl.js → requirementDiagram-Z7DCOOCP-B9J4bvUK.js} +1 -1
  42. package/dashboard/dist/assets/{sankeyDiagram-WA2Y5GQK-CAmCqGkr.js → sankeyDiagram-WA2Y5GQK-CMSzI5rg.js} +1 -1
  43. package/dashboard/dist/assets/{sequenceDiagram-2WXFIKYE-6lEzNTWG.js → sequenceDiagram-2WXFIKYE-BFQDtxd0.js} +1 -1
  44. package/dashboard/dist/assets/{stateDiagram-RAJIS63D-DyGKCS2C.js → stateDiagram-RAJIS63D-DgWYKT02.js} +1 -1
  45. package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-Nmwft4cR.js +1 -0
  46. package/dashboard/dist/assets/{timeline-definition-YZTLITO2-D9RxQE3j.js → timeline-definition-YZTLITO2-jANu0e7M.js} +1 -1
  47. package/dashboard/dist/assets/{treemap-KZPCXAKY-TuXbGNN4.js → treemap-KZPCXAKY-BFjWMkyM.js} +1 -1
  48. package/dashboard/dist/assets/{vennDiagram-LZ73GAT5-Bly5knr-.js → vennDiagram-LZ73GAT5-DGwrAJYj.js} +1 -1
  49. package/dashboard/dist/assets/{xychartDiagram-JWTSCODW-CA-5z7-4.js → xychartDiagram-JWTSCODW-BLCPfoFM.js} +1 -1
  50. package/dashboard/dist/index.html +2 -2
  51. package/dist/dashboard/server.js +2220 -479
  52. package/dist/dashboard/server.js.map +1 -1
  53. package/dist/db/leases-db.js.map +1 -1
  54. package/dist/index.js +4499 -1127
  55. package/dist/index.js.map +1 -1
  56. package/dist/launch/index.js +127 -63
  57. package/dist/launch/index.js.map +1 -1
  58. package/package.json +1 -1
  59. package/platforms/claude-code/skills/bundle-worktree/SKILL.md +107 -0
  60. package/platforms/claude-code/skills/complete-bundle/SKILL.md +113 -0
  61. package/platforms/claude-code/skills/grab-bundle/SKILL.md +111 -0
  62. package/platforms/claude-code/skills/plan-bundle/SKILL.md +88 -0
  63. package/platforms/codex/skills/bundle-worktree/SKILL.md +107 -0
  64. package/platforms/codex/skills/complete-bundle/SKILL.md +113 -0
  65. package/platforms/codex/skills/grab-bundle/SKILL.md +111 -0
  66. package/platforms/codex/skills/plan-bundle/SKILL.md +88 -0
  67. package/skills/bundle-worktree/SKILL.md +107 -0
  68. package/skills/complete-bundle/SKILL.md +113 -0
  69. package/skills/grab-bundle/SKILL.md +111 -0
  70. package/skills/plan-bundle/SKILL.md +88 -0
  71. package/dashboard/dist/assets/channel-CN5VmjNa.js +0 -1
  72. package/dashboard/dist/assets/classDiagram-VBA2DB6C-CqLb9GuU.js +0 -1
  73. package/dashboard/dist/assets/classDiagram-v2-RAHNMMFH-CqLb9GuU.js +0 -1
  74. package/dashboard/dist/assets/clone-DwvrjCQs.js +0 -1
  75. package/dashboard/dist/assets/index-D7UtkCYM.js +0 -515
  76. package/dashboard/dist/assets/index-DTXSWSzH.css +0 -1
  77. package/dashboard/dist/assets/stateDiagram-v2-FVOUBMTO-BOmRICoY.js +0 -1
@@ -887,7 +887,20 @@ async function readConfig() {
887
887
  };
888
888
  }
889
889
  function getAgents(config) {
890
- return config.agents ?? BUILTIN_AGENTS;
890
+ if (config.agents === null) return BUILTIN_AGENTS;
891
+ const builtinById = new Map(BUILTIN_AGENTS.map((a) => [a.id, a]));
892
+ return config.agents.map((agent) => {
893
+ const builtin = builtinById.get(agent.id);
894
+ if (!builtin) return agent;
895
+ const resume = agent.resume ?? builtin.resume;
896
+ const fork = agent.fork ?? builtin.fork;
897
+ if (resume === agent.resume && fork === agent.fork) return agent;
898
+ return {
899
+ ...agent,
900
+ ...resume ? { resume } : {},
901
+ ...fork ? { fork } : {}
902
+ };
903
+ });
891
904
  }
892
905
  function parseTerminalConfig(value) {
893
906
  if (value === void 0 || value === null || value === "") return null;
@@ -1333,7 +1346,7 @@ function buildTransitionTable(transitions) {
1333
1346
  return table;
1334
1347
  }
1335
1348
  function getTargetStatus(_from, command, table) {
1336
- if (!table || table === DEFAULT_TRANSITION_TABLE) {
1349
+ if (!table) {
1337
1350
  return DEFAULT_COMMAND_TARGETS.get(command) ?? null;
1338
1351
  }
1339
1352
  return table.get(command) ?? table.get(`${_from}:${command}`) ?? null;
@@ -1715,6 +1728,10 @@ var init_overviewCopy = __esm({
1715
1728
  // src/dashboard/api.ts
1716
1729
  import { readdir as readdir6, readFile as readFile8, writeFile as writeFile3 } from "fs/promises";
1717
1730
  import { resolve as resolve11, dirname as dirname2, basename } from "path";
1731
+ function accumulatePhase(traces, label, ms) {
1732
+ if (!traces) return;
1733
+ traces.subPhases.set(label, (traces.subPhases.get(label) ?? 0) + ms);
1734
+ }
1718
1735
  async function listStandaloneRecords(assignmentsDir) {
1719
1736
  if (!assignmentsDir) return [];
1720
1737
  if (!await fileExists(assignmentsDir)) return [];
@@ -1759,12 +1776,17 @@ async function getStatusConfig() {
1759
1776
  const terminalSet = new Set(
1760
1777
  config.statuses.statuses.filter((s) => s.terminal).map((s) => s.id)
1761
1778
  );
1779
+ const hasCustomTransitions = config.statuses.transitions.length > 0;
1780
+ const effectiveTransitions = hasCustomTransitions ? config.statuses.transitions : Array.from(DEFAULT_TRANSITION_TABLE.entries()).map(([key, to]) => {
1781
+ const [from, command] = key.split(":");
1782
+ return { from, command, to };
1783
+ });
1762
1784
  _cachedConfig = {
1763
1785
  custom: true,
1764
1786
  statuses: config.statuses.statuses,
1765
1787
  order: config.statuses.order,
1766
- transitions: config.statuses.transitions,
1767
- transitionTable: buildTransitionTable(config.statuses.transitions),
1788
+ transitions: effectiveTransitions,
1789
+ transitionTable: buildTransitionTable(effectiveTransitions),
1768
1790
  terminalStatuses: terminalSet.size > 0 ? terminalSet : /* @__PURE__ */ new Set(["completed", "failed"])
1769
1791
  };
1770
1792
  } else {
@@ -1792,16 +1814,17 @@ async function getStandaloneAvailableTransitions(assignment) {
1792
1814
  const transitionDefs = getTransitionDefinitions(config);
1793
1815
  const actions = [];
1794
1816
  for (const definition of transitionDefs) {
1817
+ const target = getTargetStatus(assignment.status, definition.command, config.transitionTable);
1818
+ if (target === null) continue;
1795
1819
  let warning = null;
1796
1820
  if (definition.command === "start" && !assignment.assignee) {
1797
1821
  warning = "No assignee set \u2014 consider assigning before starting.";
1798
1822
  }
1799
- const target = getTargetStatus(assignment.status, definition.command, config.transitionTable);
1800
1823
  actions.push({
1801
1824
  command: definition.command,
1802
1825
  label: definition.label,
1803
1826
  description: definition.description,
1804
- targetStatus: target ?? definition.command,
1827
+ targetStatus: target,
1805
1828
  disabled: false,
1806
1829
  disabledReason: null,
1807
1830
  warning,
@@ -1895,6 +1918,7 @@ async function getAssignmentDetail(projectsDir, projectSlug, assignmentSlug) {
1895
1918
  slug: assignment.slug || assignmentSlug,
1896
1919
  title: assignment.title,
1897
1920
  status: assignment.status,
1921
+ type: assignment.type,
1898
1922
  priority: assignment.priority,
1899
1923
  assignee: assignment.assignee,
1900
1924
  dependsOn: assignment.dependsOn,
@@ -2143,6 +2167,7 @@ async function buildStandaloneAssignmentDetail(resolved) {
2143
2167
  slug: assignment.slug || resolved.id,
2144
2168
  title: assignment.title,
2145
2169
  status: assignment.status,
2170
+ type: assignment.type,
2146
2171
  priority: assignment.priority,
2147
2172
  assignee: assignment.assignee,
2148
2173
  dependsOn: [],
@@ -2169,7 +2194,7 @@ async function buildStandaloneAssignmentDetail(resolved) {
2169
2194
  };
2170
2195
  return detail;
2171
2196
  }
2172
- async function listProjectRecords(projectsDir) {
2197
+ async function listProjectRecords(projectsDir, traces) {
2173
2198
  if (!await fileExists(projectsDir)) {
2174
2199
  return [];
2175
2200
  }
@@ -2179,61 +2204,75 @@ async function listProjectRecords(projectsDir) {
2179
2204
  }
2180
2205
  const entries = await readdir6(projectsDir, { withFileTypes: true });
2181
2206
  const projectDirs = entries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("."));
2182
- const records = [];
2183
- for (const entry of projectDirs) {
2184
- const projectPath = resolve11(projectsDir, entry.name);
2185
- const projectMdPath = resolve11(projectPath, "project.md");
2186
- if (!await fileExists(projectMdPath)) {
2187
- continue;
2188
- }
2189
- const projectContent = await readFile8(projectMdPath, "utf-8");
2190
- const project = parseProject(projectContent);
2191
- const assignments = await listAssignmentRecords(projectPath);
2192
- const rollup = await buildProjectRollup(projectPath, project, assignments);
2193
- const updated = getProjectActivityTimestamp(project.updated, assignments);
2194
- records.push({
2195
- projectPath,
2196
- project,
2197
- assignments,
2198
- dependencyGraph: await loadDependencyGraph(projectPath, assignments),
2199
- summary: {
2200
- slug: project.slug || entry.name,
2201
- title: project.title,
2202
- status: rollup.status,
2203
- statusOverride: project.statusOverride,
2204
- archived: project.archived,
2205
- archivedAt: project.archivedAt,
2206
- archivedReason: project.archivedReason,
2207
- created: project.created,
2208
- updated,
2209
- tags: project.tags,
2210
- progress: rollup.progress,
2211
- needsAttention: rollup.needsAttention,
2212
- workspace: project.workspace
2207
+ const maybeRecords = await Promise.all(
2208
+ projectDirs.map(async (entry) => {
2209
+ const projectPath = resolve11(projectsDir, entry.name);
2210
+ const projectMdPath = resolve11(projectPath, "project.md");
2211
+ if (!await fileExists(projectMdPath)) {
2212
+ return null;
2213
2213
  }
2214
- });
2215
- }
2214
+ const t0 = traces ? performance.now() : 0;
2215
+ const projectContent = await readFile8(projectMdPath, "utf-8");
2216
+ const project = parseProject(projectContent);
2217
+ if (traces) accumulatePhase(traces, "parse-project-md", performance.now() - t0);
2218
+ const t1 = traces ? performance.now() : 0;
2219
+ const assignments = await listAssignmentRecords(projectPath, traces);
2220
+ if (traces) accumulatePhase(traces, "list-assignments", performance.now() - t1);
2221
+ const t2 = traces ? performance.now() : 0;
2222
+ const rollup = await buildProjectRollup(projectPath, project, assignments, traces);
2223
+ if (traces) accumulatePhase(traces, "build-rollup", performance.now() - t2);
2224
+ const updated = getProjectActivityTimestamp(project.updated, assignments);
2225
+ const t3 = traces ? performance.now() : 0;
2226
+ const dependencyGraph = await loadDependencyGraph(projectPath, assignments);
2227
+ if (traces) accumulatePhase(traces, "load-dep-graph", performance.now() - t3);
2228
+ return {
2229
+ projectPath,
2230
+ project,
2231
+ assignments,
2232
+ dependencyGraph,
2233
+ summary: {
2234
+ slug: project.slug || entry.name,
2235
+ title: project.title,
2236
+ status: rollup.status,
2237
+ statusOverride: project.statusOverride,
2238
+ archived: project.archived,
2239
+ archivedAt: project.archivedAt,
2240
+ archivedReason: project.archivedReason,
2241
+ created: project.created,
2242
+ updated,
2243
+ tags: project.tags,
2244
+ progress: rollup.progress,
2245
+ needsAttention: rollup.needsAttention,
2246
+ workspace: project.workspace
2247
+ }
2248
+ };
2249
+ })
2250
+ );
2251
+ const records = maybeRecords.filter((r) => r !== null);
2216
2252
  records.sort((left, right) => compareTimestamps(right.summary.updated, left.summary.updated));
2217
2253
  return records;
2218
2254
  }
2219
- async function listAssignmentRecords(projectPath) {
2255
+ async function listAssignmentRecords(projectPath, traces) {
2220
2256
  const assignmentsDir = resolve11(projectPath, "assignments");
2221
2257
  if (!await fileExists(assignmentsDir)) {
2222
2258
  return [];
2223
2259
  }
2224
2260
  const entries = await readdir6(assignmentsDir, { withFileTypes: true });
2225
- const records = [];
2226
- for (const entry of entries) {
2227
- if (!entry.isDirectory()) {
2228
- continue;
2229
- }
2230
- const assignmentMd = resolve11(assignmentsDir, entry.name, "assignment.md");
2231
- if (!await fileExists(assignmentMd)) {
2232
- continue;
2233
- }
2234
- const content = await readFile8(assignmentMd, "utf-8");
2235
- records.push(parseAssignmentFull(content));
2236
- }
2261
+ const dirEntries = entries.filter((entry) => entry.isDirectory());
2262
+ const maybeRecords = await Promise.all(
2263
+ dirEntries.map(async (entry) => {
2264
+ const assignmentMd = resolve11(assignmentsDir, entry.name, "assignment.md");
2265
+ if (!await fileExists(assignmentMd)) {
2266
+ return null;
2267
+ }
2268
+ const t0 = traces ? performance.now() : 0;
2269
+ const content = await readFile8(assignmentMd, "utf-8");
2270
+ const parsed = parseAssignmentFull(content);
2271
+ if (traces) accumulatePhase(traces, "read-assignment-md", performance.now() - t0);
2272
+ return parsed;
2273
+ })
2274
+ );
2275
+ const records = maybeRecords.filter((r) => r !== null);
2237
2276
  records.sort((left, right) => compareTimestamps(right.updated, left.updated));
2238
2277
  return records;
2239
2278
  }
@@ -2249,13 +2288,20 @@ async function loadDependencyGraph(projectPath, assignments) {
2249
2288
  }
2250
2289
  return buildDependencyGraph(assignments);
2251
2290
  }
2252
- async function buildProjectRollup(projectPath, project, assignments) {
2291
+ async function buildProjectRollup(projectPath, project, assignments, traces) {
2253
2292
  const progress = { total: assignments.length };
2293
+ const perAssignment = await Promise.all(
2294
+ assignments.map(async (assignment) => {
2295
+ const t0 = traces ? performance.now() : 0;
2296
+ const openQuestions2 = await countOpenQuestions(projectPath, assignment.slug);
2297
+ if (traces) accumulatePhase(traces, "count-open-questions", performance.now() - t0);
2298
+ return { status: assignment.status, openQuestions: openQuestions2 };
2299
+ })
2300
+ );
2254
2301
  let openQuestions = 0;
2255
- for (const assignment of assignments) {
2256
- const s = assignment.status;
2257
- progress[s] = (progress[s] ?? 0) + 1;
2258
- openQuestions += await countOpenQuestions(projectPath, assignment.slug);
2302
+ for (const entry of perAssignment) {
2303
+ progress[entry.status] = (progress[entry.status] ?? 0) + 1;
2304
+ openQuestions += entry.openQuestions;
2259
2305
  }
2260
2306
  const needsAttention = {
2261
2307
  blockedCount: progress["blocked"] ?? 0,
@@ -2308,28 +2354,37 @@ function buildDependencyGraph(assignments) {
2308
2354
  function findAssignmentStatus(assignments, slug) {
2309
2355
  return assignments.find((assignment) => assignment.slug === slug)?.status ?? "pending";
2310
2356
  }
2311
- async function getAvailableTransitions(projectsDir, projectSlug, assignmentSlug, assignment) {
2357
+ async function getAvailableTransitions(projectsDir, projectSlug, assignmentSlug, assignment, options) {
2312
2358
  const config = await getStatusConfig();
2313
2359
  const transitionDefs = getTransitionDefinitions(config);
2314
2360
  const actions = [];
2315
2361
  const projectPath = resolve11(projectsDir, projectSlug);
2362
+ const traces = options?.traces;
2316
2363
  for (const definition of transitionDefs) {
2364
+ const target = getTargetStatus(assignment.status, definition.command, config.transitionTable);
2365
+ if (target === null) continue;
2317
2366
  let warning = null;
2318
2367
  if (definition.command === "start" && !assignment.assignee) {
2319
2368
  warning = "No assignee set \u2014 consider assigning before starting.";
2320
2369
  }
2321
2370
  if (definition.command === "start" && assignment.dependsOn.length > 0) {
2322
- const unmetDependencies = await getUnmetDependencies(projectPath, assignment.dependsOn, config.terminalStatuses);
2371
+ const t0 = traces ? performance.now() : 0;
2372
+ const unmetDependencies = await getUnmetDependencies(
2373
+ projectPath,
2374
+ assignment.dependsOn,
2375
+ config.terminalStatuses,
2376
+ options?.dependencyStatusMap
2377
+ );
2378
+ if (traces) accumulatePhase(traces, "get-unmet-dependencies", performance.now() - t0);
2323
2379
  if (unmetDependencies.length > 0) {
2324
2380
  warning = `Unmet dependencies: ${unmetDependencies.join(", ")}.`;
2325
2381
  }
2326
2382
  }
2327
- const target = getTargetStatus(assignment.status, definition.command, config.transitionTable);
2328
2383
  actions.push({
2329
2384
  command: definition.command,
2330
2385
  label: definition.label,
2331
2386
  description: definition.description,
2332
- targetStatus: target ?? definition.command,
2387
+ targetStatus: target,
2333
2388
  disabled: false,
2334
2389
  disabledReason: null,
2335
2390
  warning,
@@ -2338,10 +2393,19 @@ async function getAvailableTransitions(projectsDir, projectSlug, assignmentSlug,
2338
2393
  }
2339
2394
  return actions;
2340
2395
  }
2341
- async function getUnmetDependencies(projectPath, dependsOn, terminalStatuses) {
2396
+ async function getUnmetDependencies(projectPath, dependsOn, terminalStatuses, dependencyStatusMap) {
2342
2397
  const terminals = terminalStatuses ?? /* @__PURE__ */ new Set(["completed"]);
2343
2398
  const unmet = [];
2344
2399
  for (const dependency of dependsOn) {
2400
+ if (dependencyStatusMap) {
2401
+ const mappedStatus = dependencyStatusMap.get(dependency);
2402
+ if (mappedStatus !== void 0) {
2403
+ if (!terminals.has(mappedStatus)) {
2404
+ unmet.push(`${dependency} (${mappedStatus})`);
2405
+ }
2406
+ continue;
2407
+ }
2408
+ }
2345
2409
  const dependencyPath = resolve11(projectPath, "assignments", dependency, "assignment.md");
2346
2410
  if (!await fileExists(dependencyPath)) {
2347
2411
  unmet.push(`${dependency} (missing)`);