@kaddo/cli 3.37.0 → 3.38.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 +197 -102
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -533,6 +533,8 @@ 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 |
537
+ | v3.38 | Open-question source locations: `kaddo questions` shows each question's `Source` (path:line), `Status`, `Severity`, `Note` + a copy/paste resolution example and localized how-to-resolve guide; JSON/report/MCP carry `sourcePath`, `line`, `raw`, `note` |
536
538
 
537
539
  **Optional modules (installed with `kaddo add`):**
538
540
 
package/dist/index.js CHANGED
@@ -7205,10 +7205,10 @@ function extractFromMarkdown(md) {
7205
7205
  }
7206
7206
  const m = line.match(/^\s*(?:[-*]|\d+\.)\s+(.+?)\s*$/);
7207
7207
  if (m) {
7208
- const raw = m[1].trim();
7209
- if (!raw || /^_.*_$/.test(raw)) continue;
7210
- const { text: text3, resolution_status } = parseResolution(raw);
7211
- if (text3) out.push({ text: text3, resolution_status });
7208
+ const bullet = m[1].trim();
7209
+ if (!bullet || /^_.*_$/.test(bullet)) continue;
7210
+ const { text: text3, resolution_status } = parseResolution(bullet);
7211
+ if (text3) out.push({ text: text3, resolution_status, line: i + 1, raw: line.trim() });
7212
7212
  }
7213
7213
  }
7214
7214
  return out;
@@ -7248,12 +7248,15 @@ function buildOpenQuestionsReport(dir, now = /* @__PURE__ */ new Date()) {
7248
7248
  questions.push({
7249
7249
  id: `OQ-${String(seq).padStart(3, "0")}`,
7250
7250
  source,
7251
+ sourcePath: source,
7252
+ line: eq.line,
7253
+ raw: eq.raw,
7251
7254
  section: "Open Questions",
7252
7255
  question: eq.text,
7253
7256
  classification,
7254
7257
  resolution_status: eq.resolution_status,
7255
7258
  reason,
7256
- ...eq.resolution_note ? { resolution_note: eq.resolution_note } : {},
7259
+ ...eq.resolution_note ? { resolution_note: eq.resolution_note, note: eq.resolution_note } : {},
7257
7260
  ...classification === "blocking" && eq.resolution_status === "open" ? { suggested_assumption: suggestedAssumption(eq.text) } : {}
7258
7261
  });
7259
7262
  }
@@ -7323,17 +7326,23 @@ function renderOpenQuestionsMarkdown(r) {
7323
7326
  L.push("## Blocking Open Questions", "");
7324
7327
  if (blockingOpen.length === 0) L.push("_None \u2014 nothing blocks readiness._", "");
7325
7328
  for (const q of blockingOpen) {
7326
- L.push(`### ${q.id}`, "");
7327
- L.push(`- Source: \`${q.source}\``);
7328
- L.push(`- Question: ${q.question}`);
7329
+ L.push(`### ${q.question}`, "");
7330
+ L.push(`- Status: ${q.resolution_status}`);
7331
+ L.push(`- Severity: ${q.classification}`);
7332
+ L.push(`- Source: \`${q.sourcePath}:${q.line}\``);
7329
7333
  L.push(`- Reason: ${q.reason}`);
7330
- if (q.suggested_assumption) L.push(`- Suggested assumption: ${q.suggested_assumption}`);
7334
+ L.push("");
7335
+ L.push("Suggested action:", "");
7336
+ L.push("```md");
7337
+ L.push(`- [assumed] ${q.question}`);
7338
+ L.push(` - note: ${q.suggested_assumption ?? "<editable assumption for the MVP>"}`);
7339
+ L.push("```");
7331
7340
  L.push("");
7332
7341
  }
7333
7342
  const renderStatusList = (title, items) => {
7334
7343
  L.push(`## ${title}`, "");
7335
7344
  if (items.length === 0) L.push("_None._");
7336
- for (const q of items) L.push(`- ${q.question}${q.resolution_note ? ` \u2014 _${q.resolution_note}_` : ""}`);
7345
+ for (const q of items) L.push(`- ${q.question} \u2014 \`${q.sourcePath}:${q.line}\`${q.note ? ` \u2014 _${q.note}_` : ""}`);
7337
7346
  L.push("");
7338
7347
  };
7339
7348
  renderStatusList("Resolved", r.resolved_questions);
@@ -7745,14 +7754,7 @@ function buildSharedFileStatuses(statuses) {
7745
7754
  }));
