@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.
- package/dist/index.js +147 -21
- 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,
|
|
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] !== "
|
|
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: `
|
|
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