@kaddo/cli 3.48.0 → 3.49.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 +135 -21
  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
  };
@@ -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";
@@ -9327,12 +9410,12 @@ var captureTechDecisions = {
9327
9410
  var createWorkSource = {
9328
9411
  id: "create-work-source",
9329
9412
  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
- })
9413
+ evaluate: (ctx) => {
9414
+ if (!ctx.hasRoadmap && ctx.totalWorkItems === 0) return { status: "pending", command: "kaddo roadmap", agent: "roadmap-agent" };
9415
+ if (ctx.hasUnknownSources) return { status: "warning", evidence: ["Work Items with unknown source"], reason: "Some Work Items have no source metadata." };
9416
+ const evidence = ctx.hasRoadmap ? ["knowledge/delivery/roadmap.md"] : void 0;
9417
+ return { status: "done", evidence };
9418
+ }
9336
9419
  };
9337
9420
  var materializeWorkItem = {
9338
9421
  id: "materialize-work-item",
@@ -9549,6 +9632,10 @@ function buildRouteContext(dir) {
9549
9632
  adaptersInstalled: adapters.length,
9550
9633
  hasGuardHistory: exists(join(dir, ".kaddo", "history", "guard-runs.jsonl")),
9551
9634
  hasScanWarnings: hasScan ? loadScanWarnings(dir) : false,
9635
+ hasUnknownSources: wis.some((w) => {
9636
+ const src = parseWorkItemSource(w.rawFrontmatter);
9637
+ return src.type === "unknown" && src.inferred;
9638
+ }),
9552
9639
  nextStepId: mapNextStepId(nextStep.id)
9553
9640
  };
9554
9641
  }
@@ -9764,17 +9851,21 @@ function buildProjectExplanation(dir) {
9764
9851
  hasAgents: hasAgents(dir)
9765
9852
  };
9766
9853
  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
- }));
9854
+ const items = workItemArtifacts.map((a) => {
9855
+ const src = parseWorkItemSource(a.rawFrontmatter);
9856
+ return {
9857
+ id: a.id || a.title,
9858
+ title: a.title,
9859
+ type: a.type,
9860
+ status: a.status,
9861
+ lifecycle: lifecycleStateOf({ status: a.status, filePath: a.filePath }),
9862
+ initiative: a.initiative,
9863
+ knowledgeLevel: a.knowledgeLevel,
9864
+ hasOwnership: a.codeGlobs.length > 0,
9865
+ domains: a.domains,
9866
+ source: { type: src.type, ...src.id ? { id: src.id } : {}, inferred: src.inferred }
9867
+ };
9868
+ });
9778
9869
  const byState = lifecycleCounts(items.map((i) => i.lifecycle));
9779
9870
  const byType = {};
9780
9871
  for (const i of items) {
@@ -9971,6 +10062,17 @@ function renderExplanationHuman(exp) {
9971
10062
  for (const [t, n] of typeEntries) lines.push(`- ${typeLabel(t)}: ${n}`);
9972
10063
  lines.push("");
9973
10064
  }
10065
+ const sourceCounts = {};
10066
+ for (const i of exp.workItems.items) {
10067
+ const t = i.source?.type ?? "unknown";
10068
+ sourceCounts[t] = (sourceCounts[t] ?? 0) + 1;
10069
+ }
10070
+ const sourceEntries = Object.entries(sourceCounts).filter(([, n]) => n > 0);
10071
+ if (sourceEntries.length > 0) {
10072
+ lines.push("## Work Item Sources");
10073
+ for (const [t, n] of sourceEntries) lines.push(`- ${t.charAt(0).toUpperCase() + t.slice(1)}: ${n}`);
10074
+ lines.push("");
10075
+ }
9974
10076
  const grouped = exp.workItems.initiatives.filter(
9975
10077
  (g) => LIFECYCLE_STATES.some((s2) => g.states[s2] > 0)
9976
10078
  );
@@ -10439,7 +10541,8 @@ function toContextWorkItem(a) {
10439
10541
  status: a.status,
10440
10542
  lifecycle: lifecycleStateOf({ status: a.status, filePath: a.filePath }),
10441
10543
  knowledgeLevel: a.knowledgeLevel,
10442
- domains: a.domains
10544
+ domains: a.domains,
10545
+ source: parseWorkItemSource(a.rawFrontmatter)
10443
10546
  };
10444
10547
  }
10445
10548
  function toContextArtifact(a) {
@@ -10780,7 +10883,10 @@ function renderContextPack(pack) {
10780
10883
  const level = wi.knowledgeLevel ? ` [${wi.knowledgeLevel}]` : "";
10781
10884
  const status = wi.lifecycle ? ` (${wi.lifecycle})` : wi.status ? ` (${wi.status})` : "";
10782
10885
  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}`;
10886
+ const line = `- ${wi.id || wi.title} [${wi.type}]${level}${status} \u2014 ${wi.title}${domains}`;
10887
+ const src = wi.source && wi.source.type !== "unknown" ? `
10888
+ - Source: ${renderSourceCompact(wi.source)}` : "";
10889
+ return `${line}${src}`;
10784
10890
  });
10785
10891
  parts.push(lines.join("\n") + "\n");
10786
10892
  } else {
@@ -11090,7 +11196,11 @@ function renderUnderstand(plan) {
11090
11196
  if (plan.activeWorkItems && plan.activeWorkItems.length > 0) {
11091
11197
  parts.push("## Active Work Items\n");
11092
11198
  parts.push(
11093
- plan.activeWorkItems.map((w) => `- ${w.id} [${w.type}] ${w.lifecycle} \u2014 ${w.title}`).join("\n") + "\n"
11199
+ plan.activeWorkItems.map((w) => {
11200
+ const src = w.source && w.source.type !== "unknown" ? `
11201
+ - Source: ${w.source.type}${w.source.id ? ` \xB7 ${w.source.id}` : ""}` : "";
11202
+ return `- ${w.id} [${w.type}] ${w.lifecycle} \u2014 ${w.title}${src}`;
11203
+ }).join("\n") + "\n"
11094
11204
  );
11095
11205
  }
11096
11206
  parts.push("## Context Pack\n");
@@ -11411,7 +11521,11 @@ function runUnderstand() {
11411
11521
  type: w.type,
11412
11522
  lifecycle: w.lifecycle ?? "draft",
11413
11523
  knowledgeLevel: w.knowledgeLevel,
11414
- hasOwnership: w.codeGlobs.length > 0
11524
+ hasOwnership: w.codeGlobs.length > 0,
11525
+ source: (() => {
11526
+ const s = parseWorkItemSource(w.rawFrontmatter);
11527
+ return { type: s.type, ...s.id ? { id: s.id } : {} };
11528
+ })()
11415
11529
  }));
11416
11530
  const recommendedPaths = [];
11417
11531
  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.49.0",
4
4
  "description": "Knowledge Driven Development toolkit",
5
5
  "license": "MIT",
6
6
  "repository": {