@kaddo/mcp 3.52.0 → 3.54.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 +115 -12
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -274,7 +274,7 @@ function join(...parts) {
274
274
  }
275
275
 
276
276
  // ../cli/src/core/impact-report.ts
277
- import matter7 from "gray-matter";
277
+ import matter8 from "gray-matter";
278
278
 
279
279
  // ../cli/src/core/config.ts
280
280
  import { z } from "zod";
@@ -2496,9 +2496,6 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
2496
2496
  if (!exists(join(dir, ".kaddo", "context-pack.md"))) {
2497
2497
  return { id: "context", phase: "Discovery", label: "Run `kaddo context` to prepare the LLM context pack.", command: "kaddo context", reason: "No context pack has been generated yet." };
2498
2498
  }
2499
- if (!exists(join(dir, ".kaddo", "understand.md"))) {
2500
- return { id: "understand", phase: "Discovery", label: "Run `kaddo understand` to summarize the project context.", command: "kaddo understand", reason: "No understand handoff has been generated yet." };
2501
- }
2502
2499
  const discovery = state === "pre-ai" || state === "legacy";
2503
2500
  const resolveAgent = (agent) => {
2504
2501
  const file = agent.endsWith(".md") ? agent : `${agent}.md`;
@@ -2538,6 +2535,9 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
2538
2535
  const agent = ctx.agents.includes("codebase-agent") ? "codebase-agent" : "architecture-agent";
2539
2536
  return refine("refine-codebase", agent, CB, qCodebase);
2540
2537
  }
2538
+ if (!exists(join(dir, ".kaddo", "understand.md"))) {
2539
+ return { id: "understand", phase: "Discovery", label: "Run `kaddo understand` to summarize the project context.", command: "kaddo understand", reason: "No understand handoff has been generated yet." };
2540
+ }
2541
2541
  const oq = buildOpenQuestionsReport(dir, now);
2542
2542
  if (oq.summary.blocking_open > 0) {
2543
2543
  return { id: "questions", phase: "Knowledge Refinement", label: "Run `kaddo questions` to see source locations and resolution guidance, then resolve, assume or defer the blocking open questions.", command: "kaddo questions", reason: `${oq.summary.blocking_open} blocking open question(s) remain.` };
@@ -3445,16 +3445,49 @@ function renderSkillsSection(agent) {
3445
3445
  ""
3446
3446
  ].join("\n");
3447
3447
  }
3448
+ var KNOWLEDGE_REFINING_AGENTS = {
3449
+ "business-agent": "business-agent",
3450
+ "capability-agent": "capability-agent",
3451
+ "bootstrap-agent": "bootstrap-agent",
3452
+ "codebase-agent": "codebase-agent",
3453
+ "architecture-agent": "architecture-agent",
3454
+ "roadmap-agent": "roadmap-agent",
3455
+ "legacy-agent": "legacy-agent",
3456
+ "work-item-agent": "work-item-agent",
3457
+ "backlog-agent": "backlog-agent",
3458
+ "adr-agent": "adr-agent",
3459
+ "implementation-agent": "implementation-agent"
3460
+ };
3461
+ function renderFrontmatterRules(agent) {
3462
+ if (!KNOWLEDGE_REFINING_AGENTS[agent]) return "";
3463
+ return [
3464
+ "## Frontmatter Rules",
3465
+ "",
3466
+ "When rewriting an existing Kaddo knowledge file:",
3467
+ "",
3468
+ "- Preserve the existing YAML frontmatter.",
3469
+ "- Do not remove `type`, `generated_by`, or `template_version`.",
3470
+ "- If the document is no longer a placeholder, set `project_state: ai-assisted`.",
3471
+ `- Add or update \`refined_by: ${agent}\`.`,
3472
+ "- Preserve unknown frontmatter keys \u2014 do not strip fields you do not recognize.",
3473
+ "- Only rewrite the markdown body unless metadata changes are explicitly required by these rules.",
3474
+ "- Preserve structural sections like `## Open Questions` \u2014 leave them empty rather than removing them.",
3475
+ ""
3476
+ ].join("\n");
3477
+ }
3448
3478
  function withResponsibilityTrace(fileName, content) {
3449
3479
  const agent = fileName.replace(/\.md$/, "");
3450
3480
  if (!RESPONSIBILITY_MATRIX[agent]) return content;
3451
3481
  const skills = renderSkillsSection(agent);
3452
3482
  const skillsBlock = skills ? `${skills}
3483
+ ` : "";
3484
+ const frontmatter = renderFrontmatterRules(agent);
3485
+ const frontmatterBlock = frontmatter ? `${frontmatter}
3453
3486
  ` : "";
3454
3487
  return `${content.trimEnd()}
3455
3488
 
3456
3489
  ${renderLanguageRule()}
3457
- ${renderAgentBoundaries(agent)}
3490
+ ${frontmatterBlock}${renderAgentBoundaries(agent)}
3458
3491
  ${skillsBlock}${renderAgentTrace(agent)}`;
3459
3492
  }
