@kaddo/cli 3.20.0 → 3.22.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.
Files changed (3) hide show
  1. package/README.md +4 -0
  2. package/dist/index.js +598 -85
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -505,6 +505,10 @@ create --from roadmap → owners → guard → explain`.
505
505
  | v3.16 | Knowledge Capsules: `kaddo capsule export/add`, External Knowledge in context/explain, new `capsule-agent` |
506
506
  | v3.17 | Knowledge Graph Export: `kaddo graph export` (`.kaddo/graph.json` + `.mmd`, `--scope`/`--format`); graph summary in context/explain |
507
507
  | v3.18 | Graph relationship quality & metadata hints: `graph-hints.md`/`.json`, quality levels, `graph-agent`; hints in context/explain/understand |
508
+ | v3.19 | Read-only MCP server `@kaddo/mcp` (resources, tools, prompts over stdio) |
509
+ | v3.20 | MCP derived tools: safe regeneration of context/explain/understand/graph/capsule-draft under `.kaddo/` |
510
+ | v3.21 | Reusable Skills layer (`kaddo add skills`); skills in context/explain/understand, agent prompts and MCP |
511
+ | v3.22 | Guard & graph scope semantics: graph scope metadata, contextual-empty messaging, Guard ownership scope (active + completed; `--include-archived`) |
508
512
 
509
513
  **Optional modules (installed with `kaddo add`):**
510
514
 
package/dist/index.js CHANGED
@@ -1487,6 +1487,386 @@ var guardAdvancedModule = {
1487
1487
  ]
1488
1488
  };
1489
1489
 
1490
+ // src/skills/skills.ts
1491
+ function skill(id, title, group, appliesTo, body) {
1492
+ const frontMatter2 = [
1493
+ "---",
1494
+ "type: skill",
1495
+ `id: ${id}`,
1496
+ `title: ${title}`,
1497
+ "version: 1",
1498
+ `group: ${group}`,
1499
+ "applies_to:",
1500
+ ...appliesTo.map((a) => ` - ${a}`),
1501
+ "---",
1502
+ ""
1503
+ ].join("\n");
1504
+ return { id, title, group, appliesTo, content: frontMatter2 + body.trimStart() };
1505
+ }
1506
+ var ADR_WRITING = skill(
1507
+ "adr-writing",
1508
+ "ADR Writing Skill",
1509
+ "tech",
1510
+ ["decision-agent", "architecture-agent", "implementation-agent"],
1511
+ `
1512
+ # ADR Writing Skill
1513
+
1514
+ ## Purpose
1515
+
1516
+ Standardize how Architecture Decision Records are written so every decision is captured the same
1517
+ way and stays auditable.
1518
+
1519
+ ## When to use
1520
+
1521
+ When a real, consequential technical decision is being made or recognized \u2014 and only then.
1522
+
1523
+ ## Inputs
1524
+
1525
+ The context pack, the relevant Work Item or architecture note, and the decision being made.
1526
+
1527
+ ## Output
1528
+
1529
+ A single ADR containing: context, the decision, alternatives considered, consequences, the code
1530
+ paths it governs (\`code:\` globs when known) and the decision status (proposed / accepted /
1531
+ superseded).
1532
+
1533
+ ## Rules
1534
+
1535
+ - One ADR = one decision. Never mix unrelated decisions.
1536
+ - Never invent decisions; never write an ADR without a clear reason.
1537
+ - Record alternatives honestly, including the one chosen and why.
1538
+ - Prefer narrow governed \`code:\` globs over broad ones.
1539
+
1540
+ ## Quality checklist
1541
+
1542
+ - Context explains why the decision was needed.
1543
+ - The decision and its alternatives are explicit.
1544
+ - Consequences (positive and negative) are stated.
1545
+ - Status and governed paths are present.
1546
+
1547
+ ## Example output
1548
+
1549
+ \`\`\`md
1550
+ # ADR-0007 \u2014 Use SQLite for local persistence
1551
+ Status: accepted
1552
+ ## Context
1553
+ ...
1554
+ ## Decision
1555
+ ...
1556
+ ## Alternatives considered
1557
+ ...
1558
+ ## Consequences
1559
+ ...
1560
+ \`\`\`
1561
+ `
1562
+ );
1563
+ var WORK_ITEM_REFINEMENT = skill(
1564
+ "work-item-refinement",
1565
+ "Work Item Refinement Skill",
1566
+ "delivery",
1567
+ ["work-item-agent", "backlog-agent", "roadmap-agent"],
1568
+ `
1569
+ # Work Item Refinement Skill
1570
+
1571
+ ## Purpose
1572
+
1573
+ Standardize how a Work Item is sharpened from a rough idea into a ready, implementable item.
1574
+
1575
+ ## When to use
1576
+
1577
+ When improving a draft Work Item, or turning a backlog idea / roadmap candidate into a ready item.
1578
+
1579
+ ## Inputs
1580
+
1581
+ The context pack and the Work Item (draft or candidate).
1582
+
1583
+ ## Output
1584
+
1585
+ An improved Work Item with: problem, expected result, scope, out of scope, acceptance criteria,
1586
+ validation (how to test it), definition of done, open questions and dependencies.
1587
+
1588
+ ## Rules
1589
+
1590
+ - Do not implement code.
1591
+ - Do not expand scope without explicit confirmation.
1592
+ - Do not create mega Work Items \u2014 split when it covers multiple outcomes.
1593
+ - Keep acceptance criteria testable.
1594
+
1595
+ ## Quality checklist
1596
+
1597
+ - Problem and expected result are unambiguous.
1598
+ - Scope and out-of-scope are explicit.
1599
+ - Acceptance criteria and validation are present and testable.
1600
+ - Open questions and dependencies are surfaced, not hidden.
1601
+
1602
+ ## Example output
1603
+
1604
+ A Work Item markdown with the sections above filled in, ready for the implementation-agent.
1605
+ `
1606
+ );
1607
+ var OWNERSHIP_SUGGESTION = skill(
1608
+ "ownership-suggestion",
1609
+ "Ownership Suggestion Skill",
1610
+ "tech",
1611
+ ["ownership-agent", "work-item-agent", "graph-agent", "implementation-agent"],
1612
+ `
1613
+ # Ownership Suggestion Skill
1614
+
1615
+ ## Purpose
1616
+
1617
+ Standardize how precise \`code:\` ownership globs are proposed so Guard can relate code changes to
1618
+ the right knowledge.
1619
+
1620
+ ## When to use
1621
+
1622
+ When a Work Item or artifact is missing ownership, or its ownership is too broad/inaccurate.
1623
+
1624
+ ## Inputs
1625
+
1626
+ The context pack, the Work Item, and the technical inventory / codebase notes.
1627
+
1628
+ ## Output
1629
+
1630
+ A \`code:\` glob proposal, e.g.
1631
+
1632
+ \`\`\`yaml
1633
+ code:
1634
+ - src/database/**
1635
+ - src/cli/**
1636
+ \`\`\`
1637
+
1638
+ ## Rules
1639
+
1640
+ - Prefer small, specific globs; avoid \`src/**\`.
1641
+ - Use only real paths; validate intent against the Work Item.
1642
+ - Explain uncertainty instead of guessing.
1643
+ - Propose only \u2014 the human applies with \`kaddo owners suggest\`.
1644
+
1645
+ ## Quality checklist
1646
+
1647
+ - Every glob maps to a real path relevant to the item.
1648
+ - No catch-all globs.
1649
+ - Uncertainty is marked.
1650
+
1651
+ ## Example output
1652
+
1653
+ The YAML \`code:\` block above plus a one-line rationale per glob.
1654
+ `
1655
+ );
1656
+ var GRAPH_METADATA_REVIEW = skill(
1657
+ "graph-metadata-review",
1658
+ "Graph Metadata Review Skill",
1659
+ "tech",
1660
+ ["graph-agent", "ownership-agent", "work-item-agent"],
1661
+ `
1662
+ # Graph Metadata Review Skill
1663
+
1664
+ ## Purpose
1665
+
1666
+ Standardize how \`kaddo graph export\` hints become precise relationship front matter.
1667
+
1668
+ ## When to use
1669
+
1670
+ When relationship quality is partial/sparse/empty, or when reviewing \`.kaddo/graph-hints.md\`.
1671
+
1672
+ ## Inputs
1673
+
1674
+ The context pack, \`.kaddo/graph.json\` and \`.kaddo/graph-hints.md\`, plus the affected artifacts.
1675
+
1676
+ ## Output
1677
+
1678
+ Front matter proposals, e.g.
1679
+
1680
+ \`\`\`yaml
1681
+ capabilities:
1682
+ - local-persistence
1683
+ decisions:
1684
+ - ADR-0001
1685
+ code:
1686
+ - src/database/**
1687
+ capsules:
1688
+ - orders-service
1689
+ \`\`\`
1690
+
1691
+ ## Rules
1692
+
1693
+ - Never invent relationships, paths or IDs.
1694
+ - Do not try to resolve every hint at once \u2014 propose what is justified.
1695
+ - Do not modify artifacts; the human applies and re-runs \`kaddo graph export\`.
1696
+
1697
+ ## Quality checklist
1698
+
1699
+ - Each proposal maps to a real artifact/path/capability/ADR/capsule.
1700
+ - Globs are narrow; uncertainty is marked.
1701
+
1702
+ ## Example output
1703
+
1704
+ The YAML proposal above, grouped per artifact, with a short reason each.
1705
+ `
1706
+ );
1707
+ var CAPSULE_WRITING = skill(
1708
+ "capsule-writing",
1709
+ "Capsule Writing Skill",
1710
+ "integration",
1711
+ ["capsule-agent", "architecture-agent", "product-agent"],
1712
+ `
1713
+ # Capsule Writing Skill
1714
+
1715
+ ## Purpose
1716
+
1717
+ Standardize how a Knowledge Capsule is written/reviewed so external consumers get safe, useful
1718
+ context.
1719
+
1720
+ ## When to use
1721
+
1722
+ When creating or refining a Knowledge Capsule for sharing with another project.
1723
+
1724
+ ## Inputs
1725
+
1726
+ The context pack, capabilities, current-state, decisions and any public contracts.
1727
+
1728
+ ## Output
1729
+
1730
+ A capsule with: purpose, responsibilities, capabilities, contracts, dependencies, risks, owners,
1731
+ out of scope and usage notes.
1732
+
1733
+ ## Rules
1734
+
1735
+ - Never include secrets, tokens, credentials, source code, PII or unnecessary internal detail.
1736
+ - Never invent contracts; mark unknowns.
1737
+ - Summarize boundaries; prefer "unknown" over guessing.
1738
+
1739
+ ## Quality checklist
1740
+
1741
+ - Purpose and boundaries are clear.
1742
+ - Contracts are real, not invented.
1743
+ - No secrets/source/PII included.
1744
+
1745
+ ## Example output
1746
+
1747
+ A \`*.capsule.md\` with the sections above.
1748
+ `
1749
+ );
1750
+ var LEARNING_CAPTURE = skill(
1751
+ "learning-capture",
1752
+ "Learning Capture Skill",
1753
+ "delivery",
1754
+ ["implementation-agent", "guard-agent", "architecture-agent", "work-item-agent"],
1755
+ `
1756
+ # Learning Capture Skill
1757
+
1758
+ ## Purpose
1759
+
1760
+ Standardize how a Work Item's learning is captured when it closes.
1761
+
1762
+ ## When to use
1763
+
1764
+ When finishing a Work Item, after implementation and verification.
1765
+
1766
+ ## Inputs
1767
+
1768
+ The Work Item, the diff/result, and any decisions or surprises that came up.
1769
+
1770
+ ## Output
1771
+
1772
+ A learning record: what was implemented, what changed, what was learned, what decision emerged,
1773
+ which knowledge must be updated, and what remains pending.
1774
+
1775
+ ## Rules
1776
+
1777
+ - Do not close a Work Item without validation.
1778
+ - Do not hide failures; record them honestly.
1779
+ - Do not assume everything is done if errors remain.
1780
+
1781
+ ## Quality checklist
1782
+
1783
+ - Implemented vs changed vs learned are distinct.
1784
+ - Knowledge to update is named (ADR / capabilities / current-state).
1785
+ - Pending items are listed.
1786
+
1787
+ ## Example output
1788
+
1789
+ A short learning section appended to the Work Item or a learning note.
1790
+ `
1791
+ );
1792
+ var IMPLEMENTATION_PLANNING = skill(
1793
+ "implementation-planning",
1794
+ "Implementation Planning Skill",
1795
+ "delivery",
1796
+ ["implementation-agent", "work-item-agent"],
1797
+ `
1798
+ # Implementation Planning Skill
1799
+
1800
+ ## Purpose
1801
+
1802
+ Standardize the plan produced before implementation starts.
1803
+
1804
+ ## When to use
1805
+
1806
+ Before writing code for a ready Work Item.
1807
+
1808
+ ## Inputs
1809
+
1810
+ The context pack and the ready Work Item.
1811
+
1812
+ ## Output
1813
+
1814
+ A plan with: technical scope, expected files, risks, validations, out of scope, implementation
1815
+ steps, and stop criteria (when to pause and ask).
1816
+
1817
+ ## Rules
1818
+
1819
+ - Do not start coding without confirmation.
1820
+ - Do not expand scope.
1821
+ - Never make commits or push \u2014 suggest only.
1822
+
1823
+ ## Quality checklist
1824
+
1825
+ - Scope and expected files are explicit.
1826
+ - Risks and validations are listed.
1827
+ - Stop criteria are defined.
1828
+
1829
+ ## Example output
1830
+
1831
+ A numbered plan covering the sections above, ending with a request to confirm before coding.
1832
+ `
1833
+ );
1834
+ var SKILLS = [
1835
+ ADR_WRITING,
1836
+ WORK_ITEM_REFINEMENT,
1837
+ OWNERSHIP_SUGGESTION,
1838
+ GRAPH_METADATA_REVIEW,
1839
+ CAPSULE_WRITING,
1840
+ LEARNING_CAPTURE,
1841
+ IMPLEMENTATION_PLANNING
1842
+ ];
1843
+ var SKILL_GROUPS = {
1844
+ delivery: ["work-item-refinement", "implementation-planning", "learning-capture"],
1845
+ tech: ["adr-writing", "ownership-suggestion", "graph-metadata-review"],
1846
+ integration: ["capsule-writing"]
1847
+ };
1848
+ var SKILL_GROUP_NAMES = Object.keys(SKILL_GROUPS);
1849
+ var RECOMMENDED_SKILLS = [...SKILL_GROUPS.delivery, ...SKILL_GROUPS.tech];
1850
+ function skillInstallPath(id) {
1851
+ return `knowledge/skills/${id}/skill.md`;
1852
+ }
1853
+ function selectSkills(opts) {
1854
+ if (opts.all) {
1855
+ return { ids: SKILLS.map((s) => s.id), label: "all skills" };
1856
+ }
1857
+ if (opts.group) {
1858
+ const group = opts.group;
1859
+ const ids = SKILL_GROUPS[group];
1860
+ if (!ids) {
1861
+ throw new Error(
1862
+ `Unknown skill group "${opts.group}". Valid groups: ${SKILL_GROUP_NAMES.join(", ")}.`
1863
+ );
1864
+ }
1865
+ return { ids, label: `group: ${group}` };
1866
+ }
1867
+ return { ids: RECOMMENDED_SKILLS, label: "recommended skills" };
1868
+ }
1869
+
1490
1870
  // src/agents/responsibility.ts
