@kaddo/cli 3.48.0 → 3.50.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 +254 -77
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5396,6 +5396,7 @@ function buildFrontMatter(id, type, level, title, answers) {
5396
5396
  `domains: []`,
5397
5397
  `code: []`,
5398
5398
  `created_at: ${today2}`,
5399
+ `source: manual`,
5399
5400
  `summary: "${answers.problem?.split(".")[0] ?? title}"`,
5400
5401
  "---"
5401
5402
  ];
@@ -5482,6 +5483,7 @@ function buildModuleFrontMatter(id, modType, title, answers) {
5482
5483
  `domains: []`,
5483
5484
  `code: []`,
5484
5485
  `created_at: ${today2}`,
5486
+ `source: manual`,
5485
5487
  `summary: "${title}"`,
5486
5488
  ...extraLines,
5487
5489
  "---"
@@ -5661,6 +5663,8 @@ function buildRoadmapFrontMatter(id, type, level, title, candidate, answers) {
5661
5663
  // from the specific Work Item candidate it was materialized from.
5662
5664
  `source_roadmap_initiative: ${candidate.initiative?.id ?? "unknown"}`,
5663
5665
  `source_work_item_candidate: ${candidate.id}`,
5666
+ `source_title: "${q(candidate.title)}"`,
5667
+ `source_context: "Materialized from roadmap candidate ${candidate.id}${candidate.initiative?.id ? ` under initiative ${candidate.initiative.id}` : ""}."`,
5664
5668
  ...candidate.initiative?.title ? [`source_initiative_title: "${q(candidate.initiative.title)}"`] : [],
5665
5669
  ...candidate.domain ? [`related_domain: "${q(candidate.domain)}"`] : [],
5666
5670
  ...yamlList2("related_capabilities", relatedCapabilities),
@@ -5930,6 +5934,7 @@ function parseArtifact(filePath, raw) {
5930
5934
  initiative: String(data.initiative ?? data.source_initiative ?? ""),
5931
5935
  source: data.source ? String(data.source) : "",
5932
5936
  sourceId: String(data.source_id ?? ""),
5937
+ rawFrontmatter: data,
5933
5938
  decisions: Array.isArray(data.decisions) ? data.decisions.map(String).filter(Boolean) : [],
5934
5939
  capsules: Array.isArray(data.capsules) ? data.capsules.map(String).filter(Boolean) : []
5935
5940
  };
@@ -9047,7 +9052,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
9047
9052
  const ctx = buildCodexAdapterContext(dir);
9048
9053
  const agents = ctx.hasAgents ? "present" : "missing";
9049
9054
  const skills = ctx.hasSkills ? "present" : "missing";
9050
- const bootstrapBaseline = presence.business !== "missing" && presence.product !== "missing" ? "complete" : "incomplete";
9055
+ const bootstrapBaseline2 = presence.business !== "missing" && presence.product !== "missing" ? "complete" : "incomplete";
9051
9056
  const roadmap = roadmapSignal(dir);
9052
9057
  const work_items = workItemsSignal(dir);
9053
9058
  const adapters = installedAdapters(dir);
@@ -9055,7 +9060,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
9055
9060
  const signals = {
9056
9061
  scan: scan2,
9057
9062
  understand,
9058
- bootstrap_baseline: bootstrapBaseline,
9063
+ bootstrap_baseline: bootstrapBaseline2,
9059
9064
  agents,
9060
9065
  skills,
9061
9066
  current_state: presence.current_state,
@@ -9074,7 +9079,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
9074
9079
  const firstWeak = KNOWLEDGE_FILES.find((f) => presence[f.key] !== "useful");
9075
9080
  let overall;
9076
9081
  if (scan2 === "missing") overall = "initialized";
9077
- else if (bootstrapBaseline === "incomplete") overall = "bootstrap-incomplete";
9082
+ else if (bootstrapBaseline2 === "incomplete") overall = "bootstrap-incomplete";
9078
9083
  else if (agents === "missing") overall = "agents-missing";
9079
9084
  else if (skills === "missing") overall = "skills-missing";
9080
9085
  else if (understand === "missing") overall = "scanned";
@@ -9241,6 +9246,84 @@ function buildRoadmapQuality(dir) {
9241
9246
  return { initiatives, work_item_candidates };
9242
9247
  }
9243
9248
 
9249
+ // src/core/work-item-source.ts
9250
+ var VALID_SOURCES = [
9251
+ "manual",
9252
+ "roadmap",
9253
+ "jira",
9254
+ "github",
9255
+ "notion",
9256
+ "xlsx",
9257
+ "csv",
9258
+ "api",
9259
+ "external",
9260
+ "unknown"
9261
+ ];
9262
+ function isValidSource(s) {
9263
+ return VALID_SOURCES.includes(s);
9264
+ }
9265
+ function parseWorkItemSource(frontmatter) {
9266
+ const raw = frontmatter.source ? String(frontmatter.source) : "";
9267
+ if (raw && isValidSource(raw)) {
9268
+ return {
9269
+ type: raw,
9270
+ id: optStr(frontmatter.source_id),
9271
+ title: optStr(frontmatter.source_title),
9272
+ context: optStr(frontmatter.source_context),
9273
+ provider: optStr(frontmatter.source_provider),
9274
+ url: optStr(frontmatter.source_url),
9275
+ imported_at: optStr(frontmatter.source_imported_at),
9276
+ synced_at: optStr(frontmatter.source_synced_at),
9277
+ inferred: false
9278
+ };
9279
+ }
9280
+ if (raw && !isValidSource(raw)) {
9281
+ return {
9282
+ type: "unknown",
9283
+ id: optStr(frontmatter.source_id),
9284
+ title: optStr(frontmatter.source_title),
9285
+ context: optStr(frontmatter.source_context),
9286
+ provider: optStr(frontmatter.source_provider),
9287
+ url: optStr(frontmatter.source_url),
9288
+ imported_at: optStr(frontmatter.source_imported_at),
9289
+ synced_at: optStr(frontmatter.source_synced_at),
9290
+ inferred: true,
9291
+ reason: `Invalid source value: "${raw}".`
9292
+ };
9293
+ }
9294
+ if (frontmatter.source_work_item_candidate || frontmatter.source_roadmap_initiative) {
9295
+ return {
9296
+ type: "roadmap",
9297
+ id: optStr(frontmatter.source_id) ?? optStr(frontmatter.source_work_item_candidate),
9298
+ title: optStr(frontmatter.source_initiative_title),
9299
+ inferred: true,
9300
+ reason: "Inferred from legacy roadmap fields."
9301
+ };
9302
+ }
9303
+ if (frontmatter.source_id) {
9304
+ return {
9305
+ type: "unknown",
9306
+ id: optStr(frontmatter.source_id),
9307
+ inferred: true,
9308
+ reason: "Has source_id but no source type."
9309
+ };
9310
+ }
9311
+ return {
9312
+ type: "unknown",
9313
+ inferred: true,
9314
+ reason: "No source metadata found."
9315
+ };
9316
+ }
9317
+ function renderSourceCompact(source) {
9318
+ const parts = [source.type];
9319
+ if (source.id) parts.push(source.id);
9320
+ return parts.join(" \xB7 ");
9321
+ }
9322
+ function optStr(v) {
9323
+ if (typeof v === "string" && v.trim()) return v.trim();
9324
+ return void 0;
9325
+ }
9326
+
9244
9327
  // src/core/project-route.ts
9245
9328
  function isUseful(q) {
9246
9329
  return q === "useful";
@@ -9263,6 +9346,14 @@ var scanRepository = {
9263
9346
  return { status: "done", evidence: [".kaddo/scan.json"] };
9264
9347
  }
9265
9348
  };
9349
+ var bootstrapBaseline = {
9350
+ id: "bootstrap",
9351
+ label: "Bootstrap knowledge baseline",
9352
+ evaluate: (ctx) => {
9353
+ if (ctx.qBusiness !== "missing" && ctx.qProduct !== "missing") return { status: "done", evidence: ["knowledge/business/business.md", "knowledge/product/product.md"] };
9354
+ return { status: "pending", command: "kaddo bootstrap", reason: "The knowledge baseline is incomplete." };
9355
+ }
9356
+ };
9266
9357
  var defineBusiness = {
9267
9358
  id: "define-business",
9268
9359
  label: "Define business context",
@@ -9327,12 +9418,12 @@ var captureTechDecisions = {
9327
9418
  var createWorkSource = {
9328
9419
  id: "create-work-source",
9329
9420
  label: "Create or connect work source",
9330
- evaluate: (ctx) => ({
9331
- status: ctx.hasRoadmap || ctx.totalWorkItems > 0 ? "done" : "pending",
9332
- evidence: ctx.hasRoadmap ? ["knowledge/delivery/roadmap.md"] : void 0,
9333
- command: ctx.hasRoadmap ? void 0 : "kaddo roadmap",
9334
- agent: ctx.hasRoadmap ? void 0 : "roadmap-agent"
9335
- })
9421
+ evaluate: (ctx) => {
9422
+ if (!ctx.hasRoadmap && ctx.totalWorkItems === 0) return { status: "pending", command: "kaddo roadmap", agent: "roadmap-agent" };
9423
+ if (ctx.hasUnknownSources) return { status: "warning", evidence: ["Work Items with unknown source"], reason: "Some Work Items have no source metadata." };
9424
+ const evidence = ctx.hasRoadmap ? ["knowledge/delivery/roadmap.md"] : void 0;
9425
+ return { status: "done", evidence };
9426
+ }
9336
9427
  };
9337
9428
  var materializeWorkItem = {
9338
9429
  id: "materialize-work-item",
@@ -9459,6 +9550,7 @@ var NEW_STEPS = [
9459
9550
  var PRE_AI_STEPS = [
9460
9551
  enableKaddo,
9461
9552
  scanRepository,
9553
+ bootstrapBaseline,
9462
9554
  defineBusiness,
9463
9555
  defineProduct,
9464
9556
  discoverCapabilities,
@@ -9476,6 +9568,7 @@ var PRE_AI_STEPS = [
9476
9568
  var LEGACY_STEPS = [
9477
9569
  enableKaddo,
9478
9570
  scanRepository,
9571
+ bootstrapBaseline,
9479
9572
  identifyLegacyModules,
9480
9573
  { ...discoverCapabilities, label: "Discover critical capabilities" },
9481
9574
  describeArchitecture,
@@ -9549,6 +9642,10 @@ function buildRouteContext(dir) {
9549
9642
  adaptersInstalled: adapters.length,
9550
9643
  hasGuardHistory: exists(join(dir, ".kaddo", "history", "guard-runs.jsonl")),
9551
9644
  hasScanWarnings: hasScan ? loadScanWarnings(dir) : false,
9645
+ hasUnknownSources: wis.some((w) => {
9646
+ const src = parseWorkItemSource(w.rawFrontmatter);
9647
+ return src.type === "unknown" && src.inferred;
9648
+ }),
9552
9649
  nextStepId: mapNextStepId(nextStep.id)
9553
9650
  };
9554
9651
  }
@@ -9563,7 +9660,7 @@ function loadScanWarnings(dir) {
9563
9660
  function mapNextStepId(id) {
9564
9661
  const MAP = {
9565
9662
  init: "enable-kaddo",
9566
- bootstrap: "define-business",
9663
+ bootstrap: "bootstrap",
9567
9664
  "add-agents": "enable-kaddo",
9568
9665
  "add-skills": "enable-kaddo",
9569
9666
  scan: "scan-repository",
@@ -9732,6 +9829,15 @@ function hasAgents(dir) {
9732
9829
  }
9733
9830
  return hasAgentMd(agentsDir);
9734
9831
  }
9832
+ function hasSkills(dir) {
9833
+ const skillsDir = join(dir, ARCH_DIR4, "skills");
9834
+ if (!exists(skillsDir)) return false;
9835
+ try {
9836
+ return readDir(skillsDir).some((e) => e.endsWith(".md") && isFile(join(skillsDir, e)));
9837
+ } catch {
9838
+ return false;
9839
+ }
9840
+ }
9735
9841
  function buildProjectExplanation(dir) {
9736
9842
  const config = loadConfig(dir);
9737
9843
  const project = {
@@ -9758,23 +9864,30 @@ function buildProjectExplanation(dir) {
9758
9864
  hasInventory: exists(join(dir, ARCH_DIR4, "inventory.md")),
9759
9865
  hasContextPack: exists(join(dir, ".kaddo", "context-pack.md")),
9760
9866
  hasUnderstand: exists(join(dir, ".kaddo", "understand.md")),
9867
+ hasBusiness: exists(join(dir, "knowledge/business/business.md")),
9868
+ hasProduct: exists(join(dir, "knowledge/product/product.md")),
9761
9869
  hasCapabilities: layerStatus("Product") !== "Missing",
9762
9870
  hasArchitecture: layerStatus("Tech") !== "Missing",
9763
9871
  hasRoadmap: layerStatus("Delivery") !== "Missing",
9764
- hasAgents: hasAgents(dir)
9872
+ hasAgents: hasAgents(dir),
9873
+ hasSkills: hasSkills(dir)
9765
9874
  };
9766
9875
  const workItemArtifacts = discoverWorkItems(dir);
9767
- const items = workItemArtifacts.map((a) => ({
9768
- id: a.id || a.title,
9769
- title: a.title,
9770
- type: a.type,
9771
- status: a.status,
9772
- lifecycle: lifecycleStateOf({ status: a.status, filePath: a.filePath }),
9773
- initiative: a.initiative,
9774
- knowledgeLevel: a.knowledgeLevel,
9775
- hasOwnership: a.codeGlobs.length > 0,
9776
- domains: a.domains
9777
- }));
9876
+ const items = workItemArtifacts.map((a) => {
9877
+ const src = parseWorkItemSource(a.rawFrontmatter);
9878
+ return {
9879
+ id: a.id || a.title,
9880
+ title: a.title,
9881
+ type: a.type,
9882
+ status: a.status,
9883
+ lifecycle: lifecycleStateOf({ status: a.status, filePath: a.filePath }),
9884
+ initiative: a.initiative,
9885
+ knowledgeLevel: a.knowledgeLevel,
9886
+ hasOwnership: a.codeGlobs.length > 0,
9887
+ domains: a.domains,
9888
+ source: { type: src.type, ...src.id ? { id: src.id } : {}, inferred: src.inferred }
9889
+ };
9890
+ });
9778
9891
  const byState = lifecycleCounts(items.map((i) => i.lifecycle));
9779
9892
  const byType = {};
9780
9893
  for (const i of items) {
@@ -9822,33 +9935,42 @@ function buildProjectExplanation(dir) {
9822
9935
  if (!knowledge.hasAgents) missingKnowledge.push("Agents (knowledge/agents/)");
9823
9936
  if (items.length === 0) missingKnowledge.push("Work items (knowledge/delivery/work-items/)");
9824
9937
  const suggestedNextSteps = [];
9825
- if (!knowledge.hasScan) {
9826
- suggestedNextSteps.push("Run `kaddo scan` to detect the technical stack.");
9827
- } else if (!knowledge.hasContextPack) {
9828
- suggestedNextSteps.push("Run `kaddo context` to prepare an LLM context pack.");
9829
- }
9830
- if (!knowledge.hasAgents) {
9831
- suggestedNextSteps.push("Run `kaddo add agents` to install knowledge agents.");
9832
- }
9833
- if (!knowledge.hasCapabilities) {
9834
- suggestedNextSteps.push("Use capability-agent to generate knowledge/product/capabilities.md.");
9835
- }
9836
- if (!knowledge.hasArchitecture) {
9837
- suggestedNextSteps.push("Use architecture-agent to generate knowledge/tech/current-state.md.");
9838
- }
9839
- if (!knowledge.hasRoadmap) {
9840
- suggestedNextSteps.push("Use roadmap-agent to generate knowledge/delivery/roadmap.md.");
9841
- } else if (roadmap.remaining > 0) {
9842
- suggestedNextSteps.push(
9843
- `Materialize ${roadmap.remaining} roadmap candidate(s) with \`kaddo create --from roadmap\`.`
9844
- );
9845
- }
9846
- if (items.length === 0 && !roadmap.present) {
9847
- suggestedNextSteps.push("Create your first Work Item with `kaddo create`.");
9848
- } else if (ownership.workItemsMissingOwnership > 0) {
9849
- suggestedNextSteps.push(
9850
- "Run `kaddo owners suggest` for Work Items without code ownership."
9851
- );
9938
+ const baselineIncomplete = !knowledge.hasBusiness || !knowledge.hasProduct;
9939
+ if (baselineIncomplete) {
9940
+ suggestedNextSteps.push("Run `kaddo bootstrap` to create the project knowledge baseline.");
9941
+ if (!knowledge.hasAgents) suggestedNextSteps.push("Then run `kaddo add agents`.");
9942
+ if (!knowledge.hasSkills) suggestedNextSteps.push("Then run `kaddo add skills`.");
9943
+ suggestedNextSteps.push("Then run `kaddo context`.");
9944
+ suggestedNextSteps.push("Then run `kaddo understand`.");
9945
+ } else {
9946
+ if (!knowledge.hasScan) {
9947
+ suggestedNextSteps.push("Run `kaddo scan` to detect the technical stack.");
9948
+ } else if (!knowledge.hasContextPack) {
9949
+ suggestedNextSteps.push("Run `kaddo context` to prepare an LLM context pack.");
9950
+ }
9951
+ if (!knowledge.hasAgents) {
9952
+ suggestedNextSteps.push("Run `kaddo add agents` to install knowledge agents.");
9953
+ }
9954
+ if (!knowledge.hasCapabilities) {
9955
+ suggestedNextSteps.push("Use capability-agent to generate knowledge/product/capabilities.md.");
9956
+ }
9957
+ if (!knowledge.hasArchitecture) {
9958
+ suggestedNextSteps.push("Use architecture-agent to generate knowledge/tech/current-state.md.");
9959
+ }
9960
+ if (!knowledge.hasRoadmap) {
9961
+ suggestedNextSteps.push("Use roadmap-agent to generate knowledge/delivery/roadmap.md.");
9962
+ } else if (roadmap.remaining > 0) {
9963
+ suggestedNextSteps.push(
9964
+ `Materialize ${roadmap.remaining} roadmap candidate(s) with \`kaddo create --from roadmap\`.`
9965
+ );
9966
+ }
9967
+ if (items.length === 0 && !roadmap.present) {
9968
+ suggestedNextSteps.push("Create your first Work Item with `kaddo create`.");
9969
+ } else if (ownership.workItemsMissingOwnership > 0) {
9970
+ suggestedNextSteps.push(
9971
+ "Run `kaddo owners suggest` for Work Items without code ownership."
9972
+ );
9973
+ }
9852
9974
  }
9853
9975
  const readiness = buildReadinessReport(dir);
9854
9976
  return {
@@ -9971,6 +10093,17 @@ function renderExplanationHuman(exp) {
9971
10093
  for (const [t, n] of typeEntries) lines.push(`- ${typeLabel(t)}: ${n}`);
9972
10094
  lines.push("");
9973
10095
  }
10096
+ const sourceCounts = {};
10097
+ for (const i of exp.workItems.items) {
10098
+ const t = i.source?.type ?? "unknown";
10099
+ sourceCounts[t] = (sourceCounts[t] ?? 0) + 1;
10100
+ }
10101
+ const sourceEntries = Object.entries(sourceCounts).filter(([, n]) => n > 0);
10102
+ if (sourceEntries.length > 0) {
10103
+ lines.push("## Work Item Sources");
10104
+ for (const [t, n] of sourceEntries) lines.push(`- ${t.charAt(0).toUpperCase() + t.slice(1)}: ${n}`);
10105
+ lines.push("");
10106
+ }
9974
10107
  const grouped = exp.workItems.initiatives.filter(
9975
10108
  (g) => LIFECYCLE_STATES.some((s2) => g.states[s2] > 0)
9976
10109
  );
@@ -10439,7 +10572,8 @@ function toContextWorkItem(a) {
10439
10572
  status: a.status,
10440
10573
  lifecycle: lifecycleStateOf({ status: a.status, filePath: a.filePath }),
10441
10574
  knowledgeLevel: a.knowledgeLevel,
10442
- domains: a.domains
10575
+ domains: a.domains,
10576
+ source: parseWorkItemSource(a.rawFrontmatter)
10443
10577
  };
10444
10578
  }
10445
10579
  function toContextArtifact(a) {
@@ -10780,7 +10914,10 @@ function renderContextPack(pack) {
10780
10914
  const level = wi.knowledgeLevel ? ` [${wi.knowledgeLevel}]` : "";
10781
10915
  const status = wi.lifecycle ? ` (${wi.lifecycle})` : wi.status ? ` (${wi.status})` : "";
10782
10916
  const domains = wi.domains.length > 0 ? ` \xB7 domains: ${wi.domains.join(", ")}` : "";
10783
- return `- ${wi.id || wi.title} [${wi.type}]${level}${status} \u2014 ${wi.title}${domains}`;
10917
+ const line = `- ${wi.id || wi.title} [${wi.type}]${level}${status} \u2014 ${wi.title}${domains}`;
10918
+ const src = wi.source && wi.source.type !== "unknown" ? `
10919
+ - Source: ${renderSourceCompact(wi.source)}` : "";
10920
+ return `${line}${src}`;
10784
10921
  });
10785
10922
  parts.push(lines.join("\n") + "\n");
10786
10923
  } else {
@@ -10872,19 +11009,35 @@ function renderContextPack(pack) {
10872
11009
  parts.push(pack.skills.map((s) => `- ${s}`).join("\n") + "\n");
10873
11010
  parts.push("Read full skill definitions in `knowledge/skills/` or via the Kaddo MCP server (`kaddo://skills`).\n");
10874
11011
  }
11012
+ const isBootstrapIncomplete = rec.id === "bootstrap";
10875
11013
  parts.push("## Missing Context\n");
10876
- if (missing.length > 0) {
11014
+ if (isBootstrapIncomplete) {
11015
+ const baselineMissing = [
11016
+ "- Bootstrap baseline is incomplete.",
11017
+ ...!pack.knowledgeQuality.business || pack.knowledgeQuality.business.status === "Missing" ? ["- Missing business knowledge."] : [],
11018
+ ...!pack.knowledgeQuality.product || pack.knowledgeQuality.product.status === "Missing" ? ["- Missing product knowledge."] : []
11019
+ ];
11020
+ if (missing.length > 0) {
11021
+ baselineMissing.push(...missing.filter((m) => !baselineMissing.some((b) => b.includes(m))));
11022
+ }
11023
+ parts.push(baselineMissing.join("\n") + "\n");
11024
+ } else if (missing.length > 0) {
10877
11025
  parts.push(missing.map((m) => `- ${m}`).join("\n") + "\n");
10878
11026
  } else {
10879
11027
  parts.push("_None \u2014 all expected context is present._\n");
10880
11028
  }
10881
11029
  parts.push("## Recommended Agent Handoff\n");
10882
- parts.push(`Recommended next for the **${pack.phase.phase}** phase:
11030
+ if (isBootstrapIncomplete) {
11031
+ parts.push("No agent handoff yet.\n");
11032
+ parts.push("Run `kaddo bootstrap` first to create the baseline files.\n");
11033
+ } else {
11034
+ parts.push(`Recommended next for the **${pack.phase.phase}** phase:
10883
11035
  `);
10884
- parts.push(handoff.recommendedAgents.map((a, i) => `${i + 1}. ${a}`).join("\n") + "\n");
10885
- if (handoff.nextSteps.length > 0) {
10886
- parts.push("Next step:\n");
10887
- parts.push(handoff.nextSteps.map((s) => `- ${s}`).join("\n") + "\n");
11036
+ parts.push(handoff.recommendedAgents.map((a, i) => `${i + 1}. ${a}`).join("\n") + "\n");
11037
+ if (handoff.nextSteps.length > 0) {
11038
+ parts.push("Next step:\n");
11039
+ parts.push(handoff.nextSteps.map((s) => `- ${s}`).join("\n") + "\n");
11040
+ }
10888
11041
  }
10889
11042
  parts.push("## Instructions for the LLM\n");
10890
11043
  parts.push(handoff.instructions.map((i) => `- ${i}`).join("\n") + "\n");
@@ -11049,7 +11202,12 @@ function renderUnderstand(plan) {
11049
11202
  parts.push("## Project Route\n");
11050
11203
  parts.push(renderRouteCompact(plan.projectRoute));
11051
11204
  }
11052
- if (steps.length > 0) {
11205
+ const isBootstrap = rec && rec.id === "bootstrap";
11206
+ if (isBootstrap) {
11207
+ parts.push("## Agent Handoff\n");
11208
+ parts.push("Agent handoff is not ready yet.\n");
11209
+ parts.push("Run `kaddo bootstrap` first.\n");
11210
+ } else if (steps.length > 0) {
11053
11211
  parts.push("## Recommended Agent Flow\n");
11054
11212
  parts.push(`Recommended order for a ${stateLabel2(project.state)} project:
11055
11213
  `);
@@ -11090,7 +11248,11 @@ function renderUnderstand(plan) {
11090
11248
  if (plan.activeWorkItems && plan.activeWorkItems.length > 0) {
11091
11249
  parts.push("## Active Work Items\n");
11092
11250
  parts.push(
11093
- plan.activeWorkItems.map((w) => `- ${w.id} [${w.type}] ${w.lifecycle} \u2014 ${w.title}`).join("\n") + "\n"
11251
+ plan.activeWorkItems.map((w) => {
11252
+ const src = w.source && w.source.type !== "unknown" ? `
11253
+ - Source: ${w.source.type}${w.source.id ? ` \xB7 ${w.source.id}` : ""}` : "";
11254
+ return `- ${w.id} [${w.type}] ${w.lifecycle} \u2014 ${w.title}${src}`;
11255
+ }).join("\n") + "\n"
11094
11256
  );
11095
11257
  }
11096
11258
  parts.push("## Context Pack\n");
@@ -11198,25 +11360,36 @@ function renderUnderstandTerminal(plan) {
11198
11360
  lines.push(`Team: ${project.teamSize}`);
11199
11361
  lines.push(`Structure: ${project.structure}`);
11200
11362
  lines.push("");
11201
- const first2 = steps[0];
11202
- if (first2) {
11203
- lines.push("Foundational knowledge still needed:");
11204
- steps.forEach((s, i) => {
11205
- const flag = s.installed ? "" : " (not installed)";
11206
- lines.push(` ${i + 1}. ${agentName(s.agent)} \u2192 ${s.output}${flag}`);
11207
- });
11208
- lines.push("");
11209
- lines.push(`First step: use ${agentName(first2.agent)}.`);
11210
- lines.push("");
11211
- lines.push(` Context: ${plan.contextPackPath}`);
11212
- lines.push(` Agent prompt: ${agentInstallPath(first2.agent)}`);
11213
- lines.push(` Expected output: ${first2.output}`);
11363
+ const rec = plan.nextStepRecommendation;
11364
+ const isBootstrapIncomplete = rec && rec.id === "bootstrap";
11365
+ if (isBootstrapIncomplete) {
11366
+ lines.push("Current phase: Setup");
11367
+ lines.push("Next step: Run `kaddo bootstrap` to create the project knowledge baseline.");
11368
+ lines.push("Reason: The knowledge baseline is incomplete.");
11214
11369
  lines.push("");
11215
- lines.push("Instructions:");
11216
- lines.push(" Open your preferred LLM chat, paste the context pack, then paste the agent");
11217
- lines.push(" prompt. Ask the LLM to generate the expected output and save it in the target file.");
11370
+ lines.push("Agent handoff is not ready yet.");
11371
+ lines.push("Run `kaddo bootstrap` first.");
11218
11372
  } else {
11219
- lines.push("Foundational knowledge looks complete \u2014 see the phase recommendation below.");
11373
+ const first2 = steps[0];
11374
+ if (first2) {
11375
+ lines.push("Foundational knowledge still needed:");
11376
+ steps.forEach((s, i) => {
11377
+ const flag = s.installed ? "" : " (not installed)";
11378
+ lines.push(` ${i + 1}. ${agentName(s.agent)} \u2192 ${s.output}${flag}`);
11379
+ });
11380
+ lines.push("");
11381
+ lines.push(`First step: use ${agentName(first2.agent)}.`);
11382
+ lines.push("");
11383
+ lines.push(` Context: ${plan.contextPackPath}`);
11384
+ lines.push(` Agent prompt: ${agentInstallPath(first2.agent)}`);
11385
+ lines.push(` Expected output: ${first2.output}`);
11386
+ lines.push("");
11387
+ lines.push("Instructions:");
11388
+ lines.push(" Open your preferred LLM chat, paste the context pack, then paste the agent");
11389
+ lines.push(" prompt. Ask the LLM to generate the expected output and save it in the target file.");
11390
+ } else {
11391
+ lines.push("Foundational knowledge looks complete \u2014 see the phase recommendation below.");
11392
+ }
11220
11393
  }
11221
11394
  lines.push("");
11222
11395
  lines.push("Kaddo does not call an LLM. You stay in control of the interpretation.");
@@ -11411,7 +11584,11 @@ function runUnderstand() {
11411
11584
  type: w.type,
11412
11585
  lifecycle: w.lifecycle ?? "draft",
11413
11586
  knowledgeLevel: w.knowledgeLevel,
11414
- hasOwnership: w.codeGlobs.length > 0
11587
+ hasOwnership: w.codeGlobs.length > 0,
11588
+ source: (() => {
11589
+ const s = parseWorkItemSource(w.rawFrontmatter);
11590
+ return { type: s.type, ...s.id ? { id: s.id } : {} };
11591
+ })()
11415
11592
  }));
11416
11593
  const recommendedPaths = [];
11417
11594
  if (rec.agent) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/cli",
3
- "version": "3.48.0",
3
+ "version": "3.50.0",
4
4
  "description": "Knowledge Driven Development toolkit",
5
5
  "license": "MIT",
6
6
  "repository": {