@kaddo/cli 3.37.0 → 3.37.1

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 +1 -0
  2. package/dist/index.js +127 -87
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -533,6 +533,7 @@ create --from roadmap → owners → guard → explain`.
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
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
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 |
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 |
536
537
 
537
538
  **Optional modules (installed with `kaddo add`):**
538
539
 
package/dist/index.js CHANGED
@@ -7745,14 +7745,7 @@ function buildSharedFileStatuses(statuses) {
7745
7745
  }));
7746
7746
  }
7747
7747
 
7748
- // src/core/readiness.ts
7749
- var KNOWLEDGE_FILES = [
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" }
7755
- ];
7748
+ // src/core/next-step.ts
7756
7749
  function roadmapSignal(dir) {
7757
7750
  const p2 = join(dir, "knowledge/delivery/roadmap.md");
7758
7751
  if (!exists(p2)) return "missing";
@@ -7783,8 +7776,91 @@ function installedAdapters(dir) {
7783
7776
  (s) => s.state === "injected" || s.state === "legacy-injected" || s.state === "full-generated" && (s.originAdapter === s.id || s.originAdapter === null)
7784
7777
  ).map((s) => s.id);
7785
7778
  }
7779
+ var B = "knowledge/business/business.md";
7780
+ var P = "knowledge/product/product.md";
7781
+ var CAP = "knowledge/product/capabilities.md";
7782
+ var CS = "knowledge/tech/current-state.md";
7783
+ var CB = "knowledge/tech/codebase.md";
7784
+ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
7785
+ const config = loadConfig(dir);
7786
+ if (!config) {
7787
+ return { id: "init", phase: "Setup", label: "Run `kaddo init` to initialize Kaddo.", command: "kaddo init", reason: "Kaddo is not initialized in this project." };
7788
+ }
7789
+ const state = config.project.state;
7790
+ const q = (rel) => analyzeKnowledgeArtifact(dir, rel);
7791
+ const qBusiness = q(B), qProduct = q(P), qCap = q(CAP), qCurrentState = q(CS), qCodebase = q(CB);
7792
+ if (qBusiness === "missing" || qProduct === "missing") {
7793
+ return { id: "bootstrap", phase: "Setup", label: "Run `kaddo bootstrap` to create the project knowledge baseline.", command: "kaddo bootstrap", reason: "The knowledge baseline is incomplete." };
7794
+ }
7795
+ const ctx = buildCodexAdapterContext(dir);
7796
+ if (!ctx.hasAgents) {
7797
+ return { id: "add-agents", phase: "Setup", label: "Run `kaddo add agents` to install the Kaddo agent prompt packs.", command: "kaddo add agents", reason: "No Kaddo agents are installed yet." };
7798
+ }
7799
+ if (!ctx.hasSkills) {
7800
+ return { id: "add-skills", phase: "Setup", label: "Run `kaddo add skills` to install reusable Kaddo skills.", command: "kaddo add skills", reason: "No Kaddo skills are installed yet." };
7801
+ }
7802
+ if ((state === "pre-ai" || state === "legacy") && !exists(join(dir, ".kaddo", "scan.json"))) {
7803
+ return { id: "scan", phase: "Discovery", label: "Run `kaddo scan` to capture deterministic signals from the existing code.", command: "kaddo scan", reason: "No scan baseline exists for this existing project yet." };
7804
+ }
7805
+ if (!exists(join(dir, ".kaddo", "context-pack.md"))) {
7806
+ return { id: "context", phase: "Discovery", label: "Run `kaddo context` to prepare the LLM context pack.", command: "kaddo context", reason: "No context pack has been generated yet." };
7807
+ }
7808
+ if (!exists(join(dir, ".kaddo", "understand.md"))) {
7809
+ return { id: "understand", phase: "Discovery", label: "Run `kaddo understand` to summarize the project context.", command: "kaddo understand", reason: "No understand handoff has been generated yet." };
7810
+ }
7811
+ const refine = (id, agent, target, quality) => ({
7812
+ id,
7813
+ phase: "Knowledge Refinement",
7814
+ label: `Use ${agent} to complete \`${target}\`.`,
7815
+ agent,
7816
+ target,
7817
+ reason: `${target} is ${quality === "missing" ? "missing" : "still a bootstrap placeholder or too thin"}.`,
7818
+ instructions: [
7819
+ "The baseline file exists but does not yet hold real, project-specific knowledge.",
7820
+ `Use the ${agent} to replace the placeholders with real knowledge.`,
7821
+ "Do not write code."
7822
+ ]
7823
+ });
7824
+ if (qBusiness !== "useful") return refine("refine-business", "business-agent", B, qBusiness);
7825
+ if (qProduct !== "useful" || qCap !== "useful") {
7826
+ const target = qCap !== "useful" ? CAP : P;
7827
+ return refine("refine-product", "capability-agent", target, qCap !== "useful" ? qCap : qProduct);
7828
+ }
7829
+ if (qCurrentState !== "useful") return refine("refine-current-state", "architecture-agent", CS, qCurrentState);
7830
+ if (qCodebase !== "useful") {
7831
+ const agent = ctx.agents.includes("codebase-agent") ? "codebase-agent" : "architecture-agent";
7832
+ return refine("refine-codebase", agent, CB, qCodebase);
7833
+ }
7834
+ const oq = buildOpenQuestionsReport(dir, now);
7835
+ if (oq.summary.blocking_open > 0) {
7836
+ return { id: "questions", phase: "Knowledge Refinement", label: "Resolve, assume or defer the blocking open questions (`kaddo questions`).", command: "kaddo questions", reason: `${oq.summary.blocking_open} blocking open question(s) remain.` };
7837
+ }
7838
+ const roadmap = roadmapSignal(dir);
7839
+ if (roadmap !== "has-candidates") {
7840
+ return { id: "roadmap", phase: "Planning", label: "Use roadmap-agent to define roadmap candidates (`kaddo roadmap`).", command: "kaddo roadmap", agent: "roadmap-agent", target: "knowledge/delivery/roadmap.md", reason: "The roadmap has no candidates yet." };
7841
+ }
7842
+ const wi = workItemsSignal(dir);
7843
+ if (wi === "none" || wi === "none-ready") {
7844
+ return { id: "create-work-item", phase: "Delivery Preparation", label: "Run `kaddo create --from roadmap` to materialize the first Work Item.", command: "kaddo create --from roadmap", reason: "The roadmap has candidates but no Work Item is ready." };
7845
+ }
7846
+ const adapters = installedAdapters(dir);
7847
+ if (adapters.length === 0) {
7848
+ return { id: "install-adapter", phase: "Active Delivery", label: "Run `kaddo adapters list` and install the adapter for your preferred agent.", command: "kaddo adapters list", reason: "A Work Item is ready but no adapter is installed." };
7849
+ }
7850
+ return { id: "implement", phase: "Active Delivery", label: "Implement the ready Work Item and run `kaddo guard`.", reason: "A Work Item is ready and an adapter is installed." };
7851
+ }
7852
+
7853
+ // src/core/readiness.ts
7854
+ var KNOWLEDGE_FILES = [
7855
+ { key: "current_state", path: "knowledge/tech/current-state.md", label: "knowledge/tech/current-state.md", agent: "architecture-agent" },
7856
+ { key: "codebase", path: "knowledge/tech/codebase.md", label: "knowledge/tech/codebase.md", agent: "codebase-agent" },
7857
+ { key: "capabilities", path: "knowledge/product/capabilities.md", label: "knowledge/product/capabilities.md", agent: "capability-agent" },
7858
+ { key: "product", path: "knowledge/product/product.md", label: "knowledge/product/product.md", agent: "product-agent" },
7859
+ { key: "business", path: "knowledge/business/business.md", label: "knowledge/business/business.md", agent: "business-agent" }
7860
+ ];
7786
7861
  function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
