@kaddo/cli 3.45.0 → 3.47.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 (2) hide show
  1. package/dist/index.js +606 -27
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -8680,6 +8680,407 @@ function buildRoadmapQuality(dir) {
8680
8680
  return { initiatives, work_item_candidates };
8681
8681
  }
8682
8682
 
8683
+ // src/core/project-route.ts
8684
+ function isUseful(q) {
8685
+ return q === "useful";
8686
+ }
8687
+ var enableKaddo = {
8688
+ id: "enable-kaddo",
8689
+ label: "Enable Kaddo",
8690
+ evaluate: (ctx) => ({
8691
+ status: ctx.hasConfig ? "done" : "current",
8692
+ evidence: ctx.hasConfig ? [".kaddo/config.yml"] : void 0,
8693
+ command: ctx.hasConfig ? void 0 : "kaddo init"
8694
+ })
8695
+ };
8696
+ var scanRepository = {
8697
+ id: "scan-repository",
8698
+ label: "Scan repository",
8699
+ evaluate: (ctx) => ({
8700
+ status: ctx.hasScan ? "done" : ctx.hasConfig ? "pending" : "pending",
8701
+ evidence: ctx.hasScan ? [".kaddo/scan.json"] : void 0,
8702
+ command: ctx.hasScan ? void 0 : "kaddo scan"
8703
+ })
8704
+ };
8705
+ var defineBusiness = {
8706
+ id: "define-business",
8707
+ label: "Define business context",
8708
+ evaluate: (ctx) => ({
8709
+ status: isUseful(ctx.qBusiness) ? "done" : ctx.qBusiness === "missing" ? "pending" : "warning",
8710
+ evidence: isUseful(ctx.qBusiness) ? ["knowledge/business/business.md"] : void 0,
8711
+ reason: ctx.qBusiness === "placeholder" ? "Business context is still a bootstrap placeholder." : void 0,
8712
+ agent: isUseful(ctx.qBusiness) ? void 0 : "business-agent"
8713
+ })
8714
+ };
8715
+ var defineProduct = {
8716
+ id: "define-product",
8717
+ label: "Define product context",
8718
+ evaluate: (ctx) => ({
8719
+ status: isUseful(ctx.qProduct) ? "done" : ctx.qProduct === "missing" ? "pending" : "warning",
8720
+ evidence: isUseful(ctx.qProduct) ? ["knowledge/product/product.md"] : void 0,
8721
+ agent: isUseful(ctx.qProduct) ? void 0 : "capability-agent"
8722
+ })
8723
+ };
8724
+ var discoverCapabilities = {
8725
+ id: "discover-capabilities",
8726
+ label: "Discover capabilities",
8727
+ evaluate: (ctx) => ({
8728
+ status: isUseful(ctx.qCapabilities) ? "done" : ctx.qCapabilities === "missing" ? "pending" : "warning",
8729
+ evidence: isUseful(ctx.qCapabilities) ? ["knowledge/product/capabilities.md"] : void 0,
8730
+ agent: isUseful(ctx.qCapabilities) ? void 0 : "capability-agent"
8731
+ })
8732
+ };
8733
+ var describeArchitecture = {
8734
+ id: "describe-architecture",
8735
+ label: "Describe current architecture",
8736
+ evaluate: (ctx) => {
8737
+ const done = isUseful(ctx.qCurrentState) && isUseful(ctx.qCodebase);
8738
+ const evidence = [];
8739
+ if (isUseful(ctx.qCurrentState)) evidence.push("knowledge/tech/current-state.md");
8740
+ if (isUseful(ctx.qCodebase)) evidence.push("knowledge/tech/codebase.md");
8741
+ return {
8742
+ status: done ? "done" : "pending",
8743
+ evidence: evidence.length > 0 ? evidence : void 0,
8744
+ agent: done ? void 0 : "architecture-agent"
8745
+ };
8746
+ }
8747
+ };
8748
+ var captureTechDecisions = {
8749
+ id: "capture-technical-decisions",
8750
+ label: "Capture technical decisions",
8751
+ evaluate: (ctx) => {
8752
+ if (ctx.decisionCandidates === 0 && ctx.totalAdrs === 0) {
8753
+ return { status: "optional", reason: "No decision candidates found." };
8754
+ }
8755
+ if (ctx.totalAdrs > 0) {
8756
+ return { status: "done", evidence: ["knowledge/tech/decisions/"], reason: `${ctx.totalAdrs} ADR(s) exist.` };
8757
+ }
8758
+ return {
8759
+ status: "warning",
8760
+ reason: `${ctx.decisionCandidates} decision candidate(s) exist but no ADRs have been materialized.`,
8761
+ command: "kaddo adr",
8762
+ skill: "adr-writing"
8763
+ };
8764
+ }
8765
+ };
8766
+ var createWorkSource = {
8767
+ id: "create-work-source",
8768
+ label: "Create or connect work source",
8769
+ evaluate: (ctx) => ({
8770
+ status: ctx.hasRoadmap || ctx.totalWorkItems > 0 ? "done" : "pending",
8771
+ evidence: ctx.hasRoadmap ? ["knowledge/delivery/roadmap.md"] : void 0,
8772
+ command: ctx.hasRoadmap ? void 0 : "kaddo roadmap",
8773
+ agent: ctx.hasRoadmap ? void 0 : "roadmap-agent"
8774
+ })
8775
+ };
8776
+ var materializeWorkItem = {
8777
+ id: "materialize-work-item",
8778
+ label: "Materialize first Work Item",
8779
+ evaluate: (ctx) => {
8780
+ if (ctx.totalWorkItems > 0) {
8781
+ return { status: "done", evidence: ["knowledge/delivery/work-items/"] };
8782
+ }
8783
+ if (ctx.roadmapCandidates > 0) {
8784
+ return { status: "current", command: "kaddo create --from roadmap", reason: "Roadmap has candidates but no Work Item exists." };
8785
+ }
8786
+ return { status: "pending" };
8787
+ }
8788
+ };
8789
+ var refineWorkItem = {
8790
+ id: "refine-work-item",
8791
+ label: "Refine Work Item",
8792
+ evaluate: (ctx) => {
8793
+ if (ctx.readyWorkItems > 0 || ctx.inProgressWorkItems > 0) return { status: "done" };
8794
+ if (ctx.draftWorkItems > 0) {
8795
+ return {
8796
+ status: "current",
8797
+ reason: `There ${ctx.draftWorkItems === 1 ? "is" : "are"} ${ctx.draftWorkItems} draft Work Item${ctx.draftWorkItems === 1 ? "" : "s"} and no Work Item is ready.`,
8798
+ agent: "work-item-agent",
8799
+ skill: "work-item-refinement"
8800
+ };
8801
+ }
8802
+ return { status: "pending" };
8803
+ }
8804
+ };
8805
+ var suggestOwnership = {
8806
+ id: "suggest-ownership",
8807
+ label: "Suggest ownership",
8808
+ evaluate: (ctx) => {
8809
+ if (ctx.totalWorkItems === 0) return { status: "pending" };
8810
+ if (ctx.ownershipComplete) return { status: "done" };
8811
+ return {
8812
+ status: "next",
8813
+ reason: `Ownership coverage is ${ctx.ownershipCoverage}.`,
8814
+ command: "kaddo owners suggest"
8815
+ };
8816
+ }
8817
+ };
8818
+ var resolveAdrs = {
8819
+ id: "resolve-adrs",
8820
+ label: "Resolve ADRs if needed",
8821
+ evaluate: (ctx) => {
8822
+ if (ctx.decisionCandidates === 0 && ctx.totalAdrs === 0) return { status: "optional" };
8823
+ if (ctx.totalAdrs > 0) return { status: "done" };
8824
+ return {
8825
+ status: "warning",
8826
+ reason: `${ctx.decisionCandidates} decision candidate(s) without ADRs.`,
8827
+ command: "kaddo adr",
8828
+ skill: "adr-writing"
8829
+ };
8830
+ }
8831
+ };
8832
+ var prepareImplementation = {
8833
+ id: "prepare-implementation",
8834
+ label: "Prepare implementation",
8835
+ evaluate: (ctx) => {
8836
+ if (ctx.inProgressWorkItems > 0 || ctx.completedWorkItems > 0) return { status: "done" };
8837
+ if (ctx.readyWorkItems > 0) {
8838
+ if (ctx.adaptersInstalled === 0) {
8839
+ return { status: "current", reason: "Ready Work Items exist but no adapter is installed.", command: "kaddo adapters list" };
8840
+ }
8841
+ return { status: "current", agent: "implementation-agent" };
8842
+ }
8843
+ return { status: "pending" };
8844
+ }
8845
+ };
8846
+ var runGuard2 = {
8847
+ id: "run-guard",
8848
+ label: "Run guard",
8849
+ evaluate: (ctx) => {
8850
+ if (ctx.hasGuardHistory) return { status: "done", evidence: [".kaddo/history/guard-runs.jsonl"] };
8851
+ if (ctx.inProgressWorkItems > 0) return { status: "current", command: "kaddo guard" };
8852
+ return { status: "pending" };
8853
+ }
8854
+ };
8855
+ var captureLearning = {
8856
+ id: "capture-learning",
8857
+ label: "Capture learning",
8858
+ evaluate: (ctx) => {
8859
+ if (ctx.completedWorkItems > 0) return { status: "done" };
8860
+ if (ctx.totalWorkItems === 0) return { status: "optional", reason: "Project is still in early discovery." };
8861
+ return { status: "pending" };
8862
+ }
8863
+ };
8864
+ var identifyLegacyModules = {
8865
+ id: "identify-legacy-modules",
8866
+ label: "Identify legacy modules",
8867
+ evaluate: (ctx) => {
8868
+ const hasLegacy = exists(join(ctx.dir, "knowledge/legacy/risks.md"));
8869
+ return {
8870
+ status: hasLegacy ? "done" : "pending",
8871
+ evidence: hasLegacy ? ["knowledge/legacy/risks.md"] : void 0,
8872
+ agent: hasLegacy ? void 0 : "legacy-agent"
8873
+ };
8874
+ }
8875
+ };
8876
+ var identifyRisks = {
8877
+ id: "identify-risks",
8878
+ label: "Identify operational risks",
8879
+ evaluate: (ctx) => {
8880
+ const hasLegacy = exists(join(ctx.dir, "knowledge/legacy/risks.md"));
8881
+ return { status: hasLegacy ? "done" : "pending", agent: hasLegacy ? void 0 : "legacy-agent" };
8882
+ }
8883
+ };
8884
+ var NEW_STEPS = [
8885
+ enableKaddo,
8886
+ defineBusiness,
8887
+ defineProduct,
8888
+ { ...discoverCapabilities, label: "Define initial capabilities" },
8889
+ { ...describeArchitecture, label: "Define initial architecture" },
8890
+ { ...createWorkSource, label: "Create initial work source" },
8891
+ { ...materializeWorkItem, label: "Create first Work Item" },
8892
+ refineWorkItem,
8893
+ suggestOwnership,
8894
+ prepareImplementation,
8895
+ runGuard2,
8896
+ captureLearning
8897
+ ];
8898
+ var PRE_AI_STEPS = [
8899
+ enableKaddo,
8900
+ scanRepository,
8901
+ defineBusiness,
8902
+ defineProduct,
8903
+ discoverCapabilities,
8904
+ describeArchitecture,
8905
+ captureTechDecisions,
8906
+ createWorkSource,
8907
+ materializeWorkItem,
8908
+ refineWorkItem,
8909
+ suggestOwnership,
8910
+ resolveAdrs,
8911
+ prepareImplementation,
8912
+ runGuard2,
8913
+ captureLearning
8914
+ ];
8915
+ var LEGACY_STEPS = [
8916
+ enableKaddo,
8917
+ scanRepository,
8918
+ identifyLegacyModules,
8919
+ { ...discoverCapabilities, label: "Discover critical capabilities" },
8920
+ describeArchitecture,
8921
+ identifyRisks,
8922
+ captureTechDecisions,
8923
+ { ...createWorkSource, label: "Create modernization candidates" },
8924
+ { ...materializeWorkItem, label: "Materialize safe Work Item" },
8925
+ refineWorkItem,
8926
+ suggestOwnership,
8927
+ resolveAdrs,
8928
+ { ...prepareImplementation, label: "Prepare safe implementation" },
8929
+ runGuard2,
8930
+ captureLearning
8931
+ ];
8932
+ function stepsForState(state) {
8933
+ switch (state) {
8934
+ case "new":
8935
+ return NEW_STEPS;
8936
+ case "legacy":
8937
+ return LEGACY_STEPS;
8938
+ case "pre-ai":
8939
+ default:
8940
+ return PRE_AI_STEPS;
8941
+ }
8942
+ }
8943
+ function buildRouteContext(dir) {
8944
+ const config = loadConfig(dir);
8945
+ const hasScan = exists(join(dir, ".kaddo", "scan.json"));
8946
+ const hasInventory = exists(join(dir, "knowledge", "inventory.md"));
8947
+ const qa = (rel) => analyzeKnowledgeArtifact(dir, rel);
8948
+ const wis = discoverWorkItems(dir);
8949
+ const td = buildTechDecisions(dir);
8950
+ const roadmapPath = join(dir, "knowledge/delivery/roadmap.md");
8951
+ const hasRoadmap = exists(roadmapPath);
8952
+ let roadmapMd = null;
8953
+ if (hasRoadmap) {
8954
+ try {
8955
+ roadmapMd = readFile(roadmapPath);
8956
+ } catch {
8957
+ }
8958
+ }
8959
+ const stats = roadmapStats(roadmapMd, wis.length);
8960
+ const byState = (s) => wis.filter((w) => w.lifecycle === s).length;
8961
+ const total = wis.length;
8962
+ const withOwnership = wis.filter((w) => w.codeGlobs.length > 0).length;
8963
+ const adapters = installedAdapters(dir);
8964
+ const nextStep = resolveNextStep(dir);
8965
+ return {
8966
+ dir,
8967
+ hasConfig: config !== null,
8968
+ hasScan,
8969
+ hasInventory,
8970
+ qBusiness: qa("knowledge/business/business.md"),
8971
+ qProduct: qa("knowledge/product/product.md"),
8972
+ qCapabilities: qa("knowledge/product/capabilities.md"),
8973
+ qCurrentState: qa("knowledge/tech/current-state.md"),
8974
+ qCodebase: qa("knowledge/tech/codebase.md"),
8975
+ hasRoadmap,
8976
+ roadmapCandidates: stats.work_item_candidates,
8977
+ totalWorkItems: total,
8978
+ draftWorkItems: byState("draft"),
8979
+ readyWorkItems: byState("ready"),
8980
+ inProgressWorkItems: byState("in-progress"),
8981
+ completedWorkItems: byState("completed"),
8982
+ ownershipCoverage: `${withOwnership}/${total}`,
8983
+ ownershipComplete: total > 0 && withOwnership >= total,
8984
+ decisionCandidates: td.candidates,
8985
+ acceptedAdrs: td.accepted_adrs,
8986
+ draftAdrs: td.draft_adrs,
8987
+ totalAdrs: td.adrs,
8988
+ adaptersInstalled: adapters.length,
8989
+ hasGuardHistory: exists(join(dir, ".kaddo", "history", "guard-runs.jsonl")),
8990
+ nextStepId: mapNextStepId(nextStep.id)
8991
+ };
8992
+ }
8993
+ function mapNextStepId(id) {
8994
+ const MAP = {
8995
+ init: "enable-kaddo",
8996
+ bootstrap: "define-business",
8997
+ "add-agents": "enable-kaddo",
8998
+ "add-skills": "enable-kaddo",
8999
+ scan: "scan-repository",
9000
+ context: "scan-repository",
9001
+ understand: "scan-repository"
9002
+ };
9003
+ return MAP[id] ?? id;
9004
+ }
9005
+ function buildProjectRoute(dir) {
9006
+ const config = loadConfig(dir);
9007
+ const state = config?.project.state ?? "pre-ai";
9008
+ const defs = stepsForState(state);
9009
+ const ctx = buildRouteContext(dir);
9010
+ const steps = defs.map((d) => {
9011
+ const result = d.evaluate(ctx);
9012
+ return { id: d.id, label: d.label, ...result };
9013
+ });
9014
+ for (const s of steps) {
9015
+ if (s.id === ctx.nextStepId && s.status !== "done") {
9016
+ s.status = "current";
9017
+ }
9018
+ }
9019
+ let seenCurrent = false;
9020
+ for (const s of steps) {
9021
+ if (s.status === "current") seenCurrent = true;
9022
+ if (seenCurrent && s.status === "pending") {
9023
+ s.status = "next";
9024
+ break;
9025
+ }
9026
+ }
9027
+ const completed = steps.filter((s) => s.status === "done").length;
9028
+ const total = steps.length;
9029
+ const progressPercent = total > 0 ? Math.round(completed / total * 100) : 0;
9030
+ return {
9031
+ type: state,
9032
+ currentStep: steps.find((s) => s.status === "current")?.id ?? steps.find((s) => s.status !== "done")?.id ?? "complete",
9033
+ completed,
9034
+ total,
9035
+ progressPercent,
9036
+ steps
9037
+ };
9038
+ }
9039
+ var STATUS_MARKER = {
9040
+ done: "[x]",
9041
+ current: "[>]",
9042
+ next: "[ ]",
9043
+ pending: "[ ]",
9044
+ optional: "[o]",
9045
+ blocked: "[!]",
9046
+ warning: "[~]",
9047
+ skipped: "[-]"
9048
+ };
9049
+ function renderRouteMarkdown(route) {
9050
+ const lines = [];
9051
+ lines.push("## Project Route\n");
9052
+ lines.push(`Route: ${route.type}`);
9053
+ lines.push(`Progress: ${route.completed}/${route.total}
9054
+ `);
9055
+ for (const s of route.steps) {
9056
+ lines.push(`- ${STATUS_MARKER[s.status]} ${s.label}`);
9057
+ }
9058
+ lines.push("");
9059
+ return lines.join("\n");
9060
+ }
9061
+ function renderRouteCompact(route) {
9062
+ const lines = [];
9063
+ lines.push(`Route: ${route.type} \xB7 Progress: ${route.completed}/${route.total}
9064
+ `);
9065
+ const current = route.steps.find((s) => s.status === "current");
9066
+ if (current) {
9067
+ const agent = current.agent ? ` \u2014 ${current.agent}` : "";
9068
+ const skill2 = current.skill ? ` / ${current.skill}` : "";
9069
+ lines.push(`Current:
9070
+ - ${current.label}${agent}${skill2}
9071
+ `);
9072
+ }
9073
+ const warnings = route.steps.filter((s) => s.status === "warning");
9074
+ if (warnings.length > 0) {
9075
+ lines.push("Warnings:");
9076
+ for (const w of warnings) {
9077
+ lines.push(`- ${w.label}${w.reason ? ` \u2014 ${w.reason}` : ""}`);
9078
+ }
9079
+ lines.push("");
9080
+ }
9081
+ return lines.join("\n");
9082
+ }
9083
+
8683
9084
  // src/core/project-explain.ts
