@kaddo/mcp 3.39.1 → 3.40.1

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 +104 -1
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2433,6 +2433,81 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
2433
2433
  };
2434
2434
  }
2435
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 cleanCandidateTitle(title) {
2440
+ return title.replace(/^\s*#{1,6}\s+/, "").replace(/^\s*[-*]\s+/, "").replace(/^\s*\(?\d+\)?[.):]\s+/, "").trim();
2441
+ }
2442
+ function slugify(s) {
2443
+ return cleanCandidateTitle(s).toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "").slice(0, 70).replace(/-+$/g, "");
2444
+ }
2445
+ function parseDecisionCandidates(md) {
2446
+ const out = [];
2447
+ for (const line of md.split(/\r?\n/)) {
2448
+ const m = line.match(/^##\s+(.+?)\s*$/);
2449
+ if (m) {
2450
+ const raw = m[1].trim();
2451
+ if (!raw || /^_.*_$/.test(raw)) continue;
2452
+ const t = cleanCandidateTitle(raw);
2453
+ if (t) out.push(t);
2454
+ }
2455
+ }
2456
+ return out;
2457
+ }
2458
+ function countAdrs(dir) {
2459
+ const base = join(dir, DECISIONS_DIR);
2460
+ if (!exists(base)) return { total: 0, draft: 0, accepted: 0 };
2461
+ let total = 0;
2462
+ let draft = 0;
2463
+ let accepted = 0;
2464
+ for (const entry of readDir(base)) {
2465
+ if (!entry.endsWith(".md") || entry === ".gitkeep") continue;
2466
+ const full = join(base, entry);
2467
+ if (!isFile(full)) continue;
2468
+ total += 1;
2469
+ let content = "";
2470
+ try {
2471
+ content = readFile(full);
2472
+ } catch {
2473
+ continue;
2474
+ }
2475
+ const status = content.match(/^\s*status:\s*([a-z-]+)/im)?.[1]?.toLowerCase();
2476
+ if (status === "accepted") accepted += 1;
2477
+ else draft += 1;
2478
+ }
2479
+ return { total, draft, accepted };
2480
+ }
2481
+ function buildTechDecisions(dir) {
2482
+ const candFile = join(dir, CANDIDATES_PATH);
2483
+ let titles = [];
2484
+ if (exists(candFile)) {
2485
+ try {
2486
+ titles = parseDecisionCandidates(readFile(candFile));
2487
+ } catch {
2488
+ titles = [];
2489
+ }
2490
+ }
2491
+ const { total, draft, accepted } = countAdrs(dir);
2492
+ const candidate_list = titles.map((title, i) => {
2493
+ const n = String(total + i + 1).padStart(3, "0");
2494
+ return { title, source: CANDIDATES_PATH, suggestedAdrFile: `${DECISIONS_DIR}/ADR-${n}-${slugify(title)}.md` };
2495
+ });
2496
+ let status;
2497
+ if (accepted > 0) status = "accepted-adrs";
2498
+ else if (total > 0) status = "draft-adrs";
2499
+ else if (titles.length > 0) status = "candidates";
2500
+ else status = "none";
2501
+ return {
2502
+ status,
2503
+ candidates: titles.length,
2504
+ adrs: total,
2505
+ draft_adrs: draft,
2506
+ accepted_adrs: accepted,
2507
+ candidate_list
2508
+ };
2509
+ }
2510
+
2436
2511
  // ../cli/src/core/project-explain.ts
2437
2512
  var ARCH_DIR2 = "knowledge";
2438
2513
  function normalizeTitle(t) {
@@ -2644,7 +2719,8 @@ function buildProjectExplanation(dir) {
2644
2719
  missingKnowledge,
2645
2720
  suggestedNextSteps,
2646
2721
  readiness,
2647
- nextStepRecommendation: readiness.nextStepRecommendation
2722
+ nextStepRecommendation: readiness.nextStepRecommendation,
2723
+ techDecisions: buildTechDecisions(dir)
2648
2724
  };
2649
2725
  }
2650
2726
  function stateLabel(state) {
@@ -2858,6 +2934,16 @@ function renderExplanationHuman(exp) {
2858
2934
  lines.push("### Recommended next step");
2859
2935
  lines.push(r.recommended_next_step.label);
2860
2936
  lines.push("");
2937
+ const td = exp.techDecisions;
2938
+ lines.push("## Tech Decisions");
2939
+ lines.push(`- Decision candidates: ${td.candidates}`);
2940
+ lines.push(`- ADRs: ${td.adrs} (draft: ${td.draft_adrs}, accepted: ${td.accepted_adrs})`);
2941
+ lines.push(`- Status: ${td.status}`);
2942
+ if (td.candidates > 0 && td.adrs === 0) {
2943
+ lines.push("");
2944
+ lines.push("Use the adr-writing skill to materialize decision candidates into ADRs (`kaddo adr`) before implementing related technical Work Items.");
2945
+ }
2946
+ lines.push("");
2861
2947
  return lines.join("\n").trimEnd() + "\n";
2862
2948
  }
2863
2949
  function renderExplanationAgent(exp) {
@@ -4044,6 +4130,18 @@ var RESOURCES = [
4044
4130
  }
4045
4131
  return [{ uri: "kaddo://roadmap-readiness", text: JSON.stringify(roadmapReadinessSummary(root), null, 2), mimeType: "application/json" }];
4046
4132
  }
4133
+ },
4134
+ {
4135
+ uri: "kaddo://tech-decisions",
4136
+ name: "Kaddo tech decisions",
4137
+ description: "Technical decision candidates vs materialized ADRs (status, counts, candidate list with suggested ADR filenames). Read-only; shares buildTechDecisions with `kaddo adr`.",
4138
+ mimeType: "application/json",
4139
+ read: (root) => {
4140
+ if (!hasKnowledge(root)) {
4141
+ return text("kaddo://tech-decisions", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
4142
+ }
4143
+ return [{ uri: "kaddo://tech-decisions", text: JSON.stringify(buildTechDecisions(root), null, 2), mimeType: "application/json" }];
4144
+ }
4047
4145
  }
4048
4146
  ];
4049
4147
 
@@ -4313,6 +4411,10 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
4313
4411
  }
4314
4412
  });
4315
4413
  const nextStepRecommendation = resolveNextStep(dir, now);
4414
+ const techDecisions = buildTechDecisions(dir);
4415
+ if (techDecisions.candidates > 0 && techDecisions.adrs === 0) {
4416
+ missing.push(`${techDecisions.candidates} technical decision candidate(s) not yet materialized as ADRs (run \`kaddo adr\`).`);
4417
+ }
4316
4418
  const unifiedPhase = {
4317
4419
  ...phase,
4318
4420
  nextStep: nextStepRecommendation.label,
@@ -4350,6 +4452,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
4350
4452
  roadmap,
4351
4453
  phase: unifiedPhase,
4352
4454
  nextStepRecommendation,
4455
+ techDecisions,
4353
4456
  deliveryMix,
4354
4457
  external: loadExternalCapsules(dir),
4355
4458
  graph: loadGraphSummary(dir),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/mcp",
3
- "version": "3.39.1",
3
+ "version": "3.40.1",
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": {