prizmkit 1.0.35 → 1.0.58

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 (74) hide show
  1. package/bundled/VERSION.json +3 -3
  2. package/bundled/adapters/claude/agent-adapter.js +2 -1
  3. package/bundled/adapters/claude/command-adapter.js +4 -3
  4. package/bundled/agents/prizm-dev-team-dev.md +12 -12
  5. package/bundled/agents/prizm-dev-team-reviewer.md +10 -10
  6. package/bundled/dev-pipeline/README.md +15 -19
  7. package/bundled/dev-pipeline/assets/prizm-dev-team-integration.md +16 -23
  8. package/bundled/dev-pipeline/launch-bugfix-daemon.sh +8 -0
  9. package/bundled/dev-pipeline/launch-daemon.sh +2 -0
  10. package/bundled/dev-pipeline/lib/branch.sh +76 -0
  11. package/bundled/dev-pipeline/retry-bug.sh +5 -2
  12. package/bundled/dev-pipeline/retry-feature.sh +5 -2
  13. package/bundled/dev-pipeline/run-bugfix.sh +74 -0
  14. package/bundled/dev-pipeline/run.sh +76 -2
  15. package/bundled/dev-pipeline/scripts/check-session-status.py +3 -1
  16. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +0 -8
  17. package/bundled/dev-pipeline/scripts/parse-stream-progress.py +1 -1
  18. package/bundled/dev-pipeline/scripts/update-bug-status.py +24 -1
  19. package/bundled/dev-pipeline/scripts/update-feature-status.py +3 -2
  20. package/bundled/dev-pipeline/templates/bootstrap-tier1.md +11 -25
  21. package/bundled/dev-pipeline/templates/bootstrap-tier2.md +12 -26
  22. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +54 -65
  23. package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +7 -7
  24. package/bundled/dev-pipeline/templates/session-status-schema.json +1 -1
  25. package/bundled/dev-pipeline/tests/conftest.py +19 -131
  26. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +207 -0
  27. package/bundled/dev-pipeline/tests/test_utils.py +51 -110
  28. package/bundled/rules/prizm/prizm-commit-workflow.md +3 -3
  29. package/bundled/skills/_metadata.json +15 -16
  30. package/bundled/skills/app-planner/SKILL.md +8 -7
  31. package/bundled/skills/bug-fix-workflow/SKILL.md +174 -0
  32. package/bundled/skills/bug-planner/SKILL.md +20 -32
  33. package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +3 -5
  34. package/bundled/skills/dev-pipeline-launcher/SKILL.md +4 -6
  35. package/bundled/skills/feature-workflow/SKILL.md +25 -42
  36. package/bundled/skills/prizm-kit/SKILL.md +57 -21
  37. package/bundled/skills/prizm-kit/assets/{claude-md-template.md → project-memory-template.md} +2 -2
  38. package/bundled/skills/prizmkit-analyze/SKILL.md +41 -29
  39. package/bundled/skills/prizmkit-clarify/SKILL.md +40 -30
  40. package/bundled/skills/prizmkit-code-review/SKILL.md +48 -43
  41. package/bundled/skills/prizmkit-committer/SKILL.md +30 -68
  42. package/bundled/skills/prizmkit-implement/SKILL.md +48 -24
  43. package/bundled/skills/prizmkit-init/SKILL.md +57 -66
  44. package/bundled/skills/prizmkit-plan/SKILL.md +46 -20
  45. package/bundled/skills/prizmkit-prizm-docs/SKILL.md +60 -19
  46. package/bundled/skills/prizmkit-prizm-docs/assets/PRIZM-SPEC.md +23 -23
  47. package/bundled/skills/prizmkit-retrospective/SKILL.md +142 -65
  48. package/bundled/skills/prizmkit-retrospective/assets/retrospective-template.md +13 -0
  49. package/bundled/skills/prizmkit-specify/SKILL.md +63 -13
  50. package/bundled/skills/refactor-workflow/SKILL.md +105 -49
  51. package/bundled/team/prizm-dev-team.json +5 -19
  52. package/package.json +1 -1
  53. package/src/clean.js +0 -2
  54. package/src/manifest.js +8 -4
  55. package/src/scaffold.js +72 -6
  56. package/src/upgrade.js +32 -5
  57. package/bundled/agents/prizm-dev-team-coordinator.md +0 -141
  58. package/bundled/agents/prizm-dev-team-pm.md +0 -126
  59. package/bundled/dev-pipeline/tests/__init__.py +0 -0
  60. package/bundled/dev-pipeline/tests/test_check_session.py +0 -127
  61. package/bundled/dev-pipeline/tests/test_cleanup_logs.py +0 -119
  62. package/bundled/dev-pipeline/tests/test_detect_stuck.py +0 -207
  63. package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +0 -181
  64. package/bundled/dev-pipeline/tests/test_generate_prompt.py +0 -190
  65. package/bundled/dev-pipeline/tests/test_init_bugfix_pipeline.py +0 -153
  66. package/bundled/dev-pipeline/tests/test_init_pipeline.py +0 -241
  67. package/bundled/dev-pipeline/tests/test_update_bug_status.py +0 -142
  68. package/bundled/dev-pipeline/tests/test_update_feature_status.py +0 -268
  69. package/bundled/skills/prizm-kit/assets/codebuddy-md-template.md +0 -35
  70. package/bundled/skills/prizm-kit/assets/hooks/prizm-commit-hook.json +0 -15
  71. package/bundled/skills/prizmkit-summarize/SKILL.md +0 -51
  72. package/bundled/skills/prizmkit-summarize/assets/registry-template.md +0 -18
  73. package/bundled/templates/hooks/commit-intent-claude.json +0 -26
  74. /package/bundled/templates/hooks/{commit-intent-codebuddy.json → commit-intent.json} +0 -0
