prizmkit 1.1.57 → 1.1.60
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/bin/create-prizmkit.js +8 -6
- package/bundled/VERSION.json +3 -3
- package/bundled/adapters/codex/agent-adapter.js +38 -0
- package/bundled/adapters/codex/paths.js +27 -0
- package/bundled/adapters/codex/rules-adapter.js +30 -0
- package/bundled/adapters/codex/settings-adapter.js +27 -0
- package/bundled/adapters/codex/skill-adapter.js +65 -0
- package/bundled/adapters/codex/team-adapter.js +37 -0
- package/bundled/dev-pipeline/.env.example +2 -1
- package/bundled/dev-pipeline/README.md +10 -7
- package/bundled/dev-pipeline/lib/common.sh +278 -37
- package/bundled/dev-pipeline/run-bugfix.sh +10 -61
- package/bundled/dev-pipeline/run-feature.sh +10 -78
- package/bundled/dev-pipeline/run-recovery.sh +10 -46
- package/bundled/dev-pipeline/run-refactor.sh +10 -61
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +17 -7
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +9 -3
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +9 -3
- package/bundled/dev-pipeline/scripts/utils.py +6 -4
- package/bundled/dev-pipeline-windows/.env.example +28 -0
- package/bundled/dev-pipeline-windows/README.md +30 -0
- package/bundled/dev-pipeline-windows/SCHEMA_ANALYSIS.md +525 -0
- package/bundled/dev-pipeline-windows/assets/feature-list-example.json +146 -0
- package/bundled/dev-pipeline-windows/assets/prizm-dev-team-integration.md +138 -0
- package/bundled/dev-pipeline-windows/launch-bugfix-daemon.ps1 +9 -0
- package/bundled/dev-pipeline-windows/launch-feature-daemon.ps1 +9 -0
- package/bundled/dev-pipeline-windows/launch-refactor-daemon.ps1 +9 -0
- package/bundled/dev-pipeline-windows/lib/common.ps1 +432 -0
- package/bundled/dev-pipeline-windows/lib/daemon.ps1 +140 -0
- package/bundled/dev-pipeline-windows/lib/pipeline.ps1 +446 -0
- package/bundled/dev-pipeline-windows/lib/reset.ps1 +87 -0
- package/bundled/dev-pipeline-windows/reset-bug.ps1 +9 -0
- package/bundled/dev-pipeline-windows/reset-feature.ps1 +9 -0
- package/bundled/dev-pipeline-windows/reset-refactor.ps1 +9 -0
- package/bundled/dev-pipeline-windows/run-bugfix.ps1 +9 -0
- package/bundled/dev-pipeline-windows/run-feature.ps1 +9 -0
- package/bundled/dev-pipeline-windows/run-recovery.ps1 +76 -0
- package/bundled/dev-pipeline-windows/run-refactor.ps1 +9 -0
- package/bundled/dev-pipeline-windows/scripts/check-session-status.py +228 -0
- package/bundled/dev-pipeline-windows/scripts/cleanup-logs.py +192 -0
- package/bundled/dev-pipeline-windows/scripts/detect-stuck.py +530 -0
- package/bundled/dev-pipeline-windows/scripts/generate-bootstrap-prompt.py +1737 -0
- package/bundled/dev-pipeline-windows/scripts/generate-bugfix-prompt.py +685 -0
- package/bundled/dev-pipeline-windows/scripts/generate-recovery-prompt.py +805 -0
- package/bundled/dev-pipeline-windows/scripts/generate-refactor-prompt.py +763 -0
- package/bundled/dev-pipeline-windows/scripts/init-bugfix-pipeline.py +316 -0
- package/bundled/dev-pipeline-windows/scripts/init-dev-team.py +134 -0
- package/bundled/dev-pipeline-windows/scripts/init-pipeline.py +380 -0
- package/bundled/dev-pipeline-windows/scripts/init-refactor-pipeline.py +399 -0
- package/bundled/dev-pipeline-windows/scripts/parse-stream-progress.py +388 -0
- package/bundled/dev-pipeline-windows/scripts/patch-completion-notes.py +191 -0
- package/bundled/dev-pipeline-windows/scripts/update-bug-status.py +864 -0
- package/bundled/dev-pipeline-windows/scripts/update-checkpoint.py +173 -0
- package/bundled/dev-pipeline-windows/scripts/update-feature-status.py +1501 -0
- package/bundled/dev-pipeline-windows/scripts/update-refactor-status.py +1073 -0
- package/bundled/dev-pipeline-windows/scripts/utils.py +542 -0
- package/bundled/dev-pipeline-windows/templates/agent-prompts/critic-plan-challenge.md +7 -0
- package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-fix.md +7 -0
- package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-implement.md +30 -0
- package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-resume.md +5 -0
- package/bundled/dev-pipeline-windows/templates/agent-prompts/reviewer-review.md +7 -0
- package/bundled/dev-pipeline-windows/templates/bootstrap-prompt.md +46 -0
- package/bundled/dev-pipeline-windows/templates/bootstrap-tier1.md +43 -0
- package/bundled/dev-pipeline-windows/templates/bootstrap-tier2.md +43 -0
- package/bundled/dev-pipeline-windows/templates/bootstrap-tier3.md +43 -0
- package/bundled/dev-pipeline-windows/templates/bug-fix-list-schema.json +263 -0
- package/bundled/dev-pipeline-windows/templates/bugfix-bootstrap-prompt.md +320 -0
- package/bundled/dev-pipeline-windows/templates/feature-list-schema.json +237 -0
- package/bundled/dev-pipeline-windows/templates/refactor-bootstrap-prompt.md +331 -0
- package/bundled/dev-pipeline-windows/templates/refactor-list-schema.json +270 -0
- package/bundled/dev-pipeline-windows/templates/sections/ac-verification-checklist.md +13 -0
- package/bundled/dev-pipeline-windows/templates/sections/checkpoint-system.md +91 -0
- package/bundled/dev-pipeline-windows/templates/sections/context-budget-rules.md +33 -0
- package/bundled/dev-pipeline-windows/templates/sections/critical-paths-agent.md +10 -0
- package/bundled/dev-pipeline-windows/templates/sections/critical-paths-full.md +12 -0
- package/bundled/dev-pipeline-windows/templates/sections/critical-paths-lite.md +7 -0
- package/bundled/dev-pipeline-windows/templates/sections/directory-convention-agent.md +8 -0
- package/bundled/dev-pipeline-windows/templates/sections/directory-convention-full.md +9 -0
- package/bundled/dev-pipeline-windows/templates/sections/directory-convention-lite.md +6 -0
- package/bundled/dev-pipeline-windows/templates/sections/failure-capture.md +21 -0
- package/bundled/dev-pipeline-windows/templates/sections/feature-context.md +31 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification-auto.md +72 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification-opencli.md +63 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-browser-verification.md +62 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-commit-full.md +71 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-commit.md +64 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-agent-suffix.md +23 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-base.md +24 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-context-snapshot-lite-suffix.md +12 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-critic-plan-full.md +53 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-critic-plan.md +32 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-implement-agent.md +37 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-implement-full.md +50 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-implement-lite.md +52 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-plan-agent.md +27 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-plan-lite.md +27 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-review-agent.md +27 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-review-full.md +29 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase-specify-plan-full.md +77 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase0-init.md +13 -0
- package/bundled/dev-pipeline-windows/templates/sections/phase0-test-baseline.md +23 -0
- package/bundled/dev-pipeline-windows/templates/sections/session-context.md +5 -0
- package/bundled/dev-pipeline-windows/templates/sections/subagent-timeout-recovery.md +6 -0
- package/bundled/dev-pipeline-windows/templates/sections/test-failure-recovery-agent.md +67 -0
- package/bundled/dev-pipeline-windows/templates/sections/test-failure-recovery-lite.md +58 -0
- package/bundled/dev-pipeline-windows/templates/session-status-schema.json +83 -0
- package/bundled/skills/_metadata.json +1 -1
- package/bundled/skills/app-planner/SKILL.md +26 -18
- package/bundled/skills/app-planner/references/architecture-decisions.md +9 -5
- package/bundled/skills/app-planner/references/frontend-design-guide.md +1 -1
- package/bundled/skills/feature-planner/SKILL.md +9 -2
- package/bundled/skills/prizmkit-init/SKILL.md +7 -6
- package/bundled/skills/recovery-workflow/scripts/detect-recovery-state.py +2 -0
- package/bundled/skills-windows/app-planner/SKILL.md +639 -0
- package/bundled/skills-windows/app-planner/assets/app-design-guide.md +101 -0
- package/bundled/skills-windows/app-planner/references/architecture-decisions.md +52 -0
- package/bundled/skills-windows/app-planner/references/brainstorm-guide.md +101 -0
- package/bundled/skills-windows/app-planner/references/frontend-design-guide.md +71 -0
- package/bundled/skills-windows/app-planner/references/project-brief-guide.md +82 -0
- package/bundled/skills-windows/app-planner/references/red-team-checklist.md +40 -0
- package/bundled/skills-windows/app-planner/references/rules/backend/derivation-rules.md +609 -0
- package/bundled/skills-windows/app-planner/references/rules/backend/fixed-rules.md +285 -0
- package/bundled/skills-windows/app-planner/references/rules/backend/question-bank.md +249 -0
- package/bundled/skills-windows/app-planner/references/rules/backend/template.md +173 -0
- package/bundled/skills-windows/app-planner/references/rules/database/derivation-rules.md +373 -0
- package/bundled/skills-windows/app-planner/references/rules/database/fixed-rules.md +211 -0
- package/bundled/skills-windows/app-planner/references/rules/database/question-bank.md +184 -0
- package/bundled/skills-windows/app-planner/references/rules/database/template.md +158 -0
- package/bundled/skills-windows/app-planner/references/rules/frontend/derivation-rules.md +810 -0
- package/bundled/skills-windows/app-planner/references/rules/frontend/fixed-rules.md +188 -0
- package/bundled/skills-windows/app-planner/references/rules/frontend/question-bank.md +302 -0
- package/bundled/skills-windows/app-planner/references/rules/frontend/template.md +320 -0
- package/bundled/skills-windows/app-planner/references/rules/mobile/derivation-rules.md +639 -0
- package/bundled/skills-windows/app-planner/references/rules/mobile/fixed-rules.md +290 -0
- package/bundled/skills-windows/app-planner/references/rules/mobile/question-bank.md +232 -0
- package/bundled/skills-windows/app-planner/references/rules/mobile/template.md +175 -0
- package/bundled/skills-windows/bug-fix-workflow/SKILL.md +415 -0
- package/bundled/skills-windows/bug-planner/SKILL.md +395 -0
- package/bundled/skills-windows/bug-planner/assets/bug-confirmation-template.md +43 -0
- package/bundled/skills-windows/bug-planner/references/critic-and-verification.md +44 -0
- package/bundled/skills-windows/bug-planner/references/error-recovery.md +73 -0
- package/bundled/skills-windows/bug-planner/references/input-formats.md +53 -0
- package/bundled/skills-windows/bug-planner/references/schema-validation.md +25 -0
- package/bundled/skills-windows/bug-planner/references/severity-rules.md +16 -0
- package/bundled/skills-windows/bug-planner/scripts/validate-bug-list.py +322 -0
- package/bundled/skills-windows/bugfix-pipeline-launcher/SKILL.md +380 -0
- package/bundled/skills-windows/feature-pipeline-launcher/SKILL.md +441 -0
- package/bundled/skills-windows/feature-pipeline-launcher/scripts/preflight-check.py +462 -0
- package/bundled/skills-windows/feature-planner/SKILL.md +401 -0
- package/bundled/skills-windows/feature-planner/assets/evaluation-guide.md +64 -0
- package/bundled/skills-windows/feature-planner/assets/planning-guide.md +214 -0
- package/bundled/skills-windows/feature-planner/references/browser-interaction.md +59 -0
- package/bundled/skills-windows/feature-planner/references/completeness-review.md +57 -0
- package/bundled/skills-windows/feature-planner/references/decomposition-patterns.md +75 -0
- package/bundled/skills-windows/feature-planner/references/error-recovery.md +90 -0
- package/bundled/skills-windows/feature-planner/references/incremental-feature-planning.md +112 -0
- package/bundled/skills-windows/feature-planner/references/new-project-planning.md +85 -0
- package/bundled/skills-windows/feature-planner/scripts/validate-and-generate.py +1029 -0
- package/bundled/skills-windows/feature-workflow/SKILL.md +531 -0
- package/bundled/skills-windows/prizmkit-init/SKILL.md +356 -0
- package/bundled/skills-windows/prizmkit-init/assets/project-brief-template.md +82 -0
- package/bundled/skills-windows/prizmkit-init/references/config-schema.md +68 -0
- package/bundled/skills-windows/prizmkit-init/references/rules/layer-detection.md +41 -0
- package/bundled/skills-windows/prizmkit-init/references/tech-stack-catalog.md +13 -0
- package/bundled/skills-windows/prizmkit-init/references/update-supplement.md +9 -0
- package/bundled/skills-windows/recovery-workflow/SKILL.md +456 -0
- package/bundled/skills-windows/recovery-workflow/evals/evals.json +46 -0
- package/bundled/skills-windows/recovery-workflow/scripts/detect-recovery-state.py +544 -0
- package/bundled/skills-windows/refactor-pipeline-launcher/SKILL.md +406 -0
- package/bundled/skills-windows/refactor-planner/SKILL.md +540 -0
- package/bundled/skills-windows/refactor-planner/assets/planning-guide.md +292 -0
- package/bundled/skills-windows/refactor-planner/references/behavior-preservation.md +301 -0
- package/bundled/skills-windows/refactor-planner/references/refactor-scoping-guide.md +221 -0
- package/bundled/skills-windows/refactor-planner/scripts/validate-and-generate-refactor.py +858 -0
- package/bundled/skills-windows/refactor-workflow/SKILL.md +503 -0
- package/package.json +3 -2
- package/src/clean.js +73 -2
- package/src/config.js +159 -50
- package/src/detect-platform.js +16 -8
- package/src/external-skills.js +26 -19
- package/src/index.js +31 -9
- package/src/manifest.js +6 -2
- package/src/metadata.js +43 -5
- package/src/platforms.js +36 -0
- package/src/prompts.js +31 -6
- package/src/runtimes.js +20 -0
- package/src/scaffold.js +314 -110
- package/src/upgrade.js +81 -41
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Validate and generate .prizmkit/plans/bug-fix-list.json files
|
|
4
|
+
for the dev-pipeline system.
|
|
5
|
+
|
|
6
|
+
Commands:
|
|
7
|
+
validate Validate an existing bug-fix-list.json
|
|
8
|
+
generate Validate a draft JSON and generate final bug-fix-list.json with defaults
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
python3 validate-bug-list.py validate .prizmkit/plans/bug-fix-list.json [--feature-list .prizmkit/plans/feature-list.json]
|
|
12
|
+
python3 validate-bug-list.py generate --input draft.json --output .prizmkit/plans/bug-fix-list.json
|
|
13
|
+
|
|
14
|
+
Exit codes:
|
|
15
|
+
0 = valid / generated
|
|
16
|
+
1 = validation errors found
|
|
17
|
+
2 = file not found or JSON parse error
|
|
18
|
+
|
|
19
|
+
Python 3.6+ required. No external dependencies.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
import argparse
|
|
23
|
+
import json
|
|
24
|
+
import sys
|
|
25
|
+
import os
|
|
26
|
+
import re
|
|
27
|
+
from datetime import datetime, timezone
|
|
28
|
+
|
|
29
|
+
VALID_SEVERITIES = {"critical", "high", "medium", "low"}
|
|
30
|
+
VALID_SOURCE_TYPES = {"stack_trace", "user_report", "failed_test", "log_pattern", "monitoring_alert"}
|
|
31
|
+
VALID_VERIFICATION_TYPES = {"automated", "manual", "hybrid"}
|
|
32
|
+
VALID_STATUSES = {"pending", "triaging", "reproducing", "fixing", "verifying", "completed", "failed", "needs_info", "skipped"}
|
|
33
|
+
BUG_ID_PATTERN = re.compile(r"^B-\d{3}$")
|
|
34
|
+
SCHEMA_VERSION = "dev-pipeline-bug-fix-list-v1"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _err(msg):
|
|
38
|
+
"""Print an error message to stderr."""
|
|
39
|
+
print("ERROR: {}".format(msg), file=sys.stderr)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _warn(msg):
|
|
43
|
+
"""Print a warning message to stderr."""
|
|
44
|
+
print("WARN: {}".format(msg), file=sys.stderr)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _info(msg):
|
|
48
|
+
"""Print an informational message to stderr."""
|
|
49
|
+
print("INFO: {}".format(msg), file=sys.stderr)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _load_json(path):
|
|
53
|
+
"""Load and return parsed JSON from a file. Returns (data, error_string)."""
|
|
54
|
+
if not os.path.isfile(path):
|
|
55
|
+
return None, "File not found: {}".format(path)
|
|
56
|
+
try:
|
|
57
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
58
|
+
data = json.load(f)
|
|
59
|
+
return data, None
|
|
60
|
+
except json.JSONDecodeError as e:
|
|
61
|
+
return None, "Invalid JSON in {}: {}".format(path, e)
|
|
62
|
+
except Exception as e:
|
|
63
|
+
return None, "Cannot read {}: {}".format(path, e)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _write_json(path, data):
|
|
67
|
+
"""Write data as pretty-printed JSON to path. Creates parent dirs if needed."""
|
|
68
|
+
parent = os.path.dirname(os.path.abspath(path))
|
|
69
|
+
if parent and not os.path.isdir(parent):
|
|
70
|
+
os.makedirs(parent, exist_ok=True)
|
|
71
|
+
with open(path, "w", encoding="utf-8") as f:
|
|
72
|
+
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
73
|
+
f.write("\n")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def validate(data, feature_ids=None):
|
|
77
|
+
"""Validate a parsed bug-fix-list data structure.
|
|
78
|
+
|
|
79
|
+
Returns a dict with keys: valid, errors, warnings, stats.
|
|
80
|
+
"""
|
|
81
|
+
errors = []
|
|
82
|
+
warnings = []
|
|
83
|
+
|
|
84
|
+
# Top-level required fields
|
|
85
|
+
if "$schema" not in data:
|
|
86
|
+
errors.append("Missing required field: $schema")
|
|
87
|
+
elif data["$schema"] != SCHEMA_VERSION:
|
|
88
|
+
errors.append("Invalid $schema: expected '{}', got '{}'".format(SCHEMA_VERSION, data["$schema"]))
|
|
89
|
+
|
|
90
|
+
if not data.get("project_name"):
|
|
91
|
+
errors.append("Missing or empty required field: project_name")
|
|
92
|
+
|
|
93
|
+
bugs = data.get("bugs", [])
|
|
94
|
+
if not bugs or not isinstance(bugs, list):
|
|
95
|
+
errors.append("Missing or empty required field: bugs")
|
|
96
|
+
return {
|
|
97
|
+
"valid": False,
|
|
98
|
+
"errors": errors,
|
|
99
|
+
"warnings": warnings,
|
|
100
|
+
"stats": {"total_bugs": 0, "severity_distribution": {}},
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
# Per-bug validation
|
|
104
|
+
seen_ids = set()
|
|
105
|
+
severity_counts = {}
|
|
106
|
+
|
|
107
|
+
for i, bug in enumerate(bugs):
|
|
108
|
+
prefix = "bugs[{}]".format(i)
|
|
109
|
+
|
|
110
|
+
# Required fields
|
|
111
|
+
bug_id = bug.get("id", "")
|
|
112
|
+
if not bug_id:
|
|
113
|
+
errors.append("{}: missing required field 'id'".format(prefix))
|
|
114
|
+
elif not BUG_ID_PATTERN.match(bug_id):
|
|
115
|
+
errors.append("{}: id '{}' does not match pattern B-NNN".format(prefix, bug_id))
|
|
116
|
+
|
|
117
|
+
if bug_id in seen_ids:
|
|
118
|
+
errors.append("{}: duplicate bug id '{}'".format(prefix, bug_id))
|
|
119
|
+
seen_ids.add(bug_id)
|
|
120
|
+
|
|
121
|
+
if not bug.get("title"):
|
|
122
|
+
errors.append("{} ({}): missing required field 'title'".format(prefix, bug_id))
|
|
123
|
+
|
|
124
|
+
if not bug.get("description"):
|
|
125
|
+
errors.append("{} ({}): missing required field 'description'".format(prefix, bug_id))
|
|
126
|
+
|
|
127
|
+
severity = bug.get("severity", "")
|
|
128
|
+
if severity not in VALID_SEVERITIES:
|
|
129
|
+
errors.append("{} ({}): invalid severity '{}' — must be one of {}".format(
|
|
130
|
+
prefix, bug_id, severity, sorted(VALID_SEVERITIES)))
|
|
131
|
+
else:
|
|
132
|
+
severity_counts[severity] = severity_counts.get(severity, 0) + 1
|
|
133
|
+
|
|
134
|
+
# error_source
|
|
135
|
+
error_source = bug.get("error_source", {})
|
|
136
|
+
source_type = error_source.get("type", "") if isinstance(error_source, dict) else ""
|
|
137
|
+
if source_type not in VALID_SOURCE_TYPES:
|
|
138
|
+
errors.append("{} ({}): invalid error_source.type '{}' — must be one of {}".format(
|
|
139
|
+
prefix, bug_id, source_type, sorted(VALID_SOURCE_TYPES)))
|
|
140
|
+
|
|
141
|
+
# verification_type
|
|
142
|
+
vtype = bug.get("verification_type", "")
|
|
143
|
+
if vtype not in VALID_VERIFICATION_TYPES:
|
|
144
|
+
errors.append("{} ({}): invalid verification_type '{}' — must be one of {}".format(
|
|
145
|
+
prefix, bug_id, vtype, sorted(VALID_VERIFICATION_TYPES)))
|
|
146
|
+
|
|
147
|
+
# acceptance_criteria
|
|
148
|
+
ac = bug.get("acceptance_criteria", [])
|
|
149
|
+
if not ac or not isinstance(ac, list):
|
|
150
|
+
errors.append("{} ({}): missing or empty acceptance_criteria array".format(prefix, bug_id))
|
|
151
|
+
|
|
152
|
+
# status
|
|
153
|
+
status = bug.get("status", "")
|
|
154
|
+
if status not in VALID_STATUSES:
|
|
155
|
+
errors.append("{} ({}): invalid status '{}' — must be one of {}".format(
|
|
156
|
+
prefix, bug_id, status, sorted(VALID_STATUSES)))
|
|
157
|
+
|
|
158
|
+
# Priority validation (optional field)
|
|
159
|
+
priority = bug.get("priority")
|
|
160
|
+
if priority is not None:
|
|
161
|
+
if priority not in ("high", "medium", "low"):
|
|
162
|
+
errors.append("{} ({}): invalid priority '{}' — must be one of 'high', 'medium', 'low'".format(
|
|
163
|
+
prefix, bug_id, priority))
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
"valid": len(errors) == 0,
|
|
167
|
+
"errors": errors,
|
|
168
|
+
"warnings": warnings,
|
|
169
|
+
"stats": {
|
|
170
|
+
"total_bugs": len(bugs),
|
|
171
|
+
"severity_distribution": severity_counts,
|
|
172
|
+
},
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def cmd_validate(args):
|
|
177
|
+
"""Handle the 'validate' command."""
|
|
178
|
+
bug_list = args.input
|
|
179
|
+
feature_list = args.feature_list
|
|
180
|
+
|
|
181
|
+
data, load_err = _load_json(bug_list)
|
|
182
|
+
if load_err:
|
|
183
|
+
_err(load_err)
|
|
184
|
+
return 2
|
|
185
|
+
|
|
186
|
+
# Load feature-list.json (optional, for cross-reference)
|
|
187
|
+
if feature_list:
|
|
188
|
+
fl_data, fl_err = _load_json(feature_list)
|
|
189
|
+
if not fl_data:
|
|
190
|
+
_warn("Could not load feature-list.json at {}: {}".format(feature_list, fl_err))
|
|
191
|
+
|
|
192
|
+
result = validate(data)
|
|
193
|
+
|
|
194
|
+
# Print results to stdout
|
|
195
|
+
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
196
|
+
|
|
197
|
+
if result["valid"]:
|
|
198
|
+
bug_count = result["stats"]["total_bugs"]
|
|
199
|
+
sev = result["stats"]["severity_distribution"]
|
|
200
|
+
sev_str = ", ".join("{}={}".format(k, v) for k, v in sorted(sev.items()))
|
|
201
|
+
_info("VALIDATION PASSED — {} bugs ({})".format(bug_count, sev_str))
|
|
202
|
+
return 0
|
|
203
|
+
else:
|
|
204
|
+
_err("VALIDATION FAILED — {} error(s), {} warning(s)".format(
|
|
205
|
+
len(result["errors"]), len(result["warnings"])))
|
|
206
|
+
for e in result["errors"]:
|
|
207
|
+
_err(" ERROR: {}".format(e))
|
|
208
|
+
for w in result["warnings"]:
|
|
209
|
+
_warn(" WARN: {}".format(w))
|
|
210
|
+
return 1
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def cmd_generate(args):
|
|
214
|
+
"""Handle the 'generate' command.
|
|
215
|
+
|
|
216
|
+
Loads a draft JSON (produced by AI), fills in defaults, validates,
|
|
217
|
+
and writes the final bug-fix-list.json.
|
|
218
|
+
"""
|
|
219
|
+
# Load draft (supports stdin via '-')
|
|
220
|
+
if args.input == "-":
|
|
221
|
+
try:
|
|
222
|
+
data = json.load(sys.stdin)
|
|
223
|
+
except json.JSONDecodeError as exc:
|
|
224
|
+
_err("Invalid JSON from stdin: {}".format(exc))
|
|
225
|
+
return 2
|
|
226
|
+
else:
|
|
227
|
+
data, load_err = _load_json(args.input)
|
|
228
|
+
if load_err:
|
|
229
|
+
_err(load_err)
|
|
230
|
+
return 2
|
|
231
|
+
|
|
232
|
+
# Fill in defaults
|
|
233
|
+
now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
234
|
+
data.setdefault("$schema", SCHEMA_VERSION)
|
|
235
|
+
data.setdefault("created_at", now)
|
|
236
|
+
data.setdefault("created_by", "bug-planner")
|
|
237
|
+
|
|
238
|
+
# Set default status for bugs without one
|
|
239
|
+
for bug in data.get("bugs", []):
|
|
240
|
+
bug.setdefault("status", "pending")
|
|
241
|
+
|
|
242
|
+
# Validate
|
|
243
|
+
result = validate(data)
|
|
244
|
+
|
|
245
|
+
# Output validation result
|
|
246
|
+
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
247
|
+
|
|
248
|
+
if result["valid"]:
|
|
249
|
+
_write_json(args.output, data)
|
|
250
|
+
_info("Generated bug-fix-list written to {}".format(args.output))
|
|
251
|
+
return 0
|
|
252
|
+
else:
|
|
253
|
+
_err("Validation failed with {} error(s)".format(len(result["errors"])))
|
|
254
|
+
for e in result["errors"]:
|
|
255
|
+
_err(" ERROR: {}".format(e))
|
|
256
|
+
return 1
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def main():
|
|
260
|
+
# Backward compatibility: if first arg is a file path (not a subcommand),
|
|
261
|
+
# treat it as 'validate' command
|
|
262
|
+
if len(sys.argv) > 1 and not sys.argv[1].startswith("-") and sys.argv[1] not in ("validate", "generate"):
|
|
263
|
+
sys.argv.insert(1, "validate")
|
|
264
|
+
|
|
265
|
+
parser = argparse.ArgumentParser(
|
|
266
|
+
description="Validate and generate .prizmkit/plans/bug-fix-list.json files.",
|
|
267
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
268
|
+
epilog=(
|
|
269
|
+
"Examples:\n"
|
|
270
|
+
" %(prog)s validate .prizmkit/plans/bug-fix-list.json\n"
|
|
271
|
+
" %(prog)s validate .prizmkit/plans/bug-fix-list.json --feature-list .prizmkit/plans/feature-list.json\n"
|
|
272
|
+
" %(prog)s generate --input draft.json --output .prizmkit/plans/bug-fix-list.json\n"
|
|
273
|
+
),
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
subparsers = parser.add_subparsers(dest="command", help="Command to execute")
|
|
277
|
+
|
|
278
|
+
# -- validate --
|
|
279
|
+
p_validate = subparsers.add_parser(
|
|
280
|
+
"validate",
|
|
281
|
+
help="Validate an existing bug-fix-list.json",
|
|
282
|
+
)
|
|
283
|
+
p_validate.add_argument(
|
|
284
|
+
"input", help="Path to bug-fix-list.json"
|
|
285
|
+
)
|
|
286
|
+
p_validate.add_argument(
|
|
287
|
+
"--feature-list", default=None, help="Path to feature-list.json for cross-reference"
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
# -- generate --
|
|
291
|
+
p_generate = subparsers.add_parser(
|
|
292
|
+
"generate",
|
|
293
|
+
help="Validate a draft and generate final bug-fix-list.json with defaults",
|
|
294
|
+
)
|
|
295
|
+
p_generate.add_argument(
|
|
296
|
+
"--input", required=True, help="Path to draft JSON (or '-' for stdin)"
|
|
297
|
+
)
|
|
298
|
+
p_generate.add_argument(
|
|
299
|
+
"--output", required=True, help="Path to write final bug-fix-list.json"
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
args = parser.parse_args()
|
|
303
|
+
|
|
304
|
+
if not args.command:
|
|
305
|
+
parser.print_help(sys.stderr)
|
|
306
|
+
return 2
|
|
307
|
+
|
|
308
|
+
dispatch = {
|
|
309
|
+
"validate": cmd_validate,
|
|
310
|
+
"generate": cmd_generate,
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
handler = dispatch.get(args.command)
|
|
314
|
+
if handler is None:
|
|
315
|
+
_err("Unknown command: {}".format(args.command))
|
|
316
|
+
return 2
|
|
317
|
+
|
|
318
|
+
return handler(args)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
if __name__ == "__main__":
|
|
322
|
+
sys.exit(main())
|