7787
7862
  const config = loadConfig(dir);
7863
+ const rec = resolveNextStep(dir, now);
7788
7864
  const stub = (overall2, label, command) => ({
7789
7865
  project_name: config?.project.name ?? "unknown",
7790
7866
  project_type: config?.project.state ?? "unknown",
@@ -7808,9 +7884,10 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
7808
7884
  resolved_questions: 0,
7809
7885
  deferred_questions: 0
7810
7886
  },
7811
- recommended_next_step: { label, ...command ? { command } : {} }
7887
+ recommended_next_step: { label, ...command ? { command } : {} },
7888
+ nextStepRecommendation: rec
7812
7889
  });
7813
- if (!config) return stub("not-initialized", "Run `kaddo init` to initialize Kaddo.", "kaddo init");
7890
+ if (!config) return stub("not-initialized", rec.label, rec.command);
7814
7891
  if (config.project.state === "new") return stub("not-applicable", "This project uses the standard new-project Kaddo flow.");
7815
7892
  if (config.project.state === "legacy") return stub("legacy-project", "Use the legacy project flow.");
7816
7893
  const scan2 = exists(join(dir, ".kaddo", "scan.json")) ? "available" : "missing";
@@ -7843,41 +7920,26 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
7843
7920
  resolved_questions: oq.summary.resolution.resolved,
