@kaddo/mcp 3.42.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 +304 -26
- 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
|
|
@@ -3628,6 +3677,24 @@ Adapt priorities to the project state from the context pack:
|
|
|
3628
3677
|
- **legacy** \u2014 prioritize risk reduction, unknowns and safe modernization before feature
|
|
3629
3678
|
delivery.
|
|
3630
3679
|
|
|
3680
|
+
## Grounding rules (VS-077)
|
|
3681
|
+
|
|
3682
|
+
Every candidate initiative must be **grounded** in the knowledge base \u2014 never a loose idea. For each
|
|
3683
|
+
\`### RM-xxx\` you must provide:
|
|
3684
|
+
|
|
3685
|
+
- **Related domain** \u2014 a domain from \`## Capability Domains\` in \`capabilities.md\` (or, if genuinely
|
|
3686
|
+
new, prefix it \`[new candidate domain] <name>\` \u2014 do not invent domains silently).
|
|
3687
|
+
- **Related capabilities** \u2014 one or more existing/partial capabilities.
|
|
3688
|
+
- **Source signals** \u2014 at least one traceable reason: Capability Gap, Roadmap Candidate Signal, Risk,
|
|
3689
|
+
Open Question, Assumption, Deferred Decision, Tech Decision Candidate, ADR, Business Goal,
|
|
3690
|
+
Operational Need or Legacy Modernization Signal.
|
|
3691
|
+
- **Expected value**, **Risks**, **Dependencies**, and **Suggested Work Items** (candidates only).
|
|
3692
|
+
|
|
3693
|
+
Do **not** emit a candidate with no source signal. Keep initiatives at initiative granularity (small
|
|
3694
|
+
tasks go under **Suggested Work Items**, not as their own RM). Every roadmap ends with a global
|
|
3695
|
+
**## Not Now** section. For pre-ai/legacy, prioritize stabilization, security, data, operations,
|
|
3696
|
+
architectural decisions and business-blocking gaps before expansive features.
|
|
3697
|
+
|
|
3631
3698
|
## Constraints
|
|
3632
3699
|
|
|
3633
3700
|
- Do not invent business priorities or business facts \u2014 mark them as assumptions when inferred.
|
|
@@ -3636,6 +3703,8 @@ Adapt priorities to the project state from the context pack:
|
|
|
3636
3703
|
implementation-agent, and only after Work Items are materialized. Your handoff is
|
|
3637
3704
|
\`kaddo create --from roadmap\` \u2192 work-item-agent.
|
|
3638
3705
|
- Do not create the work items themselves; only propose candidates.
|
|
3706
|
+
- **Never create files under \`knowledge/delivery/work-items/\`** \u2014 materialization is
|
|
3707
|
+
\`kaddo create --from roadmap\`, not the roadmap-agent.
|
|
3639
3708
|
- Make clear that initiatives and work items are **candidates**, not final decisions.
|
|
3640
3709
|
- Mark any uncertain information as an assumption or open question.
|
|
3641
3710
|
- Keep sequencing justified by dependencies and risk.
|
|
@@ -3669,31 +3738,38 @@ human review \u2014 not final commitments.
|
|
|
3669
3738
|
|
|
3670
3739
|
### RM-001: <Initiative Name>
|
|
3671
3740
|
|
|
3672
|
-
**
|
|
3741
|
+
**Status:** candidate <!-- candidate | selected | deferred | rejected -->
|
|
3673
3742
|
|
|
3674
|
-
**
|
|
3743
|
+
**Priority:** high / medium / low
|
|
3675
3744
|
|
|
3676
|
-
**
|
|
3745
|
+
**Suggested Knowledge Level:** K1 / K2 / K3 / K4
|
|
3677
3746
|
|
|
3678
|
-
**
|
|
3747
|
+
**Related domain:** <one of the ## Capability Domains from capabilities.md>
|
|
3679
3748
|
|
|
3680
|
-
**
|
|
3749
|
+
**Related capabilities:**
|
|
3750
|
+
- <existing or partial capability>
|
|
3681
3751
|
|
|
3682
|
-
**
|
|
3752
|
+
**Source signals:** <!-- REQUIRED: why this candidate exists (at least one) -->
|
|
3753
|
+
- Capability Gap: <...>
|
|
3754
|
+
- Roadmap Candidate Signal: <...>
|
|
3755
|
+
- Risk / Open Question / Assumption / Deferred Decision / Tech Decision Candidate / ADR / Business Goal: <...>
|
|
3683
3756
|
|
|
3684
|
-
**
|
|
3757
|
+
**Problem / opportunity:**
|
|
3685
3758
|
|
|
3686
|
-
**
|
|
3759
|
+
**Expected value:**
|
|
3687
3760
|
|
|
3688
|
-
**
|
|
3761
|
+
**Risks:**
|
|
3689
3762
|
|
|
3763
|
+
**Dependencies:**
|
|
3764
|
+
|
|
3765
|
+
**Suggested Work Items:**
|
|
3690
3766
|
- WI-CANDIDATE-001: <candidate work item>
|
|
3691
3767
|
- type:
|
|
3692
3768
|
- suggested knowledge level:
|
|
3693
3769
|
- expected value:
|
|
3694
3770
|
- notes:
|
|
3695
3771
|
|
|
3696
|
-
**
|
|
3772
|
+
**Not now:**
|
|
3697
3773
|
|
|
3698
3774
|
---
|
|
3699
3775
|
|
|
@@ -3988,6 +4064,23 @@ that it should be materialized first (\`kaddo adr\` + the adr-writing skill) and
|
|
|
3988
4064
|
without surfacing it. -->
|
|
3989
4065
|
\`\`\`
|
|
3990
4066
|
|
|
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)
|
|
4080
|
+
|
|
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.
|
|
4083
|
+
|
|
3991
4084
|
## Where to Save the Result
|
|
3992
4085
|
|
|
3993
4086
|
Save new output as a draft under \`knowledge/delivery/work-items/draft/\` unless a human
|
|
@@ -5208,6 +5301,88 @@ function installedAssetsSummary(dir) {
|
|
|
5208
5301
|
return { version: KADDO_VERSION, agents: assetStatus(dir, "agent"), skills: assetStatus(dir, "skill") };
|
|
5209
5302
|
}
|
|
5210
5303
|
|
|
5304
|
+
// ../cli/src/core/roadmap-quality.ts
|
|
5305
|
+
var ROADMAP_PATH = "knowledge/delivery/roadmap.md";
|
|
5306
|
+
var INITIATIVE_RE2 = /^#{2,4}\s+(RM-[\w.-]+)\s*[:\-–]?\s*(.*)$/;
|
|
5307
|
+
function fieldPresent(lines, label) {
|
|
5308
|
+
for (let i = 0; i < lines.length; i++) {
|
|
5309
|
+
const m = lines[i].match(new RegExp(`^\\s*[-*]?\\s*(?:\\*\\*)?\\s*(${label.source})\\s*(?:\\*\\*)?\\s*:\\s*(.*)$`, "i"));
|
|
5310
|
+
if (!m) continue;
|
|
5311
|
+
const inline = m[2].trim();
|
|
5312
|
+
if (inline) return true;
|
|
5313
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
5314
|
+
if (/^\s{2,}[-*]\s+\S/.test(lines[j])) return true;
|
|
5315
|
+
if (/^\S/.test(lines[j]) || /^#{2,4}\s/.test(lines[j])) break;
|
|
5316
|
+
if (/^\s*[-*]\s+\S/.test(lines[j]) && !/^\s{2,}/.test(lines[j])) break;
|
|
5317
|
+
}
|
|
5318
|
+
}
|
|
5319
|
+
return false;
|
|
5320
|
+
}
|
|
5321
|
+
function parseRoadmapCandidateQuality(md) {
|
|
5322
|
+
const lines = md.split(/\r?\n/);
|
|
5323
|
+
const items = [];
|
|
5324
|
+
let cur = null;
|
|
5325
|
+
const flush = () => {
|
|
5326
|
+
if (!cur) return;
|
|
5327
|
+
const hasRelatedDomain = fieldPresent(cur.lines, /related domain/);
|
|
5328
|
+
const hasRelatedCapability = fieldPresent(cur.lines, /related capabilit(?:y|ies)/);
|
|
5329
|
+
const hasSourceSignals = fieldPresent(cur.lines, /source signals?/);
|
|
5330
|
+
items.push({
|
|
5331
|
+
id: cur.id,
|
|
5332
|
+
title: cur.title,
|
|
5333
|
+
hasRelatedDomain,
|
|
5334
|
+
hasRelatedCapability,
|
|
5335
|
+
hasSourceSignals,
|
|
5336
|
+
grounded: hasRelatedDomain && hasRelatedCapability && hasSourceSignals
|
|
5337
|
+
});
|
|
5338
|
+
cur = null;
|
|
5339
|
+
};
|
|
5340
|
+
for (const line of lines) {
|
|
5341
|
+
const m = line.match(INITIATIVE_RE2);
|
|
5342
|
+
if (m) {
|
|
5343
|
+
flush();
|
|
5344
|
+
cur = { id: m[1], title: m[2].trim(), lines: [] };
|
|
5345
|
+
continue;
|
|
5346
|
+
}
|
|
5347
|
+
if (cur) cur.lines.push(line);
|
|
5348
|
+
}
|
|
5349
|
+
flush();
|
|
5350
|
+
return items;
|
|
5351
|
+
}
|
|
5352
|
+
function buildRoadmapQuality(dir) {
|
|
5353
|
+
let md = "";
|
|
5354
|
+
const p = join(dir, ROADMAP_PATH);
|
|
5355
|
+
if (exists(p)) {
|
|
5356
|
+
try {
|
|
5357
|
+
md = readFile(p);
|
|
5358
|
+
} catch {
|
|
5359
|
+
md = "";
|
|
5360
|
+
}
|
|
5361
|
+
}
|
|
5362
|
+
const items = parseRoadmapCandidateQuality(md);
|
|
5363
|
+
const count = (pred) => items.filter(pred).length;
|
|
5364
|
+
const grounded = count((i) => i.grounded);
|
|
5365
|
+
const initiatives = {
|
|
5366
|
+
total: items.length,
|
|
5367
|
+
grounded,
|
|
5368
|
+
with_related_domain: count((i) => i.hasRelatedDomain),
|
|
5369
|
+
with_related_capability: count((i) => i.hasRelatedCapability),
|
|
5370
|
+
with_source_signals: count((i) => i.hasSourceSignals),
|
|
5371
|
+
// Only "needs refinement" when there are initiatives and at least one isn't grounded.
|
|
5372
|
+
needs_refinement: items.length > 0 && grounded < items.length,
|
|
5373
|
+
items
|
|
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 };
|
|
5384
|
+
}
|
|
5385
|
+
|
|
5211
5386
|
// ../cli/src/core/project-explain.ts
|
|
5212
5387
|
var ARCH_DIR2 = "knowledge";
|
|
5213
5388
|
function normalizeTitle(t) {
|
|
@@ -5432,7 +5607,8 @@ function buildProjectExplanation(dir) {
|
|
|
5432
5607
|
legacyLocation: exists(join(dir, "knowledge/tech/architecture-notes.md")) || exists(join(dir, "knowledge/tech/decision-candidates.md"))
|
|
5433
5608
|
}
|
|
5434
5609
|
},
|
|
5435
|
-
installedAssets: installedAssetsSummary(dir)
|
|
5610
|
+
installedAssets: installedAssetsSummary(dir),
|
|
5611
|
+
roadmapQuality: buildRoadmapQuality(dir)
|
|
5436
5612
|
};
|
|
5437
5613
|
}
|
|
5438
5614
|
function stateLabel(state) {
|
|
@@ -5487,10 +5663,11 @@ function renderExplanationHuman(exp) {
|
|
|
5487
5663
|
lines.push(`- Delivery: ${ls("Delivery")}`);
|
|
5488
5664
|
lines.push(`- Agents: ${exp.knowledge.hasAgents ? "available" : "missing"}`);
|
|
5489
5665
|
if (exp.roadmap.present) {
|
|
5490
|
-
lines.push(`- Roadmap
|
|
5491
|
-
lines.push(`-
|
|
5492
|
-
|
|
5493
|
-
|
|
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}`);
|
|
5494
5671
|
} else {
|
|
5495
5672
|
lines.push(`- Work items: ${exp.workItems.total}`);
|
|
5496
5673
|
}
|
|
@@ -5667,6 +5844,45 @@ function renderExplanationHuman(exp) {
|
|
|
5667
5844
|
lines.push("Tech discovery files are in the legacy `knowledge/tech/` root. Suggested cleanup: run `kaddo tech organize`.");
|
|
5668
5845
|
lines.push("");
|
|
5669
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
|
+
}
|
|
5855
|
+
const rq = exp.roadmapQuality;
|
|
5856
|
+
const rqi = rq.initiatives;
|
|
5857
|
+
const rqw = rq.work_item_candidates;
|
|
5858
|
+
if (rqi.total > 0 || rqw.total > 0) {
|
|
5859
|
+
lines.push("## Roadmap Quality");
|
|
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) {
|
|
5869
|
+
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.");
|
|
5883
|
+
}
|
|
5884
|
+
lines.push("");
|
|
5885
|
+
}
|
|
5670
5886
|
const ia = exp.installedAssets;
|
|
5671
5887
|
const agentsInstalled = ia.agents.total - ia.agents.missing;
|
|
5672
5888
|
const skillsInstalled = ia.skills.total - ia.skills.missing;
|
|
@@ -6892,6 +7108,32 @@ var RESOURCES = [
|
|
|
6892
7108
|
}
|
|
6893
7109
|
return [{ uri: "kaddo://installed-assets", text: JSON.stringify(installedAssetsSummary(root), null, 2), mimeType: "application/json" }];
|
|
6894
7110
|
}
|
|
7111
|
+
},
|
|
7112
|
+
{
|
|
7113
|
+
uri: "kaddo://roadmap-quality",
|
|
7114
|
+
name: "Kaddo roadmap quality",
|
|
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.",
|
|
7116
|
+
mimeType: "application/json",
|
|
7117
|
+
read: (root) => {
|
|
7118
|
+
if (!hasKnowledge(root)) {
|
|
7119
|
+
return text("kaddo://roadmap-quality", "Knowledge repository not found. Run `kaddo bootstrap` first.", "text/plain");
|
|
7120
|
+
}
|
|
7121
|
+
return [{ uri: "kaddo://roadmap-quality", text: JSON.stringify(buildRoadmapQuality(root), null, 2), mimeType: "application/json" }];
|
|
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
|
+
}
|
|
6895
7137
|
}
|
|
6896
7138
|
];
|
|
6897
7139
|
|
|
@@ -7220,6 +7462,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
7220
7462
|
nextStepRecommendation,
|
|
7221
7463
|
techDecisions,
|
|
7222
7464
|
techKnowledge,
|
|
7465
|
+
roadmapQuality: buildRoadmapQuality(dir),
|
|
7223
7466
|
installedAssets: (() => {
|
|
7224
7467
|
const s = installedAssetsSummary(dir);
|
|
7225
7468
|
const compact = (a) => ({ total: a.total, installed: a.total - a.missing, outdated: a.outdated, unknown_version: a.unknown_version, modified: a.modified });
|
|
@@ -7318,22 +7561,57 @@ function renderContextPack(pack) {
|
|
|
7318
7561
|
}
|
|
7319
7562
|
parts.push("## Current Knowledge\n");
|
|
7320
7563
|
parts.push((knowledge.summary || "No project knowledge summary found yet.") + "\n");
|
|
7321
|
-
parts.push("## Roadmap\n");
|
|
7564
|
+
parts.push("## Roadmap Status\n");
|
|
7322
7565
|
if (pack.roadmap.present) {
|
|
7323
7566
|
parts.push(
|
|
7324
7567
|
[
|
|
7325
|
-
`-
|
|
7326
|
-
`-
|
|
7327
|
-
`-
|
|
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}`
|
|
7328
7572
|
].join("\n") + "\n"
|
|
7329
7573
|
);
|
|
7330
|
-
if (pack.roadmap.
|
|
7574
|
+
if (pack.roadmap.remaining_work_item_candidates > 0) {
|
|
7331
7575
|
parts.push(
|
|
7332
|
-
"
|
|
7576
|
+
"Work Item candidates are not yet Work Items. Materialize them with `kaddo create --from roadmap`.\n"
|
|
7333
7577
|
);
|
|
7334
7578
|
}
|
|
7335
7579
|
}
|
|
7336
7580
|
parts.push((knowledge.roadmapSummary || "No roadmap baseline found.") + "\n");
|
|
7581
|
+
const rq = pack.roadmapQuality;
|
|
7582
|
+
const rqi = rq.initiatives;
|
|
7583
|
+
const rqw = rq.work_item_candidates;
|
|
7584
|
+
if (rqi.total > 0 || rqw.total > 0) {
|
|
7585
|
+
parts.push("## Roadmap Quality\n");
|
|
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) {
|
|
7610
|
+
parts.push(
|
|
7611
|
+
"Roadmap quality: needs refinement. Use the roadmap-agent to add domain / capability / source signals.\n"
|
|
7612
|
+
);
|
|
7613
|
+
}
|
|
7614
|
+
}
|
|
7337
7615
|
parts.push("## Active Work Items\n");
|
|
7338
7616
|
if (knowledge.workItems.length > 0) {
|
|
7339
7617
|
const lines = knowledge.workItems.map((wi) => {
|
package/package.json
CHANGED