@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.
- package/README.md +4 -0
- package/dist/index.js +598 -85
- 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,
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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 } =
|
|
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 } =
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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 } =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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(
|
|
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
|
|
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) => {
|