@kaddo/cli 3.53.0 → 3.55.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 +199 -45
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2791,16 +2791,49 @@ function renderSkillsSection(agent) {
|
|
|
2791
2791
|
""
|
|
2792
2792
|
].join("\n");
|
|
2793
2793
|
}
|
|
2794
|
+
var KNOWLEDGE_REFINING_AGENTS = {
|
|
2795
|
+
"business-agent": "business-agent",
|
|
2796
|
+
"capability-agent": "capability-agent",
|
|
2797
|
+
"bootstrap-agent": "bootstrap-agent",
|
|
2798
|
+
"codebase-agent": "codebase-agent",
|
|
2799
|
+
"architecture-agent": "architecture-agent",
|
|
2800
|
+
"roadmap-agent": "roadmap-agent",
|
|
2801
|
+
"legacy-agent": "legacy-agent",
|
|
2802
|
+
"work-item-agent": "work-item-agent",
|
|
2803
|
+
"backlog-agent": "backlog-agent",
|
|
2804
|
+
"adr-agent": "adr-agent",
|
|
2805
|
+
"implementation-agent": "implementation-agent"
|
|
2806
|
+
};
|
|
2807
|
+
function renderFrontmatterRules(agent) {
|
|
2808
|
+
if (!KNOWLEDGE_REFINING_AGENTS[agent]) return "";
|
|
2809
|
+
return [
|
|
2810
|
+
"## Frontmatter Rules",
|
|
2811
|
+
"",
|
|
2812
|
+
"When rewriting an existing Kaddo knowledge file:",
|
|
2813
|
+
"",
|
|
2814
|
+
"- Preserve the existing YAML frontmatter.",
|
|
2815
|
+
"- Do not remove `type`, `generated_by`, or `template_version`.",
|
|
2816
|
+
"- If the document is no longer a placeholder, set `project_state: ai-assisted`.",
|
|
2817
|
+
`- Add or update \`refined_by: ${agent}\`.`,
|
|
2818
|
+
"- Preserve unknown frontmatter keys \u2014 do not strip fields you do not recognize.",
|
|
2819
|
+
"- Only rewrite the markdown body unless metadata changes are explicitly required by these rules.",
|
|
2820
|
+
"- Preserve structural sections like `## Open Questions` \u2014 leave them empty rather than removing them.",
|
|
2821
|
+
""
|
|
2822
|
+
].join("\n");
|
|
2823
|
+
}
|
|
2794
2824
|
function withResponsibilityTrace(fileName, content) {
|
|
2795
2825
|
const agent = fileName.replace(/\.md$/, "");
|
|
2796
2826
|
if (!RESPONSIBILITY_MATRIX[agent]) return content;
|
|
2797
2827
|
const skills = renderSkillsSection(agent);
|
|
2798
2828
|
const skillsBlock = skills ? `${skills}
|
|
2829
|
+
` : "";
|
|
2830
|
+
const frontmatter = renderFrontmatterRules(agent);
|
|
2831
|
+
const frontmatterBlock = frontmatter ? `${frontmatter}
|
|
2799
2832
|
` : "";
|
|
2800
2833
|
return `${content.trimEnd()}
|
|
2801
2834
|
|
|
2802
2835
|
${renderLanguageRule()}
|
|
2803
|
-
${renderAgentBoundaries(agent)}
|
|
2836
|
+
${frontmatterBlock}${renderAgentBoundaries(agent)}
|
|
2804
2837
|
${skillsBlock}${renderAgentTrace(agent)}`;
|
|
2805
2838
|
}
|
|
2806
2839
|
|
|
@@ -5345,6 +5378,42 @@ function domainsFromRelated(domain) {
|
|
|
5345
5378
|
var WORK_ITEMS_DIR = "knowledge/delivery/work-items";
|
|
5346
5379
|
var DRAFT_DIR = `${WORK_ITEMS_DIR}/draft`;
|
|
5347
5380
|
var ROADMAP_PATH = "knowledge/delivery/roadmap.md";
|
|
5381
|
+
function ensureWorkItemsDir(dir) {
|
|
5382
|
+
if (exists(join(dir, WORK_ITEMS_DIR))) return;
|
|
5383
|
+
if (!exists(join(dir, ".kaddo", "config.yml"))) {
|
|
5384
|
+
log2.warn("Kaddo is not initialized. Run `kaddo init` first.");
|
|
5385
|
+
process.exit(1);
|
|
5386
|
+
}
|
|
5387
|
+
ensureDir(join(dir, WORK_ITEMS_DIR));
|
|
5388
|
+
log2.info(`Created ${WORK_ITEMS_DIR}/`);
|
|
5389
|
+
}
|
|
5390
|
+
async function collectAcceptanceCriteria() {
|
|
5391
|
+
const criteria = [];
|
|
5392
|
+
while (true) {
|
|
5393
|
+
const criterion = await text2({
|
|
5394
|
+
message: criteria.length === 0 ? "Acceptance criterion" : "Acceptance criterion",
|
|
5395
|
+
placeholder: "e.g. Users see confirmation after checkout",
|
|
5396
|
+
validate: (v) => criteria.length === 0 && v.trim().length === 0 ? "At least one criterion is required." : void 0
|
|
5397
|
+
});
|
|
5398
|
+
const trimmed = criterion.trim();
|
|
5399
|
+
if (!trimmed && criteria.length > 0) break;
|
|
5400
|
+
if (trimmed.includes(";")) {
|
|
5401
|
+
criteria.push(...trimmed.split(";").map((s) => s.trim()).filter(Boolean));
|
|
5402
|
+
} else {
|
|
5403
|
+
criteria.push(trimmed);
|
|
5404
|
+
}
|
|
5405
|
+
const addMore = await confirm2({ message: "Add another acceptance criterion?" });
|
|
5406
|
+
if (!addMore) break;
|
|
5407
|
+
}
|
|
5408
|
+
return criteria.join("\n");
|
|
5409
|
+
}
|
|
5410
|
+
function renderAcceptanceCriteria(raw) {
|
|
5411
|
+
const items = raw.split(/\n|;/).map((l) => l.trim()).filter(Boolean);
|
|
5412
|
+
return items.map((item) => {
|
|
5413
|
+
const normalized = item.endsWith(".") ? item : `${item}.`;
|
|
5414
|
+
return `- [ ] ${normalized.charAt(0).toUpperCase() + normalized.slice(1)}`;
|
|
5415
|
+
}).join("\n");
|
|
5416
|
+
}
|
|
5348
5417
|
function printStateGuidance(dir) {
|
|
5349
5418
|
let config;
|
|
5350
5419
|
try {
|
|
@@ -5393,11 +5462,16 @@ function buildFrontMatter(id, type, level, title, answers) {
|
|
|
5393
5462
|
`knowledge_level: ${level}`,
|
|
5394
5463
|
`status: draft`,
|
|
5395
5464
|
`phase: now`,
|
|
5465
|
+
`work_type: ${type}`,
|
|
5396
5466
|
`initiative:`,
|
|
5397
5467
|
`domains: []`,
|
|
5398
5468
|
`code: []`,
|
|
5399
5469
|
`created_at: ${today2}`,
|
|
5400
|
-
`source
|
|
5470
|
+
`source:`,
|
|
5471
|
+
` type: manual`,
|
|
5472
|
+
` inferred: false`,
|
|
5473
|
+
`generated_by: kaddo-create`,
|
|
5474
|
+
`template_version: 1`,
|
|
5401
5475
|
`summary: "${answers.problem?.split(".")[0] ?? title}"`,
|
|
5402
5476
|
"---"
|
|
5403
5477
|
];
|
|
@@ -5428,10 +5502,9 @@ ${answers.impact}
|
|
|
5428
5502
|
`);
|
|
5429
5503
|
}
|
|
5430
5504
|
if (answers.acceptance_criteria) {
|
|
5431
|
-
const items = answers.acceptance_criteria.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
5432
5505
|
sections.push(`## Acceptance criteria
|
|
5433
5506
|
|
|
5434
|
-
${
|
|
5507
|
+
${renderAcceptanceCriteria(answers.acceptance_criteria)}
|
|
5435
5508
|
`);
|
|
5436
5509
|
}
|
|
5437
5510
|
if (answers.design) {
|
|
@@ -5554,6 +5627,7 @@ async function runCreate(type, opts = {}) {
|
|
|
5554
5627
|
intro2(`kaddo create ${workItemType}`);
|
|
5555
5628
|
log2.info(`Knowledge level: ${level} \u2014 ${levelDef.description}`);
|
|
5556
5629
|
printStateGuidance(dir);
|
|
5630
|
+
ensureWorkItemsDir(dir);
|
|
5557
5631
|
const title = await text2({
|
|
5558
5632
|
message: "Title for this work item",
|
|
5559
5633
|
placeholder: `e.g. ${workItemType === "feature" ? "Add email verification to checkout" : workItemType === "hotfix" ? "Fix null pointer in payment handler" : workItemType === "bugfix" ? "Fix broken pagination on orders list" : workItemType === "chore" ? "Configure Vitest and CI pipeline" : "Explore caching strategies for API responses"}`,
|
|
@@ -5561,6 +5635,10 @@ async function runCreate(type, opts = {}) {
|
|
|
5561
5635
|
});
|
|
5562
5636
|
const answers = {};
|
|
5563
5637
|
for (const question of levelDef.questions) {
|
|
5638
|
+
if (question.frontMatterField === "acceptance_criteria") {
|
|
5639
|
+
answers.acceptance_criteria = await collectAcceptanceCriteria();
|
|
5640
|
+
continue;
|
|
5641
|
+
}
|
|
5564
5642
|
const answer = await text2({
|
|
5565
5643
|
message: question.prompt,
|
|
5566
5644
|
placeholder: question.placeholder,
|
|
@@ -5577,10 +5655,6 @@ async function runCreate(type, opts = {}) {
|
|
|
5577
5655
|
const content = `${frontMatter2}
|
|
5578
5656
|
|
|
5579
5657
|
${body}`;
|
|
5580
|
-
if (!exists(join(dir, WORK_ITEMS_DIR))) {
|
|
5581
|
-
log2.warn(`${WORK_ITEMS_DIR}/ not found. Run \`kaddo init\` first.`);
|
|
5582
|
-
process.exit(1);
|
|
5583
|
-
}
|
|
5584
5658
|
writeFile(filePath, content);
|
|
5585
5659
|
log2.success(`Created ${DRAFT_DIR}/${fileName}`);
|
|
5586
5660
|
log2.info(`New Work Items start in \`draft\`. Move to \`ready\` when scope and acceptance are set.`);
|
|
@@ -5591,10 +5665,7 @@ async function runCreateModule(dir, modType) {
|
|
|
5591
5665
|
intro2(`kaddo create ${modType.name}`);
|
|
5592
5666
|
log2.info(`Knowledge level: ${modType.knowledgeLevel} \u2014 ${modType.description}`);
|
|
5593
5667
|
printStateGuidance(dir);
|
|
5594
|
-
|
|
5595
|
-
log2.warn(`${WORK_ITEMS_DIR}/ not found. Run \`kaddo init\` first.`);
|
|
5596
|
-
process.exit(1);
|
|
5597
|
-
}
|
|
5668
|
+
ensureWorkItemsDir(dir);
|
|
5598
5669
|
const title = await text2({
|
|
5599
5670
|
message: "Title for this work item",
|
|
5600
5671
|
placeholder: `e.g. ${modType.questions[0]?.placeholder ?? modType.description}`,
|
|
@@ -5731,10 +5802,9 @@ ${formatList(candidate.sourceSignals)}`);
|
|
|
5731
5802
|
${ctx.join("\n\n")}
|
|
5732
5803
|
`);
|
|
5733
5804
|
if (answers.acceptance_criteria) {
|
|
5734
|
-
const items = answers.acceptance_criteria.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
5735
5805
|
sections.push(`## Acceptance Criteria
|
|
5736
5806
|
|
|
5737
|
-
${
|
|
5807
|
+
${renderAcceptanceCriteria(answers.acceptance_criteria)}
|
|
5738
5808
|
`);
|
|
5739
5809
|
}
|
|
5740
5810
|
if (answers.design) sections.push(`## Design
|
|
@@ -5788,10 +5858,7 @@ ${body}` };
|
|
|
5788
5858
|
}
|
|
5789
5859
|
async function runCreateFromRoadmap(dir, cliType) {
|
|
5790
5860
|
intro2("kaddo create --from roadmap");
|
|
5791
|
-
|
|
5792
|
-
log2.warn(`${WORK_ITEMS_DIR}/ not found. Run \`kaddo init\` first.`);
|
|
5793
|
-
process.exit(1);
|
|
5794
|
-
}
|
|
5861
|
+
ensureWorkItemsDir(dir);
|
|
5795
5862
|
const roadmapFull = join(dir, ROADMAP_PATH);
|
|
5796
5863
|
if (!exists(roadmapFull)) {
|
|
5797
5864
|
console.error(`No roadmap found at ${ROADMAP_PATH}.`);
|
|
@@ -6271,6 +6338,54 @@ async function collectWorkspaceChanges(dir, mode = "head", deps = defaultDeps) {
|
|
|
6271
6338
|
};
|
|
6272
6339
|
}
|
|
6273
6340
|
|
|
6341
|
+
// src/core/metadata-health.ts
|
|
6342
|
+
import matter2 from "gray-matter";
|
|
6343
|
+
var KNOWLEDGE_FILES = [
|
|
6344
|
+
"knowledge/business/business.md",
|
|
6345
|
+
"knowledge/product/product.md",
|
|
6346
|
+
"knowledge/product/capabilities.md",
|
|
6347
|
+
"knowledge/tech/codebase.md",
|
|
6348
|
+
"knowledge/tech/current-state.md",
|
|
6349
|
+
"knowledge/delivery/roadmap.md"
|
|
6350
|
+
];
|
|
6351
|
+
var REQUIRED_FIELDS = ["type", "generated_by", "template_version"];
|
|
6352
|
+
function analyzeMetadataHealth(dir) {
|
|
6353
|
+
const findings = [];
|
|
6354
|
+
let healthy = 0;
|
|
6355
|
+
let drifted = 0;
|
|
6356
|
+
for (const rel of KNOWLEDGE_FILES) {
|
|
6357
|
+
const p2 = join(dir, rel);
|
|
6358
|
+
if (!exists(p2)) continue;
|
|
6359
|
+
let data;
|
|
6360
|
+
try {
|
|
6361
|
+
const raw = readFile(p2);
|
|
6362
|
+
data = matter2(raw).data;
|
|
6363
|
+
} catch {
|
|
6364
|
+
continue;
|
|
6365
|
+
}
|
|
6366
|
+
if (Object.keys(data).length === 0) continue;
|
|
6367
|
+
let fileDrifted = false;
|
|
6368
|
+
for (const field of REQUIRED_FIELDS) {
|
|
6369
|
+
if (data[field] === void 0 || data[field] === null || data[field] === "") {
|
|
6370
|
+
findings.push({ file: rel, field, issue: "missing", detail: `Missing \`${field}\` in frontmatter.` });
|
|
6371
|
+
fileDrifted = true;
|
|
6372
|
+
}
|
|
6373
|
+
}
|
|
6374
|
+
if (data.refined_by && data.project_state && data.project_state !== "ai-assisted") {
|
|
6375
|
+
findings.push({
|
|
6376
|
+
file: rel,
|
|
6377
|
+
field: "project_state",
|
|
6378
|
+
issue: "inconsistent",
|
|
6379
|
+
detail: `File has \`refined_by: ${data.refined_by}\` but \`project_state\` is \`${data.project_state}\`, expected \`ai-assisted\`.`
|
|
6380
|
+
});
|
|
6381
|
+
fileDrifted = true;
|
|
6382
|
+
}
|
|
6383
|
+
if (fileDrifted) drifted++;
|
|
6384
|
+
else healthy++;
|
|
6385
|
+
}
|
|
6386
|
+
return { findings, healthy, drifted };
|
|
6387
|
+
}
|
|
6388
|
+
|
|
6274
6389
|
// src/commands/guard.ts
|
|
6275
6390
|
import path4 from "path";
|
|
6276
6391
|
import { parse as parseYaml7 } from "yaml";
|
|
@@ -6893,6 +7008,14 @@ async function runGuard(opts = {}) {
|
|
|
6893
7008
|
console.log("");
|
|
6894
7009
|
}
|
|
6895
7010
|
printPluginSignals(pluginSignals);
|
|
7011
|
+
const mh = analyzeMetadataHealth(dir);
|
|
7012
|
+
if (mh.findings.length > 0) {
|
|
7013
|
+
console.log("Metadata health:");
|
|
7014
|
+
for (const f of mh.findings) {
|
|
7015
|
+
console.log(` \u26A0 ${f.file}: ${f.detail}`);
|
|
7016
|
+
}
|
|
7017
|
+
console.log("");
|
|
7018
|
+
}
|
|
6896
7019
|
const ownerMap = loadOwners(dir);
|
|
6897
7020
|
const matchedDomains = collectMatchedDomains(activeMatches.map((m) => m.artifact.domains));
|
|
6898
7021
|
const affectedOwners = resolveAffectedOwners(matchedDomains, ownerMap);
|
|
@@ -6954,7 +7077,7 @@ function runIgnoreRemove(artifactId) {
|
|
|
6954
7077
|
}
|
|
6955
7078
|
|
|
6956
7079
|
// src/commands/explain.ts
|
|
6957
|
-
import
|
|
7080
|
+
import matter6 from "gray-matter";
|
|
6958
7081
|
import { parse as parseYaml9 } from "yaml";
|
|
6959
7082
|
|
|
6960
7083
|
// src/core/delivery-phase.ts
|
|
@@ -7120,7 +7243,7 @@ function assessPhase(input) {
|
|
|
7120
7243
|
}
|
|
7121
7244
|
|
|
7122
7245
|
// src/core/capsule.ts
|
|
7123
|
-
import
|
|
7246
|
+
import matter3 from "gray-matter";
|
|
7124
7247
|
import { parse as parseYaml8, stringify as stringifyYaml3 } from "yaml";
|
|
7125
7248
|
var KNOWLEDGE = "knowledge";
|
|
7126
7249
|
function today() {
|
|
@@ -7255,7 +7378,7 @@ function sectionParagraph(md, title) {
|
|
|
7255
7378
|
return "";
|
|
7256
7379
|
}
|
|
7257
7380
|
function parseCapsule(id, path6, md) {
|
|
7258
|
-
const { data } =
|
|
7381
|
+
const { data } = matter3(md);
|
|
7259
7382
|
const updatedAt = data.updated_at ? String(data.updated_at) : void 0;
|
|
7260
7383
|
let ageDays = null;
|
|
7261
7384
|
if (updatedAt) {
|
|
@@ -7281,7 +7404,7 @@ function slugId(s) {
|
|
|
7281
7404
|
function addExternalCapsule(dir, sourceFile) {
|
|
7282
7405
|
if (!exists(sourceFile)) throw new Error(`Capsule not found: ${sourceFile}`);
|
|
7283
7406
|
const raw = readFile(sourceFile);
|
|
7284
|
-
const { data } =
|
|
7407
|
+
const { data } = matter3(raw);
|
|
7285
7408
|
const isCapsuleType = data.type === "knowledge-capsule";
|
|
7286
7409
|
const fallbackName = sourceFile.split(/[\\/]/).pop()?.replace(/\.capsule\.md$/, "") ?? "external";
|
|
7287
7410
|
const id = slugId(String(data.system ?? fallbackName));
|
|
@@ -7753,7 +7876,7 @@ function loadGraphHints(dir) {
|
|
|
7753
7876
|
}
|
|
7754
7877
|
|
|
7755
7878
|
// src/services/installed-skills.ts
|
|
7756
|
-
import
|
|
7879
|
+
import matter4 from "gray-matter";
|
|
7757
7880
|
var SKILLS_DIR = join("knowledge", "skills");
|
|
7758
7881
|
function discoverInstalledSkills(dir) {
|
|
7759
7882
|
const base = join(dir, SKILLS_DIR);
|
|
@@ -7763,7 +7886,7 @@ function discoverInstalledSkills(dir) {
|
|
|
7763
7886
|
const skillFile = join(base, entry, "skill.md");
|
|
7764
7887
|
if (!isFile(skillFile)) continue;
|
|
7765
7888
|
try {
|
|
7766
|
-
const { data } =
|
|
7889
|
+
const { data } = matter4(readFile(skillFile));
|
|
7767
7890
|
if (data.type && String(data.type) !== "skill") continue;
|
|
7768
7891
|
const id = String(data.id ?? entry);
|
|
7769
7892
|
out.push({
|
|
@@ -9021,7 +9144,7 @@ function buildSecondaryRecommendations(st) {
|
|
|
9021
9144
|
}
|
|
9022
9145
|
|
|
9023
9146
|
// src/core/readiness.ts
|
|
9024
|
-
var
|
|
9147
|
+
var KNOWLEDGE_FILES2 = [
|
|
9025
9148
|
{ key: "current_state", path: "knowledge/tech/current-state.md", label: "knowledge/tech/current-state.md", agent: "architecture-agent" },
|
|
9026
9149
|
{ key: "codebase", path: "knowledge/tech/codebase.md", label: "knowledge/tech/codebase.md", agent: "codebase-agent" },
|
|
9027
9150
|
{ key: "capabilities", path: "knowledge/product/capabilities.md", label: "knowledge/product/capabilities.md", agent: "capability-agent" },
|
|
@@ -9062,7 +9185,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
9062
9185
|
if (config.project.state === "legacy") return stub("legacy-project", "Use the legacy project flow.");
|
|
9063
9186
|
const scan2 = exists(join(dir, ".kaddo", "scan.json")) ? "available" : "missing";
|
|
9064
9187
|
const understand = exists(join(dir, ".kaddo", "understand.md")) ? "available" : "missing";
|
|
9065
|
-
const presence = Object.fromEntries(
|
|
9188
|
+
const presence = Object.fromEntries(KNOWLEDGE_FILES2.map((f) => [f.key, analyzeKnowledgeArtifact(dir, f.path)]));
|
|
9066
9189
|
const ctx = buildCodexAdapterContext(dir);
|
|
9067
9190
|
const agents = ctx.hasAgents ? "present" : "missing";
|
|
9068
9191
|
const skills = ctx.hasSkills ? "present" : "missing";
|
|
@@ -9090,7 +9213,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
9090
9213
|
resolved_questions: oq.summary.resolution.resolved,
|
|
9091
9214
|
deferred_questions: oq.summary.resolution.deferred
|
|
9092
9215
|
};
|
|
9093
|
-
const firstWeak =
|
|
9216
|
+
const firstWeak = KNOWLEDGE_FILES2.find((f) => presence[f.key] !== "useful");
|
|
9094
9217
|
let overall;
|
|
9095
9218
|
if (scan2 === "missing") overall = "initialized";
|
|
9096
9219
|
else if (bootstrapBaseline2 === "incomplete") overall = "bootstrap-incomplete";
|
|
@@ -9113,7 +9236,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
9113
9236
|
}
|
|
9114
9237
|
|
|
9115
9238
|
// src/core/assets.ts
|
|
9116
|
-
import
|
|
9239
|
+
import matter5 from "gray-matter";
|
|
9117
9240
|
function canonicalAgents() {
|
|
9118
9241
|
return AGENT_PROMPTS.map((a) => ({
|
|
9119
9242
|
name: a.fileName.replace(/\.md$/, ""),
|
|
@@ -9126,7 +9249,7 @@ function canonicalSkills() {
|
|
|
9126
9249
|
}
|
|
9127
9250
|
function versionOf(content) {
|
|
9128
9251
|
try {
|
|
9129
|
-
const v =
|
|
9252
|
+
const v = matter5(content).data.version;
|
|
9130
9253
|
return v === void 0 || v === null ? null : String(v);
|
|
9131
9254
|
} catch {
|
|
9132
9255
|
return null;
|
|
@@ -10028,7 +10151,8 @@ function buildProjectExplanation(dir) {
|
|
|
10028
10151
|
installedAssets: installedAssetsSummary(dir),
|
|
10029
10152
|
roadmapQuality: buildRoadmapQuality(dir),
|
|
10030
10153
|
projectRoute: buildProjectRoute(dir),
|
|
10031
|
-
scanSignals: loadScanSignals(dir)
|
|
10154
|
+
scanSignals: loadScanSignals(dir),
|
|
10155
|
+
metadataHealth: analyzeMetadataHealth(dir)
|
|
10032
10156
|
};
|
|
10033
10157
|
}
|
|
10034
10158
|
function stateLabel(state) {
|
|
@@ -10337,6 +10461,13 @@ function renderExplanationHuman(exp) {
|
|
|
10337
10461
|
}
|
|
10338
10462
|
lines.push("");
|
|
10339
10463
|
}
|
|
10464
|
+
if (exp.metadataHealth.findings.length > 0) {
|
|
10465
|
+
lines.push("## Metadata Health");
|
|
10466
|
+
for (const f of exp.metadataHealth.findings) {
|
|
10467
|
+
lines.push(`- \`${f.file}\`: ${f.detail}`);
|
|
10468
|
+
}
|
|
10469
|
+
lines.push("");
|
|
10470
|
+
}
|
|
10340
10471
|
return lines.join("\n").trimEnd() + "\n";
|
|
10341
10472
|
}
|
|
10342
10473
|
function renderExplanationAgent(exp) {
|
|
@@ -10352,7 +10483,7 @@ function readKnowledge(dir) {
|
|
|
10352
10483
|
if (!exists(knowledgePath)) return null;
|
|
10353
10484
|
try {
|
|
10354
10485
|
const raw = readFile(knowledgePath);
|
|
10355
|
-
const { data, content } =
|
|
10486
|
+
const { data, content } = matter6(raw);
|
|
10356
10487
|
return { content, data };
|
|
10357
10488
|
} catch {
|
|
10358
10489
|
return null;
|
|
@@ -10363,7 +10494,7 @@ function readRoadmap(dir) {
|
|
|
10363
10494
|
if (!exists(roadmapPath)) return null;
|
|
10364
10495
|
try {
|
|
10365
10496
|
const raw = readFile(roadmapPath);
|
|
10366
|
-
const { content } =
|
|
10497
|
+
const { content } = matter6(raw);
|
|
10367
10498
|
return content.trim();
|
|
10368
10499
|
} catch {
|
|
10369
10500
|
return null;
|
|
@@ -10532,7 +10663,7 @@ function runExplain(opts) {
|
|
|
10532
10663
|
}
|
|
10533
10664
|
|
|
10534
10665
|
// src/core/context-pack.ts
|
|
10535
|
-
import
|
|
10666
|
+
import matter7 from "gray-matter";
|
|
10536
10667
|
var CONTEXT_PACK_VERSION = "1";
|
|
10537
10668
|
var ARCH_DIR6 = "knowledge";
|
|
10538
10669
|
function readScanJson(dir) {
|
|
@@ -10545,7 +10676,7 @@ function readScanJson(dir) {
|
|
|
10545
10676
|
}
|
|
10546
10677
|
}
|
|
10547
10678
|
function firstParagraph2(markdown) {
|
|
10548
|
-
const body =
|
|
10679
|
+
const body = matter7(markdown).content.trim();
|
|
10549
10680
|
const para = body.split("\n\n").map((p2) => p2.trim()).find((p2) => p2 && !p2.startsWith("#"));
|
|
10550
10681
|
return para ?? "";
|
|
10551
10682
|
}
|
|
@@ -10760,6 +10891,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
10760
10891
|
skills: discoverInstalledSkills(dir).map((s) => s.id),
|
|
10761
10892
|
scanSignals: scanJson?.signals ?? null,
|
|
10762
10893
|
projectRoute: buildProjectRoute(dir),
|
|
10894
|
+
metadataHealth: analyzeMetadataHealth(dir),
|
|
10763
10895
|
mappedModules,
|
|
10764
10896
|
missing,
|
|
10765
10897
|
// VS-052/VS-073.2: the handoff is driven by the unified next step, so the pack never contradicts
|
|
@@ -11048,6 +11180,13 @@ function renderContextPack(pack) {
|
|
|
11048
11180
|
} else {
|
|
11049
11181
|
parts.push("_None \u2014 all expected context is present._\n");
|
|
11050
11182
|
}
|
|
11183
|
+
if (pack.metadataHealth.findings.length > 0) {
|
|
11184
|
+
parts.push("\n### Metadata Health\n");
|
|
11185
|
+
for (const f of pack.metadataHealth.findings) {
|
|
11186
|
+
parts.push(`- \`${f.file}\`: ${f.detail}
|
|
11187
|
+
`);
|
|
11188
|
+
}
|
|
11189
|
+
}
|
|
11051
11190
|
parts.push("## Recommended Agent Handoff\n");
|
|
11052
11191
|
if (isBootstrapIncomplete) {
|
|
11053
11192
|
parts.push("No agent handoff yet.\n");
|
|
@@ -11179,7 +11318,8 @@ function enrichUnderstandPlan(plan, opts) {
|
|
|
11179
11318
|
activeWorkItems: opts.activeWorkItems,
|
|
11180
11319
|
recommendedPaths: opts.recommendedPaths,
|
|
11181
11320
|
recommendedSkillPaths: opts.recommendedSkillPaths,
|
|
11182
|
-
projectRoute: opts.projectRoute
|
|
11321
|
+
projectRoute: opts.projectRoute,
|
|
11322
|
+
metadataHealth: opts.metadataHealth
|
|
11183
11323
|
};
|
|
11184
11324
|
}
|
|
11185
11325
|
|
|
@@ -11407,6 +11547,13 @@ function renderUnderstand(plan) {
|
|
|
11407
11547
|
} else {
|
|
11408
11548
|
parts.push("Re-run `kaddo understand` any time to see this plan again.\n");
|
|
11409
11549
|
}
|
|
11550
|
+
if (plan.metadataHealth && plan.metadataHealth.findings.length > 0) {
|
|
11551
|
+
parts.push("## Metadata Health\n");
|
|
11552
|
+
for (const f of plan.metadataHealth.findings) {
|
|
11553
|
+
parts.push(`- \`${f.file}\`: ${f.detail}
|
|
11554
|
+
`);
|
|
11555
|
+
}
|
|
11556
|
+
}
|
|
11410
11557
|
return parts.join("\n");
|
|
11411
11558
|
}
|
|
11412
11559
|
function renderUnderstandTerminal(plan) {
|
|
@@ -11467,7 +11614,13 @@ function renderUnderstandTerminal(plan) {
|
|
|
11467
11614
|
}
|
|
11468
11615
|
}
|
|
11469
11616
|
}
|
|
11470
|
-
|
|
11617
|
+
if (plan.metadataHealth && plan.metadataHealth.findings.length > 0) {
|
|
11618
|
+
lines.push("Metadata health:");
|
|
11619
|
+
for (const f of plan.metadataHealth.findings) {
|
|
11620
|
+
lines.push(` \u26A0 ${f.file}: ${f.detail}`);
|
|
11621
|
+
}
|
|
11622
|
+
lines.push("");
|
|
11623
|
+
}
|
|
11471
11624
|
lines.push("Kaddo does not call an LLM. You stay in control of the interpretation.");
|
|
11472
11625
|
lines.push("");
|
|
11473
11626
|
return lines.join("\n");
|
|
@@ -11697,7 +11850,8 @@ function runUnderstand() {
|
|
|
11697
11850
|
recommendedPaths,
|
|
11698
11851
|
recommendedSkillPaths,
|
|
11699
11852
|
language: languageLabel(projectLanguage(config)),
|
|
11700
|
-
projectRoute: buildProjectRoute(dir)
|
|
11853
|
+
projectRoute: buildProjectRoute(dir),
|
|
11854
|
+
metadataHealth: analyzeMetadataHealth(dir)
|
|
11701
11855
|
});
|
|
11702
11856
|
writeFile(join(dir, ".kaddo", "understand.md"), renderUnderstand(enrichedPlan));
|
|
11703
11857
|
log2.success("Wrote .kaddo/understand.md");
|
|
@@ -11987,7 +12141,7 @@ function runStatus() {
|
|
|
11987
12141
|
}
|
|
11988
12142
|
|
|
11989
12143
|
// src/commands/learn.ts
|
|
11990
|
-
import
|
|
12144
|
+
import matter8 from "gray-matter";
|
|
11991
12145
|
var ARCH_DIR9 = "knowledge";
|
|
11992
12146
|
var WORK_ITEMS_DIR2 = "knowledge/delivery/work-items";
|
|
11993
12147
|
function findWorkItemFile(dir, id) {
|
|
@@ -11999,7 +12153,7 @@ function findWorkItemFile(dir, id) {
|
|
|
11999
12153
|
}
|
|
12000
12154
|
function updateWorkItemFile(filePath, learning) {
|
|
12001
12155
|
const raw = readFile(filePath);
|
|
12002
|
-
const { data, content } =
|
|
12156
|
+
const { data, content } = matter8(raw);
|
|
12003
12157
|
data.status = "done";
|
|
12004
12158
|
data.completed_at = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
12005
12159
|
let updatedContent = content;
|
|
@@ -12024,7 +12178,7 @@ ${learning.trim()}
|
|
|
12024
12178
|
${learning.trim()}
|
|
12025
12179
|
`;
|
|
12026
12180
|
}
|
|
12027
|
-
const newRaw =
|
|
12181
|
+
const newRaw = matter8.stringify(updatedContent, data);
|
|
12028
12182
|
writeFile(filePath, newRaw);
|
|
12029
12183
|
}
|
|
12030
12184
|
async function runLearn(artifactId) {
|
|
@@ -12274,7 +12428,7 @@ function runAdd(moduleName, opts = {}, dir = cwd()) {
|
|
|
12274
12428
|
}
|
|
12275
12429
|
|
|
12276
12430
|
// src/core/ownership-suggest.ts
|
|
12277
|
-
import
|
|
12431
|
+
import matter9 from "gray-matter";
|
|
12278
12432
|
var SCAN_PATH = ".kaddo/scan.json";
|
|
12279
12433
|
function normalizeGlob(input) {
|
|
12280
12434
|
let g = input.trim().replace(/\\/g, "/");
|
|
@@ -12396,11 +12550,11 @@ function suggestGlobs(artifact, signals) {
|
|
|
12396
12550
|
return [...new Set(out)];
|
|
12397
12551
|
}
|
|
12398
12552
|
function applyOwnership(raw, globs, mode = "replace") {
|
|
12399
|
-
const parsed =
|
|
12553
|
+
const parsed = matter9(raw);
|
|
12400
12554
|
const existing = toStringArray3(parsed.data.code);
|
|
12401
12555
|
const next = mode === "append" ? [.../* @__PURE__ */ new Set([...existing, ...globs])] : [...new Set(globs)];
|
|
12402
12556
|
const data = { ...parsed.data, code: next };
|
|
12403
|
-
return
|
|
12557
|
+
return matter9.stringify(parsed.content, data);
|
|
12404
12558
|
}
|
|
12405
12559
|
|
|
12406
12560
|
// src/commands/owners.ts
|
|
@@ -15012,7 +15166,7 @@ function runGraphExport(opts = {}) {
|
|
|
15012
15166
|
}
|
|
15013
15167
|
|
|
15014
15168
|
// src/core/impact-report.ts
|
|
15015
|
-
import
|
|
15169
|
+
import matter10 from "gray-matter";
|
|
15016
15170
|
function isBroadGlob(glob) {
|
|
15017
15171
|
if (!glob.endsWith("/**")) return false;
|
|
15018
15172
|
const prefix = glob.slice(0, -3);
|
|
@@ -15081,7 +15235,7 @@ function buildImpactReport(dir, opts = {}, now = /* @__PURE__ */ new Date()) {
|
|
|
15081
15235
|
}
|
|
15082
15236
|
}
|
|
15083
15237
|
try {
|
|
15084
|
-
const body =
|
|
15238
|
+
const body = matter10(readFile(wi.filePath)).content;
|
|
15085
15239
|
if (hasSection(body, /acceptance|criterios de aceptaci/i)) withAcceptance++;
|
|
15086
15240
|
else gaps.missing_acceptance_criteria.push(gapItem(wi, "Add an `## Acceptance Criteria` section."));
|
|
15087
15241
|
if (hasSection(body, /definition of done|^#{1,6}\s*dod\b|definici[oó]n de (terminado|hecho)/i)) withDoD++;
|