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,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Initialize the dev-pipeline state directory from a feature-list.json file.
|
|
2
|
+
"""Initialize the dev-pipeline state directory from a .prizmkit/plans/feature-list.json file.
|
|
3
3
|
|
|
4
4
|
Validates the feature list schema, checks dependency DAG for cycles,
|
|
5
5
|
and creates the state directory structure with pipeline and feature status files.
|
|
@@ -18,8 +18,8 @@ from datetime import datetime, timezone
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
EXPECTED_SCHEMA = "dev-pipeline-feature-list-v1"
|
|
21
|
-
FEATURE_ID_PATTERN = re.compile(r"^F-\d{3}
|
|
22
|
-
TERMINAL_STATUSES = {"completed", "failed", "skipped"}
|
|
21
|
+
FEATURE_ID_PATTERN = re.compile(r"^F-\d{3}(-[A-Z])?$")
|
|
22
|
+
TERMINAL_STATUSES = {"completed", "failed", "skipped", "split", "auto_skipped"}
|
|
23
23
|
VALID_PRIORITIES = {"critical", "high", "medium", "low"}
|
|
24
24
|
|
|
25
25
|
REQUIRED_FEATURE_FIELDS = [
|
|
@@ -35,17 +35,17 @@ REQUIRED_FEATURE_FIELDS = [
|
|
|
35
35
|
|
|
36
36
|
def parse_args():
|
|
37
37
|
parser = argparse.ArgumentParser(
|
|
38
|
-
description="Initialize dev-pipeline state from a feature-list.json file."
|
|
38
|
+
description="Initialize dev-pipeline state from a .prizmkit/plans/feature-list.json file."
|
|
39
39
|
)
|
|
40
40
|
parser.add_argument(
|
|
41
41
|
"--feature-list",
|
|
42
42
|
required=True,
|
|
43
|
-
help="Path to the feature-list.json file",
|
|
43
|
+
help="Path to the .prizmkit/plans/feature-list.json file",
|
|
44
44
|
)
|
|
45
45
|
parser.add_argument(
|
|
46
46
|
"--state-dir",
|
|
47
47
|
required=True,
|
|
48
|
-
help="Path to the state directory
|
|
48
|
+
help="Path to the state directory (default: .prizmkit/state/features)",
|
|
49
49
|
)
|
|
50
50
|
return parser.parse_args()
|
|
51
51
|
|
|
@@ -245,7 +245,7 @@ def create_state_directory(state_dir, feature_list_path, features):
|
|
|
245
245
|
features_dir = os.path.join(abs_state_dir, "features")
|
|
246
246
|
|
|
247
247
|
now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
248
|
-
run_id = "run-" + datetime.now(timezone.utc).strftime("%Y%m%d%H%M")
|
|
248
|
+
run_id = "run-" + datetime.now(timezone.utc).strftime("%Y%m%d%H%M%S")
|
|
249
249
|
|
|
250
250
|
# Create top-level state directory
|
|
251
251
|
os.makedirs(abs_state_dir, exist_ok=True)
|
|
@@ -283,7 +283,7 @@ def create_state_directory(state_dir, feature_list_path, features):
|
|
|
283
283
|
sessions_dir = os.path.join(feature_dir, "sessions")
|
|
284
284
|
os.makedirs(sessions_dir, exist_ok=True)
|
|
285
285
|
|
|
286
|
-
# Respect existing terminal status from feature-list.json
|
|
286
|
+
# Respect existing terminal status from .prizmkit/plans/feature-list.json
|
|
287
287
|
fl_status = feature.get("status", "pending")
|
|
288
288
|
init_status = fl_status if fl_status in TERMINAL_STATUSES else "pending"
|
|
289
289
|
|
|
@@ -316,13 +316,13 @@ def main():
|
|
|
316
316
|
print(json.dumps(output, indent=2, ensure_ascii=False))
|
|
317
317
|
sys.exit(1)
|
|
318
318
|
|
|
319
|
-
# Warn if feature-list.json is not at project root
|
|
319
|
+
# Warn if .prizmkit/plans/feature-list.json is not at project root
|
|
320
320
|
feature_list_dir = os.path.dirname(os.path.abspath(args.feature_list))
|
|
321
321
|
indicators = ['.git', 'package.json', '.prizmkit']
|
|
322
322
|
is_at_root = any(os.path.exists(os.path.join(feature_list_dir, i)) for i in indicators)
|
|
323
323
|
if not is_at_root:
|
|
324
324
|
sys.stderr.write(
|
|
325
|
-
"Warning: feature-list.json may not be at project root: {}\n".format(feature_list_dir)
|
|
325
|
+
"Warning: .prizmkit/plans/feature-list.json may not be at project root: {}\n".format(feature_list_dir)
|
|
326
326
|
)
|
|
327
327
|
|
|
328
328
|
# Validate schema
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Initialize the refactor pipeline state directory from a refactor-list.json file.
|
|
2
|
+
"""Initialize the refactor pipeline state directory from a .prizmkit/plans/refactor-list.json file.
|
|
3
3
|
|
|
4
4
|
Validates the refactor list schema, sorts by priority/complexity, checks for
|
|
5
5
|
circular dependencies, and creates the state directory structure with pipeline
|
|
@@ -40,24 +40,25 @@ VALID_TYPES = ["extract", "rename", "restructure", "simplify", "decouple", "migr
|
|
|
40
40
|
VALID_PRIORITIES = ["critical", "high", "medium", "low"]
|
|
41
41
|
VALID_COMPLEXITIES = ["low", "medium", "high"]
|
|
42
42
|
VALID_STATUSES = [
|
|
43
|
-
"pending", "in_progress", "completed", "failed", "skipped",
|
|
43
|
+
"pending", "in_progress", "completed", "failed", "skipped", "auto_skipped",
|
|
44
44
|
]
|
|
45
|
+
TERMINAL_STATUSES = {"completed", "failed", "skipped", "auto_skipped"}
|
|
45
46
|
VALID_BEHAVIOR_STRATEGIES = ["test-gate", "snapshot", "manual"]
|
|
46
47
|
|
|
47
48
|
|
|
48
49
|
def parse_args():
|
|
49
50
|
parser = argparse.ArgumentParser(
|
|
50
|
-
description="Initialize refactor pipeline state from a refactor-list.json file."
|
|
51
|
+
description="Initialize refactor pipeline state from a .prizmkit/plans/refactor-list.json file."
|
|
51
52
|
)
|
|
52
53
|
parser.add_argument(
|
|
53
54
|
"--refactor-list",
|
|
54
55
|
required=True,
|
|
55
|
-
help="Path to the refactor-list.json file",
|
|
56
|
+
help="Path to the .prizmkit/plans/refactor-list.json file",
|
|
56
57
|
)
|
|
57
58
|
parser.add_argument(
|
|
58
59
|
"--state-dir",
|
|
59
60
|
required=True,
|
|
60
|
-
help="Path to the state directory
|
|
61
|
+
help="Path to the state directory (default: .prizmkit/state/refactor)",
|
|
61
62
|
)
|
|
62
63
|
return parser.parse_args()
|
|
63
64
|
|
|
@@ -285,12 +286,18 @@ def create_state_directory(state_dir, refactor_list_path, refactors):
|
|
|
285
286
|
refactors_dir = os.path.join(abs_state_dir, "refactors")
|
|
286
287
|
|
|
287
288
|
now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
288
|
-
run_id = "refactor-run-" + datetime.now(timezone.utc).strftime("%Y%m%d%H%M")
|
|
289
|
+
run_id = "refactor-run-" + datetime.now(timezone.utc).strftime("%Y%m%d%H%M%S")
|
|
289
290
|
|
|
290
291
|
# Create top-level state directory
|
|
291
292
|
os.makedirs(abs_state_dir, exist_ok=True)
|
|
292
293
|
os.makedirs(refactors_dir, exist_ok=True)
|
|
293
294
|
|
|
295
|
+
# Count refactors already in terminal status at init time
|
|
296
|
+
completed_count = sum(
|
|
297
|
+
1 for r in refactors
|
|
298
|
+
if isinstance(r, dict) and r.get("status") in TERMINAL_STATUSES
|
|
299
|
+
)
|
|
300
|
+
|
|
294
301
|
# Write pipeline.json
|
|
295
302
|
pipeline_state = {
|
|
296
303
|
"run_id": run_id,
|
|
@@ -299,7 +306,7 @@ def create_state_directory(state_dir, refactor_list_path, refactors):
|
|
|
299
306
|
"refactor_list_path": rel_refactor_list_path,
|
|
300
307
|
"created_at": now,
|
|
301
308
|
"total_refactors": len(refactors),
|
|
302
|
-
"completed_refactors":
|
|
309
|
+
"completed_refactors": completed_count,
|
|
303
310
|
}
|
|
304
311
|
pipeline_path = os.path.join(abs_state_dir, "pipeline.json")
|
|
305
312
|
with open(pipeline_path, "w", encoding="utf-8") as f:
|
|
@@ -318,9 +325,13 @@ def create_state_directory(state_dir, refactor_list_path, refactors):
|
|
|
318
325
|
sessions_dir = os.path.join(refactor_dir, "sessions")
|
|
319
326
|
os.makedirs(sessions_dir, exist_ok=True)
|
|
320
327
|
|
|
328
|
+
# Respect existing terminal status from refactor-list.json
|
|
329
|
+
rl_status = refactor.get("status", "pending")
|
|
330
|
+
init_status = rl_status if rl_status in TERMINAL_STATUSES else "pending"
|
|
331
|
+
|
|
321
332
|
refactor_status = {
|
|
322
333
|
"refactor_id": rid,
|
|
323
|
-
"status":
|
|
334
|
+
"status": init_status,
|
|
324
335
|
"retry_count": 0,
|
|
325
336
|
"max_retries": 3,
|
|
326
337
|
"sessions": [],
|
|
@@ -28,7 +28,7 @@ from datetime import datetime, timezone
|
|
|
28
28
|
# Ordered pipeline phases — index defines forward-only progression.
|
|
29
29
|
# Phase detection is monotonic: once a phase is reached, earlier phases
|
|
30
30
|
# cannot be re-entered (prevents false positives from file content mentions).
|
|
31
|
-
PHASE_ORDER = ["plan", "
|
|
31
|
+
PHASE_ORDER = ["plan", "implement", "code-review", "retrospective", "commit"]
|
|
32
32
|
|
|
33
33
|
# Keywords for phase detection.
|
|
34
34
|
# "strong" keywords are skill invocations — high confidence, but still
|
|
@@ -40,10 +40,6 @@ PHASE_KEYWORDS = {
|
|
|
40
40
|
"strong": ["prizmkit-plan"],
|
|
41
41
|
"weak": ["spec.md", "plan.md", "specification", "architecture", "task checklist", "task breakdown", "gathering requirements"],
|
|
42
42
|
},
|
|
43
|
-
"analyze": {
|
|
44
|
-
"strong": ["prizmkit-analyze"],
|
|
45
|
-
"weak": ["cross-check", "consistency analysis", "analyzing"],
|
|
46
|
-
},
|
|
47
43
|
"implement": {
|
|
48
44
|
"strong": ["prizmkit-implement"],
|
|
49
45
|
"weak": ["implement", "writing code", "TDD", "coding"],
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Patch completion_notes into feature-list.json, refactor-list.json, or bug-fix-list.json.
|
|
3
|
+
|
|
4
|
+
Reads a completion-summary.json file written by the AI session and patches
|
|
5
|
+
the corresponding item in the task list with the completion_notes field.
|
|
6
|
+
|
|
7
|
+
This enables rich dependency context propagation: when a downstream task's
|
|
8
|
+
bootstrap prompt is generated, it can read completion_notes from its
|
|
9
|
+
completed dependencies to understand what was built/changed.
|
|
10
|
+
|
|
11
|
+
Usage:
|
|
12
|
+
python3 patch-completion-notes.py \
|
|
13
|
+
--feature-list .prizmkit/plans/feature-list.json \
|
|
14
|
+
--feature-id F-001 \
|
|
15
|
+
--summary .prizmkit/specs/001-my-feature/completion-summary.json
|
|
16
|
+
|
|
17
|
+
python3 patch-completion-notes.py \
|
|
18
|
+
--refactor-list .prizmkit/plans/refactor-list.json \
|
|
19
|
+
--refactor-id R-001 \
|
|
20
|
+
--summary <path-to-summary>
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import argparse
|
|
24
|
+
import json
|
|
25
|
+
import os
|
|
26
|
+
import sys
|
|
27
|
+
|
|
28
|
+
from utils import load_json_file, write_json_file, setup_logging
|
|
29
|
+
|
|
30
|
+
LOGGER = setup_logging("patch-completion-notes")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def parse_args():
|
|
34
|
+
parser = argparse.ArgumentParser(
|
|
35
|
+
description="Patch completion_notes into a task list from completion-summary.json."
|
|
36
|
+
)
|
|
37
|
+
parser.add_argument(
|
|
38
|
+
"--feature-list",
|
|
39
|
+
default=None,
|
|
40
|
+
help="Path to .prizmkit/plans/feature-list.json",
|
|
41
|
+
)
|
|
42
|
+
parser.add_argument(
|
|
43
|
+
"--refactor-list",
|
|
44
|
+
default=None,
|
|
45
|
+
help="Path to .prizmkit/plans/refactor-list.json",
|
|
46
|
+
)
|
|
47
|
+
parser.add_argument(
|
|
48
|
+
"--bug-list",
|
|
49
|
+
default=None,
|
|
50
|
+
help="Path to .prizmkit/plans/bug-fix-list.json",
|
|
51
|
+
)
|
|
52
|
+
parser.add_argument(
|
|
53
|
+
"--feature-id",
|
|
54
|
+
default=None,
|
|
55
|
+
help="Feature ID to patch (e.g. F-001)",
|
|
56
|
+
)
|
|
57
|
+
parser.add_argument(
|
|
58
|
+
"--refactor-id",
|
|
59
|
+
default=None,
|
|
60
|
+
help="Refactor ID to patch (e.g. R-001)",
|
|
61
|
+
)
|
|
62
|
+
parser.add_argument(
|
|
63
|
+
"--bug-id",
|
|
64
|
+
default=None,
|
|
65
|
+
help="Bug ID to patch (e.g. B-001)",
|
|
66
|
+
)
|
|
67
|
+
parser.add_argument(
|
|
68
|
+
"--summary",
|
|
69
|
+
required=True,
|
|
70
|
+
help="Path to completion-summary.json file",
|
|
71
|
+
)
|
|
72
|
+
return parser.parse_args()
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def read_completion_notes(summary_path):
|
|
76
|
+
"""Read completion_notes from a completion-summary.json file.
|
|
77
|
+
|
|
78
|
+
Returns a list of strings, or an empty list if the file is missing
|
|
79
|
+
or malformed.
|
|
80
|
+
"""
|
|
81
|
+
if not os.path.isfile(summary_path):
|
|
82
|
+
LOGGER.warning("Summary file not found: %s", summary_path)
|
|
83
|
+
return []
|
|
84
|
+
|
|
85
|
+
data, err = load_json_file(summary_path)
|
|
86
|
+
if err:
|
|
87
|
+
LOGGER.warning("Failed to read summary: %s", err)
|
|
88
|
+
return []
|
|
89
|
+
|
|
90
|
+
notes = data.get("completion_notes", [])
|
|
91
|
+
if not isinstance(notes, list):
|
|
92
|
+
LOGGER.warning("completion_notes is not a list in %s", summary_path)
|
|
93
|
+
return []
|
|
94
|
+
|
|
95
|
+
# Filter: only keep non-empty strings
|
|
96
|
+
return [n for n in notes if isinstance(n, str) and n.strip()]
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def patch_list(list_path, item_id, item_key, notes):
|
|
100
|
+
"""Patch completion_notes into a task list JSON file.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
list_path: Path to the JSON list file
|
|
104
|
+
item_id: ID of the item to patch (e.g. "F-001" or "R-001")
|
|
105
|
+
item_key: Key for the items array (e.g. "features" or "refactors")
|
|
106
|
+
notes: List of completion note strings
|
|
107
|
+
"""
|
|
108
|
+
data, err = load_json_file(list_path)
|
|
109
|
+
if err:
|
|
110
|
+
LOGGER.error("Failed to read list: %s", err)
|
|
111
|
+
return False
|
|
112
|
+
|
|
113
|
+
items = data.get(item_key, [])
|
|
114
|
+
found = False
|
|
115
|
+
for item in items:
|
|
116
|
+
if isinstance(item, dict) and item.get("id") == item_id:
|
|
117
|
+
item["completion_notes"] = notes
|
|
118
|
+
found = True
|
|
119
|
+
break
|
|
120
|
+
|
|
121
|
+
if not found:
|
|
122
|
+
LOGGER.error("Item %s not found in %s", item_id, list_path)
|
|
123
|
+
return False
|
|
124
|
+
|
|
125
|
+
err = write_json_file(list_path, data)
|
|
126
|
+
if err:
|
|
127
|
+
LOGGER.error("Failed to write list: %s", err)
|
|
128
|
+
return False
|
|
129
|
+
|
|
130
|
+
LOGGER.info(
|
|
131
|
+
"Patched %d completion notes for %s in %s",
|
|
132
|
+
len(notes), item_id, list_path,
|
|
133
|
+
)
|
|
134
|
+
return True
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def main():
|
|
138
|
+
args = parse_args()
|
|
139
|
+
|
|
140
|
+
# Determine mode: feature, refactor, or bug
|
|
141
|
+
if args.feature_list and args.feature_id:
|
|
142
|
+
list_path = args.feature_list
|
|
143
|
+
item_id = args.feature_id
|
|
144
|
+
item_key = "features"
|
|
145
|
+
elif args.refactor_list and args.refactor_id:
|
|
146
|
+
list_path = args.refactor_list
|
|
147
|
+
item_id = args.refactor_id
|
|
148
|
+
item_key = "refactors"
|
|
149
|
+
elif args.bug_list and args.bug_id:
|
|
150
|
+
list_path = args.bug_list
|
|
151
|
+
item_id = args.bug_id
|
|
152
|
+
item_key = "bugs"
|
|
153
|
+
else:
|
|
154
|
+
print(
|
|
155
|
+
"Error: must provide either (--feature-list + --feature-id) "
|
|
156
|
+
"or (--refactor-list + --refactor-id) "
|
|
157
|
+
"or (--bug-list + --bug-id)",
|
|
158
|
+
file=sys.stderr,
|
|
159
|
+
)
|
|
160
|
+
sys.exit(1)
|
|
161
|
+
|
|
162
|
+
# Read completion notes
|
|
163
|
+
notes = read_completion_notes(args.summary)
|
|
164
|
+
if not notes:
|
|
165
|
+
LOGGER.info("No completion notes to patch for %s", item_id)
|
|
166
|
+
sys.exit(0)
|
|
167
|
+
|
|
168
|
+
# Patch the list
|
|
169
|
+
if not patch_list(list_path, item_id, item_key, notes):
|
|
170
|
+
sys.exit(1)
|
|
171
|
+
|
|
172
|
+
# Output result
|
|
173
|
+
result = {
|
|
174
|
+
"item_id": item_id,
|
|
175
|
+
"notes_count": len(notes),
|
|
176
|
+
"list_path": os.path.abspath(list_path),
|
|
177
|
+
}
|
|
178
|
+
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
if __name__ == "__main__":
|
|
182
|
+
try:
|
|
183
|
+
main()
|
|
184
|
+
except KeyboardInterrupt:
|
|
185
|
+
sys.exit(130)
|
|
186
|
+
except SystemExit:
|
|
187
|
+
raise
|
|
188
|
+
except Exception as exc:
|
|
189
|
+
LOGGER.exception("Unhandled exception")
|
|
190
|
+
print("Error: {}".format(exc), file=sys.stderr)
|
|
191
|
+
sys.exit(1)
|