@kaddo/mcp 3.65.0 → 3.67.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 (2) hide show
  1. package/dist/index.js +221 -15
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -521,7 +521,14 @@ function parseArtifact(filePath, raw) {
521
521
  sourceId: String(data.source_id ?? ""),
522
522
  rawFrontmatter: data,
523
523
  decisions: Array.isArray(data.decisions) ? data.decisions.map(String).filter(Boolean) : [],
524
- capsules: Array.isArray(data.capsules) ? data.capsules.map(String).filter(Boolean) : []
524
+ capsules: Array.isArray(data.capsules) ? data.capsules.map(String).filter(Boolean) : [],
525
+ implementationStatus: String(data.implementation_status ?? ""),
526
+ validationStatus: String(data.validation_status ?? ""),
527
+ releaseStatus: String(data.release_status ?? ""),
528
+ affectedModules: Array.isArray(data.affected_modules) ? data.affected_modules.map(String).filter(Boolean) : [],
529
+ refinedBy: String(data.refined_by ?? ""),
530
+ implementedBy: String(data.implemented_by ?? ""),
531
+ closedBy: String(data.closed_by ?? "")
525
532
  };
526
533
  } catch {
527
534
  return null;
@@ -2413,6 +2420,7 @@ function buildGraph(dir, config, opts = {}, now = /* @__PURE__ */ new Date()) {
2413
2420
  const selectedWIs = workItems.filter((a2) => a2.lifecycle && includedSet.has(a2.lifecycle));
2414
2421
  for (const wi of selectedWIs) {
2415
2422
  const id = wi.id || wi.title;
2423
+ if (!id || !id.trim()) continue;
2416
2424
  const wiNodeId = `wi:${id}`;
2417
2425
  addNode({
2418
2426
  id: wiNodeId,
@@ -2423,16 +2431,19 @@ function buildGraph(dir, config, opts = {}, now = /* @__PURE__ */ new Date()) {
2423
2431
  knowledge_level: wi.knowledgeLevel || void 0
2424
2432
  });
2425
2433
  for (const glob of wi.codeGlobs) {
2434
+ if (!glob || !glob.trim()) continue;
2426
2435
  const codeId = `code:${glob}`;
2427
2436
  addNode({ id: codeId, type: "code-glob", label: glob });
2428
2437
  addEdge(wiNodeId, codeId, "owns");
2429
2438
  }
2430
2439
  for (const cap of wi.capabilities) {
2440
+ if (!cap || !cap.trim()) continue;
2431
2441
  const capId = `capability:${slug(cap) || cap}`;
2432
2442
  addNode({ id: capId, type: "capability", label: cap });
2433
2443
  addEdge(wiNodeId, capId, "implements");
2434
2444
  }
2435
2445
  for (const dec of wi.decisions) {
2446
+ if (!dec || !dec.trim()) continue;
2436
2447
  const adrId = `adr:${dec}`;
2437
2448
  addNode({ id: adrId, type: "decision", label: dec });
2438
2449
  addEdge(wiNodeId, adrId, "depends_on");
@@ -2449,16 +2460,19 @@ function buildGraph(dir, config, opts = {}, now = /* @__PURE__ */ new Date()) {
2449
2460
  }
2450
2461
  }
2451
2462
  for (const adr of all.filter(isAdr)) {
2452
- const adrId = `adr:${adr.id || adr.title}`;
2463
+ const adrLabel = adr.id || adr.title;
2464
+ if (!adrLabel || !adrLabel.trim()) continue;
2465
+ const adrId = `adr:${adrLabel}`;
2453
2466
  const referenced = nodes.has(adrId);
2454
2467
  if (scope === "all" || referenced) {
2455
2468
  nodes.set(adrId, {
2456
2469
  id: adrId,
2457
2470
  type: "decision",
2458
- label: `${adr.id} ${adr.title}`.trim() || adr.id || adr.title,
2471
+ label: `${adr.id} ${adr.title}`.trim() || adrLabel,
2459
2472
  path: adr.relPath
2460
2473
  });
2461
2474
  for (const glob of adr.codeGlobs) {
2475
+ if (!glob || !glob.trim()) continue;
2462
2476
  const codeId = `code:${glob}`;
2463
2477
  addNode({ id: codeId, type: "code-glob", label: glob });
2464
2478
  addEdge(adrId, codeId, "governs");
@@ -2514,13 +2528,20 @@ function renderGraphMermaid(graph) {
2514
2528
  safeIds.set(id, candidate);
2515
2529
  return candidate;
2516
2530
  };
2517
- const escapeLabel = (s) => s.replace(/"/g, "'");
2531
+ const escapeLabel = (s) => s.replace(/"/g, "'").replace(/\[/g, "(").replace(/\]/g, ")").replace(/\n/g, " ");
2532
+ const validNodes = graph.nodes.filter(
2533
+ (n) => n.id && n.id.trim() !== "" && n.label && n.label.trim() !== ""
2534
+ );
2535
+ const validNodeIds = new Set(validNodes.map((n) => n.id));
2518
2536
  const lines = ["flowchart LR"];
2519
- for (const node of graph.nodes) {
2537
+ for (const node of validNodes) {
2520
2538
  lines.push(` ${safe(node.id)}["${escapeLabel(node.label)}"]`);
2521
2539
  }
2522
- if (graph.edges.length > 0) lines.push("");
2523
- for (const edge of graph.edges) {
2540
+ const validEdges = graph.edges.filter(
2541
+ (e) => validNodeIds.has(e.from) && validNodeIds.has(e.to)
2542
+ );
2543
+ if (validEdges.length > 0) lines.push("");
2544
+ for (const edge of validEdges) {
2524
2545
  lines.push(` ${safe(edge.from)} -->|${edge.type}| ${safe(edge.to)}`);
2525
2546
  }
2526
2547
  return lines.join("\n") + "\n";
@@ -3942,6 +3963,8 @@ function workItemsSignal(dir) {
3942
3963
  if (wis.length === 0) return "none";
3943
3964
  if (wis.some((w3) => w3.lifecycle === "in-progress")) return "in-progress";
3944
3965
  if (wis.some((w3) => w3.lifecycle === "ready")) return "ready";
3966
+ const hasActive = wis.some((w3) => w3.lifecycle === "draft" || w3.lifecycle === "blocked");
3967
+ if (!hasActive && wis.some((w3) => w3.lifecycle === "completed" || w3.lifecycle === "archived")) return "completed-only";
3945
3968
  return "none-ready";
3946
3969
  }
3947
3970
  function installedAdapters(dir) {
@@ -4370,6 +4393,8 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
4370
4393
  else if (understand === "missing") overall = "scanned";
4371
4394
  else if (firstWeak) overall = "knowledge-incomplete";
4372
4395
  else if (oq.summary.blocking_open > 0) overall = "needs-decisions";
4396
+ else if (work_items === "in-progress") overall = "active-implementation";
4397
+ else if (work_items === "completed-only") overall = deriveDeliveryCompletedStatus(dir);
4373
4398
  else if (roadmap !== "has-candidates") overall = "ready-for-roadmap";
4374
4399
  else if (work_items === "none" || work_items === "none-ready") overall = "ready-for-work-item";
4375
4400
  else overall = "ready-for-implementation";
@@ -4382,6 +4407,16 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
4382
4407
  nextStepRecommendation: rec
4383
4408
  };
4384
4409
  }
4410
+ function deriveDeliveryCompletedStatus(dir) {
4411
+ const wis = discoverWorkItems(dir);
4412
+ const completed = wis.filter((w3) => lifecycleStateOf({ status: w3.status, filePath: w3.filePath }) === "completed");
4413
+ if (completed.length === 0) return "delivery-completed";
4414
+ const hasReleaseBlocked = completed.some((w3) => w3.releaseStatus === "blocked");
4415
+ const hasReleaseReady = completed.some((w3) => w3.releaseStatus === "ready" || w3.releaseStatus === "released");
4416
+ if (hasReleaseBlocked) return "delivery-completed-release-blocked";
4417
+ if (hasReleaseReady) return "delivery-completed-release-ready";
4418
+ return "delivery-completed";
4419
+ }
4385
4420
 
4386
4421
  // ../cli/src/core/assets.ts
4387
4422
  import matter6 from "gray-matter";
@@ -7606,7 +7641,7 @@ var refineWorkItem = {
7606
7641
  id: "refine-work-item",
7607
7642
  label: "Refine Work Item",
7608
7643
  evaluate: (ctx) => {
7609
- if (ctx.readyWorkItems > 0 || ctx.inProgressWorkItems > 0) return { status: "done" };
7644
+ if (ctx.readyWorkItems > 0 || ctx.inProgressWorkItems > 0 || ctx.blockedWorkItems > 0 || ctx.completedWorkItems > 0 || ctx.archivedWorkItems > 0) return { status: "done" };
7610
7645
  if (ctx.draftWorkItems > 0) {
7611
7646
  return {
7612
7647
  status: "current",
@@ -7857,7 +7892,9 @@ function buildRouteContext(dir) {
7857
7892
  draftWorkItems: byState("draft"),
7858
7893
  readyWorkItems: byState("ready"),
7859
7894
  inProgressWorkItems: byState("in-progress"),
7895
+ blockedWorkItems: byState("blocked"),
7860
7896
  completedWorkItems: byState("completed"),
7897
+ archivedWorkItems: byState("archived"),
7861
7898
  ownershipCoverage: `${withOwnership}/${total}`,
7862
7899
  ownershipComplete: total > 0 && withOwnership >= total,
7863
7900
  decisionCandidates: td.candidates,
@@ -8030,6 +8067,33 @@ function analyzeMetadataHealth(dir) {
8030
8067
  if (fileDrifted) drifted++;
8031
8068
  else healthy++;
8032
8069
  }
8070
+ const wiDir = join(dir, "knowledge/delivery/work-items");
8071
+ if (exists(wiDir)) {
8072
+ const walkWIs = (d3) => {
8073
+ for (const entry of readDir(d3)) {
8074
+ const p = join(d3, entry);
8075
+ if (isFile(p) && entry.endsWith(".md")) {
8076
+ try {
8077
+ const raw = readFile(p);
8078
+ const fm = matter7(raw).data;
8079
+ if (fm.status === "done") {
8080
+ const rel = p.replace(dir + "/", "").replace(dir + "\\", "").replace(/\\/g, "/");
8081
+ findings.push({
8082
+ file: rel,
8083
+ field: "status",
8084
+ issue: "inconsistent",
8085
+ detail: "Legacy status `done` detected. Canonical status is `completed`."
8086
+ });
8087
+ }
8088
+ } catch {
8089
+ }
8090
+ } else if (!isFile(p) && !entry.startsWith(".")) {
8091
+ walkWIs(p);
8092
+ }
8093
+ }
8094
+ };
8095
+ walkWIs(wiDir);
8096
+ }
8033
8097
  return { findings, healthy, drifted };
8034
8098
  }
8035
8099
 
@@ -8319,7 +8383,46 @@ function buildProjectExplanation(dir) {
8319
8383
  projectRoute: buildProjectRoute(dir),
8320
8384
  scanSignals: loadScanSignals(dir),
8321
8385
  metadataHealth: analyzeMetadataHealth(dir),
8322
- isModuleRepo: config != null && isModule(config)
8386
+ isModuleRepo: config != null && isModule(config),
8387
+ deliverySummary: (() => {
8388
+ const completed = workItemArtifacts.filter((a2) => lifecycleStateOf({ status: a2.status, filePath: a2.filePath }) === "completed");
8389
+ const archived = workItemArtifacts.filter((a2) => lifecycleStateOf({ status: a2.status, filePath: a2.filePath }) === "archived");
8390
+ const active = workItemArtifacts.filter((a2) => isActiveState(lifecycleStateOf({ status: a2.status, filePath: a2.filePath })));
8391
+ if (completed.length === 0 && archived.length === 0) return null;
8392
+ return {
8393
+ completedWorkItems: completed.length,
8394
+ archivedWorkItems: archived.length,
8395
+ activeWorkItems: active.length,
8396
+ implementationCompleted: completed.filter((a2) => a2.implementationStatus === "completed").length,
8397
+ releaseBlocked: completed.filter((a2) => a2.releaseStatus === "blocked").length,
8398
+ releaseReady: completed.filter((a2) => a2.releaseStatus === "ready" || a2.releaseStatus === "released").length
8399
+ };
8400
+ })(),
8401
+ implementationEvidence: workItemArtifacts.filter((a2) => a2.affectedModules.length > 0).map((a2) => {
8402
+ const fm = a2.rawFrontmatter;
8403
+ const evidence = fm.implementation_evidence;
8404
+ const repos = evidence?.repositories ?? {};
8405
+ const repoEvidence = {};
8406
+ for (const [repoId, data] of Object.entries(repos)) {
8407
+ repoEvidence[repoId] = {
8408
+ role: String(data.role ?? (repoId === "core" ? "core" : "module")),
8409
+ status: String(data.status ?? "unknown")
8410
+ };
8411
+ }
8412
+ const lc = lifecycleStateOf({ status: a2.status, filePath: a2.filePath });
8413
+ const historicalDefault = lc === "completed" || lc === "archived" ? "not-assessed" : "not-started";
8414
+ return {
8415
+ id: a2.id || a2.title,
8416
+ lifecycle: lc,
8417
+ implementationStatus: a2.implementationStatus || historicalDefault,
8418
+ validationStatus: a2.validationStatus || historicalDefault,
8419
+ releaseStatus: a2.releaseStatus || "not-assessed",
8420
+ affectedModules: a2.affectedModules,
8421
+ releaseGates: Array.isArray(fm.release_gates) ? fm.release_gates : [],
8422
+ completionExceptions: Array.isArray(fm.completion_exceptions) ? fm.completion_exceptions : [],
8423
+ repoEvidence
8424
+ };
8425
+ })
8323
8426
  };
8324
8427
  }
8325
8428
  function stateLabel(state) {
@@ -8445,6 +8548,36 @@ function renderExplanationHuman(exp) {
8445
8548
  }
8446
8549
  lines.push("");
8447
8550
  }
8551
+ if (exp.implementationEvidence.length > 0) {
8552
+ lines.push("## Implementation Evidence");
8553
+ for (const ev of exp.implementationEvidence) {
8554
+ lines.push("");
8555
+ lines.push(`### ${ev.id}`);
8556
+ lines.push(`- Lifecycle: ${ev.lifecycle.charAt(0).toUpperCase() + ev.lifecycle.slice(1)}`);
8557
+ lines.push(`- Implementation: ${ev.implementationStatus}`);
8558
+ lines.push(`- Validation: ${ev.validationStatus}`);
8559
+ lines.push(`- Release: ${ev.releaseStatus}`);
8560
+ if (Object.keys(ev.repoEvidence).length > 0) {
8561
+ lines.push("Repositories:");
8562
+ for (const [repoId, info] of Object.entries(ev.repoEvidence)) {
8563
+ lines.push(`- ${repoId} \u2014 ${info.status}`);
8564
+ }
8565
+ } else if (ev.affectedModules.length > 0) {
8566
+ lines.push(`Affected modules: ${ev.affectedModules.join(", ")}`);
8567
+ }
8568
+ const pendingGates = ev.releaseGates.filter((g) => g.status === "blocked" || g.status === "pending");
8569
+ if (pendingGates.length > 0) {
8570
+ lines.push("Pending release gates:");
8571
+ for (const g of pendingGates) lines.push(`- ${g.id}${g.reason ? ` \u2014 ${g.reason}` : ""}`);
8572
+ }
8573
+ const acceptedExceptions = ev.completionExceptions.filter((e) => e.status === "accepted" || e.status === "deferred");
8574
+ if (acceptedExceptions.length > 0) {
8575
+ lines.push("Completion exceptions:");
8576
+ for (const e of acceptedExceptions) lines.push(`- ${e.id}: ${e.status}${e.reason ? ` \u2014 ${e.reason}` : ""}`);
8577
+ }
8578
+ }
8579
+ lines.push("");
8580
+ }
8448
8581
  if (exp.domains.length > 0) {
8449
8582
  lines.push("## Domains");
8450
8583
  lines.push(`- ${exp.domains.join(", ")}`);
@@ -8527,6 +8660,17 @@ function renderExplanationHuman(exp) {
8527
8660
  }
8528
8661
  lines.push(`- Next step: ${exp.readiness.recommended_next_step.label}`);
8529
8662
  lines.push("");
8663
+ if (exp.deliverySummary) {
8664
+ const ds = exp.deliverySummary;
8665
+ lines.push("## Delivery Summary");
8666
+ lines.push(`- Completed Work Items: ${ds.completedWorkItems}`);
8667
+ if (ds.archivedWorkItems > 0) lines.push(`- Archived Work Items: ${ds.archivedWorkItems}`);
8668
+ lines.push(`- Active Work Items: ${ds.activeWorkItems}`);
8669
+ if (ds.implementationCompleted > 0) lines.push(`- Implementation completed: ${ds.implementationCompleted}`);
8670
+ if (ds.releaseBlocked > 0) lines.push(`- Release blocked: ${ds.releaseBlocked}`);
8671
+ if (ds.releaseReady > 0) lines.push(`- Release ready: ${ds.releaseReady}`);
8672
+ lines.push("");
8673
+ }
8530
8674
  const rec = exp.nextStepRecommendation;
8531
8675
  const secondary = rec.secondary ?? [];
8532
8676
  const steps = secondary.length > 0 || /Delivery|Active|Maintenance/.test(rec.phase) ? [rec.label, ...secondary.map((s2) => s2.label)] : exp.suggestedNextSteps;
@@ -8561,6 +8705,10 @@ function renderExplanationHuman(exp) {
8561
8705
  if (!exp.isModuleRepo) {
8562
8706
  lines.push(`- roadmap: ${s.roadmap}`);
8563
8707
  lines.push(`- work-items: ${s.work_items}`);
8708
+ if (exp.deliverySummary) {
8709
+ lines.push(`- work-items completed: ${exp.deliverySummary.completedWorkItems}`);
8710
+ lines.push(`- work-items active: ${exp.deliverySummary.activeWorkItems}`);
8711
+ }
8564
8712
  lines.push(`- adapters: ${s.adapters.length > 0 ? s.adapters.join(", ") + " installed" : "none installed"}`);
8565
8713
  } else {
8566
8714
  lines.push("- roadmap: managed-by-core");
@@ -9641,7 +9789,16 @@ function listWorkItems(root) {
9641
9789
  capsules: strArray(data.capsules),
9642
9790
  source,
9643
9791
  domains,
9644
- readiness
9792
+ readiness,
9793
+ ...data.implementation_status ? { implementation_status: String(data.implementation_status) } : {},
9794
+ ...data.validation_status ? { validation_status: String(data.validation_status) } : {},
9795
+ ...data.release_status ? { release_status: String(data.release_status) } : {},
9796
+ ...Array.isArray(data.affected_modules) && data.affected_modules.length > 0 ? { affected_modules: data.affected_modules.map(String) } : {},
9797
+ ...data.refined_by ? { refined_by: String(data.refined_by) } : {},
9798
+ ...data.implemented_by ? { implemented_by: String(data.implemented_by) } : {},
9799
+ ...data.closed_by ? { closed_by: String(data.closed_by) } : {},
9800
+ ...Array.isArray(data.release_gates) && data.release_gates.length > 0 ? { release_gates: data.release_gates } : {},
9801
+ ...Array.isArray(data.completion_exceptions) && data.completion_exceptions.length > 0 ? { completion_exceptions: data.completion_exceptions } : {}
9645
9802
  });
9646
9803
  }
9647
9804
  return items.sort((a2, b2) => a2.id.localeCompare(b2.id));
@@ -10063,6 +10220,13 @@ function projectStatus(root) {
10063
10220
  agents: "managed-by-core",
10064
10221
  skills: "managed-by-core"
10065
10222
  };
10223
+ } else {
10224
+ result.readiness = {
10225
+ overall: explain.readiness?.overall ?? "unknown"
10226
+ };
10227
+ }
10228
+ if (explain.deliverySummary) {
10229
+ result.deliverySummary = explain.deliverySummary;
10066
10230
  }
10067
10231
  return ok(result);
10068
10232
  }
@@ -10766,16 +10930,23 @@ var OPERATING_RULES = [
10766
10930
  "Kaddo itself never calls an LLM and never runs git \u2014 every git action is the human\u2019s."
10767
10931
  ];
10768
10932
  function toContextWorkItem(a2) {
10769
- return {
10933
+ const lifecycle = lifecycleStateOf({ status: a2.status, filePath: a2.filePath });
10934
+ const isHistorical = lifecycle === "completed" || lifecycle === "archived";
10935
+ const wi = {
10770
10936
  id: a2.id,
10771
10937
  type: a2.type,
10772
10938
  title: a2.title,
10773
10939
  status: a2.status,
10774
- lifecycle: lifecycleStateOf({ status: a2.status, filePath: a2.filePath }),
10940
+ lifecycle,
10775
10941
  knowledgeLevel: a2.knowledgeLevel,
10776
10942
  domains: a2.domains,
10777
10943
  source: parseWorkItemSource(a2.rawFrontmatter)
10778
10944
  };
10945
+ wi.implementationStatus = a2.implementationStatus || (isHistorical ? "not-assessed" : void 0);
10946
+ wi.validationStatus = a2.validationStatus || (isHistorical ? "not-assessed" : void 0);
10947
+ wi.releaseStatus = a2.releaseStatus || (isHistorical ? "not-assessed" : void 0);
10948
+ if (a2.affectedModules.length > 0) wi.affectedModules = a2.affectedModules;
10949
+ return wi;
10779
10950
  }
10780
10951
  function toContextArtifact(a2) {
10781
10952
  return { id: a2.id, type: a2.type, title: a2.title, summary: a2.summary, codeGlobs: a2.codeGlobs };
@@ -10804,10 +10975,17 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
10804
10975
  missing.push("No roadmap baseline found.");
10805
10976
  }
10806
10977
  const allArtifacts = discoverKnowledge(dir);
10807
- const workItems = allArtifacts.filter(
10808
- (a2) => isDeliveryWorkItem(a2) && isActiveState(lifecycleStateOf({ status: a2.status, filePath: a2.filePath }))
10978
+ const allWorkItemArtifacts = allArtifacts.filter((a2) => isDeliveryWorkItem(a2));
10979
+ const workItems = allWorkItemArtifacts.filter(
10980
+ (a2) => isActiveState(lifecycleStateOf({ status: a2.status, filePath: a2.filePath }))
10981
+ );
10982
+ const completedWorkItems = allWorkItemArtifacts.filter(
10983
+ (a2) => lifecycleStateOf({ status: a2.status, filePath: a2.filePath }) === "completed"
10809
10984
  );
10810
- if (workItems.length === 0 && !moduleRepo) {
10985
+ const archivedWorkItems = allWorkItemArtifacts.filter(
10986
+ (a2) => lifecycleStateOf({ status: a2.status, filePath: a2.filePath }) === "archived"
10987
+ );
10988
+ if (allWorkItemArtifacts.length === 0 && !moduleRepo) {
10811
10989
  missing.push("No work items found.");
10812
10990
  }
10813
10991
  const state = config.project.state;
@@ -10922,6 +11100,10 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
10922
11100
  roadmapSummary,
10923
11101
  inventoryAvailable,
10924
11102
  workItems: workItems.map(toContextWorkItem),
11103
+ activeWorkItems: workItems.map(toContextWorkItem),
11104
+ completedWorkItems: completedWorkItems.map(toContextWorkItem),
11105
+ archivedWorkItems: archivedWorkItems.map(toContextWorkItem),
11106
+ allWorkItems: allWorkItemArtifacts.map(toContextWorkItem),
10925
11107
  artifacts: allArtifacts.filter((a2) => a2.codeGlobs.length > 0).map(toContextArtifact)
10926
11108
  },
10927
11109
  layers,
@@ -10938,6 +11120,30 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
10938
11120
  const compact = (a2) => ({ total: a2.total, installed: a2.total - a2.missing, outdated: a2.outdated, unknown_version: a2.unknown_version, modified: a2.modified });
10939
11121
  return { version: s.version, agents: compact(s.agents), skills: compact(s.skills) };
10940
11122
  })(),
11123
+ workItemSummary: (() => {
11124
+ const lc = (s) => allWorkItemArtifacts.filter(
11125
+ (a2) => lifecycleStateOf({ status: a2.status, filePath: a2.filePath }) === s
11126
+ ).length;
11127
+ const draft = lc("draft");
11128
+ const ready = lc("ready");
11129
+ const inProgress = lc("in-progress");
11130
+ const blocked = lc("blocked");
11131
+ const completed = lc("completed");
11132
+ const archived = lc("archived");
11133
+ const active = draft + ready + inProgress + blocked;
11134
+ const total = allWorkItemArtifacts.length;
11135
+ let summary = "none";
11136
+ if (total === 0) summary = "none";
11137
+ else if (active === 0 && completed > 0 && archived === 0) summary = "completed-only";
11138
+ else if (active === 0 && archived > 0 && completed === 0) summary = "archived-only";
11139
+ else if (active === 0 && completed + archived > 0) summary = "historical-only";
11140
+ else if (inProgress > 0) summary = "active";
11141
+ else if (blocked > 0 && ready === 0 && inProgress === 0) summary = "blocked";
11142
+ else if (ready > 0) summary = "ready";
11143
+ else if (draft > 0 && ready === 0) summary = "draft-only";
11144
+ else summary = "mixed-active";
11145
+ return { total, active, draft, ready, in_progress: inProgress, blocked, completed, archived, summary };
11146
+ })(),
10941
11147
  deliveryMix,
10942
11148
  external: loadExternalCapsules(dir),
10943
11149
  graph: loadGraphSummary(dir),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/mcp",
3
- "version": "3.65.0",
3
+ "version": "3.67.0",
4
4
  "description": "MCP server for Kaddo project knowledge: read-only resources/tools/prompts plus safe derived generation under .kaddo/.",
5
5
  "license": "MIT",
6
6
  "repository": {