@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.
- package/README.md +2 -0
- package/dist/index.js +197 -102
- 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
|
|
7209
|
-
if (!
|
|
7210
|
-
const { text: text3, resolution_status } = parseResolution(
|
|
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.
|
|
7327
|
-
L.push(`-
|
|
7328
|
-
L.push(`-
|
|
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
|
-
|
|
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}
|
|
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/
|
|
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",
|
|
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
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7853
|
-
|
|
7854
|
-
|
|
7855
|
-
|
|
7856
|
-
|
|
7857
|
-
|
|
7858
|
-
|
|
7859
|
-
|
|
7860
|
-
|
|
7861
|
-
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
7865
|
-
|
|
7866
|
-
|
|
7867
|
-
}
|
|
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
|
|
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
|
-
|
|
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
|
|
8711
|
-
//
|
|
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:
|
|
8714
|
-
nextSteps:
|
|
8715
|
-
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 (
|
|
9226
|
-
|
|
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
|
-
|
|
13430
|
-
|
|
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(", ");
|