@@ -1,142 +0,0 @@
1
- """Tests for update-bug-status.py."""
2
-
3
- import json
4
- import os
5
- import re
6
- import sys
7
- import pytest
8
-
9
-
10
- def _import_update_bug_status():
11
- import importlib.util
12
- path = os.path.join(
13
- os.path.dirname(__file__), "..", "scripts", "update-bug-status.py"
14
- )
15
- spec = importlib.util.spec_from_file_location("update_bug_status", path)
16
- mod = importlib.util.module_from_spec(spec)
17
- sys.modules["update_bug_status"] = mod
18
- spec.loader.exec_module(mod)
19
- return mod
20
-
21
-
22
- ubs = _import_update_bug_status()
23
- now_iso = ubs.now_iso
24
- load_bug_status = ubs.load_bug_status
25
- save_bug_status = ubs.save_bug_status
26
- action_get_next = ubs.action_get_next
27
- SEVERITY_PRIORITY = ubs.SEVERITY_PRIORITY
28
-
29
-
30
- class TestNowIso:
31
- def test_valid_format(self):
32
- result = now_iso()
33
- pattern = r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$"
34
- assert re.match(pattern, result) is not None
35
-
36
-
37
- class TestLoadAndSaveBugStatus:
38
- def test_round_trip(self, bugfix_state_dir):
39
- bid = "B-001"
40
- bdir = os.path.join(bugfix_state_dir, "bugs", bid)
41
- os.makedirs(bdir, exist_ok=True)
42
-
43
- data = {
44
- "bug_id": bid,
45
- "status": "in_progress",
46
- "retry_count": 2,
47
- "max_retries": 3,
48
- "sessions": ["s-001"],
49
- "last_session_id": "s-001",
50
- "resume_from_phase": None,
51
- "created_at": "2024-01-01T00:00:00Z",
52
- "updated_at": "2024-01-01T01:00:00Z",
53
- }
54
- err = save_bug_status(bugfix_state_dir, bid, data)
55
- assert err is None
56
-
57
- loaded = load_bug_status(bugfix_state_dir, bid)
58
- assert loaded["bug_id"] == bid
59
- assert loaded["status"] == "in_progress"
60
- assert loaded["retry_count"] == 2
61
-
62
- def test_load_missing_returns_default(self, bugfix_state_dir):
63
- result = load_bug_status(bugfix_state_dir, "B-999")
64
- assert result["bug_id"] == "B-999"
65
- assert result["status"] == "pending"
66
- assert result["retry_count"] == 0
67
-
68
- def test_load_invalid_json_returns_default(self, bugfix_state_dir):
69
- bid = "B-BAD"
70
- bdir = os.path.join(bugfix_state_dir, "bugs", bid)
71
- os.makedirs(bdir, exist_ok=True)
72
- with open(os.path.join(bdir, "status.json"), "w") as f:
73
- f.write("not json!")
74
- result = load_bug_status(bugfix_state_dir, bid)
75
- assert result["status"] == "pending"
76
-
77
-
78
- class TestActionGetNext:
79
- def test_selects_critical_before_medium(self, bugfix_state_dir, capsys):
80
- bug_list = {
81
- "bugs": [
82
- {"id": "B-001", "title": "Low", "severity": "medium", "priority": 1},
83
- {"id": "B-002", "title": "High", "severity": "critical", "priority": 2},
84
- ]
85
- }
86
- action_get_next(bug_list, bugfix_state_dir)
87
- captured = capsys.readouterr()
88
- result = json.loads(captured.out)
89
- assert result["bug_id"] == "B-002"
90
- assert result["severity"] == "critical"
91
-
92
- def test_same_severity_sorted_by_priority(self, bugfix_state_dir, capsys):
93
- bug_list = {
94
- "bugs": [
95
- {"id": "B-001", "title": "P3", "severity": "high", "priority": 3},
96
- {"id": "B-002", "title": "P1", "severity": "high", "priority": 1},
97
- ]
98
- }
99
- action_get_next(bug_list, bugfix_state_dir)
100
- captured = capsys.readouterr()
101
- result = json.loads(captured.out)
102
- assert result["bug_id"] == "B-002"
103
-
104
- def test_all_completed_prints_pipeline_complete(self, bugfix_state_dir, capsys):
105
- bug_list = {"bugs": [{"id": "B-001", "title": "Done", "severity": "low"}]}
106
- # Mark as completed
107
- bdir = os.path.join(bugfix_state_dir, "bugs", "B-001")
108
- os.makedirs(bdir, exist_ok=True)
109
- with open(os.path.join(bdir, "status.json"), "w") as f:
110
- json.dump({"status": "completed"}, f)
111
- action_get_next(bug_list, bugfix_state_dir)
112
- captured = capsys.readouterr()
113
- assert "PIPELINE_COMPLETE" in captured.out
114
-
115
- def test_empty_bugs_prints_pipeline_complete(self, bugfix_state_dir, capsys):
116
- action_get_next({"bugs": []}, bugfix_state_dir)
117
- captured = capsys.readouterr()
118
- assert "PIPELINE_COMPLETE" in captured.out
119
-
120
- def test_prefers_in_progress_over_pending(self, bugfix_state_dir, capsys):
121
- bug_list = {
122
- "bugs": [
123
- {"id": "B-001", "title": "Pending", "severity": "critical", "priority": 1},
124
- {"id": "B-002", "title": "In Progress", "severity": "low", "priority": 2},
125
- ]
126
- }
127
- # Mark B-002 as in_progress
128
- bdir = os.path.join(bugfix_state_dir, "bugs", "B-002")
129
- os.makedirs(bdir, exist_ok=True)
130
- with open(os.path.join(bdir, "status.json"), "w") as f:
131
- json.dump({"status": "in_progress", "retry_count": 0}, f)
132
- action_get_next(bug_list, bugfix_state_dir)
133
- captured = capsys.readouterr()
134
- result = json.loads(captured.out)
135
- assert result["bug_id"] == "B-002"
136
-
137
-
138
- class TestSeverityPriority:
139
- def test_order(self):
140
- assert SEVERITY_PRIORITY["critical"] < SEVERITY_PRIORITY["high"]
141
- assert SEVERITY_PRIORITY["high"] < SEVERITY_PRIORITY["medium"]
142
- assert SEVERITY_PRIORITY["medium"] < SEVERITY_PRIORITY["low"]
@@ -1,268 +0,0 @@
1
- """Tests for update-feature-status.py."""
2
-
3
- import json
4
- import os
5
- import re
6
- import sys
7
- import pytest
8
- from types import SimpleNamespace
9
-
10
-
11
- def _import_update_feature_status():
12
- import importlib.util
13
- path = os.path.join(
14
- os.path.dirname(__file__), "..", "scripts", "update-feature-status.py"
15
- )
16
- spec = importlib.util.spec_from_file_location("update_feature_status", path)
17
- mod = importlib.util.module_from_spec(spec)
18
- sys.modules["update_feature_status"] = mod
19
- spec.loader.exec_module(mod)
20
- return mod
21
-
22
-
23
- ufs = _import_update_feature_status()
24
- now_iso = ufs.now_iso
25
- load_feature_status = ufs.load_feature_status
26
- save_feature_status = ufs.save_feature_status
27
- _build_feature_slug = ufs._build_feature_slug
28
- _format_duration = ufs._format_duration
29
- _calc_feature_duration = ufs._calc_feature_duration
30
-
31
-
32
- class TestSessionStatusValues:
33
- def test_contains_commit_missing(self):
34
- assert "commit_missing" in ufs.SESSION_STATUS_VALUES
35
-
36
- def test_contains_docs_missing(self):
37
- assert "docs_missing" in ufs.SESSION_STATUS_VALUES
38
-
39
-
40
- class TestNowIso:
41
- def test_returns_valid_iso_format(self):
42
- result = now_iso()
43
- # Should match YYYY-MM-DDTHH:MM:SSZ
44
- pattern = r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$"
45
- assert re.match(pattern, result) is not None
46
-
47
- def test_returns_string(self):
48
- assert isinstance(now_iso(), str)
49
-
50
-
51
- class TestLoadAndSaveFeatureStatus:
52
- def test_round_trip(self, state_dir):
53
- fid = "F-001"
54
- # Create the feature directory
55
- fdir = os.path.join(state_dir, "features", fid)
56
- os.makedirs(fdir, exist_ok=True)
57
-
58
- status_data = {
59
- "feature_id": fid,
60
- "status": "in_progress",
61
- "retry_count": 1,
62
- "max_retries": 3,
63
- "sessions": ["s-001"],
64
- "last_session_id": "s-001",
65
- "resume_from_phase": "3",
66
- "created_at": "2024-01-01T00:00:00Z",
67
- "updated_at": "2024-01-01T01:00:00Z",
68
- }
69
- err = save_feature_status(state_dir, fid, status_data)
70
- assert err is None
71
-
72
- loaded = load_feature_status(state_dir, fid)
73
- assert loaded["feature_id"] == fid
74
- assert loaded["status"] == "in_progress"
75
- assert loaded["retry_count"] == 1
76
-
77
- def test_load_missing_returns_default(self, state_dir):
78
- result = load_feature_status(state_dir, "F-999")
79
- assert result["feature_id"] == "F-999"
80
- assert result["status"] == "pending"
81
- assert result["retry_count"] == 0
82
-
83
- def test_load_invalid_json_returns_default(self, state_dir):
84
- fid = "F-BAD"
85
- fdir = os.path.join(state_dir, "features", fid)
86
- os.makedirs(fdir, exist_ok=True)
87
- with open(os.path.join(fdir, "status.json"), "w") as f:
88
- f.write("{invalid json")
89
- result = load_feature_status(state_dir, fid)
90
- assert result["status"] == "pending"
91
-
92
-
93
- class TestBuildFeatureSlug:
94
- def test_basic(self):
95
- assert _build_feature_slug("F-001", "Project Setup") == "001-project-setup"
96
-
97
- def test_special_chars(self):
98
- result = _build_feature_slug("F-002", "Auth (OAuth2.0)")
99
- assert result == "002-auth-oauth20"
100
-
101
- def test_empty_title(self):
102
- result = _build_feature_slug("F-003", "")
103
- assert result == "003-feature"
104
-
105
- def test_none_title(self):
106
- result = _build_feature_slug("F-003", None)
107
- assert result == "003-feature"
108
-
109
- def test_lowercase_f(self):
110
- result = _build_feature_slug("f-5", "Test")
111
- assert result == "005-test"
112
-
113
- def test_numeric_padding(self):
114
- result = _build_feature_slug("F-1", "A")
115
- assert result.startswith("001-")
116
-
117
-
118
- class TestFormatDuration:
119
- def test_none(self):
120
- assert _format_duration(None) == "N/A"
121
-
122
- def test_seconds(self):
123
- assert _format_duration(45) == "45s"
124
-
125
- def test_minutes(self):
126
- assert _format_duration(125) == "2m5s"
127
-
128
- def test_hours(self):
129
- assert _format_duration(3661) == "1h1m"
130
-
131
- def test_zero(self):
132
- assert _format_duration(0) == "0s"
133
-
134
- def test_exact_minute(self):
135
- assert _format_duration(60) == "1m0s"
136
-
137
- def test_exact_hour(self):
138
- assert _format_duration(3600) == "1h0m"
139
-
140
-
141
- class TestCalcFeatureDuration:
142
- def test_valid_duration(self, state_dir):
143
- fid = "F-001"
144
- fdir = os.path.join(state_dir, "features", fid)
145
- os.makedirs(fdir, exist_ok=True)
146
- status = {
147
- "created_at": "2024-01-01T00:00:00Z",
148
- "updated_at": "2024-01-01T00:05:00Z", # 300 seconds
149
- }
150
- with open(os.path.join(fdir, "status.json"), "w") as f:
151
- json.dump(status, f)
152
- result = _calc_feature_duration(state_dir, fid)
153
- assert result == 300.0
154
-
155
- def test_too_short_duration(self, state_dir):
156
- fid = "F-002"
157
- fdir = os.path.join(state_dir, "features", fid)
158
- os.makedirs(fdir, exist_ok=True)
159
- status = {
160
- "created_at": "2024-01-01T00:00:00Z",
161
- "updated_at": "2024-01-01T00:00:05Z", # 5 seconds - below 10s threshold
162
- }
163
- with open(os.path.join(fdir, "status.json"), "w") as f:
164
- json.dump(status, f)
165
- result = _calc_feature_duration(state_dir, fid)
166
- assert result is None
167
-
168
- def test_missing_file(self, state_dir):
169
- result = _calc_feature_duration(state_dir, "F-MISSING")
170
- assert result is None
171
-
172
- def test_missing_timestamps(self, state_dir):
173
- fid = "F-003"
174
- fdir = os.path.join(state_dir, "features", fid)
175
- os.makedirs(fdir, exist_ok=True)
176
- with open(os.path.join(fdir, "status.json"), "w") as f:
177
- json.dump({"status": "pending"}, f)
178
- result = _calc_feature_duration(state_dir, fid)
179
- assert result is None
180
-
181
-
182
- class TestActionUpdateDegradedStatuses:
183
- def test_commit_missing_updates_feature_state_without_cleanup(
184
- self, feature_list_file, state_dir, monkeypatch, capsys
185
- ):
186
- called = {"cleanup": 0}
187
-
188
- def _fake_cleanup(**_kwargs):
189
- called["cleanup"] += 1
190
- return []
191
-
192
- monkeypatch.setattr(ufs, "cleanup_feature_artifacts", _fake_cleanup)
193
-
194
- args = SimpleNamespace(
195
- feature_id="F-001",
196
- session_status="commit_missing",
197
- session_id="s-commit-missing",
198
- max_retries=3,
199
- project_root=None,
200
- )
201
-
202
- ufs.action_update(args, feature_list_file, state_dir)
203
- out = capsys.readouterr().out
204
- summary = json.loads(out)
205
-
206
- fs = ufs.load_feature_status(state_dir, "F-001")
207
- assert fs["status"] == "commit_missing"
208
- assert fs["retry_count"] == 1
209
- assert summary["new_status"] == "commit_missing"
210
- assert summary["degraded_reason"] == "commit_missing"
211
- assert summary["restart_policy"] == "finalization_retry"
212
- assert called["cleanup"] == 0
213
-
214
- with open(feature_list_file, "r", encoding="utf-8") as f:
215
- data = json.load(f)
216
- f1 = next(x for x in data["features"] if x["id"] == "F-001")
217
- assert f1["status"] == "commit_missing"
218
-
219
- def test_docs_missing_reaches_failed_when_retry_exhausted(
220
- self, feature_list_file, state_dir, monkeypatch, capsys
221
- ):
222
- called = {"cleanup": 0}
223
-
224
- def _fake_cleanup(**_kwargs):
225
- called["cleanup"] += 1
226
- return []
227
-
228
- monkeypatch.setattr(ufs, "cleanup_feature_artifacts", _fake_cleanup)
229
-
230
- args = SimpleNamespace(
231
- feature_id="F-001",
232
- session_status="docs_missing",
233
- session_id="s-docs-missing",
234
- max_retries=1,
235
- project_root=None,
236
- )
237
-
238
- ufs.action_update(args, feature_list_file, state_dir)
239
- out = capsys.readouterr().out
240
- summary = json.loads(out)
241
-
242
- fs = ufs.load_feature_status(state_dir, "F-001")
243
- assert fs["status"] == "failed"
244
- assert fs["retry_count"] == 1
245
- assert summary["new_status"] == "failed"
246
- assert summary["degraded_reason"] == "docs_missing"
247
- assert summary["restart_policy"] == "finalization_retry"
248
- assert called["cleanup"] == 0
249
-
250
- with open(feature_list_file, "r", encoding="utf-8") as f:
251
- data = json.load(f)
252
- f1 = next(x for x in data["features"] if x["id"] == "F-001")
253
- assert f1["status"] == "failed"
254
-
255
-
256
- class TestActionStatusForDegradedStates:
257
- def test_status_output_contains_degraded_counters(self, feature_list_file, state_dir, capsys):
258
- # Update feature-list.json to set degraded statuses (single source of truth)
259
- with open(feature_list_file, "r", encoding="utf-8") as f:
260
- feature_list_data = json.load(f)
261
-
262
- feature_list_data["features"][0]["status"] = "commit_missing"
263
- feature_list_data["features"][1]["status"] = "docs_missing"
264
-
265
- ufs.action_status(feature_list_data, state_dir)
266
- out = capsys.readouterr().out
267
-
268
- assert "Commit Missing: 1 | Docs Missing: 1" in out
@@ -1,35 +0,0 @@
1
- ## PrizmKit Documentation Framework
2
-
3
- This project uses PrizmKit with the Prizm documentation system for AI-optimized progressive context loading.
4
-
5
- ### Progressive Loading Protocol
6
- - ON SESSION START: Always read `.prizm-docs/root.prizm` first (L0 — project map)
7
- - ON TASK: Read L1 (`.prizm-docs/<module>.prizm`) for relevant modules referenced in MODULE_INDEX
8
- - ON FILE EDIT: Read L2 (`.prizm-docs/<module>/<submodule>.prizm`) before modifying files. Pay attention to TRAPS and DECISIONS.
9
- - NEVER load all .prizm docs at once. Load only what is needed for the current task.
10
-
11
- ### Auto-Update Protocol
12
- - BEFORE EVERY COMMIT: Update affected `.prizm-docs/` files
13
- - The UserPromptSubmit hook will remind you automatically
14
- - Use `prizmkit-committer` skill for the complete commit workflow
15
-
16
- ### Doc Format Rules
17
- - All `.prizm` files use KEY: value format, not prose
18
- - Size limits: L0 = 4KB, L1 = 3KB, L2 = 5KB
19
- - Arrow notation (->) indicates load pointers to other .prizm docs
20
- - DECISIONS and CHANGELOG are append-only (never delete entries)
21
-
22
- ### Creating New L2 Docs
23
- - When you first modify files in a sub-module that has no L2 doc:
24
- 1. Read the source files in that sub-module
25
- 2. Generate a new L2 `.prizm` file following Prizm specification
26
- 3. Add a pointer in the parent L1 doc's SUBDIRS section
27
-
28
- ### Fast Path for Simple Changes
29
- Not every change needs the full spec -> plan -> tasks workflow. Use fast path for:
30
- - Bug fixes with clear root cause, config tweaks, typo fixes, simple refactors
31
- - Documentation-only changes, test additions for existing code
32
- - Directly use `prizmkit.implement` with inline task description, then `prizmkit.commit`
33
-
34
- Use the full workflow (specify -> plan -> tasks -> analyze -> implement) for:
35
- - New features, multi-file coordinated changes, architectural decisions, data model or API changes
@@ -1,15 +0,0 @@
1
- {
2
- "hooks": {
3
- "UserPromptSubmit": [
4
- {
5
- "matcher": "\\b(commit|Commit|push|Push|finish|Finish|ship|Ship|merge|Merge|pull request|Pull Request|pr|PR)\\b|提交|推送|收尾|完成任务|合并|发版|发布",
6
- "hooks": [
7
- {
8
- "type": "command",
9
- "command": "echo 'PRIZMKIT_DOC_UPDATE_REQUIRED: Before committing, you MUST update .prizm-docs/ per Prizm auto-update protocol. Steps: 1) Run git diff --cached --name-status. 2) Map changed files to modules via root.prizm MODULE_INDEX. 3) Read and update affected .prizm files (only changed sections). 4) Append to changelog.prizm. 5) Stage .prizm files with git add .prizm-docs/. 6) Then proceed with commit using prizmkit-committer workflow. RULES: Never rewrite entire .prizm files. Never add prose. Only update affected sections.'"
10
- }
11
- ]
12
- }
13
- ]
14
- }
15
- }
@@ -1,51 +0,0 @@
1
- ---
2
- name: "prizmkit-summarize"
3
- description: "Archive completed features to REGISTRY.md. Extracts metadata from specs, scans code, updates feature index. Invoke after code review passes or feature is done. (project)"
4
- ---
5
-
6
- # PrizmKit Summarize
7
-
8
- Archive completed features to the feature registry. Extracts metadata from specs and code, generates a registry entry, and appends a changelog record. Idempotent — re-running produces the same output.
9
-
10
- ## Commands
11
-
12
- ### prizmkit.summarize
13
-
14
- Archive a completed feature to the registry.
15
-
16
- **PRECONDITION:** `spec.md`, `plan.md`, `tasks.md` exist in `.prizmkit/specs/###-feature-name/`
17
-
18
- **STEPS:**
19
-
20
- 1. Read `spec.md`, `plan.md`, `tasks.md`
21
- 2. Analyze `tasks.md` completion rate — warn if < 100%
22
- 3. Scan actual code directories for core file paths
23
- 4. Generate REGISTRY entry:
24
- - Feature number and name
25
- - Branch name
26
- - Status (complete/partial)
27
- - Key files and directories
28
- - API endpoints added/modified
29
- - Data model changes
30
- - Completion date
31
- 5. Append to `.prizmkit/specs/REGISTRY.md` (create from template `${SKILL_DIR}/assets/registry-template.md` if not exists)
32
- 6. Append changelog entry
33
- 7. Output: registry entry summary
34
-
35
- **KEY RULES:**
36
- - Idempotent: same input MUST produce same output on re-run
37
- - If `tasks.md` completion < 100%, status is "Partial" with warning
38
- - REGISTRY.md is append-only — never modify existing entries
39
- - Changelog entries use format: `YYYY-MM-DD | [###] [Feature Name] | [Status]`
40
- - If REGISTRY.md does not exist, create it from template before appending
41
- - **Bug fixes MUST NOT create new REGISTRY.md entries.** Bugs are refinements of incomplete existing features, not new functionality. Bug fix commits should only update the original feature's changelog, not generate a new registry entry. Do NOT invoke this skill for bug fix commits.
42
-
43
- **HANDOFF:** `prizmkit.specify` (start next feature) or `prizmkit.retrospective` (extract lessons)
44
-
45
- ## Template
46
-
47
- The registry template is located at `${SKILL_DIR}/assets/registry-template.md`.
48
-
49
- ## Output
50
-
51
- - `.prizmkit/specs/REGISTRY.md` — Updated with new feature entry and changelog record
@@ -1,18 +0,0 @@
1
- # PrizmKit Feature Registry
2
-
3
- > Auto-generated by prizmkit-summarize. Do not edit manually.
4
-
5
- ## Features
6
-
7
- ### [###] [Feature Name]
8
- - **Branch**: ###-feature-name
9
- - **Status**: Complete | Partial
10
- - **Date**: YYYY-MM-DD
11
- - **Key Files**: [list]
12
- - **API Changes**: [summary]
13
- - **Data Changes**: [summary]
14
-
15
- ---
16
-
17
- ## Changelog
18
- - YYYY-MM-DD | [###] [Feature Name] | [Status]
@@ -1,26 +0,0 @@
1
- {
2
- "hooks": {
3
- "UserPromptSubmit": [
4
- {
5
- "matcher": "\\b(commit|Commit|push|Push|finish|Finish|ship|Ship|merge|Merge|pull request|Pull Request|pr|PR)\\b|提交|推送|收尾|完成任务|合并|发版|发布",
6
- "hooks": [
7
- {
8
- "type": "command",
9
- "command": "SRC=$(git diff --cached --name-only 2>/dev/null | grep -cE '\\.(ts|tsx|js|jsx|py|go|rs|java)$'); if [ \"$SRC\" -gt 0 ]; then PRIZM=$(git diff --cached --name-only 2>/dev/null | grep -c '^\\.prizm-docs/'); if [ \"$PRIZM\" -gt 0 ]; then echo \"PRIZMKIT_DOC_STATUS: $SRC source file(s) staged | .prizm-docs/ updated ($PRIZM file(s))\"; else echo \"PRIZMKIT_DOC_STATUS: $SRC source file(s) staged | .prizm-docs/ NOT UPDATED — update if this is a feature change\"; fi; fi"
10
- }
11
- ]
12
- }
13
- ],
14
- "PostToolUse": [
15
- {
16
- "matcher": "Bash",
17
- "hooks": [
18
- {
19
- "type": "command",
20
- "command": "if echo \"$CLAUDE_TOOL_INPUT\" 2>/dev/null | grep -qE 'git (commit|merge|rebase)' 2>/dev/null; then DRIFT=$(sh .prizmkit/scripts/diff-prizm-docs.sh 2>/dev/null); if [ -n \"$DRIFT\" ]; then echo \"PRIZMKIT_DRIFT_DETECTED: prizm-docs structural differences found after git operation:\"; echo \"$DRIFT\"; echo \"Please update affected .prizm-docs/ files using /prizmkit-prizm-docs.\"; fi; fi"
21
- }
22
- ]
23
- }
24
- ]
25
- }
26
- }