@kaddo/cli 3.66.0 → 3.67.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 +117 -13
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -6939,17 +6939,27 @@ function analyzeCrossRepoEvidence(input) {
6939
6939
  }
6940
6940
  }
6941
6941
  }
6942
+ if (validationStatus === "accepted-with-exceptions") {
6943
+ const hasExceptions = exceptions.length > 0;
6944
+ const hasValidationGate = releaseGates.some(
6945
+ (g) => (g.status === "pending" || g.status === "blocked") && (g.id.includes("validation") || g.id.includes("test"))
6946
+ );
6947
+ if (!hasExceptions && !hasValidationGate) {
6948
+ findings.push({ id, severity: "warning", message: "Validation status is accepted-with-exceptions, but no exception evidence was found." });
6949
+ }
6950
+ }
6942
6951
  if (raw.status === "done") {
6943
6952
  findings.push({ id, severity: "warning", message: "Legacy status `done` detected. Canonical status is `completed`." });
6944
6953
  }
6945
6954
  if (raw.refined_by && raw.implemented_by && raw.refined_by === raw.implemented_by) {
6946
6955
  findings.push({ id, severity: "fyi", message: "refined_by and implemented_by point to the same agent." });
6947
6956
  }
6957
+ const historicalDefault = lifecycle === "completed" || lifecycle === "archived" ? "not-assessed" : "not-started";
6948
6958
  return {
6949
6959
  id,
6950
6960
  lifecycle,
6951
- implementationStatus: implementationStatus || "not-started",
6952
- validationStatus: validationStatus || "not-started",
6961
+ implementationStatus: implementationStatus || historicalDefault,
6962
+ validationStatus: validationStatus || historicalDefault,
6953
6963
  releaseStatus: releaseStatus || "not-assessed",
6954
6964
  affectedModules,
6955
6965
  findings,
@@ -11741,6 +11751,8 @@ function workItemsSignal(dir) {
11741
11751
  if (wis.length === 0) return "none";
11742
11752
  if (wis.some((w) => w.lifecycle === "in-progress")) return "in-progress";
11743
11753
  if (wis.some((w) => w.lifecycle === "ready")) return "ready";
11754
+ const hasActive = wis.some((w) => w.lifecycle === "draft" || w.lifecycle === "blocked");
11755
+ if (!hasActive && wis.some((w) => w.lifecycle === "completed" || w.lifecycle === "archived")) return "completed-only";
11744
11756
  return "none-ready";
11745
11757
  }
11746
11758
  function installedAdapters(dir) {
@@ -12169,6 +12181,8 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
12169
12181
  else if (understand === "missing") overall = "scanned";
12170
12182
  else if (firstWeak) overall = "knowledge-incomplete";
12171
12183
  else if (oq.summary.blocking_open > 0) overall = "needs-decisions";
12184
+ else if (work_items === "in-progress") overall = "active-implementation";
12185
+ else if (work_items === "completed-only") overall = deriveDeliveryCompletedStatus(dir);
12172
12186
  else if (roadmap !== "has-candidates") overall = "ready-for-roadmap";
12173
12187
  else if (work_items === "none" || work_items === "none-ready") overall = "ready-for-work-item";
12174
12188
  else overall = "ready-for-implementation";
@@ -12181,6 +12195,16 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
12181
12195
  nextStepRecommendation: rec
12182
12196
  };
12183
12197
  }
12198
+ function deriveDeliveryCompletedStatus(dir) {
12199
+ const wis = discoverWorkItems(dir);
12200
+ const completed = wis.filter((w) => lifecycleStateOf({ status: w.status, filePath: w.filePath }) === "completed");
12201
+ if (completed.length === 0) return "delivery-completed";
12202
+ const hasReleaseBlocked = completed.some((w) => w.releaseStatus === "blocked");
12203
+ const hasReleaseReady = completed.some((w) => w.releaseStatus === "ready" || w.releaseStatus === "released");
12204
+ if (hasReleaseBlocked) return "delivery-completed-release-blocked";
12205
+ if (hasReleaseReady) return "delivery-completed-release-ready";
12206
+ return "delivery-completed";
12207
+ }
12184
12208
 
12185
12209
  // src/core/assets.ts
12186
12210
  import matter5 from "gray-matter";
