@kaddo/cli 3.35.0 → 3.37.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 +577 -71
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -531,6 +531,8 @@ create --from roadmap → owners → guard → explain`.
|
|
|
531
531
|
| v3.33 | Open questions resolution tracking: mark questions `[open]`/`[resolved]`/`[assumed]`/`[deferred]` (EN+ES); only `open` blocks readiness, so assumed/resolved/deferred decisions stop false blocks. `kaddo questions` shows status counts + `resolution_status` in JSON |
|
|
532
532
|
| v3.34 | Pre-AI onboarding: `kaddo onboarding` (alias `onboard`) / `kaddo report onboarding` — read-only diagnosis of an existing project's readiness (scan/understand/knowledge/questions/roadmap/work-items/adapters) with a single recommended next step; `--json` |
|
|
533
533
|
| v3.35 | Folded onboarding into `kaddo explain`: removed `kaddo onboarding`/`onboard`/`report onboarding`; project readiness + single recommended next step now live in `kaddo explain` (human `## Project Readiness` + `readiness` in agent JSON) |
|
|
534
|
+
| v3.36 | State-aware bootstrap: `kaddo bootstrap` creates the full knowledge baseline for any `project.state` (new/pre-ai/legacy) with state-specific templates — no more new-only warning; idempotent, never overwrites, ensures `tech/decisions/` and `delivery/work-items/` |
|
|
535
|
+
| v3.37 | Placeholder-aware readiness: knowledge files are classified missing/placeholder/weak/useful; a bootstrap file isn't treated as ready knowledge. Layers downgrade to Placeholder/Weak, a new Knowledge Refinement phase recommends the right agent, and `create --from roadmap` is never suggested with 0 candidates |
|
|
534
536
|
|
|
535
537
|
**Optional modules (installed with `kaddo add`):**
|
|
536
538
|
|
package/dist/index.js
CHANGED
|
@@ -6041,14 +6041,23 @@ import { parse as parseYaml9 } from "yaml";
|
|
|
6041
6041
|
function layer(layers, name) {
|
|
6042
6042
|
return layers.find((l) => l.layer === name)?.status ?? "Missing";
|
|
6043
6043
|
}
|
|
6044
|
+
var NOT_READY_LAYER = ["Missing", "Placeholder", "Weak"];
|
|
6044
6045
|
function baseComplete(layers) {
|
|
6045
6046
|
return layer(layers, "Business") !== "Missing" && layer(layers, "Product") !== "Missing" && layer(layers, "Tech") !== "Missing";
|
|
6046
6047
|
}
|
|
6048
|
+
function baseUseful(layers) {
|
|
6049
|
+
return ["Business", "Product", "Tech"].every((n) => !NOT_READY_LAYER.includes(layer(layers, n)));
|
|
6050
|
+
}
|
|
6051
|
+
function roadmapHasCandidates(roadmap) {
|
|
6052
|
+
return roadmap.candidates > 0 || roadmap.remaining > 0;
|
|
6053
|
+
}
|
|
6047
6054
|
function determinePhase(input) {
|
|
6048
6055
|
const { roadmap, workItems } = input;
|
|
6049
6056
|
const active = workItems.byState.draft + workItems.byState.ready + workItems.byState["in-progress"] + workItems.byState.blocked;
|
|
6050
6057
|
if (!baseComplete(input.layers)) return "Discovery";
|
|
6058
|
+
if (!baseUseful(input.layers)) return "Knowledge Refinement";
|
|
6051
6059
|
if (!roadmap.present) return "Planning";
|
|
6060
|
+
if (!roadmapHasCandidates(roadmap) && workItems.total === 0) return "Planning";
|
|
6052
6061
|
if (workItems.total === 0) return "Delivery Preparation";
|
|
6053
6062
|
if (active > 0) return "Active Delivery";
|
|
6054
6063
|
return "Maintenance";
|
|
@@ -6078,6 +6087,14 @@ function firstMissingLayerAgent(layers) {
|
|
|
6078
6087
|
return { agent: "capability-agent", step: "Use capability-agent to create knowledge/product/capabilities.md" };
|
|
6079
6088
|
return { agent: "architecture-agent", step: "Use architecture-agent to create knowledge/tech/current-state.md" };
|
|
6080
6089
|
}
|
|
6090
|
+
function firstUnrefinedLayerAgent(layers) {
|
|
6091
|
+
const isThin = (n) => NOT_READY_LAYER.includes(layer(layers, n));
|
|
6092
|
+
if (isThin("Business"))
|
|
6093
|
+
return { agent: "business-agent", step: "Use business-agent to complete knowledge/business/business.md" };
|
|
6094
|
+
if (isThin("Product"))
|
|
6095
|
+
return { agent: "capability-agent", step: "Use capability-agent to complete knowledge/product/capabilities.md" };
|
|
6096
|
+
return { agent: "architecture-agent", step: "Use architecture-agent to complete knowledge/tech/current-state.md" };
|
|
6097
|
+
}
|
|
6081
6098
|
function assessPhase(input) {
|
|
6082
6099
|
const phase = determinePhase(input);
|
|
6083
6100
|
const reasons = buildReasons(input);
|
|
@@ -6095,6 +6112,17 @@ function assessPhase(input) {
|
|
|
6095
6112
|
llmInstructions = [`Use the ${m.agent} to fill the missing base knowledge.`, "Do not write code."];
|
|
6096
6113
|
break;
|
|
6097
6114
|
}
|
|
6115
|
+
case "Knowledge Refinement": {
|
|
6116
|
+
const m = firstUnrefinedLayerAgent(input.layers);
|
|
6117
|
+
recommendedAgents2 = [m.agent];
|
|
6118
|
+
nextStep = m.step;
|
|
6119
|
+
llmInstructions = [
|
|
6120
|
+
"The baseline files exist but still look like bootstrap placeholders.",
|
|
6121
|
+
`Use the ${m.agent} to replace the placeholders with real, project-specific knowledge.`,
|
|
6122
|
+
"Do not write code."
|
|
6123
|
+
];
|
|
6124
|
+
break;
|
|
6125
|
+
}
|
|
6098
6126
|
case "Planning": {
|
|
6099
6127
|
recommendedAgents2 = ["roadmap-agent"];
|
|
6100
6128
|
nextStep = "Use roadmap-agent to create knowledge/delivery/roadmap.md";
|
|
@@ -6230,7 +6258,7 @@ ${items.map((i) => `- ${i}`).join("\n")}
|
|
|
6230
6258
|
`;
|
|
6231
6259
|
}
|
|
6232
6260
|
function renderCapsuleMarkdown(c) {
|
|
6233
|
-
const
|
|
6261
|
+
const fm2 = [
|
|
6234
6262
|
"---",
|
|
6235
6263
|
"type: knowledge-capsule",
|
|
6236
6264
|
`system: ${c.system}`,
|
|
@@ -6242,7 +6270,7 @@ function renderCapsuleMarkdown(c) {
|
|
|
6242
6270
|
"---"
|
|
6243
6271
|
].join("\n");
|
|
6244
6272
|
const parts = [
|
|
6245
|
-
|
|
6273
|
+
fm2,
|
|
6246
6274
|
"",
|
|
6247
6275
|
`# ${c.system} \u2014 Knowledge Capsule`,
|
|
6248
6276
|
"",
|
|
@@ -6723,9 +6751,9 @@ var QUALITY_NOTE = {
|
|
|
6723
6751
|
sparse: "The graph has many nodes but few meaningful edges.",
|
|
6724
6752
|
empty: "The graph has almost no relationships."
|
|
6725
6753
|
};
|
|
6726
|
-
function yamlBlock(
|
|
6754
|
+
function yamlBlock(fm2) {
|
|
6727
6755
|
const lines = ["```yaml"];
|
|
6728
|
-
for (const [k, vals] of Object.entries(
|
|
6756
|
+
for (const [k, vals] of Object.entries(fm2)) {
|
|
6729
6757
|
lines.push(`${k}:`);
|
|
6730
6758
|
for (const v of vals) lines.push(` - ${v}`);
|
|
6731
6759
|
}
|
|
@@ -6957,9 +6985,97 @@ function statusFor(layer2, a) {
|
|
|
6957
6985
|
return "Missing";
|
|
6958
6986
|
}
|
|
6959
6987
|
|
|
6988
|
+
// src/core/artifact-quality.ts
|
|
6989
|
+
function isPlaceholderLine(line) {
|
|
6990
|
+
const t = line.trim();
|
|
6991
|
+
if (/^_.+_$/.test(t)) return true;
|
|
6992
|
+
if (/^[-*]\s+(\[[^\]]+\]\s*)?_.+_$/.test(t)) return true;
|
|
6993
|
+
if (/^[-*]\s+\[[^\]]+\]\s*$/.test(t)) return true;
|
|
6994
|
+
if (/^_(?:Describe|List|Document|What|Which|Who|Use|To be defined|No production code)\b/i.test(t)) return true;
|
|
6995
|
+
return false;
|
|
6996
|
+
}
|
|
6997
|
+
function isStructuralLine(line, inFrontMatter) {
|
|
6998
|
+
const t = line.trim();
|
|
6999
|
+
if (inFrontMatter) return true;
|
|
7000
|
+
if (t === "") return true;
|
|
7001
|
+
if (/^#{1,6}\s/.test(t)) return true;
|
|
7002
|
+
if (/^<!--/.test(t)) return true;
|
|
7003
|
+
if (/^>/.test(t)) return true;
|
|
7004
|
+
return false;
|
|
7005
|
+
}
|
|
7006
|
+
function analyzeContent(md) {
|
|
7007
|
+
const lines = md.split(/\r?\n/);
|
|
7008
|
+
let inFrontMatter = false;
|
|
7009
|
+
let seenFmFence = 0;
|
|
7010
|
+
let currentSectionHasUseful = false;
|
|
7011
|
+
const sectionsWithUseful = /* @__PURE__ */ new Set();
|
|
7012
|
+
let sectionIndex = 0;
|
|
7013
|
+
const contentLines = [];
|
|
7014
|
+
const usefulLines = [];
|
|
7015
|
+
for (const raw of lines) {
|
|
7016
|
+
const t = raw.trim();
|
|
7017
|
+
if (t === "---" && seenFmFence < 2) {
|
|
7018
|
+
seenFmFence += 1;
|
|
7019
|
+
inFrontMatter = seenFmFence === 1;
|
|
7020
|
+
continue;
|
|
7021
|
+
}
|
|
7022
|
+
if (seenFmFence === 1) continue;
|
|
7023
|
+
if (/^#{1,6}\s/.test(t)) {
|
|
7024
|
+
sectionIndex += 1;
|
|
7025
|
+
currentSectionHasUseful = false;
|
|
7026
|
+
continue;
|
|
7027
|
+
}
|
|
7028
|
+
if (isStructuralLine(raw, false)) continue;
|
|
7029
|
+
contentLines.push(t);
|
|
7030
|
+
if (!isPlaceholderLine(raw)) {
|
|
7031
|
+
usefulLines.push(t);
|
|
7032
|
+
if (!currentSectionHasUseful) {
|
|
7033
|
+
currentSectionHasUseful = true;
|
|
7034
|
+
sectionsWithUseful.add(sectionIndex);
|
|
7035
|
+
}
|
|
7036
|
+
}
|
|
7037
|
+
}
|
|
7038
|
+
if (usefulLines.length === 0) return "placeholder";
|
|
7039
|
+
const usefulWordCount = usefulLines.join(" ").split(/\s+/).filter(Boolean).length;
|
|
7040
|
+
const placeholderRatio = contentLines.length > 0 ? (contentLines.length - usefulLines.length) / contentLines.length : 1;
|
|
7041
|
+
if (usefulWordCount >= 80 && placeholderRatio < 0.25 && sectionsWithUseful.size >= 2) return "useful";
|
|
7042
|
+
return "weak";
|
|
7043
|
+
}
|
|
7044
|
+
function analyzeKnowledgeArtifact(dir, rel) {
|
|
7045
|
+
const p2 = join(dir, rel);
|
|
7046
|
+
if (!exists(p2)) return "missing";
|
|
7047
|
+
try {
|
|
7048
|
+
return analyzeContent(readFile(p2));
|
|
7049
|
+
} catch {
|
|
7050
|
+
return "missing";
|
|
7051
|
+
}
|
|
7052
|
+
}
|
|
7053
|
+
|
|
6960
7054
|
// src/core/layers.ts
|
|
7055
|
+
var LAYER_BASELINE = {
|
|
7056
|
+
Business: ["knowledge/business/business.md"],
|
|
7057
|
+
Product: ["knowledge/product/product.md", "knowledge/product/capabilities.md"],
|
|
7058
|
+
Tech: ["knowledge/tech/codebase.md", "knowledge/tech/current-state.md"],
|
|
7059
|
+
Delivery: ["knowledge/delivery/roadmap.md"]
|
|
7060
|
+
};
|
|
7061
|
+
function layerQuality(dir, layer2) {
|
|
7062
|
+
const order = ["missing", "placeholder", "weak", "useful"];
|
|
7063
|
+
let worst = null;
|
|
7064
|
+
for (const rel of LAYER_BASELINE[layer2]) {
|
|
7065
|
+
const q = analyzeKnowledgeArtifact(dir, rel);
|
|
7066
|
+
if (q === "missing") continue;
|
|
7067
|
+
if (worst === null || order.indexOf(q) < order.indexOf(worst)) worst = q;
|
|
7068
|
+
}
|
|
7069
|
+
return worst;
|
|
7070
|
+
}
|
|
6961
7071
|
function knowledgeLayers(dir) {
|
|
6962
|
-
return discoverLayers(dir)
|
|
7072
|
+
return discoverLayers(dir).map((l) => {
|
|
7073
|
+
if (l.status !== "Consolidated" && l.status !== "Structured") return l;
|
|
7074
|
+
const q = layerQuality(dir, l.layer);
|
|
7075
|
+
if (q === "placeholder") return { ...l, status: "Placeholder" };
|
|
7076
|
+
if (q === "weak") return { ...l, status: "Weak" };
|
|
7077
|
+
return l;
|
|
7078
|
+
});
|
|
6963
7079
|
}
|
|
6964
7080
|
function renderLayersMarkdown(layers) {
|
|
6965
7081
|
const lines = [];
|
|
@@ -7631,24 +7747,12 @@ function buildSharedFileStatuses(statuses) {
|
|
|
7631
7747
|
|
|
7632
7748
|
// src/core/readiness.ts
|
|
7633
7749
|
var KNOWLEDGE_FILES = [
|
|
7634
|
-
{ key: "current_state", path: "knowledge/tech/current-state.md", label: "knowledge/tech/current-state.md" },
|
|
7635
|
-
{ key: "codebase", path: "knowledge/tech/codebase.md", label: "knowledge/tech/codebase.md" },
|
|
7636
|
-
{ key: "capabilities", path: "knowledge/product/capabilities.md", label: "knowledge/product/capabilities.md" },
|
|
7637
|
-
{ key: "product", path: "knowledge/product/product.md", label: "knowledge/product/product.md" },
|
|
7638
|
-
{ key: "business", path: "knowledge/business/business.md", label: "knowledge/business/business.md" }
|
|
7750
|
+
{ key: "current_state", path: "knowledge/tech/current-state.md", label: "knowledge/tech/current-state.md", agent: "architecture-agent" },
|
|
7751
|
+
{ key: "codebase", path: "knowledge/tech/codebase.md", label: "knowledge/tech/codebase.md", agent: "codebase-agent" },
|
|
7752
|
+
{ key: "capabilities", path: "knowledge/product/capabilities.md", label: "knowledge/product/capabilities.md", agent: "capability-agent" },
|
|
7753
|
+
{ key: "product", path: "knowledge/product/product.md", label: "knowledge/product/product.md", agent: "product-agent" },
|
|
7754
|
+
{ key: "business", path: "knowledge/business/business.md", label: "knowledge/business/business.md", agent: "business-agent" }
|
|
7639
7755
|
];
|
|
7640
|
-
function knowledgePresence(dir, rel) {
|
|
7641
|
-
const p2 = join(dir, rel);
|
|
7642
|
-
if (!exists(p2)) return "missing";
|
|
7643
|
-
let md;
|
|
7644
|
-
try {
|
|
7645
|
-
md = readFile(p2);
|
|
7646
|
-
} catch {
|
|
7647
|
-
return "missing";
|
|
7648
|
-
}
|
|
7649
|
-
const body = md.replace(/^---[\s\S]*?---/m, "").split(/\r?\n/).filter((l) => !/^\s*#{1,6}\s/.test(l) && !/^\s*$/.test(l) && !/^\s*<!--/.test(l)).join(" ").trim();
|
|
7650
|
-
return body.length >= 40 ? "present" : "weak";
|
|
7651
|
-
}
|
|
7652
7756
|
function roadmapSignal(dir) {
|
|
7653
7757
|
const p2 = join(dir, "knowledge/delivery/roadmap.md");
|
|
7654
7758
|
if (!exists(p2)) return "missing";
|
|
@@ -7711,7 +7815,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
7711
7815
|
if (config.project.state === "legacy") return stub("legacy-project", "Use the legacy project flow.");
|
|
7712
7816
|
const scan2 = exists(join(dir, ".kaddo", "scan.json")) ? "available" : "missing";
|
|
7713
7817
|
const understand = exists(join(dir, ".kaddo", "understand.md")) ? "available" : "missing";
|
|
7714
|
-
const presence = Object.fromEntries(KNOWLEDGE_FILES.map((f) => [f.key,
|
|
7818
|
+
const presence = Object.fromEntries(KNOWLEDGE_FILES.map((f) => [f.key, analyzeKnowledgeArtifact(dir, f.path)]));
|
|
7715
7819
|
const ctx = buildCodexAdapterContext(dir);
|
|
7716
7820
|
const agents = ctx.hasAgents ? "present" : "missing";
|
|
7717
7821
|
const skills = ctx.hasSkills ? "present" : "missing";
|
|
@@ -7741,7 +7845,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
7741
7845
|
};
|
|
7742
7846
|
let overall;
|
|
7743
7847
|
let next;
|
|
7744
|
-
const firstWeak = KNOWLEDGE_FILES.find((f) => presence[f.key] !== "
|
|
7848
|
+
const firstWeak = KNOWLEDGE_FILES.find((f) => presence[f.key] !== "useful");
|
|
7745
7849
|
if (scan2 === "missing") {
|
|
7746
7850
|
overall = "initialized";
|
|
7747
7851
|
next = { label: "Run `kaddo scan` to capture deterministic signals from the existing code.", command: "kaddo scan" };
|
|
@@ -7759,7 +7863,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
7759
7863
|
next = { label: "Run `kaddo understand` to summarize the project context.", command: "kaddo understand" };
|
|
7760
7864
|
} else if (firstWeak) {
|
|
7761
7865
|
overall = "knowledge-incomplete";
|
|
7762
|
-
next = { label: `
|
|
7866
|
+
next = { label: `Use ${firstWeak.agent} to complete \`${firstWeak.label}\` (it is ${presence[firstWeak.key]}).` };
|
|
7763
7867
|
} else if (oq.summary.blocking_open > 0) {
|
|
7764
7868
|
overall = "needs-decisions";
|
|
7765
7869
|
next = { label: "Resolve, assume or defer the blocking open questions (`kaddo questions`).", command: "kaddo questions" };
|
|
@@ -8183,6 +8287,9 @@ function renderExplanationHuman(exp) {
|
|
|
8183
8287
|
lines.push(`- understand: ${s.understand}`);
|
|
8184
8288
|
lines.push(`- agents: ${s.agents}`);
|
|
8185
8289
|
lines.push(`- skills: ${s.skills}`);
|
|
8290
|
+
lines.push(`- business: ${s.business}`);
|
|
8291
|
+
lines.push(`- product: ${s.product}`);
|
|
8292
|
+
lines.push(`- capabilities: ${s.capabilities}`);
|
|
8186
8293
|
lines.push(`- current-state: ${s.current_state}`);
|
|
8187
8294
|
lines.push(`- codebase: ${s.codebase}`);
|
|
8188
8295
|
lines.push(`- capabilities: ${s.capabilities}`);
|
|
@@ -8240,9 +8347,9 @@ function readConfig(dir) {
|
|
|
8240
8347
|
}
|
|
8241
8348
|
function filterBySince(artifacts, since) {
|
|
8242
8349
|
return artifacts.filter((a) => {
|
|
8243
|
-
const
|
|
8244
|
-
if (!
|
|
8245
|
-
return
|
|
8350
|
+
const fm2 = a;
|
|
8351
|
+
if (!fm2.created_at) return true;
|
|
8352
|
+
return fm2.created_at >= since;
|
|
8246
8353
|
});
|
|
8247
8354
|
}
|
|
8248
8355
|
function filterByScope(artifacts, scope) {
|
|
@@ -8522,6 +8629,24 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
8522
8629
|
}
|
|
8523
8630
|
const mappedModules = loadMappedModules(dir);
|
|
8524
8631
|
const layers = knowledgeLayers(dir);
|
|
8632
|
+
const qa = (rel) => analyzeKnowledgeArtifact(dir, rel);
|
|
8633
|
+
const qBusiness = qa("knowledge/business/business.md");
|
|
8634
|
+
const qProduct = qa("knowledge/product/product.md");
|
|
8635
|
+
const qCapabilities = qa("knowledge/product/capabilities.md");
|
|
8636
|
+
const qCodebase = qa("knowledge/tech/codebase.md");
|
|
8637
|
+
const qCurrentState = qa("knowledge/tech/current-state.md");
|
|
8638
|
+
const qRoadmap = qa("knowledge/delivery/roadmap.md");
|
|
8639
|
+
const layerStatusOf = (name) => layers.find((l) => l.layer === name)?.status ?? "Missing";
|
|
8640
|
+
const knowledgeQuality = {
|
|
8641
|
+
business: { status: layerStatusOf("Business"), artifacts: { "knowledge/business/business.md": qBusiness } },
|
|
8642
|
+
product: { status: layerStatusOf("Product"), artifacts: { "knowledge/product/product.md": qProduct, "knowledge/product/capabilities.md": qCapabilities } },
|
|
8643
|
+
tech: { status: layerStatusOf("Tech"), artifacts: { "knowledge/tech/codebase.md": qCodebase, "knowledge/tech/current-state.md": qCurrentState } },
|
|
8644
|
+
delivery: { status: layerStatusOf("Delivery"), artifacts: { "knowledge/delivery/roadmap.md": qRoadmap } }
|
|
8645
|
+
};
|
|
8646
|
+
if (qBusiness === "placeholder") missing.push("Business context exists but still looks like a bootstrap placeholder.");
|
|
8647
|
+
if (qProduct === "placeholder" || qCapabilities === "placeholder") missing.push("Product capabilities exist but still look like a bootstrap placeholder.");
|
|
8648
|
+
if (qCurrentState === "placeholder") missing.push("Current state exists but still looks like a bootstrap placeholder.");
|
|
8649
|
+
if (qCodebase === "placeholder") missing.push("Codebase map exists but still looks like a bootstrap placeholder.");
|
|
8525
8650
|
const allWorkItems = allArtifacts.filter((a) => a.isWorkItem);
|
|
8526
8651
|
const wiWithOwnership = allWorkItems.filter((a) => a.codeGlobs.length > 0).length;
|
|
8527
8652
|
const phase = assessPhase({
|
|
@@ -8572,6 +8697,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
8572
8697
|
artifacts: allArtifacts.filter((a) => a.codeGlobs.length > 0).map(toContextArtifact)
|
|
8573
8698
|
},
|
|
8574
8699
|
layers,
|
|
8700
|
+
knowledgeQuality,
|
|
8575
8701
|
roadmap,
|
|
8576
8702
|
phase,
|
|
8577
8703
|
deliveryMix,
|
|
@@ -9102,6 +9228,12 @@ function runUnderstand() {
|
|
|
9102
9228
|
if (assessment.nextStep) {
|
|
9103
9229
|
console.log(`Next step: ${assessment.nextStep}`);
|
|
9104
9230
|
}
|
|
9231
|
+
const readiness = exp.readiness;
|
|
9232
|
+
if (readiness.overall === "initialized" || readiness.overall === "bootstrap-incomplete") {
|
|
9233
|
+
console.log("");
|
|
9234
|
+
console.log(`Project readiness: ${readiness.overall}.`);
|
|
9235
|
+
console.log(` \u2192 ${readiness.recommended_next_step.label}`);
|
|
9236
|
+
}
|
|
9105
9237
|
const installedSkills = discoverInstalledSkills(dir);
|
|
9106
9238
|
if (installedSkills.length > 0 && assessment.recommendedAgents.length > 0) {
|
|
9107
9239
|
const recSkills = skillsForAgents(installedSkills, assessment.recommendedAgents);
|
|
@@ -11835,48 +11967,431 @@ function runModulesList(dir = cwd()) {
|
|
|
11835
11967
|
console.log("");
|
|
11836
11968
|
}
|
|
11837
11969
|
|
|
11970
|
+
// src/core/bootstrap-templates.ts
|
|
11971
|
+
function fm(type, state) {
|
|
11972
|
+
return `---
|
|
11973
|
+
type: ${type}
|
|
11974
|
+
project_state: ${state}
|
|
11975
|
+
generated_by: kaddo-bootstrap
|
|
11976
|
+
template_version: 1
|
|
11977
|
+
---
|
|
11978
|
+
|
|
11979
|
+
`;
|
|
11980
|
+
}
|
|
11981
|
+
var T = {
|
|
11982
|
+
business: {
|
|
11983
|
+
new: `# Business Context
|
|
11984
|
+
|
|
11985
|
+
## Problem
|
|
11986
|
+
|
|
11987
|
+
_What problem are we solving?_
|
|
11988
|
+
|
|
11989
|
+
## Users
|
|
11990
|
+
|
|
11991
|
+
_Who will use this product?_
|
|
11992
|
+
|
|
11993
|
+
## Business goals
|
|
11994
|
+
|
|
11995
|
+
_What outcomes matter?_
|
|
11996
|
+
|
|
11997
|
+
## Constraints
|
|
11998
|
+
|
|
11999
|
+
_Business, operational or regulatory constraints._
|
|
12000
|
+
`,
|
|
12001
|
+
"pre-ai": `# Business Context
|
|
12002
|
+
|
|
12003
|
+
## What this product appears to support
|
|
12004
|
+
|
|
12005
|
+
_Describe the business purpose based on confirmed knowledge._
|
|
12006
|
+
|
|
12007
|
+
## Users or roles
|
|
12008
|
+
|
|
12009
|
+
_List known users or roles. Mark unknowns explicitly._
|
|
12010
|
+
|
|
12011
|
+
## Existing business rules
|
|
12012
|
+
|
|
12013
|
+
_Document confirmed business rules._
|
|
12014
|
+
|
|
12015
|
+
## Open questions
|
|
12016
|
+
|
|
12017
|
+
- [open] _What business context still needs confirmation?_
|
|
12018
|
+
`,
|
|
12019
|
+
legacy: `# Business Context
|
|
12020
|
+
|
|
12021
|
+
## Critical business purpose
|
|
12022
|
+
|
|
12023
|
+
_What critical business process does this system support?_
|
|
12024
|
+
|
|
12025
|
+
## Users and operational dependency
|
|
12026
|
+
|
|
12027
|
+
_Who depends on this system?_
|
|
12028
|
+
|
|
12029
|
+
## Business continuity constraints
|
|
12030
|
+
|
|
12031
|
+
_What cannot be interrupted?_
|
|
12032
|
+
|
|
12033
|
+
## Open questions
|
|
12034
|
+
|
|
12035
|
+
- [open] _What business risk still needs confirmation?_
|
|
12036
|
+
`
|
|
12037
|
+
},
|
|
12038
|
+
product: {
|
|
12039
|
+
new: `# Product Context
|
|
12040
|
+
|
|
12041
|
+
## Product vision
|
|
12042
|
+
|
|
12043
|
+
_What are we building?_
|
|
12044
|
+
|
|
12045
|
+
## User journeys
|
|
12046
|
+
|
|
12047
|
+
_Main user journeys._
|
|
12048
|
+
|
|
12049
|
+
## Scope
|
|
12050
|
+
|
|
12051
|
+
_What is in scope and out of scope?_
|
|
12052
|
+
|
|
12053
|
+
## Success criteria
|
|
12054
|
+
|
|
12055
|
+
_How will we know this product is working?_
|
|
12056
|
+
`,
|
|
12057
|
+
"pre-ai": `# Product Context
|
|
12058
|
+
|
|
12059
|
+
## Existing product behavior
|
|
12060
|
+
|
|
12061
|
+
_Describe what the product currently does._
|
|
12062
|
+
|
|
12063
|
+
## Main flows
|
|
12064
|
+
|
|
12065
|
+
_List confirmed user or system flows._
|
|
12066
|
+
|
|
12067
|
+
## Inferred or uncertain behavior
|
|
12068
|
+
|
|
12069
|
+
_Document uncertain behavior as assumptions, not facts._
|
|
12070
|
+
|
|
12071
|
+
## Open questions
|
|
12072
|
+
|
|
12073
|
+
- [open] _What product behavior still needs confirmation?_
|
|
12074
|
+
`,
|
|
12075
|
+
legacy: `# Product Context
|
|
12076
|
+
|
|
12077
|
+
## Existing behavior
|
|
12078
|
+
|
|
12079
|
+
_What does the legacy system do today?_
|
|
12080
|
+
|
|
12081
|
+
## Critical flows
|
|
12082
|
+
|
|
12083
|
+
_Which flows are business-critical?_
|
|
12084
|
+
|
|
12085
|
+
## Known pain points
|
|
12086
|
+
|
|
12087
|
+
_What problems are known?_
|
|
12088
|
+
|
|
12089
|
+
## Out of scope
|
|
12090
|
+
|
|
12091
|
+
_What should not be changed yet?_
|
|
12092
|
+
`
|
|
12093
|
+
},
|
|
12094
|
+
capabilities: {
|
|
12095
|
+
new: `# Capabilities
|
|
12096
|
+
|
|
12097
|
+
## Planned capabilities
|
|
12098
|
+
|
|
12099
|
+
- [planned] _Capability name_
|
|
12100
|
+
|
|
12101
|
+
## Capability map
|
|
12102
|
+
|
|
12103
|
+
_Document the product capabilities that should exist._
|
|
12104
|
+
|
|
12105
|
+
## Open questions
|
|
12106
|
+
|
|
12107
|
+
- [open] _What capability decisions are still unclear?_
|
|
12108
|
+
`,
|
|
12109
|
+
"pre-ai": `# Existing Capabilities
|
|
12110
|
+
|
|
12111
|
+
## Observed capabilities
|
|
12112
|
+
|
|
12113
|
+
- [observed] _Capability observed in the existing system._
|
|
12114
|
+
|
|
12115
|
+
## Partial capabilities
|
|
12116
|
+
|
|
12117
|
+
- [partial] _Capability that appears incomplete or uncertain._
|
|
12118
|
+
|
|
12119
|
+
## Assumptions
|
|
12120
|
+
|
|
12121
|
+
- [assumed] _Safe assumption to confirm later._
|
|
12122
|
+
|
|
12123
|
+
## Open questions
|
|
12124
|
+
|
|
12125
|
+
- [open] _What capability is unclear?_
|
|
12126
|
+
`,
|
|
12127
|
+
legacy: `# Legacy Capabilities
|
|
12128
|
+
|
|
12129
|
+
## Critical capabilities
|
|
12130
|
+
|
|
12131
|
+
- [critical] _Capability that must keep working._
|
|
12132
|
+
|
|
12133
|
+
## Risky capabilities
|
|
12134
|
+
|
|
12135
|
+
- [risky] _Capability that is hard to change or poorly understood._
|
|
12136
|
+
|
|
12137
|
+
## Replacement candidates
|
|
12138
|
+
|
|
12139
|
+
- [candidate] _Capability that may be modernized later._
|
|
12140
|
+
|
|
12141
|
+
## Open questions
|
|
12142
|
+
|
|
12143
|
+
- [open] _What capability risk is unclear?_
|
|
12144
|
+
`
|
|
12145
|
+
},
|
|
12146
|
+
codebase: {
|
|
12147
|
+
new: `# Codebase Map
|
|
12148
|
+
|
|
12149
|
+
## Repository structure
|
|
12150
|
+
|
|
12151
|
+
_No production code yet. Describe the intended structure as it emerges._
|
|
12152
|
+
|
|
12153
|
+
## Entry points
|
|
12154
|
+
|
|
12155
|
+
_To be defined._
|
|
12156
|
+
|
|
12157
|
+
## How to run
|
|
12158
|
+
|
|
12159
|
+
_To be defined._
|
|
12160
|
+
|
|
12161
|
+
## How to test
|
|
12162
|
+
|
|
12163
|
+
_To be defined._
|
|
12164
|
+
|
|
12165
|
+
## Open questions
|
|
12166
|
+
|
|
12167
|
+
- [open] _What structural decisions are still open?_
|
|
12168
|
+
`,
|
|
12169
|
+
"pre-ai": `# Codebase Map
|
|
12170
|
+
|
|
12171
|
+
## Repository structure
|
|
12172
|
+
|
|
12173
|
+
_Describe the main folders and their purpose._
|
|
12174
|
+
|
|
12175
|
+
## Entry points
|
|
12176
|
+
|
|
12177
|
+
_List known entry points._
|
|
12178
|
+
|
|
12179
|
+
## Important modules
|
|
12180
|
+
|
|
12181
|
+
_List modules or areas that appear important._
|
|
12182
|
+
|
|
12183
|
+
## How to run
|
|
12184
|
+
|
|
12185
|
+
_Document commands to run the project._
|
|
12186
|
+
|
|
12187
|
+
## How to test
|
|
12188
|
+
|
|
12189
|
+
_Document how this project is tested. If unknown, mark as open._
|
|
12190
|
+
|
|
12191
|
+
## Open questions
|
|
12192
|
+
|
|
12193
|
+
- [open] _What part of the codebase still needs explanation?_
|
|
12194
|
+
`,
|
|
12195
|
+
legacy: `# Codebase Map
|
|
12196
|
+
|
|
12197
|
+
## Repository structure
|
|
12198
|
+
|
|
12199
|
+
_Describe the main folders and their purpose._
|
|
12200
|
+
|
|
12201
|
+
## Entry points
|
|
12202
|
+
|
|
12203
|
+
_List known entry points._
|
|
12204
|
+
|
|
12205
|
+
## Fragile / delicate areas
|
|
12206
|
+
|
|
12207
|
+
_List modules that are risky to change._
|
|
12208
|
+
|
|
12209
|
+
## How to run
|
|
12210
|
+
|
|
12211
|
+
_Document commands to run the project._
|
|
12212
|
+
|
|
12213
|
+
## How to test
|
|
12214
|
+
|
|
12215
|
+
_Document how this project is tested. If unknown, mark as open._
|
|
12216
|
+
|
|
12217
|
+
## Open questions
|
|
12218
|
+
|
|
12219
|
+
- [open] _What part of the codebase still needs explanation?_
|
|
12220
|
+
`
|
|
12221
|
+
},
|
|
12222
|
+
"current-state": {
|
|
12223
|
+
new: `# Current State
|
|
12224
|
+
|
|
12225
|
+
## Initial technical direction
|
|
12226
|
+
|
|
12227
|
+
_What technical direction has been decided?_
|
|
12228
|
+
|
|
12229
|
+
## Known constraints
|
|
12230
|
+
|
|
12231
|
+
_What constraints shape implementation?_
|
|
12232
|
+
|
|
12233
|
+
## Unknowns
|
|
12234
|
+
|
|
12235
|
+
- [open] _What technical questions remain open?_
|
|
12236
|
+
`,
|
|
12237
|
+
"pre-ai": `# Current State
|
|
12238
|
+
|
|
12239
|
+
## What exists today
|
|
12240
|
+
|
|
12241
|
+
_Describe the confirmed current state of the system._
|
|
12242
|
+
|
|
12243
|
+
## Observed technical signals
|
|
12244
|
+
|
|
12245
|
+
_Use \`kaddo scan\` output to document language, framework, package manager, source directories and infrastructure._
|
|
12246
|
+
|
|
12247
|
+
## Inferred architecture
|
|
12248
|
+
|
|
12249
|
+
_Document inferred architecture carefully. Mark uncertainty._
|
|
12250
|
+
|
|
12251
|
+
## Known constraints
|
|
12252
|
+
|
|
12253
|
+
_List technical, operational, business or infrastructure constraints._
|
|
12254
|
+
|
|
12255
|
+
## Risks of interpretation
|
|
12256
|
+
|
|
12257
|
+
_What could an agent misunderstand?_
|
|
12258
|
+
|
|
12259
|
+
## Open questions
|
|
12260
|
+
|
|
12261
|
+
- [open] _What technical decisions still need confirmation?_
|
|
12262
|
+
`,
|
|
12263
|
+
legacy: `# Legacy Current State
|
|
12264
|
+
|
|
12265
|
+
## Current architecture
|
|
12266
|
+
|
|
12267
|
+
_Describe the existing architecture._
|
|
12268
|
+
|
|
12269
|
+
## Critical dependencies
|
|
12270
|
+
|
|
12271
|
+
_List systems, databases, integrations or manual operations this system depends on._
|
|
12272
|
+
|
|
12273
|
+
## Known risks
|
|
12274
|
+
|
|
12275
|
+
_List known technical or operational risks._
|
|
12276
|
+
|
|
12277
|
+
## Change constraints
|
|
12278
|
+
|
|
12279
|
+
_What should not be changed without validation?_
|
|
12280
|
+
|
|
12281
|
+
## Modernization notes
|
|
12282
|
+
|
|
12283
|
+
_Initial notes about possible modernization paths._
|
|
12284
|
+
|
|
12285
|
+
## Open questions
|
|
12286
|
+
|
|
12287
|
+
- [open] _What legacy risk still needs confirmation?_
|
|
12288
|
+
`
|
|
12289
|
+
},
|
|
12290
|
+
roadmap: {
|
|
12291
|
+
new: `# Roadmap
|
|
12292
|
+
|
|
12293
|
+
## Now
|
|
12294
|
+
|
|
12295
|
+
_First outcomes to pursue._
|
|
12296
|
+
|
|
12297
|
+
## Next
|
|
12298
|
+
|
|
12299
|
+
_What comes after._
|
|
12300
|
+
|
|
12301
|
+
## Later
|
|
12302
|
+
|
|
12303
|
+
_Deferred ideas._
|
|
12304
|
+
`,
|
|
12305
|
+
"pre-ai": `# Roadmap
|
|
12306
|
+
|
|
12307
|
+
## Now
|
|
12308
|
+
|
|
12309
|
+
_First outcomes to pursue for this existing project._
|
|
12310
|
+
|
|
12311
|
+
## Next
|
|
12312
|
+
|
|
12313
|
+
_What comes after._
|
|
12314
|
+
|
|
12315
|
+
## Later
|
|
12316
|
+
|
|
12317
|
+
_Deferred ideas._
|
|
12318
|
+
`,
|
|
12319
|
+
legacy: `# Modernization Roadmap
|
|
12320
|
+
|
|
12321
|
+
## Stabilize
|
|
12322
|
+
|
|
12323
|
+
_What must be made safe first._
|
|
12324
|
+
|
|
12325
|
+
## Modernize
|
|
12326
|
+
|
|
12327
|
+
_Controlled modernization steps._
|
|
12328
|
+
|
|
12329
|
+
## Later
|
|
12330
|
+
|
|
12331
|
+
_Deferred modernization ideas._
|
|
12332
|
+
`
|
|
12333
|
+
}
|
|
12334
|
+
};
|
|
12335
|
+
function baselineTemplate(kind, state) {
|
|
12336
|
+
const st = state === "pre-ai" || state === "legacy" ? state : "new";
|
|
12337
|
+
return fm(kind, st) + T[kind][st];
|
|
12338
|
+
}
|
|
12339
|
+
|
|
11838
12340
|
// src/commands/bootstrap.ts
|
|
11839
12341
|
var CONFIG_PATH8 = ".kaddo/config.yml";
|
|
11840
|
-
var
|
|
11841
|
-
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
{
|
|
11845
|
-
{
|
|
11846
|
-
{
|
|
12342
|
+
var FILE_TARGETS = [
|
|
12343
|
+
{ path: "knowledge/business/business.md", kind: "business" },
|
|
12344
|
+
{ path: "knowledge/product/product.md", kind: "product" },
|
|
12345
|
+
{ path: "knowledge/product/capabilities.md", kind: "capabilities" },
|
|
12346
|
+
{ path: "knowledge/tech/codebase.md", kind: "codebase" },
|
|
12347
|
+
{ path: "knowledge/tech/current-state.md", kind: "current-state" },
|
|
12348
|
+
{ path: "knowledge/delivery/roadmap.md", kind: "roadmap" }
|
|
11847
12349
|
];
|
|
11848
|
-
var
|
|
12350
|
+
var DIR_TARGETS = ["knowledge/tech/decisions", "knowledge/delivery/work-items"];
|
|
12351
|
+
function withLanguageDirective(content, language) {
|
|
12352
|
+
if (language !== "es") return content;
|
|
12353
|
+
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";
|
|
12354
|
+
const fm2 = content.match(/^---\n[\s\S]*?\n---\n/);
|
|
12355
|
+
if (fm2) return content.slice(0, fm2[0].length) + "\n" + note + content.slice(fm2[0].length);
|
|
12356
|
+
return `${note}
|
|
12357
|
+
${content}`;
|
|
12358
|
+
}
|
|
11849
12359
|
function bootstrap(dir) {
|
|
11850
12360
|
const written = [];
|
|
11851
12361
|
const skipped = [];
|
|
12362
|
+
const createdDirs = [];
|
|
12363
|
+
let state = "new";
|
|
11852
12364
|
let language = "en";
|
|
11853
12365
|
try {
|
|
11854
12366
|
const config = loadConfig(dir);
|
|
11855
|
-
if (config)
|
|
12367
|
+
if (config) {
|
|
12368
|
+
state = config.project.state;
|
|
12369
|
+
language = projectLanguage(config);
|
|
12370
|
+
}
|
|
11856
12371
|
} catch {
|
|
11857
12372
|
}
|
|
11858
|
-
for (const target of
|
|
12373
|
+
for (const target of FILE_TARGETS) {
|
|
11859
12374
|
const full = join(dir, target.path);
|
|
11860
12375
|
if (exists(full)) {
|
|
11861
12376
|
skipped.push(target.path);
|
|
11862
12377
|
continue;
|
|
11863
12378
|
}
|
|
11864
|
-
const
|
|
11865
|
-
const base = tpl ? tpl.content : "";
|
|
11866
|
-
const content = withLanguageDirective(base, language);
|
|
12379
|
+
const content = withLanguageDirective(baselineTemplate(target.kind, state), language);
|
|
11867
12380
|
writeFile(full, content.endsWith("\n") ? content : `${content}
|
|
11868
12381
|
`);
|
|
11869
12382
|
written.push(target.path);
|
|
11870
12383
|
}
|
|
11871
|
-
|
|
11872
|
-
|
|
11873
|
-
|
|
11874
|
-
|
|
11875
|
-
|
|
11876
|
-
|
|
11877
|
-
|
|
11878
|
-
|
|
11879
|
-
|
|
12384
|
+
for (const d of DIR_TARGETS) {
|
|
12385
|
+
const full = join(dir, d);
|
|
12386
|
+
if (exists(full)) {
|
|
12387
|
+
skipped.push(`${d}/`);
|
|
12388
|
+
continue;
|
|
12389
|
+
}
|
|
12390
|
+
ensureDir(full);
|
|
12391
|
+
writeFile(join(full, ".gitkeep"), "");
|
|
12392
|
+
createdDirs.push(`${d}/`);
|
|
12393
|
+
}
|
|
12394
|
+
return { state, written, skipped, createdDirs };
|
|
11880
12395
|
}
|
|
11881
12396
|
async function runBootstrap(dir = cwd()) {
|
|
11882
12397
|
intro2("kaddo bootstrap");
|
|
@@ -11885,46 +12400,37 @@ async function runBootstrap(dir = cwd()) {
|
|
|
11885
12400
|
console.error("Run `kaddo init` first.");
|
|
11886
12401
|
process.exit(1);
|
|
11887
12402
|
}
|
|
11888
|
-
let state = "
|
|
12403
|
+
let state = "new";
|
|
11889
12404
|
try {
|
|
11890
12405
|
const config = loadConfig(dir);
|
|
11891
|
-
state = config?.project.state ?? "
|
|
12406
|
+
state = config?.project.state ?? "new";
|
|
11892
12407
|
} catch (err) {
|
|
11893
|
-
|
|
11894
|
-
console.error(message);
|
|
12408
|
+
console.error(err instanceof ConfigError ? err.message : String(err));
|
|
11895
12409
|
process.exit(1);
|
|
11896
12410
|
}
|
|
11897
|
-
|
|
11898
|
-
log2.info(
|
|
11899
|
-
|
|
11900
|
-
|
|
11901
|
-
const ok = await confirm2({ message: "Continue anyway?", initialValue: false });
|
|
11902
|
-
if (!ok) {
|
|
11903
|
-
outro2("Bootstrap cancelled.");
|
|
11904
|
-
return;
|
|
11905
|
-
}
|
|
11906
|
-
}
|
|
12411
|
+
const stateLabel3 = state === "pre-ai" ? "pre-ai" : state;
|
|
12412
|
+
log2.info(`Project state: ${stateLabel3}`);
|
|
12413
|
+
log2.info(`Creating ${stateLabel3} knowledge baseline.`);
|
|
12414
|
+
log2.info("Existing files will not be overwritten.");
|
|
11907
12415
|
const result = bootstrap(dir);
|
|
11908
12416
|
console.log("");
|
|
11909
|
-
|
|
11910
|
-
for (const layer2 of result.layers) console.log(` \u2713 ${layer2}`);
|
|
11911
|
-
console.log("");
|
|
11912
|
-
if (result.written.length > 0) {
|
|
12417
|
+
if (result.written.length > 0 || result.createdDirs.length > 0) {
|
|
11913
12418
|
console.log("Created:");
|
|
11914
12419
|
for (const p2 of result.written) console.log(` - ${p2}`);
|
|
12420
|
+
for (const d of result.createdDirs) console.log(` - ${d}`);
|
|
11915
12421
|
}
|
|
11916
12422
|
if (result.skipped.length > 0) {
|
|
11917
12423
|
console.log("");
|
|
11918
|
-
console.log("
|
|
12424
|
+
console.log("Skipped (kept existing):");
|
|
11919
12425
|
for (const p2 of result.skipped) console.log(` - ${p2}`);
|
|
11920
12426
|
}
|
|
11921
12427
|
console.log("");
|
|
11922
|
-
console.log("");
|
|
11923
12428
|
log2.info(
|
|
11924
12429
|
"When you pass the context pack to your LLM/coding agent, it must never commit, push or merge without your confirmation \u2014 and create a branch before implementing."
|
|
11925
12430
|
);
|
|
12431
|
+
printCommandFooter("bootstrap");
|
|
11926
12432
|
outro2(
|
|
11927
|
-
|
|
12433
|
+
`${stateLabel3} knowledge baseline ready. Next: \`kaddo add agents\` (then \`kaddo add skills\`), and refine the knowledge with the relevant agents.`
|
|
11928
12434
|
);
|
|
11929
12435
|
}
|
|
11930
12436
|
|