@kaddo/mcp 3.39.0 → 3.40.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 +91 -2
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1505,6 +1505,9 @@ function isPlaceholderLine(line) {
1505
1505
  if (/<[^>]+>/.test(t)) return true;
1506
1506
  if (/^[-*]\s+[^:]+:\s*$/.test(t)) return true;
1507
1507
  if (/^[-*]\s+[^:]+:\s*\S.*\s\|\s/.test(t)) return true;
1508
+ if (/^\*\*[^*]+:\*\*\s*$/.test(t)) return true;
1509
+ if (/^\*\*[^*]+:\*\*\s*_.*_$/.test(t)) return true;
1510
+ if (/^\*\*[^*]+:\*\*\s*\S.*\s\|\s/.test(t)) return true;
1508
1511
  return false;
1509
1512
  }
1510
1513
  function isStructuralLine(line, inFrontMatter) {
@@ -2310,7 +2313,7 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
2310
2313
  if (qBusiness !== "useful") return refine("refine-business", "business-agent", B, qBusiness);
2311
2314
  if (qProduct !== "useful" || qCap !== "useful") {
2312
2315
  if (qCap !== "useful") {
2313
- return refine("refine-product", "capability-agent", CAP, qCap, discovery ? "discover and document existing system capabilities in" : "complete");
2316
+ return refine("refine-product", "capability-agent", CAP, qCap, discovery ? "discover and document existing system capabilities grouped by functional domains in" : "complete");
2314
2317
  }
2315
2318
  return refine("refine-product", "capability-agent", P, qProduct);
2316
2319
  }
@@ -2430,6 +2433,76 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
2430
2433
  };
2431
2434
  }
2432
2435
 
2436
+ // ../cli/src/core/decisions.ts
2437
+ var CANDIDATES_PATH = "knowledge/tech/decision-candidates.md";
2438
+ var DECISIONS_DIR = "knowledge/tech/decisions";
2439
+ function slugify(s) {
2440
+ return s.toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60);
2441
+ }
2442
+ function parseDecisionCandidates(md) {
2443
+ const out = [];
2444
+ for (const line of md.split(/\r?\n/)) {
2445
+ const m = line.match(/^##\s+(.+?)\s*$/);
2446
+ if (m) {
2447
+ const t = m[1].trim();
2448
+ if (t && !/^_.*_$/.test(t)) out.push(t);
2449
+ }
2450
+ }
2451
+ return out;
2452
+ }
2453
+ function countAdrs(dir) {
2454
+ const base = join(dir, DECISIONS_DIR);
2455
+ if (!exists(base)) return { total: 0, draft: 0, accepted: 0 };
2456
+ let total = 0;
2457
+ let draft = 0;
2458
+ let accepted = 0;
2459
+ for (const entry of readDir(base)) {
2460
+ if (!entry.endsWith(".md") || entry === ".gitkeep") continue;
2461
+ const full = join(base, entry);
2462
+ if (!isFile(full)) continue;
2463
+ total += 1;
2464
+ let content = "";
2465
+ try {
2466
+ content = readFile(full);
2467
+ } catch {
2468
+ continue;
2469
+ }
2470
+ const status = content.match(/^\s*status:\s*([a-z-]+)/im)?.[1]?.toLowerCase();
2471
+ if (status === "accepted") accepted += 1;
2472
+ else draft += 1;
2473
+ }
2474
+ return { total, draft, accepted };
2475
+ }
2476
+ function buildTechDecisions(dir) {
2477
+ const candFile = join(dir, CANDIDATES_PATH);
2478
+ let titles = [];
2479
+ if (exists(candFile)) {
2480
+ try {
2481
+ titles = parseDecisionCandidates(readFile(candFile));
2482
+ } catch {
2483
+ titles = [];
2484
+ }
2485
+ }
2486
+ const { total, draft, accepted } = countAdrs(dir);
2487
+ const candidate_list = titles.map((title, i) => {
2488
+ const n = String(total + i + 1).padStart(3, "0");
2489
+ return { title, source: CANDIDATES_PATH, suggestedAdrFile: `${DECISIONS_DIR}/ADR-${n}-${slugify(title)}.md` };
2490
+ });
2491
+ let status;
2492
+ if (accepted > 0) status = "accepted-adrs";
2493
+ else if (total > 0) status = "draft-adrs";
2494
+ else if (titles.length > 0) status = "candidates";
2495
+ else status = "none";
2496
+ return {
2497
+ status,
2498
+ candidates: titles.length,
2499
+ adrs: total,
2500
+ draft_adrs: draft,
2501
+ accepted_adrs: accepted,
2502
+ candidate_list
2503
+ };
2504
+ }
2505
+
2433
2506
  // ../cli/src/core/project-explain.ts
2434
2507
  var ARCH_DIR2 = "knowledge";
2435
2508
  function normalizeTitle(t) {
@@ -2641,7 +2714,8 @@ function buildProjectExplanation(dir) {
2641
2714
  missingKnowledge,
2642
2715
  suggestedNextSteps,
2643
2716
  readiness,
2644
- nextStepRecommendation: readiness.nextStepRecommendation
2717
+ nextStepRecommendation: readiness.nextStepRecommendation,
2718
+ techDecisions: buildTechDecisions(dir)
2645
2719
  };
2646
2720
  }
2647
2721
  function stateLabel(state) {
@@ -2855,6 +2929,16 @@ function renderExplanationHuman(exp) {
2855
2929
  lines.push("### Recommended next step");
2856
2930
  lines.push(r.recommended_next_step.label);
2857
2931
  lines.push("");
2932
+ const td = exp.techDecisions;
2933
+ lines.push("## Tech Decisions");
2934
+ lines.push(`- Decision candidates: ${td.candidates}`);
2935
+ lines.push(`- ADRs: ${td.adrs} (draft: ${td.draft_adrs}, accepted: ${td.accepted_adrs})`);
2936
+ lines.push(`- Status: ${td.status}`);
2937
+ if (td.candidates > 0 && td.adrs === 0) {
2938
+ lines.push("");
2939
+ lines.push("Use the adr-writing skill to materialize decision candidates into ADRs (`kaddo adr`) before implementing related technical Work Items.");
2940
+ }
2941
+ lines.push("");
2858
2942
  return lines.join("\n").trimEnd() + "\n";
2859
2943
  }
2860
2944
  function renderExplanationAgent(exp) {
@@ -4310,6 +4394,10 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
4310
4394
  }
4311
4395
  });
4312
4396
  const nextStepRecommendation = resolveNextStep(dir, now);
4397
+ const techDecisions = buildTechDecisions(dir);
4398
+ if (techDecisions.candidates > 0 && techDecisions.adrs === 0) {
4399
+ missing.push(`${techDecisions.candidates} technical decision candidate(s) not yet materialized as ADRs (run \`kaddo adr\`).`);
4400
+ }
4313
4401
  const unifiedPhase = {
4314
4402
  ...phase,
4315
4403
  nextStep: nextStepRecommendation.label,
@@ -4347,6 +4435,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
4347
4435
  roadmap,
4348
4436
  phase: unifiedPhase,
4349
4437
  nextStepRecommendation,
4438
+ techDecisions,
4350
4439
  deliveryMix,
4351
4440
  external: loadExternalCapsules(dir),
4352
4441
  graph: loadGraphSummary(dir),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/mcp",
3
- "version": "3.39.0",
3
+ "version": "3.40.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": {