8684
9085
  var ARCH_DIR4 = "knowledge";
8685
9086
  function normalizeTitle(t) {
@@ -8905,7 +9306,8 @@ function buildProjectExplanation(dir) {
8905
9306
  }
8906
9307
  },
8907
9308
  installedAssets: installedAssetsSummary(dir),
8908
- roadmapQuality: buildRoadmapQuality(dir)
9309
+ roadmapQuality: buildRoadmapQuality(dir),
9310
+ projectRoute: buildProjectRoute(dir)
8909
9311
  };
8910
9312
  }
8911
9313
  function stateLabel(state) {
@@ -9080,6 +9482,7 @@ function renderExplanationHuman(exp) {
9080
9482
  lines.push("Review before continuing (non-blocking).");
9081
9483
  lines.push("");
9082
9484
  }
9485
+ lines.push(renderRouteMarkdown(exp.projectRoute));
9083
9486
  const assessment = assessPhase(exp);
9084
9487
  lines.push("## Phase");
9085
9488
  lines.push(`- Phase: ${assessment.phase}`);
@@ -9614,6 +10017,7 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
9614
10017
  graph: loadGraphSummary(dir),
9615
10018
  graphHints: loadGraphHints(dir),
9616
10019
  skills: discoverInstalledSkills(dir).map((s) => s.id),
10020
+ projectRoute: buildProjectRoute(dir),
9617
10021
  mappedModules,
9618
10022
  missing,
9619
10023
  // VS-052/VS-073.2: the handoff is driven by the unified next step, so the pack never contradicts
@@ -9690,6 +10094,8 @@ function renderContextPack(pack) {
9690
10094
  parts.push(rec.secondary.map((s) => `- ${s.label}`).join("\n") + "\n");
9691
10095
  }
9692
10096
  }