7844
7921
  deferred_questions: oq.summary.resolution.deferred
7845
7922
  };
7846
- let overall;
7847
- let next;
7848
7923
  const firstWeak = KNOWLEDGE_FILES.find((f) => presence[f.key] !== "useful");
7849
- if (scan2 === "missing") {
7850
- overall = "initialized";
7851
- next = { label: "Run `kaddo scan` to capture deterministic signals from the existing code.", command: "kaddo scan" };
7852
- } else if (bootstrapBaseline === "incomplete") {
7853
- overall = "bootstrap-incomplete";
7854
- next = { label: "Run `kaddo bootstrap` to create the project knowledge baseline.", command: "kaddo bootstrap" };
7855
- } else if (agents === "missing") {
7856
- overall = "agents-missing";
7857
- next = { label: "Run `kaddo add agents` to install the Kaddo agent prompt packs.", command: "kaddo add agents" };
7858
- } else if (skills === "missing") {
7859
- overall = "skills-missing";
7860
- next = { label: "Run `kaddo add skills` to install reusable Kaddo skills.", command: "kaddo add skills" };
7861
- } else if (understand === "missing") {
7862
- overall = "scanned";
7863
- next = { label: "Run `kaddo understand` to summarize the project context.", command: "kaddo understand" };
7864
- } else if (firstWeak) {
7865
- overall = "knowledge-incomplete";
7866
- next = { label: `Use ${firstWeak.agent} to complete \`${firstWeak.label}\` (it is ${presence[firstWeak.key]}).` };
7867
- } else if (oq.summary.blocking_open > 0) {
7868
- overall = "needs-decisions";
7869
- next = { label: "Resolve, assume or defer the blocking open questions (`kaddo questions`).", command: "kaddo questions" };
7870
- } else if (roadmap !== "has-candidates") {
7871
- overall = "ready-for-roadmap";
7872
- next = { label: "Run `kaddo roadmap` to draft the roadmap from the current knowledge.", command: "kaddo roadmap" };
7873
- } else if (work_items === "none" || work_items === "none-ready") {
7874
- overall = "ready-for-work-item";
7875
- next = { label: "Run `kaddo create --from roadmap` to materialize the first Work Item.", command: "kaddo create --from roadmap" };
7876
- } else {
7877
- overall = "ready-for-implementation";
7878
- next = adapters.length > 0 ? { label: "Implement the ready Work Item and run `kaddo guard`." } : { label: "Run `kaddo adapters list` and install the adapter for your preferred agent.", command: "kaddo adapters list" };
7879
- }
7880
- return { project_name: config.project.name, project_type: config.project.state, overall, signals, recommended_next_step: next };
7924
+ let overall;
7925
+ if (scan2 === "missing") overall = "initialized";
7926
+ else if (bootstrapBaseline === "incomplete") overall = "bootstrap-incomplete";
7927
+ else if (agents === "missing") overall = "agents-missing";
7928
+ else if (skills === "missing") overall = "skills-missing";
7929
+ else if (understand === "missing") overall = "scanned";
7930
+ else if (firstWeak) overall = "knowledge-incomplete";
7931
+ else if (oq.summary.blocking_open > 0) overall = "needs-decisions";
7932
+ else if (roadmap !== "has-candidates") overall = "ready-for-roadmap";
7933
+ else if (work_items === "none" || work_items === "none-ready") overall = "ready-for-work-item";
7934
+ else overall = "ready-for-implementation";
7935
+ return {
7936
+ project_name: config.project.name,
7937
+ project_type: config.project.state,
7938
+ overall,
7939
+ signals,
7940
+ recommended_next_step: { label: rec.label, ...rec.command ? { command: rec.command } : {} },
7941
+ nextStepRecommendation: rec
7942
+ };
7881
7943
  }
