@kaddo/cli 3.39.0 → 3.40.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 +2 -0
- package/dist/index.js +287 -55
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -536,6 +536,8 @@ create --from roadmap → owners → guard → explain`.
|
|
|
536
536
|
| v3.37.1 | Unified next-step: one shared resolver (`core/next-step.ts`) powers `context`, `understand` and `explain` (Phase + Readiness) so they never diverge; agent JSON exposes `nextStepRecommendation`. Fixes duplicate `capabilities` line in explain |
|
|
537
537
|
| v3.38 | Open-question source locations: `kaddo questions` shows each question's `Source` (path:line), `Status`, `Severity`, `Note` + a copy/paste resolution example and localized how-to-resolve guide; JSON/report/MCP carry `sourcePath`, `line`, `raw`, `note` |
|
|
538
538
|
| v3.39 | Existing capability discovery: state-aware `capabilities.md` (pre-ai/legacy = evidence-backed Capability Inventory + Gaps + Roadmap Candidate Signals; legacy adds criticality/change-risk/modernization); capability-agent discovers with evidence, roadmap-agent treats capabilities as primary source |
|
|
539
|
+
| v3.39.1 | Domain-oriented capability inventory: pre-ai/legacy `capabilities.md` groups capabilities under `## Capability Domains` (functional domains, not technical folders); gaps/candidates name their `Domain`; roadmap-agent reads it as a domain map; work-item-agent recommends `related_domain` + `related_capability` |
|
|
540
|
+
| v3.40 | ADR materialization: `kaddo adr` (alias `decisions`) detects decision candidates + ADRs and hands off the ADR files to create; `tech_decisions` status (none/candidates/draft-adrs/accepted-adrs) surfaced in `explain`/`context`/`understand`; adr-writing skill formalized |
|
|
539
541
|
|
|
540
542
|
**Optional modules (installed with `kaddo add`):**
|
|
541
543
|
|
package/dist/index.js
CHANGED
|
@@ -704,6 +704,10 @@ var COMMAND_HELP = {
|
|
|
704
704
|
"adapters install codex": {
|
|
705
705
|
question: "How does Codex work with this Kaddo project?",
|
|
706
706
|
next: "Open AGENTS.md, or regenerate it after knowledge changes"
|
|
707
|
+
},
|
|
708
|
+
adr: {
|
|
709
|
+
question: "Which technical decisions still need to become ADRs?",
|
|
710
|
+
next: "Use the adr-writing skill to draft ADRs, then mark them accepted when confirmed"
|
|
707
711
|
}
|
|
708
712
|
};
|
|
709
713
|
function commandFooterLines(name) {
|
|
@@ -1546,37 +1550,56 @@ The context pack, the relevant Work Item or architecture note, and the decision
|
|
|
1546
1550
|
|
|
1547
1551
|
## Output
|
|
1548
1552
|
|
|
1549
|
-
A single ADR
|
|
1550
|
-
|
|
1551
|
-
superseded
|
|
1553
|
+
A single ADR (saved under \`knowledge/tech/decisions/\`) with front matter and the standard sections:
|
|
1554
|
+
context, options considered, the decision, consequences, related capabilities and related Work Items.
|
|
1555
|
+
Status is one of \`draft\`, \`accepted\`, \`superseded\`, \`deprecated\`.
|
|
1556
|
+
|
|
1557
|
+
## Materializing from decision candidates (VS-075)
|
|
1558
|
+
|
|
1559
|
+
When \`knowledge/tech/decisions/\` is empty but \`knowledge/tech/decision-candidates.md\` holds
|
|
1560
|
+
candidates, materialize each candidate as an ADR **draft** \u2014 copy its context and options, leave the
|
|
1561
|
+
decision and consequences as \`[open]\` for human confirmation, and record its origin with
|
|
1562
|
+
\`created_from: knowledge/tech/decision-candidates.md\`. Never mark a materialized draft \`accepted\`;
|
|
1563
|
+
acceptance is a human decision.
|
|
1552
1564
|
|
|
1553
1565
|
## Rules
|
|
1554
1566
|
|
|
1555
1567
|
- One ADR = one decision. Never mix unrelated decisions.
|
|
1556
1568
|
- Never invent decisions; never write an ADR without a clear reason.
|
|
1557
|
-
- Record alternatives honestly, including the one chosen and why.
|
|
1569
|
+
- Record alternatives honestly, including the one chosen and why (or \`[open]\` when undecided).
|
|
1558
1570
|
- Prefer narrow governed \`code:\` globs over broad ones.
|
|
1559
1571
|
|
|
1560
1572
|
## Quality checklist
|
|
1561
1573
|
|
|
1562
1574
|
- Context explains why the decision was needed.
|
|
1563
|
-
- The decision and its alternatives are explicit.
|
|
1575
|
+
- The decision and its alternatives are explicit (or explicitly \`[open]\`).
|
|
1564
1576
|
- Consequences (positive and negative) are stated.
|
|
1565
1577
|
- Status and governed paths are present.
|
|
1566
1578
|
|
|
1567
1579
|
## Example output
|
|
1568
1580
|
|
|
1569
1581
|
\`\`\`md
|
|
1570
|
-
|
|
1571
|
-
|
|
1582
|
+
---
|
|
1583
|
+
type: adr
|
|
1584
|
+
status: draft | accepted | superseded | deprecated
|
|
1585
|
+
date: YYYY-MM-DD
|
|
1586
|
+
created_from: knowledge/tech/decision-candidates.md
|
|
1587
|
+
---
|
|
1588
|
+
|
|
1589
|
+
# ADR-001 \u2014 Use INTERNAL_CRON_SECRET for internal endpoint protection
|
|
1590
|
+
|
|
1572
1591
|
## Context
|
|
1573
1592
|
...
|
|
1574
|
-
##
|
|
1575
|
-
...
|
|
1576
|
-
## Alternatives considered
|
|
1593
|
+
## Options Considered
|
|
1577
1594
|
...
|
|
1595
|
+
## Decision
|
|
1596
|
+
[open]
|
|
1578
1597
|
## Consequences
|
|
1579
|
-
|
|
1598
|
+
[open]
|
|
1599
|
+
## Related Capabilities
|
|
1600
|
+
- <domain / capability>
|
|
1601
|
+
## Related Work Items
|
|
1602
|
+
- <WI id>
|
|
1580
1603
|
\`\`\`
|
|
1581
1604
|
`
|
|
1582
1605
|
);
|
|
@@ -2213,11 +2236,11 @@ Adapt to \`project.state\` (from \`.kaddo/config.yml\`):
|
|
|
2213
2236
|
|
|
2214
2237
|
- **new \u2192 Planned Capability Definition.** Define the capabilities the product *should* have. Use
|
|
2215
2238
|
\`[planned]\` items; evidence is not required yet.
|
|
2216
|
-
- **pre-ai \u2192 Existing Capability Discovery.** Document the
|
|
2217
|
-
|
|
2218
|
-
wishlist.
|
|
2219
|
-
- **legacy \u2192 Legacy Capability Discovery.** Same inventory plus **criticality**,
|
|
2220
|
-
**operational dependency** and **modernization notes** per capability.
|
|
2239
|
+
- **pre-ai \u2192 Existing Capability Discovery (Domain-Oriented Capability Inventory).** Document the
|
|
2240
|
+
capabilities the system *already has*, **grouped by functional domain**, with **evidence**, status
|
|
2241
|
+
and gaps \u2014 a photograph of what exists today, not a wishlist.
|
|
2242
|
+
- **legacy \u2192 Legacy Capability Discovery.** Same domain-oriented inventory plus **criticality**,
|
|
2243
|
+
**change risk**, **operational dependency** and **modernization notes** per domain/capability.
|
|
2221
2244
|
|
|
2222
2245
|
## Capability status values
|
|
2223
2246
|
|
|
@@ -2256,10 +2279,12 @@ Analyze the context pack and identify:
|
|
|
2256
2279
|
7. Suggested ownership.
|
|
2257
2280
|
8. Candidate code globs if evident.
|
|
2258
2281
|
|
|
2259
|
-
For **pre-ai** and **legacy**, produce the
|
|
2260
|
-
\`## Capability
|
|
2261
|
-
|
|
2262
|
-
|
|
2282
|
+
For **pre-ai** and **legacy**, produce the domain-oriented inventory (see Output Format): a
|
|
2283
|
+
\`## Capability Domains\` section where each \`### Domain:\` groups capabilities by functional
|
|
2284
|
+
responsibility (with Purpose + Evidence summary), each \`#### Capability:\` has status + evidence, plus
|
|
2285
|
+
\`## Capability Gaps\` and \`## Roadmap Candidate Signals\` (signals only \u2014 never a formal roadmap). Every
|
|
2286
|
+
gap and candidate names its \`Domain\` and \`Related capability\`. For **legacy**, add \`Criticality\`,
|
|
2287
|
+
\`Change risk\`, \`Operational dependency\` and \`Modernization notes\`.
|
|
2263
2288
|
|
|
2264
2289
|
## Constraints
|
|
2265
2290
|
|
|
@@ -2312,36 +2337,50 @@ Generated from Kaddo Context Pack.
|
|
|
2312
2337
|
## Suggested Next Step
|
|
2313
2338
|
\`\`\`
|
|
2314
2339
|
|
|
2315
|
-
### Output Format \u2014 pre-ai / legacy (
|
|
2340
|
+
### Output Format \u2014 pre-ai / legacy (Domain-Oriented Capability Inventory)
|
|
2341
|
+
|
|
2342
|
+
Group capabilities by **functional domain**, not by technical folder. Infer domains from the system
|
|
2343
|
+
(e.g. Loyalty, Billing & Subscriptions, Communications, Operations & Automation) \u2014 do not use a rigid
|
|
2344
|
+
universal taxonomy and do not use folders like \`src/components\` or \`src/app/api\` as domains. A single
|
|
2345
|
+
capability may have evidence across layers (frontend hook + API route + table + webhook).
|
|
2316
2346
|
|
|
2317
2347
|
\`\`\`markdown
|
|
2318
2348
|
# Existing Capabilities
|
|
2319
2349
|
|
|
2320
|
-
## Capability
|
|
2350
|
+
## Capability Domains
|
|
2321
2351
|
|
|
2322
|
-
### <
|
|
2352
|
+
### Domain: <Domain name>
|
|
2353
|
+
|
|
2354
|
+
**Purpose:** <functional responsibility of this domain>
|
|
2355
|
+
|
|
2356
|
+
**Evidence summary:**
|
|
2357
|
+
- \`<path>\` / \`<route>\` / \`<table>\` / \`<function>\`
|
|
2358
|
+
<!-- legacy only: -->
|
|
2359
|
+
**Criticality:** low | medium | high
|
|
2360
|
+
**Change risk:** low | medium | high
|
|
2361
|
+
**Operational dependency:** <...>
|
|
2362
|
+
|
|
2363
|
+
#### Capability: <Capability name>
|
|
2323
2364
|
|
|
2324
2365
|
- Status: implemented | partial | inferred | risky | deprecated | unknown
|
|
2325
2366
|
- Capability type: business | product | technical | integration | operational
|
|
2326
2367
|
- User-facing: yes | no | internal
|
|
2327
2368
|
- Evidence:
|
|
2328
|
-
- \`<path/to/file>\`
|
|
2329
|
-
|
|
2330
|
-
- Related
|
|
2369
|
+
- \`<path/to/file>\` / \`<route>\` / \`<table>\` / \`<function>\`
|
|
2370
|
+
- Related flows:
|
|
2371
|
+
- Related data:
|
|
2372
|
+
- Related integrations:
|
|
2331
2373
|
- Current behavior:
|
|
2332
2374
|
- Known constraints:
|
|
2333
2375
|
- Risks or uncertainty:
|
|
2334
2376
|
- Open questions:
|
|
2335
2377
|
- [open] ...
|
|
2336
|
-
<!-- legacy only: -->
|
|
2337
|
-
- Criticality: low | medium | high
|
|
2338
|
-
- Change risk: low | medium | high
|
|
2339
|
-
- Operational dependency:
|
|
2340
|
-
- Modernization notes:
|
|
2378
|
+
<!-- legacy only, per capability: Modernization notes -->
|
|
2341
2379
|
|
|
2342
2380
|
## Capability Gaps
|
|
2343
2381
|
|
|
2344
2382
|
- [gap] <Gap description>
|
|
2383
|
+
- Domain: <Domain name>
|
|
2345
2384
|
- Related capability: <name>
|
|
2346
2385
|
- Impact: low | medium | high
|
|
2347
2386
|
- Possible roadmap candidate: yes | no
|
|
@@ -2349,10 +2388,20 @@ Generated from Kaddo Context Pack.
|
|
|
2349
2388
|
## Roadmap Candidate Signals
|
|
2350
2389
|
|
|
2351
2390
|
- [candidate] <Potential roadmap candidate>
|
|
2352
|
-
-
|
|
2391
|
+
- Domain: <Domain name>
|
|
2353
2392
|
- Related capability: <name>
|
|
2393
|
+
- Based on: partial capability | gap | risk | open question | business goal
|
|
2354
2394
|
\`\`\`
|
|
2355
2395
|
|
|
2396
|
+
### Domain grouping rules
|
|
2397
|
+
|
|
2398
|
+
- Group by **functional responsibility**, never by technical folder.
|
|
2399
|
+
- A capability may span multiple layers \u2014 list all its evidence.
|
|
2400
|
+
- Keep the VS-074 evidence rule: \`implemented\` needs concrete evidence; indirect \u2192 \`inferred\`; none \u2192
|
|
2401
|
+
\`unknown\`. Never invent domains, paths, routes, tables or functions.
|
|
2402
|
+
- Every \`[gap]\` names its \`Domain\` and \`Related capability\`; every \`[candidate]\` names \`Domain\`,
|
|
2403
|
+
\`Related capability\` and \`Based on\`.
|
|
2404
|
+
|
|
2356
2405
|
## Where to Save the Result
|
|
2357
2406
|
|
|
2358
2407
|
Save the output as \`knowledge/product/capabilities.md\`.
|
|
@@ -2472,7 +2521,8 @@ Use this agent after capabilities and architecture are understood (or at least a
|
|
|
2472
2521
|
Provide \`.kaddo/context-pack.md\` as the primary input, and treat
|
|
2473
2522
|
\`knowledge/product/capabilities.md\` as the **primary source for roadmap candidates** (VS-074).
|
|
2474
2523
|
|
|
2475
|
-
|
|
2524
|
+
Read \`capabilities.md\` as a **map of functional domains** (\`## Capability Domains\`). Derive roadmap
|
|
2525
|
+
candidates from the inventory, prioritizing:
|
|
2476
2526
|
|
|
2477
2527
|
- \`partial\` capabilities (finish what exists)
|
|
2478
2528
|
- \`## Capability Gaps\` (\`[gap]\` items, especially Impact: high)
|
|
@@ -2481,6 +2531,15 @@ Derive roadmap candidates from the capability inventory, prioritizing:
|
|
|
2481
2531
|
- resolved/assumed/deferred open questions and business goals
|
|
2482
2532
|
- technical risks and decision candidates
|
|
2483
2533
|
|
|
2534
|
+
Each roadmap candidate should reference its \`Domain\` and \`Related capability\`, e.g.:
|
|
2535
|
+
|
|
2536
|
+
\`\`\`md
|
|
2537
|
+
- [candidate] Harden idempotent payment webhook processing.
|
|
2538
|
+
- Domain: Billing & Subscriptions
|
|
2539
|
+
- Related capability: Payment Webhook Processing
|
|
2540
|
+
- Based on: risk
|
|
2541
|
+
\`\`\`
|
|
2542
|
+
|
|
2484
2543
|
**Do not** build a roadmap from general ideas when \`capabilities.md\` is still a placeholder or weak:
|
|
2485
2544
|
if capabilities are not yet discovered, recommend running the \`capability-agent\` first.
|
|
2486
2545
|
|
|
@@ -2895,9 +2954,17 @@ A refined Work Item intended to be saved under the lifecycle workspace:
|
|
|
2895
2954
|
|
|
2896
2955
|
**Suggested ownership (code globs):**
|
|
2897
2956
|
|
|
2898
|
-
**Related capability:** <!-- recommended (VS-074): the
|
|
2899
|
-
knowledge/product/capabilities.md this Work Item advances, so work traces back to
|
|
2900
|
-
Add \`related_capability: <name>\` to the front
|
|
2957
|
+
**Related domain / capability:** <!-- recommended (VS-074/074.1): the functional domain and the
|
|
2958
|
+
capability from knowledge/product/capabilities.md this Work Item advances, so work traces back to the
|
|
2959
|
+
system's functional map. Add \`related_domain: <domain>\` and \`related_capability: <name>\` to the front
|
|
2960
|
+
matter when known. -->
|
|
2961
|
+
|
|
2962
|
+
**Related decisions:** <!-- recommended (VS-075): if this Work Item is affected by a technical
|
|
2963
|
+
decision, reference the ADR under knowledge/tech/decisions/ as \`related_decisions: [ADR-001-...]\`. If
|
|
2964
|
+
the decision is still a candidate in knowledge/tech/decision-candidates.md with no ADR yet, **warn**
|
|
2965
|
+
that it should be materialized first (\`kaddo adr\` + the adr-writing skill) and record
|
|
2966
|
+
\`decision_candidates: [<title>]\` \u2014 do not implement work that depends on an unformalized decision
|
|
2967
|
+
without surfacing it. -->
|
|
2901
2968
|
\`\`\`
|
|
2902
2969
|
|
|
2903
2970
|
## Where to Save the Result
|
|
@@ -3474,6 +3541,12 @@ architecture, persistence, authentication or the Work Item's scope. Block only o
|
|
|
3474
3541
|
mention the relevant assumptions instead of pausing. If any blocking question is still open, pause and
|
|
3475
3542
|
ask the user to confirm assumptions or resolve them before writing code.
|
|
3476
3543
|
|
|
3544
|
+
Also check **technical decisions** (VS-075): if the Work Item touches a decision that is still a
|
|
3545
|
+
candidate in \`knowledge/tech/decision-candidates.md\` with no ADR under \`knowledge/tech/decisions/\`
|
|
3546
|
+
(run \`kaddo adr\`), **warn** and recommend materializing it as an ADR (adr-writing skill) before
|
|
3547
|
+
implementing \u2014 do not silently implement work that depends on an unformalized architectural,
|
|
3548
|
+
security, data, integration or infrastructure decision.
|
|
3549
|
+
|
|
3477
3550
|
## When to Use
|
|
3478
3551
|
|
|
3479
3552
|
Use this agent after the work-item-agent has produced a clear, traceable Work Item under
|
|
@@ -7084,6 +7157,9 @@ function isPlaceholderLine(line) {
|
|
|
7084
7157
|
if (/<[^>]+>/.test(t)) return true;
|
|
7085
7158
|
if (/^[-*]\s+[^:]+:\s*$/.test(t)) return true;
|
|
7086
7159
|
if (/^[-*]\s+[^:]+:\s*\S.*\s\|\s/.test(t)) return true;
|
|
7160
|
+
if (/^\*\*[^*]+:\*\*\s*$/.test(t)) return true;
|
|
7161
|
+
if (/^\*\*[^*]+:\*\*\s*_.*_$/.test(t)) return true;
|
|
7162
|
+
if (/^\*\*[^*]+:\*\*\s*\S.*\s\|\s/.test(t)) return true;
|
|
7087
7163
|
return false;
|
|
7088
7164
|
}
|
|
7089
7165
|
function isStructuralLine(line, inFrontMatter) {
|
|
@@ -7926,7 +8002,7 @@ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
7926
8002
|
if (qBusiness !== "useful") return refine("refine-business", "business-agent", B, qBusiness);
|
|
7927
8003
|
if (qProduct !== "useful" || qCap !== "useful") {
|
|
7928
8004
|
if (qCap !== "useful") {
|
|
7929
|
-
return refine("refine-product", "capability-agent", CAP, qCap, discovery ? "discover and document existing system capabilities in" : "complete");
|
|
8005
|
+
return refine("refine-product", "capability-agent", CAP, qCap, discovery ? "discover and document existing system capabilities grouped by functional domains in" : "complete");
|
|
7930
8006
|
}
|
|
7931
8007
|
return refine("refine-product", "capability-agent", P, qProduct);
|
|
7932
8008
|
}
|
|
@@ -8046,6 +8122,76 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
8046
8122
|
};
|
|
8047
8123
|
}
|
|
8048
8124
|
|
|
8125
|
+
// src/core/decisions.ts
|
|
8126
|
+
var CANDIDATES_PATH = "knowledge/tech/decision-candidates.md";
|
|
8127
|
+
var DECISIONS_DIR = "knowledge/tech/decisions";
|
|
8128
|
+
function slugify2(s) {
|
|
8129
|
+
return s.toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60);
|
|
8130
|
+
}
|
|
8131
|
+
function parseDecisionCandidates(md) {
|
|
8132
|
+
const out = [];
|
|
8133
|
+
for (const line of md.split(/\r?\n/)) {
|
|
8134
|
+
const m = line.match(/^##\s+(.+?)\s*$/);
|
|
8135
|
+
if (m) {
|
|
8136
|
+
const t = m[1].trim();
|
|
8137
|
+
if (t && !/^_.*_$/.test(t)) out.push(t);
|
|
8138
|
+
}
|
|
8139
|
+
}
|
|
8140
|
+
return out;
|
|
8141
|
+
}
|
|
8142
|
+
function countAdrs(dir) {
|
|
8143
|
+
const base = join(dir, DECISIONS_DIR);
|
|
8144
|
+
if (!exists(base)) return { total: 0, draft: 0, accepted: 0 };
|
|
8145
|
+
let total = 0;
|
|
8146
|
+
let draft = 0;
|
|
8147
|
+
let accepted = 0;
|
|
8148
|
+
for (const entry of readDir(base)) {
|
|
8149
|
+
if (!entry.endsWith(".md") || entry === ".gitkeep") continue;
|
|
8150
|
+
const full = join(base, entry);
|
|
8151
|
+
if (!isFile(full)) continue;
|
|
8152
|
+
total += 1;
|
|
8153
|
+
let content = "";
|
|
8154
|
+
try {
|
|
8155
|
+
content = readFile(full);
|
|
8156
|
+
} catch {
|
|
8157
|
+
continue;
|
|
8158
|
+
}
|
|
8159
|
+
const status = content.match(/^\s*status:\s*([a-z-]+)/im)?.[1]?.toLowerCase();
|
|
8160
|
+
if (status === "accepted") accepted += 1;
|
|
8161
|
+
else draft += 1;
|
|
8162
|
+
}
|
|
8163
|
+
return { total, draft, accepted };
|
|
8164
|
+
}
|
|
8165
|
+
function buildTechDecisions(dir) {
|
|
8166
|
+
const candFile = join(dir, CANDIDATES_PATH);
|
|
8167
|
+
let titles = [];
|
|
8168
|
+
if (exists(candFile)) {
|
|
8169
|
+
try {
|
|
8170
|
+
titles = parseDecisionCandidates(readFile(candFile));
|
|
8171
|
+
} catch {
|
|
8172
|
+
titles = [];
|
|
8173
|
+
}
|
|
8174
|
+
}
|
|
8175
|
+
const { total, draft, accepted } = countAdrs(dir);
|
|
8176
|
+
const candidate_list = titles.map((title, i) => {
|
|
8177
|
+
const n = String(total + i + 1).padStart(3, "0");
|
|
8178
|
+
return { title, source: CANDIDATES_PATH, suggestedAdrFile: `${DECISIONS_DIR}/ADR-${n}-${slugify2(title)}.md` };
|
|
8179
|
+
});
|
|
8180
|
+
let status;
|
|
8181
|
+
if (accepted > 0) status = "accepted-adrs";
|
|
8182
|
+
else if (total > 0) status = "draft-adrs";
|
|
8183
|
+
else if (titles.length > 0) status = "candidates";
|
|
8184
|
+
else status = "none";
|
|
8185
|
+
return {
|
|
8186
|
+
status,
|
|
8187
|
+
candidates: titles.length,
|
|
8188
|
+
adrs: total,
|
|
8189
|
+
draft_adrs: draft,
|
|
8190
|
+
accepted_adrs: accepted,
|
|
8191
|
+
candidate_list
|
|
8192
|
+
};
|
|
8193
|
+
}
|
|
8194
|
+
|
|
8049
8195
|
// src/core/project-explain.ts
|
|
8050
8196
|
var ARCH_DIR4 = "knowledge";
|
|
8051
8197
|
function normalizeTitle(t) {
|
|
@@ -8257,7 +8403,8 @@ function buildProjectExplanation(dir) {
|
|
|
8257
8403
|
missingKnowledge,
|
|
8258
8404
|
suggestedNextSteps,
|
|
8259
8405
|
readiness,
|
|
8260
|
-
nextStepRecommendation: readiness.nextStepRecommendation
|
|
8406
|
+
nextStepRecommendation: readiness.nextStepRecommendation,
|
|
8407
|
+
techDecisions: buildTechDecisions(dir)
|
|
8261
8408
|
};
|
|
8262
8409
|
}
|
|
8263
8410
|
function stateLabel(state) {
|
|
@@ -8471,6 +8618,16 @@ function renderExplanationHuman(exp) {
|
|
|
8471
8618
|
lines.push("### Recommended next step");
|
|
8472
8619
|
lines.push(r.recommended_next_step.label);
|
|
8473
8620
|
lines.push("");
|
|
8621
|
+
const td = exp.techDecisions;
|
|
8622
|
+
lines.push("## Tech Decisions");
|
|
8623
|
+
lines.push(`- Decision candidates: ${td.candidates}`);
|
|
8624
|
+
lines.push(`- ADRs: ${td.adrs} (draft: ${td.draft_adrs}, accepted: ${td.accepted_adrs})`);
|
|
8625
|
+
lines.push(`- Status: ${td.status}`);
|
|
8626
|
+
if (td.candidates > 0 && td.adrs === 0) {
|
|
8627
|
+
lines.push("");
|
|
8628
|
+
lines.push("Use the adr-writing skill to materialize decision candidates into ADRs (`kaddo adr`) before implementing related technical Work Items.");
|
|
8629
|
+
}
|
|
8630
|
+
lines.push("");
|
|
8474
8631
|
return lines.join("\n").trimEnd() + "\n";
|
|
8475
8632
|
}
|
|
8476
8633
|
function renderExplanationAgent(exp) {
|
|
@@ -8815,6 +8972,10 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
8815
8972
|
}
|
|
8816
8973
|
});
|
|
8817
8974
|
const nextStepRecommendation = resolveNextStep(dir, now);
|
|
8975
|
+
const techDecisions = buildTechDecisions(dir);
|
|
8976
|
+
if (techDecisions.candidates > 0 && techDecisions.adrs === 0) {
|
|
8977
|
+
missing.push(`${techDecisions.candidates} technical decision candidate(s) not yet materialized as ADRs (run \`kaddo adr\`).`);
|
|
8978
|
+
}
|
|
8818
8979
|
const unifiedPhase = {
|
|
8819
8980
|
...phase,
|
|
8820
8981
|
nextStep: nextStepRecommendation.label,
|
|
@@ -8852,6 +9013,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
8852
9013
|
roadmap,
|
|
8853
9014
|
phase: unifiedPhase,
|
|
8854
9015
|
nextStepRecommendation,
|
|
9016
|
+
techDecisions,
|
|
8855
9017
|
deliveryMix,
|
|
8856
9018
|
external: loadExternalCapsules(dir),
|
|
8857
9019
|
graph: loadGraphSummary(dir),
|
|
@@ -9275,12 +9437,12 @@ function renderUnderstandTerminal(plan) {
|
|
|
9275
9437
|
|
|
9276
9438
|
// src/core/delivery.ts
|
|
9277
9439
|
import { parse as parseYaml10 } from "yaml";
|
|
9278
|
-
function
|
|
9440
|
+
function slugify3(s) {
|
|
9279
9441
|
return s.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
9280
9442
|
}
|
|
9281
9443
|
function toActive(a) {
|
|
9282
9444
|
const id = a.id || a.title || "WI";
|
|
9283
|
-
return { id, title: a.title || id, type: a.type, slug:
|
|
9445
|
+
return { id, title: a.title || id, type: a.type, slug: slugify3(a.title || id) };
|
|
9284
9446
|
}
|
|
9285
9447
|
function activeWorkItems(dir) {
|
|
9286
9448
|
return discoverWorkItems(dir).filter((a) => a.lifecycle === "in-progress").map(toActive);
|
|
@@ -9386,6 +9548,13 @@ function runUnderstand() {
|
|
|
9386
9548
|
for (const s of recSkills) console.log(` - ${s}`);
|
|
9387
9549
|
}
|
|
9388
9550
|
}
|
|
9551
|
+
const td = exp.techDecisions;
|
|
9552
|
+
if (td.candidates > 0 && td.adrs === 0) {
|
|
9553
|
+
console.log("");
|
|
9554
|
+
console.log(`Tech decisions: ${td.candidates} decision candidate(s) not yet materialized as ADRs.`);
|
|
9555
|
+
console.log(" \u2192 Use the adr-writing skill to create ADR drafts from `knowledge/tech/decision-candidates.md`");
|
|
9556
|
+
console.log(" into `knowledge/tech/decisions/` before implementing affected technical Work Items (`kaddo adr`).");
|
|
9557
|
+
}
|
|
9389
9558
|
if (exp.externalCapsules.length > 0) {
|
|
9390
9559
|
console.log("");
|
|
9391
9560
|
console.log("External knowledge:");
|
|
@@ -11900,7 +12069,7 @@ var MODULE_TYPES = [
|
|
|
11900
12069
|
"data",
|
|
11901
12070
|
"unknown"
|
|
11902
12071
|
];
|
|
11903
|
-
function
|
|
12072
|
+
function slugify4(name) {
|
|
11904
12073
|
return name.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
11905
12074
|
}
|
|
11906
12075
|
function readModulesDescriptor(dir) {
|
|
@@ -11920,7 +12089,7 @@ function moduleDir(id) {
|
|
|
11920
12089
|
return `knowledge/tech/modules/${id}`;
|
|
11921
12090
|
}
|
|
11922
12091
|
function buildModule(input) {
|
|
11923
|
-
const id =
|
|
12092
|
+
const id = slugify4(input.name);
|
|
11924
12093
|
const base = moduleDir(id);
|
|
11925
12094
|
return {
|
|
11926
12095
|
id,
|
|
@@ -12252,18 +12421,29 @@ _Document the product capabilities that should exist._
|
|
|
12252
12421
|
`,
|
|
12253
12422
|
"pre-ai": `# Existing Capabilities
|
|
12254
12423
|
|
|
12255
|
-
> Discover the capabilities the system already has (evidence-backed
|
|
12424
|
+
> Discover the capabilities the system already has, grouped by **functional domain** (not technical folders), evidence-backed. Use the capability-agent to fill this in \u2014 run \`kaddo add agents\`, then feed it the context pack.
|
|
12425
|
+
|
|
12426
|
+
## Capability Domains
|
|
12427
|
+
|
|
12428
|
+
### Domain: <Domain name>
|
|
12429
|
+
|
|
12430
|
+
**Purpose:** _What functional responsibility this domain covers._
|
|
12256
12431
|
|
|
12257
|
-
|
|
12432
|
+
**Evidence summary:**
|
|
12433
|
+
- _\`path\`, route, table or function._
|
|
12258
12434
|
|
|
12259
|
-
|
|
12435
|
+
#### Capability: <Capability name>
|
|
12260
12436
|
|
|
12261
12437
|
- Status: implemented | partial | inferred | risky | deprecated | unknown
|
|
12262
12438
|
- Capability type: business | product | technical | integration | operational
|
|
12263
12439
|
- User-facing: yes | no | internal
|
|
12264
12440
|
- Evidence:
|
|
12265
12441
|
- _\`path/to/file\`, route, table or function \u2014 or \`pending validation\`._
|
|
12266
|
-
- Related flows
|
|
12442
|
+
- Related flows:
|
|
12443
|
+
- _..._
|
|
12444
|
+
- Related data:
|
|
12445
|
+
- _..._
|
|
12446
|
+
- Related integrations:
|
|
12267
12447
|
- _..._
|
|
12268
12448
|
- Current behavior:
|
|
12269
12449
|
- _..._
|
|
@@ -12277,6 +12457,7 @@ _Document the product capabilities that should exist._
|
|
|
12277
12457
|
## Capability Gaps
|
|
12278
12458
|
|
|
12279
12459
|
- [gap] _Gap description._
|
|
12460
|
+
- Domain: _<Domain name>_
|
|
12280
12461
|
- Related capability: _<name>_
|
|
12281
12462
|
- Impact: low | medium | high
|
|
12282
12463
|
- Possible roadmap candidate: yes | no
|
|
@@ -12284,24 +12465,32 @@ _Document the product capabilities that should exist._
|
|
|
12284
12465
|
## Roadmap Candidate Signals
|
|
12285
12466
|
|
|
12286
12467
|
- [candidate] _Potential roadmap candidate._
|
|
12287
|
-
-
|
|
12468
|
+
- Domain: _<Domain name>_
|
|
12288
12469
|
- Related capability: _<name>_
|
|
12470
|
+
- Based on: partial capability | gap | risk | open question | business goal
|
|
12289
12471
|
`,
|
|
12290
12472
|
legacy: `# Legacy Capabilities
|
|
12291
12473
|
|
|
12292
|
-
> Discover existing capabilities plus
|
|
12474
|
+
> Discover existing capabilities grouped by **functional domain** (not technical folders), plus criticality, change risk and modernization signals. Use the capability-agent to fill this in.
|
|
12475
|
+
|
|
12476
|
+
## Capability Domains
|
|
12293
12477
|
|
|
12294
|
-
|
|
12478
|
+
### Domain: <Domain name>
|
|
12295
12479
|
|
|
12296
|
-
|
|
12480
|
+
**Purpose:** _What functional responsibility this domain covers._
|
|
12481
|
+
|
|
12482
|
+
**Criticality:** low | medium | high
|
|
12483
|
+
**Change risk:** low | medium | high
|
|
12484
|
+
**Operational dependency:** _..._
|
|
12485
|
+
|
|
12486
|
+
**Evidence summary:**
|
|
12487
|
+
- _\`path\`, route, table or function._
|
|
12488
|
+
|
|
12489
|
+
#### Capability: <Capability name>
|
|
12297
12490
|
|
|
12298
12491
|
- Status: implemented | partial | inferred | risky | deprecated | unknown
|
|
12299
12492
|
- Capability type: business | product | technical | integration | operational
|
|
12300
12493
|
- User-facing: yes | no | internal
|
|
12301
|
-
- Criticality: low | medium | high
|
|
12302
|
-
- Change risk: low | medium | high
|
|
12303
|
-
- Operational dependency:
|
|
12304
|
-
- _..._
|
|
12305
12494
|
- Evidence:
|
|
12306
12495
|
- _\`path/to/file\`, route, table or function \u2014 or \`pending validation\`._
|
|
12307
12496
|
- Current behavior:
|
|
@@ -12314,6 +12503,7 @@ _Document the product capabilities that should exist._
|
|
|
12314
12503
|
## Capability Gaps
|
|
12315
12504
|
|
|
12316
12505
|
- [gap] _Gap description._
|
|
12506
|
+
- Domain: _<Domain name>_
|
|
12317
12507
|
- Related capability: _<name>_
|
|
12318
12508
|
- Impact: low | medium | high
|
|
12319
12509
|
- Possible roadmap candidate: yes | no
|
|
@@ -12321,8 +12511,9 @@ _Document the product capabilities that should exist._
|
|
|
12321
12511
|
## Roadmap Candidate Signals
|
|
12322
12512
|
|
|
12323
12513
|
- [candidate] _Potential modernization or roadmap candidate._
|
|
12324
|
-
-
|
|
12514
|
+
- Domain: _<Domain name>_
|
|
12325
12515
|
- Related capability: _<name>_
|
|
12516
|
+
- Based on: partial capability | gap | risk | open question | business goal
|
|
12326
12517
|
`
|
|
12327
12518
|
},
|
|
12328
12519
|
codebase: {
|
|
@@ -13807,6 +13998,44 @@ function runAdaptersStatus(opts = {}) {
|
|
|
13807
13998
|
}
|
|
13808
13999
|
}
|
|
13809
14000
|
|
|
14001
|
+
// src/commands/adr.ts
|
|
14002
|
+
function runAdr(opts = {}) {
|
|
14003
|
+
const dir = cwd();
|
|
14004
|
+
requireConfig(dir);
|
|
14005
|
+
const td = buildTechDecisions(dir);
|
|
14006
|
+
if (opts.json) {
|
|
14007
|
+
console.log(JSON.stringify(td, null, 2));
|
|
14008
|
+
return;
|
|
14009
|
+
}
|
|
14010
|
+
console.log("");
|
|
14011
|
+
console.log("Tech Decisions");
|
|
14012
|
+
console.log(` Decision candidates: ${td.candidates}`);
|
|
14013
|
+
console.log(` ADRs: ${td.adrs} (draft: ${td.draft_adrs}, accepted: ${td.accepted_adrs})`);
|
|
14014
|
+
console.log(` Status: ${td.status}`);
|
|
14015
|
+
if (td.candidate_list.length > 0 && td.adrs === 0) {
|
|
14016
|
+
console.log("");
|
|
14017
|
+
console.log("ADR candidates found:");
|
|
14018
|
+
td.candidate_list.forEach((c, i) => {
|
|
14019
|
+
console.log("");
|
|
14020
|
+
console.log(`${i + 1}. ${c.title}`);
|
|
14021
|
+
console.log(` Source: ${c.source}`);
|
|
14022
|
+
console.log(` Suggested ADR: ${c.suggestedAdrFile}`);
|
|
14023
|
+
});
|
|
14024
|
+
console.log("");
|
|
14025
|
+
console.log("Next:");
|
|
14026
|
+
console.log(" Use the adr-writing skill to create ADR drafts from these candidates");
|
|
14027
|
+
console.log(" (copy context + options; leave the decision/consequences as [open] for human review).");
|
|
14028
|
+
} else if (td.candidates === 0) {
|
|
14029
|
+
console.log("");
|
|
14030
|
+
console.log("No decision candidates found. Run the architecture-agent to produce");
|
|
14031
|
+
console.log("`knowledge/tech/decision-candidates.md`, or add ADRs under `knowledge/tech/decisions/`.");
|
|
14032
|
+
} else {
|
|
14033
|
+
console.log("");
|
|
14034
|
+
console.log("ADRs already exist. Review drafts and mark them `accepted` when confirmed.");
|
|
14035
|
+
}
|
|
14036
|
+
printCommandFooter("adr");
|
|
14037
|
+
}
|
|
14038
|
+
|
|
13810
14039
|
// src/index.ts
|
|
13811
14040
|
var require2 = createRequire(import.meta.url);
|
|
13812
14041
|
var { version } = require2("../package.json");
|
|
@@ -13860,6 +14089,9 @@ program.command("drift").description("Drift Trend Report from recorded `kaddo gu
|
|
|
13860
14089
|
var questionsAction = (opts) => runQuestions(opts);
|
|
13861
14090
|
program.command("questions").description("Open-questions readiness gate: blocking/important/deferred decisions before the roadmap").option("--json", "Output JSON instead of a summary").option("--output <path>", "Write the report to a file (e.g. .kaddo/reports/questions-report.md)").action(questionsAction);
|
|
13862
14091
|
program.command("readiness").description("Alias for `kaddo questions`").option("--json", "Output JSON instead of a summary").option("--output <path>", "Write the report to a file").action(questionsAction);
|
|
14092
|
+
program.command("adr").alias("decisions").description("List technical decision candidates and the ADR files to create from them (read-only)").option("--json", "Output JSON").action((opts) => {
|
|
14093
|
+
runAdr(opts);
|
|
14094
|
+
});
|
|
13863
14095
|
var adaptersCmd = program.command("adapters").description("Generate adapters that project Kaddo knowledge for external coding agents");
|
|
13864
14096
|
adaptersCmd.command("install <adapter>").description("Generate an adapter file (codex/opencode/antigravity/kiro \u2192 AGENTS.md, claude \u2192 CLAUDE.md) from Kaddo knowledge").option("--force", "Overwrite an existing output file").option("--inject", "Add or update only the Kaddo block in an existing file, preserving the rest").option("--dry-run", "Print the content without writing files").action((adapter, opts) => {
|
|
13865
14097
|
runAdaptersInstall(adapter, opts);
|