@kaddo/mcp 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 +233 -60
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -384,6 +384,7 @@ function parseArtifact(filePath, raw) {
384
384
  initiative: String(data.initiative ?? data.source_initiative ?? ""),
385
385
  source: data.source ? String(data.source) : "",
386
386
  sourceId: String(data.source_id ?? ""),
387
+ rawFrontmatter: data,
387
388
  decisions: Array.isArray(data.decisions) ? data.decisions.map(String).filter(Boolean) : [],
388
389
  capsules: Array.isArray(data.capsules) ? data.capsules.map(String).filter(Boolean) : []
389
390
  };
@@ -2655,7 +2656,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
2655
2656
  const ctx = buildCodexAdapterContext(dir);
2656
2657
  const agents = ctx.hasAgents ? "present" : "missing";
2657
2658
  const skills = ctx.hasSkills ? "present" : "missing";
2658
- const bootstrapBaseline = presence.business !== "missing" && presence.product !== "missing" ? "complete" : "incomplete";
2659
+ const bootstrapBaseline2 = presence.business !== "missing" && presence.product !== "missing" ? "complete" : "incomplete";
2659
2660
  const roadmap = roadmapSignal(dir);
2660
2661
  const work_items = workItemsSignal(dir);
2661
2662
  const adapters = installedAdapters(dir);