7746
7755
  }
7747
7756
 
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
- ];
7757
+ // src/core/next-step.ts
7756
7758
  function roadmapSignal(dir) {
7757
7759
  const p2 = join(dir, "knowledge/delivery/roadmap.md");
7758
7760
  if (!exists(p2)) return "missing";
@@ -7783,8 +7785,91 @@ function installedAdapters(dir) {
7783
7785
  (s) => s.state === "injected" || s.state === "legacy-injected" || s.state === "full-generated" && (s.originAdapter === s.id || s.originAdapter === null)
7784
7786
  ).map((s) => s.id);
7785
7787
  }
7788
+ var B = "knowledge/business/business.md";
7789
+ var P = "knowledge/product/product.md";
7790
+ var CAP = "knowledge/product/capabilities.md";
7791
+ var CS = "knowledge/tech/current-state.md";
7792
+ var CB = "knowledge/tech/codebase.md";
7793
+ function resolveNextStep(dir, now = /* @__PURE__ */ new Date()) {
7794
+ const config = loadConfig(dir);
7795
+ if (!config) {
7796
+ return { id: "init", phase: "Setup", label: "Run `kaddo init` to initialize Kaddo.", command: "kaddo init", reason: "Kaddo is not initialized in this project." };
7797
+ }
7798
+ const state = config.project.state;
7799
+ const q = (rel) => analyzeKnowledgeArtifact(dir, rel);
7800
+ const qBusiness = q(B), qProduct = q(P), qCap = q(CAP), qCurrentState = q(CS), qCodebase = q(CB);
7801
+ if (qBusiness === "missing" || qProduct === "missing") {
7802
+ return { id: "bootstrap", phase: "Setup", label: "Run `kaddo bootstrap` to create the project knowledge baseline.", command: "kaddo bootstrap", reason: "The knowledge baseline is incomplete." };
7803
+ }
7804
+ const ctx = buildCodexAdapterContext(dir);
7805
+ if (!ctx.hasAgents) {
7806
+ 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." };
7807
+ }
7808
+ if (!ctx.hasSkills) {
7809
+ 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." };
7810
+ }
7811
+ if ((state === "pre-ai" || state === "legacy") && !exists(join(dir, ".kaddo", "scan.json"))) {
7812
+ 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." };
7813
+ }
7814
+ if (!exists(join(dir, ".kaddo", "context-pack.md"))) {
7815
+ 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." };
7816
+ }
7817
+ if (!exists(join(dir, ".kaddo", "understand.md"))) {
7818
+ 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." };
7819
+ }
7820
+ const refine = (id, agent, target, quality) => ({
7821
+ id,
7822
+ phase: "Knowledge Refinement",
7823
+ label: `Use ${agent} to complete \`${target}\`.`,
7824
+ agent,
7825
+ target,
7826
+ reason: `${target} is ${quality === "missing" ? "missing" : "still a bootstrap placeholder or too thin"}.`,
7827
+ instructions: [
7828
+ "The baseline file exists but does not yet hold real, project-specific knowledge.",
7829
+ `Use the ${agent} to replace the placeholders with real knowledge.`,
7830
+ "Do not write code."
7831
+ ]
7832
+ });
7833
+ if (qBusiness !== "useful") return refine("refine-business", "business-agent", B, qBusiness);
7834
+ if (qProduct !== "useful" || qCap !== "useful") {
7835
+ const target = qCap !== "useful" ? CAP : P;
7836
+ return refine("refine-product", "capability-agent", target, qCap !== "useful" ? qCap : qProduct);
7837
+ }
7838
+ if (qCurrentState !== "useful") return refine("refine-current-state", "architecture-agent", CS, qCurrentState);
7839
+ if (qCodebase !== "useful") {
7840
+ const agent = ctx.agents.includes("codebase-agent") ? "codebase-agent" : "architecture-agent";
7841
+ return refine("refine-codebase", agent, CB, qCodebase);
7842
+ }
7843
+ const oq = buildOpenQuestionsReport(dir, now);
7844
+ if (oq.summary.blocking_open > 0) {
7845
+ return { id: "questions", phase: "Knowledge Refinement", label: "Run `kaddo questions` to see source locations and resolution guidance, then resolve, assume or defer the blocking open questions.", command: "kaddo questions", reason: `${oq.summary.blocking_open} blocking open question(s) remain.` };
7846
+ }
7847
+ const roadmap = roadmapSignal(dir);
7848
+ if (roadmap !== "has-candidates") {
7849
+ 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." };
7850
+ }
7851
+ const wi = workItemsSignal(dir);
7852
+ if (wi === "none" || wi === "none-ready") {
7853
+ 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." };
7854
+ }
7855
+ const adapters = installedAdapters(dir);
7856
+ if (adapters.length === 0) {
7857
+ 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." };
7858
+ }
7859
+ 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." };
7860
+ }
7861
+
7862
+ // src/core/readiness.ts
7863
+ var KNOWLEDGE_FILES = [
7864
+ { key: "current_state", path: "knowledge/tech/current-state.md", label: "knowledge/tech/current-state.md", agent: "architecture-agent" },
7865
+ { key: "codebase", path: "knowledge/tech/codebase.md", label: "knowledge/tech/codebase.md", agent: "codebase-agent" },
7866
+ { key: "capabilities", path: "knowledge/product/capabilities.md", label: "knowledge/product/capabilities.md", agent: "capability-agent" },
7867
+ { key: "product", path: "knowledge/product/product.md", label: "knowledge/product/product.md", agent: "product-agent" },
7868
+ { key: "business", path: "knowledge/business/business.md", label: "knowledge/business/business.md", agent: "business-agent" }
7869
+ ];
7786
7870
  function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