1491
1871
  var RESPONSIBILITY_MATRIX = {
1492
1872
  "business-agent": {
@@ -1758,14 +2138,30 @@ function renderLanguageRule() {
1758
2138
  ""
1759
2139
  ].join("\n");
1760
2140
  }
2141
+ function renderSkillsSection(agent) {
2142
+ const applicable = SKILLS.filter((s) => s.appliesTo.includes(agent));
2143
+ if (applicable.length === 0) return "";
2144
+ return [
2145
+ "## Reusable Skills",
2146
+ "",
2147
+ "Apply these reusable skills when relevant (install with `kaddo add skills`; read them in",
2148
+ "`knowledge/skills/` or via the Kaddo MCP server):",
2149
+ "",
2150
+ ...applicable.map((s) => `- **${s.id}** \u2014 ${s.title}.`),
2151
+ ""
2152
+ ].join("\n");
2153
+ }
1761
2154
  function withResponsibilityTrace(fileName, content) {
1762
2155
  const agent = fileName.replace(/\.md$/, "");
1763
2156
  if (!RESPONSIBILITY_MATRIX[agent]) return content;
2157
+ const skills = renderSkillsSection(agent);
2158
+ const skillsBlock = skills ? `${skills}
2159
+ ` : "";
1764
2160
  return `${content.trimEnd()}
1765
2161
 
1766
2162
  ${renderLanguageRule()}
1767
2163
  ${renderAgentBoundaries(agent)}
1768
- ${renderAgentTrace(agent)}`;
2164
+ ${skillsBlock}${renderAgentTrace(agent)}`;
1769
2165
  }
1770
2166
 
1771
2167
  // src/agents/prompts.ts
@@ -3532,74 +3928,40 @@ var agentsModule = {
3532
3928
  };
3533
3929
 
3534
3930
  // src/modules/skills.ts
3931
+ var skillsReadme = {
3932
+ path: "knowledge/skills/README.md",
3933
+ content: [
3934
+ "# Skills",
3935
+ "",
3936
+ "Reusable **skill** definitions \u2014 capabilities shared across agents. A skill does not decide",
3937
+ "WHAT to do (that is the agent); it defines HOW to do one thing well. Agents orchestrate;",
3938
+ "skills standardize; knowledge grounds; MCP exposes.",
3939
+ "",
3940
+ "Skills never execute anything \u2014 they are reusable instructions, not tools. They never run",
3941
+ "git, never call an LLM and never modify files.",
3942
+ "",
3943
+ "## Installed skills",
3944
+ "",
3945
+ ...SKILLS.map((s) => `- \`${s.id}\` (${s.group}) \u2014 ${s.title}. Applies to: ${s.appliesTo.join(", ")}.`),
3946
+ "",
3947
+ "## Groups",
3948
+ "",
3949
+ ...Object.entries(SKILL_GROUPS).map(([g, ids]) => `- **${g}**: ${ids.join(", ")}`),
3950
+ "",
3951
+ "Install: `kaddo add skills` (recommended), `--all`, or `--group <delivery|tech|integration>`."
3952
+ ].join("\n")
3953
+ };
3954
+ var skillFiles = SKILLS.map((s) => ({
3955
+ path: skillInstallPath(s.id),
3956
+ content: s.content
3957
+ }));
3535
3958
  var skillsModule = {
3536
3959
  name: "skills",
3537
- description: "Reusable skills \u2014 capabilities shared across agents, teams, or projects",
3960
+ description: "Reusable skills \u2014 capabilities shared across agents (adr-writing, work-item-refinement, \u2026)",
3538
3961
  configKey: "module_skills",
3539
3962
  dirs: ["knowledge/skills"],
3540
- files: [
3541
- {
3542
- path: "knowledge/skills/.gitkeep",
3543
- content: ""
3544
- },
3545
- {
3546
- path: "knowledge/skills/README.md",
3547
- content: [
3548
- "# Skills",
3549
- "",
3550
- "This directory contains skill definitions \u2014 reusable capabilities that agents",
3551
- "or team members can invoke.",
3552
- "",
3553
- "A skill is a well-defined, repeatable capability with:",
3554
- "- Clear inputs and outputs",
3555
- "- A defined trigger (when to use it)",
3556
- "- Known preconditions",
3557
- "",
3558
- "Skills differ from agents: a skill is a single capability,",
3559
- "an agent is an orchestrator that uses skills."
3560
- ].join("\n")
3561
- }
3562
- ],
3563
- workItemTypes: [
3564
- {
3565
- name: "skill",
3566
- knowledgeLevel: "K3",
3567
- description: "Skill \u2014 a reusable capability shared across agents, teams, or projects.",
3568
- questions: [
3569
- {
3570
- id: "what_it_does",
3571
- prompt: "What does this skill do?",
3572
- placeholder: "e.g. Reads the artifact front matters and returns ownership gaps",
3573
- frontMatterField: "what_it_does",
3574
- required: true
3575
- },
3576
- {
3577
- id: "trigger",
3578
- prompt: "When should this skill be invoked?",
3579
- placeholder: "e.g. When a guard FYI has no matching artifact with code globs",
3580
- frontMatterField: "trigger",
3581
- required: true
3582
- },
3583
- {
3584
- id: "inputs_outputs",
3585
- prompt: "What are the inputs and outputs?",
3586
- placeholder: "e.g. Input: list of touched files. Output: suggested artifact IDs to update",
3587
- frontMatterField: "inputs_outputs",
3588
- required: true
3589
- }
3590
- ],
3591
- qualityGate: [
3592
- "Skill is scoped to a single, reusable capability.",
3593
- "Trigger condition is explicit.",
3594
- "Inputs and outputs are defined."
3595
- ],
3596
- extraFrontMatter: {
3597
- skill_type: "analysis",
3598
- reusable_by: [],
3599
- code: []
3600
- }
3601
- }
3602
- ]
3963
+ files: [skillsReadme, ...skillFiles],
3964
+ workItemTypes: []
3603
3965
  };
