@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.
Files changed (3) hide show
  1. package/README.md +2 -0
  2. package/dist/index.js +577 -71
  3. 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 fm = [
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
- fm,
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(fm) {
6754
+ function yamlBlock(fm2) {
6727
6755
  const lines = ["```yaml"];
6728
- for (const [k, vals] of Object.entries(fm)) {
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, knowledgePresence(dir, f.path)]));
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] !== "present");
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: `Complete \`${firstWeak.label}\` (it is ${presence[firstWeak.key]}).` };
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 fm = a;
8244
- if (!fm.created_at) return true;
8245
- return fm.created_at >= since;
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 TARGETS = [
11841
- // Minimum sufficient knowledge: one consolidated file per layer. Specialized
11842
- // artifacts (problem.md, users.md, capabilities.md, …) appear later, as the project
11843
- // matures, via agents and refinement — not at bootstrap.
11844
- { layer: "Business", path: "knowledge/business/business.md", templateId: "business" },
11845
- { layer: "Product", path: "knowledge/product/product.md", templateId: "product" },
11846
- { layer: "Tech", path: "knowledge/tech/codebase.md", templateId: "codebase" }
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 BOOTSTRAP_LAYERS = ["Business", "Product", "Tech"];
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) language = projectLanguage(config);
12367
+ if (config) {
12368
+ state = config.project.state;
12369
+ language = projectLanguage(config);
12370
+ }
11856
12371
  } catch {
11857
12372
  }
11858
- for (const target of TARGETS) {
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 tpl = getTemplate(target.templateId);
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
- return { written, skipped, layers: BOOTSTRAP_LAYERS };
11872
- }
11873
- function withLanguageDirective(content, language) {
11874
- if (language !== "es") return content;
11875
- 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";
11876
- const fm = content.match(/^---\n[\s\S]*?\n---\n/);
11877
- if (fm) return content.slice(0, fm[0].length) + "\n" + note + content.slice(fm[0].length);
11878
- return `${note}
11879
- ${content}`;
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 = "unknown";
12403
+ let state = "new";
11889
12404
  try {
11890
12405
  const config = loadConfig(dir);
11891
- state = config?.project.state ?? "unknown";
12406
+ state = config?.project.state ?? "new";
11892
12407
  } catch (err) {
11893
- const message = err instanceof ConfigError ? err.message : String(err);
11894
- console.error(message);
12408
+ console.error(err instanceof ConfigError ? err.message : String(err));
11895
12409
  process.exit(1);
11896
12410
  }
11897
- log2.info(`Project state: ${state}`);
11898
- log2.info("Base layers: Business \u2192 Product \u2192 Tech \u2192 Delivery");
11899
- if (state !== "new") {
11900
- log2.warn("This project is not marked as new. Bootstrap is designed for new projects.");
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
- console.log("Bootstrap layers:");
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("Kept existing (skipped):");
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
- "Minimal knowledge base ready (Business \u2192 Product \u2192 Tech). Run `kaddo context` and `kaddo add agents`, then refine with the business-agent, bootstrap-agent and codebase-agent. Roadmap and work items come next under knowledge/delivery/."
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/cli",
3
- "version": "3.35.0",
3
+ "version": "3.37.0",
4
4
  "description": "Knowledge Driven Development toolkit",
5
5
  "license": "MIT",
6
6
  "repository": {