@kaddo/mcp 3.35.0 → 3.37.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 +147 -21
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -502,14 +502,23 @@ function discoverWorkItems(dir) {
502
502
  function layer(layers, name) {
503
503
  return layers.find((l) => l.layer === name)?.status ?? "Missing";
504
504
  }
505
+ var NOT_READY_LAYER = ["Missing", "Placeholder", "Weak"];
505
506
  function baseComplete(layers) {
506
507
  return layer(layers, "Business") !== "Missing" && layer(layers, "Product") !== "Missing" && layer(layers, "Tech") !== "Missing";
507
508
  }
509
+ function baseUseful(layers) {
510
+ return ["Business", "Product", "Tech"].every((n) => !NOT_READY_LAYER.includes(layer(layers, n)));
511
+ }
512
+ function roadmapHasCandidates(roadmap) {
513
+ return roadmap.candidates > 0 || roadmap.remaining > 0;
514
+ }
508
515
  function determinePhase(input) {
509
516
  const { roadmap, workItems } = input;
510
517
  const active = workItems.byState.draft + workItems.byState.ready + workItems.byState["in-progress"] + workItems.byState.blocked;
511
518
  if (!baseComplete(input.layers)) return "Discovery";
519
+ if (!baseUseful(input.layers)) return "Knowledge Refinement";
512
520
  if (!roadmap.present) return "Planning";
521
+ if (!roadmapHasCandidates(roadmap) && workItems.total === 0) return "Planning";
513
522
  if (workItems.total === 0) return "Delivery Preparation";
514
523
  if (active > 0) return "Active Delivery";
515
524
  return "Maintenance";
@@ -539,6 +548,14 @@ function firstMissingLayerAgent(layers) {
539
548
  return { agent: "capability-agent", step: "Use capability-agent to create knowledge/product/capabilities.md" };
540
549
  return { agent: "architecture-agent", step: "Use architecture-agent to create knowledge/tech/current-state.md" };
541
550
  }
551
+ function firstUnrefinedLayerAgent(layers) {
552
+ const isThin = (n) => NOT_READY_LAYER.includes(layer(layers, n));
553
+ if (isThin("Business"))
554
+ return { agent: "business-agent", step: "Use business-agent to complete knowledge/business/business.md" };
555
+ if (isThin("Product"))
556
+ return { agent: "capability-agent", step: "Use capability-agent to complete knowledge/product/capabilities.md" };
557
+ return { agent: "architecture-agent", step: "Use architecture-agent to complete knowledge/tech/current-state.md" };
558
+ }
542
559
  function assessPhase(input) {
543
560
  const phase = determinePhase(input);
544
561
  const reasons = buildReasons(input);
@@ -556,6 +573,17 @@ function assessPhase(input) {
556
573
  llmInstructions = [`Use the ${m.agent} to fill the missing base knowledge.`, "Do not write code."];
557
574
  break;
558
575
  }
576
+ case "Knowledge Refinement": {
577
+ const m = firstUnrefinedLayerAgent(input.layers);
578
+ recommendedAgents = [m.agent];
579
+ nextStep = m.step;
580
+ llmInstructions = [
581
+ "The baseline files exist but still look like bootstrap placeholders.",
582
+ `Use the ${m.agent} to replace the placeholders with real, project-specific knowledge.`,
583
+ "Do not write code."
584
+ ];
585
+ break;
586
+ }
559
587
  case "Planning": {
560
588
  recommendedAgents = ["roadmap-agent"];
561
589
  nextStep = "Use roadmap-agent to create knowledge/delivery/roadmap.md";
@@ -1467,9 +1495,97 @@ function statusFor(layer2, a) {
1467
1495
  return "Missing";
1468
1496
  }
1469
1497
 
1498
+ // ../cli/src/core/artifact-quality.ts
1499
+ function isPlaceholderLine(line) {
1500
+ const t = line.trim();
1501
+ if (/^_.+_$/.test(t)) return true;
1502
+ if (/^[-*]\s+(\[[^\]]+\]\s*)?_.+_$/.test(t)) return true;
1503
+ if (/^[-*]\s+\[[^\]]+\]\s*$/.test(t)) return true;
1504
+ if (/^_(?:Describe|List|Document|What|Which|Who|Use|To be defined|No production code)\b/i.test(t)) return true;
1505
+ return false;
1506
+ }
1507
+ function isStructuralLine(line, inFrontMatter) {
1508
+ const t = line.trim();
1509
+ if (inFrontMatter) return true;
1510
+ if (t === "") return true;
1511
+ if (/^#{1,6}\s/.test(t)) return true;
1512
+ if (/^<!--/.test(t)) return true;
1513
+ if (/^>/.test(t)) return true;
1514
+ return false;
1515
+ }
1516
+ function analyzeContent(md) {
1517
+ const lines = md.split(/\r?\n/);
1518
+ let inFrontMatter = false;
1519
+ let seenFmFence = 0;
1520
+ let currentSectionHasUseful = false;
1521
+ const sectionsWithUseful = /* @__PURE__ */ new Set();
1522
+ let sectionIndex = 0;
1523
+ const contentLines = [];
1524
+ const usefulLines = [];
1525
+ for (const raw of lines) {
1526
+ const t = raw.trim();
1527
+ if (t === "---" && seenFmFence < 2) {
1528
+ seenFmFence += 1;
1529
+ inFrontMatter = seenFmFence === 1;
1530
+ continue;
1531
+ }
1532
+ if (seenFmFence === 1) continue;
1533
+ if (/^#{1,6}\s/.test(t)) {
1534
+ sectionIndex += 1;
1535
+ currentSectionHasUseful = false;
1536
+ continue;
1537
+ }
1538
+ if (isStructuralLine(raw, false)) continue;
1539
+ contentLines.push(t);
1540
+ if (!isPlaceholderLine(raw)) {
1541
+ usefulLines.push(t);
1542
+ if (!currentSectionHasUseful) {
1543
+ currentSectionHasUseful = true;
1544
+ sectionsWithUseful.add(sectionIndex);
1545
+ }
1546
+ }
1547
+ }
1548
+ if (usefulLines.length === 0) return "placeholder";
1549
+ const usefulWordCount = usefulLines.join(" ").split(/\s+/).filter(Boolean).length;
1550
+ const placeholderRatio = contentLines.length > 0 ? (contentLines.length - usefulLines.length) / contentLines.length : 1;
1551
+ if (usefulWordCount >= 80 && placeholderRatio < 0.25 && sectionsWithUseful.size >= 2) return "useful";
1552
+ return "weak";
1553
+ }
1554
+ function analyzeKnowledgeArtifact(dir, rel) {
1555
+ const p = join(dir, rel);
1556
+ if (!exists(p)) return "missing";
1557
+ try {
1558
+ return analyzeContent(readFile(p));
1559
+ } catch {
1560
+ return "missing";
1561
+ }
1562
+ }
1563
+
1470
1564
  // ../cli/src/core/layers.ts
1565
+ var LAYER_BASELINE = {
1566
+ Business: ["knowledge/business/business.md"],
1567
+ Product: ["knowledge/product/product.md", "knowledge/product/capabilities.md"],
1568
+ Tech: ["knowledge/tech/codebase.md", "knowledge/tech/current-state.md"],
1569
+ Delivery: ["knowledge/delivery/roadmap.md"]
1570
+ };
1571
+ function layerQuality(dir, layer2) {
1572
+ const order = ["missing", "placeholder", "weak", "useful"];
1573
+ let worst = null;
1574
+ for (const rel of LAYER_BASELINE[layer2]) {
1575
+ const q = analyzeKnowledgeArtifact(dir, rel);
1576
+ if (q === "missing") continue;
1577
+ if (worst === null || order.indexOf(q) < order.indexOf(worst)) worst = q;
1578
+ }
1579
+ return worst;
1580
+ }
1471
1581
  function knowledgeLayers(dir) {
1472
- return discoverLayers(dir);
1582
+ return discoverLayers(dir).map((l) => {
1583
+ if (l.status !== "Consolidated" && l.status !== "Structured") return l;
1584
+ const q = layerQuality(dir, l.layer);
1585
+ if (q === "placeholder") return { ...l, status: "Placeholder" };
1586
+ if (q === "weak") return { ...l, status: "Weak" };
1587
+ return l;
1588
+ });
1473
1589
  }
1474
1590
  function renderLayersMarkdown(layers) {
1475
1591
  const lines = [];
@@ -2104,24 +2220,12 @@ function buildAdapterStatuses(dir) {
2104
2220
 
2105
2221
  // ../cli/src/core/readiness.ts
2106
2222
  var KNOWLEDGE_FILES = [
2107
- { key: "current_state", path: "knowledge/tech/current-state.md", label: "knowledge/tech/current-state.md" },
2108
- { key: "codebase", path: "knowledge/tech/codebase.md", label: "knowledge/tech/codebase.md" },
2109
- { key: "capabilities", path: "knowledge/product/capabilities.md", label: "knowledge/product/capabilities.md" },
2110
- { key: "product", path: "knowledge/product/product.md", label: "knowledge/product/product.md" },
2111
- { key: "business", path: "knowledge/business/business.md", label: "knowledge/business/business.md" }
2223
+ { key: "current_state", path: "knowledge/tech/current-state.md", label: "knowledge/tech/current-state.md", agent: "architecture-agent" },
2224
+ { key: "codebase", path: "knowledge/tech/codebase.md", label: "knowledge/tech/codebase.md", agent: "codebase-agent" },
2225
+ { key: "capabilities", path: "knowledge/product/capabilities.md", label: "knowledge/product/capabilities.md", agent: "capability-agent" },
2226
+ { key: "product", path: "knowledge/product/product.md", label: "knowledge/product/product.md", agent: "product-agent" },
2227
+ { key: "business", path: "knowledge/business/business.md", label: "knowledge/business/business.md", agent: "business-agent" }
2112
2228
  ];
2113
- function knowledgePresence(dir, rel) {
2114
- const p = join(dir, rel);
2115
- if (!exists(p)) return "missing";
2116
- let md;
2117
- try {
2118
- md = readFile(p);
2119
- } catch {
2120
- return "missing";
2121
- }
2122
- const body = md.replace(/^---[\s\S]*?---/m, "").split(/\r?\n/).filter((l) => !/^\s*#{1,6}\s/.test(l) && !/^\s*$/.test(l) && !/^\s*<!--/.test(l)).join(" ").trim();
2123
- return body.length >= 40 ? "present" : "weak";
2124
- }
2125
2229
  function roadmapSignal(dir) {
2126
2230
  const p = join(dir, "knowledge/delivery/roadmap.md");
2127
2231
  if (!exists(p)) return "missing";
@@ -2184,7 +2288,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
2184
2288
  if (config.project.state === "legacy") return stub("legacy-project", "Use the legacy project flow.");
2185
2289
  const scan = exists(join(dir, ".kaddo", "scan.json")) ? "available" : "missing";
2186
2290
  const understand = exists(join(dir, ".kaddo", "understand.md")) ? "available" : "missing";
2187
- const presence = Object.fromEntries(KNOWLEDGE_FILES.map((f) => [f.key, knowledgePresence(dir, f.path)]));
2291
+ const presence = Object.fromEntries(KNOWLEDGE_FILES.map((f) => [f.key, analyzeKnowledgeArtifact(dir, f.path)]));
2188
2292
  const ctx = buildCodexAdapterContext(dir);
2189
2293
  const agents = ctx.hasAgents ? "present" : "missing";
2190
2294
  const skills = ctx.hasSkills ? "present" : "missing";
@@ -2214,7 +2318,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
2214
2318
  };
2215
2319
  let overall;
2216
2320
  let next;
2217
- const firstWeak = KNOWLEDGE_FILES.find((f) => presence[f.key] !== "present");
2321
+ const firstWeak = KNOWLEDGE_FILES.find((f) => presence[f.key] !== "useful");
2218
2322
  if (scan === "missing") {
2219
2323
  overall = "initialized";
2220
2324
  next = { label: "Run `kaddo scan` to capture deterministic signals from the existing code.", command: "kaddo scan" };
@@ -2232,7 +2336,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
2232
2336
  next = { label: "Run `kaddo understand` to summarize the project context.", command: "kaddo understand" };
2233
2337
  } else if (firstWeak) {
2234
2338
  overall = "knowledge-incomplete";
2235
- next = { label: `Complete \`${firstWeak.label}\` (it is ${presence[firstWeak.key]}).` };
2339
+ next = { label: `Use ${firstWeak.agent} to complete \`${firstWeak.label}\` (it is ${presence[firstWeak.key]}).` };
2236
2340
  } else if (oq.summary.blocking_open > 0) {
2237
2341
  overall = "needs-decisions";
2238
2342
  next = { label: "Resolve, assume or defer the blocking open questions (`kaddo questions`).", command: "kaddo questions" };
@@ -2656,6 +2760,9 @@ function renderExplanationHuman(exp) {
2656
2760
  lines.push(`- understand: ${s.understand}`);
2657
2761
  lines.push(`- agents: ${s.agents}`);
2658
2762
  lines.push(`- skills: ${s.skills}`);
2763
+ lines.push(`- business: ${s.business}`);
2764
+ lines.push(`- product: ${s.product}`);
2765
+ lines.push(`- capabilities: ${s.capabilities}`);
2659
2766
  lines.push(`- current-state: ${s.current_state}`);
2660
2767
  lines.push(`- codebase: ${s.codebase}`);
2661
2768
  lines.push(`- capabilities: ${s.capabilities}`);
@@ -4106,6 +4213,24 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
4106
4213
  }
4107
4214
  const mappedModules = loadMappedModules(dir);
4108
4215
  const layers = knowledgeLayers(dir);
4216
+ const qa = (rel) => analyzeKnowledgeArtifact(dir, rel);
4217
+ const qBusiness = qa("knowledge/business/business.md");
4218
+ const qProduct = qa("knowledge/product/product.md");
4219
+ const qCapabilities = qa("knowledge/product/capabilities.md");
4220
+ const qCodebase = qa("knowledge/tech/codebase.md");
4221
+ const qCurrentState = qa("knowledge/tech/current-state.md");
4222
+ const qRoadmap = qa("knowledge/delivery/roadmap.md");
4223
+ const layerStatusOf = (name) => layers.find((l) => l.layer === name)?.status ?? "Missing";
4224
+ const knowledgeQuality = {
4225
+ business: { status: layerStatusOf("Business"), artifacts: { "knowledge/business/business.md": qBusiness } },
4226
+ product: { status: layerStatusOf("Product"), artifacts: { "knowledge/product/product.md": qProduct, "knowledge/product/capabilities.md": qCapabilities } },
4227
+ tech: { status: layerStatusOf("Tech"), artifacts: { "knowledge/tech/codebase.md": qCodebase, "knowledge/tech/current-state.md": qCurrentState } },
4228
+ delivery: { status: layerStatusOf("Delivery"), artifacts: { "knowledge/delivery/roadmap.md": qRoadmap } }
4229
+ };
4230
+ if (qBusiness === "placeholder") missing.push("Business context exists but still looks like a bootstrap placeholder.");
4231
+ if (qProduct === "placeholder" || qCapabilities === "placeholder") missing.push("Product capabilities exist but still look like a bootstrap placeholder.");
4232
+ if (qCurrentState === "placeholder") missing.push("Current state exists but still looks like a bootstrap placeholder.");
4233
+ if (qCodebase === "placeholder") missing.push("Codebase map exists but still looks like a bootstrap placeholder.");
4109
4234
  const allWorkItems = allArtifacts.filter((a) => a.isWorkItem);
4110
4235
  const wiWithOwnership = allWorkItems.filter((a) => a.codeGlobs.length > 0).length;
4111
4236
  const phase = assessPhase({
@@ -4156,6 +4281,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
4156
4281
  artifacts: allArtifacts.filter((a) => a.codeGlobs.length > 0).map(toContextArtifact)
4157
4282
  },
4158
4283
  layers,
4284
+ knowledgeQuality,
4159
4285
  roadmap,
4160
4286
  phase,
4161
4287
  deliveryMix,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/mcp",
3
- "version": "3.35.0",
3
+ "version": "3.37.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": {