7882
7944
 
7883
7945
  // src/core/project-explain.ts
@@ -8069,6 +8131,7 @@ function buildProjectExplanation(dir) {
8069
8131
  "Run `kaddo owners suggest` for Work Items without code ownership."
8070
8132
  );
8071
8133
  }
8134
+ const readiness = buildReadinessReport(dir);
8072
8135
  return {
8073
8136
  project,
8074
8137
  stack,
@@ -8089,7 +8152,8 @@ function buildProjectExplanation(dir) {
8089
8152
  mappedModules,
8090
8153
  missingKnowledge,
8091
8154
  suggestedNextSteps,
8092
- readiness: buildReadinessReport(dir)
8155
+ readiness,
8156
+ nextStepRecommendation: readiness.nextStepRecommendation
8093
8157
  };
8094
8158
  }
8095
8159
  function stateLabel(state) {
@@ -8270,7 +8334,7 @@ function renderExplanationHuman(exp) {
8270
8334
  lines.push("- Reason:");
8271
8335
  for (const r2 of assessment.reasons) lines.push(` - ${r2}`);
8272
8336
  }
8273
- if (assessment.nextStep) lines.push(`- Next step: ${assessment.nextStep}`);
8337
+ lines.push(`- Next step: ${exp.readiness.recommended_next_step.label}`);
8274
8338
  lines.push("");
8275
8339
  if (exp.suggestedNextSteps.length > 0) {
8276
8340
  lines.push("## Suggested Next Steps");
@@ -8292,7 +8356,6 @@ function renderExplanationHuman(exp) {
8292
8356
  lines.push(`- capabilities: ${s.capabilities}`);
8293
8357
  lines.push(`- current-state: ${s.current_state}`);
8294
8358
  lines.push(`- codebase: ${s.codebase}`);
8295
- lines.push(`- capabilities: ${s.capabilities}`);
8296
8359
  lines.push(`- roadmap: ${s.roadmap}`);
8297
8360
  lines.push(`- work-items: ${s.work_items}`);
8298
8361
  lines.push(`- adapters: ${s.adapters.length > 0 ? s.adapters.join(", ") + " installed" : "none installed"}`);
@@ -8536,28 +8599,6 @@ function recommendedAgentsForState(state) {
8536
8599
  return ["capability-agent", "architecture-agent", "roadmap-agent"];
8537
8600
  }
8538
8601
  }
8539
- function nextStepsForState2(state) {
8540
- switch (state) {
8541
- case "new":
8542
- return [
8543
- "Use roadmap-agent to shape an initial roadmap.",
8544
- "Use architecture-agent to outline the intended architecture."
8545
- ];
8546
- case "legacy":
8547
- return [
8548
- "Use legacy-agent to surface risks and unknowns before changing code.",
8549
- "Use architecture-agent to reconstruct the current architecture.",
8550
- "Use capability-agent to map existing capabilities."
8551
- ];
8552
- case "pre-ai":
8553
- default:
8554
- return [
8555
- "Use capability-agent to extract system capabilities.",
8556
- "Use architecture-agent to reconstruct the current architecture.",
8557
- "Use roadmap-agent to propose roadmap candidates."
8558
- ];
8559
- }
8560
- }
8561
8602
  var LLM_INSTRUCTIONS = [
8562
8603
  "Use this context pack as the project baseline.",
8563
8604
  "Do not write code yet.",
@@ -8669,6 +8710,12 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
8669
8710
  workItemsMissingOwnership: allWorkItems.length - wiWithOwnership
8670
8711
  }
8671
8712
  });
