@kaddo/mcp 3.43.0 → 3.44.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 +168 -44
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1629,7 +1629,12 @@ function splitInitiatives(markdown) {
|
|
|
1629
1629
|
return blocks;
|
|
1630
1630
|
}
|
|
1631
1631
|
function parseBlock(block) {
|
|
1632
|
-
const meta = {
|
|
1632
|
+
const meta = {
|
|
1633
|
+
relatedCapabilities: [],
|
|
1634
|
+
dependencies: [],
|
|
1635
|
+
openQuestions: [],
|
|
1636
|
+
sourceSignals: []
|
|
1637
|
+
};
|
|
1633
1638
|
const rawCandidates = [];
|
|
1634
1639
|
let listField = null;
|
|
1635
1640
|
let inCandidateSection = false;
|
|
@@ -1679,7 +1684,7 @@ function parseBlock(block) {
|
|
|
1679
1684
|
meta.impact = value || void 0;
|
|
1680
1685
|
} else if (key === "risk") {
|
|
1681
1686
|
meta.risk = value || void 0;
|
|
1682
|
-
} else if (key === "project area / domain" || key === "domain" || key === "project area") {
|
|
1687
|
+
} else if (key === "project area / domain" || key === "domain" || key === "project area" || key === "related domain") {
|
|
1683
1688
|
meta.domain = value || void 0;
|
|
1684
1689
|
} else if (key === "related capabilities") {
|
|
1685
1690
|
listField = "relatedCapabilities";
|
|
@@ -1690,6 +1695,9 @@ function parseBlock(block) {
|
|
|
1690
1695
|
} else if (key === "open questions") {
|
|
1691
1696
|
listField = "openQuestions";
|
|
1692
1697
|
if (value) meta.openQuestions.push(value);
|
|
1698
|
+
} else if (key === "source signals" || key === "source signal") {
|
|
1699
|
+
listField = "sourceSignals";
|
|
1700
|
+
if (value) meta.sourceSignals.push(value);
|
|
1693
1701
|
}
|
|
1694
1702
|
continue;
|
|
1695
1703
|
}
|
|
@@ -1707,6 +1715,7 @@ function parseBlock(block) {
|
|
|
1707
1715
|
}
|
|
1708
1716
|
}
|
|
1709
1717
|
flush();
|
|
1718
|
+
const decisionCandidates = decisionCandidatesFromSignals(meta.sourceSignals);
|
|
1710
1719
|
return rawCandidates.map((c) => ({
|
|
1711
1720
|
...c,
|
|
1712
1721
|
initiative: block.initiative.id || block.initiative.title ? { ...block.initiative } : void 0,
|
|
@@ -1715,9 +1724,23 @@ function parseBlock(block) {
|
|
|
1715
1724
|
impact: meta.impact,
|
|
1716
1725
|
risk: meta.risk,
|
|
1717
1726
|
dependencies: meta.dependencies.length ? [...meta.dependencies] : void 0,
|
|
1718
|
-
openQuestions: meta.openQuestions.length ? [...meta.openQuestions] : void 0
|
|
1727
|
+
openQuestions: meta.openQuestions.length ? [...meta.openQuestions] : void 0,
|
|
1728
|
+
sourceSignals: meta.sourceSignals.length ? [...meta.sourceSignals] : void 0,
|
|
1729
|
+
decisionCandidates: decisionCandidates.length ? decisionCandidates : void 0
|
|
1719
1730
|
}));
|
|
1720
1731
|
}
|
|
1732
|
+
function decisionCandidatesFromSignals(signals) {
|
|
1733
|
+
const out = [];
|
|
1734
|
+
for (const sig of signals) {
|
|
1735
|
+
const m = sig.match(/decision candidate\s*:?\s*(.+)$/i);
|
|
1736
|
+
if (!m) continue;
|
|
1737
|
+
const rest = m[1].trim();
|
|
1738
|
+
const token = rest.match(/\b[A-Z][A-Z0-9_]{2,}\b/);
|
|
1739
|
+
const value = token ? token[0] : rest.replace(/[.。]+$/, "").trim();
|
|
1740
|
+
if (value && !out.includes(value)) out.push(value);
|
|
1741
|
+
}
|
|
1742
|
+
return out;
|
|
1743
|
+
}
|
|
1721
1744
|
var WI_ID_RE = /\bWI-[A-Za-z0-9-]*\d/;
|
|
1722
1745
|
var HEADING_RE = /^#{2,4}\s+(.*)$/;
|
|
1723
1746
|
var FLEX_BULLET_RE = /^\s*[-*]\s+(?:\[[ xX]?\]\s+)?(WI-[A-Za-z0-9-]*\d)\b[\s:.\-–)]*\s*(.*)$/;
|
|
@@ -1799,10 +1822,36 @@ function parseRoadmapCandidates(markdown) {
|
|
|
1799
1822
|
if (strict.length > 0) return strict;
|
|
1800
1823
|
return parseFlexible(markdown);
|
|
1801
1824
|
}
|
|
1825
|
+
function countRoadmapInitiatives(markdown) {
|
|
1826
|
+
if (markdown == null) return 0;
|
|
1827
|
+
let n = 0;
|
|
1828
|
+
for (const line of markdown.split(/\r?\n/)) if (INITIATIVE_RE.test(line)) n++;
|
|
1829
|
+
return n;
|
|
1830
|
+
}
|
|
1802
1831
|
function roadmapStats(markdown, materialized) {
|
|
1803
|
-
if (markdown == null)
|
|
1832
|
+
if (markdown == null)
|
|
1833
|
+
return {
|
|
1834
|
+
present: false,
|
|
1835
|
+
initiatives: 0,
|
|
1836
|
+
work_item_candidates: 0,
|
|
1837
|
+
materialized_work_items: materialized,
|
|
1838
|
+
remaining_work_item_candidates: 0,
|
|
1839
|
+
candidates: 0,
|
|
1840
|
+
materialized,
|
|
1841
|
+
remaining: 0
|
|
1842
|
+
};
|
|
1804
1843
|
const candidates = parseRoadmapCandidates(markdown).length;
|
|
1805
|
-
|
|
1844
|
+
const remaining = Math.max(0, candidates - materialized);
|
|
1845
|
+
return {
|
|
1846
|
+
present: true,
|
|
1847
|
+
initiatives: countRoadmapInitiatives(markdown),
|
|
1848
|
+
work_item_candidates: candidates,
|
|
1849
|
+
materialized_work_items: materialized,
|
|
1850
|
+
remaining_work_item_candidates: remaining,
|
|
1851
|
+
candidates,
|
|
1852
|
+
materialized,
|
|
1853
|
+
remaining
|
|
1854
|
+
};
|
|
1806
1855
|
}
|
|
1807
1856
|
|
|
1808
1857
|
// ../cli/src/core/open-questions.ts
|
|
@@ -4015,13 +4064,22 @@ that it should be materialized first (\`kaddo adr\` + the adr-writing skill) and
|
|
|
4015
4064
|
without surfacing it. -->
|
|
4016
4065
|
\`\`\`
|
|
4017
4066
|
|
|
4018
|
-
### Preserve roadmap metadata (VS-077)
|
|
4067
|
+
### Preserve roadmap metadata (VS-077 / VS-078)
|
|
4068
|
+
|
|
4069
|
+
When a Work Item comes from \`kaddo create --from roadmap\`, the front matter already carries the trace
|
|
4070
|
+
back to the roadmap. **Keep and refine \u2014 never delete** these fields:
|
|
4071
|
+
|
|
4072
|
+
- \`source_roadmap_initiative\` and \`source_work_item_candidate\` (the RM-xxx initiative and the
|
|
4073
|
+
WI-CANDIDATE-xxx it was materialized from)
|
|
4074
|
+
- \`related_domain\` and \`domains\` (keep them consistent \u2014 \`domains\` must not be empty when
|
|
4075
|
+
\`related_domain\` exists)
|
|
4076
|
+
- \`related_capabilities\` (a real list, one capability per item \u2014 never a single comma-joined string)
|
|
4077
|
+
- \`expected_value\`, \`risks\`, \`dependencies\`
|
|
4078
|
+
- \`source_signals\` (do **not** invent them \u2014 if absent, leave them absent)
|
|
4079
|
+
- \`decision_candidates\` and \`related_decisions\` (when the work depends on a technical decision)
|
|
4019
4080
|
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
\`knowledge_level\`, \`expected_value\`, \`risks\` and \`dependencies\`. **Keep and refine** this metadata \u2014
|
|
4023
|
-
do not drop the trace back to the capability domain and source signals. Add \`related_decisions\` /
|
|
4024
|
-
\`decision_candidates\` when the work depends on a technical decision.
|
|
4081
|
+
Do not drop the trace back to the capability domain and source signals. If a Work Item depends on a
|
|
4082
|
+
tech decision candidate with no ADR yet, keep the warning surfaced in the body.
|
|
4025
4083
|
|
|
4026
4084
|
## Where to Save the Result
|
|
4027
4085
|
|
|
@@ -5304,16 +5362,25 @@ function buildRoadmapQuality(dir) {
|
|
|
5304
5362
|
const items = parseRoadmapCandidateQuality(md);
|
|
5305
5363
|
const count = (pred) => items.filter(pred).length;
|
|
5306
5364
|
const grounded = count((i) => i.grounded);
|
|
5307
|
-
|
|
5308
|
-
|
|
5365
|
+
const initiatives = {
|
|
5366
|
+
total: items.length,
|
|
5309
5367
|
grounded,
|
|
5310
5368
|
with_related_domain: count((i) => i.hasRelatedDomain),
|
|
5311
5369
|
with_related_capability: count((i) => i.hasRelatedCapability),
|
|
5312
5370
|
with_source_signals: count((i) => i.hasSourceSignals),
|
|
5313
|
-
// Only "needs refinement" when there are
|
|
5371
|
+
// Only "needs refinement" when there are initiatives and at least one isn't grounded.
|
|
5314
5372
|
needs_refinement: items.length > 0 && grounded < items.length,
|
|
5315
5373
|
items
|
|
5316
5374
|
};
|
|
5375
|
+
const wiCandidates = md ? parseRoadmapCandidates(md) : [];
|
|
5376
|
+
const wcount = (pred) => wiCandidates.filter(pred).length;
|
|
5377
|
+
const work_item_candidates = {
|
|
5378
|
+
total: wiCandidates.length,
|
|
5379
|
+
with_source_initiative: wcount((c) => Boolean(c.initiative?.id || c.initiative?.title)),
|
|
5380
|
+
with_related_domain: wcount((c) => Boolean(c.domain)),
|
|
5381
|
+
with_related_capability: wcount((c) => Boolean(c.relatedCapabilities?.length))
|
|
5382
|
+
};
|
|
5383
|
+
return { initiatives, work_item_candidates };
|
|
5317
5384
|
}
|
|
5318
5385
|
|
|
5319
5386
|
// ../cli/src/core/project-explain.ts
|
|
@@ -5596,10 +5663,11 @@ function renderExplanationHuman(exp) {
|
|
|
5596
5663
|
lines.push(`- Delivery: ${ls("Delivery")}`);
|
|
5597
5664
|
lines.push(`- Agents: ${exp.knowledge.hasAgents ? "available" : "missing"}`);
|
|
5598
5665
|
if (exp.roadmap.present) {
|
|
5599
|
-
lines.push(`- Roadmap
|
|
5600
|
-
lines.push(`-
|
|
5601
|
-
|
|
5602
|
-
|
|
5666
|
+
lines.push(`- Roadmap initiatives: ${exp.roadmap.initiatives}`);
|
|
5667
|
+
lines.push(`- Work Item candidates: ${exp.roadmap.work_item_candidates}`);
|
|
5668
|
+
lines.push(`- Materialized Work Items: ${exp.roadmap.materialized_work_items}`);
|
|
5669
|
+
if (exp.roadmap.remaining_work_item_candidates > 0)
|
|
5670
|
+
lines.push(`- Remaining Work Item candidates: ${exp.roadmap.remaining_work_item_candidates}`);
|
|
5603
5671
|
} else {
|
|
5604
5672
|
lines.push(`- Work items: ${exp.workItems.total}`);
|
|
5605
5673
|
}
|
|
@@ -5776,17 +5844,42 @@ function renderExplanationHuman(exp) {
|
|
|
5776
5844
|
lines.push("Tech discovery files are in the legacy `knowledge/tech/` root. Suggested cleanup: run `kaddo tech organize`.");
|
|
5777
5845
|
lines.push("");
|
|
5778
5846
|
}
|
|
5847
|
+
if (exp.roadmap.present) {
|
|
5848
|
+
lines.push("## Roadmap Status");
|
|
5849
|
+
lines.push(`- Initiatives: ${exp.roadmap.initiatives}`);
|
|
5850
|
+
lines.push(`- Work Item candidates: ${exp.roadmap.work_item_candidates}`);
|
|
5851
|
+
lines.push(`- Materialized Work Items: ${exp.roadmap.materialized_work_items}`);
|
|
5852
|
+
lines.push(`- Remaining Work Item candidates: ${exp.roadmap.remaining_work_item_candidates}`);
|
|
5853
|
+
lines.push("");
|
|
5854
|
+
}
|
|
5779
5855
|
const rq = exp.roadmapQuality;
|
|
5780
|
-
|
|
5856
|
+
const rqi = rq.initiatives;
|
|
5857
|
+
const rqw = rq.work_item_candidates;
|
|
5858
|
+
if (rqi.total > 0 || rqw.total > 0) {
|
|
5781
5859
|
lines.push("## Roadmap Quality");
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5860
|
+
if (rqi.total > 0) {
|
|
5861
|
+
lines.push("Initiatives:");
|
|
5862
|
+
lines.push(`- Candidates evaluated: ${rqi.total}`);
|
|
5863
|
+
lines.push(`- Grounded: ${rqi.grounded}/${rqi.total}`);
|
|
5864
|
+
lines.push(`- With related domain: ${rqi.with_related_domain}/${rqi.total}`);
|
|
5865
|
+
lines.push(`- With related capability: ${rqi.with_related_capability}/${rqi.total}`);
|
|
5866
|
+
lines.push(`- With source signals: ${rqi.with_source_signals}/${rqi.total}`);
|
|
5867
|
+
}
|
|
5868
|
+
if (rqw.total > 0) {
|
|
5788
5869
|
lines.push("");
|
|
5789
|
-
lines.push("
|
|
5870
|
+
lines.push("Work Item Candidates:");
|
|
5871
|
+
lines.push(`- Candidates: ${rqw.total}`);
|
|
5872
|
+
lines.push(`- With source initiative: ${rqw.with_source_initiative}/${rqw.total}`);
|
|
5873
|
+
lines.push(`- With related domain: ${rqw.with_related_domain}/${rqw.total}`);
|
|
5874
|
+
lines.push(`- With related capability: ${rqw.with_related_capability}/${rqw.total}`);
|
|
5875
|
+
}
|
|
5876
|
+
if (rqi.needs_refinement) {
|
|
5877
|
+
lines.push("");
|
|
5878
|
+
lines.push("Roadmap quality: needs refinement.");
|
|
5879
|
+
lines.push("Suggested: use roadmap-agent to add domain / capability / source signals.");
|
|
5880
|
+
} else if (rqw.total > 0) {
|
|
5881
|
+
lines.push("");
|
|
5882
|
+
lines.push("Work Item candidate quality: good.");
|
|
5790
5883
|
}
|
|
5791
5884
|
lines.push("");
|
|
5792
5885
|
}
|
|
@@ -7019,7 +7112,7 @@ var RESOURCES = [
|
|
|
7019
7112
|
{
|
|
7020
7113
|
uri: "kaddo://roadmap-quality",
|
|
7021
7114
|
name: "Kaddo roadmap quality",
|
|
7022
|
-
description: "How well roadmap candidates are grounded in capability domains, related capabilities and source signals (VS-077). Read-only.",
|
|
7115
|
+
description: "How well roadmap initiatives and Work Item candidates are grounded in capability domains, related capabilities and source signals (VS-077 / VS-077.1). Two levels: initiatives + work_item_candidates. Read-only.",
|
|
7023
7116
|
mimeType: "application/json",
|
|
7024
7117
|
read: (root) => {
|
|
7025
7118
|
if (!hasKnowledge(root)) {
|
|
@@ -7027,6 +7120,20 @@ var RESOURCES = [
|
|
|
7027
7120
|
}
|
|
7028
7121
|
return [{ uri: "kaddo://roadmap-quality", text: JSON.stringify(buildRoadmapQuality(root), null, 2), mimeType: "application/json" }];
|
|
7029
7122
|
}
|
|
7123
|
+
},
|
|
7124
|
+
{
|
|
7125
|
+
uri: "kaddo://work-item-candidates",
|
|
7126
|
+
name: "Kaddo work item candidates",
|
|
7127
|
+
description: "Materializable Work Item candidates (WI-CANDIDATE-xxx) parsed from the roadmap, with their source initiative and inherited metadata (VS-078). Read-only.",
|
|
7128
|
+
mimeType: "application/json",
|
|
7129
|
+
read: (root) => {
|
|
7130
|
+
if (!hasKnowledge(root)) {
|
|
7131
|
+
return text("kaddo://work-item-candidates", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
7132
|
+
}
|
|
7133
|
+
const md = readText(root, "knowledge/delivery/roadmap.md");
|
|
7134
|
+
const candidates = md ? parseRoadmapCandidates(md) : [];
|
|
7135
|
+
return [{ uri: "kaddo://work-item-candidates", text: JSON.stringify({ candidates }, null, 2), mimeType: "application/json" }];
|
|
7136
|
+
}
|
|
7030
7137
|
}
|
|
7031
7138
|
];
|
|
7032
7139
|
|
|
@@ -7454,35 +7561,52 @@ function renderContextPack(pack) {
|
|
|
7454
7561
|
}
|
|
7455
7562
|
parts.push("## Current Knowledge\n");
|
|
7456
7563
|
parts.push((knowledge.summary || "No project knowledge summary found yet.") + "\n");
|
|
7457
|
-
parts.push("## Roadmap\n");
|
|
7564
|
+
parts.push("## Roadmap Status\n");
|
|
7458
7565
|
if (pack.roadmap.present) {
|
|
7459
7566
|
parts.push(
|
|
7460
7567
|
[
|
|
7461
|
-
`-
|
|
7462
|
-
`-
|
|
7463
|
-
`-
|
|
7568
|
+
`- Initiatives: ${pack.roadmap.initiatives}`,
|
|
7569
|
+
`- Work Item candidates: ${pack.roadmap.work_item_candidates}`,
|
|
7570
|
+
`- Materialized Work Items: ${pack.roadmap.materialized_work_items}`,
|
|
7571
|
+
`- Remaining Work Item candidates: ${pack.roadmap.remaining_work_item_candidates}`
|
|
7464
7572
|
].join("\n") + "\n"
|
|
7465
7573
|
);
|
|
7466
|
-
if (pack.roadmap.
|
|
7574
|
+
if (pack.roadmap.remaining_work_item_candidates > 0) {
|
|
7467
7575
|
parts.push(
|
|
7468
|
-
"
|
|
7576
|
+
"Work Item candidates are not yet Work Items. Materialize them with `kaddo create --from roadmap`.\n"
|
|
7469
7577
|
);
|
|
7470
7578
|
}
|
|
7471
7579
|
}
|
|
7472
7580
|
parts.push((knowledge.roadmapSummary || "No roadmap baseline found.") + "\n");
|
|
7473
7581
|
const rq = pack.roadmapQuality;
|
|
7474
|
-
|
|
7582
|
+
const rqi = rq.initiatives;
|
|
7583
|
+
const rqw = rq.work_item_candidates;
|
|
7584
|
+
if (rqi.total > 0 || rqw.total > 0) {
|
|
7475
7585
|
parts.push("## Roadmap Quality\n");
|
|
7476
|
-
|
|
7477
|
-
|
|
7478
|
-
|
|
7479
|
-
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
|
|
7483
|
-
|
|
7484
|
-
|
|
7485
|
-
|
|
7586
|
+
if (rqi.total > 0) {
|
|
7587
|
+
parts.push(
|
|
7588
|
+
[
|
|
7589
|
+
"Initiatives:",
|
|
7590
|
+
`- Candidates evaluated: ${rqi.total}`,
|
|
7591
|
+
`- Grounded: ${rqi.grounded}/${rqi.total}`,
|
|
7592
|
+
`- With related domain: ${rqi.with_related_domain}/${rqi.total}`,
|
|
7593
|
+
`- With related capability: ${rqi.with_related_capability}/${rqi.total}`,
|
|
7594
|
+
`- With source signals: ${rqi.with_source_signals}/${rqi.total}`
|
|
7595
|
+
].join("\n") + "\n"
|
|
7596
|
+
);
|
|
7597
|
+
}
|
|
7598
|
+
if (rqw.total > 0) {
|
|
7599
|
+
parts.push(
|
|
7600
|
+
[
|
|
7601
|
+
"Work Item Candidates:",
|
|
7602
|
+
`- Candidates: ${rqw.total}`,
|
|
7603
|
+
`- With source initiative: ${rqw.with_source_initiative}/${rqw.total}`,
|
|
7604
|
+
`- With related domain: ${rqw.with_related_domain}/${rqw.total}`,
|
|
7605
|
+
`- With related capability: ${rqw.with_related_capability}/${rqw.total}`
|
|
7606
|
+
].join("\n") + "\n"
|
|
7607
|
+
);
|
|
7608
|
+
}
|
|
7609
|
+
if (rqi.needs_refinement) {
|
|
7486
7610
|
parts.push(
|
|
7487
7611
|
"Roadmap quality: needs refinement. Use the roadmap-agent to add domain / capability / source signals.\n"
|
|
7488
7612
|
);
|
package/package.json
CHANGED