10097
+ parts.push("## Project Route\n");
10098
+ parts.push(renderRouteCompact(pack.projectRoute));
9693
10099
  parts.push("## Knowledge Layers\n");
9694
10100
  parts.push(
9695
10101
  "Project knowledge is organized in four layers: **Business \u2192 Product \u2192 Tech \u2192 Delivery**.\n"
@@ -9975,7 +10381,8 @@ function buildUnderstandPlan(dir, config) {
9975
10381
  name: config.project.name,
9976
10382
  state,
9977
10383
  teamSize: config.team.size,
9978
- structure: config.project.structure
10384
+ structure: config.project.structure,
10385
+ language: "English"
9979
10386
  },
9980
10387
  scanAvailable: exists(join(dir, ".kaddo", "scan.json")),
9981
10388
  contextPackPath: ".kaddo/context-pack.md",
@@ -9984,6 +10391,19 @@ function buildUnderstandPlan(dir, config) {
9984
10391
  steps
9985
10392
  };
9986
10393
  }
10394
+ function enrichUnderstandPlan(plan, opts) {
10395
+ return {
10396
+ ...plan,
10397
+ project: { ...plan.project, language: opts.language },
10398
+ phase: opts.phase,
10399
+ nextStepRecommendation: opts.nextStepRecommendation,
10400
+ deliveryState: opts.deliveryState,
10401
+ activeWorkItems: opts.activeWorkItems,
10402
+ recommendedPaths: opts.recommendedPaths,
10403
+ recommendedSkillPaths: opts.recommendedSkillPaths,
10404
+ projectRoute: opts.projectRoute
10405
+ };
10406
+ }
9987
10407
 