8713
+ const nextStepRecommendation = resolveNextStep(dir, now);
8714
+ const unifiedPhase = {
8715
+ ...phase,
8716
+ nextStep: nextStepRecommendation.label,
8717
+ recommendedAgents: nextStepRecommendation.agent ? [nextStepRecommendation.agent] : phase.recommendedAgents
8718
+ };
8672
8719
  return {
8673
8720
  version: CONTEXT_PACK_VERSION,
8674
8721
  generatedAt: now.toISOString(),
@@ -8699,7 +8746,8 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
8699
8746
  layers,
8700
8747
  knowledgeQuality,
8701
8748
  roadmap,
8702
- phase,
8749
+ phase: unifiedPhase,
8750
+ nextStepRecommendation,
8703
8751
  deliveryMix,
8704
8752
  external: loadExternalCapsules(dir),
8705
8753
  graph: loadGraphSummary(dir),
@@ -8707,12 +8755,12 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
8707
8755
  skills: discoverInstalledSkills(dir).map((s) => s.id),
8708
8756
  mappedModules,
8709
8757
  missing,
8710
- // VS-052: the handoff is driven by the REAL phase, not project.state, so the pack never
8711
- // contradicts the Current Phase block above it.
8758
+ // VS-052/VS-073.2: the handoff is driven by the unified next step, so the pack never contradicts
8759
+ // the Current Phase block above it.
8712
8760
  handoff: {
8713
- recommendedAgents: phase.recommendedAgents.length > 0 ? phase.recommendedAgents : recommendedAgentsForState(state),
8714
- nextSteps: phase.nextStep ? [phase.nextStep] : nextStepsForState2(state),
8715
- instructions: phase.llmInstructions.length > 0 ? phase.llmInstructions : LLM_INSTRUCTIONS,
8761
+ recommendedAgents: unifiedPhase.recommendedAgents.length > 0 ? unifiedPhase.recommendedAgents : recommendedAgentsForState(state),
8762
+ nextSteps: [nextStepRecommendation.label],
8763
+ instructions: unifiedPhase.llmInstructions.length > 0 ? unifiedPhase.llmInstructions : LLM_INSTRUCTIONS,
8716
8764
  operatingRules: OPERATING_RULES
8717
8765
  }
8718
8766
  };
@@ -9216,24 +9264,16 @@ function runUnderstand() {
9216
9264
  console.log(`Project language: ${pack.project.language} (knowledge artifacts are written in this language)`);
9217
9265
  const exp = buildProjectExplanation(dir);
9218
9266
  const assessment = assessPhase(exp);
9267
+ const rec = exp.nextStepRecommendation;
9219
9268
  console.log("");
9220
9269
  console.log(`Current phase: ${assessment.phase}`);
9221
9270
  if (assessment.reasons.length > 0) {
9222
9271
  console.log("Reason:");
9223
9272
  for (const r of assessment.reasons) console.log(` - ${r}`);
9224
9273
  }
9225
- if (assessment.recommendedAgents.length > 0) {
9226
- console.log(`Recommended: ${assessment.recommendedAgents.join(", ")}`);
9227
- }
9228
- if (assessment.nextStep) {
9229
- console.log(`Next step: ${assessment.nextStep}`);
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
- }
9274
+ if (rec.agent) console.log(`Recommended: ${rec.agent}`);
9275
+ console.log(`Next step: ${rec.label}`);
9276
+ if (rec.reason) console.log(`Why: ${rec.reason}`);
9237
9277
  const installedSkills = discoverInstalledSkills(dir);
9238
9278
  if (installedSkills.length > 0 && assessment.recommendedAgents.length > 0) {
9239
9279
  const recSkills = skillsForAgents(installedSkills, assessment.recommendedAgents);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/cli",
3
- "version": "3.37.0",
3
+ "version": "3.37.1",
4
4
  "description": "Knowledge Driven Development toolkit",
5
5
  "license": "MIT",
6
6
  "repository": {