3460
3493
 
@@ -5986,7 +6019,6 @@ function mapNextStepId(id) {
5986
6019
  "add-skills": "enable-kaddo",
5987
6020
  scan: "scan-repository",
5988
6021
  context: "scan-repository",
5989
- understand: "scan-repository",
5990
6022
  "refine-business": "define-business",
5991
6023
  "refine-product": "define-product",
5992
6024
  "refine-capabilities": "discover-capabilities",
@@ -6074,6 +6106,54 @@ function renderRouteCompact(route) {
6074
6106
  return lines.join("\n");
6075
6107
  }
6076
6108
 
6109
+ // ../cli/src/core/metadata-health.ts
6110
+ import matter7 from "gray-matter";
6111
+ var KNOWLEDGE_FILES2 = [
6112
+ "knowledge/business/business.md",
6113
+ "knowledge/product/product.md",
6114
+ "knowledge/product/capabilities.md",
6115
+ "knowledge/tech/codebase.md",
6116
+ "knowledge/tech/current-state.md",
6117
+ "knowledge/delivery/roadmap.md"
6118
+ ];
6119
+ var REQUIRED_FIELDS = ["type", "generated_by", "template_version"];
6120
+ function analyzeMetadataHealth(dir) {
6121
+ const findings = [];
6122
+ let healthy = 0;
6123
+ let drifted = 0;
6124
+ for (const rel of KNOWLEDGE_FILES2) {
6125
+ const p = join(dir, rel);
6126
+ if (!exists(p)) continue;
6127
+ let data;
6128
+ try {
6129
+ const raw = readFile(p);
6130
+ data = matter7(raw).data;
6131
+ } catch {
6132
+ continue;
6133
+ }
6134
+ if (Object.keys(data).length === 0) continue;
6135
+ let fileDrifted = false;
6136
+ for (const field of REQUIRED_FIELDS) {
6137
+ if (data[field] === void 0 || data[field] === null || data[field] === "") {
6138
+ findings.push({ file: rel, field, issue: "missing", detail: `Missing \`${field}\` in frontmatter.` });
6139
+ fileDrifted = true;
6140
+ }
6141
+ }
6142
+ if (data.refined_by && data.project_state && data.project_state !== "ai-assisted") {
6143
+ findings.push({
6144
+ file: rel,
6145
+ field: "project_state",
6146
+ issue: "inconsistent",
6147
+ detail: `File has \`refined_by: ${data.refined_by}\` but \`project_state\` is \`${data.project_state}\`, expected \`ai-assisted\`.`
6148
+ });
6149
+ fileDrifted = true;
6150
+ }
6151
+ if (fileDrifted) drifted++;
6152
+ else healthy++;
6153
+ }
6154
+ return { findings, healthy, drifted };
6155
+ }
6156
+
6077
6157
  // ../cli/src/core/project-explain.ts
6078
6158
  var ARCH_DIR2 = "knowledge";
6079
6159
  function normalizeTitle(t) {
@@ -6336,7 +6416,8 @@ function buildProjectExplanation(dir) {
6336
6416
  installedAssets: installedAssetsSummary(dir),
6337
6417
  roadmapQuality: buildRoadmapQuality(dir),
6338
6418
  projectRoute: buildProjectRoute(dir),
6339
- scanSignals: loadScanSignals(dir)
6419
+ scanSignals: loadScanSignals(dir),
6420
+ metadataHealth: analyzeMetadataHealth(dir)
6340
6421
  };
6341
6422
  }
6342
6423
  function stateLabel(state) {
@@ -6645,6 +6726,13 @@ function renderExplanationHuman(exp) {
6645
6726
  }
6646
6727
  lines.push("");
6647
6728
  }
6729
+ if (exp.metadataHealth.findings.length > 0) {
6730
+ lines.push("## Metadata Health");
6731
+ for (const f of exp.metadataHealth.findings) {
6732
+ lines.push(`- \`${f.file}\`: ${f.detail}`);
6733
+ }
6734
+ lines.push("");
6735
+ }
6648
6736
  return lines.join("\n").trimEnd() + "\n";
6649
6737
  }