9988
10408
  // src/templates/understand-template.ts
9989
10409
  function stateLabel2(state) {
@@ -9994,42 +10414,144 @@ function agentName(file) {
9994
10414
  }
9995
10415
  function renderUnderstand(plan) {
9996
10416
  const { project, steps } = plan;
10417
+ const rec = plan.nextStepRecommendation;
10418
+ const ds = plan.deliveryState;
9997
10419
  const parts = [];
9998
10420
  parts.push("# Kaddo Understand Handoff\n");
9999
10421
  parts.push(
10000
10422
  "> Generated by `kaddo understand`. Kaddo does not call an LLM \u2014 you stay in control of the interpretation.\n"
10001
10423
  );
10002
10424
  parts.push("## Project\n");
10003
- parts.push(
10004
- [
10005
- `- Name: ${project.name}`,
10006
- `- State: ${project.state}`,
10007
- `- Team: ${project.teamSize}`,
10008
- `- Structure: ${project.structure}`
10009
- ].join("\n") + "\n"
10010
- );
10011
- parts.push("## Recommended Agent Flow\n");
10012
- parts.push(`Recommended order for a ${stateLabel2(project.state)} project:
10425
+ const projectLines = [
10426
+ `- Name: ${project.name}`,
10427
+ `- State: ${project.state}`,
10428
+ `- Team: ${project.teamSize}`,
10429
+ `- Structure: ${project.structure}`
10430
+ ];
10431
+ if (project.language) projectLines.push(`- Language: ${project.language}`);
10432
+ parts.push(projectLines.join("\n") + "\n");
10433
+ if (plan.phase && rec) {
10434
+ parts.push("## Current Phase\n");
10435
+ const phaseLines = [`- Phase: ${plan.phase}`];
10436
+ if (rec.agent) phaseLines.push(`- Recommended agent: ${agentName(rec.agent)}`);
10437
+ if (rec.skill) phaseLines.push(`- Recommended skill: ${rec.skill}`);
10438
+ phaseLines.push(`- Next step: ${rec.label}`);
10439
+ if (rec.reason) phaseLines.push(`- Reason: ${rec.reason}`);
10440
+ parts.push(phaseLines.join("\n") + "\n");
10441
+ }
10442
+ if (ds && ds.total_work_items > 0) {
10443
+ parts.push("## Delivery State\n");
10444
+ parts.push(
10445
+ [
10446
+ `- Draft Work Items: ${ds.draft_work_items}`,
10447
+ `- Ready Work Items: ${ds.ready_work_items}`,
10448
+ `- In-progress Work Items: ${ds.in_progress_work_items}`,
10449
+ `- Blocked Work Items: ${ds.blocked_work_items}`,
10450
+ `- Ownership coverage: ${ds.ownership_coverage}`,
10451
+ `- Remaining Work Item candidates: ${ds.remaining_work_item_candidates}`,
10452
+ `- Technical decision candidates: ${ds.decision_candidates}`,
10453
+ `- Accepted ADRs: ${ds.accepted_adrs}`,
10454
+ `- Installed adapters: ${ds.adapters_installed}`
10455
+ ].join("\n") + "\n"
10456
+ );
10457
+ }
10458
+ if (plan.projectRoute) {
10459
+ parts.push("## Project Route\n");
10460
+ parts.push(renderRouteCompact(plan.projectRoute));
10461
+ }
10462
+ if (steps.length > 0) {
10463
+ parts.push("## Recommended Agent Flow\n");
10464
+ parts.push(`Recommended order for a ${stateLabel2(project.state)} project:
10013
10465
  `);
10014
- parts.push(
10015
- steps.map((s, i) => {
10016
- const flag = s.installed ? "" : " _(not installed \u2014 run `kaddo add agents`)_";
10017
- return `${i + 1}. ${agentName(s.agent)} \u2192 \`${s.output}\`${flag}`;
10018
- }).join("\n") + "\n"
10019
- );
10466
+ parts.push(
10467
+ steps.map((s, i) => {
10468
+ const flag = s.installed ? "" : " _(not installed \u2014 run `kaddo add agents`)_";
10469
+ return `${i + 1}. ${agentName(s.agent)} \u2192 \`${s.output}\`${flag}`;
10470
+ }).join("\n") + "\n"
10471
+ );
10472
+ } else if (rec) {
10473
+ parts.push("## Recommended Agent Flow\n");
10474
+ const flowSteps = [];
10475
+ if (rec.agent) flowSteps.push(agentName(rec.agent));
10476
+ if (rec.secondary) {
10477
+ for (const s of rec.secondary) {
10478
+ if (s.agent) flowSteps.push(agentName(s.agent));
10479
+ else if (s.skill) flowSteps.push(`${s.skill} skill`);
10480
+ else if (s.command) flowSteps.push(`\`${s.command}\``);
10481
+ }
10482
+ }
10483
+ if (flowSteps.length > 0) {
10484
+ parts.push(flowSteps.map((f, i) => `${i + 1}. ${f}`).join("\n") + "\n");
10485
+ }
10486
+ }
10487
+ if (rec) {
10488
+ parts.push("## Primary Recommendation\n");
10489
+ const recLines = [`- id: ${rec.id}`];
10490
+ if (rec.agent) recLines.push(`- agent: ${agentName(rec.agent)}`);
10491
+ if (rec.skill) recLines.push(`- skill: ${rec.skill}`);
10492
+ if (rec.command) recLines.push(`- command: \`${rec.command}\``);
10493
+ recLines.push(`- reason: ${rec.reason}`);
10494
+ parts.push(recLines.join("\n") + "\n");
10495
+ }
10496
+ if (rec?.secondary && rec.secondary.length > 0) {
10497
+ parts.push("## Secondary Recommendations\n");
10498
+ parts.push(rec.secondary.map((s, i) => `${i + 1}. ${s.label}`).join("\n") + "\n");
10499
+ }
10500
+ if (plan.activeWorkItems && plan.activeWorkItems.length > 0) {
10501
+ parts.push("## Active Work Items\n");
10502
+ parts.push(
10503
+ plan.activeWorkItems.map((w) => `- ${w.id} [${w.type}] ${w.lifecycle} \u2014 ${w.title}`).join("\n") + "\n"
10504
+ );
10505
+ }
10020
10506
  parts.push("## Context Pack\n");