7787
7871
  const config = loadConfig(dir);
7872
+ const rec = resolveNextStep(dir, now);
7788
7873
  const stub = (overall2, label, command) => ({
7789
7874
  project_name: config?.project.name ?? "unknown",
7790
7875
  project_type: config?.project.state ?? "unknown",
@@ -7808,9 +7893,10 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
7808
7893
  resolved_questions: 0,
7809
7894
  deferred_questions: 0
7810
7895
  },
7811
- recommended_next_step: { label, ...command ? { command } : {} }
7896
+ recommended_next_step: { label, ...command ? { command } : {} },
7897
+ nextStepRecommendation: rec
7812
7898
  });
7813
- if (!config) return stub("not-initialized", "Run `kaddo init` to initialize Kaddo.", "kaddo init");
7899
+ if (!config) return stub("not-initialized", rec.label, rec.command);
7814
7900
  if (config.project.state === "new") return stub("not-applicable", "This project uses the standard new-project Kaddo flow.");
7815
7901
  if (config.project.state === "legacy") return stub("legacy-project", "Use the legacy project flow.");
7816
7902
  const scan2 = exists(join(dir, ".kaddo", "scan.json")) ? "available" : "missing";
@@ -7843,41 +7929,26 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
7843
7929
  resolved_questions: oq.summary.resolution.resolved,
7844
7930
  deferred_questions: oq.summary.resolution.deferred
7845
7931
  };
7846
- let overall;
7847
- let next;
7848
7932
  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 };
