@kaddo/mcp 3.66.0 → 3.68.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 +389 -29
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -500,6 +500,53 @@ function isCore(config) {
500
500
 
501
501
  // ../cli/src/services/artifact-reader.ts
502
502
  import matter3 from "gray-matter";
503
+ var VALID_SCOPE_CONFIDENCE_LEVELS = /* @__PURE__ */ new Set(["high", "medium", "low"]);
504
+ var VALID_COVERAGE_STATUSES = /* @__PURE__ */ new Set(["affected", "reviewed-not-affected", "unknown", "not-applicable"]);
505
+ function parseScopeConfidence(data) {
506
+ const sc = data.scope_confidence;
507
+ if (!sc || typeof sc !== "object" || Array.isArray(sc)) return null;
508
+ const obj = sc;
509
+ const level = String(obj.level ?? "");
510
+ if (!VALID_SCOPE_CONFIDENCE_LEVELS.has(level)) return null;
511
+ const reasons = Array.isArray(obj.reasons) ? obj.reasons.map(String).filter(Boolean) : [];
512
+ return { level, reasons };
513
+ }
514
+ function parseModuleCoverage(data) {
515
+ const mc = data.module_coverage;
516
+ if (!mc || typeof mc !== "object" || Array.isArray(mc)) return null;
517
+ const result = {};
518
+ for (const [id, val] of Object.entries(mc)) {
519
+ if (!val || typeof val !== "object" || Array.isArray(val)) continue;
520
+ const v = val;
521
+ const status = String(v.status ?? "");
522
+ if (!VALID_COVERAGE_STATUSES.has(status)) continue;
523
+ result[id] = {
524
+ status,
525
+ ...v.reason ? { reason: String(v.reason) } : {},
526
+ ...Array.isArray(v.evidence) ? { evidence: v.evidence.map(String).filter(Boolean) } : {}
527
+ };
528
+ }
529
+ return Object.keys(result).length > 0 ? result : null;
530
+ }
531
+ function parseImpactAnalysis(data) {
532
+ const ia = data.impact_analysis;
533
+ if (!ia || typeof ia !== "object" || Array.isArray(ia)) return null;
534
+ const surfaces = ia.surfaces;
535
+ if (!surfaces || typeof surfaces !== "object" || Array.isArray(surfaces)) return null;
536
+ const result = {};
537
+ for (const [id, val] of Object.entries(surfaces)) {
538
+ if (!val || typeof val !== "object" || Array.isArray(val)) continue;
539
+ const v = val;
540
+ const status = String(v.status ?? "");
541
+ if (!VALID_COVERAGE_STATUSES.has(status)) continue;
542
+ result[id] = {
543
+ status,
544
+ ...v.reason ? { reason: String(v.reason) } : {},
545
+ ...v.question ? { question: String(v.question) } : {}
546
+ };
547
+ }
548
+ return Object.keys(result).length > 0 ? result : null;
549
+ }
503
550
  function parseArtifact(filePath, raw) {
504
551
  try {
505
552
  const { data } = matter3(raw);
@@ -528,7 +575,10 @@ function parseArtifact(filePath, raw) {
528
575
  affectedModules: Array.isArray(data.affected_modules) ? data.affected_modules.map(String).filter(Boolean) : [],
529
576
  refinedBy: String(data.refined_by ?? ""),
530
577
  implementedBy: String(data.implemented_by ?? ""),
531
- closedBy: String(data.closed_by ?? "")
578
+ closedBy: String(data.closed_by ?? ""),
579
+ scopeConfidence: parseScopeConfidence(data),
580
+ moduleCoverage: parseModuleCoverage(data),
581
+ impactAnalysis: parseImpactAnalysis(data)
532
582
  };
533
583
  } catch {
534
584
  return null;
@@ -1105,12 +1155,44 @@ domains: []
1105
1155
  capabilities: []
1106
1156
  code: []
1107
1157
  created_at: YYYY-MM-DD
1158
+ # scope_confidence:
1159
+ # level: medium
1160
+ # reasons: []
1161
+ # module_coverage:
1162
+ # core:
1163
+ # status: affected
1164
+ # reason: ""
1165
+ # impact_analysis:
1166
+ # surfaces:
1167
+ # frontend:
1168
+ # status: affected
1169
+ # reason: ""
1108
1170
  ---
1109
1171
 
1110
1172
  # <Title>
1111
1173
 
1112
1174
  > Type: feature \xB7 Level: K2
1113
1175
 
1176
+ ## Actor and outcome
1177
+
1178
+ _Who experiences the change and what is the observable result?_
1179
+
1180
+ ## Current behavior
1181
+
1182
+ _What happens today?_
1183
+
1184
+ ## Target behavior
1185
+
1186
+ _What should happen after this change?_
1187
+
1188
+ ## Entry points
1189
+
1190
+ _Where does the flow start for the actor?_
1191
+
1192
+ ## End-to-end flow
1193
+
1194
+ _Describe the complete flow from entry point to final result._
1195
+
1114
1196
  ## Problem
1115
1197
 
1116
1198
  _What problem or opportunity does this address?_
@@ -1119,9 +1201,26 @@ _What problem or opportunity does this address?_
1119
1201
 
1120
1202
  _What should be true once this is done?_
1121
1203
 
1204
+ ## Impact analysis
1205
+
1206
+ _Which surfaces are affected, reviewed-not-affected, unknown, or not-applicable?_
1207
+
1208
+ ## Module coverage
1209
+
1210
+ _For multirepo: which modules were evaluated and their status._
1211
+
1212
+ ## Scope unknowns
1213
+
1214
+ _What remains unknown? Include focused questions._
1215
+
1216
+ ## Scope confidence
1217
+
1218
+ _high / medium / low \u2014 with reasons._
1219
+
1122
1220
  ## Acceptance criteria
1123
1221
 
1124
1222
  - [ ] ...
1223
+ - [ ] _Include at least one end-to-end criterion for user-facing changes._
1125
1224
 
1126
1225
  ## Design
1127
1226
 
@@ -1153,6 +1252,9 @@ ${QUALITY}
1153
1252
  - [ ] Title is specific and action-oriented.
1154
1253
  - [ ] \`code:\` globs declared so Guard can relate changes.
1155
1254
  - [ ] Knowledge level matches the real uncertainty.
1255
+ - [ ] Actor and outcome are identified.
1256
+ - [ ] Current and target behavior are documented.
1257
+ - [ ] Scope confidence is declared.
1156
1258
  `;
1157
1259
  var ROADMAP = `---
1158
1260
  type: roadmap
@@ -3963,6 +4065,8 @@ function workItemsSignal(dir) {
3963
4065
  if (wis.length === 0) return "none";
3964
4066
  if (wis.some((w3) => w3.lifecycle === "in-progress")) return "in-progress";
3965
4067
  if (wis.some((w3) => w3.lifecycle === "ready")) return "ready";
4068
+ const hasActive = wis.some((w3) => w3.lifecycle === "draft" || w3.lifecycle === "blocked");
4069
+ if (!hasActive && wis.some((w3) => w3.lifecycle === "completed" || w3.lifecycle === "archived")) return "completed-only";
3966
4070
  return "none-ready";
3967
4071
  }
3968
4072
  function installedAdapters(dir) {
@@ -4391,6 +4495,8 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
4391
4495
  else if (understand === "missing") overall = "scanned";
4392
4496
  else if (firstWeak) overall = "knowledge-incomplete";
4393
4497
  else if (oq.summary.blocking_open > 0) overall = "needs-decisions";
4498
+ else if (work_items === "in-progress") overall = "active-implementation";
4499
+ else if (work_items === "completed-only") overall = deriveDeliveryCompletedStatus(dir);
4394
4500
  else if (roadmap !== "has-candidates") overall = "ready-for-roadmap";
4395
4501
  else if (work_items === "none" || work_items === "none-ready") overall = "ready-for-work-item";
4396
4502
  else overall = "ready-for-implementation";
@@ -4403,6 +4509,16 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
4403
4509
  nextStepRecommendation: rec
4404
4510
  };
4405
4511
  }
4512
+ function deriveDeliveryCompletedStatus(dir) {
4513
+ const wis = discoverWorkItems(dir);
4514
+ const completed = wis.filter((w3) => lifecycleStateOf({ status: w3.status, filePath: w3.filePath }) === "completed");
4515
+ if (completed.length === 0) return "delivery-completed";
4516
+ const hasReleaseBlocked = completed.some((w3) => w3.releaseStatus === "blocked");
4517
+ const hasReleaseReady = completed.some((w3) => w3.releaseStatus === "ready" || w3.releaseStatus === "released");
4518
+ if (hasReleaseBlocked) return "delivery-completed-release-blocked";
4519
+ if (hasReleaseReady) return "delivery-completed-release-ready";
4520
+ return "delivery-completed";
4521
+ }
4406
4522
 
4407
4523
  // ../cli/src/core/assets.ts
4408
4524
  import matter6 from "gray-matter";
@@ -4545,8 +4661,23 @@ The context pack and the Work Item (draft or candidate).
4545
4661
 
4546
4662
  ## Output
4547
4663
 
4548
- An improved Work Item with: problem, expected result, scope, out of scope, acceptance criteria,
4549
- validation (how to test it), definition of done, open questions and dependencies.
4664
+ An improved Work Item with: actor and outcome, current behavior, target behavior, entry points,
4665
+ end-to-end flow, impact analysis, module coverage, scope unknowns, scope confidence, problem,
4666
+ expected result, scope, out of scope, acceptance criteria (including end-to-end criteria for
4667
+ user-facing changes), validation (how to test it), definition of done, open questions and
4668
+ dependencies.
4669
+
4670
+ ## Steps
4671
+
4672
+ 1. **Outcome framing** \u2014 identify actor, current behavior, target behavior, observable completion.
4673
+ 2. **Journey reconstruction** \u2014 map entry point, interaction, service/API, state change, response,
4674
+ final outcome.
4675
+ 3. **Surface review** \u2014 evaluate: product/UI, frontend, backend, database, configuration, feature
4676
+ flags, content/copy, authentication/authorization, notifications, analytics, documentation,
4677
+ operations/release \u2014 as affected, reviewed-not-affected, unknown, or not-applicable.
4678
+ 4. **Module review** \u2014 for multirepo, evaluate each mapped module with the same statuses.
4679
+ 5. **Completeness review** \u2014 confirm: outcome covered, journey covered, modules assessed, unknowns
4680
+ visible, acceptance criteria end-to-end, scope and out-of-scope coherent.
4550
4681
 
4551
4682
  ## Rules
4552
4683
 
@@ -4554,14 +4685,23 @@ validation (how to test it), definition of done, open questions and dependencies
4554
4685
  - Do not expand scope without explicit confirmation.
4555
4686
  - Do not create mega Work Items \u2014 split when it covers multiple outcomes.
4556
4687
  - Keep acceptance criteria testable.
4688
+ - Include at least one end-to-end acceptance criterion for user-facing changes.
4689
+ - Do not reduce a product intent to the first technical implementation found.
4690
+ - Evaluate surfaces and modules before proposing files.
4557
4691
  - This skill refines scope and acceptance criteria but does not approve implementation readiness.
4558
4692
  Readiness requires human confirmation through \`kaddo ready\` or the MCP \`mark_work_item_ready\` action.
4559
4693
 
4560
4694
  ## Quality checklist
4561
4695
 
4696
+ - Actor and outcome are identified.
4697
+ - Current and target behavior are documented.
4698
+ - Journey is reconstructed for user-facing changes.
4699
+ - Surfaces and modules are evaluated with explicit statuses.
4562
4700
  - Problem and expected result are unambiguous.
4563
4701
  - Scope and out-of-scope are explicit.
4564
- - Acceptance criteria and validation are present and testable.
4702
+ - Acceptance criteria include end-to-end validation when applicable.
4703
+ - Scope unknowns are visible, not hidden.
4704
+ - Scope confidence is declared with reasons.
4565
4705
  - Open questions and dependencies are surfaced, not hidden.
4566
4706
 
4567
4707
  ## Example output
@@ -4782,14 +4922,19 @@ steps, and stop criteria (when to pause and ask).
4782
4922
  ## Rules
4783
4923
 
4784
4924
  - Do not start coding without confirmation.
4785
- - Do not expand scope.
4925
+ - Do not expand scope without updating the Work Item.
4786
4926
  - Never make commits or push \u2014 suggest only.
4927
+ - Review scope coverage before planning: check that expected result, current/target behavior,
4928
+ module coverage, and acceptance criteria are consistent. Flag contradictions (e.g., user-facing
4929
+ change with unassessed frontend module).
4787
4930
 
4788
4931
  ## Quality checklist
4789
4932
 
4933
+ - Pre-implementation scope review is documented.
4790
4934
  - Scope and expected files are explicit.
4791
4935
  - Risks and validations are listed.
4792
4936
  - Stop criteria are defined.
4937
+ - Module coverage aligns with planned changes.
4793
4938
 
4794
4939
  ## Example output
4795
4940
 
@@ -5937,18 +6082,31 @@ A refined Work Item intended to be saved under the lifecycle workspace:
5937
6082
 
5938
6083
  ## Instructions
5939
6084
 
5940
- 1. Restate the problem in one clear sentence.
5941
- 2. Split the candidate if it is too large for a single Work Item.
5942
- 3. Preserve the candidate's type (\`feature\`, \`bugfix\`, \`hotfix\`, \`spike\`, \`chore\`).
5943
- Keep \`chore\` for maintenance/tooling/config/infra work \u2014 never upgrade a chore to a feature.
5944
- 4. Validate the Knowledge Level (K0\u2013K4) and propose a different one if needed.
5945
- 5. Propose acceptance criteria.
5946
- 6. Propose an Out of scope section.
5947
- 7. Propose **how to test it** \u2014 concrete validation steps (commands to run, manual steps, or
5948
- test cases) that prove the change works once implemented. This is mandatory.
5949
- 8. Propose a Definition of Done.
5950
- 9. Identify open questions and assumptions.
5951
- 10. Suggest ownership candidates (code globs) if evident.
6085
+ 1. **Interpret the outcome** \u2014 what must change for the actor or consumer of this change.
6086
+ 2. **Identify the actor** \u2014 who experiences or triggers the change.
6087
+ 3. **Describe current behavior** \u2014 what happens today.
6088
+ 4. **Describe target behavior** \u2014 what should happen after the change.
6089
+ 5. **Reconstruct the journey** \u2014 for user-facing changes, map the end-to-end flow from entry
6090
+ point to final observable result before proposing files.
6091
+ 6. **Evaluate surfaces** \u2014 assess each potentially affected surface (frontend, backend, database,
6092
+ configuration, content, feature flags, authentication, notifications, analytics, documentation,
6093
+ operations) as \`affected\`, \`reviewed-not-affected\`, \`unknown\`, or \`not-applicable\`.
6094
+ 7. **Evaluate modules** \u2014 for multirepo projects, assess each plausibly related mapped module with
6095
+ the same statuses. A module must be \`affected\`, \`reviewed-not-affected\`, \`unknown\`, or
6096
+ \`not-applicable\`. Do not leave related modules unmentioned.
6097
+ 8. Restate the problem in one clear sentence.
6098
+ 9. Split the candidate if it is too large for a single Work Item.
6099
+ 10. Preserve the candidate's type (\`feature\`, \`bugfix\`, \`hotfix\`, \`spike\`, \`chore\`).
6100
+ Keep \`chore\` for maintenance/tooling/config/infra work \u2014 never upgrade a chore to a feature.
6101
+ 11. Validate the Knowledge Level (K0\u2013K4) and propose a different one if needed.
6102
+ 12. Propose acceptance criteria \u2014 include at least one end-to-end criterion for user-facing changes.
6103
+ 13. Propose an Out of scope section.
6104
+ 14. Propose **how to test it** \u2014 concrete validation steps (commands to run, manual steps, or
6105
+ test cases) that prove the change works once implemented. This is mandatory.
6106
+ 15. Propose a Definition of Done.
6107
+ 16. Identify open questions, assumptions, and scope unknowns.
6108
+ 17. Determine scope confidence (high, medium, low) with reasons.
6109
+ 18. Suggest ownership candidates (code globs) if evident.
5952
6110
 
5953
6111
  ## Constraints
5954
6112
 
@@ -5956,19 +6114,49 @@ A refined Work Item intended to be saved under the lifecycle workspace:
5956
6114
  - Do not invent business facts.
5957
6115
  - Do not assign a Knowledge Level higher than the change requires.
5958
6116
  - Mark assumptions explicitly.
6117
+ - Do not reduce a product intent to the first technical implementation found.
6118
+ - Inspect the observable outcome before proposing files.
6119
+ - For user-facing changes, assess the entry point, interaction surface, backend behavior, and
6120
+ final user-visible result.
6121
+ - For multirepo projects, assess each plausibly related mapped module.
6122
+ - Do not mark the Work Item ready while material scope remains unknown.
6123
+ - Ask focused questions instead of silently narrowing the request.
6124
+ - Preserve unsupported assumptions as assumptions.
5959
6125
 
5960
6126
  ## Output Format
5961
6127
 
5962
6128
  \`\`\`markdown
5963
6129
  # <Work Item title>
5964
6130
 
6131
+ **Actor and outcome:**
6132
+
6133
+ **Current behavior:**
6134
+
6135
+ **Target behavior:**
6136
+
6137
+ **Entry points:**
6138
+
6139
+ **End-to-end flow:**
6140
+
5965
6141
  **Problem:**
5966
6142
 
5967
6143
  **Expected result:**
5968
6144
 
5969
6145
  **Suggested Knowledge Level:** K1 / K2 / K3 / K4
5970
6146
 
6147
+ **Impact analysis:**
6148
+ <!-- surfaces: affected / reviewed-not-affected / unknown / not-applicable -->
6149
+
6150
+ **Module coverage:**
6151
+ <!-- for multirepo: each module as affected / reviewed-not-affected / unknown / not-applicable -->
6152
+
6153
+ **Scope unknowns:**
6154
+
6155
+ **Scope confidence:** high / medium / low
6156
+ <!-- reasons: -->
6157
+
5971
6158
  **Acceptance criteria:**
6159
+ <!-- include at least one end-to-end criterion for user-facing changes -->
5972
6160
 
5973
6161
  **Out of scope:**
5974
6162
 
@@ -6705,6 +6893,20 @@ Working code, tests and migrations, plus updated knowledge (ADR / capabilities /
6705
6893
  when the change affects them. You also produce a suggested branch name and a suggested
6706
6894
  Conventional Commit message \u2014 as suggestions, never executed.
6707
6895
 
6896
+ ## Pre-implementation Scope Review (VS-095)
6897
+
6898
+ Before implementing, review the Work Item's scope coverage:
6899
+ - Check that expected result, current behavior, and target behavior are documented.
6900
+ - Verify the journey covers the full user-facing flow when applicable.
6901
+ - Confirm affected surfaces and modules are declared.
6902
+ - Check module_coverage: if a mapped module is plausibly related but not assessed, flag it.
6903
+ - Verify acceptance criteria include end-to-end validation for user-facing changes.
6904
+ - Check for unresolved scope unknowns that could change the implementation.
6905
+
6906
+ If you find a contradiction (e.g., target behavior describes a user-facing registration flow but
6907
+ the mapped frontend module was not assessed), explain the finding, propose updating the Work Item,
6908
+ and wait for confirmation before proceeding. Do not silently expand scope.
6909
+
6708
6910
  ## Instructions
6709
6911
 
6710
6912
  1. **Suggest a branch first** (do not run it). Follow the Git strategy
@@ -7627,7 +7829,7 @@ var refineWorkItem = {
7627
7829
  id: "refine-work-item",
7628
7830
  label: "Refine Work Item",
7629
7831
  evaluate: (ctx) => {
7630
- if (ctx.readyWorkItems > 0 || ctx.inProgressWorkItems > 0) return { status: "done" };
7832
+ if (ctx.readyWorkItems > 0 || ctx.inProgressWorkItems > 0 || ctx.blockedWorkItems > 0 || ctx.completedWorkItems > 0 || ctx.archivedWorkItems > 0) return { status: "done" };
7631
7833
  if (ctx.draftWorkItems > 0) {
7632
7834
  return {
7633
7835
  status: "current",
@@ -7878,7 +8080,9 @@ function buildRouteContext(dir) {
7878
8080
  draftWorkItems: byState("draft"),
7879
8081
  readyWorkItems: byState("ready"),
7880
8082
  inProgressWorkItems: byState("in-progress"),
8083
+ blockedWorkItems: byState("blocked"),
7881
8084
  completedWorkItems: byState("completed"),
8085
+ archivedWorkItems: byState("archived"),
7882
8086
  ownershipCoverage: `${withOwnership}/${total}`,
7883
8087
  ownershipComplete: total > 0 && withOwnership >= total,
7884
8088
  decisionCandidates: td.candidates,
@@ -8368,6 +8572,30 @@ function buildProjectExplanation(dir) {
8368
8572
  scanSignals: loadScanSignals(dir),
8369
8573
  metadataHealth: analyzeMetadataHealth(dir),
8370
8574
  isModuleRepo: config != null && isModule(config),
8575
+ deliverySummary: (() => {
8576
+ const completed = workItemArtifacts.filter((a2) => lifecycleStateOf({ status: a2.status, filePath: a2.filePath }) === "completed");
8577
+ const archived = workItemArtifacts.filter((a2) => lifecycleStateOf({ status: a2.status, filePath: a2.filePath }) === "archived");
8578
+ const active = workItemArtifacts.filter((a2) => isActiveState(lifecycleStateOf({ status: a2.status, filePath: a2.filePath })));
8579
+ if (completed.length === 0 && archived.length === 0) return null;
8580
+ return {
8581
+ completedWorkItems: completed.length,
8582
+ archivedWorkItems: archived.length,
8583
+ activeWorkItems: active.length,
8584
+ implementationCompleted: completed.filter((a2) => a2.implementationStatus === "completed").length,
8585
+ releaseBlocked: completed.filter((a2) => a2.releaseStatus === "blocked").length,
8586
+ releaseReady: completed.filter((a2) => a2.releaseStatus === "ready" || a2.releaseStatus === "released").length
8587
+ };
8588
+ })(),
8589
+ scopeCoverage: workItemArtifacts.filter((a2) => a2.scopeConfidence || a2.moduleCoverage || a2.impactAnalysis).map((a2) => {
8590
+ const unknownModules = a2.moduleCoverage ? Object.entries(a2.moduleCoverage).filter(([, v]) => v.status === "unknown").map(([k2]) => k2) : [];
8591
+ return {
8592
+ id: a2.id || a2.title,
8593
+ scopeConfidence: a2.scopeConfidence,
8594
+ moduleCoverage: a2.moduleCoverage,
8595
+ unknownModules,
8596
+ hasScopeCoverage: true
8597
+ };
8598
+ }),
8371
8599
  implementationEvidence: workItemArtifacts.filter((a2) => a2.affectedModules.length > 0).map((a2) => {
8372
8600
  const fm = a2.rawFrontmatter;
8373
8601
  const evidence = fm.implementation_evidence;
@@ -8379,11 +8607,13 @@ function buildProjectExplanation(dir) {
8379
8607
  status: String(data.status ?? "unknown")
8380
8608
  };
8381
8609
  }
8610
+ const lc = lifecycleStateOf({ status: a2.status, filePath: a2.filePath });
8611
+ const historicalDefault = lc === "completed" || lc === "archived" ? "not-assessed" : "not-started";
8382
8612
  return {
8383
8613
  id: a2.id || a2.title,
8384
- lifecycle: lifecycleStateOf({ status: a2.status, filePath: a2.filePath }),
8385
- implementationStatus: a2.implementationStatus || "not-started",
8386
- validationStatus: a2.validationStatus || "not-started",
8614
+ lifecycle: lc,
8615
+ implementationStatus: a2.implementationStatus || historicalDefault,
8616
+ validationStatus: a2.validationStatus || historicalDefault,
8387
8617
  releaseStatus: a2.releaseStatus || "not-assessed",
8388
8618
  affectedModules: a2.affectedModules,
8389
8619
  releaseGates: Array.isArray(fm.release_gates) ? fm.release_gates : [],
@@ -8546,6 +8776,23 @@ function renderExplanationHuman(exp) {
8546
8776
  }
8547
8777
  lines.push("");
8548
8778
  }
8779
+ if (exp.scopeCoverage.length > 0) {
8780
+ lines.push("## Work Item Scope Coverage");
8781
+ for (const sc of exp.scopeCoverage) {
8782
+ lines.push("");
8783
+ lines.push(`### ${sc.id}`);
8784
+ if (sc.scopeConfidence) lines.push(`- Scope confidence: ${sc.scopeConfidence.level}`);
8785
+ if (sc.moduleCoverage) {
8786
+ const affected = Object.entries(sc.moduleCoverage).filter(([, v]) => v.status === "affected").map(([k2]) => k2);
8787
+ const reviewed = Object.entries(sc.moduleCoverage).filter(([, v]) => v.status === "reviewed-not-affected").map(([k2]) => k2);
8788
+ const unknown = Object.entries(sc.moduleCoverage).filter(([, v]) => v.status === "unknown").map(([k2]) => k2);
8789
+ if (affected.length > 0) lines.push(`Affected: ${affected.join(", ")}`);
8790
+ if (reviewed.length > 0) lines.push(`Reviewed, not affected: ${reviewed.join(", ")}`);
8791
+ if (unknown.length > 0) lines.push(`Unknown: ${unknown.join(", ")}`);
8792
+ }
8793
+ }
8794
+ lines.push("");
8795
+ }
8549
8796
  if (exp.domains.length > 0) {
8550
8797
  lines.push("## Domains");
8551
8798
  lines.push(`- ${exp.domains.join(", ")}`);
@@ -8628,6 +8875,17 @@ function renderExplanationHuman(exp) {
8628
8875
  }
8629
8876
  lines.push(`- Next step: ${exp.readiness.recommended_next_step.label}`);
8630
8877
  lines.push("");
8878
+ if (exp.deliverySummary) {
8879
+ const ds = exp.deliverySummary;
8880
+ lines.push("## Delivery Summary");
8881
+ lines.push(`- Completed Work Items: ${ds.completedWorkItems}`);
8882
+ if (ds.archivedWorkItems > 0) lines.push(`- Archived Work Items: ${ds.archivedWorkItems}`);
8883
+ lines.push(`- Active Work Items: ${ds.activeWorkItems}`);
8884
+ if (ds.implementationCompleted > 0) lines.push(`- Implementation completed: ${ds.implementationCompleted}`);
8885
+ if (ds.releaseBlocked > 0) lines.push(`- Release blocked: ${ds.releaseBlocked}`);
8886
+ if (ds.releaseReady > 0) lines.push(`- Release ready: ${ds.releaseReady}`);
8887
+ lines.push("");
8888
+ }
8631
8889
  const rec = exp.nextStepRecommendation;
8632
8890
  const secondary = rec.secondary ?? [];
8633
8891
  const steps = secondary.length > 0 || /Delivery|Active|Maintenance/.test(rec.phase) ? [rec.label, ...secondary.map((s2) => s2.label)] : exp.suggestedNextSteps;
@@ -8662,6 +8920,10 @@ function renderExplanationHuman(exp) {
8662
8920
  if (!exp.isModuleRepo) {
8663
8921
  lines.push(`- roadmap: ${s.roadmap}`);
8664
8922
  lines.push(`- work-items: ${s.work_items}`);
8923
+ if (exp.deliverySummary) {
8924
+ lines.push(`- work-items completed: ${exp.deliverySummary.completedWorkItems}`);
8925
+ lines.push(`- work-items active: ${exp.deliverySummary.activeWorkItems}`);
8926
+ }
8665
8927
  lines.push(`- adapters: ${s.adapters.length > 0 ? s.adapters.join(", ") + " installed" : "none installed"}`);
8666
8928
  } else {
8667
8929
  lines.push("- roadmap: managed-by-core");
@@ -9709,6 +9971,49 @@ function firstParagraph2(body) {
9709
9971
  }
9710
9972
  return "";
9711
9973
  }
9974
+ var VALID_COVERAGE_STATUSES2 = /* @__PURE__ */ new Set(["affected", "reviewed-not-affected", "unknown", "not-applicable"]);
9975
+ function parseScopeMeta(data) {
9976
+ const result = {};
9977
+ const sc = data.scope_confidence;
9978
+ if (sc && typeof sc === "object" && !Array.isArray(sc)) {
9979
+ const obj = sc;
9980
+ const level = String(obj.level ?? "");
9981
+ if (["high", "medium", "low"].includes(level)) {
9982
+ result.scope_confidence = { level, reasons: Array.isArray(obj.reasons) ? obj.reasons.map(String) : [] };
9983
+ }
9984
+ }
9985
+ const mc = data.module_coverage;
9986
+ if (mc && typeof mc === "object" && !Array.isArray(mc)) {
9987
+ const parsed = {};
9988
+ const unknowns = [];
9989
+ for (const [id, val] of Object.entries(mc)) {
9990
+ if (!val || typeof val !== "object" || Array.isArray(val)) continue;
9991
+ const v = val;
9992
+ const status = String(v.status ?? "");
9993
+ if (!VALID_COVERAGE_STATUSES2.has(status)) continue;
9994
+ parsed[id] = { status, ...v.reason ? { reason: String(v.reason) } : {} };
9995
+ if (status === "unknown") unknowns.push(id);
9996
+ }
9997
+ if (Object.keys(parsed).length > 0) result.module_coverage = parsed;
9998
+ if (unknowns.length > 0) result.scope_unknowns = unknowns;
9999
+ }
10000
+ const ia = data.impact_analysis;
10001
+ if (ia && typeof ia === "object" && !Array.isArray(ia)) {
10002
+ const surfaces = ia.surfaces;
10003
+ if (surfaces && typeof surfaces === "object" && !Array.isArray(surfaces)) {
10004
+ const parsed = {};
10005
+ for (const [id, val] of Object.entries(surfaces)) {
10006
+ if (!val || typeof val !== "object" || Array.isArray(val)) continue;
10007
+ const v = val;
10008
+ const status = String(v.status ?? "");
10009
+ if (!VALID_COVERAGE_STATUSES2.has(status)) continue;
10010
+ parsed[id] = { status, ...v.reason ? { reason: String(v.reason) } : {} };
10011
+ }
10012
+ if (Object.keys(parsed).length > 0) result.impact_analysis = parsed;
10013
+ }
10014
+ }
10015
+ return result;
10016
+ }
9712
10017
  function listWorkItems(root) {
9713
10018
  const files = listFiles(root, "knowledge/delivery/work-items", ".md");
9714
10019
  const items = [];
@@ -9751,7 +10056,8 @@ function listWorkItems(root) {
9751
10056
  ...data.implemented_by ? { implemented_by: String(data.implemented_by) } : {},
9752
10057
  ...data.closed_by ? { closed_by: String(data.closed_by) } : {},
9753
10058
  ...Array.isArray(data.release_gates) && data.release_gates.length > 0 ? { release_gates: data.release_gates } : {},
9754
- ...Array.isArray(data.completion_exceptions) && data.completion_exceptions.length > 0 ? { completion_exceptions: data.completion_exceptions } : {}
10059
+ ...Array.isArray(data.completion_exceptions) && data.completion_exceptions.length > 0 ? { completion_exceptions: data.completion_exceptions } : {},
10060
+ ...parseScopeMeta(data)
9755
10061
  });
9756
10062
  }
9757
10063
  return items.sort((a2, b2) => a2.id.localeCompare(b2.id));
@@ -10173,6 +10479,16 @@ function projectStatus(root) {
10173
10479
  agents: "managed-by-core",
10174
10480
  skills: "managed-by-core"
10175
10481
  };
10482
+ } else {
10483
+ result.readiness = {
10484
+ overall: explain.readiness?.overall ?? "unknown"
10485
+ };
10486
+ }
10487
+ if (explain.deliverySummary) {
10488
+ result.deliverySummary = explain.deliverySummary;
10489
+ }
10490
+ if (explain.scopeCoverage && Array.isArray(explain.scopeCoverage) && explain.scopeCoverage.length > 0) {
10491
+ result.scopeCoverage = explain.scopeCoverage;
10176
10492
  }
10177
10493
  return ok(result);
10178
10494
  }
