@kaddo/mcp 3.40.0 → 3.41.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.
- package/dist/index.js +83 -16
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2434,18 +2434,31 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
2434
2434
|
}
|
|
2435
2435
|
|
|
2436
2436
|
// ../cli/src/core/decisions.ts
|
|
2437
|
-
var
|
|
2437
|
+
var CANDIDATES_DISCOVERY = "knowledge/tech/discovery/decision-candidates.md";
|
|
2438
|
+
var CANDIDATES_LEGACY = "knowledge/tech/decision-candidates.md";
|
|
2438
2439
|
var DECISIONS_DIR = "knowledge/tech/decisions";
|
|
2440
|
+
function resolveCandidatesPath(dir) {
|
|
2441
|
+
const discovery = exists(join(dir, CANDIDATES_DISCOVERY));
|
|
2442
|
+
const legacy = exists(join(dir, CANDIDATES_LEGACY));
|
|
2443
|
+
if (discovery) return { path: CANDIDATES_DISCOVERY, legacy: false, bothExist: legacy };
|
|
2444
|
+
if (legacy) return { path: CANDIDATES_LEGACY, legacy: true, bothExist: false };
|
|
2445
|
+
return { path: null, legacy: false, bothExist: false };
|
|
2446
|
+
}
|
|
2447
|
+
function cleanCandidateTitle(title) {
|
|
2448
|
+
return title.replace(/^\s*#{1,6}\s+/, "").replace(/^\s*[-*]\s+/, "").replace(/^\s*\(?\d+\)?[.):]\s+/, "").trim();
|
|
2449
|
+
}
|
|
2439
2450
|
function slugify(s) {
|
|
2440
|
-
return s.toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0,
|
|
2451
|
+
return cleanCandidateTitle(s).toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "").slice(0, 70).replace(/-+$/g, "");
|
|
2441
2452
|
}
|
|
2442
2453
|
function parseDecisionCandidates(md) {
|
|
2443
2454
|
const out = [];
|
|
2444
2455
|
for (const line of md.split(/\r?\n/)) {
|
|
2445
2456
|
const m = line.match(/^##\s+(.+?)\s*$/);
|
|
2446
2457
|
if (m) {
|
|
2447
|
-
const
|
|
2448
|
-
if (
|
|
2458
|
+
const raw = m[1].trim();
|
|
2459
|
+
if (!raw || /^_.*_$/.test(raw)) continue;
|
|
2460
|
+
const t = cleanCandidateTitle(raw);
|
|
2461
|
+
if (t) out.push(t);
|
|
2449
2462
|
}
|
|
2450
2463
|
}
|
|
2451
2464
|
return out;
|
|
@@ -2474,11 +2487,11 @@ function countAdrs(dir) {
|
|
|
2474
2487
|
return { total, draft, accepted };
|
|
2475
2488
|
}
|
|
2476
2489
|
function buildTechDecisions(dir) {
|
|
2477
|
-
const
|
|
2490
|
+
const resolved = resolveCandidatesPath(dir);
|
|
2478
2491
|
let titles = [];
|
|
2479
|
-
if (
|
|
2492
|
+
if (resolved.path) {
|
|
2480
2493
|
try {
|
|
2481
|
-
titles = parseDecisionCandidates(readFile(
|
|
2494
|
+
titles = parseDecisionCandidates(readFile(join(dir, resolved.path)));
|
|
2482
2495
|
} catch {
|
|
2483
2496
|
titles = [];
|
|
2484
2497
|
}
|
|
@@ -2486,7 +2499,7 @@ function buildTechDecisions(dir) {
|
|
|
2486
2499
|
const { total, draft, accepted } = countAdrs(dir);
|
|
2487
2500
|
const candidate_list = titles.map((title, i) => {
|
|
2488
2501
|
const n = String(total + i + 1).padStart(3, "0");
|
|
2489
|
-
return { title, source:
|
|
2502
|
+
return { title, source: resolved.path, suggestedAdrFile: `${DECISIONS_DIR}/ADR-${n}-${slugify(title)}.md` };
|
|
2490
2503
|
});
|
|
2491
2504
|
let status;
|
|
2492
2505
|
if (accepted > 0) status = "accepted-adrs";
|
|
@@ -2499,7 +2512,10 @@ function buildTechDecisions(dir) {
|
|
|
2499
2512
|
adrs: total,
|
|
2500
2513
|
draft_adrs: draft,
|
|
2501
2514
|
accepted_adrs: accepted,
|
|
2502
|
-
candidate_list
|
|
2515
|
+
candidate_list,
|
|
2516
|
+
candidates_source: resolved.path,
|
|
2517
|
+
candidates_legacy_location: resolved.legacy,
|
|
2518
|
+
candidates_both_exist: resolved.bothExist
|
|
2503
2519
|
};
|
|
2504
2520
|
}
|
|
2505
2521
|
|
|
@@ -2715,7 +2731,18 @@ function buildProjectExplanation(dir) {
|
|
|
2715
2731
|
suggestedNextSteps,
|
|
2716
2732
|
readiness,
|
|
2717
2733
|
nextStepRecommendation: readiness.nextStepRecommendation,
|
|
2718
|
-
techDecisions: buildTechDecisions(dir)
|
|
2734
|
+
techDecisions: buildTechDecisions(dir),
|
|
2735
|
+
techKnowledge: {
|
|
2736
|
+
core: {
|
|
2737
|
+
currentState: exists(join(dir, "knowledge/tech/current-state.md")),
|
|
2738
|
+
codebase: exists(join(dir, "knowledge/tech/codebase.md"))
|
|
2739
|
+
},
|
|
2740
|
+
discovery: {
|
|
2741
|
+
architectureNotes: exists(join(dir, "knowledge/tech/discovery/architecture-notes.md")) || exists(join(dir, "knowledge/tech/architecture-notes.md")),
|
|
2742
|
+
decisionCandidates: exists(join(dir, "knowledge/tech/discovery/decision-candidates.md")) || exists(join(dir, "knowledge/tech/decision-candidates.md")),
|
|
2743
|
+
legacyLocation: exists(join(dir, "knowledge/tech/architecture-notes.md")) || exists(join(dir, "knowledge/tech/decision-candidates.md"))
|
|
2744
|
+
}
|
|
2745
|
+
}
|
|
2719
2746
|
};
|
|
2720
2747
|
}
|
|
2721
2748
|
function stateLabel(state) {
|
|
@@ -2930,15 +2957,26 @@ function renderExplanationHuman(exp) {
|
|
|
2930
2957
|
lines.push(r.recommended_next_step.label);
|
|
2931
2958
|
lines.push("");
|
|
2932
2959
|
const td = exp.techDecisions;
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
lines.push(
|
|
2936
|
-
lines.push(
|
|
2960
|
+
const tk = exp.techKnowledge;
|
|
2961
|
+
const mark = (b) => b ? "\u2713" : "\u2717";
|
|
2962
|
+
lines.push("## Tech Knowledge");
|
|
2963
|
+
lines.push("Core:");
|
|
2964
|
+
lines.push(`- ${mark(tk.core.currentState)} current-state.md`);
|
|
2965
|
+
lines.push(`- ${mark(tk.core.codebase)} codebase.md`);
|
|
2966
|
+
lines.push("Decisions:");
|
|
2967
|
+
lines.push(`- ADRs: ${td.adrs} (draft: ${td.draft_adrs}, accepted: ${td.accepted_adrs}) \xB7 status: ${td.status}`);
|
|
2968
|
+
lines.push("Discovery:");
|
|
2969
|
+
lines.push(`- ${mark(tk.discovery.architectureNotes)} architecture-notes.md`);
|
|
2970
|
+
lines.push(`- ${mark(tk.discovery.decisionCandidates)} decision-candidates.md`);
|
|
2971
|
+
lines.push("");
|
|
2937
2972
|
if (td.candidates > 0 && td.adrs === 0) {
|
|
2938
|
-
lines.push("");
|
|
2939
2973
|
lines.push("Use the adr-writing skill to materialize decision candidates into ADRs (`kaddo adr`) before implementing related technical Work Items.");
|
|
2974
|
+
lines.push("");
|
|
2975
|
+
}
|
|
2976
|
+
if (tk.discovery.legacyLocation) {
|
|
2977
|
+
lines.push("Tech discovery files are in the legacy `knowledge/tech/` root. Suggested cleanup: run `kaddo tech organize`.");
|
|
2978
|
+
lines.push("");
|
|
2940
2979
|
}
|
|
2941
|
-
lines.push("");
|
|
2942
2980
|
return lines.join("\n").trimEnd() + "\n";
|
|
2943
2981
|
}
|
|
2944
2982
|
function renderExplanationAgent(exp) {
|
|
@@ -4125,6 +4163,18 @@ var RESOURCES = [
|
|
|
4125
4163
|
}
|
|
4126
4164
|
return [{ uri: "kaddo://roadmap-readiness", text: JSON.stringify(roadmapReadinessSummary(root), null, 2), mimeType: "application/json" }];
|
|
4127
4165
|
}
|
|
4166
|
+
},
|
|
4167
|
+
{
|
|
4168
|
+
uri: "kaddo://tech-decisions",
|
|
4169
|
+
name: "Kaddo tech decisions",
|
|
4170
|
+
description: "Technical decision candidates vs materialized ADRs (status, counts, candidate list with suggested ADR filenames). Read-only; shares buildTechDecisions with `kaddo adr`.",
|
|
4171
|
+
mimeType: "application/json",
|
|
4172
|
+
read: (root) => {
|
|
4173
|
+
if (!hasKnowledge(root)) {
|
|
4174
|
+
return text("kaddo://tech-decisions", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
4175
|
+
}
|
|
4176
|
+
return [{ uri: "kaddo://tech-decisions", text: JSON.stringify(buildTechDecisions(root), null, 2), mimeType: "application/json" }];
|
|
4177
|
+
}
|
|
4128
4178
|
}
|
|
4129
4179
|
];
|
|
4130
4180
|
|
|
@@ -4398,6 +4448,22 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
4398
4448
|
if (techDecisions.candidates > 0 && techDecisions.adrs === 0) {
|
|
4399
4449
|
missing.push(`${techDecisions.candidates} technical decision candidate(s) not yet materialized as ADRs (run \`kaddo adr\`).`);
|
|
4400
4450
|
}
|
|
4451
|
+
const techFile = (rel) => exists(join(dir, ARCH_DIR3, rel));
|
|
4452
|
+
const techKnowledge = {
|
|
4453
|
+
core: {
|
|
4454
|
+
"current-state.md": techFile("tech/current-state.md"),
|
|
4455
|
+
"codebase.md": techFile("tech/codebase.md")
|
|
4456
|
+
},
|
|
4457
|
+
decisions: { adrs: techDecisions.adrs, dir: exists(join(dir, ARCH_DIR3, "tech/decisions")) },
|
|
4458
|
+
discovery: {
|
|
4459
|
+
"architecture-notes.md": techFile("tech/discovery/architecture-notes.md") || techFile("tech/architecture-notes.md"),
|
|
4460
|
+
"decision-candidates.md": techFile("tech/discovery/decision-candidates.md") || techFile("tech/decision-candidates.md"),
|
|
4461
|
+
legacyLocation: techFile("tech/architecture-notes.md") || techFile("tech/decision-candidates.md")
|
|
4462
|
+
}
|
|
4463
|
+
};
|
|
4464
|
+
if (techKnowledge.discovery.legacyLocation) {
|
|
4465
|
+
missing.push("Tech discovery files are in the legacy `knowledge/tech/` root. Run `kaddo tech organize` to move them to `knowledge/tech/discovery/`.");
|
|
4466
|
+
}
|
|
4401
4467
|
const unifiedPhase = {
|
|
4402
4468
|
...phase,
|
|
4403
4469
|
nextStep: nextStepRecommendation.label,
|
|
@@ -4436,6 +4502,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
4436
4502
|
phase: unifiedPhase,
|
|
4437
4503
|
nextStepRecommendation,
|
|
4438
4504
|
techDecisions,
|
|
4505
|
+
techKnowledge,
|
|
4439
4506
|
deliveryMix,
|
|
4440
4507
|
external: loadExternalCapsules(dir),
|
|
4441
4508
|
graph: loadGraphSummary(dir),
|
package/package.json
CHANGED