@kaddo/mcp 3.36.0 → 3.37.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.
- package/dist/index.js +263 -89
- 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 = [];
|
|
@@ -2102,26 +2218,7 @@ function buildAdapterStatuses(dir) {
|
|
|
2102
2218
|
});
|
|
2103
2219
|
}
|
|
2104
2220
|
|
|
2105
|
-
// ../cli/src/core/
|
|
2106
|
-
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" }
|
|
2112
|
-
];
|
|
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
|
-
}
|
|
2221
|
+
// ../cli/src/core/next-step.ts
|
|
2125
2222
|
function roadmapSignal(dir) {
|
|
2126
2223
|
const p = join(dir, "knowledge/delivery/roadmap.md");
|
|
2127
2224
|
if (!exists(p)) return "missing";
|
|
@@ -2152,8 +2249,91 @@ function installedAdapters(dir) {
|
|
|
2152
2249
|
(s) => s.state === "injected" || s.state === "legacy-injected" || s.state === "full-generated" && (s.originAdapter === s.id || s.originAdapter === null)
|
|
2153
2250
|
).map((s) => s.id);
|
|
2154
2251
|
}
|
|
2252
|
+
var B = "knowledge/business/business.md";
|
|
2253
|
+
var P = "knowledge/product/product.md";
|
|
2254
|
+
var CAP = "knowledge/product/capabilities.md";
|
|
2255
|
+
var CS = "knowledge/tech/current-state.md";
|
|
2256
|
+
var CB = "knowledge/tech/codebase.md";
|
|
2257
|
+
function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
|
|
2258
|
+
const config = loadConfig(dir);
|
|
2259
|
+
if (!config) {
|
|
2260
|
+
return { id: "init", phase: "Setup", label: "Run `kaddo init` to initialize Kaddo.", command: "kaddo init", reason: "Kaddo is not initialized in this project." };
|
|
2261
|
+
}
|
|
2262
|
+
const state = config.project.state;
|
|
2263
|
+
const q = (rel) => analyzeKnowledgeArtifact(dir, rel);
|
|
2264
|
+
const qBusiness = q(B), qProduct = q(P), qCap = q(CAP), qCurrentState = q(CS), qCodebase = q(CB);
|
|
2265
|
+
if (qBusiness === "missing" || qProduct === "missing") {
|
|
2266
|
+
return { id: "bootstrap", phase: "Setup", label: "Run `kaddo bootstrap` to create the project knowledge baseline.", command: "kaddo bootstrap", reason: "The knowledge baseline is incomplete." };
|
|
2267
|
+
}
|
|
2268
|
+
const ctx = buildCodexAdapterContext(dir);
|
|
2269
|
+
if (!ctx.hasAgents) {
|
|
2270
|
+
return { id: "add-agents", phase: "Setup", label: "Run `kaddo add agents` to install the Kaddo agent prompt packs.", command: "kaddo add agents", reason: "No Kaddo agents are installed yet." };
|
|
2271
|
+
}
|
|
2272
|
+
if (!ctx.hasSkills) {
|
|
2273
|
+
return { id: "add-skills", phase: "Setup", label: "Run `kaddo add skills` to install reusable Kaddo skills.", command: "kaddo add skills", reason: "No Kaddo skills are installed yet." };
|
|
2274
|
+
}
|
|
2275
|
+
if ((state === "pre-ai" || state === "legacy") && !exists(join(dir, ".kaddo", "scan.json"))) {
|
|
2276
|
+
return { id: "scan", phase: "Discovery", label: "Run `kaddo scan` to capture deterministic signals from the existing code.", command: "kaddo scan", reason: "No scan baseline exists for this existing project yet." };
|
|
2277
|
+
}
|
|
2278
|
+
if (!exists(join(dir, ".kaddo", "context-pack.md"))) {
|
|
2279
|
+
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." };
|
|
2280
|
+
}
|
|
2281
|
+
if (!exists(join(dir, ".kaddo", "understand.md"))) {
|
|
2282
|
+
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." };
|
|
2283
|
+
}
|
|
2284
|
+
const refine = (id, agent, target, quality) => ({
|
|
2285
|
+
id,
|
|
2286
|
+
phase: "Knowledge Refinement",
|
|
2287
|
+
label: `Use ${agent} to complete \`${target}\`.`,
|
|
2288
|
+
agent,
|
|
2289
|
+
target,
|
|
2290
|
+
reason: `${target} is ${quality === "missing" ? "missing" : "still a bootstrap placeholder or too thin"}.`,
|
|
2291
|
+
instructions: [
|
|
2292
|
+
"The baseline file exists but does not yet hold real, project-specific knowledge.",
|
|
2293
|
+
`Use the ${agent} to replace the placeholders with real knowledge.`,
|
|
2294
|
+
"Do not write code."
|
|
2295
|
+
]
|
|
2296
|
+
});
|
|
2297
|
+
if (qBusiness !== "useful") return refine("refine-business", "business-agent", B, qBusiness);
|
|
2298
|
+
if (qProduct !== "useful" || qCap !== "useful") {
|
|
2299
|
+
const target = qCap !== "useful" ? CAP : P;
|
|
2300
|
+
return refine("refine-product", "capability-agent", target, qCap !== "useful" ? qCap : qProduct);
|
|
2301
|
+
}
|
|
2302
|
+
if (qCurrentState !== "useful") return refine("refine-current-state", "architecture-agent", CS, qCurrentState);
|
|
2303
|
+
if (qCodebase !== "useful") {
|
|
2304
|
+
const agent = ctx.agents.includes("codebase-agent") ? "codebase-agent" : "architecture-agent";
|
|
2305
|
+
return refine("refine-codebase", agent, CB, qCodebase);
|
|
2306
|
+
}
|
|
2307
|
+
const oq = buildOpenQuestionsReport(dir, now);
|
|
2308
|
+
if (oq.summary.blocking_open > 0) {
|
|
2309
|
+
return { id: "questions", phase: "Knowledge Refinement", label: "Resolve, assume or defer the blocking open questions (`kaddo questions`).", command: "kaddo questions", reason: `${oq.summary.blocking_open} blocking open question(s) remain.` };
|
|
2310
|
+
}
|
|
2311
|
+
const roadmap = roadmapSignal(dir);
|
|
2312
|
+
if (roadmap !== "has-candidates") {
|
|
2313
|
+
return { id: "roadmap", phase: "Planning", label: "Use roadmap-agent to define roadmap candidates (`kaddo roadmap`).", command: "kaddo roadmap", agent: "roadmap-agent", target: "knowledge/delivery/roadmap.md", reason: "The roadmap has no candidates yet." };
|
|
2314
|
+
}
|
|
2315
|
+
const wi = workItemsSignal(dir);
|
|
2316
|
+
if (wi === "none" || wi === "none-ready") {
|
|
2317
|
+
return { id: "create-work-item", phase: "Delivery Preparation", label: "Run `kaddo create --from roadmap` to materialize the first Work Item.", command: "kaddo create --from roadmap", reason: "The roadmap has candidates but no Work Item is ready." };
|
|
2318
|
+
}
|
|
2319
|
+
const adapters = installedAdapters(dir);
|
|
2320
|
+
if (adapters.length === 0) {
|
|
2321
|
+
return { id: "install-adapter", phase: "Active Delivery", label: "Run `kaddo adapters list` and install the adapter for your preferred agent.", command: "kaddo adapters list", reason: "A Work Item is ready but no adapter is installed." };
|
|
2322
|
+
}
|
|
2323
|
+
return { id: "implement", phase: "Active Delivery", label: "Implement the ready Work Item and run `kaddo guard`.", reason: "A Work Item is ready and an adapter is installed." };
|
|
2324
|
+
}
|
|
2325
|
+
|
|
2326
|
+
// ../cli/src/core/readiness.ts
|
|
2327
|
+
var KNOWLEDGE_FILES = [
|
|
2328
|
+
{ key: "current_state", path: "knowledge/tech/current-state.md", label: "knowledge/tech/current-state.md", agent: "architecture-agent" },
|
|
2329
|
+
{ key: "codebase", path: "knowledge/tech/codebase.md", label: "knowledge/tech/codebase.md", agent: "codebase-agent" },
|
|
2330
|
+
{ key: "capabilities", path: "knowledge/product/capabilities.md", label: "knowledge/product/capabilities.md", agent: "capability-agent" },
|
|
2331
|
+
{ key: "product", path: "knowledge/product/product.md", label: "knowledge/product/product.md", agent: "product-agent" },
|
|
2332
|
+
{ key: "business", path: "knowledge/business/business.md", label: "knowledge/business/business.md", agent: "business-agent" }
|
|
2333
|
+
];
|
|
2155
2334
|
function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
2156
2335
|
const config = loadConfig(dir);
|
|
2336
|
+
const rec = resolveNextStep(dir, now);
|
|
2157
2337
|
const stub = (overall2, label, command) => ({
|
|
2158
2338
|
project_name: config?.project.name ?? "unknown",
|
|
2159
2339
|
project_type: config?.project.state ?? "unknown",
|
|
@@ -2177,14 +2357,15 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
2177
2357
|
resolved_questions: 0,
|
|
2178
2358
|
deferred_questions: 0
|
|
2179
2359
|
},
|
|
2180
|
-
recommended_next_step: { label, ...command ? { command } : {} }
|
|
2360
|
+
recommended_next_step: { label, ...command ? { command } : {} },
|
|
2361
|
+
nextStepRecommendation: rec
|
|
2181
2362
|
});
|
|
2182
|
-
if (!config) return stub("not-initialized",
|
|
2363
|
+
if (!config) return stub("not-initialized", rec.label, rec.command);
|
|
2183
2364
|
if (config.project.state === "new") return stub("not-applicable", "This project uses the standard new-project Kaddo flow.");
|
|
2184
2365
|
if (config.project.state === "legacy") return stub("legacy-project", "Use the legacy project flow.");
|
|
2185
2366
|
const scan = exists(join(dir, ".kaddo", "scan.json")) ? "available" : "missing";
|
|
2186
2367
|
const understand = exists(join(dir, ".kaddo", "understand.md")) ? "available" : "missing";
|
|
2187
|
-
const presence = Object.fromEntries(KNOWLEDGE_FILES.map((f) => [f.key,
|
|
2368
|
+
const presence = Object.fromEntries(KNOWLEDGE_FILES.map((f) => [f.key, analyzeKnowledgeArtifact(dir, f.path)]));
|
|
2188
2369
|
const ctx = buildCodexAdapterContext(dir);
|
|
2189
2370
|
const agents = ctx.hasAgents ? "present" : "missing";
|
|
2190
2371
|
const skills = ctx.hasSkills ? "present" : "missing";
|
|
@@ -2212,41 +2393,26 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
2212
2393
|
resolved_questions: oq.summary.resolution.resolved,
|
|
2213
2394
|
deferred_questions: oq.summary.resolution.deferred
|
|
2214
2395
|
};
|
|
2396
|
+
const firstWeak = KNOWLEDGE_FILES.find((f) => presence[f.key] !== "useful");
|
|
2215
2397
|
let overall;
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
if (
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
}
|
|
2234
|
-
overall = "knowledge-incomplete";
|
|
2235
|
-
next = { label: `Complete \`${firstWeak.label}\` (it is ${presence[firstWeak.key]}).` };
|
|
2236
|
-
} else if (oq.summary.blocking_open > 0) {
|
|
2237
|
-
overall = "needs-decisions";
|
|
2238
|
-
next = { label: "Resolve, assume or defer the blocking open questions (`kaddo questions`).", command: "kaddo questions" };
|
|
2239
|
-
} else if (roadmap !== "has-candidates") {
|
|
2240
|
-
overall = "ready-for-roadmap";
|
|
2241
|
-
next = { label: "Run `kaddo roadmap` to draft the roadmap from the current knowledge.", command: "kaddo roadmap" };
|
|
2242
|
-
} else if (work_items === "none" || work_items === "none-ready") {
|
|
2243
|
-
overall = "ready-for-work-item";
|
|
2244
|
-
next = { label: "Run `kaddo create --from roadmap` to materialize the first Work Item.", command: "kaddo create --from roadmap" };
|
|
2245
|
-
} else {
|
|
2246
|
-
overall = "ready-for-implementation";
|
|
2247
|
-
next = adapters.length > 0 ? { label: "Implement the ready Work Item and run `kaddo guard`." } : { label: "Run `kaddo adapters list` and install the adapter for your preferred agent.", command: "kaddo adapters list" };
|
|
2248
|
-
}
|
|
2249
|
-
return { project_name: config.project.name, project_type: config.project.state, overall, signals, recommended_next_step: next };
|
|
2398
|
+
if (scan === "missing") overall = "initialized";
|
|
2399
|
+
else if (bootstrapBaseline === "incomplete") overall = "bootstrap-incomplete";
|
|
2400
|
+
else if (agents === "missing") overall = "agents-missing";
|
|
2401
|
+
else if (skills === "missing") overall = "skills-missing";
|
|
2402
|
+
else if (understand === "missing") overall = "scanned";
|
|
2403
|
+
else if (firstWeak) overall = "knowledge-incomplete";
|
|
2404
|
+
else if (oq.summary.blocking_open > 0) overall = "needs-decisions";
|
|
2405
|
+
else if (roadmap !== "has-candidates") overall = "ready-for-roadmap";
|
|
2406
|
+
else if (work_items === "none" || work_items === "none-ready") overall = "ready-for-work-item";
|
|
2407
|
+
else overall = "ready-for-implementation";
|
|
2408
|
+
return {
|
|
2409
|
+
project_name: config.project.name,
|
|
2410
|
+
project_type: config.project.state,
|
|
2411
|
+
overall,
|
|
2412
|
+
signals,
|
|
2413
|
+
recommended_next_step: { label: rec.label, ...rec.command ? { command: rec.command } : {} },
|
|
2414
|
+
nextStepRecommendation: rec
|
|
2415
|
+
};
|
|
2250
2416
|
}
|
|
2251
2417
|
|
|
2252
2418
|
// ../cli/src/core/project-explain.ts
|
|
@@ -2438,6 +2604,7 @@ function buildProjectExplanation(dir) {
|
|
|
2438
2604
|
"Run `kaddo owners suggest` for Work Items without code ownership."
|
|
2439
2605
|
);
|
|
2440
2606
|
}
|
|
2607
|
+
const readiness = buildReadinessReport(dir);
|
|
2441
2608
|
return {
|
|
2442
2609
|
project,
|
|
2443
2610
|
stack,
|
|
@@ -2458,7 +2625,8 @@ function buildProjectExplanation(dir) {
|
|
|
2458
2625
|
mappedModules,
|
|
2459
2626
|
missingKnowledge,
|
|
2460
2627
|
suggestedNextSteps,
|
|
2461
|
-
readiness
|
|
2628
|
+
readiness,
|
|
2629
|
+
nextStepRecommendation: readiness.nextStepRecommendation
|
|
2462
2630
|
};
|
|
2463
2631
|
}
|
|
2464
2632
|
function stateLabel(state) {
|
|
@@ -2639,7 +2807,7 @@ function renderExplanationHuman(exp) {
|
|
|
2639
2807
|
lines.push("- Reason:");
|
|
2640
2808
|
for (const r2 of assessment.reasons) lines.push(` - ${r2}`);
|
|
2641
2809
|
}
|
|
2642
|
-
|
|
2810
|
+
lines.push(`- Next step: ${exp.readiness.recommended_next_step.label}`);
|
|
2643
2811
|
lines.push("");
|
|
2644
2812
|
if (exp.suggestedNextSteps.length > 0) {
|
|
2645
2813
|
lines.push("## Suggested Next Steps");
|
|
@@ -2656,9 +2824,11 @@ function renderExplanationHuman(exp) {
|
|
|
2656
2824
|
lines.push(`- understand: ${s.understand}`);
|
|
2657
2825
|
lines.push(`- agents: ${s.agents}`);
|
|
2658
2826
|
lines.push(`- skills: ${s.skills}`);
|
|
2827
|
+
lines.push(`- business: ${s.business}`);
|
|
2828
|
+
lines.push(`- product: ${s.product}`);
|
|
2829
|
+
lines.push(`- capabilities: ${s.capabilities}`);
|
|
2659
2830
|
lines.push(`- current-state: ${s.current_state}`);
|
|
2660
2831
|
lines.push(`- codebase: ${s.codebase}`);
|
|
2661
|
-
lines.push(`- capabilities: ${s.capabilities}`);
|
|
2662
2832
|
lines.push(`- roadmap: ${s.roadmap}`);
|
|
2663
2833
|
lines.push(`- work-items: ${s.work_items}`);
|
|
2664
2834
|
lines.push(`- adapters: ${s.adapters.length > 0 ? s.adapters.join(", ") + " installed" : "none installed"}`);
|
|
@@ -4013,28 +4183,6 @@ function recommendedAgentsForState(state) {
|
|
|
4013
4183
|
return ["capability-agent", "architecture-agent", "roadmap-agent"];
|
|
4014
4184
|
}
|
|
4015
4185
|
}
|
|
4016
|
-
function nextStepsForState(state) {
|
|
4017
|
-
switch (state) {
|
|
4018
|
-
case "new":
|
|
4019
|
-
return [
|
|
4020
|
-
"Use roadmap-agent to shape an initial roadmap.",
|
|
4021
|
-
"Use architecture-agent to outline the intended architecture."
|
|
4022
|
-
];
|
|
4023
|
-
case "legacy":
|
|
4024
|
-
return [
|
|
4025
|
-
"Use legacy-agent to surface risks and unknowns before changing code.",
|
|
4026
|
-
"Use architecture-agent to reconstruct the current architecture.",
|
|
4027
|
-
"Use capability-agent to map existing capabilities."
|
|
4028
|
-
];
|
|
4029
|
-
case "pre-ai":
|
|
4030
|
-
default:
|
|
4031
|
-
return [
|
|
4032
|
-
"Use capability-agent to extract system capabilities.",
|
|
4033
|
-
"Use architecture-agent to reconstruct the current architecture.",
|
|
4034
|
-
"Use roadmap-agent to propose roadmap candidates."
|
|
4035
|
-
];
|
|
4036
|
-
}
|
|
4037
|
-
}
|
|
4038
4186
|
var LLM_INSTRUCTIONS = [
|
|
4039
4187
|
"Use this context pack as the project baseline.",
|
|
4040
4188
|
"Do not write code yet.",
|
|
@@ -4106,6 +4254,24 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
4106
4254
|
}
|
|
4107
4255
|
const mappedModules = loadMappedModules(dir);
|
|
4108
4256
|
const layers = knowledgeLayers(dir);
|
|
4257
|
+
const qa = (rel) => analyzeKnowledgeArtifact(dir, rel);
|
|
4258
|
+
const qBusiness = qa("knowledge/business/business.md");
|
|
4259
|
+
const qProduct = qa("knowledge/product/product.md");
|
|
4260
|
+
const qCapabilities = qa("knowledge/product/capabilities.md");
|
|
4261
|
+
const qCodebase = qa("knowledge/tech/codebase.md");
|
|
4262
|
+
const qCurrentState = qa("knowledge/tech/current-state.md");
|
|
4263
|
+
const qRoadmap = qa("knowledge/delivery/roadmap.md");
|
|
4264
|
+
const layerStatusOf = (name) => layers.find((l) => l.layer === name)?.status ?? "Missing";
|
|
4265
|
+
const knowledgeQuality = {
|
|
4266
|
+
business: { status: layerStatusOf("Business"), artifacts: { "knowledge/business/business.md": qBusiness } },
|
|
4267
|
+
product: { status: layerStatusOf("Product"), artifacts: { "knowledge/product/product.md": qProduct, "knowledge/product/capabilities.md": qCapabilities } },
|
|
4268
|
+
tech: { status: layerStatusOf("Tech"), artifacts: { "knowledge/tech/codebase.md": qCodebase, "knowledge/tech/current-state.md": qCurrentState } },
|
|
4269
|
+
delivery: { status: layerStatusOf("Delivery"), artifacts: { "knowledge/delivery/roadmap.md": qRoadmap } }
|
|
4270
|
+
};
|
|
4271
|
+
if (qBusiness === "placeholder") missing.push("Business context exists but still looks like a bootstrap placeholder.");
|
|
4272
|
+
if (qProduct === "placeholder" || qCapabilities === "placeholder") missing.push("Product capabilities exist but still look like a bootstrap placeholder.");
|
|
4273
|
+
if (qCurrentState === "placeholder") missing.push("Current state exists but still looks like a bootstrap placeholder.");
|
|
4274
|
+
if (qCodebase === "placeholder") missing.push("Codebase map exists but still looks like a bootstrap placeholder.");
|
|
4109
4275
|
const allWorkItems = allArtifacts.filter((a) => a.isWorkItem);
|
|
4110
4276
|
const wiWithOwnership = allWorkItems.filter((a) => a.codeGlobs.length > 0).length;
|
|
4111
4277
|
const phase = assessPhase({
|
|
@@ -4128,6 +4294,12 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
4128
4294
|
workItemsMissingOwnership: allWorkItems.length - wiWithOwnership
|
|
4129
4295
|
}
|
|
4130
4296
|
});
|
|
4297
|
+
const nextStepRecommendation = resolveNextStep(dir, now);
|
|
4298
|
+
const unifiedPhase = {
|
|
4299
|
+
...phase,
|
|
4300
|
+
nextStep: nextStepRecommendation.label,
|
|
4301
|
+
recommendedAgents: nextStepRecommendation.agent ? [nextStepRecommendation.agent] : phase.recommendedAgents
|
|
4302
|
+
};
|
|
4131
4303
|
return {
|
|
4132
4304
|
version: CONTEXT_PACK_VERSION,
|
|
4133
4305
|
generatedAt: now.toISOString(),
|
|
@@ -4156,8 +4328,10 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
4156
4328
|
artifacts: allArtifacts.filter((a) => a.codeGlobs.length > 0).map(toContextArtifact)
|
|
4157
4329
|
},
|
|
4158
4330
|
layers,
|
|
4331
|
+
knowledgeQuality,
|
|
4159
4332
|
roadmap,
|
|
4160
|
-
phase,
|
|
4333
|
+
phase: unifiedPhase,
|
|
4334
|
+
nextStepRecommendation,
|
|
4161
4335
|
deliveryMix,
|
|
4162
4336
|
external: loadExternalCapsules(dir),
|
|
4163
4337
|
graph: loadGraphSummary(dir),
|
|
@@ -4165,12 +4339,12 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
4165
4339
|
skills: discoverInstalledSkills(dir).map((s) => s.id),
|
|
4166
4340
|
mappedModules,
|
|
4167
4341
|
missing,
|
|
4168
|
-
// VS-052: the handoff is driven by the
|
|
4169
|
-
//
|
|
4342
|
+
// VS-052/VS-073.2: the handoff is driven by the unified next step, so the pack never contradicts
|
|
4343
|
+
// the Current Phase block above it.
|
|
4170
4344
|
handoff: {
|
|
4171
|
-
recommendedAgents:
|
|
4172
|
-
nextSteps:
|
|
4173
|
-
instructions:
|
|
4345
|
+
recommendedAgents: unifiedPhase.recommendedAgents.length > 0 ? unifiedPhase.recommendedAgents : recommendedAgentsForState(state),
|
|
4346
|
+
nextSteps: [nextStepRecommendation.label],
|
|
4347
|
+
instructions: unifiedPhase.llmInstructions.length > 0 ? unifiedPhase.llmInstructions : LLM_INSTRUCTIONS,
|
|
4174
4348
|
operatingRules: OPERATING_RULES
|
|
4175
4349
|
}
|
|
4176
4350
|
};
|
package/package.json
CHANGED