7933
+ let overall;
7934
+ if (scan2 === "missing") overall = "initialized";
7935
+ else if (bootstrapBaseline === "incomplete") overall = "bootstrap-incomplete";
7936
+ else if (agents === "missing") overall = "agents-missing";
7937
+ else if (skills === "missing") overall = "skills-missing";
7938
+ else if (understand === "missing") overall = "scanned";
7939
+ else if (firstWeak) overall = "knowledge-incomplete";
7940
+ else if (oq.summary.blocking_open > 0) overall = "needs-decisions";
7941
+ else if (roadmap !== "has-candidates") overall = "ready-for-roadmap";
7942
+ else if (work_items === "none" || work_items === "none-ready") overall = "ready-for-work-item";
7943
+ else overall = "ready-for-implementation";
7944
+ return {
7945
+ project_name: config.project.name,
7946
+ project_type: config.project.state,
7947
+ overall,
7948
+ signals,
7949
+ recommended_next_step: { label: rec.label, ...rec.command ? { command: rec.command } : {} },
7950
+ nextStepRecommendation: rec
7951
+ };
7881
7952
  }
7882
7953
 
7883
7954
  // src/core/project-explain.ts
@@ -8069,6 +8140,7 @@ function buildProjectExplanation(dir) {
8069
8140
  "Run `kaddo owners suggest` for Work Items without code ownership."
8070
8141
  );
8071
8142
  }
8143
+ const readiness = buildReadinessReport(dir);
8072
8144
  return {
8073
8145
  project,
8074
8146
  stack,
@@ -8089,7 +8161,8 @@ function buildProjectExplanation(dir) {
8089
8161
  mappedModules,
8090
8162
  missingKnowledge,
8091
8163
  suggestedNextSteps,
8092
- readiness: buildReadinessReport(dir)
8164
+ readiness,
8165
+ nextStepRecommendation: readiness.nextStepRecommendation
8093
8166
  };
8094
8167
  }
8095
8168
  function stateLabel(state) {
@@ -8270,7 +8343,7 @@ function renderExplanationHuman(exp) {
8270
8343
  lines.push("- Reason:");
8271
8344
  for (const r2 of assessment.reasons) lines.push(` - ${r2}`);
8272
8345
  }
8273
- if (assessment.nextStep) lines.push(`- Next step: ${assessment.nextStep}`);
8346
+ lines.push(`- Next step: ${exp.readiness.recommended_next_step.label}`);
8274
8347
  lines.push("");
8275
8348
  if (exp.suggestedNextSteps.length > 0) {
8276
8349
  lines.push("## Suggested Next Steps");
@@ -8292,7 +8365,6 @@ function renderExplanationHuman(exp) {
8292
8365
  lines.push(`- capabilities: ${s.capabilities}`);
8293
8366
  lines.push(`- current-state: ${s.current_state}`);
8294
8367
  lines.push(`- codebase: ${s.codebase}`);
8295
- lines.push(`- capabilities: ${s.capabilities}`);
8296
8368
  lines.push(`- roadmap: ${s.roadmap}`);
8297
8369
  lines.push(`- work-items: ${s.work_items}`);
8298
8370
  lines.push(`- adapters: ${s.adapters.length > 0 ? s.adapters.join(", ") + " installed" : "none installed"}`);
@@ -8536,28 +8608,6 @@ function recommendedAgentsForState(state) {
8536
8608
  return ["capability-agent", "architecture-agent", "roadmap-agent"];
8537
8609
  }
8538
8610
  }
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
8611
  var LLM_INSTRUCTIONS = [
8562
8612
  "Use this context pack as the project baseline.",
8563
8613
  "Do not write code yet.",
@@ -8669,6 +8719,12 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
8669
8719
  workItemsMissingOwnership: allWorkItems.length - wiWithOwnership
8670
8720
  }
8671
8721
  });
