@kaddo/cli 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.
- package/dist/index.js +531 -30
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2455,8 +2455,23 @@ The context pack and the Work Item (draft or candidate).
|
|
|
2455
2455
|
|
|
2456
2456
|
## Output
|
|
2457
2457
|
|
|
2458
|
-
An improved Work Item with:
|
|
2459
|
-
|
|
2458
|
+
An improved Work Item with: actor and outcome, current behavior, target behavior, entry points,
|
|
2459
|
+
end-to-end flow, impact analysis, module coverage, scope unknowns, scope confidence, problem,
|
|
2460
|
+
expected result, scope, out of scope, acceptance criteria (including end-to-end criteria for
|
|
2461
|
+
user-facing changes), validation (how to test it), definition of done, open questions and
|
|
2462
|
+
dependencies.
|
|
2463
|
+
|
|
2464
|
+
## Steps
|
|
2465
|
+
|
|
2466
|
+
1. **Outcome framing** \u2014 identify actor, current behavior, target behavior, observable completion.
|
|
2467
|
+
2. **Journey reconstruction** \u2014 map entry point, interaction, service/API, state change, response,
|
|
2468
|
+
final outcome.
|
|
2469
|
+
3. **Surface review** \u2014 evaluate: product/UI, frontend, backend, database, configuration, feature
|
|
2470
|
+
flags, content/copy, authentication/authorization, notifications, analytics, documentation,
|
|
2471
|
+
operations/release \u2014 as affected, reviewed-not-affected, unknown, or not-applicable.
|
|
2472
|
+
4. **Module review** \u2014 for multirepo, evaluate each mapped module with the same statuses.
|
|
2473
|
+
5. **Completeness review** \u2014 confirm: outcome covered, journey covered, modules assessed, unknowns
|
|
2474
|
+
visible, acceptance criteria end-to-end, scope and out-of-scope coherent.
|
|
2460
2475
|
|
|
2461
2476
|
## Rules
|
|
2462
2477
|
|
|
@@ -2464,14 +2479,23 @@ validation (how to test it), definition of done, open questions and dependencies
|
|
|
2464
2479
|
- Do not expand scope without explicit confirmation.
|
|
2465
2480
|
- Do not create mega Work Items \u2014 split when it covers multiple outcomes.
|
|
2466
2481
|
- Keep acceptance criteria testable.
|
|
2482
|
+
- Include at least one end-to-end acceptance criterion for user-facing changes.
|
|
2483
|
+
- Do not reduce a product intent to the first technical implementation found.
|
|
2484
|
+
- Evaluate surfaces and modules before proposing files.
|
|
2467
2485
|
- This skill refines scope and acceptance criteria but does not approve implementation readiness.
|
|
2468
2486
|
Readiness requires human confirmation through \`kaddo ready\` or the MCP \`mark_work_item_ready\` action.
|
|
2469
2487
|
|
|
2470
2488
|
## Quality checklist
|
|
2471
2489
|
|
|
2490
|
+
- Actor and outcome are identified.
|
|
2491
|
+
- Current and target behavior are documented.
|
|
2492
|
+
- Journey is reconstructed for user-facing changes.
|
|
2493
|
+
- Surfaces and modules are evaluated with explicit statuses.
|
|
2472
2494
|
- Problem and expected result are unambiguous.
|
|
2473
2495
|
- Scope and out-of-scope are explicit.
|
|
2474
|
-
- Acceptance criteria
|
|
2496
|
+
- Acceptance criteria include end-to-end validation when applicable.
|
|
2497
|
+
- Scope unknowns are visible, not hidden.
|
|
2498
|
+
- Scope confidence is declared with reasons.
|
|
2475
2499
|
- Open questions and dependencies are surfaced, not hidden.
|
|
2476
2500
|
|
|
2477
2501
|
## Example output
|
|
@@ -2692,14 +2716,19 @@ steps, and stop criteria (when to pause and ask).
|
|
|
2692
2716
|
## Rules
|
|
2693
2717
|
|
|
2694
2718
|
- Do not start coding without confirmation.
|
|
2695
|
-
- Do not expand scope.
|
|
2719
|
+
- Do not expand scope without updating the Work Item.
|
|
2696
2720
|
- Never make commits or push \u2014 suggest only.
|
|
2721
|
+
- Review scope coverage before planning: check that expected result, current/target behavior,
|
|
2722
|
+
module coverage, and acceptance criteria are consistent. Flag contradictions (e.g., user-facing
|
|
2723
|
+
change with unassessed frontend module).
|
|
2697
2724
|
|
|
2698
2725
|
## Quality checklist
|
|
2699
2726
|
|
|
2727
|
+
- Pre-implementation scope review is documented.
|
|
2700
2728
|
- Scope and expected files are explicit.
|
|
2701
2729
|
- Risks and validations are listed.
|
|
2702
2730
|
- Stop criteria are defined.
|
|
2731
|
+
- Module coverage aligns with planned changes.
|
|
2703
2732
|
|
|
2704
2733
|
## Example output
|
|
2705
2734
|
|
|
@@ -3863,18 +3892,31 @@ A refined Work Item intended to be saved under the lifecycle workspace:
|
|
|
3863
3892
|
|
|
3864
3893
|
## Instructions
|
|
3865
3894
|
|
|
3866
|
-
1.
|
|
3867
|
-
2.
|
|
3868
|
-
3.
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
6.
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3895
|
+
1. **Interpret the outcome** \u2014 what must change for the actor or consumer of this change.
|
|
3896
|
+
2. **Identify the actor** \u2014 who experiences or triggers the change.
|
|
3897
|
+
3. **Describe current behavior** \u2014 what happens today.
|
|
3898
|
+
4. **Describe target behavior** \u2014 what should happen after the change.
|
|
3899
|
+
5. **Reconstruct the journey** \u2014 for user-facing changes, map the end-to-end flow from entry
|
|
3900
|
+
point to final observable result before proposing files.
|
|
3901
|
+
6. **Evaluate surfaces** \u2014 assess each potentially affected surface (frontend, backend, database,
|
|
3902
|
+
configuration, content, feature flags, authentication, notifications, analytics, documentation,
|
|
3903
|
+
operations) as \`affected\`, \`reviewed-not-affected\`, \`unknown\`, or \`not-applicable\`.
|
|
3904
|
+
7. **Evaluate modules** \u2014 for multirepo projects, assess each plausibly related mapped module with
|
|
3905
|
+
the same statuses. A module must be \`affected\`, \`reviewed-not-affected\`, \`unknown\`, or
|
|
3906
|
+
\`not-applicable\`. Do not leave related modules unmentioned.
|
|
3907
|
+
8. Restate the problem in one clear sentence.
|
|
3908
|
+
9. Split the candidate if it is too large for a single Work Item.
|
|
3909
|
+
10. Preserve the candidate's type (\`feature\`, \`bugfix\`, \`hotfix\`, \`spike\`, \`chore\`).
|
|
3910
|
+
Keep \`chore\` for maintenance/tooling/config/infra work \u2014 never upgrade a chore to a feature.
|
|
3911
|
+
11. Validate the Knowledge Level (K0\u2013K4) and propose a different one if needed.
|
|
3912
|
+
12. Propose acceptance criteria \u2014 include at least one end-to-end criterion for user-facing changes.
|
|
3913
|
+
13. Propose an Out of scope section.
|
|
3914
|
+
14. Propose **how to test it** \u2014 concrete validation steps (commands to run, manual steps, or
|
|
3915
|
+
test cases) that prove the change works once implemented. This is mandatory.
|
|
3916
|
+
15. Propose a Definition of Done.
|
|
3917
|
+
16. Identify open questions, assumptions, and scope unknowns.
|
|
3918
|
+
17. Determine scope confidence (high, medium, low) with reasons.
|
|
3919
|
+
18. Suggest ownership candidates (code globs) if evident.
|
|
3878
3920
|
|
|
3879
3921
|
## Constraints
|
|
3880
3922
|
|
|
@@ -3882,19 +3924,49 @@ A refined Work Item intended to be saved under the lifecycle workspace:
|
|
|
3882
3924
|
- Do not invent business facts.
|
|
3883
3925
|
- Do not assign a Knowledge Level higher than the change requires.
|
|
3884
3926
|
- Mark assumptions explicitly.
|
|
3927
|
+
- Do not reduce a product intent to the first technical implementation found.
|
|
3928
|
+
- Inspect the observable outcome before proposing files.
|
|
3929
|
+
- For user-facing changes, assess the entry point, interaction surface, backend behavior, and
|
|
3930
|
+
final user-visible result.
|
|
3931
|
+
- For multirepo projects, assess each plausibly related mapped module.
|
|
3932
|
+
- Do not mark the Work Item ready while material scope remains unknown.
|
|
3933
|
+
- Ask focused questions instead of silently narrowing the request.
|
|
3934
|
+
- Preserve unsupported assumptions as assumptions.
|
|
3885
3935
|
|
|
3886
3936
|
## Output Format
|
|
3887
3937
|
|
|
3888
3938
|
\`\`\`markdown
|
|
3889
3939
|
# <Work Item title>
|
|
3890
3940
|
|
|
3941
|
+
**Actor and outcome:**
|
|
3942
|
+
|
|
3943
|
+
**Current behavior:**
|
|
3944
|
+
|
|
3945
|
+
**Target behavior:**
|
|
3946
|
+
|
|
3947
|
+
**Entry points:**
|
|
3948
|
+
|
|
3949
|
+
**End-to-end flow:**
|
|
3950
|
+
|
|
3891
3951
|
**Problem:**
|
|
3892
3952
|
|
|
3893
3953
|
**Expected result:**
|
|
3894
3954
|
|
|
3895
3955
|
**Suggested Knowledge Level:** K1 / K2 / K3 / K4
|
|
3896
3956
|
|
|
3957
|
+
**Impact analysis:**
|
|
3958
|
+
<!-- surfaces: affected / reviewed-not-affected / unknown / not-applicable -->
|
|
3959
|
+
|
|
3960
|
+
**Module coverage:**
|
|
3961
|
+
<!-- for multirepo: each module as affected / reviewed-not-affected / unknown / not-applicable -->
|
|
3962
|
+
|
|
3963
|
+
**Scope unknowns:**
|
|
3964
|
+
|
|
3965
|
+
**Scope confidence:** high / medium / low
|
|
3966
|
+
<!-- reasons: -->
|
|
3967
|
+
|
|
3897
3968
|
**Acceptance criteria:**
|
|
3969
|
+
<!-- include at least one end-to-end criterion for user-facing changes -->
|
|
3898
3970
|
|
|
3899
3971
|
**Out of scope:**
|
|
3900
3972
|
|
|
@@ -4631,6 +4703,20 @@ Working code, tests and migrations, plus updated knowledge (ADR / capabilities /
|
|
|
4631
4703
|
when the change affects them. You also produce a suggested branch name and a suggested
|
|
4632
4704
|
Conventional Commit message \u2014 as suggestions, never executed.
|
|
4633
4705
|
|
|
4706
|
+
## Pre-implementation Scope Review (VS-095)
|
|
4707
|
+
|
|
4708
|
+
Before implementing, review the Work Item's scope coverage:
|
|
4709
|
+
- Check that expected result, current behavior, and target behavior are documented.
|
|
4710
|
+
- Verify the journey covers the full user-facing flow when applicable.
|
|
4711
|
+
- Confirm affected surfaces and modules are declared.
|
|
4712
|
+
- Check module_coverage: if a mapped module is plausibly related but not assessed, flag it.
|
|
4713
|
+
- Verify acceptance criteria include end-to-end validation for user-facing changes.
|
|
4714
|
+
- Check for unresolved scope unknowns that could change the implementation.
|
|
4715
|
+
|
|
4716
|
+
If you find a contradiction (e.g., target behavior describes a user-facing registration flow but
|
|
4717
|
+
the mapped frontend module was not assessed), explain the finding, propose updating the Work Item,
|
|
4718
|
+
and wait for confirmation before proceeding. Do not silently expand scope.
|
|
4719
|
+
|
|
4634
4720
|
## Instructions
|
|
4635
4721
|
|
|
4636
4722
|
1. **Suggest a branch first** (do not run it). Follow the Git strategy
|
|
@@ -6380,6 +6466,53 @@ async function getUntrackedFiles() {
|
|
|
6380
6466
|
|
|
6381
6467
|
// src/services/artifact-reader.ts
|
|
6382
6468
|
import matter from "gray-matter";
|
|
6469
|
+
var VALID_SCOPE_CONFIDENCE_LEVELS = /* @__PURE__ */ new Set(["high", "medium", "low"]);
|
|
6470
|
+
var VALID_COVERAGE_STATUSES = /* @__PURE__ */ new Set(["affected", "reviewed-not-affected", "unknown", "not-applicable"]);
|
|
6471
|
+
function parseScopeConfidence(data) {
|
|
6472
|
+
const sc = data.scope_confidence;
|
|
6473
|
+
if (!sc || typeof sc !== "object" || Array.isArray(sc)) return null;
|
|
6474
|
+
const obj = sc;
|
|
6475
|
+
const level = String(obj.level ?? "");
|
|
6476
|
+
if (!VALID_SCOPE_CONFIDENCE_LEVELS.has(level)) return null;
|
|
6477
|
+
const reasons = Array.isArray(obj.reasons) ? obj.reasons.map(String).filter(Boolean) : [];
|
|
6478
|
+
return { level, reasons };
|
|
6479
|
+
}
|
|
6480
|
+
function parseModuleCoverage(data) {
|
|
6481
|
+
const mc = data.module_coverage;
|
|
6482
|
+
if (!mc || typeof mc !== "object" || Array.isArray(mc)) return null;
|
|
6483
|
+
const result = {};
|
|
6484
|
+
for (const [id, val] of Object.entries(mc)) {
|
|
6485
|
+
if (!val || typeof val !== "object" || Array.isArray(val)) continue;
|
|
6486
|
+
const v = val;
|
|
6487
|
+
const status = String(v.status ?? "");
|
|
6488
|
+
if (!VALID_COVERAGE_STATUSES.has(status)) continue;
|
|
6489
|
+
result[id] = {
|
|
6490
|
+
status,
|
|
6491
|
+
...v.reason ? { reason: String(v.reason) } : {},
|
|
6492
|
+
...Array.isArray(v.evidence) ? { evidence: v.evidence.map(String).filter(Boolean) } : {}
|
|
6493
|
+
};
|
|
6494
|
+
}
|
|
6495
|
+
return Object.keys(result).length > 0 ? result : null;
|
|
6496
|
+
}
|
|
6497
|
+
function parseImpactAnalysis(data) {
|
|
6498
|
+
const ia = data.impact_analysis;
|
|
6499
|
+
if (!ia || typeof ia !== "object" || Array.isArray(ia)) return null;
|
|
6500
|
+
const surfaces = ia.surfaces;
|
|
6501
|
+
if (!surfaces || typeof surfaces !== "object" || Array.isArray(surfaces)) return null;
|
|
6502
|
+
const result = {};
|
|
6503
|
+
for (const [id, val] of Object.entries(surfaces)) {
|
|
6504
|
+
if (!val || typeof val !== "object" || Array.isArray(val)) continue;
|
|
6505
|
+
const v = val;
|
|
6506
|
+
const status = String(v.status ?? "");
|
|
6507
|
+
if (!VALID_COVERAGE_STATUSES.has(status)) continue;
|
|
6508
|
+
result[id] = {
|
|
6509
|
+
status,
|
|
6510
|
+
...v.reason ? { reason: String(v.reason) } : {},
|
|
6511
|
+
...v.question ? { question: String(v.question) } : {}
|
|
6512
|
+
};
|
|
6513
|
+
}
|
|
6514
|
+
return Object.keys(result).length > 0 ? result : null;
|
|
6515
|
+
}
|
|
6383
6516
|
function parseArtifact(filePath, raw) {
|
|
6384
6517
|
try {
|
|
6385
6518
|
const { data } = matter(raw);
|
|
@@ -6408,7 +6541,10 @@ function parseArtifact(filePath, raw) {
|
|
|
6408
6541
|
affectedModules: Array.isArray(data.affected_modules) ? data.affected_modules.map(String).filter(Boolean) : [],
|
|
6409
6542
|
refinedBy: String(data.refined_by ?? ""),
|
|
6410
6543
|
implementedBy: String(data.implemented_by ?? ""),
|
|
6411
|
-
closedBy: String(data.closed_by ?? "")
|
|
6544
|
+
closedBy: String(data.closed_by ?? ""),
|
|
6545
|
+
scopeConfidence: parseScopeConfidence(data),
|
|
6546
|
+
moduleCoverage: parseModuleCoverage(data),
|
|
6547
|
+
impactAnalysis: parseImpactAnalysis(data)
|
|
6412
6548
|
};
|
|
6413
6549
|
} catch {
|
|
6414
6550
|
return null;
|
|
@@ -6939,17 +7075,27 @@ function analyzeCrossRepoEvidence(input) {
|
|
|
6939
7075
|
}
|
|
6940
7076
|
}
|
|
6941
7077
|
}
|
|
7078
|
+
if (validationStatus === "accepted-with-exceptions") {
|
|
7079
|
+
const hasExceptions = exceptions.length > 0;
|
|
7080
|
+
const hasValidationGate = releaseGates.some(
|
|
7081
|
+
(g) => (g.status === "pending" || g.status === "blocked") && (g.id.includes("validation") || g.id.includes("test"))
|
|
7082
|
+
);
|
|
7083
|
+
if (!hasExceptions && !hasValidationGate) {
|
|
7084
|
+
findings.push({ id, severity: "warning", message: "Validation status is accepted-with-exceptions, but no exception evidence was found." });
|
|
7085
|
+
}
|
|
7086
|
+
}
|
|
6942
7087
|
if (raw.status === "done") {
|
|
6943
7088
|
findings.push({ id, severity: "warning", message: "Legacy status `done` detected. Canonical status is `completed`." });
|
|
6944
7089
|
}
|
|
6945
7090
|
if (raw.refined_by && raw.implemented_by && raw.refined_by === raw.implemented_by) {
|
|
6946
7091
|
findings.push({ id, severity: "fyi", message: "refined_by and implemented_by point to the same agent." });
|
|
6947
7092
|
}
|
|
7093
|
+
const historicalDefault = lifecycle === "completed" || lifecycle === "archived" ? "not-assessed" : "not-started";
|
|
6948
7094
|
return {
|
|
6949
7095
|
id,
|
|
6950
7096
|
lifecycle,
|
|
6951
|
-
implementationStatus: implementationStatus ||
|
|
6952
|
-
validationStatus: validationStatus ||
|
|
7097
|
+
implementationStatus: implementationStatus || historicalDefault,
|
|
7098
|
+
validationStatus: validationStatus || historicalDefault,
|
|
6953
7099
|
releaseStatus: releaseStatus || "not-assessed",
|
|
6954
7100
|
affectedModules,
|
|
6955
7101
|
findings,
|
|
@@ -6959,6 +7105,142 @@ function analyzeCrossRepoEvidence(input) {
|
|
|
6959
7105
|
};
|
|
6960
7106
|
}
|
|
6961
7107
|
|
|
7108
|
+
// src/core/scope-coverage.ts
|
|
7109
|
+
var VALID_CONFIDENCE_LEVELS = /* @__PURE__ */ new Set(["high", "medium", "low"]);
|
|
7110
|
+
var VALID_COVERAGE_STATUSES2 = /* @__PURE__ */ new Set(["affected", "reviewed-not-affected", "unknown", "not-applicable"]);
|
|
7111
|
+
var USER_FACING_KEYWORDS_EN = [
|
|
7112
|
+
"user",
|
|
7113
|
+
"visitor",
|
|
7114
|
+
"page",
|
|
7115
|
+
"registration",
|
|
7116
|
+
"login",
|
|
7117
|
+
"form",
|
|
7118
|
+
"show",
|
|
7119
|
+
"display",
|
|
7120
|
+
"cta",
|
|
7121
|
+
"flow",
|
|
7122
|
+
"screen",
|
|
7123
|
+
"dashboard",
|
|
7124
|
+
"ui",
|
|
7125
|
+
"frontend",
|
|
7126
|
+
"interface",
|
|
7127
|
+
"button",
|
|
7128
|
+
"menu",
|
|
7129
|
+
"navigation",
|
|
7130
|
+
"modal",
|
|
7131
|
+
"dialog",
|
|
7132
|
+
"notification",
|
|
7133
|
+
"toast",
|
|
7134
|
+
"message"
|
|
7135
|
+
];
|
|
7136
|
+
var USER_FACING_KEYWORDS_ES = [
|
|
7137
|
+
"usuario",
|
|
7138
|
+
"visitante",
|
|
7139
|
+
"p\xE1gina",
|
|
7140
|
+
"registro",
|
|
7141
|
+
"login",
|
|
7142
|
+
"formulario",
|
|
7143
|
+
"mostrar",
|
|
7144
|
+
"cta",
|
|
7145
|
+
"flujo",
|
|
7146
|
+
"pantalla",
|
|
7147
|
+
"interfaz",
|
|
7148
|
+
"bot\xF3n",
|
|
7149
|
+
"men\xFA",
|
|
7150
|
+
"navegaci\xF3n",
|
|
7151
|
+
"modal",
|
|
7152
|
+
"di\xE1logo",
|
|
7153
|
+
"notificaci\xF3n",
|
|
7154
|
+
"mensaje"
|
|
7155
|
+
];
|
|
7156
|
+
var USER_FACING_KEYWORDS = /* @__PURE__ */ new Set([...USER_FACING_KEYWORDS_EN, ...USER_FACING_KEYWORDS_ES]);
|
|
7157
|
+
function analyzeScopeCoverage(artifact, registeredModuleIds, frontendModuleIds) {
|
|
7158
|
+
const findings = [];
|
|
7159
|
+
const id = artifact.id || artifact.title;
|
|
7160
|
+
const mc = artifact.moduleCoverage;
|
|
7161
|
+
const ia = artifact.impactAnalysis;
|
|
7162
|
+
const sc = artifact.scopeConfidence;
|
|
7163
|
+
const affectedModules = artifact.affectedModules;
|
|
7164
|
+
const lifecycle = artifact.status;
|
|
7165
|
+
const isCompleted = lifecycle === "completed" || lifecycle === "archived";
|
|
7166
|
+
const isReady = lifecycle === "ready";
|
|
7167
|
+
const hasScopeCoverage = mc !== null || ia !== null || sc !== null;
|
|
7168
|
+
const unknownModules = [];
|
|
7169
|
+
if (sc) {
|
|
7170
|
+
if (!VALID_CONFIDENCE_LEVELS.has(sc.level)) {
|
|
7171
|
+
findings.push({ id, severity: "blocking", message: `Invalid scope_confidence level "${sc.level}". Must be high, medium, or low.` });
|
|
7172
|
+
}
|
|
7173
|
+
if (isReady && sc.level === "low") {
|
|
7174
|
+
findings.push({ id, severity: "warning", message: "Work Item is ready but scope confidence is low." });
|
|
7175
|
+
}
|
|
7176
|
+
}
|
|
7177
|
+
if (mc) {
|
|
7178
|
+
for (const modId of Object.keys(mc)) {
|
|
7179
|
+
if (modId === "core") continue;
|
|
7180
|
+
if (!registeredModuleIds.includes(modId)) {
|
|
7181
|
+
findings.push({ id, severity: "blocking", message: `Module "${modId}" in module_coverage is not registered in .kaddo/modules.yml.` });
|
|
7182
|
+
}
|
|
7183
|
+
}
|
|
7184
|
+
for (const [modId, entry] of Object.entries(mc)) {
|
|
7185
|
+
if (!VALID_COVERAGE_STATUSES2.has(entry.status)) {
|
|
7186
|
+
findings.push({ id, severity: "blocking", message: `Invalid module_coverage status "${entry.status}" for module "${modId}".` });
|
|
7187
|
+
}
|
|
7188
|
+
if (entry.status === "affected" && !entry.reason) {
|
|
7189
|
+
findings.push({ id, severity: "warning", message: `Module "${modId}" is affected but has no reason.` });
|
|
7190
|
+
}
|
|
7191
|
+
if (entry.status === "unknown") {
|
|
7192
|
+
unknownModules.push(modId);
|
|
7193
|
+
}
|
|
7194
|
+
}
|
|
7195
|
+
for (const [modId, entry] of Object.entries(mc)) {
|
|
7196
|
+
if (entry.status === "affected" && !affectedModules.includes(modId)) {
|
|
7197
|
+
findings.push({ id, severity: "blocking", message: `Module "${modId}" is marked affected in module_coverage but missing from affected_modules.` });
|
|
7198
|
+
}
|
|
7199
|
+
}
|
|
7200
|
+
for (const modId of affectedModules) {
|
|
7201
|
+
const entry = mc[modId];
|
|
7202
|
+
if (entry && entry.status !== "affected") {
|
|
7203
|
+
findings.push({ id, severity: "blocking", message: `Module "${modId}" is in affected_modules but module_coverage status is "${entry.status}", not "affected".` });
|
|
7204
|
+
}
|
|
7205
|
+
}
|
|
7206
|
+
if (isReady && unknownModules.length > 0) {
|
|
7207
|
+
for (const modId of unknownModules) {
|
|
7208
|
+
findings.push({ id, severity: "warning", message: `Work Item is ready but module "${modId}" scope remains unknown.` });
|
|
7209
|
+
}
|
|
7210
|
+
}
|
|
7211
|
+
}
|
|
7212
|
+
if (ia) {
|
|
7213
|
+
for (const [surface, entry] of Object.entries(ia)) {
|
|
7214
|
+
if (!VALID_COVERAGE_STATUSES2.has(entry.status)) {
|
|
7215
|
+
findings.push({ id, severity: "blocking", message: `Invalid impact_analysis status "${entry.status}" for surface "${surface}".` });
|
|
7216
|
+
}
|
|
7217
|
+
if (entry.status === "unknown" && !entry.question && !entry.reason) {
|
|
7218
|
+
findings.push({ id, severity: "warning", message: `Surface "${surface}" is unknown but has no question or explanation.` });
|
|
7219
|
+
}
|
|
7220
|
+
}
|
|
7221
|
+
}
|
|
7222
|
+
if (!isCompleted && frontendModuleIds.length > 0) {
|
|
7223
|
+
const wiText = `${artifact.title} ${artifact.rawFrontmatter?.target_behavior ?? ""} ${artifact.rawFrontmatter?.current_behavior ?? ""}`.toLowerCase();
|
|
7224
|
+
const isUserFacing = [...USER_FACING_KEYWORDS].some((kw) => wiText.includes(kw));
|
|
7225
|
+
if (isUserFacing && mc) {
|
|
7226
|
+
for (const fid of frontendModuleIds) {
|
|
7227
|
+
if (!mc[fid]) {
|
|
7228
|
+
findings.push({ id, severity: "warning", message: `A mapped user-facing module "${fid}" was not assessed in module_coverage.` });
|
|
7229
|
+
}
|
|
7230
|
+
}
|
|
7231
|
+
}
|
|
7232
|
+
}
|
|
7233
|
+
return {
|
|
7234
|
+
id,
|
|
7235
|
+
scopeConfidence: sc,
|
|
7236
|
+
moduleCoverage: mc,
|
|
7237
|
+
impactAnalysis: ia,
|
|
7238
|
+
findings,
|
|
7239
|
+
unknownModules,
|
|
7240
|
+
hasScopeCoverage
|
|
7241
|
+
};
|
|
7242
|
+
}
|
|
7243
|
+
|
|
6962
7244
|
// src/commands/guard.ts
|
|
6963
7245
|
import path4 from "path";
|
|
6964
7246
|
import { parse as parseYaml7 } from "yaml";
|
|
@@ -7620,6 +7902,27 @@ async function runGuard(opts = {}) {
|
|
|
7620
7902
|
console.log("");
|
|
7621
7903
|
}
|
|
7622
7904
|
}
|
|
7905
|
+
const mappedModules = loadMappedModules(dir);
|
|
7906
|
+
const registeredModuleIdsForScope = mappedModules.map((m) => m.id);
|
|
7907
|
+
const frontendModuleIds = mappedModules.filter((m) => m.type === "frontend" || m.type === "web" || m.type === "mobile" || m.type === "ui").map((m) => m.id);
|
|
7908
|
+
const wiArtifactsForScope = artifacts.filter((a) => a.isWorkItem);
|
|
7909
|
+
const scopeSummaries = [];
|
|
7910
|
+
for (const wi of wiArtifactsForScope) {
|
|
7911
|
+
if (!wi.scopeConfidence && !wi.moduleCoverage && !wi.impactAnalysis) continue;
|
|
7912
|
+
const summary = analyzeScopeCoverage(wi, registeredModuleIdsForScope, frontendModuleIds);
|
|
7913
|
+
if (summary.findings.length > 0) scopeSummaries.push(summary);
|
|
7914
|
+
}
|
|
7915
|
+
if (scopeSummaries.length > 0) {
|
|
7916
|
+
console.log("Scope coverage:");
|
|
7917
|
+
for (const s of scopeSummaries) {
|
|
7918
|
+
console.log(` ${s.id}:`);
|
|
7919
|
+
for (const f of s.findings) {
|
|
7920
|
+
const icon = f.severity === "blocking" ? "\u2717" : f.severity === "warning" ? "!" : "\xB7";
|
|
7921
|
+
console.log(` ${icon} ${f.message}`);
|
|
7922
|
+
}
|
|
7923
|
+
}
|
|
7924
|
+
console.log("");
|
|
7925
|
+
}
|
|
7623
7926
|
const ownerMap = loadOwners(dir);
|
|
7624
7927
|
const matchedDomains = collectMatchedDomains(activeMatches.map((m) => m.artifact.domains));
|
|
7625
7928
|
const affectedOwners = resolveAffectedOwners(matchedDomains, ownerMap);
|
|
@@ -7897,12 +8200,44 @@ domains: []
|
|
|
7897
8200
|
capabilities: []
|
|
7898
8201
|
code: []
|
|
7899
8202
|
created_at: YYYY-MM-DD
|
|
8203
|
+
# scope_confidence:
|
|
8204
|
+
# level: medium
|
|
8205
|
+
# reasons: []
|
|
8206
|
+
# module_coverage:
|
|
8207
|
+
# core:
|
|
8208
|
+
# status: affected
|
|
8209
|
+
# reason: ""
|
|
8210
|
+
# impact_analysis:
|
|
8211
|
+
# surfaces:
|
|
8212
|
+
# frontend:
|
|
8213
|
+
# status: affected
|
|
8214
|
+
# reason: ""
|
|
7900
8215
|
---
|
|
7901
8216
|
|
|
7902
8217
|
# <Title>
|
|
7903
8218
|
|
|
7904
8219
|
> Type: feature \xB7 Level: K2
|
|
7905
8220
|
|
|
8221
|
+
## Actor and outcome
|
|
8222
|
+
|
|
8223
|
+
_Who experiences the change and what is the observable result?_
|
|
8224
|
+
|
|
8225
|
+
## Current behavior
|
|
8226
|
+
|
|
8227
|
+
_What happens today?_
|
|
8228
|
+
|
|
8229
|
+
## Target behavior
|
|
8230
|
+
|
|
8231
|
+
_What should happen after this change?_
|
|
8232
|
+
|
|
8233
|
+
## Entry points
|
|
8234
|
+
|
|
8235
|
+
_Where does the flow start for the actor?_
|
|
8236
|
+
|
|
8237
|
+
## End-to-end flow
|
|
8238
|
+
|
|
8239
|
+
_Describe the complete flow from entry point to final result._
|
|
8240
|
+
|
|
7906
8241
|
## Problem
|
|
7907
8242
|
|
|
7908
8243
|
_What problem or opportunity does this address?_
|
|
@@ -7911,9 +8246,26 @@ _What problem or opportunity does this address?_
|
|
|
7911
8246
|
|
|
7912
8247
|
_What should be true once this is done?_
|
|
7913
8248
|
|
|
8249
|
+
## Impact analysis
|
|
8250
|
+
|
|
8251
|
+
_Which surfaces are affected, reviewed-not-affected, unknown, or not-applicable?_
|
|
8252
|
+
|
|
8253
|
+
## Module coverage
|
|
8254
|
+
|
|
8255
|
+
_For multirepo: which modules were evaluated and their status._
|
|
8256
|
+
|
|
8257
|
+
## Scope unknowns
|
|
8258
|
+
|
|
8259
|
+
_What remains unknown? Include focused questions._
|
|
8260
|
+
|
|
8261
|
+
## Scope confidence
|
|
8262
|
+
|
|
8263
|
+
_high / medium / low \u2014 with reasons._
|
|
8264
|
+
|
|
7914
8265
|
## Acceptance criteria
|
|
7915
8266
|
|
|
7916
8267
|
- [ ] ...
|
|
8268
|
+
- [ ] _Include at least one end-to-end criterion for user-facing changes._
|
|
7917
8269
|
|
|
7918
8270
|
## Design
|
|
7919
8271
|
|
|
@@ -7945,6 +8297,9 @@ ${QUALITY}
|
|
|
7945
8297
|
- [ ] Title is specific and action-oriented.
|
|
7946
8298
|
- [ ] \`code:\` globs declared so Guard can relate changes.
|
|
7947
8299
|
- [ ] Knowledge level matches the real uncertainty.
|
|
8300
|
+
- [ ] Actor and outcome are identified.
|
|
8301
|
+
- [ ] Current and target behavior are documented.
|
|
8302
|
+
- [ ] Scope confidence is declared.
|
|
7948
8303
|
`;
|
|
7949
8304
|
var ROADMAP = `---
|
|
7950
8305
|
type: roadmap
|
|
@@ -11741,6 +12096,8 @@ function workItemsSignal(dir) {
|
|
|
11741
12096
|
if (wis.length === 0) return "none";
|
|
11742
12097
|
if (wis.some((w) => w.lifecycle === "in-progress")) return "in-progress";
|
|
11743
12098
|
if (wis.some((w) => w.lifecycle === "ready")) return "ready";
|
|
12099
|
+
const hasActive = wis.some((w) => w.lifecycle === "draft" || w.lifecycle === "blocked");
|
|
12100
|
+
if (!hasActive && wis.some((w) => w.lifecycle === "completed" || w.lifecycle === "archived")) return "completed-only";
|
|
11744
12101
|
return "none-ready";
|
|
11745
12102
|
}
|
|
11746
12103
|
function installedAdapters(dir) {
|
|
@@ -12169,6 +12526,8 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
12169
12526
|
else if (understand === "missing") overall = "scanned";
|
|
12170
12527
|
else if (firstWeak) overall = "knowledge-incomplete";
|
|
12171
12528
|
else if (oq.summary.blocking_open > 0) overall = "needs-decisions";
|
|
12529
|
+
else if (work_items === "in-progress") overall = "active-implementation";
|
|
12530
|
+
else if (work_items === "completed-only") overall = deriveDeliveryCompletedStatus(dir);
|
|
12172
12531
|
else if (roadmap !== "has-candidates") overall = "ready-for-roadmap";
|
|
12173
12532
|
else if (work_items === "none" || work_items === "none-ready") overall = "ready-for-work-item";
|
|
12174
12533
|
else overall = "ready-for-implementation";
|
|
@@ -12181,6 +12540,16 @@ function buildReadinessReport(dir, now = /* @__PURE__ */ new Date()) {
|
|
|
12181
12540
|
nextStepRecommendation: rec
|
|
12182
12541
|
};
|
|
12183
12542
|
}
|
|
12543
|
+
function deriveDeliveryCompletedStatus(dir) {
|
|
12544
|
+
const wis = discoverWorkItems(dir);
|
|
12545
|
+
const completed = wis.filter((w) => lifecycleStateOf({ status: w.status, filePath: w.filePath }) === "completed");
|
|
12546
|
+
if (completed.length === 0) return "delivery-completed";
|
|
12547
|
+
const hasReleaseBlocked = completed.some((w) => w.releaseStatus === "blocked");
|
|
12548
|
+
const hasReleaseReady = completed.some((w) => w.releaseStatus === "ready" || w.releaseStatus === "released");
|
|
12549
|
+
if (hasReleaseBlocked) return "delivery-completed-release-blocked";
|
|
12550
|
+
if (hasReleaseReady) return "delivery-completed-release-ready";
|
|
12551
|
+
return "delivery-completed";
|
|
12552
|
+
}
|
|
12184
12553
|
|
|
12185
12554
|
// src/core/assets.ts
|
|
12186
12555
|
import matter5 from "gray-matter";
|
|
@@ -12544,7 +12913,7 @@ var refineWorkItem = {
|
|
|
12544
12913
|
id: "refine-work-item",
|
|
12545
12914
|
label: "Refine Work Item",
|
|
12546
12915
|
evaluate: (ctx) => {
|
|
12547
|
-
if (ctx.readyWorkItems > 0 || ctx.inProgressWorkItems > 0) return { status: "done" };
|
|
12916
|
+
if (ctx.readyWorkItems > 0 || ctx.inProgressWorkItems > 0 || ctx.blockedWorkItems > 0 || ctx.completedWorkItems > 0 || ctx.archivedWorkItems > 0) return { status: "done" };
|
|
12548
12917
|
if (ctx.draftWorkItems > 0) {
|
|
12549
12918
|
return {
|
|
12550
12919
|
status: "current",
|
|
@@ -12795,7 +13164,9 @@ function buildRouteContext(dir) {
|
|
|
12795
13164
|
draftWorkItems: byState("draft"),
|
|
12796
13165
|
readyWorkItems: byState("ready"),
|
|
12797
13166
|
inProgressWorkItems: byState("in-progress"),
|
|
13167
|
+
blockedWorkItems: byState("blocked"),
|
|
12798
13168
|
completedWorkItems: byState("completed"),
|
|
13169
|
+
archivedWorkItems: byState("archived"),
|
|
12799
13170
|
ownershipCoverage: `${withOwnership}/${total}`,
|
|
12800
13171
|
ownershipComplete: total > 0 && withOwnership >= total,
|
|
12801
13172
|
decisionCandidates: td.candidates,
|
|
@@ -13210,6 +13581,30 @@ function buildProjectExplanation(dir) {
|
|
|
13210
13581
|
scanSignals: loadScanSignals(dir),
|
|
13211
13582
|
metadataHealth: analyzeMetadataHealth(dir),
|
|
13212
13583
|
isModuleRepo: config != null && isModule(config),
|
|
13584
|
+
deliverySummary: (() => {
|
|
13585
|
+
const completed = workItemArtifacts.filter((a) => lifecycleStateOf({ status: a.status, filePath: a.filePath }) === "completed");
|
|
13586
|
+
const archived = workItemArtifacts.filter((a) => lifecycleStateOf({ status: a.status, filePath: a.filePath }) === "archived");
|
|
13587
|
+
const active = workItemArtifacts.filter((a) => isActiveState(lifecycleStateOf({ status: a.status, filePath: a.filePath })));
|
|
13588
|
+
if (completed.length === 0 && archived.length === 0) return null;
|
|
13589
|
+
return {
|
|
13590
|
+
completedWorkItems: completed.length,
|
|
13591
|
+
archivedWorkItems: archived.length,
|
|
13592
|
+
activeWorkItems: active.length,
|
|
13593
|
+
implementationCompleted: completed.filter((a) => a.implementationStatus === "completed").length,
|
|
13594
|
+
releaseBlocked: completed.filter((a) => a.releaseStatus === "blocked").length,
|
|
13595
|
+
releaseReady: completed.filter((a) => a.releaseStatus === "ready" || a.releaseStatus === "released").length
|
|
13596
|
+
};
|
|
13597
|
+
})(),
|
|
13598
|
+
scopeCoverage: workItemArtifacts.filter((a) => a.scopeConfidence || a.moduleCoverage || a.impactAnalysis).map((a) => {
|
|
13599
|
+
const unknownModules = a.moduleCoverage ? Object.entries(a.moduleCoverage).filter(([, v]) => v.status === "unknown").map(([k]) => k) : [];
|
|
13600
|
+
return {
|
|
13601
|
+
id: a.id || a.title,
|
|
13602
|
+
scopeConfidence: a.scopeConfidence,
|
|
13603
|
+
moduleCoverage: a.moduleCoverage,
|
|
13604
|
+
unknownModules,
|
|
13605
|
+
hasScopeCoverage: true
|
|
13606
|
+
};
|
|
13607
|
+
}),
|
|
13213
13608
|
implementationEvidence: workItemArtifacts.filter((a) => a.affectedModules.length > 0).map((a) => {
|
|
13214
13609
|
const fm2 = a.rawFrontmatter;
|
|
13215
13610
|
const evidence = fm2.implementation_evidence;
|
|
@@ -13221,11 +13616,13 @@ function buildProjectExplanation(dir) {
|
|
|
13221
13616
|
status: String(data.status ?? "unknown")
|
|
13222
13617
|
};
|
|
13223
13618
|
}
|
|
13619
|
+
const lc = lifecycleStateOf({ status: a.status, filePath: a.filePath });
|
|
13620
|
+
const historicalDefault = lc === "completed" || lc === "archived" ? "not-assessed" : "not-started";
|
|
13224
13621
|
return {
|
|
13225
13622
|
id: a.id || a.title,
|
|
13226
|
-
lifecycle:
|
|
13227
|
-
implementationStatus: a.implementationStatus ||
|
|
13228
|
-
validationStatus: a.validationStatus ||
|
|
13623
|
+
lifecycle: lc,
|
|
13624
|
+
implementationStatus: a.implementationStatus || historicalDefault,
|
|
13625
|
+
validationStatus: a.validationStatus || historicalDefault,
|
|
13229
13626
|
releaseStatus: a.releaseStatus || "not-assessed",
|
|
13230
13627
|
affectedModules: a.affectedModules,
|
|
13231
13628
|
releaseGates: Array.isArray(fm2.release_gates) ? fm2.release_gates : [],
|
|
@@ -13388,6 +13785,23 @@ function renderExplanationHuman(exp) {
|
|
|
13388
13785
|
}
|
|
13389
13786
|
lines.push("");
|
|
13390
13787
|
}
|
|
13788
|
+
if (exp.scopeCoverage.length > 0) {
|
|
13789
|
+
lines.push("## Work Item Scope Coverage");
|
|
13790
|
+
for (const sc of exp.scopeCoverage) {
|
|
13791
|
+
lines.push("");
|
|
13792
|
+
lines.push(`### ${sc.id}`);
|
|
13793
|
+
if (sc.scopeConfidence) lines.push(`- Scope confidence: ${sc.scopeConfidence.level}`);
|
|
13794
|
+
if (sc.moduleCoverage) {
|
|
13795
|
+
const affected = Object.entries(sc.moduleCoverage).filter(([, v]) => v.status === "affected").map(([k]) => k);
|
|
13796
|
+
const reviewed = Object.entries(sc.moduleCoverage).filter(([, v]) => v.status === "reviewed-not-affected").map(([k]) => k);
|
|
13797
|
+
const unknown = Object.entries(sc.moduleCoverage).filter(([, v]) => v.status === "unknown").map(([k]) => k);
|
|
13798
|
+
if (affected.length > 0) lines.push(`Affected: ${affected.join(", ")}`);
|
|
13799
|
+
if (reviewed.length > 0) lines.push(`Reviewed, not affected: ${reviewed.join(", ")}`);
|
|
13800
|
+
if (unknown.length > 0) lines.push(`Unknown: ${unknown.join(", ")}`);
|
|
13801
|
+
}
|
|
13802
|
+
}
|
|
13803
|
+
lines.push("");
|
|
13804
|
+
}
|
|
13391
13805
|
if (exp.domains.length > 0) {
|
|
13392
13806
|
lines.push("## Domains");
|
|
13393
13807
|
lines.push(`- ${exp.domains.join(", ")}`);
|
|
@@ -13470,6 +13884,17 @@ function renderExplanationHuman(exp) {
|
|
|
13470
13884
|
}
|
|
13471
13885
|
lines.push(`- Next step: ${exp.readiness.recommended_next_step.label}`);
|
|
13472
13886
|
lines.push("");
|
|
13887
|
+
if (exp.deliverySummary) {
|
|
13888
|
+
const ds = exp.deliverySummary;
|
|
13889
|
+
lines.push("## Delivery Summary");
|
|
13890
|
+
lines.push(`- Completed Work Items: ${ds.completedWorkItems}`);
|
|
13891
|
+
if (ds.archivedWorkItems > 0) lines.push(`- Archived Work Items: ${ds.archivedWorkItems}`);
|
|
13892
|
+
lines.push(`- Active Work Items: ${ds.activeWorkItems}`);
|
|
13893
|
+
if (ds.implementationCompleted > 0) lines.push(`- Implementation completed: ${ds.implementationCompleted}`);
|
|
13894
|
+
if (ds.releaseBlocked > 0) lines.push(`- Release blocked: ${ds.releaseBlocked}`);
|
|
13895
|
+
if (ds.releaseReady > 0) lines.push(`- Release ready: ${ds.releaseReady}`);
|
|
13896
|
+
lines.push("");
|
|
13897
|
+
}
|
|
13473
13898
|
const rec = exp.nextStepRecommendation;
|
|
13474
13899
|
const secondary = rec.secondary ?? [];
|
|
13475
13900
|
const steps = secondary.length > 0 || /Delivery|Active|Maintenance/.test(rec.phase) ? [rec.label, ...secondary.map((s2) => s2.label)] : exp.suggestedNextSteps;
|
|
@@ -13504,6 +13929,10 @@ function renderExplanationHuman(exp) {
|
|
|
13504
13929
|
if (!exp.isModuleRepo) {
|
|
13505
13930
|
lines.push(`- roadmap: ${s.roadmap}`);
|
|
13506
13931
|
lines.push(`- work-items: ${s.work_items}`);
|
|
13932
|
+
if (exp.deliverySummary) {
|
|
13933
|
+
lines.push(`- work-items completed: ${exp.deliverySummary.completedWorkItems}`);
|
|
13934
|
+
lines.push(`- work-items active: ${exp.deliverySummary.activeWorkItems}`);
|
|
13935
|
+
}
|
|
13507
13936
|
lines.push(`- adapters: ${s.adapters.length > 0 ? s.adapters.join(", ") + " installed" : "none installed"}`);
|
|
13508
13937
|
} else {
|
|
13509
13938
|
lines.push("- roadmap: managed-by-core");
|
|
@@ -13845,20 +14274,29 @@ var OPERATING_RULES = [
|
|
|
13845
14274
|
"Kaddo itself never calls an LLM and never runs git \u2014 every git action is the human\u2019s."
|
|
13846
14275
|
];
|
|
13847
14276
|
function toContextWorkItem(a) {
|
|
14277
|
+
const lifecycle = lifecycleStateOf({ status: a.status, filePath: a.filePath });
|
|
14278
|
+
const isHistorical = lifecycle === "completed" || lifecycle === "archived";
|
|
13848
14279
|
const wi = {
|
|
13849
14280
|
id: a.id,
|
|
13850
14281
|
type: a.type,
|
|
13851
14282
|
title: a.title,
|
|
13852
14283
|
status: a.status,
|
|
13853
|
-
lifecycle
|
|
14284
|
+
lifecycle,
|
|
13854
14285
|
knowledgeLevel: a.knowledgeLevel,
|
|
13855
14286
|
domains: a.domains,
|
|
13856
14287
|
source: parseWorkItemSource(a.rawFrontmatter)
|
|
13857
14288
|
};
|
|
13858
|
-
|
|
13859
|
-
|
|
13860
|
-
|
|
14289
|
+
wi.implementationStatus = a.implementationStatus || (isHistorical ? "not-assessed" : void 0);
|
|
14290
|
+
wi.validationStatus = a.validationStatus || (isHistorical ? "not-assessed" : void 0);
|
|
14291
|
+
wi.releaseStatus = a.releaseStatus || (isHistorical ? "not-assessed" : void 0);
|
|
13861
14292
|
if (a.affectedModules.length > 0) wi.affectedModules = a.affectedModules;
|
|
14293
|
+
if (a.scopeConfidence) wi.scopeConfidence = a.scopeConfidence;
|
|
14294
|
+
if (a.moduleCoverage) wi.moduleCoverage = a.moduleCoverage;
|
|
14295
|
+
if (a.impactAnalysis) wi.impactAnalysis = a.impactAnalysis;
|
|
14296
|
+
if (a.moduleCoverage) {
|
|
14297
|
+
const unknowns = Object.entries(a.moduleCoverage).filter(([, v]) => v.status === "unknown").map(([k]) => k);
|
|
14298
|
+
if (unknowns.length > 0) wi.scopeUnknowns = unknowns;
|
|
14299
|
+
}
|
|
13862
14300
|
return wi;
|
|
13863
14301
|
}
|
|
13864
14302
|
function toContextArtifact(a) {
|
|
@@ -13888,10 +14326,17 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
13888
14326
|
missing.push("No roadmap baseline found.");
|
|
13889
14327
|
}
|
|
13890
14328
|
const allArtifacts = discoverKnowledge(dir);
|
|
13891
|
-
const
|
|
13892
|
-
|
|
14329
|
+
const allWorkItemArtifacts = allArtifacts.filter((a) => isDeliveryWorkItem(a));
|
|
14330
|
+
const workItems = allWorkItemArtifacts.filter(
|
|
14331
|
+
(a) => isActiveState(lifecycleStateOf({ status: a.status, filePath: a.filePath }))
|
|
13893
14332
|
);
|
|
13894
|
-
|
|
14333
|
+
const completedWorkItems = allWorkItemArtifacts.filter(
|
|
14334
|
+
(a) => lifecycleStateOf({ status: a.status, filePath: a.filePath }) === "completed"
|
|
14335
|
+
);
|
|
14336
|
+
const archivedWorkItems = allWorkItemArtifacts.filter(
|
|
14337
|
+
(a) => lifecycleStateOf({ status: a.status, filePath: a.filePath }) === "archived"
|
|
14338
|
+
);
|
|
14339
|
+
if (allWorkItemArtifacts.length === 0 && !moduleRepo) {
|
|
13895
14340
|
missing.push("No work items found.");
|
|
13896
14341
|
}
|
|
13897
14342
|
const state = config.project.state;
|
|
@@ -14006,6 +14451,10 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
14006
14451
|
roadmapSummary,
|
|
14007
14452
|
inventoryAvailable,
|
|
14008
14453
|
workItems: workItems.map(toContextWorkItem),
|
|
14454
|
+
activeWorkItems: workItems.map(toContextWorkItem),
|
|
14455
|
+
completedWorkItems: completedWorkItems.map(toContextWorkItem),
|
|
14456
|
+
archivedWorkItems: archivedWorkItems.map(toContextWorkItem),
|
|
14457
|
+
allWorkItems: allWorkItemArtifacts.map(toContextWorkItem),
|
|
14009
14458
|
artifacts: allArtifacts.filter((a) => a.codeGlobs.length > 0).map(toContextArtifact)
|
|
14010
14459
|
},
|
|
14011
14460
|
layers,
|
|
@@ -14022,6 +14471,30 @@ function buildContextPack(dir, config, now = /* @__PURE__ */ new Date()) {
|
|
|
14022
14471
|
const compact = (a) => ({ total: a.total, installed: a.total - a.missing, outdated: a.outdated, unknown_version: a.unknown_version, modified: a.modified });
|
|
14023
14472
|
return { version: s.version, agents: compact(s.agents), skills: compact(s.skills) };
|
|
14024
14473
|
})(),
|
|
14474
|
+
workItemSummary: (() => {
|
|
14475
|
+
const lc = (s) => allWorkItemArtifacts.filter(
|
|
14476
|
+
(a) => lifecycleStateOf({ status: a.status, filePath: a.filePath }) === s
|
|
14477
|
+
).length;
|
|
14478
|
+
const draft = lc("draft");
|
|
14479
|
+
const ready = lc("ready");
|
|
14480
|
+
const inProgress = lc("in-progress");
|
|
14481
|
+
const blocked = lc("blocked");
|
|
14482
|
+
const completed = lc("completed");
|
|
14483
|
+
const archived = lc("archived");
|
|
14484
|
+
const active = draft + ready + inProgress + blocked;
|
|
14485
|
+
const total = allWorkItemArtifacts.length;
|
|
14486
|
+
let summary = "none";
|
|
14487
|
+
if (total === 0) summary = "none";
|
|
14488
|
+
else if (active === 0 && completed > 0 && archived === 0) summary = "completed-only";
|
|
14489
|
+
else if (active === 0 && archived > 0 && completed === 0) summary = "archived-only";
|
|
14490
|
+
else if (active === 0 && completed + archived > 0) summary = "historical-only";
|
|
14491
|
+
else if (inProgress > 0) summary = "active";
|
|
14492
|
+
else if (blocked > 0 && ready === 0 && inProgress === 0) summary = "blocked";
|
|
14493
|
+
else if (ready > 0) summary = "ready";
|
|
14494
|
+
else if (draft > 0 && ready === 0) summary = "draft-only";
|
|
14495
|
+
else summary = "mixed-active";
|
|
14496
|
+
return { total, active, draft, ready, in_progress: inProgress, blocked, completed, archived, summary };
|
|
14497
|
+
})(),
|
|
14025
14498
|
deliveryMix,
|
|
14026
14499
|
external: loadExternalCapsules(dir),
|
|
14027
14500
|
graph: loadGraphSummary(dir),
|
|
@@ -14950,6 +15423,34 @@ function runUnderstand() {
|
|
|
14950
15423
|
} else if (rec.agentPath) {
|
|
14951
15424
|
console.log(` Agent prompt: ${rec.agentPath}`);
|
|
14952
15425
|
}
|
|
15426
|
+
if (exp.deliverySummary) {
|
|
15427
|
+
const ds2 = exp.deliverySummary;
|
|
15428
|
+
console.log("");
|
|
15429
|
+
console.log("Previous delivery:");
|
|
15430
|
+
console.log(` - Completed Work Items: ${ds2.completedWorkItems}`);
|
|
15431
|
+
if (ds2.implementationCompleted > 0) console.log(` - Implementation completed: ${ds2.implementationCompleted}`);
|
|
15432
|
+
if (ds2.releaseBlocked > 0) console.log(` - Release blocked: ${ds2.releaseBlocked}`);
|
|
15433
|
+
if (ds2.releaseReady > 0) console.log(` - Release ready: ${ds2.releaseReady}`);
|
|
15434
|
+
console.log(` - Current active work: ${ds2.activeWorkItems > 0 ? ds2.activeWorkItems : "none"}`);
|
|
15435
|
+
}
|
|
15436
|
+
if (exp.scopeCoverage.length > 0) {
|
|
15437
|
+
const withUnknowns = exp.scopeCoverage.filter((sc) => sc.unknownModules.length > 0);
|
|
15438
|
+
if (withUnknowns.length > 0) {
|
|
15439
|
+
console.log("");
|
|
15440
|
+
console.log("Scope unknowns:");
|
|
15441
|
+
for (const sc of withUnknowns) {
|
|
15442
|
+
console.log(` ${sc.id}: ${sc.unknownModules.join(", ")}`);
|
|
15443
|
+
}
|
|
15444
|
+
}
|
|
15445
|
+
const lowConfidence = exp.scopeCoverage.filter((sc) => sc.scopeConfidence?.level === "low");
|
|
15446
|
+
if (lowConfidence.length > 0) {
|
|
15447
|
+
console.log("");
|
|
15448
|
+
console.log("Low scope confidence:");
|
|
15449
|
+
for (const sc of lowConfidence) {
|
|
15450
|
+
console.log(` ${sc.id}`);
|
|
15451
|
+
}
|
|
15452
|
+
}
|
|
15453
|
+
}
|
|
14953
15454
|
if (rec.skill) console.log(`Recommended skill: ${rec.skill}`);
|
|
14954
15455
|
console.log(`Next step: ${rec.label}`);
|
|
14955
15456
|
if (rec.reason) console.log(`Why: ${rec.reason}`);
|