10021
10507
  const scanNote = plan.scanAvailable ? "" : " (incomplete \u2014 run `kaddo scan` first for a richer baseline)";
10022
10508
  parts.push(`Use \`${plan.contextPackPath}\` as the primary input${scanNote}.
10023
10509
  `);
10510
+ const agentPaths = [];
10511
+ if (plan.recommendedPaths && plan.recommendedPaths.length > 0) {
10512
+ agentPaths.push(...plan.recommendedPaths);
10513
+ } else if (steps.length > 0) {
10514
+ agentPaths.push(...steps.map((s) => agentInstallPath(s.agent)));
10515
+ }
10516
+ if (plan.recommendedSkillPaths && plan.recommendedSkillPaths.length > 0) {
10517
+ agentPaths.push(...plan.recommendedSkillPaths);
10518
+ }
10519
+ agentPaths.push(plan.contextPackPath);
10024
10520
  parts.push("## Agent Prompts\n");
10025
- parts.push(
10026
- steps.map((s) => `- \`${agentInstallPath(s.agent)}\``).join("\n") + "\n"
10027
- );
10028
- parts.push("## Expected Outputs\n");
10029
- parts.push(steps.map((s) => `- \`${s.output}\``).join("\n") + "\n");
10521
+ if (agentPaths.length > 1) {
10522
+ parts.push("Use:\n");
10523
+ parts.push(agentPaths.map((p2) => `- \`${p2}\``).join("\n") + "\n");
10524
+ } else {
10525
+ parts.push(`- \`${plan.contextPackPath}\`
10526
+ `);
10527
+ }
10528
+ if (steps.length > 0) {
10529
+ parts.push("## Expected Outputs\n");
10530
+ parts.push(steps.map((s) => `- \`${s.output}\``).join("\n") + "\n");
10531
+ } else if (rec) {
10532
+ parts.push("## Expected Outputs\n");
10533
+ const outputs = [];
10534
+ if (rec.target) outputs.push(`- \`${rec.target}\``);
10535
+ if (rec.id === "refine-work-item" || rec.id === "resolve-blocker")
10536
+ outputs.push("- Refined Work Item content.");
10537
+ if (rec.id === "create-work-item")
10538
+ outputs.push("- A new Work Item under `knowledge/delivery/work-items/`.");
10539
+ if (rec.id === "implement")
10540
+ outputs.push("- Implementation plan or code changes guided by the Work Item.");
10541
+ if (rec.id === "guard")
10542
+ outputs.push("- Updated knowledge artifacts reflecting recent code changes.");
10543
+ if (rec.id === "install-adapter")
10544
+ outputs.push("- An adapter configured and injected (`kaddo adapters list`).");
10545
+ if (outputs.length > 0) {
10546
+ parts.push("The LLM should produce:\n");
10547
+ parts.push(outputs.join("\n") + "\n");
10548
+ } else {
10549
+ parts.push("_See the primary recommendation above._\n");
10550
+ }
10551
+ }
10030
10552
  parts.push("## Copy/Paste Instructions\n");