@@ -10876,20 +11192,29 @@ var OPERATING_RULES = [
10876
11192
  "Kaddo itself never calls an LLM and never runs git \u2014 every git action is the human\u2019s."
10877
11193
  ];
10878
11194
  function toContextWorkItem(a2) {
11195
+ const lifecycle = lifecycleStateOf({ status: a2.status, filePath: a2.filePath });
11196
+ const isHistorical = lifecycle === "completed" || lifecycle === "archived";
10879
11197
  const wi = {
10880
11198
  id: a2.id,
10881
11199
  type: a2.type,
10882
11200
  title: a2.title,
10883
11201
  status: a2.status,
10884
- lifecycle: lifecycleStateOf({ status: a2.status, filePath: a2.filePath }),
11202
+ lifecycle,
10885
11203
  knowledgeLevel: a2.knowledgeLevel,
10886
11204
  domains: a2.domains,
10887
11205
  source: parseWorkItemSource(a2.rawFrontmatter)
10888
11206
  };
10889
- if (a2.implementationStatus) wi.implementationStatus = a2.implementationStatus;
10890
- if (a2.validationStatus) wi.validationStatus = a2.validationStatus;
10891
- if (a2.releaseStatus) wi.releaseStatus = a2.releaseStatus;
11207
+ wi.implementationStatus = a2.implementationStatus || (isHistorical ? "not-assessed" : void 0);
11208
+ wi.validationStatus = a2.validationStatus || (isHistorical ? "not-assessed" : void 0);
11209
+ wi.releaseStatus = a2.releaseStatus || (isHistorical ? "not-assessed" : void 0);
10892
11210
  if (a2.affectedModules.length > 0) wi.affectedModules = a2.affectedModules;
11211
+ if (a2.scopeConfidence) wi.scopeConfidence = a2.scopeConfidence;
11212
+ if (a2.moduleCoverage) wi.moduleCoverage = a2.moduleCoverage;
11213
+ if (a2.impactAnalysis) wi.impactAnalysis = a2.impactAnalysis;
11214
+ if (a2.moduleCoverage) {
11215
+ const unknowns = Object.entries(a2.moduleCoverage).filter(([, v]) => v.status === "unknown").map(([k2]) => k2);
11216
+ if (unknowns.length > 0) wi.scopeUnknowns = unknowns;
11217
+ }
10893
11218
  return wi;
10894
11219
  }