@@ -2663,7 +2664,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
2663
2664
  const signals = {
2664
2665
  scan,
2665
2666
  understand,
2666
- bootstrap_baseline: bootstrapBaseline,
2667
+ bootstrap_baseline: bootstrapBaseline2,
2667
2668
  agents,
2668
2669
  skills,
2669
2670
  current_state: presence.current_state,
@@ -2682,7 +2683,7 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
2682
2683
  const firstWeak = KNOWLEDGE_FILES.find((f) => presence[f.key] !== "useful");
2683
2684
  let overall;
2684
2685
  if (scan === "missing") overall = "initialized";
2685
- else if (bootstrapBaseline === "incomplete") overall = "bootstrap-incomplete";
2686
+ else if (bootstrapBaseline2 === "incomplete") overall = "bootstrap-incomplete";
2686
2687
  else if (agents === "missing") overall = "agents-missing";
2687
2688
  else if (skills === "missing") overall = "skills-missing";
2688
2689
  else if (understand === "missing") overall = "scanned";
@@ -5553,6 +5554,84 @@ function renderSignalsCompact(signals) {
5553
5554
  return lines.length > 0 ? lines.join("\n") + "\n" : "No signals detected.\n";
5554
5555
  }
5555
5556
 
5557
+ // ../cli/src/core/work-item-source.ts
5558
+ var VALID_SOURCES = [
5559
+ "manual",
5560
+ "roadmap",
5561
+ "jira",
5562
+ "github",
5563
+ "notion",
5564
+ "xlsx",
5565
+ "csv",
5566
+ "api",
5567
+ "external",
5568
+ "unknown"
5569
+ ];
5570
+ function isValidSource(s) {
5571
+ return VALID_SOURCES.includes(s);
5572
+ }
5573
+ function parseWorkItemSource(frontmatter) {
5574
+ const raw = frontmatter.source ? String(frontmatter.source) : "";
5575
+ if (raw && isValidSource(raw)) {
5576
+ return {
5577
+ type: raw,
5578
+ id: optStr(frontmatter.source_id),
5579
+ title: optStr(frontmatter.source_title),
5580
+ context: optStr(frontmatter.source_context),
5581
+ provider: optStr(frontmatter.source_provider),
5582
+ url: optStr(frontmatter.source_url),
5583
+ imported_at: optStr(frontmatter.source_imported_at),
5584
+ synced_at: optStr(frontmatter.source_synced_at),
5585
+ inferred: false
5586
+ };
5587
+ }
5588
+ if (raw && !isValidSource(raw)) {
5589
+ return {
5590
+ type: "unknown",
5591
+ id: optStr(frontmatter.source_id),
5592
+ title: optStr(frontmatter.source_title),
5593
+ context: optStr(frontmatter.source_context),
5594
+ provider: optStr(frontmatter.source_provider),
5595
+ url: optStr(frontmatter.source_url),
5596
+ imported_at: optStr(frontmatter.source_imported_at),
5597
+ synced_at: optStr(frontmatter.source_synced_at),
5598
+ inferred: true,
5599
+ reason: `Invalid source value: "${raw}".`
5600
+ };
5601
+ }
5602
+ if (frontmatter.source_work_item_candidate || frontmatter.source_roadmap_initiative) {
5603
+ return {
5604
+ type: "roadmap",
5605
+ id: optStr(frontmatter.source_id) ?? optStr(frontmatter.source_work_item_candidate),
5606
+ title: optStr(frontmatter.source_initiative_title),
5607
+ inferred: true,
5608
+ reason: "Inferred from legacy roadmap fields."
5609
+ };
5610
+ }
5611
+ if (frontmatter.source_id) {
5612
+ return {
5613
+ type: "unknown",
5614
+ id: optStr(frontmatter.source_id),
5615
+ inferred: true,
5616
+ reason: "Has source_id but no source type."
5617
+ };
5618
+ }
5619
+ return {
5620
+ type: "unknown",
5621
+ inferred: true,
5622
+ reason: "No source metadata found."
5623
+ };
5624
+ }
5625
+ function renderSourceCompact(source) {
5626
+ const parts = [source.type];
5627
+ if (source.id) parts.push(source.id);
5628
+ return parts.join(" \xB7 ");
5629
+ }
5630
+ function optStr(v) {
5631
+ if (typeof v === "string" && v.trim()) return v.trim();
5632
+ return void 0;
5633
+ }
5634
+
5556
5635
  // ../cli/src/core/project-route.ts
5557
5636
  function isUseful(q) {
5558
5637
  return q === "useful";
@@ -5575,6 +5654,14 @@ var scanRepository = {
5575
5654
  return { status: "done", evidence: [".kaddo/scan.json"] };
5576
5655
  }
5577
5656
  };
5657
+ var bootstrapBaseline = {
5658
+ id: "bootstrap",
5659
+ label: "Bootstrap knowledge baseline",
5660
+ evaluate: (ctx) => {
5661
+ if (ctx.qBusiness !== "missing" && ctx.qProduct !== "missing") return { status: "done", evidence: ["knowledge/business/business.md", "knowledge/product/product.md"] };
5662
+ return { status: "pending", command: "kaddo bootstrap", reason: "The knowledge baseline is incomplete." };
5663
+ }
5664
+ };
5578
5665
  var defineBusiness = {
5579
5666
  id: "define-business",
5580
5667
  label: "Define business context",
@@ -5639,12 +5726,12 @@ var captureTechDecisions = {
5639
5726
  var createWorkSource = {
5640
5727
  id: "create-work-source",
5641
5728
  label: "Create or connect work source",
5642
- evaluate: (ctx) => ({
5643
- status: ctx.hasRoadmap || ctx.totalWorkItems > 0 ? "done" : "pending",
5644
- evidence: ctx.hasRoadmap ? ["knowledge/delivery/roadmap.md"] : void 0,
5645
- command: ctx.hasRoadmap ? void 0 : "kaddo roadmap",
5646
- agent: ctx.hasRoadmap ? void 0 : "roadmap-agent"
5647
- })
5729
+ evaluate: (ctx) => {
5730
+ if (!ctx.hasRoadmap && ctx.totalWorkItems === 0) return { status: "pending", command: "kaddo roadmap", agent: "roadmap-agent" };
5731
+ if (ctx.hasUnknownSources) return { status: "warning", evidence: ["Work Items with unknown source"], reason: "Some Work Items have no source metadata." };
5732
+ const evidence = ctx.hasRoadmap ? ["knowledge/delivery/roadmap.md"] : void 0;
5733
+ return { status: "done", evidence };
5734
+ }
5648
5735
  };
5649
5736
  var materializeWorkItem = {
5650
5737
  id: "materialize-work-item",
@@ -5771,6 +5858,7 @@ var NEW_STEPS = [
5771
5858
  var PRE_AI_STEPS = [
5772
5859
  enableKaddo,
5773
5860
  scanRepository,
5861
+ bootstrapBaseline,
5774
5862
  defineBusiness,
5775
5863
  defineProduct,
5776
5864
  discoverCapabilities,
@@ -5788,6 +5876,7 @@ var PRE_AI_STEPS = [
5788
5876
  var LEGACY_STEPS = [
5789
5877
  enableKaddo,
5790
5878
  scanRepository,
5879
+ bootstrapBaseline,
5791
5880
  identifyLegacyModules,
5792
5881
  { ...discoverCapabilities, label: "Discover critical capabilities" },
5793
5882
  describeArchitecture,
@@ -5861,6 +5950,10 @@ function buildRouteContext(dir) {
5861
5950
  adaptersInstalled: adapters.length,
5862
5951
  hasGuardHistory: exists(join(dir, ".kaddo", "history", "guard-runs.jsonl")),
5863
5952
  hasScanWarnings: hasScan ? loadScanWarnings(dir) : false,
5953
+ hasUnknownSources: wis.some((w) => {
5954
+ const src = parseWorkItemSource(w.rawFrontmatter);
5955
+ return src.type === "unknown" && src.inferred;
5956
+ }),
5864
5957
  nextStepId: mapNextStepId(nextStep.id)
5865
5958
  };
5866
5959
  }
@@ -5875,7 +5968,7 @@ function loadScanWarnings(dir) {
5875
5968
  function mapNextStepId(id) {
5876
5969
  const MAP = {
5877
5970
  init: "enable-kaddo",
5878
- bootstrap: "define-business",
5971
+ bootstrap: "bootstrap",
5879
5972
  "add-agents": "enable-kaddo",
5880
5973
  "add-skills": "enable-kaddo",
5881
5974
  scan: "scan-repository",
@@ -6044,6 +6137,15 @@ function hasAgents(dir) {
6044
6137
  }
6045
6138
  return hasAgentMd(agentsDir);
6046
6139
  }
6140
+ function hasSkills(dir) {
6141
+ const skillsDir = join(dir, ARCH_DIR2, "skills");
6142
+ if (!exists(skillsDir)) return false;
6143
+ try {
6144
+ return readDir(skillsDir).some((e) => e.endsWith(".md") && isFile(join(skillsDir, e)));
6145
+ } catch {
6146
+ return false;
6147
+ }
6148
+ }
6047
6149
  function buildProjectExplanation(dir) {
6048
6150
  const config = loadConfig(dir);
6049
6151
  const project = {
@@ -6070,23 +6172,30 @@ function buildProjectExplanation(dir) {
6070
6172
  hasInventory: exists(join(dir, ARCH_DIR2, "inventory.md")),
6071
6173
  hasContextPack: exists(join(dir, ".kaddo", "context-pack.md")),
6072
6174
  hasUnderstand: exists(join(dir, ".kaddo", "understand.md")),
6175
+ hasBusiness: exists(join(dir, "knowledge/business/business.md")),
6176
+ hasProduct: exists(join(dir, "knowledge/product/product.md")),
6073
6177
  hasCapabilities: layerStatus("Product") !== "Missing",
6074
6178
  hasArchitecture: layerStatus("Tech") !== "Missing",
6075
6179
  hasRoadmap: layerStatus("Delivery") !== "Missing",
6076
- hasAgents: hasAgents(dir)
6180
+ hasAgents: hasAgents(dir),
6181
+ hasSkills: hasSkills(dir)
6077
6182
  };
6078
6183
  const workItemArtifacts = discoverWorkItems(dir);
6079
- const items = workItemArtifacts.map((a) => ({
6080
- id: a.id || a.title,
6081
- title: a.title,
6082
- type: a.type,
6083
- status: a.status,
6084
- lifecycle: lifecycleStateOf({ status: a.status, filePath: a.filePath }),
6085
- initiative: a.initiative,
6086
- knowledgeLevel: a.knowledgeLevel,
6087
- hasOwnership: a.codeGlobs.length > 0,
6088
- domains: a.domains
6089
- }));
6184
+ const items = workItemArtifacts.map((a) => {
6185
+ const src = parseWorkItemSource(a.rawFrontmatter);
6186
+ return {
6187
+ id: a.id || a.title,
6188
+ title: a.title,
6189
+ type: a.type,
6190
+ status: a.status,
6191
+ lifecycle: lifecycleStateOf({ status: a.status, filePath: a.filePath }),
6192
+ initiative: a.initiative,
6193
+ knowledgeLevel: a.knowledgeLevel,
6194
+ hasOwnership: a.codeGlobs.length > 0,
6195
+ domains: a.domains,
6196
+ source: { type: src.type, ...src.id ? { id: src.id } : {}, inferred: src.inferred }
6197
+ };
6198
+ });
6090
6199
  const byState = lifecycleCounts(items.map((i) => i.lifecycle));
6091
6200
  const byType = {};
6092
6201
  for (const i of items) {
@@ -6134,33 +6243,42 @@ function buildProjectExplanation(dir) {
6134
6243
  if (!knowledge.hasAgents) missingKnowledge.push("Agents (knowledge/agents/)");
6135
6244
  if (items.length === 0) missingKnowledge.push("Work items (knowledge/delivery/work-items/)");
6136
6245
  const suggestedNextSteps = [];
6137
- if (!knowledge.hasScan) {
6138
- suggestedNextSteps.push("Run `kaddo scan` to detect the technical stack.");
6139
- } else if (!knowledge.hasContextPack) {
6140
- suggestedNextSteps.push("Run `kaddo context` to prepare an LLM context pack.");
6141
- }
6142
- if (!knowledge.hasAgents) {
6143
- suggestedNextSteps.push("Run `kaddo add agents` to install knowledge agents.");
6144
- }
6145
- if (!knowledge.hasCapabilities) {
6146
- suggestedNextSteps.push("Use capability-agent to generate knowledge/product/capabilities.md.");
6147
- }
6148
- if (!knowledge.hasArchitecture) {
6149
- suggestedNextSteps.push("Use architecture-agent to generate knowledge/tech/current-state.md.");
6150
- }
6151
- if (!knowledge.hasRoadmap) {
6152
- suggestedNextSteps.push("Use roadmap-agent to generate knowledge/delivery/roadmap.md.");
6153
- } else if (roadmap.remaining > 0) {
6154
- suggestedNextSteps.push(
6155
- `Materialize ${roadmap.remaining} roadmap candidate(s) with \`kaddo create --from roadmap\`.`
6156
- );
6157
- }
6158
- if (items.length === 0 && !roadmap.present) {
6159
- suggestedNextSteps.push("Create your first Work Item with `kaddo create`.");
6160
- } else if (ownership.workItemsMissingOwnership > 0) {
6161
- suggestedNextSteps.push(
6162
- "Run `kaddo owners suggest` for Work Items without code ownership."
6163
- );
6246
+ const baselineIncomplete = !knowledge.hasBusiness || !knowledge.hasProduct;
6247
+ if (baselineIncomplete) {
6248
+ suggestedNextSteps.push("Run `kaddo bootstrap` to create the project knowledge baseline.");
6249
+ if (!knowledge.hasAgents) suggestedNextSteps.push("Then run `kaddo add agents`.");
6250
+ if (!knowledge.hasSkills) suggestedNextSteps.push("Then run `kaddo add skills`.");
6251
+ suggestedNextSteps.push("Then run `kaddo context`.");
6252
+ suggestedNextSteps.push("Then run `kaddo understand`.");
6253
+ } else {
6254
+ if (!knowledge.hasScan) {
6255
+ suggestedNextSteps.push("Run `kaddo scan` to detect the technical stack.");
6256
+ } else if (!knowledge.hasContextPack) {
6257
+ suggestedNextSteps.push("Run `kaddo context` to prepare an LLM context pack.");
6258
+ }
6259
+ if (!knowledge.hasAgents) {
6260
+ suggestedNextSteps.push("Run `kaddo add agents` to install knowledge agents.");
6261
+ }
6262
+ if (!knowledge.hasCapabilities) {
6263
+ suggestedNextSteps.push("Use capability-agent to generate knowledge/product/capabilities.md.");
6264
+ }
6265
+ if (!knowledge.hasArchitecture) {
6266
+ suggestedNextSteps.push("Use architecture-agent to generate knowledge/tech/current-state.md.");
6267
+ }
6268
+ if (!knowledge.hasRoadmap) {
6269
+ suggestedNextSteps.push("Use roadmap-agent to generate knowledge/delivery/roadmap.md.");
6270
+ } else if (roadmap.remaining > 0) {
6271
+ suggestedNextSteps.push(
6272
+ `Materialize ${roadmap.remaining} roadmap candidate(s) with \`kaddo create --from roadmap\`.`
6273
+ );
6274
+ }
6275
+ if (items.length === 0 && !roadmap.present) {
6276
+ suggestedNextSteps.push("Create your first Work Item with `kaddo create`.");
6277
+ } else if (ownership.workItemsMissingOwnership > 0) {
6278
+ suggestedNextSteps.push(
6279
+ "Run `kaddo owners suggest` for Work Items without code ownership."
6280
+ );
6281
+ }
6164
6282
  }
6165
6283
  const readiness = buildReadinessReport(dir);
6166
6284
  return {
@@ -6283,6 +6401,17 @@ function renderExplanationHuman(exp) {
6283
6401
  for (const [t, n] of typeEntries) lines.push(`- ${typeLabel(t)}: ${n}`);
6284
6402
  lines.push("");
6285
6403
  }
6404
+ const sourceCounts = {};
6405
+ for (const i of exp.workItems.items) {
6406
+ const t = i.source?.type ?? "unknown";
6407
+ sourceCounts[t] = (sourceCounts[t] ?? 0) + 1;
6408
+ }
6409
+ const sourceEntries = Object.entries(sourceCounts).filter(([, n]) => n > 0);
6410
+ if (sourceEntries.length > 0) {
6411
+ lines.push("## Work Item Sources");
6412
+ for (const [t, n] of sourceEntries) lines.push(`- ${t.charAt(0).toUpperCase() + t.slice(1)}: ${n}`);
6413
+ lines.push("");
6414
+ }
6286
6415
  const grouped = exp.workItems.initiatives.filter(
6287
6416
  (g) => LIFECYCLE_STATES.some((s2) => g.states[s2] > 0)
6288
6417
  );
@@ -7411,6 +7540,20 @@ function serializeDriftJson(r) {
7411
7540
 
7412
7541
  // src/workitems.ts
7413
7542
  import matter8 from "gray-matter";
7543
+ var VALID_SOURCES2 = /* @__PURE__ */ new Set(["manual", "roadmap", "jira", "github", "notion", "xlsx", "csv", "api", "external", "unknown"]);
7544
+ function optStr2(v) {
7545
+ return typeof v === "string" && v.trim() ? v.trim() : void 0;
7546
+ }
7547
+ function parseSource(data) {
7548
+ const raw = data.source ? String(data.source) : "";
7549
+ if (raw && VALID_SOURCES2.has(raw)) {
7550
+ return { type: raw, id: optStr2(data.source_id), title: optStr2(data.source_title), url: optStr2(data.source_url), provider: optStr2(data.source_provider), inferred: false };
7551
+ }
7552
+ if (data.source_work_item_candidate || data.source_roadmap_initiative) {
7553
+ return { type: "roadmap", id: optStr2(data.source_id) ?? optStr2(data.source_work_item_candidate), title: optStr2(data.source_initiative_title), inferred: true };
7554
+ }
7555
+ return { type: "unknown", inferred: true };
7556
+ }
7414
7557
  var ACTIVE_STATES2 = /* @__PURE__ */ new Set(["draft", "ready", "in-progress", "blocked"]);
7415
7558
  function strArray(v) {
7416
7559
  return Array.isArray(v) ? v.map((x) => String(x)).filter(Boolean) : [];
@@ -7454,7 +7597,8 @@ function listWorkItems(root) {
7454
7597
  code: strArray(data.code),
7455
7598
  capabilities: strArray(data.capabilities),
7456
7599
  decisions: strArray(data.decisions),
7457
- capsules: strArray(data.capsules)
7600
+ capsules: strArray(data.capsules),
7601
+ source: parseSource(data)
7458
7602
  });
7459
7603
  }
7460
7604
  return items.sort((a, b) => a.id.localeCompare(b.id));
@@ -7957,7 +8101,8 @@ function toContextWorkItem(a) {
7957
8101
  status: a.status,
7958
8102
  lifecycle: lifecycleStateOf({ status: a.status, filePath: a.filePath }),
7959
8103
  knowledgeLevel: a.knowledgeLevel,
7960
- domains: a.domains
8104
+ domains: a.domains,
8105
+ source: parseWorkItemSource(a.rawFrontmatter)
7961
8106
  };
7962
8107
  }
7963
8108
  function toContextArtifact(a) {
@@ -8298,7 +8443,10 @@ function renderContextPack(pack) {
8298
8443
  const level = wi.knowledgeLevel ? ` [${wi.knowledgeLevel}]` : "";
8299
8444
  const status = wi.lifecycle ? ` (${wi.lifecycle})` : wi.status ? ` (${wi.status})` : "";
8300
8445
  const domains = wi.domains.length > 0 ? ` \xB7 domains: ${wi.domains.join(", ")}` : "";
8301
- return `- ${wi.id || wi.title} [${wi.type}]${level}${status} \u2014 ${wi.title}${domains}`;
8446
+ const line = `- ${wi.id || wi.title} [${wi.type}]${level}${status} \u2014 ${wi.title}${domains}`;
8447
+ const src = wi.source && wi.source.type !== "unknown" ? `
8448
+ - Source: ${renderSourceCompact(wi.source)}` : "";
8449
+ return `${line}${src}`;
8302
8450
  });
8303
8451
  parts.push(lines.join("\n") + "\n");
8304
8452
  } else {
@@ -8390,19 +8538,35 @@ function renderContextPack(pack) {
8390
8538
  parts.push(pack.skills.map((s) => `- ${s}`).join("\n") + "\n");
8391
8539
  parts.push("Read full skill definitions in `knowledge/skills/` or via the Kaddo MCP server (`kaddo://skills`).\n");
8392
8540
  }
8541
+ const isBootstrapIncomplete = rec.id === "bootstrap";
8393
8542
  parts.push("## Missing Context\n");
8394
- if (missing.length > 0) {
8543
+ if (isBootstrapIncomplete) {
8544
+ const baselineMissing = [
8545
+ "- Bootstrap baseline is incomplete.",
8546
+ ...!pack.knowledgeQuality.business || pack.knowledgeQuality.business.status === "Missing" ? ["- Missing business knowledge."] : [],
8547
+ ...!pack.knowledgeQuality.product || pack.knowledgeQuality.product.status === "Missing" ? ["- Missing product knowledge."] : []
8548
+ ];
8549
+ if (missing.length > 0) {
8550
+ baselineMissing.push(...missing.filter((m) => !baselineMissing.some((b) => b.includes(m))));
8551
+ }
8552
+ parts.push(baselineMissing.join("\n") + "\n");
8553
+ } else if (missing.length > 0) {
8395
8554
  parts.push(missing.map((m) => `- ${m}`).join("\n") + "\n");
8396
8555
  } else {
8397
8556
  parts.push("_None \u2014 all expected context is present._\n");
8398
8557
  }
8399
8558
  parts.push("## Recommended Agent Handoff\n");
8400
- parts.push(`Recommended next for the **${pack.phase.phase}** phase:
8559
+ if (isBootstrapIncomplete) {
8560
+ parts.push("No agent handoff yet.\n");
8561
+ parts.push("Run `kaddo bootstrap` first to create the baseline files.\n");
8562
+ } else {
8563
+ parts.push(`Recommended next for the **${pack.phase.phase}** phase:
8401
8564
  `);
8402
- parts.push(handoff.recommendedAgents.map((a, i) => `${i + 1}. ${a}`).join("\n") + "\n");
8403
- if (handoff.nextSteps.length > 0) {
8404
- parts.push("Next step:\n");
8405
- parts.push(handoff.nextSteps.map((s) => `- ${s}`).join("\n") + "\n");
8565
+ parts.push(handoff.recommendedAgents.map((a, i) => `${i + 1}. ${a}`).join("\n") + "\n");
8566
+ if (handoff.nextSteps.length > 0) {
8567
+ parts.push("Next step:\n");
8568
+ parts.push(handoff.nextSteps.map((s) => `- ${s}`).join("\n") + "\n");
8569
+ }
8406
8570
  }
8407
8571
  parts.push("## Instructions for the LLM\n");
8408
8572
  parts.push(handoff.instructions.map((i) => `- ${i}`).join("\n") + "\n");
@@ -8515,7 +8679,12 @@ function renderUnderstand(plan) {
8515
8679
  parts.push("## Project Route\n");
8516
8680
  parts.push(renderRouteCompact(plan.projectRoute));
8517
8681
  }
8518
- if (steps.length > 0) {
8682
+ const isBootstrap = rec && rec.id === "bootstrap";
8683
+ if (isBootstrap) {
8684
+ parts.push("## Agent Handoff\n");
8685
+ parts.push("Agent handoff is not ready yet.\n");
8686
+ parts.push("Run `kaddo bootstrap` first.\n");
8687
+ } else if (steps.length > 0) {
8519
8688
  parts.push("## Recommended Agent Flow\n");
8520
8689
  parts.push(`Recommended order for a ${stateLabel2(project.state)} project:
8521
8690
  `);
@@ -8556,7 +8725,11 @@ function renderUnderstand(plan) {
8556
8725
  if (plan.activeWorkItems && plan.activeWorkItems.length > 0) {
8557
8726
  parts.push("## Active Work Items\n");
8558
8727
  parts.push(
8559
- plan.activeWorkItems.map((w) => `- ${w.id} [${w.type}] ${w.lifecycle} \u2014 ${w.title}`).join("\n") + "\n"
8728
+ plan.activeWorkItems.map((w) => {
8729
+ const src = w.source && w.source.type !== "unknown" ? `
8730
+ - Source: ${w.source.type}${w.source.id ? ` \xB7 ${w.source.id}` : ""}` : "";
8731
+ return `- ${w.id} [${w.type}] ${w.lifecycle} \u2014 ${w.title}${src}`;
8732
+ }).join("\n") + "\n"
8560
8733
  );
8561
8734
  }
8562
8735
  parts.push("## Context Pack\n");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/mcp",
3
- "version": "3.48.0",
3
+ "version": "3.50.0",
4
4
  "description": "MCP server for Kaddo project knowledge: read-only resources/tools/prompts plus safe derived generation under .kaddo/.",
5
5
  "license": "MIT",
6
6
  "repository": {