prizmkit 1.1.7 → 1.1.9
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/bundled/VERSION.json +3 -3
- package/bundled/adapters/codebuddy/skill-adapter.js +21 -7
- package/bundled/agents/prizm-dev-team-reviewer.md +53 -173
- package/bundled/dev-pipeline/.env.example +45 -0
- package/bundled/dev-pipeline/README.md +64 -64
- package/bundled/dev-pipeline/SCHEMA_ANALYSIS.md +535 -0
- package/bundled/dev-pipeline/assets/feature-list-example.json +0 -1
- package/bundled/dev-pipeline/launch-bugfix-daemon.sh +64 -18
- package/bundled/dev-pipeline/launch-feature-daemon.sh +15 -12
- package/bundled/dev-pipeline/launch-refactor-daemon.sh +64 -18
- package/bundled/dev-pipeline/lib/branch.sh +6 -1
- package/bundled/dev-pipeline/lib/common.sh +71 -0
- package/bundled/dev-pipeline/lib/heartbeat.sh +2 -2
- package/bundled/dev-pipeline/reset-bug.sh +10 -9
- package/bundled/dev-pipeline/reset-feature.sh +9 -8
- package/bundled/dev-pipeline/reset-refactor.sh +10 -9
- package/bundled/dev-pipeline/retry-bugfix.sh +67 -29
- package/bundled/dev-pipeline/retry-feature.sh +54 -18
- package/bundled/dev-pipeline/retry-refactor.sh +112 -29
- package/bundled/dev-pipeline/run-bugfix.sh +281 -59
- package/bundled/dev-pipeline/run-feature.sh +53 -18
- package/bundled/dev-pipeline/run-refactor.sh +392 -66
- package/bundled/dev-pipeline/scripts/check-session-status.py +24 -1
- package/bundled/dev-pipeline/scripts/cleanup-logs.py +2 -2
- package/bundled/dev-pipeline/scripts/detect-stuck.py +195 -85
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +57 -33
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +25 -9
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +104 -17
- package/bundled/dev-pipeline/scripts/init-bugfix-pipeline.py +34 -9
- package/bundled/dev-pipeline/scripts/init-pipeline.py +10 -10
- package/bundled/dev-pipeline/scripts/init-refactor-pipeline.py +19 -8
- package/bundled/dev-pipeline/scripts/parse-stream-progress.py +1 -5
- package/bundled/dev-pipeline/scripts/patch-completion-notes.py +191 -0
- package/bundled/dev-pipeline/scripts/update-bug-status.py +167 -22
- package/bundled/dev-pipeline/scripts/update-feature-status.py +104 -62
- package/bundled/dev-pipeline/scripts/update-refactor-status.py +351 -21
- package/bundled/dev-pipeline/templates/agent-prompts/dev-fix.md +1 -1
- package/bundled/dev-pipeline/templates/agent-prompts/reviewer-review.md +7 -11
- package/bundled/dev-pipeline/templates/bootstrap-prompt.md +41 -7
- package/bundled/dev-pipeline/templates/bootstrap-tier1.md +27 -3
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +43 -19
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +54 -26
- package/bundled/dev-pipeline/templates/bug-fix-list-schema.json +6 -15
- package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +36 -25
- package/bundled/dev-pipeline/templates/feature-list-schema.json +109 -31
- package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +270 -0
- package/bundled/dev-pipeline/templates/refactor-list-schema.json +11 -3
- package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +3 -1
- package/bundled/dev-pipeline/templates/sections/critical-paths-agent.md +1 -0
- package/bundled/dev-pipeline/templates/sections/feature-context.md +2 -0
- package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +29 -2
- package/bundled/dev-pipeline/templates/sections/phase-commit.md +22 -0
- package/bundled/dev-pipeline/templates/sections/phase-deploy-verification.md +2 -2
- package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +8 -6
- package/bundled/dev-pipeline/templates/sections/phase-review-full.md +7 -5
- package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +3 -3
- package/bundled/skills/_metadata.json +5 -22
- package/bundled/skills/app-planner/SKILL.md +98 -72
- package/bundled/skills/app-planner/assets/app-design-guide.md +1 -1
- package/bundled/skills/app-planner/references/architecture-decisions.md +1 -1
- package/bundled/skills/app-planner/references/project-brief-guide.md +69 -66
- package/bundled/skills/bug-fix-workflow/SKILL.md +52 -9
- package/bundled/skills/bug-planner/SKILL.md +139 -197
- package/bundled/skills/bug-planner/assets/bug-confirmation-template.md +43 -0
- package/bundled/skills/bug-planner/references/critic-and-verification.md +44 -0
- package/bundled/skills/bug-planner/references/error-recovery.md +73 -0
- package/bundled/skills/bug-planner/references/input-formats.md +53 -0
- package/bundled/skills/bug-planner/references/schema-validation.md +25 -0
- package/bundled/skills/bug-planner/references/severity-rules.md +16 -0
- package/bundled/skills/bug-planner/scripts/validate-bug-list.py +4 -8
- package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +34 -39
- package/bundled/skills/feature-pipeline-launcher/SKILL.md +49 -36
- package/bundled/skills/feature-pipeline-launcher/scripts/preflight-check.py +3 -3
- package/bundled/skills/feature-planner/SKILL.md +53 -142
- package/bundled/skills/feature-planner/assets/evaluation-guide.md +1 -1
- package/bundled/skills/feature-planner/assets/planning-guide.md +21 -5
- package/bundled/skills/feature-planner/references/browser-interaction.md +2 -4
- package/bundled/skills/feature-planner/references/completeness-review.md +57 -0
- package/bundled/skills/feature-planner/references/error-recovery.md +16 -35
- package/bundled/skills/feature-planner/references/incremental-feature-planning.md +1 -1
- package/bundled/skills/feature-planner/references/new-project-planning.md +2 -2
- package/bundled/skills/feature-planner/scripts/validate-and-generate.py +19 -20
- package/bundled/skills/feature-workflow/SKILL.md +24 -25
- package/bundled/skills/prizm-kit/SKILL.md +39 -49
- package/bundled/skills/prizmkit-code-review/SKILL.md +51 -64
- package/bundled/skills/prizmkit-code-review/rules/dimensions.md +85 -0
- package/bundled/skills/prizmkit-code-review/rules/fix-strategy.md +11 -11
- package/bundled/skills/prizmkit-committer/SKILL.md +3 -31
- package/bundled/skills/prizmkit-deploy/SKILL.md +34 -31
- package/bundled/skills/prizmkit-deploy/assets/deploy-template.md +1 -1
- package/bundled/skills/prizmkit-implement/SKILL.md +35 -68
- package/bundled/skills/prizmkit-init/SKILL.md +112 -65
- package/bundled/skills/prizmkit-init/assets/project-brief-template.md +82 -0
- package/bundled/skills/prizmkit-plan/SKILL.md +120 -79
- package/bundled/skills/prizmkit-plan/assets/plan-template.md +28 -18
- package/bundled/skills/prizmkit-plan/assets/spec-template.md +28 -11
- package/bundled/skills/prizmkit-plan/references/clarify-guide.md +3 -3
- package/bundled/skills/prizmkit-plan/references/verification-checklist.md +60 -0
- package/bundled/skills/prizmkit-prizm-docs/SKILL.md +10 -81
- package/bundled/skills/prizmkit-prizm-docs/assets/{PRIZM-SPEC.md → prizm-docs-format.md} +41 -526
- package/bundled/skills/prizmkit-prizm-docs/references/op-init.md +46 -0
- package/bundled/skills/prizmkit-prizm-docs/references/op-rebuild.md +16 -0
- package/bundled/skills/prizmkit-prizm-docs/references/op-status.md +14 -0
- package/bundled/skills/prizmkit-prizm-docs/references/op-update.md +19 -0
- package/bundled/skills/prizmkit-prizm-docs/references/op-validate.md +17 -0
- package/bundled/skills/prizmkit-retrospective/SKILL.md +27 -65
- package/bundled/skills/prizmkit-retrospective/references/knowledge-injection-steps.md +3 -4
- package/bundled/skills/prizmkit-retrospective/references/structural-sync-steps.md +7 -25
- package/bundled/skills/recovery-workflow/SKILL.md +22 -22
- package/bundled/skills/recovery-workflow/evals/evals.json +5 -5
- package/bundled/skills/recovery-workflow/scripts/detect-recovery-state.py +43 -10
- package/bundled/skills/refactor-pipeline-launcher/SKILL.md +48 -40
- package/bundled/skills/refactor-planner/SKILL.md +43 -61
- package/bundled/skills/refactor-planner/scripts/validate-and-generate-refactor.py +17 -17
- package/bundled/skills/refactor-workflow/SKILL.md +23 -24
- package/bundled/team/prizm-dev-team.json +1 -1
- package/bundled/{skills/prizm-kit/assets → templates}/project-memory-template.md +1 -1
- package/package.json +1 -1
- package/src/clean.js +3 -4
- package/src/gitignore-template.js +7 -9
- package/src/scaffold.js +14 -5
- package/bundled/dev-pipeline/templates/agent-prompts/reviewer-analyze.md +0 -5
- package/bundled/dev-pipeline/templates/sections/phase-analyze-agent.md +0 -19
- package/bundled/dev-pipeline/templates/sections/phase-analyze-full.md +0 -19
- package/bundled/skills/app-planner/references/project-conventions.md +0 -93
- package/bundled/skills/prizmkit-analyze/SKILL.md +0 -207
- package/bundled/skills/prizmkit-code-review/rules/dimensions-bugfix.md +0 -25
- package/bundled/skills/prizmkit-code-review/rules/dimensions-feature.md +0 -43
- package/bundled/skills/prizmkit-code-review/rules/dimensions-refactor.md +0 -25
- package/bundled/skills/prizmkit-implement/references/deploy-guide-protocol.md +0 -69
- package/bundled/skills/prizmkit-verify/SKILL.md +0 -281
- package/bundled/skills/prizmkit-verify/scripts/verify-light.py +0 -402
|
@@ -1,402 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""PrizmKit Light Verification Script — static checks for framework integrity.
|
|
3
|
-
|
|
4
|
-
Usage:
|
|
5
|
-
python3 verify-light.py # Run all rounds
|
|
6
|
-
python3 verify-light.py --round R1 # Run specific round
|
|
7
|
-
python3 verify-light.py --round R1 R2 R4 # Run multiple rounds
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
import argparse
|
|
11
|
-
import json
|
|
12
|
-
import os
|
|
13
|
-
import re
|
|
14
|
-
import subprocess
|
|
15
|
-
import sys
|
|
16
|
-
from pathlib import Path
|
|
17
|
-
|
|
18
|
-
# --- Configuration ---
|
|
19
|
-
|
|
20
|
-
PROJECT_ROOT = Path(__file__).resolve().parents[5] # core/skills/prizmkit-skill/prizmkit-verify/scripts/verify-light.py → root (5 levels up)
|
|
21
|
-
|
|
22
|
-
SKILL_LAYER_DIR = PROJECT_ROOT / "core" / "skills" / "prizmkit-skill"
|
|
23
|
-
PIPELINE_LAYER_DIR = PROJECT_ROOT / "core" / "skills" / "orchestration-skill" / "pipelines"
|
|
24
|
-
WORKFLOW_LAYER_DIR = PROJECT_ROOT / "core" / "skills" / "orchestration-skill" / "workflows"
|
|
25
|
-
DEV_PIPELINE_DIR = PROJECT_ROOT / "dev-pipeline"
|
|
26
|
-
ALL_SKILLS_DIR = PROJECT_ROOT / "core" / "skills"
|
|
27
|
-
|
|
28
|
-
# Expected items per layer
|
|
29
|
-
EXPECTED_PIPELINE_SKILLS = {
|
|
30
|
-
"app-planner", "feature-planner", "bug-planner", "refactor-planner",
|
|
31
|
-
"feature-pipeline-launcher", "bugfix-pipeline-launcher", "refactor-pipeline-launcher",
|
|
32
|
-
}
|
|
33
|
-
EXPECTED_WORKFLOW_SKILLS = {
|
|
34
|
-
"feature-workflow", "bug-fix-workflow", "refactor-workflow", "recovery-workflow",
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
# --- Helpers ---
|
|
38
|
-
|
|
39
|
-
class Result:
|
|
40
|
-
def __init__(self):
|
|
41
|
-
self.passed = 0
|
|
42
|
-
self.warned = 0
|
|
43
|
-
self.failed = 0
|
|
44
|
-
self.details = []
|
|
45
|
-
|
|
46
|
-
def ok(self, msg):
|
|
47
|
-
self.passed += 1
|
|
48
|
-
self.details.append(("PASS", msg))
|
|
49
|
-
|
|
50
|
-
def warn(self, msg):
|
|
51
|
-
self.warned += 1
|
|
52
|
-
self.details.append(("WARN", msg))
|
|
53
|
-
|
|
54
|
-
def fail(self, msg):
|
|
55
|
-
self.failed += 1
|
|
56
|
-
self.details.append(("FAIL", msg))
|
|
57
|
-
|
|
58
|
-
@property
|
|
59
|
-
def status(self):
|
|
60
|
-
if self.failed > 0:
|
|
61
|
-
return "FAIL"
|
|
62
|
-
if self.warned > 0:
|
|
63
|
-
return "WARN"
|
|
64
|
-
return "PASS"
|
|
65
|
-
|
|
66
|
-
def summary(self):
|
|
67
|
-
return f"PASS={self.passed} WARN={self.warned} FAIL={self.failed}"
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def parse_frontmatter(skill_md_path):
|
|
71
|
-
"""Extract YAML frontmatter from SKILL.md."""
|
|
72
|
-
text = skill_md_path.read_text(encoding="utf-8")
|
|
73
|
-
match = re.match(r"^---\n(.*?)\n---", text, re.DOTALL)
|
|
74
|
-
if not match:
|
|
75
|
-
return {}
|
|
76
|
-
fm = {}
|
|
77
|
-
for line in match.group(1).split("\n"):
|
|
78
|
-
if ":" in line:
|
|
79
|
-
key, val = line.split(":", 1)
|
|
80
|
-
fm[key.strip()] = val.strip().strip('"').strip("'")
|
|
81
|
-
return fm
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def find_skill_dirs(base_dir):
|
|
85
|
-
"""Find all directories containing SKILL.md under base_dir."""
|
|
86
|
-
return sorted(
|
|
87
|
-
d for d in base_dir.iterdir()
|
|
88
|
-
if d.is_dir() and (d / "SKILL.md").exists()
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
def collect_all_skill_names():
|
|
93
|
-
"""Collect all known skill names across all categories."""
|
|
94
|
-
names = set()
|
|
95
|
-
for category_dir in ALL_SKILLS_DIR.iterdir():
|
|
96
|
-
if not category_dir.is_dir() or category_dir.name.startswith("."):
|
|
97
|
-
continue
|
|
98
|
-
# Direct skill dirs
|
|
99
|
-
for d in category_dir.iterdir():
|
|
100
|
-
if d.is_dir() and (d / "SKILL.md").exists():
|
|
101
|
-
names.add(d.name)
|
|
102
|
-
# Nested (pipelines/, workflows/)
|
|
103
|
-
if d.is_dir() and not (d / "SKILL.md").exists():
|
|
104
|
-
for sub in d.iterdir():
|
|
105
|
-
if sub.is_dir() and (sub / "SKILL.md").exists():
|
|
106
|
-
names.add(sub.name)
|
|
107
|
-
return names
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
# --- Round Checks ---
|
|
111
|
-
|
|
112
|
-
def run_r1(result: Result):
|
|
113
|
-
"""R1: L1 Skill Layer Light checks."""
|
|
114
|
-
print("\n=== R1: L1 Skill Layer ===")
|
|
115
|
-
skill_dirs = find_skill_dirs(SKILL_LAYER_DIR)
|
|
116
|
-
all_skill_names = collect_all_skill_names()
|
|
117
|
-
|
|
118
|
-
if not skill_dirs:
|
|
119
|
-
result.fail("No skill directories found in prizmkit-skill/")
|
|
120
|
-
return
|
|
121
|
-
|
|
122
|
-
print(f" Found {len(skill_dirs)} skills")
|
|
123
|
-
|
|
124
|
-
for skill_dir in skill_dirs:
|
|
125
|
-
skill_name = skill_dir.name
|
|
126
|
-
skill_md = skill_dir / "SKILL.md"
|
|
127
|
-
|
|
128
|
-
# 1. Frontmatter validation
|
|
129
|
-
fm = parse_frontmatter(skill_md)
|
|
130
|
-
if not fm.get("name"):
|
|
131
|
-
result.fail(f"[{skill_name}] Missing 'name' in frontmatter")
|
|
132
|
-
elif fm["name"] != skill_name:
|
|
133
|
-
result.fail(f"[{skill_name}] name '{fm['name']}' != dir '{skill_name}'")
|
|
134
|
-
else:
|
|
135
|
-
result.ok(f"[{skill_name}] Frontmatter name OK")
|
|
136
|
-
|
|
137
|
-
if not fm.get("description"):
|
|
138
|
-
result.fail(f"[{skill_name}] Missing 'description' in frontmatter")
|
|
139
|
-
else:
|
|
140
|
-
result.ok(f"[{skill_name}] Frontmatter description OK")
|
|
141
|
-
|
|
142
|
-
# 2. ${SKILL_DIR} reference resolution
|
|
143
|
-
content = skill_md.read_text(encoding="utf-8")
|
|
144
|
-
refs = re.findall(r'\$\{SKILL_DIR\}/([^\s`"\')]+)', content)
|
|
145
|
-
for ref in refs:
|
|
146
|
-
resolved = skill_dir / ref
|
|
147
|
-
if resolved.exists():
|
|
148
|
-
result.ok(f"[{skill_name}] Asset ref '{ref}' exists")
|
|
149
|
-
else:
|
|
150
|
-
result.fail(f"[{skill_name}] Asset ref '{ref}' NOT FOUND at {resolved}")
|
|
151
|
-
|
|
152
|
-
# 3. Cross-skill references
|
|
153
|
-
cross_refs = re.findall(r'(?<!\w)/prizmkit-[\w-]+(?=[\s`"\',\)])', content)
|
|
154
|
-
for ref in cross_refs:
|
|
155
|
-
ref_name = ref.lstrip("/")
|
|
156
|
-
if ref_name in all_skill_names:
|
|
157
|
-
result.ok(f"[{skill_name}] Cross-ref '{ref_name}' exists")
|
|
158
|
-
else:
|
|
159
|
-
result.warn(f"[{skill_name}] Cross-ref '{ref_name}' not found as skill dir")
|
|
160
|
-
|
|
161
|
-
# 4. ESLint
|
|
162
|
-
try:
|
|
163
|
-
lint_result = subprocess.run(
|
|
164
|
-
["npm", "run", "lint"], capture_output=True, text=True,
|
|
165
|
-
cwd=str(PROJECT_ROOT), timeout=30,
|
|
166
|
-
)
|
|
167
|
-
errors = len(re.findall(r"(\d+) error[^s]", lint_result.stdout + lint_result.stderr))
|
|
168
|
-
if lint_result.returncode == 0 or errors == 0:
|
|
169
|
-
result.ok("ESLint: 0 errors")
|
|
170
|
-
else:
|
|
171
|
-
result.fail(f"ESLint: {errors} errors found")
|
|
172
|
-
except (subprocess.TimeoutExpired, FileNotFoundError) as e:
|
|
173
|
-
result.warn(f"ESLint: could not run ({e})")
|
|
174
|
-
|
|
175
|
-
# 5. Ruff
|
|
176
|
-
try:
|
|
177
|
-
ruff_result = subprocess.run(
|
|
178
|
-
["npm", "run", "lint:py"], capture_output=True, text=True,
|
|
179
|
-
cwd=str(PROJECT_ROOT), timeout=30,
|
|
180
|
-
)
|
|
181
|
-
if ruff_result.returncode == 0:
|
|
182
|
-
result.ok("Ruff: all checks passed")
|
|
183
|
-
else:
|
|
184
|
-
result.fail(f"Ruff: {ruff_result.stdout.strip()}")
|
|
185
|
-
except (subprocess.TimeoutExpired, FileNotFoundError) as e:
|
|
186
|
-
result.warn(f"Ruff: could not run ({e})")
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
def run_r2(result: Result):
|
|
190
|
-
"""R2: L2 Pipeline Layer Light checks."""
|
|
191
|
-
print("\n=== R2: L2 Pipeline Layer ===")
|
|
192
|
-
skill_dirs = find_skill_dirs(PIPELINE_LAYER_DIR)
|
|
193
|
-
found_names = {d.name for d in skill_dirs}
|
|
194
|
-
|
|
195
|
-
# Check expected skills present
|
|
196
|
-
for expected in EXPECTED_PIPELINE_SKILLS:
|
|
197
|
-
if expected in found_names:
|
|
198
|
-
result.ok(f"[{expected}] Skill exists")
|
|
199
|
-
else:
|
|
200
|
-
result.fail(f"[{expected}] Expected skill NOT FOUND")
|
|
201
|
-
|
|
202
|
-
# Frontmatter validation
|
|
203
|
-
for skill_dir in skill_dirs:
|
|
204
|
-
fm = parse_frontmatter(skill_dir / "SKILL.md")
|
|
205
|
-
if fm.get("name") == skill_dir.name and fm.get("description"):
|
|
206
|
-
result.ok(f"[{skill_dir.name}] Frontmatter OK")
|
|
207
|
-
else:
|
|
208
|
-
result.fail(f"[{skill_dir.name}] Frontmatter invalid: {fm}")
|
|
209
|
-
|
|
210
|
-
# Schema version consistency
|
|
211
|
-
scenarios = [
|
|
212
|
-
("feature", "feature-list-schema.json", "init-pipeline.py"),
|
|
213
|
-
("bugfix", "bug-fix-list-schema.json", "init-bugfix-pipeline.py"),
|
|
214
|
-
("refactor", "refactor-list-schema.json", "init-refactor-pipeline.py"),
|
|
215
|
-
]
|
|
216
|
-
for scenario, schema_file, init_script in scenarios:
|
|
217
|
-
schema_path = DEV_PIPELINE_DIR / "templates" / schema_file
|
|
218
|
-
init_path = DEV_PIPELINE_DIR / "scripts" / init_script
|
|
219
|
-
|
|
220
|
-
if not schema_path.exists():
|
|
221
|
-
result.fail(f"[{scenario}] Schema file missing: {schema_file}")
|
|
222
|
-
continue
|
|
223
|
-
if not init_path.exists():
|
|
224
|
-
result.fail(f"[{scenario}] Init script missing: {init_script}")
|
|
225
|
-
continue
|
|
226
|
-
|
|
227
|
-
# Extract schema const value
|
|
228
|
-
try:
|
|
229
|
-
schema_data = json.loads(schema_path.read_text())
|
|
230
|
-
schema_const = (
|
|
231
|
-
schema_data.get("properties", {})
|
|
232
|
-
.get("$schema", {})
|
|
233
|
-
.get("const", "NOT_FOUND")
|
|
234
|
-
)
|
|
235
|
-
except json.JSONDecodeError:
|
|
236
|
-
result.fail(f"[{scenario}] Schema file is not valid JSON")
|
|
237
|
-
continue
|
|
238
|
-
|
|
239
|
-
# Extract expected schema from init script
|
|
240
|
-
init_content = init_path.read_text()
|
|
241
|
-
match = re.search(r'EXPECTED_SCHEMA\s*=\s*["\']([^"\']+)', init_content)
|
|
242
|
-
init_expected = match.group(1) if match else "NOT_FOUND"
|
|
243
|
-
|
|
244
|
-
if schema_const == init_expected:
|
|
245
|
-
result.ok(f"[{scenario}] Schema version match: {schema_const}")
|
|
246
|
-
else:
|
|
247
|
-
result.fail(f"[{scenario}] Schema version MISMATCH: template={schema_const}, init={init_expected}")
|
|
248
|
-
|
|
249
|
-
# Launcher script path references
|
|
250
|
-
for scenario, script in [("feature", "run-feature.sh"), ("bugfix", "run-bugfix.sh"), ("refactor", "run-refactor.sh")]:
|
|
251
|
-
script_path = DEV_PIPELINE_DIR / script
|
|
252
|
-
if script_path.exists() and os.access(script_path, os.X_OK):
|
|
253
|
-
result.ok(f"[{scenario}] Script {script} exists and executable")
|
|
254
|
-
elif script_path.exists():
|
|
255
|
-
result.warn(f"[{scenario}] Script {script} exists but NOT executable")
|
|
256
|
-
else:
|
|
257
|
-
result.fail(f"[{scenario}] Script {script} NOT FOUND")
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
def run_r3(result: Result):
|
|
261
|
-
"""R3: L3 Workflow Layer Light checks."""
|
|
262
|
-
print("\n=== R3: L3 Workflow Layer ===")
|
|
263
|
-
skill_dirs = find_skill_dirs(WORKFLOW_LAYER_DIR)
|
|
264
|
-
found_names = {d.name for d in skill_dirs}
|
|
265
|
-
pipeline_names = {d.name for d in find_skill_dirs(PIPELINE_LAYER_DIR)}
|
|
266
|
-
|
|
267
|
-
# Check expected skills
|
|
268
|
-
for expected in EXPECTED_WORKFLOW_SKILLS:
|
|
269
|
-
if expected in found_names:
|
|
270
|
-
result.ok(f"[{expected}] Workflow exists")
|
|
271
|
-
else:
|
|
272
|
-
result.fail(f"[{expected}] Expected workflow NOT FOUND")
|
|
273
|
-
|
|
274
|
-
for skill_dir in skill_dirs:
|
|
275
|
-
skill_name = skill_dir.name
|
|
276
|
-
skill_md = skill_dir / "SKILL.md"
|
|
277
|
-
|
|
278
|
-
# Frontmatter
|
|
279
|
-
fm = parse_frontmatter(skill_md)
|
|
280
|
-
if fm.get("name") == skill_name and fm.get("description"):
|
|
281
|
-
result.ok(f"[{skill_name}] Frontmatter OK")
|
|
282
|
-
else:
|
|
283
|
-
result.fail(f"[{skill_name}] Frontmatter invalid")
|
|
284
|
-
|
|
285
|
-
# Pipeline skill references
|
|
286
|
-
content = skill_md.read_text(encoding="utf-8")
|
|
287
|
-
for pipeline_ref in re.findall(r'`([\w-]+-planner|[\w-]+-pipeline-launcher)`', content):
|
|
288
|
-
if pipeline_ref in pipeline_names:
|
|
289
|
-
result.ok(f"[{skill_name}] Pipeline ref '{pipeline_ref}' exists")
|
|
290
|
-
else:
|
|
291
|
-
result.warn(f"[{skill_name}] Pipeline ref '{pipeline_ref}' not found")
|
|
292
|
-
|
|
293
|
-
# Checkpoint naming
|
|
294
|
-
checkpoints = re.findall(r'CP-\w+-\d+', content)
|
|
295
|
-
if checkpoints:
|
|
296
|
-
result.ok(f"[{skill_name}] {len(checkpoints)} checkpoints found (CP-*-N pattern)")
|
|
297
|
-
else:
|
|
298
|
-
result.warn(f"[{skill_name}] No checkpoint markers found")
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
def run_r4(result: Result):
|
|
302
|
-
"""R4: L4 Script Layer Light checks."""
|
|
303
|
-
print("\n=== R4: L4 Script Layer ===")
|
|
304
|
-
|
|
305
|
-
# 1. Shell scripts executable
|
|
306
|
-
for sh_file in sorted(DEV_PIPELINE_DIR.glob("*.sh")):
|
|
307
|
-
if os.access(sh_file, os.X_OK):
|
|
308
|
-
result.ok(f"[{sh_file.name}] Executable")
|
|
309
|
-
else:
|
|
310
|
-
result.fail(f"[{sh_file.name}] NOT executable")
|
|
311
|
-
|
|
312
|
-
# 2. Python scripts compile
|
|
313
|
-
scripts_dir = DEV_PIPELINE_DIR / "scripts"
|
|
314
|
-
if scripts_dir.exists():
|
|
315
|
-
for py_file in sorted(scripts_dir.glob("*.py")):
|
|
316
|
-
try:
|
|
317
|
-
subprocess.run(
|
|
318
|
-
[sys.executable, "-m", "py_compile", str(py_file)],
|
|
319
|
-
capture_output=True, text=True, timeout=10,
|
|
320
|
-
)
|
|
321
|
-
result.ok(f"[{py_file.name}] Compiles OK")
|
|
322
|
-
except subprocess.TimeoutExpired:
|
|
323
|
-
result.warn(f"[{py_file.name}] Compile check timed out")
|
|
324
|
-
|
|
325
|
-
# 3. Bash lib sourcing
|
|
326
|
-
for run_script in ["run-feature.sh", "run-bugfix.sh", "run-refactor.sh"]:
|
|
327
|
-
script_path = DEV_PIPELINE_DIR / run_script
|
|
328
|
-
if not script_path.exists():
|
|
329
|
-
result.fail(f"[{run_script}] NOT FOUND")
|
|
330
|
-
continue
|
|
331
|
-
content = script_path.read_text(encoding="utf-8")
|
|
332
|
-
for lib in ["common.sh", "heartbeat.sh", "branch.sh"]:
|
|
333
|
-
if lib in content:
|
|
334
|
-
result.ok(f"[{run_script}] Sources {lib}")
|
|
335
|
-
else:
|
|
336
|
-
result.fail(f"[{run_script}] Does NOT source {lib}")
|
|
337
|
-
|
|
338
|
-
# 4. JSON templates valid
|
|
339
|
-
templates_dir = DEV_PIPELINE_DIR / "templates"
|
|
340
|
-
if templates_dir.exists():
|
|
341
|
-
for json_file in sorted(templates_dir.glob("*.json")):
|
|
342
|
-
try:
|
|
343
|
-
json.loads(json_file.read_text())
|
|
344
|
-
result.ok(f"[{json_file.name}] Valid JSON")
|
|
345
|
-
except json.JSONDecodeError as e:
|
|
346
|
-
result.fail(f"[{json_file.name}] Invalid JSON: {e}")
|
|
347
|
-
|
|
348
|
-
# 5. Test file existence
|
|
349
|
-
tests_dir = DEV_PIPELINE_DIR / "tests"
|
|
350
|
-
if tests_dir.exists():
|
|
351
|
-
test_files = list(tests_dir.glob("test_*.py"))
|
|
352
|
-
if test_files:
|
|
353
|
-
result.ok(f"Test files found: {len(test_files)}")
|
|
354
|
-
else:
|
|
355
|
-
result.warn("No test_*.py files found in dev-pipeline/tests/")
|
|
356
|
-
else:
|
|
357
|
-
result.warn("dev-pipeline/tests/ directory not found")
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
# --- Main ---
|
|
361
|
-
|
|
362
|
-
def main():
|
|
363
|
-
parser = argparse.ArgumentParser(description="PrizmKit Light Verification")
|
|
364
|
-
parser.add_argument("--round", nargs="*", default=["R1", "R2", "R3", "R4"],
|
|
365
|
-
help="Rounds to run (R1, R2, R3, R4)")
|
|
366
|
-
args = parser.parse_args()
|
|
367
|
-
|
|
368
|
-
rounds_to_run = [r.upper() for r in args.round]
|
|
369
|
-
result = Result()
|
|
370
|
-
|
|
371
|
-
round_map = {"R1": run_r1, "R2": run_r2, "R3": run_r3, "R4": run_r4}
|
|
372
|
-
|
|
373
|
-
for round_name in rounds_to_run:
|
|
374
|
-
if round_name in round_map:
|
|
375
|
-
round_map[round_name](result)
|
|
376
|
-
else:
|
|
377
|
-
print(f" Unknown round: {round_name}")
|
|
378
|
-
|
|
379
|
-
# Print results
|
|
380
|
-
print("\n" + "=" * 60)
|
|
381
|
-
print(f" RESULT: {result.status}")
|
|
382
|
-
print(f" {result.summary()}")
|
|
383
|
-
print("=" * 60)
|
|
384
|
-
|
|
385
|
-
if result.failed > 0:
|
|
386
|
-
print("\n FAILURES:")
|
|
387
|
-
for status, msg in result.details:
|
|
388
|
-
if status == "FAIL":
|
|
389
|
-
print(f" {msg}")
|
|
390
|
-
|
|
391
|
-
if result.warned > 0:
|
|
392
|
-
print("\n WARNINGS:")
|
|
393
|
-
for status, msg in result.details:
|
|
394
|
-
if status == "WARN":
|
|
395
|
-
print(f" {msg}")
|
|
396
|
-
|
|
397
|
-
print()
|
|
398
|
-
return 0 if result.failed == 0 else 1
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
if __name__ == "__main__":
|
|
402
|
-
sys.exit(main())
|