@kaddo/cli 3.42.0 → 3.43.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/README.md +1 -0
- package/dist/index.js +173 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -541,6 +541,7 @@ create --from roadmap → owners → guard → explain`.
|
|
|
541
541
|
| v3.40.1 | ADR slug cleanup + MCP: suggested ADR filenames strip list/heading prefixes (no `ADR-001-1-…`) and normalize acronyms; new read-only MCP resource `kaddo://tech-decisions` sharing `buildTechDecisions` with `kaddo adr` |
|
|
542
542
|
| v3.41 | Tech knowledge structure: `knowledge/tech/discovery/` for architecture-notes/decision-candidates (core vs decisions vs discovery); `kaddo adr` reads discovery-first with legacy fallback; `kaddo tech organize` migrates safely; `explain` shows `## Tech Knowledge` |
|
|
543
543
|
| v3.42 | Agent & skill version metadata: installed agents/skills carry a `version:`; `kaddo agents status` / `kaddo skills status` classify up-to-date/outdated/unknown-version/modified/missing; `agents update` / `skills update` refresh outdated safely (never overwrite edits without `--force`); MCP `kaddo://installed-assets` |
|
|
544
|
+
| v3.43 | Capability-grounded roadmap: each `RM-xxx` candidate is graded on related domain / capability / source signals; `roadmap_quality` surfaced in `explain`/`context`/`understand`; `create --from roadmap` preserves `source_roadmap_candidate` + related metadata into the Work Item; roadmap-agent emits grounded fields (never materializes Work Items); MCP `kaddo://roadmap-quality` |
|
|
544
545
|
|
|
545
546
|
**Optional modules (installed with `kaddo add`):**
|
|
546
547
|
|
package/dist/index.js
CHANGED
|
@@ -2645,6 +2645,24 @@ Adapt priorities to the project state from the context pack:
|
|
|
2645
2645
|
- **legacy** \u2014 prioritize risk reduction, unknowns and safe modernization before feature
|
|
2646
2646
|
delivery.
|
|
2647
2647
|
|
|
2648
|
+
## Grounding rules (VS-077)
|
|
2649
|
+
|
|
2650
|
+
Every candidate initiative must be **grounded** in the knowledge base \u2014 never a loose idea. For each
|
|
2651
|
+
\`### RM-xxx\` you must provide:
|
|
2652
|
+
|
|
2653
|
+
- **Related domain** \u2014 a domain from \`## Capability Domains\` in \`capabilities.md\` (or, if genuinely
|
|
2654
|
+
new, prefix it \`[new candidate domain] <name>\` \u2014 do not invent domains silently).
|
|
2655
|
+
- **Related capabilities** \u2014 one or more existing/partial capabilities.
|
|
2656
|
+
- **Source signals** \u2014 at least one traceable reason: Capability Gap, Roadmap Candidate Signal, Risk,
|
|
2657
|
+
Open Question, Assumption, Deferred Decision, Tech Decision Candidate, ADR, Business Goal,
|
|
2658
|
+
Operational Need or Legacy Modernization Signal.
|
|
2659
|
+
- **Expected value**, **Risks**, **Dependencies**, and **Suggested Work Items** (candidates only).
|
|
2660
|
+
|
|
2661
|
+
Do **not** emit a candidate with no source signal. Keep initiatives at initiative granularity (small
|
|
2662
|
+
tasks go under **Suggested Work Items**, not as their own RM). Every roadmap ends with a global
|
|
2663
|
+
**## Not Now** section. For pre-ai/legacy, prioritize stabilization, security, data, operations,
|
|
2664
|
+
architectural decisions and business-blocking gaps before expansive features.
|
|
2665
|
+
|
|
2648
2666
|
## Constraints
|
|
2649
2667
|
|
|
2650
2668
|
- Do not invent business priorities or business facts \u2014 mark them as assumptions when inferred.
|
|
@@ -2653,6 +2671,8 @@ Adapt priorities to the project state from the context pack:
|
|
|
2653
2671
|
implementation-agent, and only after Work Items are materialized. Your handoff is
|
|
2654
2672
|
\`kaddo create --from roadmap\` \u2192 work-item-agent.
|
|
2655
2673
|
- Do not create the work items themselves; only propose candidates.
|
|
2674
|
+
- **Never create files under \`knowledge/delivery/work-items/\`** \u2014 materialization is
|
|
2675
|
+
\`kaddo create --from roadmap\`, not the roadmap-agent.
|
|
2656
2676
|
- Make clear that initiatives and work items are **candidates**, not final decisions.
|
|
2657
2677
|
- Mark any uncertain information as an assumption or open question.
|
|
2658
2678
|
- Keep sequencing justified by dependencies and risk.
|
|
@@ -2686,31 +2706,38 @@ human review \u2014 not final commitments.
|
|
|
2686
2706
|
|
|
2687
2707
|
### RM-001: <Initiative Name>
|
|
2688
2708
|
|
|
2689
|
-
**
|
|
2709
|
+
**Status:** candidate <!-- candidate | selected | deferred | rejected -->
|
|
2690
2710
|
|
|
2691
|
-
**
|
|
2711
|
+
**Priority:** high / medium / low
|
|
2712
|
+
|
|
2713
|
+
**Suggested Knowledge Level:** K1 / K2 / K3 / K4
|
|
2692
2714
|
|
|
2693
|
-
**
|
|
2715
|
+
**Related domain:** <one of the ## Capability Domains from capabilities.md>
|
|
2694
2716
|
|
|
2695
|
-
**
|
|
2717
|
+
**Related capabilities:**
|
|
2718
|
+
- <existing or partial capability>
|
|
2696
2719
|
|
|
2697
|
-
**
|
|
2720
|
+
**Source signals:** <!-- REQUIRED: why this candidate exists (at least one) -->
|
|
2721
|
+
- Capability Gap: <...>
|
|
2722
|
+
- Roadmap Candidate Signal: <...>
|
|
2723
|
+
- Risk / Open Question / Assumption / Deferred Decision / Tech Decision Candidate / ADR / Business Goal: <...>
|
|
2698
2724
|
|
|
2699
|
-
**
|
|
2725
|
+
**Problem / opportunity:**
|
|
2700
2726
|
|
|
2701
|
-
**
|
|
2727
|
+
**Expected value:**
|
|
2702
2728
|
|
|
2703
|
-
**
|
|
2729
|
+
**Risks:**
|
|
2704
2730
|
|
|
2705
|
-
**
|
|
2731
|
+
**Dependencies:**
|
|
2706
2732
|
|
|
2733
|
+
**Suggested Work Items:**
|
|
2707
2734
|
- WI-CANDIDATE-001: <candidate work item>
|
|
2708
2735
|
- type:
|
|
2709
2736
|
- suggested knowledge level:
|
|
2710
2737
|
- expected value:
|
|
2711
2738
|
- notes:
|
|
2712
2739
|
|
|
2713
|
-
**
|
|
2740
|
+
**Not now:**
|
|
2714
2741
|
|
|
2715
2742
|
---
|
|
2716
2743
|
|
|
@@ -3005,6 +3032,14 @@ that it should be materialized first (\`kaddo adr\` + the adr-writing skill) and
|
|
|
3005
3032
|
without surfacing it. -->
|
|
3006
3033
|
\`\`\`
|
|
3007
3034
|
|
|
3035
|
+
### Preserve roadmap metadata (VS-077)
|
|
3036
|
+
|
|
3037
|
+
When a Work Item comes from \`kaddo create --from roadmap\`, the front matter already carries
|
|
3038
|
+
\`source_roadmap_candidate\`, \`related_domain\`, \`related_capability\` (+ \`related_capabilities\`),
|
|
3039
|
+
\`knowledge_level\`, \`expected_value\`, \`risks\` and \`dependencies\`. **Keep and refine** this metadata \u2014
|
|
3040
|
+
do not drop the trace back to the capability domain and source signals. Add \`related_decisions\` /
|
|
3041
|
+
\`decision_candidates\` when the work depends on a technical decision.
|
|
3042
|
+
|
|
3008
3043
|
## Where to Save the Result
|
|
3009
3044
|
|
|
3010
3045
|
Save new output as a draft under \`knowledge/delivery/work-items/draft/\` unless a human
|
|
@@ -4979,6 +5014,16 @@ function buildRoadmapFrontMatter(id, type, level, title, candidate, answers) {
|
|
|
4979
5014
|
`source: roadmap`,
|
|
4980
5015
|
`source_id: ${candidate.id}`,
|
|
4981
5016
|
`source_initiative: ${candidate.initiative?.id ?? "unknown"}`,
|
|
5017
|
+
// Capability-grounded traceability (VS-077): carry the roadmap metadata into the Work Item.
|
|
5018
|
+
`source_roadmap_candidate: ${candidate.initiative?.id ?? candidate.id}`,
|
|
5019
|
+
...candidate.domain ? [`related_domain: "${candidate.domain.replace(/"/g, "'")}"`] : [],
|
|
5020
|
+
...candidate.relatedCapabilities && candidate.relatedCapabilities.length > 0 ? [
|
|
5021
|
+
`related_capability: "${candidate.relatedCapabilities[0].replace(/"/g, "'")}"`,
|
|
5022
|
+
`related_capabilities: [${candidate.relatedCapabilities.map((c) => `"${c.replace(/"/g, "'")}"`).join(", ")}]`
|
|
5023
|
+
] : [],
|
|
5024
|
+
...candidate.expectedValue ? [`expected_value: "${candidate.expectedValue.replace(/"/g, "'")}"`] : [],
|
|
5025
|
+
...candidate.risk ? [`risks: "${candidate.risk.replace(/"/g, "'")}"`] : [],
|
|
5026
|
+
...candidate.dependencies && candidate.dependencies.length > 0 ? [`dependencies: [${candidate.dependencies.map((d) => `"${d.replace(/"/g, "'")}"`).join(", ")}]`] : [],
|
|
4982
5027
|
`summary: "${summary.replace(/"/g, "'")}"`,
|
|
4983
5028
|
"---"
|
|
4984
5029
|
];
|
|
@@ -8325,6 +8370,79 @@ function installedAssetsSummary(dir) {
|
|
|
8325
8370
|
return { version: KADDO_VERSION, agents: assetStatus(dir, "agent"), skills: assetStatus(dir, "skill") };
|
|
8326
8371
|
}
|
|
8327
8372
|
|
|
8373
|
+
// src/core/roadmap-quality.ts
|
|
8374
|
+
var ROADMAP_PATH2 = "knowledge/delivery/roadmap.md";
|
|
8375
|
+
var INITIATIVE_RE2 = /^#{2,4}\s+(RM-[\w.-]+)\s*[:\-–]?\s*(.*)$/;
|
|
8376
|
+
function fieldPresent(lines, label) {
|
|
8377
|
+
for (let i = 0; i < lines.length; i++) {
|
|
8378
|
+
const m = lines[i].match(new RegExp(`^\\s*[-*]?\\s*(?:\\*\\*)?\\s*(${label.source})\\s*(?:\\*\\*)?\\s*:\\s*(.*)$`, "i"));
|
|
8379
|
+
if (!m) continue;
|
|
8380
|
+
const inline = m[2].trim();
|
|
8381
|
+
if (inline) return true;
|
|
8382
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
8383
|
+
if (/^\s{2,}[-*]\s+\S/.test(lines[j])) return true;
|
|
8384
|
+
if (/^\S/.test(lines[j]) || /^#{2,4}\s/.test(lines[j])) break;
|
|
8385
|
+
if (/^\s*[-*]\s+\S/.test(lines[j]) && !/^\s{2,}/.test(lines[j])) break;
|
|
8386
|
+
}
|
|
8387
|
+
}
|
|
8388
|
+
return false;
|
|
8389
|
+
}
|
|
8390
|
+
function parseRoadmapCandidateQuality(md) {
|
|
8391
|
+
const lines = md.split(/\r?\n/);
|
|
8392
|
+
const items = [];
|
|
8393
|
+
let cur = null;
|
|
8394
|
+
const flush = () => {
|
|
8395
|
+
if (!cur) return;
|
|
8396
|
+
const hasRelatedDomain = fieldPresent(cur.lines, /related domain/);
|
|
8397
|
+
const hasRelatedCapability = fieldPresent(cur.lines, /related capabilit(?:y|ies)/);
|
|
8398
|
+
const hasSourceSignals = fieldPresent(cur.lines, /source signals?/);
|
|
8399
|
+
items.push({
|
|
8400
|
+
id: cur.id,
|
|
8401
|
+
title: cur.title,
|
|
8402
|
+
hasRelatedDomain,
|
|
8403
|
+
hasRelatedCapability,
|
|
8404
|
+
hasSourceSignals,
|
|
8405
|
+
grounded: hasRelatedDomain && hasRelatedCapability && hasSourceSignals
|
|
8406
|
+
});
|
|
8407
|
+
cur = null;
|
|
8408
|
+
};
|
|
8409
|
+
for (const line of lines) {
|
|
8410
|
+
const m = line.match(INITIATIVE_RE2);
|
|
8411
|
+
if (m) {
|
|
8412
|
+
flush();
|
|
8413
|
+
cur = { id: m[1], title: m[2].trim(), lines: [] };
|
|
8414
|
+
continue;
|
|
8415
|
+
}
|
|
8416
|
+
if (cur) cur.lines.push(line);
|
|
8417
|
+
}
|
|
8418
|
+
flush();
|
|
8419
|
+
return items;
|
|
8420
|
+
}
|
|
8421
|
+
function buildRoadmapQuality(dir) {
|
|
8422
|
+
let md = "";
|
|
8423
|
+
const p2 = join(dir, ROADMAP_PATH2);
|
|
8424
|
+
if (exists(p2)) {
|
|
8425
|
+
try {
|
|
8426
|
+
md = readFile(p2);
|
|
8427
|
+
} catch {
|
|
8428
|
+
md = "";
|
|
8429
|
+
}
|
|
8430
|
+
}
|
|
8431
|
+
const items = parseRoadmapCandidateQuality(md);
|
|
8432
|
+
const count = (pred) => items.filter(pred).length;
|
|
8433
|
+
const grounded = count((i) => i.grounded);
|
|
8434
|
+
return {
|
|
8435
|
+
candidates: items.length,
|
|
8436
|
+
grounded,
|
|
8437
|
+
with_related_domain: count((i) => i.hasRelatedDomain),
|
|
8438
|
+
with_related_capability: count((i) => i.hasRelatedCapability),
|
|
8439
|
+
with_source_signals: count((i) => i.hasSourceSignals),
|
|
8440
|
+
// Only "needs refinement" when there are candidates and at least one isn't grounded.
|
|
8441
|
+
needs_refinement: items.length > 0 && grounded < items.length,
|
|
8442
|
+
items
|
|
8443
|
+
};
|
|
8444
|
+
}
|
|
8445
|
+
|
|
8328
8446
|
// src/core/project-explain.ts
|
|
8329
8447
|
var ARCH_DIR4 = "knowledge";
|
|
8330
8448
|
function normalizeTitle(t) {
|
|
@@ -8549,7 +8667,8 @@ function buildProjectExplanation(dir) {
|
|
|
8549
8667
|
legacyLocation: exists(join(dir, "knowledge/tech/architecture-notes.md")) || exists(join(dir, "knowledge/tech/decision-candidates.md"))
|
|
8550
8668
|
}
|
|
8551
8669
|
},
|
|
8552
|
-
installedAssets: installedAssetsSummary(dir)
|
|
8670
|
+
installedAssets: installedAssetsSummary(dir),
|
|
8671
|
+
roadmapQuality: buildRoadmapQuality(dir)
|
|
8553
8672
|
};
|
|
8554
8673
|
}
|
|
8555
8674
|
function stateLabel(state) {
|
|
@@ -8784,6 +8903,20 @@ function renderExplanationHuman(exp) {
|
|
|
8784
8903
|
lines.push("Tech discovery files are in the legacy `knowledge/tech/` root. Suggested cleanup: run `kaddo tech organize`.");
|
|
8785
8904
|
lines.push("");
|
|
8786
8905
|
}
|
|
8906
|
+
const rq = exp.roadmapQuality;
|
|
8907
|
+
if (rq.candidates > 0) {
|
|
8908
|
+
lines.push("## Roadmap Quality");
|
|
8909
|
+
lines.push(`- Candidates: ${rq.candidates}`);
|
|
8910
|
+
lines.push(`- Grounded: ${rq.grounded}/${rq.candidates}`);
|
|
8911
|
+
lines.push(`- With related domain: ${rq.with_related_domain}/${rq.candidates}`);
|
|
8912
|
+
lines.push(`- With related capability: ${rq.with_related_capability}/${rq.candidates}`);
|
|
8913
|
+
lines.push(`- With source signals: ${rq.with_source_signals}/${rq.candidates}`);
|
|
8914
|
+
if (rq.needs_refinement) {
|
|
8915
|
+
lines.push("");
|
|
8916
|
+
lines.push("Roadmap quality: needs refinement. Suggested: use roadmap-agent to add domain / capability / source signals.");
|
|
8917
|
+
}
|
|
8918
|
+
lines.push("");
|
|
8919
|
+
}
|
|
8787
8920
|
const ia = exp.installedAssets;
|
|
8788
8921
|
const agentsInstalled = ia.agents.total - ia.agents.missing;
|
|
8789
8922
|
const skillsInstalled = ia.skills.total - ia.skills.missing;
|
|
@@ -9202,6 +9335,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
9202
9335
|
nextStepRecommendation,
|
|
9203
9336
|
techDecisions,
|
|
9204
9337
|
techKnowledge,
|
|
9338
|
+
roadmapQuality: buildRoadmapQuality(dir),
|
|
9205
9339
|
installedAssets: (() => {
|
|
9206
9340
|
const s = installedAssetsSummary(dir);
|
|
9207
9341
|
const compact = (a) => ({ total: a.total, installed: a.total - a.missing, outdated: a.outdated, unknown_version: a.unknown_version, modified: a.modified });
|
|
@@ -9316,6 +9450,24 @@ function renderContextPack(pack) {
|
|
|
9316
9450
|
}
|
|
9317
9451
|
}
|
|
9318
9452
|
parts.push((knowledge.roadmapSummary || "No roadmap baseline found.") + "\n");
|
|
9453
|
+
const rq = pack.roadmapQuality;
|
|
9454
|
+
if (rq.candidates > 0) {
|
|
9455
|
+
parts.push("## Roadmap Quality\n");
|
|
9456
|
+
parts.push(
|
|
9457
|
+
[
|
|
9458
|
+
`- Candidates: ${rq.candidates}`,
|
|
9459
|
+
`- Grounded: ${rq.grounded}/${rq.candidates}`,
|
|
9460
|
+
`- With related domain: ${rq.with_related_domain}/${rq.candidates}`,
|
|
9461
|
+
`- With related capability: ${rq.with_related_capability}/${rq.candidates}`,
|
|
9462
|
+
`- With source signals: ${rq.with_source_signals}/${rq.candidates}`
|
|
9463
|
+
].join("\n") + "\n"
|
|
9464
|
+
);
|
|
9465
|
+
if (rq.needs_refinement) {
|
|
9466
|
+
parts.push(
|
|
9467
|
+
"Roadmap quality: needs refinement. Use the roadmap-agent to add domain / capability / source signals.\n"
|
|
9468
|
+
);
|
|
9469
|
+
}
|
|
9470
|
+
}
|
|
9319
9471
|
parts.push("## Active Work Items\n");
|
|
9320
9472
|
if (knowledge.workItems.length > 0) {
|
|
9321
9473
|
const lines = knowledge.workItems.map((wi) => {
|
|
@@ -9748,6 +9900,16 @@ function runUnderstand() {
|
|
|
9748
9900
|
console.log(" \u2192 Use the adr-writing skill to create ADR drafts from `knowledge/tech/decision-candidates.md`");
|
|
9749
9901
|
console.log(" into `knowledge/tech/decisions/` before implementing affected technical Work Items (`kaddo adr`).");
|
|
9750
9902
|
}
|
|
9903
|
+
const rq = exp.roadmapQuality;
|
|
9904
|
+
if (rq.needs_refinement) {
|
|
9905
|
+
console.log("");
|
|
9906
|
+
console.log(`Roadmap quality: ${rq.grounded}/${rq.candidates} candidates grounded.`);
|
|
9907
|
+
console.log(" \u2192 Use roadmap-agent to ground roadmap candidates in capability domains, gaps and source signals");
|
|
9908
|
+
console.log(" before `kaddo create --from roadmap`.");
|
|
9909
|
+
} else if (rq.candidates > 0 && rq.grounded === rq.candidates) {
|
|
9910
|
+
console.log("");
|
|
9911
|
+
console.log("Roadmap candidates are grounded. \u2192 Run `kaddo create --from roadmap` to materialize the first Work Item.");
|
|
9912
|
+
}
|
|
9751
9913
|
const ia = exp.installedAssets;
|
|
9752
9914
|
const outdatedRecommended = ia.agents.items.filter(
|
|
9753
9915
|
(a) => (a.state === "outdated" || a.state === "unknown-version") && assessment.recommendedAgents.includes(a.name)
|