3604
3966
 
3605
3967
  // src/modules/global-docs.ts
@@ -5162,10 +5524,14 @@ async function offerIgnore(dir, match) {
5162
5524
  log2.success(`${id} added to .kaddo/ignores.yml`);
5163
5525
  return true;
5164
5526
  }
5165
- function printCIJson(dir, touchedFiles, activeMatches, ignoredCount, pluginSignals, affectedOwners, workspace) {
5527
+ function printCIJson(dir, touchedFiles, activeMatches, ignoredCount, pluginSignals, affectedOwners, workspace, includeArchived) {
5166
5528
  const output = {
5167
5529
  kaddo_guard: true,
5168
5530
  ci: true,
5531
+ ownership_scope: {
5532
+ included: includeArchived ? ["draft", "ready", "in-progress", "blocked", "completed", "archived"] : ["draft", "ready", "in-progress", "blocked", "completed"],
5533
+ excluded: includeArchived ? [] : ["archived"]
5534
+ },
5169
5535
  touched_files: touchedFiles.length,
5170
5536
  fyi_count: activeMatches.length,
5171
5537
  ignored_count: ignoredCount,
@@ -5194,6 +5560,12 @@ function printCIJson(dir, touchedFiles, activeMatches, ignoredCount, pluginSigna
5194
5560
  }
5195
5561
  console.log(JSON.stringify(output, null, 2));
5196
5562
  }
5563
+ function printOwnershipScope(includeArchived) {
5564
+ console.log("Ownership scope:");
5565
+ console.log("- Active and completed Work Items");
5566
+ console.log(includeArchived ? "- Archived Work Items included (--include-archived)" : "- Archived Work Items excluded");
5567
+ console.log("");
5568
+ }
5197
5569
  async function runGuard(opts = {}) {
5198
5570
  const dir = cwd();
5199
5571
  const interactive = opts.interactive !== false && !opts.ci && !opts.json;
@@ -5235,7 +5607,10 @@ async function runGuard(opts = {}) {
5235
5607
  console.log("kaddo guard: no knowledge/ directory found. Run `kaddo init` first.");
5236
5608
  return;
5237
5609
  }
5238
- const artifacts = discoverKnowledge(dir);
5610
+ const includeArchived = opts.includeArchived === true;
5611
+ const artifacts = discoverKnowledge(dir).filter(
5612
+ (a) => !(a.isWorkItem && a.lifecycle === "archived" && !includeArchived)
5613
+ );
5239
5614
  const result = analyzeGuard(touchedFiles, artifacts, silentWithoutOwnership);
5240
5615
  const pluginSignals = runPlugins(plugins, currentFiles, (filePath) => {
5241
5616
  const abs = join(dir, filePath);
@@ -5256,7 +5631,7 @@ async function runGuard(opts = {}) {
5256
5631
  const ownerMapCI = loadOwners(dir);
5257
5632
  const matchedDomainsCI = collectMatchedDomains(activeMatches.map((m) => m.artifact.domains));
5258
5633
  const affectedOwnersCI = resolveAffectedOwners(matchedDomainsCI, ownerMapCI);
5259
- printCIJson(dir, touchedFiles, activeMatches, alreadyIgnoredMatches.length, pluginSignals, affectedOwnersCI, workspaceScan);
5634
+ printCIJson(dir, touchedFiles, activeMatches, alreadyIgnoredMatches.length, pluginSignals, affectedOwnersCI, workspaceScan, includeArchived);
5260
5635
  return;
5261
5636
  }
5262
5637
  if (result.silenced && pluginSignals.length === 0) {
@@ -5266,12 +5641,18 @@ async function runGuard(opts = {}) {
5266
5641
  if (result.matches.length === 0 && pluginSignals.length === 0) {
5267
5642
  if (workspaceScan) printWorkspaceHeader(workspaceScan);
5268
5643
  printHeader(touchedFiles);
5644
+ printOwnershipScope(includeArchived);
5269
5645
  console.log(" No artifact ownership matches found.");
5646
+ console.log("");
5647
+ console.log("Note:");
5648
+ console.log("Guard checks ownership from active and completed Work Items.");
5649
+ console.log("Run `kaddo explain` to inspect ownership coverage.");
5270
5650
  printUntracked();
5271
5651
  return;
5272
5652
  }
5273
5653
  if (workspaceScan) printWorkspaceHeader(workspaceScan);
5274
5654
  printHeader(touchedFiles);
5655
+ printOwnershipScope(includeArchived);
5275
5656
  printUntracked();
5276
5657
  for (const match of activeMatches) {
5277
5658
  printFYI(match, dir);
@@ -5346,7 +5727,7 @@ function runIgnoreRemove(artifactId) {
5346
5727
  }
5347
5728
 
5348
5729
  // src/commands/explain.ts
5349
- import matter3 from "gray-matter";
5730
+ import matter4 from "gray-matter";
5350
5731
  import { parse as parseYaml9 } from "yaml";
5351
5732
 
5352
5733
  // src/core/delivery-phase.ts
@@ -5678,6 +6059,11 @@ function loadExternalCapsules(dir) {
5678
6059
 
5679
6060
  // src/core/graph.ts
5680
6061
  var KNOWLEDGE2 = "knowledge";
6062
+ var ACTIVE_STATUSES = ["draft", "ready", "in-progress", "blocked"];
6063
+ var ALL_STATUSES = ["draft", "ready", "in-progress", "blocked", "completed"];
6064
+ function scopeStatuses(scope) {
6065
+ return scope === "all" ? { included: ALL_STATUSES, excluded: ["archived"] } : { included: ACTIVE_STATUSES, excluded: ["completed", "archived"] };
6066
+ }
5681
6067
  function toPosix2(p2) {
5682
6068
  return p2.replace(/\\/g, "/");
5683
6069
  }
@@ -5720,7 +6106,10 @@ function buildGraph(dir, config, opts = {}, now = /* @__PURE__ */ new Date()) {
5720
6106
  }
5721
6107
  const all = discoverKnowledge(dir);
5722
6108
  const workItems = all.filter((a) => a.isWorkItem);
5723
- const selectedWIs = scope === "active" ? workItems.filter((a) => a.lifecycle && isActiveState(a.lifecycle)) : workItems;
6109
+ const { included, excluded } = scopeStatuses(scope);
6110
+ const includedSet = new Set(included);
6111
+ const activeWICount = workItems.filter((a) => a.lifecycle && isActiveState(a.lifecycle)).length;
6112
+ const selectedWIs = workItems.filter((a) => a.lifecycle && includedSet.has(a.lifecycle));
5724
6113
  for (const wi of selectedWIs) {
5725
6114
  const id = wi.id || wi.title;
5726
6115
  const wiNodeId = `wi:${id}`;
@@ -5790,6 +6179,7 @@ function buildGraph(dir, config, opts = {}, now = /* @__PURE__ */ new Date()) {
5790
6179
  }
5791
6180
  }
5792
6181
  }
6182
+ const scopeReason = scope === "all" ? "All supported Work Item statuses are included." : activeWICount === 0 ? "No active Work Items found. Completed Work Items are excluded from active scope." : "Active Work Items only; completed and archived are excluded.";
5793
6183
  return {
5794
6184
  generated_at: now.toISOString(),
5795
6185
  project: {
@@ -5797,6 +6187,10 @@ function buildGraph(dir, config, opts = {}, now = /* @__PURE__ */ new Date()) {
5797
6187
  state: config.project.state,
5798
6188
  structure: config.project.structure
5799
6189
  },
6190
+ scope,
6191
+ scope_reason: scopeReason,
6192
+ included_statuses: included,
6193
+ excluded_statuses: excluded,
5800
6194
  nodes: [...nodes.values()],
5801
6195
  edges
5802
6196
  };
@@ -5844,8 +6238,13 @@ function loadGraphSummary(dir) {
5844
6238
  const connected = new Set(
5845
6239
  edges.filter((e) => e.type === "owns" && activeWiIds.has(e.from)).map((e) => e.from)
5846
6240
  );
6241
+ const scope = graph.scope === "all" ? "all" : "active";
5847
6242
  return {
5848
6243
  generatedAt: String(graph.generated_at ?? ""),
6244
+ scope,
6245
+ scopeReason: String(graph.scope_reason ?? ""),
6246
+ includedStatuses: Array.isArray(graph.included_statuses) ? graph.included_statuses : [],
6247
+ excludedStatuses: Array.isArray(graph.excluded_statuses) ? graph.excluded_statuses : [],
5849
6248
  nodes: nodes.length,
5850
6249
  edges: edges.length,
5851
6250
  activeWorkItemsConnectedToCode: connected.size
@@ -5997,6 +6396,8 @@ function buildGraphHints(dir, graph, now = /* @__PURE__ */ new Date()) {
5997
6396
  const quality = assessQuality(nodes, relationshipEdges, hints.length);
5998
6397
  return {
5999
6398
  generated_at: now.toISOString(),
6399
+ scope: graph.scope,
6400
+ scope_reason: graph.scope_reason,
6000
6401
  quality,
6001
6402
  summary: { nodes, edges: graph.edges.length, hints: hints.length },
6002
6403
  metrics,
@@ -6032,13 +6433,23 @@ function renderGraphHintsMarkdown(report) {
6032
6433
  lines.push("");
6033
6434
  lines.push("## Summary");
6034
6435
  lines.push("");
6436
+ lines.push(`- Scope: ${report.scope} \u2014 ${report.scope_reason}`);
6035
6437
  lines.push(`- Relationship quality: ${report.quality} \u2014 ${QUALITY_NOTE[report.quality]}`);
6036
6438
  lines.push(`- Nodes: ${report.summary.nodes}`);
6037
6439
  lines.push(`- Edges: ${report.summary.edges}`);
6038
6440
  lines.push(`- Hints: ${report.summary.hints}`);
6039
6441
  lines.push("");
6040
6442
  if (report.hints.length === 0) {
6041
- lines.push("No hints \u2014 the declared relationships look healthy. \u{1F389}");
6443
+ if (report.quality === "empty") {
6444
+ lines.push("No active relationship hints were generated.");
6445
+ lines.push("");
6446
+ lines.push(`The graph is ${report.quality} for the **${report.scope}** scope \u2014 ${report.scope_reason}`);
6447
+ if (report.scope !== "all") {
6448
+ lines.push("Run `kaddo graph export --scope all` to inspect completed Work Items and historical relationships.");
6449
+ }
6450
+ } else {
6451
+ lines.push("No hints \u2014 the declared relationships look healthy. \u{1F389}");
6452
+ }
6042
6453
  lines.push("");
6043
6454
  return lines.join("\n");
6044
6455
  }
@@ -6074,6 +6485,8 @@ function loadGraphHints(dir) {
6074
6485
  const report = JSON.parse(readFile(p2));
6075
6486
  const hints = Array.isArray(report.hints) ? report.hints : [];
6076
6487
  return {
6488
+ scope: String(report.scope ?? "active"),
6489
+ scopeReason: String(report.scope_reason ?? ""),
6077
6490
  quality: report.quality ?? "empty",
6078
6491
  totalHints: hints.length,
6079
6492
  activeWorkItemHints: hints.filter((h) => h.artifact_type === "work-item").length,
@@ -6084,6 +6497,42 @@ function loadGraphHints(dir) {
6084
6497
  }
6085
6498
  }
6086
6499
 
6500
+ // src/services/installed-skills.ts
6501
+ import matter3 from "gray-matter";
6502
+ var SKILLS_DIR = join("knowledge", "skills");
6503
+ function discoverInstalledSkills(dir) {
6504
+ const base = join(dir, SKILLS_DIR);
6505
+ if (!exists(base) || !isDir(base)) return [];
6506
+ const out = [];
6507
+ for (const entry of readDir(base)) {
6508
+ const skillFile = join(base, entry, "skill.md");
6509
+ if (!isFile(skillFile)) continue;
6510
+ try {
6511
+ const { data } = matter3(readFile(skillFile));
6512
+ if (data.type && String(data.type) !== "skill") continue;
6513
+ const id = String(data.id ?? entry);
6514
+ out.push({
6515
+ id,
6516
+ title: String(data.title ?? id),
6517
+ group: String(data.group ?? "unknown"),
6518
+ appliesTo: Array.isArray(data.applies_to) ? data.applies_to.map(String).filter(Boolean) : [],
6519
+ relPath: `${SKILLS_DIR.replace(/\\/g, "/")}/${entry}/skill.md`
6520
+ });
6521
+ } catch {
6522
+ }
6523
+ }
6524
+ return out.sort((a, b) => a.id.localeCompare(b.id));
6525
+ }
6526
+ function skillGroupCounts(skills) {
6527
+ const counts = {};
6528
+ for (const s of skills) counts[s.group] = (counts[s.group] ?? 0) + 1;
6529
+ return counts;
6530
+ }
6531
+ function skillsForAgents(skills, agents) {
6532
+ const set = new Set(agents.map((a) => a.replace(/\.md$/, "")));
6533
+ return skills.filter((s) => s.appliesTo.some((a) => set.has(a))).map((s) => s.id);
6534
+ }
6535
+
6087
6536
  // src/core/knowledge-discovery.ts
6088
6537
  var KNOWLEDGE4 = "knowledge";
6089
6538
  var CONSOLIDATED_TYPE = {
@@ -6416,6 +6865,10 @@ function buildProjectExplanation(dir) {
6416
6865
  externalCapsules: loadExternalCapsules(dir),
6417
6866
  graph: loadGraphSummary(dir),
6418
6867
  graphHints: loadGraphHints(dir),
6868
+ skills: (() => {
6869
+ const installed = discoverInstalledSkills(dir);
6870
+ return { total: installed.length, byGroup: skillGroupCounts(installed) };
6871
+ })(),
6419
6872
  layers,
6420
6873
  roadmap,
6421
6874
  mappedModules,
@@ -6557,13 +7010,27 @@ function renderExplanationHuman(exp) {
6557
7010
  }
6558
7011
  if (exp.graph) {
6559
7012
  lines.push("## Knowledge Graph");
7013
+ lines.push(`- Scope: ${exp.graph.scope}`);
6560
7014
  lines.push(`- Nodes: ${exp.graph.nodes}`);
6561
7015
  lines.push(`- Edges: ${exp.graph.edges}`);
6562
7016
  if (exp.graphHints) {
6563
7017
  lines.push(`- Quality: ${exp.graphHints.quality}`);
6564
7018
  lines.push(`- Hints: ${exp.graphHints.totalHints}`);
6565
7019
  }
7020
+ if (exp.graph.scopeReason) lines.push(`- Reason: ${exp.graph.scopeReason}`);
6566
7021
  if (exp.graph.generatedAt) lines.push(`- Last exported: ${exp.graph.generatedAt}`);
7022
+ if (exp.graph.scope === "active" && exp.graphHints?.quality === "empty") {
7023
+ lines.push("- Tip: Run `kaddo graph export --scope all` to include completed Work Items");
7024
+ }
7025
+ lines.push("");
7026
+ }
7027
+ if (exp.skills.total > 0) {
7028
+ lines.push(`## Skills installed: ${exp.skills.total}`);
7029
+ const groups = Object.entries(exp.skills.byGroup).sort((a, b) => a[0].localeCompare(b[0]));
7030
+ if (groups.length > 0) {
7031
+ lines.push("Groups:");
7032
+ for (const [g, n] of groups) lines.push(`- ${g}: ${n}`);
7033
+ }
6567
7034
  lines.push("");
6568
7035
  }
6569
7036
  if (exp.missingKnowledge.length > 0) {
@@ -6609,7 +7076,7 @@ function readKnowledge(dir) {
6609
7076
  if (!exists(knowledgePath)) return null;
6610
7077
  try {
6611
7078
  const raw = readFile(knowledgePath);
6612
- const { data, content } = matter3(raw);
7079
+ const { data, content } = matter4(raw);
6613
7080
  return { content, data };
6614
7081
  } catch {
6615
7082
  return null;
@@ -6620,7 +7087,7 @@ function readRoadmap(dir) {
6620
7087
  if (!exists(roadmapPath)) return null;
6621
7088
  try {
6622
7089
  const raw = readFile(roadmapPath);
6623
- const { content } = matter3(raw);
7090
+ const { content } = matter4(raw);
6624
7091
  return content.trim();
6625
7092
  } catch {
6626
7093
  return null;
@@ -6789,7 +7256,7 @@ function runExplain(opts) {
6789
7256
  }
6790
7257
 
6791
7258
  // src/core/context-pack.ts
6792
- import matter4 from "gray-matter";
7259
+ import matter5 from "gray-matter";
6793
7260
  var CONTEXT_PACK_VERSION = "1";
6794
7261
  var ARCH_DIR6 = "knowledge";
6795
7262
  function readScanJson(dir) {
@@ -6802,7 +7269,7 @@ function readScanJson(dir) {
6802
7269
  }
6803
7270
  }
6804
7271
  function firstParagraph2(markdown) {
6805
- const body = matter4(markdown).content.trim();
7272
+ const body = matter5(markdown).content.trim();
6806
7273
  const para = body.split("\n\n").map((p2) => p2.trim()).find((p2) => p2 && !p2.startsWith("#"));
6807
7274
  return para ?? "";
6808
7275
  }
@@ -6975,6 +7442,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
6975
7442
  external: loadExternalCapsules(dir),
6976
7443
  graph: loadGraphSummary(dir),
6977
7444
  graphHints: loadGraphHints(dir),
7445
+ skills: discoverInstalledSkills(dir).map((s) => s.id),
6978
7446
  mappedModules,
6979
7447
  missing,
6980
7448
  // VS-052: the handoff is driven by the REAL phase, not project.state, so the pack never
@@ -7145,9 +7613,12 @@ function renderContextPack(pack) {
7145
7613
  parts.push(
7146
7614
  [
7147
7615
  "- Available: yes",
7616
+ `- Scope: ${pack.graph.scope}`,
7148
7617
  `- Nodes: ${pack.graph.nodes}`,
7149
7618
  `- Edges: ${pack.graph.edges}`,
7150
- `- Active Work Items connected to code: ${pack.graph.activeWorkItemsConnectedToCode}`
7619
+ ...pack.graphHints ? [`- Quality: ${pack.graphHints.quality}`] : [],
7620
+ `- Active Work Items connected to code: ${pack.graph.activeWorkItemsConnectedToCode}`,
7621
+ ...pack.graph.scopeReason ? [`- Reason: ${pack.graph.scopeReason}`] : []
7151
7622
  ].join("\n") + "\n"
7152
7623
  );
7153
7624
  parts.push("Full graph: `.kaddo/graph.json` / `.kaddo/graph.mmd` (run `kaddo graph export` to refresh).\n");
@@ -7168,6 +7639,12 @@ function renderContextPack(pack) {
7168
7639
  `);
7169
7640
  }
7170
7641
  }
7642
+ if (pack.skills.length > 0) {
7643
+ parts.push("## Skills\n");
7644
+ parts.push("Available reusable skills (agents apply these; content is not inlined):\n");
7645
+ parts.push(pack.skills.map((s) => `- ${s}`).join("\n") + "\n");
7646
+ parts.push("Read full skill definitions in `knowledge/skills/` or via the Kaddo MCP server (`kaddo://skills`).\n");
7647
+ }
7171
7648
  parts.push("## Missing Context\n");
7172
7649
  if (missing.length > 0) {
7173
7650
  parts.push(missing.map((m) => `- ${m}`).join("\n") + "\n");
@@ -7489,6 +7966,14 @@ function runUnderstand() {
7489
7966
  if (assessment.nextStep) {
7490
7967
  console.log(`Next step: ${assessment.nextStep}`);
7491
7968
  }
7969
+ const installedSkills = discoverInstalledSkills(dir);
7970
+ if (installedSkills.length > 0 && assessment.recommendedAgents.length > 0) {
7971
+ const recSkills = skillsForAgents(installedSkills, assessment.recommendedAgents);
7972
+ if (recSkills.length > 0) {
7973
+ console.log("Recommended skills:");
7974
+ for (const s of recSkills) console.log(` - ${s}`);
7975
+ }
7976
+ }
7492
7977
  if (exp.externalCapsules.length > 0) {
7493
7978
  console.log("");
7494
7979
  console.log("External knowledge:");
@@ -7803,7 +8288,7 @@ function runStatus() {
7803
8288
  }
7804
8289
 
7805
8290
  // src/commands/learn.ts
7806
- import matter5 from "gray-matter";
8291
+ import matter6 from "gray-matter";
7807
8292
  var ARCH_DIR9 = "knowledge";
7808
8293
  var WORK_ITEMS_DIR2 = "knowledge/delivery/work-items";
7809
8294
  function findWorkItemFile(dir, id) {
@@ -7815,7 +8300,7 @@ function findWorkItemFile(dir, id) {
7815
8300
  }
7816
8301
  function updateWorkItemFile(filePath, learning) {
7817
8302
  const raw = readFile(filePath);
7818
- const { data, content } = matter5(raw);
8303
+ const { data, content } = matter6(raw);
7819
8304
  data.status = "done";
7820
8305
  data.completed_at = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
7821
8306
  let updatedContent = content;
@@ -7840,7 +8325,7 @@ ${learning.trim()}
7840
8325
  ${learning.trim()}
7841
8326
  `;
7842
8327
  }
7843
- const newRaw = matter5.stringify(updatedContent, data);
8328
+ const newRaw = matter6.stringify(updatedContent, data);
7844
8329
  writeFile(filePath, newRaw);
7845
8330
  }
7846
8331
  async function runLearn(artifactId) {
@@ -7968,6 +8453,12 @@ function selectAgentModuleFiles(files, opts, state) {
7968
8453
  );
7969
8454
  return { files: selected, label };
7970
8455
  }
8456
+ function selectSkillModuleFiles(files, opts) {
8457
+ const { ids, label } = selectSkills({ all: opts.all, group: opts.group });
8458
+ const wanted = new Set(ids.map((id) => skillInstallPath(id)));
8459
+ const selected = files.filter((f) => f.path.endsWith("README.md") || wanted.has(f.path));
8460
+ return { files: selected, label };
8461
+ }
7971
8462
  function markModuleInstalled(dir, configKey, moduleName) {
7972
8463
  const configPath = join(dir, CONFIG_PATH5);
7973
8464
  if (!exists(configPath)) return;
@@ -8028,6 +8519,15 @@ function runAdd(moduleName, opts = {}, dir = cwd()) {
8028
8519
  console.error(err instanceof Error ? err.message : String(err));
8029
8520
  process.exit(1);
8030
8521
  }
8522
+ } else if (mod.name === "skills") {
8523
+ try {
8524
+ const sel = selectSkillModuleFiles(mod.files, opts);
8525
+ filesToInstall = sel.files;
8526
+ log2.info(`Installing skills (${sel.label}).`);
8527
+ } catch (err) {
8528
+ console.error(err instanceof Error ? err.message : String(err));
8529
+ process.exit(1);
8530
+ }
8031
8531
  }
8032
8532
  const written = [];
8033
8533
  const skipped = [];
@@ -8058,6 +8558,13 @@ function runAdd(moduleName, opts = {}, dir = cwd()) {
8058
8558
  outro2("Agents installed. Kaddo prepares context \u2014 your LLM does the interpretation.");
8059
8559
  return;
8060
8560
  }
8561
+ if (mod.name === "skills") {
8562
+ log2.info("Skills are reusable capabilities agents apply \u2014 they never run anything.");
8563
+ log2.info("More skills: `kaddo add skills --all` or `--group <delivery|tech|integration>`.");
8564
+ log2.info("Read them in `knowledge/skills/` or via the Kaddo MCP server (`kaddo://skills`).");
8565
+ outro2("Skills installed. Agents orchestrate; skills standardize.");
8566
+ return;
8567
+ }
8061
8568
  if (mod.workItemTypes.length > 0) {
8062
8569
  log2.info(`New work item types available:`);
8063
8570
  for (const t of mod.workItemTypes) {
@@ -8068,7 +8575,7 @@ function runAdd(moduleName, opts = {}, dir = cwd()) {
8068
8575
  }
8069
8576
 
8070
8577
  // src/core/ownership-suggest.ts
8071
- import matter6 from "gray-matter";
8578
+ import matter7 from "gray-matter";
8072
8579
  var SCAN_PATH = ".kaddo/scan.json";
8073
8580
  function normalizeGlob(input) {
8074
8581
  let g = input.trim().replace(/\\/g, "/");
@@ -8190,11 +8697,11 @@ function suggestGlobs(artifact, signals) {
8190
8697
  return [...new Set(out)];
8191
8698
  }
8192
8699
  function applyOwnership(raw, globs, mode = "replace") {
8193
- const parsed = matter6(raw);
8700
+ const parsed = matter7(raw);
8194
8701
  const existing = toStringArray3(parsed.data.code);
8195
8702
  const next = mode === "append" ? [.../* @__PURE__ */ new Set([...existing, ...globs])] : [...new Set(globs)];
8196
8703
  const data = { ...parsed.data, code: next };
8197
- return matter6.stringify(parsed.content, data);
8704
+ return matter7.stringify(parsed.content, data);
8198
8705
  }
8199
8706
 
8200
8707
  // src/commands/owners.ts
@@ -10349,9 +10856,15 @@ function runGraphExport(opts = {}) {
10349
10856
  writeFile(join(dir, ".kaddo", "graph-hints.md"), renderGraphHintsMarkdown(hints));
10350
10857
  writeFile(join(dir, ".kaddo", "graph-hints.json"), serializeGraphHintsJson(hints));
10351
10858
  written.push(".kaddo/graph-hints.md", ".kaddo/graph-hints.json");
10352
- log2.success("Knowledge graph exported.");
10859
+ log2.success(`Knowledge graph exported with ${scope} scope.`);
10353
10860
  log2.info(`Scope: ${scope} \xB7 Nodes: ${graph.nodes.length} \xB7 Edges: ${graph.edges.length}`);
10354
10861
  log2.info(`Relationship quality: ${hints.quality}`);
10862
+ const hasWorkItemNodes = graph.nodes.some((n) => n.type === "work-item");
10863
+ if (scope === "active" && !hasWorkItemNodes) {
10864
+ log2.warn("No active Work Items found.");
10865
+ log2.info("The active graph only includes knowledge layers.");
10866
+ log2.info("Run `kaddo graph export --scope all` to include completed Work Items.");
10867
+ }
10355
10868
  if (hints.hints.length > 0) {
10356
10869
  const shown = hints.hints.slice(0, 5);
10357
10870
  log2.warn(`${hints.hints.length} metadata hint(s) available:`);
@@ -10393,7 +10906,7 @@ var graphCmd = program.command("graph").description("Export the lightweight, fil
10393
10906
  graphCmd.command("export").description("Write the knowledge graph to .kaddo/graph.json and .kaddo/graph.mmd").option("--scope <scope>", "Graph scope: active (default) or all").option("--format <format>", "Output format: json, mermaid (default: both)").action((opts) => {
10394
10907
  runGraphExport(opts);
10395
10908
  });
10396
- program.command("guard").description("Check if modified code has related artifacts that were not updated").option("--staged", "Check only staged files").option("--no-interactive", "Disable interactive ignore prompts").option("--ci", "CI mode: output JSON, no prompts, non-blocking").option("--json", "Output JSON (alias for --ci)").option("--workspace", "Also check local mapped module repos from .kaddo/modules.yml (opt-in)").action(async (opts) => {
10909
+ program.command("guard").description("Check if modified code has related artifacts that were not updated").option("--staged", "Check only staged files").option("--no-interactive", "Disable interactive ignore prompts").option("--ci", "CI mode: output JSON, no prompts, non-blocking").option("--json", "Output JSON (alias for --ci)").option("--workspace", "Also check local mapped module repos from .kaddo/modules.yml (opt-in)").option("--include-archived", "Include archived Work Items in ownership matching (excluded by default)").action(async (opts) => {
10397
10910
  await runGuard(opts);
10398
10911
  });
10399
10912
  var ignoreCmd = program.command("ignore").description("Manage guard ignore list");
@@ -10444,7 +10957,7 @@ modulesCmd.command("map").description("Register a secondary repository as a modu
10444
10957
  modulesCmd.command("list").description("List mapped modules").action(() => {
10445
10958
  runModulesList();
10446
10959
  });
10447
- program.command("add [module]").description("Install an optional Kaddo module (adr, incident, rfc, migration, legacy, agents, standards, security, stack, git-strategy)").option("--all", "For `add agents`: install every agent (not just the recommended set)").option("--group <name>", "For `add agents`: install one layer group (business, product, tech, delivery, utilities)").action((moduleName, opts) => {
10960
+ program.command("add [module]").description("Install an optional Kaddo module (adr, incident, rfc, migration, legacy, agents, skills, standards, security, stack, git-strategy)").option("--all", "For `add agents` / `add skills`: install every item (not just the recommended set)").option("--group <name>", "For `add agents`: business|product|tech|delivery|utilities. For `add skills`: delivery|tech|integration").action((moduleName, opts) => {
10448
10961
  runAdd(moduleName ?? "", { all: opts.all, group: opts.group });
10449
10962
  });
10450
10963
  program.parseAsync(process.argv).catch((err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/cli",
3
- "version": "3.20.0",
3
+ "version": "3.22.0",
4
4
  "description": "Knowledge Driven Development toolkit",
5
5
  "license": "MIT",
6
6
  "repository": {