@@ -12544,7 +12568,7 @@ var refineWorkItem = {
12544
12568
  id: "refine-work-item",
12545
12569
  label: "Refine Work Item",
12546
12570
  evaluate: (ctx) => {
12547
- if (ctx.readyWorkItems > 0 || ctx.inProgressWorkItems > 0) return { status: "done" };
12571
+ if (ctx.readyWorkItems > 0 || ctx.inProgressWorkItems > 0 || ctx.blockedWorkItems > 0 || ctx.completedWorkItems > 0 || ctx.archivedWorkItems > 0) return { status: "done" };
12548
12572
  if (ctx.draftWorkItems > 0) {
12549
12573
  return {
12550
12574
  status: "current",
@@ -12795,7 +12819,9 @@ function buildRouteContext(dir) {
12795
12819
  draftWorkItems: byState("draft"),
12796
12820
  readyWorkItems: byState("ready"),
12797
12821
  inProgressWorkItems: byState("in-progress"),
12822
+ blockedWorkItems: byState("blocked"),
12798
12823
  completedWorkItems: byState("completed"),
12824
+ archivedWorkItems: byState("archived"),
12799
12825
  ownershipCoverage: `${withOwnership}/${total}`,
12800
12826
  ownershipComplete: total > 0 && withOwnership >= total,
12801
12827
  decisionCandidates: td.candidates,
@@ -13210,6 +13236,20 @@ function buildProjectExplanation(dir) {
13210
13236
  scanSignals: loadScanSignals(dir),
13211
13237
  metadataHealth: analyzeMetadataHealth(dir),
13212
13238
  isModuleRepo: config != null && isModule(config),
13239
+ deliverySummary: (() => {
13240
+ const completed = workItemArtifacts.filter((a) => lifecycleStateOf({ status: a.status, filePath: a.filePath }) === "completed");
13241
+ const archived = workItemArtifacts.filter((a) => lifecycleStateOf({ status: a.status, filePath: a.filePath }) === "archived");
13242
+ const active = workItemArtifacts.filter((a) => isActiveState(lifecycleStateOf({ status: a.status, filePath: a.filePath })));
13243
+ if (completed.length === 0 && archived.length === 0) return null;
13244
+ return {
13245
+ completedWorkItems: completed.length,
13246
+ archivedWorkItems: archived.length,
13247
+ activeWorkItems: active.length,
13248
+ implementationCompleted: completed.filter((a) => a.implementationStatus === "completed").length,
13249
+ releaseBlocked: completed.filter((a) => a.releaseStatus === "blocked").length,
13250
+ releaseReady: completed.filter((a) => a.releaseStatus === "ready" || a.releaseStatus === "released").length
13251
+ };
13252
+ })(),
13213
13253
  implementationEvidence: workItemArtifacts.filter((a) => a.affectedModules.length > 0).map((a) => {
13214
13254
  const fm2 = a.rawFrontmatter;
13215
13255
  const evidence = fm2.implementation_evidence;
@@ -13221,11 +13261,13 @@ function buildProjectExplanation(dir) {
13221
13261
  status: String(data.status ?? "unknown")
13222
13262
  };
13223
13263
  }
13264
+ const lc = lifecycleStateOf({ status: a.status, filePath: a.filePath });
13265
+ const historicalDefault = lc === "completed" || lc === "archived" ? "not-assessed" : "not-started";
13224
13266
  return {
13225
13267
  id: a.id || a.title,
13226
- lifecycle: lifecycleStateOf({ status: a.status, filePath: a.filePath }),
13227
- implementationStatus: a.implementationStatus || "not-started",
13228
- validationStatus: a.validationStatus || "not-started",
13268
+ lifecycle: lc,
13269
+ implementationStatus: a.implementationStatus || historicalDefault,
13270
+ validationStatus: a.validationStatus || historicalDefault,
13229
13271
  releaseStatus: a.releaseStatus || "not-assessed",
13230
13272
  affectedModules: a.affectedModules,
13231
13273
  releaseGates: Array.isArray(fm2.release_gates) ? fm2.release_gates : [],
@@ -13470,6 +13512,17 @@ function renderExplanationHuman(exp) {
13470
13512
  }
13471
13513
  lines.push(`- Next step: ${exp.readiness.recommended_next_step.label}`);
13472
13514
  lines.push("");
13515
+ if (exp.deliverySummary) {
13516
+ const ds = exp.deliverySummary;
13517
+ lines.push("## Delivery Summary");
13518
+ lines.push(`- Completed Work Items: ${ds.completedWorkItems}`);
13519
+ if (ds.archivedWorkItems > 0) lines.push(`- Archived Work Items: ${ds.archivedWorkItems}`);
13520
+ lines.push(`- Active Work Items: ${ds.activeWorkItems}`);
13521
+ if (ds.implementationCompleted > 0) lines.push(`- Implementation completed: ${ds.implementationCompleted}`);
13522
+ if (ds.releaseBlocked > 0) lines.push(`- Release blocked: ${ds.releaseBlocked}`);
13523
+ if (ds.releaseReady > 0) lines.push(`- Release ready: ${ds.releaseReady}`);
13524
+ lines.push("");
13525
+ }
13473
13526
  const rec = exp.nextStepRecommendation;
13474
13527
  const secondary = rec.secondary ?? [];
13475
13528
  const steps = secondary.length > 0 || /Delivery|Active|Maintenance/.test(rec.phase) ? [rec.label, ...secondary.map((s2) => s2.label)] : exp.suggestedNextSteps;
@@ -13504,6 +13557,10 @@ function renderExplanationHuman(exp) {
13504
13557
  if (!exp.isModuleRepo) {
13505
13558
  lines.push(`- roadmap: ${s.roadmap}`);
13506
13559
  lines.push(`- work-items: ${s.work_items}`);
13560
+ if (exp.deliverySummary) {
13561
+ lines.push(`- work-items completed: ${exp.deliverySummary.completedWorkItems}`);
13562
+ lines.push(`- work-items active: ${exp.deliverySummary.activeWorkItems}`);
13563
+ }
13507
13564
  lines.push(`- adapters: ${s.adapters.length > 0 ? s.adapters.join(", ") + " installed" : "none installed"}`);
13508
13565
  } else {
13509
13566
  lines.push("- roadmap: managed-by-core");
@@ -13845,19 +13902,21 @@ var OPERATING_RULES = [
13845
13902
  "Kaddo itself never calls an LLM and never runs git \u2014 every git action is the human\u2019s."
13846
13903
  ];
13847
13904
  function toContextWorkItem(a) {
13905
+ const lifecycle = lifecycleStateOf({ status: a.status, filePath: a.filePath });
13906
+ const isHistorical = lifecycle === "completed" || lifecycle === "archived";
13848
13907
  const wi = {
13849
13908
  id: a.id,
13850
13909
  type: a.type,
13851
13910
  title: a.title,
13852
13911
  status: a.status,
13853
- lifecycle: lifecycleStateOf({ status: a.status, filePath: a.filePath }),
13912
+ lifecycle,
13854
13913
  knowledgeLevel: a.knowledgeLevel,
13855
13914
  domains: a.domains,
13856
13915
  source: parseWorkItemSource(a.rawFrontmatter)
13857
13916
  };
13858
- if (a.implementationStatus) wi.implementationStatus = a.implementationStatus;
13859
- if (a.validationStatus) wi.validationStatus = a.validationStatus;
13860
- if (a.releaseStatus) wi.releaseStatus = a.releaseStatus;
13917
+ wi.implementationStatus = a.implementationStatus || (isHistorical ? "not-assessed" : void 0);
13918
+ wi.validationStatus = a.validationStatus || (isHistorical ? "not-assessed" : void 0);
13919
+ wi.releaseStatus = a.releaseStatus || (isHistorical ? "not-assessed" : void 0);
13861
13920
  if (a.affectedModules.length > 0) wi.affectedModules = a.affectedModules;
13862
13921
  return wi;
13863
13922
  }
@@ -13888,10 +13947,17 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
13888
13947
  missing.push("No roadmap baseline found.");
13889
13948
  }
13890
13949
  const allArtifacts = discoverKnowledge(dir);
13891
- const workItems = allArtifacts.filter(
13892
- (a) => isDeliveryWorkItem(a) && isActiveState(lifecycleStateOf({ status: a.status, filePath: a.filePath }))
13950
+ const allWorkItemArtifacts = allArtifacts.filter((a) => isDeliveryWorkItem(a));
13951
+ const workItems = allWorkItemArtifacts.filter(
13952
+ (a) => isActiveState(lifecycleStateOf({ status: a.status, filePath: a.filePath }))
13953
+ );
13954
+ const completedWorkItems = allWorkItemArtifacts.filter(
13955
+ (a) => lifecycleStateOf({ status: a.status, filePath: a.filePath }) === "completed"
13893
13956
  );
13894
- if (workItems.length === 0 && !moduleRepo) {
13957
+ const archivedWorkItems = allWorkItemArtifacts.filter(
13958
+ (a) => lifecycleStateOf({ status: a.status, filePath: a.filePath }) === "archived"
13959
+ );
13960
+ if (allWorkItemArtifacts.length === 0 && !moduleRepo) {
13895
13961
  missing.push("No work items found.");
13896
13962
  }
13897
13963
  const state = config.project.state;
@@ -14006,6 +14072,10 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
14006
14072
  roadmapSummary,
14007
14073
  inventoryAvailable,
14008
14074
  workItems: workItems.map(toContextWorkItem),
14075
+ activeWorkItems: workItems.map(toContextWorkItem),
14076
+ completedWorkItems: completedWorkItems.map(toContextWorkItem),
14077
+ archivedWorkItems: archivedWorkItems.map(toContextWorkItem),
14078
+ allWorkItems: allWorkItemArtifacts.map(toContextWorkItem),
14009
14079
  artifacts: allArtifacts.filter((a) => a.codeGlobs.length > 0).map(toContextArtifact)
14010
14080
  },
14011
14081
  layers,
@@ -14022,6 +14092,30 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
14022
14092
  const compact = (a) => ({ total: a.total, installed: a.total - a.missing, outdated: a.outdated, unknown_version: a.unknown_version, modified: a.modified });
14023
14093
  return { version: s.version, agents: compact(s.agents), skills: compact(s.skills) };
14024
14094
  })(),
14095
+ workItemSummary: (() => {
14096
+ const lc = (s) => allWorkItemArtifacts.filter(
14097
+ (a) => lifecycleStateOf({ status: a.status, filePath: a.filePath }) === s
14098
+ ).length;
14099
+ const draft = lc("draft");
14100
+ const ready = lc("ready");
14101
+ const inProgress = lc("in-progress");
14102
+ const blocked = lc("blocked");
14103
+ const completed = lc("completed");
14104
+ const archived = lc("archived");
14105
+ const active = draft + ready + inProgress + blocked;
14106
+ const total = allWorkItemArtifacts.length;
14107
+ let summary = "none";
14108
+ if (total === 0) summary = "none";
14109
+ else if (active === 0 && completed > 0 && archived === 0) summary = "completed-only";
14110
+ else if (active === 0 && archived > 0 && completed === 0) summary = "archived-only";
14111
+ else if (active === 0 && completed + archived > 0) summary = "historical-only";
14112
+ else if (inProgress > 0) summary = "active";
14113
+ else if (blocked > 0 && ready === 0 && inProgress === 0) summary = "blocked";
14114
+ else if (ready > 0) summary = "ready";
14115
+ else if (draft > 0 && ready === 0) summary = "draft-only";
14116
+ else summary = "mixed-active";
14117
+ return { total, active, draft, ready, in_progress: inProgress, blocked, completed, archived, summary };
14118
+ })(),
14025
14119
  deliveryMix,
14026
14120
  external: loadExternalCapsules(dir),
14027
14121
  graph: loadGraphSummary(dir),
@@ -14950,6 +15044,16 @@ function runUnderstand() {
14950
15044
  } else if (rec.agentPath) {
14951
15045
  console.log(` Agent prompt: ${rec.agentPath}`);
14952
15046
  }
15047
+ if (exp.deliverySummary) {
15048
+ const ds2 = exp.deliverySummary;
15049
+ console.log("");
15050
+ console.log("Previous delivery:");
15051
+ console.log(` - Completed Work Items: ${ds2.completedWorkItems}`);
15052
+ if (ds2.implementationCompleted > 0) console.log(` - Implementation completed: ${ds2.implementationCompleted}`);
15053
+ if (ds2.releaseBlocked > 0) console.log(` - Release blocked: ${ds2.releaseBlocked}`);
15054
+ if (ds2.releaseReady > 0) console.log(` - Release ready: ${ds2.releaseReady}`);
15055
+ console.log(` - Current active work: ${ds2.activeWorkItems > 0 ? ds2.activeWorkItems : "none"}`);
15056
+ }
14953
15057
  if (rec.skill) console.log(`Recommended skill: ${rec.skill}`);
14954
15058
  console.log(`Next step: ${rec.label}`);
14955
15059
  if (rec.reason) console.log(`Why: ${rec.reason}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/cli",
3
- "version": "3.66.0",
3
+ "version": "3.67.0",
4
4
  "description": "Knowledge Driven Development toolkit",
5
5
  "license": "MIT",
6
6
  "repository": {