prizmkit 1.1.6 → 1.1.8
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/dev-pipeline/README.md +65 -65
- package/bundled/dev-pipeline/assets/feature-list-example.json +2 -2
- package/bundled/dev-pipeline/launch-bugfix-daemon.sh +11 -10
- package/bundled/dev-pipeline/launch-feature-daemon.sh +12 -11
- package/bundled/dev-pipeline/launch-refactor-daemon.sh +11 -10
- package/bundled/dev-pipeline/reset-bug.sh +305 -0
- 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 +7 -6
- package/bundled/dev-pipeline/retry-feature.sh +7 -6
- package/bundled/dev-pipeline/retry-refactor.sh +7 -6
- package/bundled/dev-pipeline/run-bugfix.sh +71 -23
- package/bundled/dev-pipeline/run-feature.sh +30 -21
- package/bundled/dev-pipeline/run-refactor.sh +21 -17
- package/bundled/dev-pipeline/scripts/cleanup-logs.py +2 -2
- package/bundled/dev-pipeline/scripts/detect-stuck.py +3 -3
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +26 -14
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +6 -6
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +6 -6
- package/bundled/dev-pipeline/scripts/init-bugfix-pipeline.py +4 -4
- package/bundled/dev-pipeline/scripts/init-pipeline.py +26 -12
- package/bundled/dev-pipeline/scripts/init-refactor-pipeline.py +4 -4
- package/bundled/dev-pipeline/scripts/update-bug-status.py +10 -10
- package/bundled/dev-pipeline/scripts/update-feature-status.py +31 -31
- package/bundled/dev-pipeline/scripts/update-refactor-status.py +8 -8
- package/bundled/dev-pipeline/templates/bug-fix-list-schema.json +111 -31
- package/bundled/dev-pipeline/templates/feature-list-schema.json +91 -25
- package/bundled/dev-pipeline/templates/refactor-list-schema.json +107 -28
- package/bundled/dev-pipeline/tests/test_auto_skip.py +1 -1
- package/bundled/skills/_metadata.json +10 -2
- package/bundled/skills/app-planner/SKILL.md +24 -13
- package/bundled/skills/app-planner/references/project-brief-guide.md +1 -1
- package/bundled/skills/bug-fix-workflow/SKILL.md +7 -5
- package/bundled/skills/bug-planner/SKILL.md +80 -25
- package/bundled/skills/bug-planner/scripts/validate-bug-list.py +3 -3
- package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +38 -33
- package/bundled/skills/feature-pipeline-launcher/SKILL.md +33 -33
- package/bundled/skills/feature-pipeline-launcher/scripts/preflight-check.py +3 -3
- package/bundled/skills/feature-planner/SKILL.md +96 -24
- package/bundled/skills/feature-planner/references/error-recovery.md +9 -9
- package/bundled/skills/feature-planner/scripts/validate-and-generate.py +25 -24
- package/bundled/skills/feature-workflow/SKILL.md +23 -20
- package/bundled/skills/prizmkit-committer/SKILL.md +1 -0
- package/bundled/skills/prizmkit-deploy/SKILL.md +1 -0
- package/bundled/skills/prizmkit-deploy/assets/deploy-template.md +1 -1
- package/bundled/skills/prizmkit-implement/SKILL.md +1 -1
- package/bundled/skills/prizmkit-implement/references/deploy-guide-protocol.md +4 -4
- package/bundled/skills/prizmkit-plan/SKILL.md +3 -3
- package/bundled/skills/prizmkit-retrospective/SKILL.md +40 -3
- package/bundled/skills/prizmkit-verify/SKILL.md +281 -0
- package/bundled/skills/prizmkit-verify/scripts/verify-light.py +402 -0
- package/bundled/skills/recovery-workflow/SKILL.md +15 -14
- 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 +38 -34
- package/bundled/skills/refactor-planner/SKILL.md +74 -24
- package/bundled/skills/refactor-planner/scripts/validate-and-generate-refactor.py +17 -17
- package/bundled/skills/refactor-workflow/SKILL.md +24 -20
- package/package.json +1 -1
- package/src/clean.js +4 -4
- package/src/gitignore-template.js +7 -8
- package/src/scaffold.js +4 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Generate a session-specific bug fix bootstrap prompt from template and bug-fix-list.json.
|
|
2
|
+
"""Generate a session-specific bug fix bootstrap prompt from template and .prizmkit/plans/bug-fix-list.json.
|
|
3
3
|
|
|
4
|
-
Reads the bugfix-bootstrap-prompt.md template and a bug-fix-list.json, resolves all
|
|
4
|
+
Reads the bugfix-bootstrap-prompt.md template and a .prizmkit/plans/bug-fix-list.json, resolves all
|
|
5
5
|
{{PLACEHOLDER}} variables, handles conditional blocks, and writes the rendered
|
|
6
6
|
prompt to the specified output path.
|
|
7
7
|
|
|
@@ -31,16 +31,16 @@ def parse_args():
|
|
|
31
31
|
parser = argparse.ArgumentParser(
|
|
32
32
|
description=(
|
|
33
33
|
"Generate a session-specific bug fix bootstrap prompt from a template "
|
|
34
|
-
"and bug-fix-list.json."
|
|
34
|
+
"and .prizmkit/plans/bug-fix-list.json."
|
|
35
35
|
)
|
|
36
36
|
)
|
|
37
|
-
parser.add_argument("--bug-list", required=True, help="Path to bug-fix-list.json")
|
|
37
|
+
parser.add_argument("--bug-list", required=True, help="Path to .prizmkit/plans/bug-fix-list.json")
|
|
38
38
|
parser.add_argument("--bug-id", required=True, help="Bug ID to generate prompt for (e.g. B-001)")
|
|
39
39
|
parser.add_argument("--session-id", required=True, help="Session ID for this pipeline session")
|
|
40
40
|
parser.add_argument("--run-id", required=True, help="Pipeline run ID")
|
|
41
41
|
parser.add_argument("--retry-count", required=True, help="Current retry count")
|
|
42
42
|
parser.add_argument("--resume-phase", required=True, help='Phase to resume from, or "null" for fresh start')
|
|
43
|
-
parser.add_argument("--state-dir", default=None, help="State directory
|
|
43
|
+
parser.add_argument("--state-dir", default=None, help="State directory (default: .prizmkit/state/bugfix)")
|
|
44
44
|
parser.add_argument("--output", required=True, help="Output path for the rendered prompt")
|
|
45
45
|
parser.add_argument("--template", default=None, help="Custom template path. Defaults to {script_dir}/../templates/bugfix-bootstrap-prompt.md")
|
|
46
46
|
return parser.parse_args()
|
|
@@ -217,7 +217,7 @@ def build_replacements(args, bug, global_context, script_dir):
|
|
|
217
217
|
|
|
218
218
|
# Session status path
|
|
219
219
|
session_status_path = os.path.join(
|
|
220
|
-
project_root, "
|
|
220
|
+
project_root, ".prizmkit", "state", "bugfix", "bugs", args.bug_id,
|
|
221
221
|
"sessions", args.session_id, "session-status.json"
|
|
222
222
|
)
|
|
223
223
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Generate a session-specific refactor bootstrap prompt from template and refactor-list.json.
|
|
2
|
+
"""Generate a session-specific refactor bootstrap prompt from template and .prizmkit/plans/refactor-list.json.
|
|
3
3
|
|
|
4
|
-
Reads the refactor-bootstrap-prompt.md template and a refactor-list.json, resolves all
|
|
4
|
+
Reads the refactor-bootstrap-prompt.md template and a .prizmkit/plans/refactor-list.json, resolves all
|
|
5
5
|
{{PLACEHOLDER}} variables, handles conditional blocks, and writes the rendered
|
|
6
6
|
prompt to the specified output path.
|
|
7
7
|
|
|
@@ -30,16 +30,16 @@ def parse_args():
|
|
|
30
30
|
parser = argparse.ArgumentParser(
|
|
31
31
|
description=(
|
|
32
32
|
"Generate a session-specific refactor bootstrap prompt from a template "
|
|
33
|
-
"and refactor-list.json."
|
|
33
|
+
"and .prizmkit/plans/refactor-list.json."
|
|
34
34
|
)
|
|
35
35
|
)
|
|
36
|
-
parser.add_argument("--refactor-list", required=True, help="Path to refactor-list.json")
|
|
36
|
+
parser.add_argument("--refactor-list", required=True, help="Path to .prizmkit/plans/refactor-list.json")
|
|
37
37
|
parser.add_argument("--refactor-id", required=True, help="Refactor ID to generate prompt for (e.g. R-001)")
|
|
38
38
|
parser.add_argument("--session-id", required=True, help="Session ID for this pipeline session")
|
|
39
39
|
parser.add_argument("--run-id", required=True, help="Pipeline run ID")
|
|
40
40
|
parser.add_argument("--retry-count", required=True, help="Current retry count")
|
|
41
41
|
parser.add_argument("--resume-phase", required=True, help='Phase to resume from, or "null" for fresh start')
|
|
42
|
-
parser.add_argument("--state-dir", default=None, help="State directory
|
|
42
|
+
parser.add_argument("--state-dir", default=None, help="State directory (default: .prizmkit/state/refactor)")
|
|
43
43
|
parser.add_argument("--output", required=True, help="Output path for the rendered prompt")
|
|
44
44
|
parser.add_argument("--template", default=None, help="Custom template path. Defaults to {script_dir}/../templates/refactor-bootstrap-prompt.md")
|
|
45
45
|
return parser.parse_args()
|
|
@@ -247,7 +247,7 @@ def build_replacements(args, refactor, global_context, script_dir):
|
|
|
247
247
|
|
|
248
248
|
# Session status path
|
|
249
249
|
session_status_path = os.path.join(
|
|
250
|
-
project_root, "
|
|
250
|
+
project_root, ".prizmkit", "state", "refactor", "refactors", args.refactor_id,
|
|
251
251
|
"sessions", args.session_id, "session-status.json"
|
|
252
252
|
)
|
|
253
253
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Initialize the bug-fix pipeline state directory from a bug-fix-list.json file.
|
|
2
|
+
"""Initialize the bug-fix pipeline state directory from a .prizmkit/plans/bug-fix-list.json file.
|
|
3
3
|
|
|
4
4
|
Validates the bug fix list schema, sorts by priority/severity, and creates
|
|
5
5
|
the state directory structure with pipeline and per-bug status files.
|
|
@@ -40,17 +40,17 @@ VALID_STATUSES = [
|
|
|
40
40
|
|
|
41
41
|
def parse_args():
|
|
42
42
|
parser = argparse.ArgumentParser(
|
|
43
|
-
description="Initialize bug-fix pipeline state from a bug-fix-list.json file."
|
|
43
|
+
description="Initialize bug-fix pipeline state from a .prizmkit/plans/bug-fix-list.json file."
|
|
44
44
|
)
|
|
45
45
|
parser.add_argument(
|
|
46
46
|
"--bug-list",
|
|
47
47
|
required=True,
|
|
48
|
-
help="Path to the bug-fix-list.json file",
|
|
48
|
+
help="Path to the .prizmkit/plans/bug-fix-list.json file",
|
|
49
49
|
)
|
|
50
50
|
parser.add_argument(
|
|
51
51
|
"--state-dir",
|
|
52
52
|
required=True,
|
|
53
|
-
help="Path to the state directory
|
|
53
|
+
help="Path to the state directory (default: .prizmkit/state/bugfix)",
|
|
54
54
|
)
|
|
55
55
|
return parser.parse_args()
|
|
56
56
|
|
|
@@ -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.
|
|
@@ -20,6 +20,7 @@ from datetime import datetime, timezone
|
|
|
20
20
|
EXPECTED_SCHEMA = "dev-pipeline-feature-list-v1"
|
|
21
21
|
FEATURE_ID_PATTERN = re.compile(r"^F-\d{3}$")
|
|
22
22
|
TERMINAL_STATUSES = {"completed", "failed", "skipped"}
|
|
23
|
+
VALID_PRIORITIES = {"critical", "high", "medium", "low"}
|
|
23
24
|
|
|
24
25
|
REQUIRED_FEATURE_FIELDS = [
|
|
25
26
|
"id",
|
|
@@ -34,17 +35,17 @@ REQUIRED_FEATURE_FIELDS = [
|
|
|
34
35
|
|
|
35
36
|
def parse_args():
|
|
36
37
|
parser = argparse.ArgumentParser(
|
|
37
|
-
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."
|
|
38
39
|
)
|
|
39
40
|
parser.add_argument(
|
|
40
41
|
"--feature-list",
|
|
41
42
|
required=True,
|
|
42
|
-
help="Path to the feature-list.json file",
|
|
43
|
+
help="Path to the .prizmkit/plans/feature-list.json file",
|
|
43
44
|
)
|
|
44
45
|
parser.add_argument(
|
|
45
46
|
"--state-dir",
|
|
46
47
|
required=True,
|
|
47
|
-
help="Path to the state directory
|
|
48
|
+
help="Path to the state directory (default: .prizmkit/state/features)",
|
|
48
49
|
)
|
|
49
50
|
return parser.parse_args()
|
|
50
51
|
|
|
@@ -75,11 +76,12 @@ def validate_schema(data):
|
|
|
75
76
|
"Invalid $schema: expected '{}', got '{}'".format(EXPECTED_SCHEMA, schema)
|
|
76
77
|
)
|
|
77
78
|
|
|
78
|
-
# Check app_name
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
# Check project_name (supports legacy app_name for backward compatibility)
|
|
80
|
+
project_name = data.get("project_name", data.get("app_name"))
|
|
81
|
+
if project_name is None:
|
|
82
|
+
errors.append("Missing required field: project_name")
|
|
83
|
+
elif not isinstance(project_name, str) or not project_name.strip():
|
|
84
|
+
errors.append("project_name must be a non-empty string")
|
|
83
85
|
|
|
84
86
|
# Check features array
|
|
85
87
|
if "features" not in data:
|
|
@@ -132,6 +134,18 @@ def validate_features(features):
|
|
|
132
134
|
)
|
|
133
135
|
)
|
|
134
136
|
|
|
137
|
+
# Validate priority enum
|
|
138
|
+
priority = feature.get("priority")
|
|
139
|
+
if priority is not None and priority not in VALID_PRIORITIES:
|
|
140
|
+
errors.append(
|
|
141
|
+
"Feature '{}' has invalid priority '{}' "
|
|
142
|
+
"(must be one of: {})".format(
|
|
143
|
+
fid if fid else "index {}".format(i),
|
|
144
|
+
priority,
|
|
145
|
+
", ".join(sorted(VALID_PRIORITIES)),
|
|
146
|
+
)
|
|
147
|
+
)
|
|
148
|
+
|
|
135
149
|
# Validate acceptance_criteria is a list
|
|
136
150
|
ac = feature.get("acceptance_criteria")
|
|
137
151
|
if ac is not None and not isinstance(ac, list):
|
|
@@ -269,7 +283,7 @@ def create_state_directory(state_dir, feature_list_path, features):
|
|
|
269
283
|
sessions_dir = os.path.join(feature_dir, "sessions")
|
|
270
284
|
os.makedirs(sessions_dir, exist_ok=True)
|
|
271
285
|
|
|
272
|
-
# Respect existing terminal status from feature-list.json
|
|
286
|
+
# Respect existing terminal status from .prizmkit/plans/feature-list.json
|
|
273
287
|
fl_status = feature.get("status", "pending")
|
|
274
288
|
init_status = fl_status if fl_status in TERMINAL_STATUSES else "pending"
|
|
275
289
|
|
|
@@ -302,13 +316,13 @@ def main():
|
|
|
302
316
|
print(json.dumps(output, indent=2, ensure_ascii=False))
|
|
303
317
|
sys.exit(1)
|
|
304
318
|
|
|
305
|
-
# Warn if feature-list.json is not at project root
|
|
319
|
+
# Warn if .prizmkit/plans/feature-list.json is not at project root
|
|
306
320
|
feature_list_dir = os.path.dirname(os.path.abspath(args.feature_list))
|
|
307
321
|
indicators = ['.git', 'package.json', '.prizmkit']
|
|
308
322
|
is_at_root = any(os.path.exists(os.path.join(feature_list_dir, i)) for i in indicators)
|
|
309
323
|
if not is_at_root:
|
|
310
324
|
sys.stderr.write(
|
|
311
|
-
"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)
|
|
312
326
|
)
|
|
313
327
|
|
|
314
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
|
|
@@ -47,17 +47,17 @@ VALID_BEHAVIOR_STRATEGIES = ["test-gate", "snapshot", "manual"]
|
|
|
47
47
|
|
|
48
48
|
def parse_args():
|
|
49
49
|
parser = argparse.ArgumentParser(
|
|
50
|
-
description="Initialize refactor pipeline state from a refactor-list.json file."
|
|
50
|
+
description="Initialize refactor pipeline state from a .prizmkit/plans/refactor-list.json file."
|
|
51
51
|
)
|
|
52
52
|
parser.add_argument(
|
|
53
53
|
"--refactor-list",
|
|
54
54
|
required=True,
|
|
55
|
-
help="Path to the refactor-list.json file",
|
|
55
|
+
help="Path to the .prizmkit/plans/refactor-list.json file",
|
|
56
56
|
)
|
|
57
57
|
parser.add_argument(
|
|
58
58
|
"--state-dir",
|
|
59
59
|
required=True,
|
|
60
|
-
help="Path to the state directory
|
|
60
|
+
help="Path to the state directory (default: .prizmkit/state/refactor)",
|
|
61
61
|
)
|
|
62
62
|
return parser.parse_args()
|
|
63
63
|
|
|
@@ -57,8 +57,8 @@ def parse_args():
|
|
|
57
57
|
parser = argparse.ArgumentParser(
|
|
58
58
|
description="Core state machine for bug-fix pipeline bug status management."
|
|
59
59
|
)
|
|
60
|
-
parser.add_argument("--bug-list", required=True, help="Path to the bug-fix-list.json file")
|
|
61
|
-
parser.add_argument("--state-dir", required=True, help="Path to the
|
|
60
|
+
parser.add_argument("--bug-list", required=True, help="Path to the .prizmkit/plans/bug-fix-list.json file")
|
|
61
|
+
parser.add_argument("--state-dir", required=True, help="Path to the state directory (default: .prizmkit/state/bugfix)")
|
|
62
62
|
parser.add_argument(
|
|
63
63
|
"--action", required=True,
|
|
64
64
|
choices=["get_next", "update", "status", "pause", "reset", "clean"],
|
|
@@ -128,7 +128,7 @@ def update_bug_in_list(bug_list_path, bug_id, new_status):
|
|
|
128
128
|
found = True
|
|
129
129
|
break
|
|
130
130
|
if not found:
|
|
131
|
-
return "Bug '{}' not found in bug-fix-list.json".format(bug_id)
|
|
131
|
+
return "Bug '{}' not found in .prizmkit/plans/bug-fix-list.json".format(bug_id)
|
|
132
132
|
return write_json_file(bug_list_path, data)
|
|
133
133
|
|
|
134
134
|
|
|
@@ -183,12 +183,12 @@ def action_get_next(bug_list_data, state_dir):
|
|
|
183
183
|
elif bstatus == "pending":
|
|
184
184
|
pending_bugs.append(bug)
|
|
185
185
|
|
|
186
|
-
_PRIORITY_ORDER = {"
|
|
186
|
+
_PRIORITY_ORDER = {"critical": 0, "high": 1, "medium": 2, "low": 3}
|
|
187
187
|
|
|
188
188
|
def sort_key(b):
|
|
189
189
|
severity = b.get("severity", "medium")
|
|
190
190
|
sev_order = SEVERITY_PRIORITY.get(severity, 2)
|
|
191
|
-
priority = _PRIORITY_ORDER.get(b.get("priority", "low"),
|
|
191
|
+
priority = _PRIORITY_ORDER.get(b.get("priority", "low"), 3)
|
|
192
192
|
return (sev_order, priority)
|
|
193
193
|
|
|
194
194
|
if in_progress_bugs:
|
|
@@ -238,7 +238,7 @@ def action_update(args, bug_list_path, state_dir):
|
|
|
238
238
|
bs["resume_from_phase"] = None
|
|
239
239
|
err = update_bug_in_list(bug_list_path, bug_id, "completed")
|
|
240
240
|
if err:
|
|
241
|
-
error_out("Failed to update bug-fix-list.json: {}".format(err))
|
|
241
|
+
error_out("Failed to update .prizmkit/plans/bug-fix-list.json: {}".format(err))
|
|
242
242
|
return
|
|
243
243
|
elif session_status == "merge_conflict":
|
|
244
244
|
# Degraded outcome: keep artifacts for retry (branch preserves work)
|
|
@@ -257,7 +257,7 @@ def action_update(args, bug_list_path, state_dir):
|
|
|
257
257
|
|
|
258
258
|
err = update_bug_in_list(bug_list_path, bug_id, target_status)
|
|
259
259
|
if err:
|
|
260
|
-
error_out("Failed to update bug-fix-list.json: {}".format(err))
|
|
260
|
+
error_out("Failed to update .prizmkit/plans/bug-fix-list.json: {}".format(err))
|
|
261
261
|
return
|
|
262
262
|
else:
|
|
263
263
|
bs["retry_count"] = bs.get("retry_count", 0) + 1
|
|
@@ -281,7 +281,7 @@ def action_update(args, bug_list_path, state_dir):
|
|
|
281
281
|
|
|
282
282
|
err = update_bug_in_list(bug_list_path, bug_id, target_status)
|
|
283
283
|
if err:
|
|
284
|
-
error_out("Failed to update bug-fix-list.json: {}".format(err))
|
|
284
|
+
error_out("Failed to update .prizmkit/plans/bug-fix-list.json: {}".format(err))
|
|
285
285
|
return
|
|
286
286
|
|
|
287
287
|
if session_status == "success" and session_id:
|
|
@@ -544,7 +544,7 @@ def action_reset(args, bug_list_path, state_dir):
|
|
|
544
544
|
|
|
545
545
|
err = update_bug_in_list(bug_list_path, bug_id, "pending")
|
|
546
546
|
if err:
|
|
547
|
-
error_out("Failed to update bug-fix-list.json: {}".format(err))
|
|
547
|
+
error_out("Failed to update .prizmkit/plans/bug-fix-list.json: {}".format(err))
|
|
548
548
|
return
|
|
549
549
|
|
|
550
550
|
result = {
|
|
@@ -620,7 +620,7 @@ def action_clean(args, bug_list_path, state_dir):
|
|
|
620
620
|
|
|
621
621
|
err = update_bug_in_list(bug_list_path, bug_id, "pending")
|
|
622
622
|
if err:
|
|
623
|
-
error_out("Failed to update bug-fix-list.json: {}".format(err))
|
|
623
|
+
error_out("Failed to update .prizmkit/plans/bug-fix-list.json: {}".format(err))
|
|
624
624
|
return
|
|
625
625
|
|
|
626
626
|
result = {
|
|
@@ -60,12 +60,12 @@ def parse_args():
|
|
|
60
60
|
parser.add_argument(
|
|
61
61
|
"--feature-list",
|
|
62
62
|
required=True,
|
|
63
|
-
help="Path to the feature-list.json file",
|
|
63
|
+
help="Path to the .prizmkit/plans/feature-list.json file",
|
|
64
64
|
)
|
|
65
65
|
parser.add_argument(
|
|
66
66
|
"--state-dir",
|
|
67
67
|
required=True,
|
|
68
|
-
help="Path to the state
|
|
68
|
+
help="Path to the state directory (default: .prizmkit/state/features)",
|
|
69
69
|
)
|
|
70
70
|
parser.add_argument(
|
|
71
71
|
"--action",
|
|
@@ -159,7 +159,7 @@ def load_feature_status(state_dir, feature_id, feature_list_status=None):
|
|
|
159
159
|
If the file does not exist, return a default pending status.
|
|
160
160
|
|
|
161
161
|
If feature_list_status is a terminal status (completed, failed, skipped),
|
|
162
|
-
it overrides the status field from status.json. This makes feature-list.json
|
|
162
|
+
it overrides the status field from status.json. This makes .prizmkit/plans/feature-list.json
|
|
163
163
|
the single source of truth for terminal statuses, while all other fields
|
|
164
164
|
(retry_count, sessions, etc.) still come from status.json.
|
|
165
165
|
"""
|
|
@@ -195,7 +195,7 @@ def load_feature_status(state_dir, feature_id, feature_list_status=None):
|
|
|
195
195
|
"created_at": now,
|
|
196
196
|
"updated_at": now,
|
|
197
197
|
}
|
|
198
|
-
# feature-list.json wins for terminal statuses
|
|
198
|
+
# .prizmkit/plans/feature-list.json wins for terminal statuses
|
|
199
199
|
if feature_list_status in TERMINAL_STATUSES:
|
|
200
200
|
data["status"] = feature_list_status
|
|
201
201
|
return data
|
|
@@ -210,7 +210,7 @@ def save_feature_status(state_dir, feature_id, status_data):
|
|
|
210
210
|
|
|
211
211
|
|
|
212
212
|
def update_feature_in_list(feature_list_path, feature_id, new_status):
|
|
213
|
-
"""Update a feature's status field in feature-list.json.
|
|
213
|
+
"""Update a feature's status field in .prizmkit/plans/feature-list.json.
|
|
214
214
|
|
|
215
215
|
Reads the whole file, modifies the target feature's status, writes back.
|
|
216
216
|
Returns an error string on failure, None on success.
|
|
@@ -226,7 +226,7 @@ def update_feature_in_list(feature_list_path, feature_id, new_status):
|
|
|
226
226
|
found = True
|
|
227
227
|
break
|
|
228
228
|
if not found:
|
|
229
|
-
return "Feature '{}' not found in feature-list.json".format(feature_id)
|
|
229
|
+
return "Feature '{}' not found in .prizmkit/plans/feature-list.json".format(feature_id)
|
|
230
230
|
return write_json_file(feature_list_path, data)
|
|
231
231
|
|
|
232
232
|
|
|
@@ -336,13 +336,13 @@ def auto_skip_blocked_features(feature_list_path, state_dir, failed_feature_id):
|
|
|
336
336
|
by marking those blocked features as auto_skipped, allowing the pipeline to
|
|
337
337
|
continue processing unblocked features and eventually reach PIPELINE_COMPLETE.
|
|
338
338
|
|
|
339
|
-
Re-reads feature-list.json from disk to get the latest state (including the
|
|
339
|
+
Re-reads .prizmkit/plans/feature-list.json from disk to get the latest state (including the
|
|
340
340
|
just-written failed status from update_feature_in_list).
|
|
341
341
|
|
|
342
|
-
NOTE: This function performs a read-modify-write on feature-list.json without
|
|
343
|
-
file locking. The caller (action_update) also writes to feature-list.json
|
|
342
|
+
NOTE: This function performs a read-modify-write on .prizmkit/plans/feature-list.json without
|
|
343
|
+
file locking. The caller (action_update) also writes to .prizmkit/plans/feature-list.json
|
|
344
344
|
immediately before calling this. Safe for single-pipeline execution, but if
|
|
345
|
-
multiple pipeline instances share the same feature-list.json concurrently,
|
|
345
|
+
multiple pipeline instances share the same .prizmkit/plans/feature-list.json concurrently,
|
|
346
346
|
a race condition may cause lost writes. Add file locking if parallel pipelines
|
|
347
347
|
are introduced.
|
|
348
348
|
"""
|
|
@@ -383,7 +383,7 @@ def auto_skip_blocked_features(feature_list_path, state_dir, failed_feature_id):
|
|
|
383
383
|
if not to_skip:
|
|
384
384
|
return []
|
|
385
385
|
|
|
386
|
-
# Batch-write to feature-list.json
|
|
386
|
+
# Batch-write to .prizmkit/plans/feature-list.json
|
|
387
387
|
for f in features:
|
|
388
388
|
if isinstance(f, dict) and f.get("id") in to_skip:
|
|
389
389
|
f["status"] = "auto_skipped"
|
|
@@ -524,19 +524,19 @@ def action_get_next(feature_list_data, state_dir, feature_filter=None):
|
|
|
524
524
|
else:
|
|
525
525
|
pending_features.append(feature)
|
|
526
526
|
|
|
527
|
-
# Priority mapping: string enum → sort order (
|
|
528
|
-
_PRIORITY_ORDER = {"
|
|
527
|
+
# Priority mapping: string enum → sort order (critical first)
|
|
528
|
+
_PRIORITY_ORDER = {"critical": 0, "high": 1, "medium": 2, "low": 3}
|
|
529
529
|
|
|
530
530
|
# Prefer in_progress features, then pending; sort by priority (high > medium > low)
|
|
531
531
|
if in_progress_features:
|
|
532
532
|
candidates = sorted(
|
|
533
533
|
in_progress_features,
|
|
534
|
-
key=lambda f: _PRIORITY_ORDER.get(f.get("priority", "low"),
|
|
534
|
+
key=lambda f: _PRIORITY_ORDER.get(f.get("priority", "low"), 3)
|
|
535
535
|
)
|
|
536
536
|
else:
|
|
537
537
|
candidates = sorted(
|
|
538
538
|
pending_features,
|
|
539
|
-
key=lambda f: _PRIORITY_ORDER.get(f.get("priority", "low"),
|
|
539
|
+
key=lambda f: _PRIORITY_ORDER.get(f.get("priority", "low"), 3)
|
|
540
540
|
)
|
|
541
541
|
|
|
542
542
|
chosen = candidates[0]
|
|
@@ -605,7 +605,7 @@ def action_update(args, feature_list_path, state_dir):
|
|
|
605
605
|
fs["resume_from_phase"] = None
|
|
606
606
|
err = update_feature_in_list(feature_list_path, feature_id, "completed")
|
|
607
607
|
if err:
|
|
608
|
-
error_out("Failed to update feature-list.json: {}".format(err))
|
|
608
|
+
error_out("Failed to update .prizmkit/plans/feature-list.json: {}".format(err))
|
|
609
609
|
return
|
|
610
610
|
elif session_status in ("commit_missing", "docs_missing", "merge_conflict"):
|
|
611
611
|
# Degraded outcome: keep artifacts for retry and expose specific status.
|
|
@@ -624,7 +624,7 @@ def action_update(args, feature_list_path, state_dir):
|
|
|
624
624
|
|
|
625
625
|
err = update_feature_in_list(feature_list_path, feature_id, target_status)
|
|
626
626
|
if err:
|
|
627
|
-
error_out("Failed to update feature-list.json: {}".format(err))
|
|
627
|
+
error_out("Failed to update .prizmkit/plans/feature-list.json: {}".format(err))
|
|
628
628
|
return
|
|
629
629
|
else:
|
|
630
630
|
# crashed / failed / timed_out — preserve all artifacts for debugging.
|
|
@@ -646,7 +646,7 @@ def action_update(args, feature_list_path, state_dir):
|
|
|
646
646
|
|
|
647
647
|
err = update_feature_in_list(feature_list_path, feature_id, target_status)
|
|
648
648
|
if err:
|
|
649
|
-
error_out("Failed to update feature-list.json: {}".format(err))
|
|
649
|
+
error_out("Failed to update .prizmkit/plans/feature-list.json: {}".format(err))
|
|
650
650
|
return
|
|
651
651
|
|
|
652
652
|
if session_status == "success" and session_id:
|
|
@@ -860,12 +860,12 @@ def _estimate_remaining_time(features, state_dir, counts, feature_list_data=None
|
|
|
860
860
|
def action_status(feature_list_data, state_dir, feature_filter=None):
|
|
861
861
|
"""Print a formatted overview of all features and their status.
|
|
862
862
|
|
|
863
|
-
Status is read exclusively from feature-list.json (the single source of
|
|
863
|
+
Status is read exclusively from .prizmkit/plans/feature-list.json (the single source of
|
|
864
864
|
truth). state_dir is only used for ETA estimation when session history
|
|
865
865
|
is available.
|
|
866
866
|
"""
|
|
867
867
|
features = feature_list_data.get("features", [])
|
|
868
|
-
app_name = feature_list_data.get("app_name", "Unknown")
|
|
868
|
+
app_name = feature_list_data.get("project_name", feature_list_data.get("app_name", "Unknown"))
|
|
869
869
|
|
|
870
870
|
# Apply feature filter
|
|
871
871
|
if feature_filter is not None:
|
|
@@ -887,7 +887,7 @@ def action_status(feature_list_data, state_dir, feature_filter=None):
|
|
|
887
887
|
}
|
|
888
888
|
feature_lines = []
|
|
889
889
|
|
|
890
|
-
# Build status map from feature-list.json only
|
|
890
|
+
# Build status map from .prizmkit/plans/feature-list.json only
|
|
891
891
|
status_map = {}
|
|
892
892
|
for feature in features:
|
|
893
893
|
if not isinstance(feature, dict):
|
|
@@ -1018,7 +1018,7 @@ def action_status(feature_list_data, state_dir, feature_filter=None):
|
|
|
1018
1018
|
print("╔" + "═" * BOX_WIDTH + "╗")
|
|
1019
1019
|
print("║" + pad_right(COLOR_BOLD + " Dev-Pipeline Status" + COLOR_RESET, inner) + " ║")
|
|
1020
1020
|
print("╠" + "═" * BOX_WIDTH + "╣")
|
|
1021
|
-
print("║" + pad_right("
|
|
1021
|
+
print("║" + pad_right(" Project: {}".format(app_name), inner) + " ║")
|
|
1022
1022
|
print("║" + pad_right(" {}".format(summary_line), inner) + " ║")
|
|
1023
1023
|
print("║" + pad_right(" {}".format(summary_line2), inner) + " ║")
|
|
1024
1024
|
print("║" + pad_right(" {}".format(summary_line3), inner) + " ║")
|
|
@@ -1038,7 +1038,7 @@ def action_status(feature_list_data, state_dir, feature_filter=None):
|
|
|
1038
1038
|
def action_start(args, feature_list_path, state_dir):
|
|
1039
1039
|
"""Mark a feature as in_progress at session start.
|
|
1040
1040
|
|
|
1041
|
-
This keeps feature-list.json/state status in sync during execution,
|
|
1041
|
+
This keeps .prizmkit/plans/feature-list.json/state status in sync during execution,
|
|
1042
1042
|
instead of only updating after session end.
|
|
1043
1043
|
"""
|
|
1044
1044
|
feature_id = args.feature_id
|
|
@@ -1059,7 +1059,7 @@ def action_start(args, feature_list_path, state_dir):
|
|
|
1059
1059
|
|
|
1060
1060
|
err = update_feature_in_list(feature_list_path, feature_id, "in_progress")
|
|
1061
1061
|
if err:
|
|
1062
|
-
error_out("Failed to update feature-list.json: {}".format(err))
|
|
1062
|
+
error_out("Failed to update .prizmkit/plans/feature-list.json: {}".format(err))
|
|
1063
1063
|
return
|
|
1064
1064
|
|
|
1065
1065
|
result = {
|
|
@@ -1080,7 +1080,7 @@ def action_reset(args, feature_list_path, state_dir):
|
|
|
1080
1080
|
"""Reset a feature to pending state.
|
|
1081
1081
|
|
|
1082
1082
|
Resets status.json (status -> pending, retry_count -> 0, clear sessions,
|
|
1083
|
-
clear resume_from_phase) and updates feature-list.json status to pending.
|
|
1083
|
+
clear resume_from_phase) and updates .prizmkit/plans/feature-list.json status to pending.
|
|
1084
1084
|
Does NOT delete any files on disk.
|
|
1085
1085
|
"""
|
|
1086
1086
|
feature_id = args.feature_id
|
|
@@ -1107,10 +1107,10 @@ def action_reset(args, feature_list_path, state_dir):
|
|
|
1107
1107
|
error_out("Failed to save feature status: {}".format(err))
|
|
1108
1108
|
return
|
|
1109
1109
|
|
|
1110
|
-
# Update feature-list.json
|
|
1110
|
+
# Update .prizmkit/plans/feature-list.json
|
|
1111
1111
|
err = update_feature_in_list(feature_list_path, feature_id, "pending")
|
|
1112
1112
|
if err:
|
|
1113
|
-
error_out("Failed to update feature-list.json: {}".format(err))
|
|
1113
|
+
error_out("Failed to update .prizmkit/plans/feature-list.json: {}".format(err))
|
|
1114
1114
|
return
|
|
1115
1115
|
|
|
1116
1116
|
result = {
|
|
@@ -1202,7 +1202,7 @@ def action_clean(args, feature_list_path, state_dir):
|
|
|
1202
1202
|
|
|
1203
1203
|
err = update_feature_in_list(feature_list_path, feature_id, "pending")
|
|
1204
1204
|
if err:
|
|
1205
|
-
error_out("Failed to update feature-list.json: {}".format(err))
|
|
1205
|
+
error_out("Failed to update .prizmkit/plans/feature-list.json: {}".format(err))
|
|
1206
1206
|
return
|
|
1207
1207
|
|
|
1208
1208
|
result = {
|
|
@@ -1248,7 +1248,7 @@ def action_unskip(args, feature_list_path, state_dir):
|
|
|
1248
1248
|
target = f
|
|
1249
1249
|
break
|
|
1250
1250
|
if not target:
|
|
1251
|
-
error_out("Feature '{}' not found in feature-list.json".format(feature_id))
|
|
1251
|
+
error_out("Feature '{}' not found in .prizmkit/plans/feature-list.json".format(feature_id))
|
|
1252
1252
|
return
|
|
1253
1253
|
if target.get("status") not in ("failed", "skipped", "auto_skipped"):
|
|
1254
1254
|
error_out(
|
|
@@ -1328,7 +1328,7 @@ def action_unskip(args, feature_list_path, state_dir):
|
|
|
1328
1328
|
error_out("No features to unskip")
|
|
1329
1329
|
return
|
|
1330
1330
|
|
|
1331
|
-
# Reset all collected features in feature-list.json
|
|
1331
|
+
# Reset all collected features in .prizmkit/plans/feature-list.json
|
|
1332
1332
|
reset_details = []
|
|
1333
1333
|
for f in features:
|
|
1334
1334
|
if isinstance(f, dict) and f.get("id") in to_reset:
|
|
@@ -1342,7 +1342,7 @@ def action_unskip(args, feature_list_path, state_dir):
|
|
|
1342
1342
|
|
|
1343
1343
|
err = write_json_file(feature_list_path, data)
|
|
1344
1344
|
if err:
|
|
1345
|
-
error_out("Failed to write feature-list.json: {}".format(err))
|
|
1345
|
+
error_out("Failed to write .prizmkit/plans/feature-list.json: {}".format(err))
|
|
1346
1346
|
return
|
|
1347
1347
|
|
|
1348
1348
|
# Reset status.json for each feature
|
|
@@ -68,8 +68,8 @@ def parse_args():
|
|
|
68
68
|
parser = argparse.ArgumentParser(
|
|
69
69
|
description="Core state machine for refactor pipeline status management."
|
|
70
70
|
)
|
|
71
|
-
parser.add_argument("--refactor-list", required=True, help="Path to the refactor-list.json file")
|
|
72
|
-
parser.add_argument("--state-dir", required=True, help="Path to the
|
|
71
|
+
parser.add_argument("--refactor-list", required=True, help="Path to the .prizmkit/plans/refactor-list.json file")
|
|
72
|
+
parser.add_argument("--state-dir", required=True, help="Path to the state directory (default: .prizmkit/state/refactor)")
|
|
73
73
|
parser.add_argument(
|
|
74
74
|
"--action", required=True,
|
|
75
75
|
choices=["get_next", "update", "status", "pause", "reset", "clean"],
|
|
@@ -133,7 +133,7 @@ def update_refactor_in_list(refactor_list_path, refactor_id, new_status):
|
|
|
133
133
|
found = True
|
|
134
134
|
break
|
|
135
135
|
if not found:
|
|
136
|
-
return "Refactor '{}' not found in refactor-list.json".format(refactor_id)
|
|
136
|
+
return "Refactor '{}' not found in .prizmkit/plans/refactor-list.json".format(refactor_id)
|
|
137
137
|
return write_json_file(refactor_list_path, data)
|
|
138
138
|
|
|
139
139
|
|
|
@@ -270,7 +270,7 @@ def action_update(args, refactor_list_path, state_dir):
|
|
|
270
270
|
rs["resume_from_phase"] = None
|
|
271
271
|
err = update_refactor_in_list(refactor_list_path, refactor_id, "completed")
|
|
272
272
|
if err:
|
|
273
|
-
error_out("Failed to update refactor-list.json: {}".format(err))
|
|
273
|
+
error_out("Failed to update .prizmkit/plans/refactor-list.json: {}".format(err))
|
|
274
274
|
return
|
|
275
275
|
elif session_status == "merge_conflict":
|
|
276
276
|
rs["retry_count"] = rs.get("retry_count", 0) + 1
|
|
@@ -288,7 +288,7 @@ def action_update(args, refactor_list_path, state_dir):
|
|
|
288
288
|
|
|
289
289
|
err = update_refactor_in_list(refactor_list_path, refactor_id, target_status)
|
|
290
290
|
if err:
|
|
291
|
-
error_out("Failed to update refactor-list.json: {}".format(err))
|
|
291
|
+
error_out("Failed to update .prizmkit/plans/refactor-list.json: {}".format(err))
|
|
292
292
|
return
|
|
293
293
|
else:
|
|
294
294
|
rs["retry_count"] = rs.get("retry_count", 0) + 1
|
|
@@ -312,7 +312,7 @@ def action_update(args, refactor_list_path, state_dir):
|
|
|
312
312
|
|
|
313
313
|
err = update_refactor_in_list(refactor_list_path, refactor_id, target_status)
|
|
314
314
|
if err:
|
|
315
|
-
error_out("Failed to update refactor-list.json: {}".format(err))
|
|
315
|
+
error_out("Failed to update .prizmkit/plans/refactor-list.json: {}".format(err))
|
|
316
316
|
return
|
|
317
317
|
|
|
318
318
|
if session_status == "success" and session_id:
|
|
@@ -572,7 +572,7 @@ def action_reset(args, refactor_list_path, state_dir):
|
|
|
572
572
|
|
|
573
573
|
err = update_refactor_in_list(refactor_list_path, refactor_id, "pending")
|
|
574
574
|
if err:
|
|
575
|
-
error_out("Failed to update refactor-list.json: {}".format(err))
|
|
575
|
+
error_out("Failed to update .prizmkit/plans/refactor-list.json: {}".format(err))
|
|
576
576
|
return
|
|
577
577
|
|
|
578
578
|
result = {
|
|
@@ -644,7 +644,7 @@ def action_clean(args, refactor_list_path, state_dir):
|
|
|
644
644
|
|
|
645
645
|
err = update_refactor_in_list(refactor_list_path, refactor_id, "pending")
|
|
646
646
|
if err:
|
|
647
|
-
error_out("Failed to update refactor-list.json: {}".format(err))
|
|
647
|
+
error_out("Failed to update .prizmkit/plans/refactor-list.json: {}".format(err))
|
|
648
648
|
return
|
|
649
649
|
|
|
650
650
|
result = {
|