10895
11220
  function toContextArtifact(a2) {
@@ -10919,10 +11244,17 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
10919
11244
  missing.push("No roadmap baseline found.");
10920
11245
  }
10921
11246
  const allArtifacts = discoverKnowledge(dir);
10922
- const workItems = allArtifacts.filter(
10923
- (a2) => isDeliveryWorkItem(a2) && isActiveState(lifecycleStateOf({ status: a2.status, filePath: a2.filePath }))
11247
+ const allWorkItemArtifacts = allArtifacts.filter((a2) => isDeliveryWorkItem(a2));
11248
+ const workItems = allWorkItemArtifacts.filter(
11249
+ (a2) => isActiveState(lifecycleStateOf({ status: a2.status, filePath: a2.filePath }))
11250
+ );
11251
+ const completedWorkItems = allWorkItemArtifacts.filter(
11252
+ (a2) => lifecycleStateOf({ status: a2.status, filePath: a2.filePath }) === "completed"
10924
11253
  );
10925
- if (workItems.length === 0 && !moduleRepo) {
11254
+ const archivedWorkItems = allWorkItemArtifacts.filter(
11255
+ (a2) => lifecycleStateOf({ status: a2.status, filePath: a2.filePath }) === "archived"
11256
+ );
11257
+ if (allWorkItemArtifacts.length === 0 && !moduleRepo) {
10926
11258
  missing.push("No work items found.");
10927
11259
  }
10928
11260
  const state = config.project.state;
@@ -11037,6 +11369,10 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
11037
11369
  roadmapSummary,
11038
11370
  inventoryAvailable,
11039
11371
  workItems: workItems.map(toContextWorkItem),
11372
+ activeWorkItems: workItems.map(toContextWorkItem),
11373
+ completedWorkItems: completedWorkItems.map(toContextWorkItem),
11374
+ archivedWorkItems: archivedWorkItems.map(toContextWorkItem),
11375
+ allWorkItems: allWorkItemArtifacts.map(toContextWorkItem),
11040
11376
  artifacts: allArtifacts.filter((a2) => a2.codeGlobs.length > 0).map(toContextArtifact)
11041
11377
  },
11042
11378
  layers,
@@ -11053,6 +11389,30 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
11053
11389
  const compact = (a2) => ({ total: a2.total, installed: a2.total - a2.missing, outdated: a2.outdated, unknown_version: a2.unknown_version, modified: a2.modified });
11054
11390
  return { version: s.version, agents: compact(s.agents), skills: compact(s.skills) };
11055
11391
  })(),
