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.
Files changed (132) hide show
  1. package/bundled/VERSION.json +3 -3
  2. package/bundled/adapters/codebuddy/skill-adapter.js +21 -7
  3. package/bundled/agents/prizm-dev-team-reviewer.md +53 -173
  4. package/bundled/dev-pipeline/.env.example +45 -0
  5. package/bundled/dev-pipeline/README.md +64 -64
  6. package/bundled/dev-pipeline/SCHEMA_ANALYSIS.md +535 -0
  7. package/bundled/dev-pipeline/assets/feature-list-example.json +0 -1
  8. package/bundled/dev-pipeline/launch-bugfix-daemon.sh +64 -18
  9. package/bundled/dev-pipeline/launch-feature-daemon.sh +15 -12
  10. package/bundled/dev-pipeline/launch-refactor-daemon.sh +64 -18
  11. package/bundled/dev-pipeline/lib/branch.sh +6 -1
  12. package/bundled/dev-pipeline/lib/common.sh +71 -0
  13. package/bundled/dev-pipeline/lib/heartbeat.sh +2 -2
  14. package/bundled/dev-pipeline/reset-bug.sh +10 -9
  15. package/bundled/dev-pipeline/reset-feature.sh +9 -8
  16. package/bundled/dev-pipeline/reset-refactor.sh +10 -9
  17. package/bundled/dev-pipeline/retry-bugfix.sh +67 -29
  18. package/bundled/dev-pipeline/retry-feature.sh +54 -18
  19. package/bundled/dev-pipeline/retry-refactor.sh +112 -29
  20. package/bundled/dev-pipeline/run-bugfix.sh +281 -59
  21. package/bundled/dev-pipeline/run-feature.sh +53 -18
  22. package/bundled/dev-pipeline/run-refactor.sh +392 -66
  23. package/bundled/dev-pipeline/scripts/check-session-status.py +24 -1
  24. package/bundled/dev-pipeline/scripts/cleanup-logs.py +2 -2
  25. package/bundled/dev-pipeline/scripts/detect-stuck.py +195 -85
  26. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +57 -33
  27. package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +25 -9
  28. package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +104 -17
  29. package/bundled/dev-pipeline/scripts/init-bugfix-pipeline.py +34 -9
  30. package/bundled/dev-pipeline/scripts/init-pipeline.py +10 -10
  31. package/bundled/dev-pipeline/scripts/init-refactor-pipeline.py +19 -8
  32. package/bundled/dev-pipeline/scripts/parse-stream-progress.py +1 -5
  33. package/bundled/dev-pipeline/scripts/patch-completion-notes.py +191 -0
  34. package/bundled/dev-pipeline/scripts/update-bug-status.py +167 -22
  35. package/bundled/dev-pipeline/scripts/update-feature-status.py +104 -62
  36. package/bundled/dev-pipeline/scripts/update-refactor-status.py +351 -21
  37. package/bundled/dev-pipeline/templates/agent-prompts/dev-fix.md +1 -1
  38. package/bundled/dev-pipeline/templates/agent-prompts/reviewer-review.md +7 -11
  39. package/bundled/dev-pipeline/templates/bootstrap-prompt.md +41 -7
  40. package/bundled/dev-pipeline/templates/bootstrap-tier1.md +27 -3
  41. package/bundled/dev-pipeline/templates/bootstrap-tier2.md +43 -19
  42. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +54 -26
  43. package/bundled/dev-pipeline/templates/bug-fix-list-schema.json +6 -15
  44. package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +36 -25
  45. package/bundled/dev-pipeline/templates/feature-list-schema.json +109 -31
  46. package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +270 -0
  47. package/bundled/dev-pipeline/templates/refactor-list-schema.json +11 -3
  48. package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +3 -1
  49. package/bundled/dev-pipeline/templates/sections/critical-paths-agent.md +1 -0
  50. package/bundled/dev-pipeline/templates/sections/feature-context.md +2 -0
  51. package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +29 -2
  52. package/bundled/dev-pipeline/templates/sections/phase-commit.md +22 -0
  53. package/bundled/dev-pipeline/templates/sections/phase-deploy-verification.md +2 -2
  54. package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +8 -6
  55. package/bundled/dev-pipeline/templates/sections/phase-review-full.md +7 -5
  56. package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +3 -3
  57. package/bundled/skills/_metadata.json +5 -22
  58. package/bundled/skills/app-planner/SKILL.md +98 -72
  59. package/bundled/skills/app-planner/assets/app-design-guide.md +1 -1
  60. package/bundled/skills/app-planner/references/architecture-decisions.md +1 -1
  61. package/bundled/skills/app-planner/references/project-brief-guide.md +69 -66
  62. package/bundled/skills/bug-fix-workflow/SKILL.md +52 -9
  63. package/bundled/skills/bug-planner/SKILL.md +139 -197
  64. package/bundled/skills/bug-planner/assets/bug-confirmation-template.md +43 -0
  65. package/bundled/skills/bug-planner/references/critic-and-verification.md +44 -0
  66. package/bundled/skills/bug-planner/references/error-recovery.md +73 -0
  67. package/bundled/skills/bug-planner/references/input-formats.md +53 -0
  68. package/bundled/skills/bug-planner/references/schema-validation.md +25 -0
  69. package/bundled/skills/bug-planner/references/severity-rules.md +16 -0
  70. package/bundled/skills/bug-planner/scripts/validate-bug-list.py +4 -8
  71. package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +34 -39
  72. package/bundled/skills/feature-pipeline-launcher/SKILL.md +49 -36
  73. package/bundled/skills/feature-pipeline-launcher/scripts/preflight-check.py +3 -3
  74. package/bundled/skills/feature-planner/SKILL.md +53 -142
  75. package/bundled/skills/feature-planner/assets/evaluation-guide.md +1 -1
  76. package/bundled/skills/feature-planner/assets/planning-guide.md +21 -5
  77. package/bundled/skills/feature-planner/references/browser-interaction.md +2 -4
  78. package/bundled/skills/feature-planner/references/completeness-review.md +57 -0
  79. package/bundled/skills/feature-planner/references/error-recovery.md +16 -35
  80. package/bundled/skills/feature-planner/references/incremental-feature-planning.md +1 -1
  81. package/bundled/skills/feature-planner/references/new-project-planning.md +2 -2
  82. package/bundled/skills/feature-planner/scripts/validate-and-generate.py +19 -20
  83. package/bundled/skills/feature-workflow/SKILL.md +24 -25
  84. package/bundled/skills/prizm-kit/SKILL.md +39 -49
  85. package/bundled/skills/prizmkit-code-review/SKILL.md +51 -64
  86. package/bundled/skills/prizmkit-code-review/rules/dimensions.md +85 -0
  87. package/bundled/skills/prizmkit-code-review/rules/fix-strategy.md +11 -11
  88. package/bundled/skills/prizmkit-committer/SKILL.md +3 -31
  89. package/bundled/skills/prizmkit-deploy/SKILL.md +34 -31
  90. package/bundled/skills/prizmkit-deploy/assets/deploy-template.md +1 -1
  91. package/bundled/skills/prizmkit-implement/SKILL.md +35 -68
  92. package/bundled/skills/prizmkit-init/SKILL.md +112 -65
  93. package/bundled/skills/prizmkit-init/assets/project-brief-template.md +82 -0
  94. package/bundled/skills/prizmkit-plan/SKILL.md +120 -79
  95. package/bundled/skills/prizmkit-plan/assets/plan-template.md +28 -18
  96. package/bundled/skills/prizmkit-plan/assets/spec-template.md +28 -11
  97. package/bundled/skills/prizmkit-plan/references/clarify-guide.md +3 -3
  98. package/bundled/skills/prizmkit-plan/references/verification-checklist.md +60 -0
  99. package/bundled/skills/prizmkit-prizm-docs/SKILL.md +10 -81
  100. package/bundled/skills/prizmkit-prizm-docs/assets/{PRIZM-SPEC.md → prizm-docs-format.md} +41 -526
  101. package/bundled/skills/prizmkit-prizm-docs/references/op-init.md +46 -0
  102. package/bundled/skills/prizmkit-prizm-docs/references/op-rebuild.md +16 -0
  103. package/bundled/skills/prizmkit-prizm-docs/references/op-status.md +14 -0
  104. package/bundled/skills/prizmkit-prizm-docs/references/op-update.md +19 -0
  105. package/bundled/skills/prizmkit-prizm-docs/references/op-validate.md +17 -0
  106. package/bundled/skills/prizmkit-retrospective/SKILL.md +27 -65
  107. package/bundled/skills/prizmkit-retrospective/references/knowledge-injection-steps.md +3 -4
  108. package/bundled/skills/prizmkit-retrospective/references/structural-sync-steps.md +7 -25
  109. package/bundled/skills/recovery-workflow/SKILL.md +22 -22
  110. package/bundled/skills/recovery-workflow/evals/evals.json +5 -5
  111. package/bundled/skills/recovery-workflow/scripts/detect-recovery-state.py +43 -10
  112. package/bundled/skills/refactor-pipeline-launcher/SKILL.md +48 -40
  113. package/bundled/skills/refactor-planner/SKILL.md +43 -61
  114. package/bundled/skills/refactor-planner/scripts/validate-and-generate-refactor.py +17 -17
  115. package/bundled/skills/refactor-workflow/SKILL.md +23 -24
  116. package/bundled/team/prizm-dev-team.json +1 -1
  117. package/bundled/{skills/prizm-kit/assets → templates}/project-memory-template.md +1 -1
  118. package/package.json +1 -1
  119. package/src/clean.js +3 -4
  120. package/src/gitignore-template.js +7 -9
  121. package/src/scaffold.js +14 -5
  122. package/bundled/dev-pipeline/templates/agent-prompts/reviewer-analyze.md +0 -5
  123. package/bundled/dev-pipeline/templates/sections/phase-analyze-agent.md +0 -19
  124. package/bundled/dev-pipeline/templates/sections/phase-analyze-full.md +0 -19
  125. package/bundled/skills/app-planner/references/project-conventions.md +0 -93
  126. package/bundled/skills/prizmkit-analyze/SKILL.md +0 -207
  127. package/bundled/skills/prizmkit-code-review/rules/dimensions-bugfix.md +0 -25
  128. package/bundled/skills/prizmkit-code-review/rules/dimensions-feature.md +0 -43
  129. package/bundled/skills/prizmkit-code-review/rules/dimensions-refactor.md +0 -25
  130. package/bundled/skills/prizmkit-implement/references/deploy-guide-protocol.md +0 -69
  131. package/bundled/skills/prizmkit-verify/SKILL.md +0 -281
  132. 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 to create/initialize",
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 to create/initialize",
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": 0,
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": "pending",
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", "analyze", "implement", "code-review", "retrospective", "commit"]
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)