8722
+ const nextStepRecommendation = resolveNextStep(dir, now);
8723
+ const unifiedPhase = {
8724
+ ...phase,
8725
+ nextStep: nextStepRecommendation.label,
8726
+ recommendedAgents: nextStepRecommendation.agent ? [nextStepRecommendation.agent] : phase.recommendedAgents
8727
+ };
8672
8728
  return {
8673
8729
  version: CONTEXT_PACK_VERSION,
8674
8730
  generatedAt: now.toISOString(),
@@ -8699,7 +8755,8 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
8699
8755
  layers,
8700
8756
  knowledgeQuality,
8701
8757
  roadmap,
8702
- phase,
8758
+ phase: unifiedPhase,
8759
+ nextStepRecommendation,
8703
8760
  deliveryMix,
8704
8761
  external: loadExternalCapsules(dir),
8705
8762
  graph: loadGraphSummary(dir),
@@ -8707,12 +8764,12 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
8707
8764
  skills: discoverInstalledSkills(dir).map((s) => s.id),
8708
8765
  mappedModules,
8709
8766
  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.
8767
+ // VS-052/VS-073.2: the handoff is driven by the unified next step, so the pack never contradicts
8768
+ // the Current Phase block above it.
8712
8769
  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,
8770
+ recommendedAgents: unifiedPhase.recommendedAgents.length > 0 ? unifiedPhase.recommendedAgents : recommendedAgentsForState(state),
8771
+ nextSteps: [nextStepRecommendation.label],
8772
+ instructions: unifiedPhase.llmInstructions.length > 0 ? unifiedPhase.llmInstructions : LLM_INSTRUCTIONS,
8716
8773
  operatingRules: OPERATING_RULES
8717
8774
  }
8718
8775
  };
@@ -9216,24 +9273,16 @@ function runUnderstand() {
9216
9273
  console.log(`Project language: ${pack.project.language} (knowledge artifacts are written in this language)`);
9217
9274
  const exp = buildProjectExplanation(dir);
9218
9275
  const assessment = assessPhase(exp);
9276
+ const rec = exp.nextStepRecommendation;
9219
9277
  console.log("");
9220
9278
  console.log(`Current phase: ${assessment.phase}`);
9221
9279
  if (assessment.reasons.length > 0) {
9222
9280
  console.log("Reason:");
9223
9281
  for (const r of assessment.reasons) console.log(` - ${r}`);
9224
9282
  }
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
- }
9283
+ if (rec.agent) console.log(`Recommended: ${rec.agent}`);
9284
+ console.log(`Next step: ${rec.label}`);
9285
+ if (rec.reason) console.log(`Why: ${rec.reason}`);
9237
9286
  const installedSkills = discoverInstalledSkills(dir);