10031
- const first2 = steps[0];
10032
- if (first2) {
10553
+ if (steps.length > 0) {
10554
+ const first2 = steps[0];
10033
10555
  parts.push(
10034
10556
  [
10035
10557
  `Start with **${agentName(first2.agent)}**:`,
@@ -10041,9 +10563,31 @@ function renderUnderstand(plan) {
10041
10563
  `5. Save the result in: \`${first2.output}\``
10042
10564
  ].join("\n") + "\n"
10043
10565
  );
10566
+ } else if (agentPaths.length > 1) {
10567
+ parts.push("Paste the following into your LLM chat:\n");
10568
+ parts.push(agentPaths.map((p2, i) => `${i + 1}. \`${p2}\``).join("\n") + "\n");
10569
+ if (rec?.agent) {
10570
+ parts.push(`Ask the LLM to follow the ${agentName(rec.agent)} instructions.
10571
+ `);
10572
+ }
10573
+ } else {
10574
+ parts.push(`Paste \`${plan.contextPackPath}\` into your LLM chat.
10575
+ `);
10044
10576
  }
10045
10577
  parts.push("## Next Steps\n");
10046
- if (steps.length > 1) {
10578
+ if (rec) {
10579
+ const nextLines = [];
10580
+ nextLines.push(`1. ${rec.label}`);
10581
+ let n = 2;
10582
+ if (rec.secondary) {
10583
+ for (const s of rec.secondary) {
10584
+ nextLines.push(`${n}. ${s.label}`);
10585
+ n++;
10586
+ }
10587
+ }
10588
+ nextLines.push(`${n}. Re-run \`kaddo explain\`.`);
10589
+ parts.push(nextLines.join("\n") + "\n");
10590
+ } else if (steps.length > 1) {
10047
10591
  parts.push(
10048
10592
  `After saving \`${steps[0].output}\`, continue with **${agentName(steps[1].agent)}** (feed it the context pack plus the artifacts you already produced). Re-run \`kaddo understand\` any time to see this plan again.
10049
10593
  `
@@ -10268,7 +10812,42 @@ function runUnderstand() {
10268
10812
  console.log(`Other active work items: ${active.slice(1).map((w) => w.id).join(", ")}`);
10269
10813
  }
10270
10814
  }
10271
- writeFile(join(dir, ".kaddo", "understand.md"), renderUnderstand(plan));
10815
+ const ds = buildDeliveryState(dir);
10816
+ ds.phase = assessment.phase;
10817
+ const wis = discoverWorkItems(dir);
10818
+ const activeWis = wis.filter((w) => w.lifecycle && ["draft", "ready", "in-progress", "blocked"].includes(w.lifecycle)).map((w) => ({
10819
+ id: w.id,
10820
+ title: w.title,
10821
+ type: w.type,
10822
+ lifecycle: w.lifecycle ?? "draft",
10823
+ knowledgeLevel: w.knowledgeLevel,
10824
+ hasOwnership: w.codeGlobs.length > 0
10825
+ }));
10826
+ const recommendedPaths = [];
10827
+ if (rec.agent) {
10828
+ const agentFile = rec.agent.endsWith(".md") ? rec.agent : `${rec.agent}.md`;
10829
+ if (agentIsInstalled(dir, agentFile)) {
10830
+ recommendedPaths.push(agentInstallPath(agentFile));
10831
+ }
10832
+ }
10833
+ const recommendedSkillPaths = [];
10834
+ if (rec.skill) {
10835
+ const sp = skillInstallPath(rec.skill);
10836
+ if (exists(join(dir, sp))) {
10837
+ recommendedSkillPaths.push(sp);
10838
+ }
10839
+ }
10840
+ const enrichedPlan = enrichUnderstandPlan(plan, {
10841
+ phase: assessment.phase,
10842
+ nextStepRecommendation: rec,
10843
+ deliveryState: ds,
10844
+ activeWorkItems: activeWis,
10845
+ recommendedPaths,
10846
+ recommendedSkillPaths,
10847
+ language: languageLabel(projectLanguage(config)),
10848
+ projectRoute: buildProjectRoute(dir)
10849
+ });
10850
+ writeFile(join(dir, ".kaddo", "understand.md"), renderUnderstand(enrichedPlan));
10272
10851
  log2.success("Wrote .kaddo/understand.md");
10273
10852
  printCommandFooter("understand");
10274
10853
  outro2("Handoff ready. CLI prepares context \u2014 your LLM creates the understanding.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/cli",
3
- "version": "3.45.0",
3
+ "version": "3.47.0",
4
4
  "description": "Knowledge Driven Development toolkit",
5
5
  "license": "MIT",
6
6
  "repository": {