@kaddo/cli 3.40.1 → 3.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/index.js +125 -21
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -539,6 +539,7 @@ create --from roadmap → owners → guard → explain`.
|
|
|
539
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
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 |
|
|
541
541
|
| v3.40.1 | ADR slug cleanup + MCP: suggested ADR filenames strip list/heading prefixes (no `ADR-001-1-…`) and normalize acronyms; new read-only MCP resource `kaddo://tech-decisions` sharing `buildTechDecisions` with `kaddo adr` |
|
|
542
|
+
| v3.41 | Tech knowledge structure: `knowledge/tech/discovery/` for architecture-notes/decision-candidates (core vs decisions vs discovery); `kaddo adr` reads discovery-first with legacy fallback; `kaddo tech organize` migrates safely; `explain` shows `## Tech Knowledge` |
|
|
542
543
|
|
|
543
544
|
**Optional modules (installed with `kaddo add`):**
|
|
544
545
|
|
package/dist/index.js
CHANGED
|
@@ -708,6 +708,10 @@ var COMMAND_HELP = {
|
|
|
708
708
|
adr: {
|
|
709
709
|
question: "Which technical decisions still need to become ADRs?",
|
|
710
710
|
next: "Use the adr-writing skill to draft ADRs, then mark them accepted when confirmed"
|
|
711
|
+
},
|
|
712
|
+
"tech organize": {
|
|
713
|
+
question: "Is knowledge/tech/ cleanly separated (core vs discovery vs decisions)?",
|
|
714
|
+
next: "Discovery notes now live under knowledge/tech/discovery/"
|
|
711
715
|
}
|
|
712
716
|
};
|
|
713
717
|
function commandFooterLines(name) {
|
|
@@ -2439,9 +2443,9 @@ Optionally provide: existing diagrams, infra config, README, dependency manifest
|
|
|
2439
2443
|
|
|
2440
2444
|
Markdown artifacts intended to be saved as:
|
|
2441
2445
|
|
|
2442
|
-
- \`knowledge/tech/current-state.md\`
|
|
2443
|
-
- \`knowledge/tech/architecture-notes.md\`
|
|
2444
|
-
- \`knowledge/tech/decision-candidates.md\`
|
|
2446
|
+
- \`knowledge/tech/current-state.md\` (core artifact)
|
|
2447
|
+
- \`knowledge/tech/discovery/architecture-notes.md\` (discovery note)
|
|
2448
|
+
- \`knowledge/tech/discovery/decision-candidates.md\` (discovery input for ADRs)
|
|
2445
2449
|
|
|
2446
2450
|
## Instructions
|
|
2447
2451
|
|
|
@@ -2487,10 +2491,12 @@ Generated from Kaddo Context Pack.
|
|
|
2487
2491
|
|
|
2488
2492
|
## Where to Save the Result
|
|
2489
2493
|
|
|
2490
|
-
Save the architecture overview as \`knowledge/tech/current-state.md
|
|
2491
|
-
\`knowledge/tech/architecture-notes.md
|
|
2492
|
-
\`knowledge/tech/decision-candidates.md
|
|
2493
|
-
\`knowledge/tech/
|
|
2494
|
+
Save the architecture overview as \`knowledge/tech/current-state.md\` (a **core** artifact). Save
|
|
2495
|
+
supporting notes as \`knowledge/tech/discovery/architecture-notes.md\` and decision candidates as
|
|
2496
|
+
\`knowledge/tech/discovery/decision-candidates.md\` \u2014 **discovery** inputs live under
|
|
2497
|
+
\`knowledge/tech/discovery/\`, not directly in \`knowledge/tech/\` (VS-075.2). Final ADRs always live
|
|
2498
|
+
under \`knowledge/tech/decisions/\`. Kaddo still reads the legacy root locations for backward
|
|
2499
|
+
compatibility, but new output should use \`discovery/\`.
|
|
2494
2500
|
|
|
2495
2501
|
## Quality Checklist
|
|
2496
2502
|
|
|
@@ -8123,8 +8129,16 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
8123
8129
|
}
|
|
8124
8130
|
|
|
8125
8131
|
// src/core/decisions.ts
|
|
8126
|
-
var
|
|
8132
|
+
var CANDIDATES_DISCOVERY = "knowledge/tech/discovery/decision-candidates.md";
|
|
8133
|
+
var CANDIDATES_LEGACY = "knowledge/tech/decision-candidates.md";
|
|
8127
8134
|
var DECISIONS_DIR = "knowledge/tech/decisions";
|
|
8135
|
+
function resolveCandidatesPath(dir) {
|
|
8136
|
+
const discovery = exists(join(dir, CANDIDATES_DISCOVERY));
|
|
8137
|
+
const legacy = exists(join(dir, CANDIDATES_LEGACY));
|
|
8138
|
+
if (discovery) return { path: CANDIDATES_DISCOVERY, legacy: false, bothExist: legacy };
|
|
8139
|
+
if (legacy) return { path: CANDIDATES_LEGACY, legacy: true, bothExist: false };
|
|
8140
|
+
return { path: null, legacy: false, bothExist: false };
|
|
8141
|
+
}
|
|
8128
8142
|
function cleanCandidateTitle(title) {
|
|
8129
8143
|
return title.replace(/^\s*#{1,6}\s+/, "").replace(/^\s*[-*]\s+/, "").replace(/^\s*\(?\d+\)?[.):]\s+/, "").trim();
|
|
8130
8144
|
}
|
|
@@ -8168,11 +8182,11 @@ function countAdrs(dir) {
|
|
|
8168
8182
|
return { total, draft, accepted };
|
|
8169
8183
|
}
|
|
8170
8184
|
function buildTechDecisions(dir) {
|
|
8171
|
-
const
|
|
8185
|
+
const resolved = resolveCandidatesPath(dir);
|
|
8172
8186
|
let titles = [];
|
|
8173
|
-
if (
|
|
8187
|
+
if (resolved.path) {
|
|
8174
8188
|
try {
|
|
8175
|
-
titles = parseDecisionCandidates(readFile(
|
|
8189
|
+
titles = parseDecisionCandidates(readFile(join(dir, resolved.path)));
|
|
8176
8190
|
} catch {
|
|
8177
8191
|
titles = [];
|
|
8178
8192
|
}
|
|
@@ -8180,7 +8194,7 @@ function buildTechDecisions(dir) {
|
|
|
8180
8194
|
const { total, draft, accepted } = countAdrs(dir);
|
|
8181
8195
|
const candidate_list = titles.map((title, i) => {
|
|
8182
8196
|
const n = String(total + i + 1).padStart(3, "0");
|
|
8183
|
-
return { title, source:
|
|
8197
|
+
return { title, source: resolved.path, suggestedAdrFile: `${DECISIONS_DIR}/ADR-${n}-${slugify2(title)}.md` };
|
|
8184
8198
|
});
|
|
8185
8199
|
let status;
|
|
8186
8200
|
if (accepted > 0) status = "accepted-adrs";
|
|
@@ -8193,7 +8207,10 @@ function buildTechDecisions(dir) {
|
|
|
8193
8207
|
adrs: total,
|
|
8194
8208
|
draft_adrs: draft,
|
|
8195
8209
|
accepted_adrs: accepted,
|
|
8196
|
-
candidate_list
|
|
8210
|
+
candidate_list,
|
|
8211
|
+
candidates_source: resolved.path,
|
|
8212
|
+
candidates_legacy_location: resolved.legacy,
|
|
8213
|
+
candidates_both_exist: resolved.bothExist
|
|
8197
8214
|
};
|
|
8198
8215
|
}
|
|
8199
8216
|
|
|
@@ -8409,7 +8426,18 @@ function buildProjectExplanation(dir) {
|
|
|
8409
8426
|
suggestedNextSteps,
|
|
8410
8427
|
readiness,
|
|
8411
8428
|
nextStepRecommendation: readiness.nextStepRecommendation,
|
|
8412
|
-
techDecisions: buildTechDecisions(dir)
|
|
8429
|
+
techDecisions: buildTechDecisions(dir),
|
|
8430
|
+
techKnowledge: {
|
|
8431
|
+
core: {
|
|
8432
|
+
currentState: exists(join(dir, "knowledge/tech/current-state.md")),
|
|
8433
|
+
codebase: exists(join(dir, "knowledge/tech/codebase.md"))
|
|
8434
|
+
},
|
|
8435
|
+
discovery: {
|
|
8436
|
+
architectureNotes: exists(join(dir, "knowledge/tech/discovery/architecture-notes.md")) || exists(join(dir, "knowledge/tech/architecture-notes.md")),
|
|
8437
|
+
decisionCandidates: exists(join(dir, "knowledge/tech/discovery/decision-candidates.md")) || exists(join(dir, "knowledge/tech/decision-candidates.md")),
|
|
8438
|
+
legacyLocation: exists(join(dir, "knowledge/tech/architecture-notes.md")) || exists(join(dir, "knowledge/tech/decision-candidates.md"))
|
|
8439
|
+
}
|
|
8440
|
+
}
|
|
8413
8441
|
};
|
|
8414
8442
|
}
|
|
8415
8443
|
function stateLabel(state) {
|
|
@@ -8624,15 +8652,26 @@ function renderExplanationHuman(exp) {
|
|
|
8624
8652
|
lines.push(r.recommended_next_step.label);
|
|
8625
8653
|
lines.push("");
|
|
8626
8654
|
const td = exp.techDecisions;
|
|
8627
|
-
|
|
8628
|
-
|
|
8629
|
-
lines.push(
|
|
8630
|
-
lines.push(
|
|
8655
|
+
const tk = exp.techKnowledge;
|
|
8656
|
+
const mark = (b) => b ? "\u2713" : "\u2717";
|
|
8657
|
+
lines.push("## Tech Knowledge");
|
|
8658
|
+
lines.push("Core:");
|
|
8659
|
+
lines.push(`- ${mark(tk.core.currentState)} current-state.md`);
|
|
8660
|
+
lines.push(`- ${mark(tk.core.codebase)} codebase.md`);
|
|
8661
|
+
lines.push("Decisions:");
|
|
8662
|
+
lines.push(`- ADRs: ${td.adrs} (draft: ${td.draft_adrs}, accepted: ${td.accepted_adrs}) \xB7 status: ${td.status}`);
|
|
8663
|
+
lines.push("Discovery:");
|
|
8664
|
+
lines.push(`- ${mark(tk.discovery.architectureNotes)} architecture-notes.md`);
|
|
8665
|
+
lines.push(`- ${mark(tk.discovery.decisionCandidates)} decision-candidates.md`);
|
|
8666
|
+
lines.push("");
|
|
8631
8667
|
if (td.candidates > 0 && td.adrs === 0) {
|
|
8632
|
-
lines.push("");
|
|
8633
8668
|
lines.push("Use the adr-writing skill to materialize decision candidates into ADRs (`kaddo adr`) before implementing related technical Work Items.");
|
|
8669
|
+
lines.push("");
|
|
8670
|
+
}
|
|
8671
|
+
if (tk.discovery.legacyLocation) {
|
|
8672
|
+
lines.push("Tech discovery files are in the legacy `knowledge/tech/` root. Suggested cleanup: run `kaddo tech organize`.");
|
|
8673
|
+
lines.push("");
|
|
8634
8674
|
}
|
|
8635
|
-
lines.push("");
|
|
8636
8675
|
return lines.join("\n").trimEnd() + "\n";
|
|
8637
8676
|
}
|
|
8638
8677
|
function renderExplanationAgent(exp) {
|
|
@@ -8981,6 +9020,22 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
8981
9020
|
if (techDecisions.candidates > 0 && techDecisions.adrs === 0) {
|
|
8982
9021
|
missing.push(`${techDecisions.candidates} technical decision candidate(s) not yet materialized as ADRs (run \`kaddo adr\`).`);
|
|
8983
9022
|
}
|
|
9023
|
+
const techFile = (rel) => exists(join(dir, ARCH_DIR6, rel));
|
|
9024
|
+
const techKnowledge = {
|
|
9025
|
+
core: {
|
|
9026
|
+
"current-state.md": techFile("tech/current-state.md"),
|
|
9027
|
+
"codebase.md": techFile("tech/codebase.md")
|
|
9028
|
+
},
|
|
9029
|
+
decisions: { adrs: techDecisions.adrs, dir: exists(join(dir, ARCH_DIR6, "tech/decisions")) },
|
|
9030
|
+
discovery: {
|
|
9031
|
+
"architecture-notes.md": techFile("tech/discovery/architecture-notes.md") || techFile("tech/architecture-notes.md"),
|
|
9032
|
+
"decision-candidates.md": techFile("tech/discovery/decision-candidates.md") || techFile("tech/decision-candidates.md"),
|
|
9033
|
+
legacyLocation: techFile("tech/architecture-notes.md") || techFile("tech/decision-candidates.md")
|
|
9034
|
+
}
|
|
9035
|
+
};
|
|
9036
|
+
if (techKnowledge.discovery.legacyLocation) {
|
|
9037
|
+
missing.push("Tech discovery files are in the legacy `knowledge/tech/` root. Run `kaddo tech organize` to move them to `knowledge/tech/discovery/`.");
|
|
9038
|
+
}
|
|
8984
9039
|
const unifiedPhase = {
|
|
8985
9040
|
...phase,
|
|
8986
9041
|
nextStep: nextStepRecommendation.label,
|
|
@@ -9019,6 +9074,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
9019
9074
|
phase: unifiedPhase,
|
|
9020
9075
|
nextStepRecommendation,
|
|
9021
9076
|
techDecisions,
|
|
9077
|
+
techKnowledge,
|
|
9022
9078
|
deliveryMix,
|
|
9023
9079
|
external: loadExternalCapsules(dir),
|
|
9024
9080
|
graph: loadGraphSummary(dir),
|
|
@@ -12725,7 +12781,7 @@ var FILE_TARGETS = [
|
|
|
12725
12781
|
{ path: "knowledge/tech/current-state.md", kind: "current-state" },
|
|
12726
12782
|
{ path: "knowledge/delivery/roadmap.md", kind: "roadmap" }
|
|
12727
12783
|
];
|
|
12728
|
-
var DIR_TARGETS = ["knowledge/tech/decisions", "knowledge/delivery/work-items"];
|
|
12784
|
+
var DIR_TARGETS = ["knowledge/tech/decisions", "knowledge/tech/discovery", "knowledge/delivery/work-items"];
|
|
12729
12785
|
function withLanguageDirective(content, language) {
|
|
12730
12786
|
if (language !== "es") return content;
|
|
12731
12787
|
const note = "> Idioma del proyecto: **espa\xF1ol**. Escribe este conocimiento en espa\xF1ol. Mant\xE9n en ingl\xE9s el c\xF3digo, los nombres de archivo, los comandos y las claves de configuraci\xF3n.\n";
|
|
@@ -14017,6 +14073,15 @@ function runAdr(opts = {}) {
|
|
|
14017
14073
|
console.log(` Decision candidates: ${td.candidates}`);
|
|
14018
14074
|
console.log(` ADRs: ${td.adrs} (draft: ${td.draft_adrs}, accepted: ${td.accepted_adrs})`);
|
|
14019
14075
|
console.log(` Status: ${td.status}`);
|
|
14076
|
+
if (td.candidates_source) console.log(` Source: ${td.candidates_source}`);
|
|
14077
|
+
if (td.candidates_both_exist) {
|
|
14078
|
+
console.log("");
|
|
14079
|
+
console.log(" Note: both decision-candidate files exist.");
|
|
14080
|
+
console.log(" Using: knowledge/tech/discovery/decision-candidates.md");
|
|
14081
|
+
console.log(" Legacy file also found: knowledge/tech/decision-candidates.md");
|
|
14082
|
+
} else if (td.candidates_legacy_location) {
|
|
14083
|
+
console.log(" (legacy location \u2014 consider `kaddo tech organize` to move it to knowledge/tech/discovery/)");
|
|
14084
|
+
}
|
|
14020
14085
|
if (td.candidate_list.length > 0 && td.adrs === 0) {
|
|
14021
14086
|
console.log("");
|
|
14022
14087
|
console.log("ADR candidates found:");
|
|
@@ -14041,6 +14106,41 @@ function runAdr(opts = {}) {
|
|
|
14041
14106
|
printCommandFooter("adr");
|
|
14042
14107
|
}
|
|
14043
14108
|
|
|
14109
|
+
// src/commands/tech.ts
|
|
14110
|
+
import fs3 from "fs";
|
|
14111
|
+
var DISCOVERY_FILES = ["architecture-notes.md", "decision-candidates.md"];
|
|
14112
|
+
var DISCOVERY_DIR = "knowledge/tech/discovery";
|
|
14113
|
+
function runTechOrganize(dir = cwd()) {
|
|
14114
|
+
requireConfig(dir);
|
|
14115
|
+
intro2("kaddo tech organize");
|
|
14116
|
+
const moved = [];
|
|
14117
|
+
const skipped = [];
|
|
14118
|
+
for (const file of DISCOVERY_FILES) {
|
|
14119
|
+
const from = join(dir, "knowledge/tech", file);
|
|
14120
|
+
const to = join(dir, DISCOVERY_DIR, file);
|
|
14121
|
+
if (!exists(from)) continue;
|
|
14122
|
+
if (exists(to)) {
|
|
14123
|
+
skipped.push(file);
|
|
14124
|
+
continue;
|
|
14125
|
+
}
|
|
14126
|
+
ensureDir(join(dir, DISCOVERY_DIR));
|
|
14127
|
+
fs3.renameSync(from, to);
|
|
14128
|
+
moved.push(`knowledge/tech/${file} \u2192 ${DISCOVERY_DIR}/${file}`);
|
|
14129
|
+
}
|
|
14130
|
+
if (moved.length > 0) {
|
|
14131
|
+
log2.success("Moved:");
|
|
14132
|
+
for (const m of moved) console.log(` - ${m}`);
|
|
14133
|
+
}
|
|
14134
|
+
for (const file of skipped) {
|
|
14135
|
+
log2.warn(`Cannot move ${file} because knowledge/tech/discovery/${file} already exists. Review both files manually.`);
|
|
14136
|
+
}
|
|
14137
|
+
if (moved.length === 0 && skipped.length === 0) {
|
|
14138
|
+
log2.info("Nothing to organize \u2014 no discovery files in the legacy `knowledge/tech/` root.");
|
|
14139
|
+
}
|
|
14140
|
+
printCommandFooter("tech organize");
|
|
14141
|
+
outro2("Tech knowledge organized.");
|
|
14142
|
+
}
|
|
14143
|
+
|
|
14044
14144
|
// src/index.ts
|
|
14045
14145
|
var require2 = createRequire(import.meta.url);
|
|
14046
14146
|
var { version } = require2("../package.json");
|
|
@@ -14094,6 +14194,10 @@ program.command("drift").description("Drift Trend Report from recorded `kaddo gu
|
|
|
14094
14194
|
var questionsAction = (opts) => runQuestions(opts);
|
|
14095
14195
|
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);
|
|
14096
14196
|
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);
|
|
14197
|
+
var techCmd = program.command("tech").description("Organize the knowledge/tech/ structure (core vs discovery vs decisions)");
|
|
14198
|
+
techCmd.command("organize").description("Move discovery artifacts into knowledge/tech/discovery/ (never overwrites, no content change)").action(() => {
|
|
14199
|
+
runTechOrganize();
|
|
14200
|
+
});
|
|
14097
14201
|
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) => {
|
|
14098
14202
|
runAdr(opts);
|
|
14099
14203
|
});
|