9238
9287
  if (installedSkills.length > 0 && assessment.recommendedAgents.length > 0) {
9239
9288
  const recSkills = skillsForAgents(installedSkills, assessment.recommendedAgents);
@@ -13403,7 +13452,8 @@ function runDrift(opts = {}) {
13403
13452
  // src/commands/questions.ts
13404
13453
  function runQuestions(opts = {}) {
13405
13454
  const dir = cwd();
13406
- requireConfig(dir);
13455
+ const config = requireConfig(dir);
13456
+ const es = projectLanguage(config) === "es";
13407
13457
  const report = buildOpenQuestionsReport(dir);
13408
13458
  if (opts.output) {
13409
13459
  intro2("kaddo questions");
@@ -13422,22 +13472,67 @@ function runQuestions(opts = {}) {
13422
13472
  console.log(`Open questions detected: ${s.open_questions}`);
13423
13473
  console.log(`By resolution \u2014 open: ${s.resolution.open}, resolved: ${s.resolution.resolved}, assumed: ${s.resolution.assumed}, deferred: ${s.resolution.deferred}`);
13424
13474
  console.log(`Roadmap readiness: ${s.roadmap_readiness === "needs_decisions" ? "needs decisions" : s.roadmap_readiness} (blocking open: ${s.blocking_open}, important open: ${s.important_open})`);
13425
- const list2 = (title, qs) => {
13475
+ const list2 = (title, qs, opts2 = {}) => {
13426
13476
  if (qs.length === 0) return;
13427
13477
  console.log("");
13428
13478
  console.log(`${title}:`);
13429
- for (const q of qs.slice(0, 8)) console.log(`- ${q.question}${q.resolution_note ? ` \u2014 ${q.resolution_note}` : ""}`);
13430
- if (qs.length > 8) console.log(` \u2026and ${qs.length - 8} more`);
13479
+ console.log("");
13480
+ qs.slice(0, 12).forEach((q, i) => {
13481
+ console.log(`${i + 1}. ${q.question}`);
13482
+ console.log(` Source: ${q.sourcePath}:${q.line}`);
13483
+ console.log(` Status: ${q.resolution_status}`);
13484
+ console.log(` Severity: ${q.classification}`);
13485
+ if (q.note) console.log(` Note: ${q.note}`);
13486
+ if (opts2.example && q.resolution_status === "open") {
13487
+ console.log(" Suggested action:");
13488
+ console.log(` ${es ? "Cambia [open] por [resolved], [assumed] o [deferred]." : "Change [open] to [resolved], [assumed] or [deferred]."}`);
13489
+ console.log(" Example:");
13490
+ console.log(` - [assumed] ${q.question}`);
13491
+ console.log(` - note: ${es ? "<supuesto editable para el MVP>" : "<editable assumption for the MVP>"}`);
13492
+ }
13493
+ console.log("");
13494
+ });
13495
+ if (qs.length > 12) console.log(` \u2026and ${qs.length - 12} more`);
13431
13496
  };
13432
- list2("Blocking (open)", report.blocking_questions.filter((q) => q.resolution_status === "open"));
13497
+ list2("Blocking (open)", report.blocking_questions.filter((q) => q.resolution_status === "open"), { example: true });
13498
+ list2("Important (open)", report.important_questions.filter((q) => q.resolution_status === "open"));
13433
13499
  list2("Resolved", report.resolved_questions);
13434
13500
  list2("Assumed", report.assumed_questions);
13435
13501
  list2("Deferred", report.deferred_status_questions);
13502
+ printResolutionGuide(es);
13436
13503
  console.log("");
13437
13504
  console.log("Suggested next:");
13438
13505
  console.log(report.recommended_next_step);
13439
13506
  printCommandFooter("questions");
13440
13507
  }
13508
+ function printResolutionGuide(es) {
13509
+ console.log("");
13510
+ if (es) {
13511
+ console.log("C\xF3mo resolver");
13512
+ console.log("");
13513
+ console.log("Edita el archivo indicado en Source y cambia el marcador:");
13514
+ console.log(" [open] \u2192 sigue abierta");
13515
+ console.log(" [resolved] \u2192 respuesta confirmada");
13516
+ console.log(" [assumed] \u2192 supuesto seguro por ahora");
13517
+ console.log(" [deferred] \u2192 decisi\xF3n aplazada");
13518
+ console.log("");
13519
+ console.log("Agrega una nota debajo de la pregunta cuando sea posible:");
13520
+ console.log(" - [assumed] \xBFPregunta?");
13521
+ console.log(" - note: Se asume X para el MVP porque Y.");
13522
+ } else {
13523
+ console.log("How to resolve");
13524
+ console.log("");
13525
+ console.log("Edit the file shown in Source and change the marker:");
13526
+ console.log(" [open] \u2192 still unresolved");
13527
+ console.log(" [resolved] \u2192 confirmed answer");
13528
+ console.log(" [assumed] \u2192 safe assumption for now");
13529
+ console.log(" [deferred] \u2192 intentionally postponed");
13530
+ console.log("");
13531
+ console.log("Add a note below the question when possible:");
13532
+ console.log(" - [assumed] Question?");
13533
+ console.log(" - note: Assume X for the MVP because Y.");
13534
+ }
13535
+ }
13441
13536
 
13442
13537
  // src/commands/adapters.ts
13443
13538
  var ADAPTER_LIST = ADAPTERS.map((a) => a.id).join(", ");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/cli",
3
- "version": "3.37.0",
3
+ "version": "3.38.0",
4
4
  "description": "Knowledge Driven Development toolkit",
5
5
  "license": "MIT",
6
6
  "repository": {