11392
+ workItemSummary: (() => {
11393
+ const lc = (s) => allWorkItemArtifacts.filter(
11394
+ (a2) => lifecycleStateOf({ status: a2.status, filePath: a2.filePath }) === s
11395
+ ).length;
11396
+ const draft = lc("draft");
11397
+ const ready = lc("ready");
11398
+ const inProgress = lc("in-progress");
11399
+ const blocked = lc("blocked");
11400
+ const completed = lc("completed");
11401
+ const archived = lc("archived");
11402
+ const active = draft + ready + inProgress + blocked;
11403
+ const total = allWorkItemArtifacts.length;
11404
+ let summary = "none";
11405
+ if (total === 0) summary = "none";
11406
+ else if (active === 0 && completed > 0 && archived === 0) summary = "completed-only";
11407
+ else if (active === 0 && archived > 0 && completed === 0) summary = "archived-only";
11408
+ else if (active === 0 && completed + archived > 0) summary = "historical-only";
11409
+ else if (inProgress > 0) summary = "active";
11410
+ else if (blocked > 0 && ready === 0 && inProgress === 0) summary = "blocked";
11411
+ else if (ready > 0) summary = "ready";
11412
+ else if (draft > 0 && ready === 0) summary = "draft-only";
11413
+ else summary = "mixed-active";
11414
+ return { total, active, draft, ready, in_progress: inProgress, blocked, completed, archived, summary };
11415
+ })(),
11056
11416
  deliveryMix,
11057
11417
  external: loadExternalCapsules(dir),
11058
11418
  graph: loadGraphSummary(dir),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaddo/mcp",
3
- "version": "3.66.0",
3
+ "version": "3.68.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": {