6650
6738
  function renderExplanationAgent(exp) {
@@ -6844,7 +6932,7 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
6844
6932
  }
6845
6933
  }
6846
6934
  try {
6847
- const body = matter7(readFile(wi.filePath)).content;
6935
+ const body = matter8(readFile(wi.filePath)).content;
6848
6936
  if (hasSection(body, /acceptance|criterios de aceptaci/i)) withAcceptance++;
6849
6937
  else gaps.missing_acceptance_criteria.push(gapItem(wi, "Add an `## Acceptance Criteria` section."));
6850
6938
  if (hasSection(body, /definition of done|^#{1,6}\s*dod\b|definici[oó]n de (terminado|hecho)/i)) withDoD++;
@@ -7557,7 +7645,7 @@ function serializeDriftJson(r) {
7557
7645
  }
7558
7646
 
7559
7647
  // src/workitems.ts
7560
- import matter8 from "gray-matter";
7648
+ import matter9 from "gray-matter";
7561
7649
  var VALID_SOURCES2 = /* @__PURE__ */ new Set(["manual", "roadmap", "jira", "github", "notion", "xlsx", "csv", "api", "external", "unknown"]);
7562
7650
  function optStr2(v) {
7563
7651
  return typeof v === "string" && v.trim() ? v.trim() : void 0;
@@ -7598,7 +7686,7 @@ function listWorkItems(root) {
7598
7686
  if (raw === null) continue;
7599
7687
  let parsed;
7600
7688
  try {
7601
- parsed = matter8(raw);
7689
+ parsed = matter9(raw);
7602
7690
  } catch {
7603
7691
  continue;
7604
7692
  }
@@ -8061,7 +8149,7 @@ function listGraphHints(root, filter = {}) {
8061
8149
  }
8062
8150
 
8063
8151
  // ../cli/src/core/context-pack.ts
8064
- import matter9 from "gray-matter";
8152
+ import matter10 from "gray-matter";
8065
8153
  var CONTEXT_PACK_VERSION = "1";
8066
8154
  var ARCH_DIR3 = "knowledge";
8067
8155
  function readScanJson(dir) {
@@ -8074,7 +8162,7 @@ function readScanJson(dir) {
8074
8162
  }
8075
8163
  }
8076
8164
  function firstParagraph3(markdown) {
8077
- const body = matter9(markdown).content.trim();
8165
+ const body = matter10(markdown).content.trim();
8078
8166
  const para = body.split("\n\n").map((p) => p.trim()).find((p) => p && !p.startsWith("#"));
8079
8167
  return para ?? "";
8080
8168
  }
@@ -8289,6 +8377,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
8289
8377
  skills: discoverInstalledSkills(dir).map((s) => s.id),
8290
8378
  scanSignals: scanJson?.signals ?? null,
8291
8379
  projectRoute: buildProjectRoute(dir),
8380
+ metadataHealth: analyzeMetadataHealth(dir),
8292
8381
  mappedModules,
8293
8382
  missing,
8294
8383
  // VS-052/VS-073.2: the handoff is driven by the unified next step, so the pack never contradicts
@@ -8577,6 +8666,13 @@ function renderContextPack(pack) {
8577
8666
  } else {
8578
8667
  parts.push("_None \u2014 all expected context is present._\n");
8579
8668
  }
8669
+ if (pack.metadataHealth.findings.length > 0) {
8670
+ parts.push("\n### Metadata Health\n");
8671
+ for (const f of pack.metadataHealth.findings) {
8672
+ parts.push(`- \`${f.file}\`: ${f.detail}
8673
+ `);
8674
+ }
8675
+ }
8580
8676
  parts.push("## Recommended Agent Handoff\n");
8581
8677
  if (isBootstrapIncomplete) {
8582
8678
  parts.push("No agent handoff yet.\n");
@@ -8884,6 +8980,13 @@ function renderUnderstand(plan) {
8884
8980
  } else {
8885
8981
  parts.push("Re-run `kaddo understand` any time to see this plan again.\n");
8886
8982
  }
8983
+ if (plan.metadataHealth && plan.metadataHealth.findings.length > 0) {
8984
+ parts.push("## Metadata Health\n");
8985
+ for (const f of plan.metadataHealth.findings) {
8986
+ parts.push(`- \`${f.file}\`: ${f.detail}
8987
+ `);
8988
+ }
8989
+ }
8887
8990
  return parts.join("\n");
8888
8991
  }
8889
8992
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/mcp",
3
- "version": "3.52.0",
3
+ "version": "3.54.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": {