prizmkit 1.1.128 → 1.1.130
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/prizmkit_runtime/gitops.py +88 -58
- package/bundled/dev-pipeline/prizmkit_runtime/reset.py +4 -3
- package/bundled/dev-pipeline/prizmkit_runtime/runner_bookkeeping.py +53 -1
- package/bundled/dev-pipeline/prizmkit_runtime/runners.py +33 -17
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +30 -28
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +8 -3
- package/bundled/dev-pipeline/scripts/generate-recovery-prompt.py +3 -2
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +11 -4
- package/bundled/dev-pipeline/scripts/parse-stream-progress.py +3 -3
- package/bundled/dev-pipeline/scripts/prompt_framework.py +4 -6
- package/bundled/dev-pipeline/templates/bootstrap-prompt.md +2 -2
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +20 -19
- package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +2 -2
- package/bundled/dev-pipeline/templates/sections/bugfix-mission.md +1 -1
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-review.md +10 -2
- package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +1 -1
- package/bundled/dev-pipeline/templates/sections/directory-convention-agent.md +3 -2
- package/bundled/dev-pipeline/templates/sections/directory-convention-full.md +3 -2
- package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +1 -1
- package/bundled/dev-pipeline/templates/sections/phase-commit.md +1 -1
- package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +1 -1
- package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +1 -1
- package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +11 -3
- package/bundled/dev-pipeline/templates/sections/phase-review-full.md +11 -3
- package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +1 -1
- package/bundled/dev-pipeline/templates/sections/phase0-init.md +1 -1
- package/bundled/dev-pipeline/templates/sections/refactor-mission.md +1 -1
- package/bundled/dev-pipeline/templates/sections/refactor-phase-review.md +11 -3
- package/bundled/dev-pipeline/templates/sections/refactor-reminders.md +1 -1
- package/bundled/dev-pipeline/templates/sections/subagent-timeout-recovery.md +6 -4
- package/bundled/dev-pipeline/templates/sections/test-failure-recovery-agent.md +1 -1
- package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +192 -5
- package/bundled/dev-pipeline/tests/test_python_runner_parity.py +139 -11
- package/bundled/dev-pipeline/tests/test_unified_cli.py +215 -9
- package/bundled/skills/_metadata.json +1 -1
- package/bundled/skills/feature-planner/SKILL.md +2 -2
- package/bundled/skills/prizmkit/SKILL.md +1 -1
- package/bundled/skills/prizmkit-code-review/SKILL.md +10 -1
- package/package.json +1 -1
- package/src/manifest.js +8 -3
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import os
|
|
5
|
+
import re
|
|
5
6
|
import shutil
|
|
6
7
|
import subprocess
|
|
7
8
|
import sys
|
|
@@ -830,7 +831,8 @@ def test_headless_review_guidance_uses_main_agent_review_loop():
|
|
|
830
831
|
assert "Main-Agent review loop" in text, path
|
|
831
832
|
assert "up to ten completed rounds" in text, path
|
|
832
833
|
assert "text final-verdict" in text, path
|
|
833
|
-
assert "
|
|
834
|
+
assert "The current Main Agent is the only Code Review executor" in text, path
|
|
835
|
+
assert "Do not invoke another review skill or review workflow" in text, path
|
|
834
836
|
assert "low=0" not in text and "Reviewer 3" not in text, path
|
|
835
837
|
assert "REVIEW_BLOCKED" not in text, path
|
|
836
838
|
assert "forced-worktree changed-content fallback" not in text, path
|
|
@@ -947,10 +949,11 @@ def test_progress_parser_normalizes_codebuddy_agent_tools_with_deduplication():
|
|
|
947
949
|
|
|
948
950
|
assert data["cb_session_id"] == "cb-session"
|
|
949
951
|
assert data["subagent_provider"] == "codebuddy"
|
|
950
|
-
assert data["subagent_spawn_count"] ==
|
|
951
|
-
assert data["active_subagent_count"] ==
|
|
952
|
+
assert data["subagent_spawn_count"] == 1
|
|
953
|
+
assert data["active_subagent_count"] == 1
|
|
952
954
|
assert {item["status"] for item in data["subagent_states"]} == {"running"}
|
|
953
|
-
assert len(data["subagent_statistics"]["records"]) ==
|
|
955
|
+
assert len(data["subagent_statistics"]["records"]) == 1
|
|
956
|
+
assert data["subagent_statistics"]["records"][0]["metadata"]["tool"] == "Agent"
|
|
954
957
|
|
|
955
958
|
|
|
956
959
|
def test_progress_parser_normalizes_codex_collab_metadata_with_missing_fields():
|
|
@@ -1827,14 +1830,18 @@ def test_git_branch_worktree_plans_preserve_shell_invariants(tmp_path):
|
|
|
1827
1830
|
|
|
1828
1831
|
assert create.name == "branch_create"
|
|
1829
1832
|
assert any(command.args[:2] == ("checkout", "-b") for command in create.commands)
|
|
1830
|
-
assert any(command.args[
|
|
1833
|
+
assert not any(command.args and command.args[0] == "stash" for command in merge.commands)
|
|
1834
|
+
assert any(command.args[:2] == ("status", "--porcelain") for command in merge.commands)
|
|
1831
1835
|
assert any(command.args[:2] == ("merge", "--ff-only") for command in merge.commands)
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
assert
|
|
1836
|
+
push_index = next(index for index, command in enumerate(merge.commands) if command.args == ("push",))
|
|
1837
|
+
merge_index = next(index for index, command in enumerate(merge.commands) if command.args[:2] == ("merge", "--ff-only"))
|
|
1838
|
+
assert merge_index < push_index
|
|
1839
|
+
assert save_wip.never_fails is False
|
|
1840
|
+
assert ensure.never_fails is False
|
|
1835
1841
|
assert any(command.args[:2] == ("rebase", "--abort") for command in ensure.commands)
|
|
1836
1842
|
assert any(command.args[:2] == ("add", "-A") for command in ensure.commands)
|
|
1837
|
-
assert not any(command.args[
|
|
1843
|
+
assert not any(command.args and command.args[0] == "stash" for command in ensure.commands)
|
|
1844
|
+
assert ensure.never_fails is False
|
|
1838
1845
|
assert any(".*/worktrees/**" in " ".join(command.args) for command in save_wip.commands)
|
|
1839
1846
|
assert worktree.commands[0].args[:2] == ("worktree", "add")
|
|
1840
1847
|
|
|
@@ -1862,6 +1869,205 @@ def test_git_branch_worktree_plans_preserve_shell_invariants(tmp_path):
|
|
|
1862
1869
|
assert skipped_wip.results == ()
|
|
1863
1870
|
|
|
1864
1871
|
|
|
1872
|
+
def test_runtime_source_constructs_no_git_stash_commands():
|
|
1873
|
+
runtime = Path("dev-pipeline/prizmkit_runtime")
|
|
1874
|
+
matches = []
|
|
1875
|
+
for path in runtime.glob("*.py"):
|
|
1876
|
+
text = path.read_text(encoding="utf-8")
|
|
1877
|
+
if re.search(r'["\']stash["\']', text):
|
|
1878
|
+
matches.append(path.as_posix())
|
|
1879
|
+
|
|
1880
|
+
assert matches == []
|
|
1881
|
+
|
|
1882
|
+
|
|
1883
|
+
def _init_merge_repo(project_root):
|
|
1884
|
+
subprocess.run(["git", "init", "-b", "main"], cwd=project_root, check=True, stdout=subprocess.DEVNULL)
|
|
1885
|
+
subprocess.run(["git", "config", "user.email", "test@example.com"], cwd=project_root, check=True)
|
|
1886
|
+
subprocess.run(["git", "config", "user.name", "Test"], cwd=project_root, check=True)
|
|
1887
|
+
manifest = project_root / ".prizmkit" / "manifest.json"
|
|
1888
|
+
manifest.parent.mkdir(parents=True)
|
|
1889
|
+
manifest.write_text('{"version":"current"}\n', encoding="utf-8")
|
|
1890
|
+
(project_root / "app.txt").write_text("base\n", encoding="utf-8")
|
|
1891
|
+
subprocess.run(["git", "add", "."], cwd=project_root, check=True)
|
|
1892
|
+
subprocess.run(["git", "commit", "-m", "base"], cwd=project_root, check=True, stdout=subprocess.DEVNULL)
|
|
1893
|
+
|
|
1894
|
+
|
|
1895
|
+
def _stash_oids(project_root):
|
|
1896
|
+
output = subprocess.run(
|
|
1897
|
+
["git", "stash", "list", "--format=%H"],
|
|
1898
|
+
cwd=project_root,
|
|
1899
|
+
check=True,
|
|
1900
|
+
stdout=subprocess.PIPE,
|
|
1901
|
+
text=True,
|
|
1902
|
+
).stdout
|
|
1903
|
+
return tuple(line for line in output.splitlines() if line)
|
|
1904
|
+
|
|
1905
|
+
|
|
1906
|
+
def test_branch_merge_preserves_preexisting_stash_when_workspace_is_clean(tmp_path):
|
|
1907
|
+
from prizmkit_runtime.gitops import BranchContext, branch_merge_plan, run_git_plan
|
|
1908
|
+
|
|
1909
|
+
_init_merge_repo(tmp_path)
|
|
1910
|
+
manifest = tmp_path / ".prizmkit" / "manifest.json"
|
|
1911
|
+
manifest.write_text('{"version":"stale"}\n', encoding="utf-8")
|
|
1912
|
+
subprocess.run(["git", "stash", "push", "-m", "stale-install", "--", ".prizmkit/manifest.json"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1913
|
+
stale_stashes = _stash_oids(tmp_path)
|
|
1914
|
+
subprocess.run(["git", "checkout", "-b", "dev/example"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1915
|
+
(tmp_path / "feature.txt").write_text("done\n", encoding="utf-8")
|
|
1916
|
+
subprocess.run(["git", "add", "feature.txt"], cwd=tmp_path, check=True)
|
|
1917
|
+
subprocess.run(["git", "commit", "-m", "feature"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1918
|
+
|
|
1919
|
+
result = run_git_plan(
|
|
1920
|
+
tmp_path,
|
|
1921
|
+
branch_merge_plan(BranchContext("main", "dev/example", tmp_path)),
|
|
1922
|
+
)
|
|
1923
|
+
|
|
1924
|
+
assert result.ok is True
|
|
1925
|
+
assert _stash_oids(tmp_path) == stale_stashes
|
|
1926
|
+
assert json.loads(manifest.read_text(encoding="utf-8"))["version"] == "current"
|
|
1927
|
+
assert (tmp_path / "feature.txt").read_text(encoding="utf-8") == "done\n"
|
|
1928
|
+
|
|
1929
|
+
|
|
1930
|
+
def test_branch_merge_rejects_dirty_task_checkout_without_touching_stashes(tmp_path):
|
|
1931
|
+
from prizmkit_runtime.gitops import BranchContext, branch_merge_plan, run_git_plan
|
|
1932
|
+
|
|
1933
|
+
_init_merge_repo(tmp_path)
|
|
1934
|
+
manifest = tmp_path / ".prizmkit" / "manifest.json"
|
|
1935
|
+
manifest.write_text('{"version":"stale"}\n', encoding="utf-8")
|
|
1936
|
+
subprocess.run(["git", "stash", "push", "-m", "user-stash", "--", ".prizmkit/manifest.json"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1937
|
+
stale_stashes = _stash_oids(tmp_path)
|
|
1938
|
+
subprocess.run(["git", "checkout", "-b", "dev/example"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1939
|
+
(tmp_path / "feature.txt").write_text("done\n", encoding="utf-8")
|
|
1940
|
+
subprocess.run(["git", "add", "feature.txt"], cwd=tmp_path, check=True)
|
|
1941
|
+
subprocess.run(["git", "commit", "-m", "feature"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1942
|
+
(tmp_path / "app.txt").write_text("local visible change\n", encoding="utf-8")
|
|
1943
|
+
|
|
1944
|
+
result = run_git_plan(
|
|
1945
|
+
tmp_path,
|
|
1946
|
+
branch_merge_plan(BranchContext("main", "dev/example", tmp_path)),
|
|
1947
|
+
)
|
|
1948
|
+
|
|
1949
|
+
assert result.ok is False
|
|
1950
|
+
assert _stash_oids(tmp_path) == stale_stashes
|
|
1951
|
+
assert (tmp_path / "app.txt").read_text(encoding="utf-8") == "local visible change\n"
|
|
1952
|
+
assert json.loads(manifest.read_text(encoding="utf-8"))["version"] == "current"
|
|
1953
|
+
assert subprocess.run(
|
|
1954
|
+
["git", "branch", "--show-current"],
|
|
1955
|
+
cwd=tmp_path,
|
|
1956
|
+
check=True,
|
|
1957
|
+
stdout=subprocess.PIPE,
|
|
1958
|
+
text=True,
|
|
1959
|
+
).stdout.strip() == "dev/example"
|
|
1960
|
+
|
|
1961
|
+
|
|
1962
|
+
def test_branch_merge_rebases_committed_task_without_stash_restore_conflict(tmp_path):
|
|
1963
|
+
from prizmkit_runtime.gitops import BranchContext, branch_merge_plan, run_git_plan
|
|
1964
|
+
|
|
1965
|
+
_init_merge_repo(tmp_path)
|
|
1966
|
+
subprocess.run(["git", "checkout", "-b", "dev/example"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1967
|
+
(tmp_path / "feature.txt").write_text("done\n", encoding="utf-8")
|
|
1968
|
+
subprocess.run(["git", "add", "feature.txt"], cwd=tmp_path, check=True)
|
|
1969
|
+
subprocess.run(["git", "commit", "-m", "feature"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1970
|
+
subprocess.run(["git", "checkout", "main"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1971
|
+
(tmp_path / "app.txt").write_text("main changed\n", encoding="utf-8")
|
|
1972
|
+
subprocess.run(["git", "commit", "-am", "advance main"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1973
|
+
subprocess.run(["git", "checkout", "dev/example"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1974
|
+
|
|
1975
|
+
result = run_git_plan(
|
|
1976
|
+
tmp_path,
|
|
1977
|
+
branch_merge_plan(BranchContext("main", "dev/example", tmp_path)),
|
|
1978
|
+
)
|
|
1979
|
+
|
|
1980
|
+
assert result.ok is True
|
|
1981
|
+
assert _stash_oids(tmp_path) == ()
|
|
1982
|
+
assert (tmp_path / "app.txt").read_text(encoding="utf-8") == "main changed\n"
|
|
1983
|
+
assert subprocess.run(
|
|
1984
|
+
["git", "branch", "--show-current"],
|
|
1985
|
+
cwd=tmp_path,
|
|
1986
|
+
check=True,
|
|
1987
|
+
stdout=subprocess.PIPE,
|
|
1988
|
+
text=True,
|
|
1989
|
+
).stdout.strip() == "main"
|
|
1990
|
+
|
|
1991
|
+
|
|
1992
|
+
def test_branch_return_commits_wip_without_touching_user_stashes(tmp_path):
|
|
1993
|
+
from prizmkit_runtime.gitops import branch_ensure_return
|
|
1994
|
+
|
|
1995
|
+
_init_merge_repo(tmp_path)
|
|
1996
|
+
manifest = tmp_path / ".prizmkit" / "manifest.json"
|
|
1997
|
+
manifest.write_text('{"version":"stale"}\n', encoding="utf-8")
|
|
1998
|
+
subprocess.run(["git", "stash", "push", "-m", "user-stash", "--", ".prizmkit/manifest.json"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
1999
|
+
user_stashes = _stash_oids(tmp_path)
|
|
2000
|
+
subprocess.run(["git", "checkout", "-b", "dev/interrupted"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
2001
|
+
(tmp_path / "app.txt").write_text("interrupted work\n", encoding="utf-8")
|
|
2002
|
+
|
|
2003
|
+
result = branch_ensure_return(tmp_path, "main", "dev/interrupted")
|
|
2004
|
+
|
|
2005
|
+
assert result.ok is True
|
|
2006
|
+
assert _stash_oids(tmp_path) == user_stashes
|
|
2007
|
+
assert subprocess.run(
|
|
2008
|
+
["git", "branch", "--show-current"], cwd=tmp_path, check=True, stdout=subprocess.PIPE, text=True,
|
|
2009
|
+
).stdout.strip() == "main"
|
|
2010
|
+
assert subprocess.run(
|
|
2011
|
+
["git", "show", "dev/interrupted:app.txt"], cwd=tmp_path, check=True, stdout=subprocess.PIPE, text=True,
|
|
2012
|
+
).stdout == "interrupted work\n"
|
|
2013
|
+
|
|
2014
|
+
|
|
2015
|
+
def test_branch_return_commit_failure_does_not_checkout_base(monkeypatch, tmp_path):
|
|
2016
|
+
from prizmkit_runtime import gitops
|
|
2017
|
+
|
|
2018
|
+
calls = []
|
|
2019
|
+
|
|
2020
|
+
def fake_run(_root, args):
|
|
2021
|
+
args = tuple(args)
|
|
2022
|
+
calls.append(args)
|
|
2023
|
+
if args[:3] == ("rev-parse", "--abbrev-ref", "HEAD"):
|
|
2024
|
+
return gitops.GitCommandResult(args, 0, "dev/interrupted\n", "")
|
|
2025
|
+
if args and args[0] == "commit":
|
|
2026
|
+
return gitops.GitCommandResult(args, 1, "", "commit failed")
|
|
2027
|
+
if args[:2] == ("status", "--porcelain"):
|
|
2028
|
+
return gitops.GitCommandResult(args, 0, " M app.txt\n", "")
|
|
2029
|
+
return gitops.GitCommandResult(args, 0, "", "")
|
|
2030
|
+
|
|
2031
|
+
monkeypatch.setattr(gitops, "run_git_command", fake_run)
|
|
2032
|
+
|
|
2033
|
+
result = gitops.branch_ensure_return(tmp_path, "main", "dev/interrupted")
|
|
2034
|
+
|
|
2035
|
+
assert result.ok is False
|
|
2036
|
+
assert not any(args[:2] == ("checkout", "main") for args in calls)
|
|
2037
|
+
assert not any(args and args[0] == "stash" for args in calls)
|
|
2038
|
+
|
|
2039
|
+
|
|
2040
|
+
def test_non_current_reset_preserves_dirty_workspace_and_user_stashes(tmp_path):
|
|
2041
|
+
from prizmkit_runtime.gitops import reset_cleanup_branch
|
|
2042
|
+
|
|
2043
|
+
_init_merge_repo(tmp_path)
|
|
2044
|
+
subprocess.run(["git", "branch", "dev/other"], cwd=tmp_path, check=True)
|
|
2045
|
+
manifest = tmp_path / ".prizmkit" / "manifest.json"
|
|
2046
|
+
manifest.write_text('{"version":"stale"}\n', encoding="utf-8")
|
|
2047
|
+
subprocess.run(["git", "stash", "push", "-m", "user-stash", "--", ".prizmkit/manifest.json"], cwd=tmp_path, check=True, stdout=subprocess.DEVNULL)
|
|
2048
|
+
user_stashes = _stash_oids(tmp_path)
|
|
2049
|
+
(tmp_path / "app.txt").write_text("unstaged\n", encoding="utf-8")
|
|
2050
|
+
(tmp_path / "staged.txt").write_text("staged\n", encoding="utf-8")
|
|
2051
|
+
subprocess.run(["git", "add", "staged.txt"], cwd=tmp_path, check=True)
|
|
2052
|
+
(tmp_path / "untracked.txt").write_text("untracked\n", encoding="utf-8")
|
|
2053
|
+
before = subprocess.run(["git", "status", "--porcelain"], cwd=tmp_path, check=True, stdout=subprocess.PIPE, text=True).stdout
|
|
2054
|
+
|
|
2055
|
+
reset_result = reset_cleanup_branch(tmp_path, "dev/other", return_branch="main", delete=False)
|
|
2056
|
+
|
|
2057
|
+
assert reset_result.branch_preserved is True
|
|
2058
|
+
assert reset_result.checkout_discarded is False
|
|
2059
|
+
assert subprocess.run(["git", "branch", "--show-current"], cwd=tmp_path, check=True, stdout=subprocess.PIPE, text=True).stdout.strip() == "main"
|
|
2060
|
+
assert subprocess.run(["git", "status", "--porcelain"], cwd=tmp_path, check=True, stdout=subprocess.PIPE, text=True).stdout == before
|
|
2061
|
+
assert _stash_oids(tmp_path) == user_stashes
|
|
2062
|
+
assert subprocess.run(["git", "show-ref", "--verify", "refs/heads/dev/other"], cwd=tmp_path, check=False).returncode == 0
|
|
2063
|
+
|
|
2064
|
+
clean_result = reset_cleanup_branch(tmp_path, "dev/other", return_branch="main", delete=True)
|
|
2065
|
+
|
|
2066
|
+
assert clean_result.deleted is True
|
|
2067
|
+
assert subprocess.run(["git", "status", "--porcelain"], cwd=tmp_path, check=True, stdout=subprocess.PIPE, text=True).stdout == before
|
|
2068
|
+
assert _stash_oids(tmp_path) == user_stashes
|
|
2069
|
+
|
|
2070
|
+
|
|
1865
2071
|
def test_worktree_runtime_context_uses_safe_deterministic_path(tmp_path):
|
|
1866
2072
|
from prizmkit_runtime.gitops import BranchContext, WorktreePolicy, worktree_runtime_context
|
|
1867
2073
|
|
|
@@ -361,8 +361,8 @@ Key requirements:
|
|
|
361
361
|
- descriptions: minimum 15 words (error), recommended minimum 30/50/80/100+ for low/medium/high/critical (warning). No upper limit — more detail prevents AI guessing
|
|
362
362
|
- `estimated_complexity` determines pipeline execution tier:
|
|
363
363
|
- `low` / `medium` → **lite** (single agent, no subagents)
|
|
364
|
-
- `high` → **standard** (
|
|
365
|
-
- `critical` → **full** (strongest
|
|
364
|
+
- `high` → **standard** (Main-Agent review guardrails, 3-agent compatibility metadata)
|
|
365
|
+
- `critical` → **full** (strongest Main-Agent review guardrails). Use for: architectural changes touching 10+ files, cross-module refactoring with API surface changes, or safety/security/data-loss risk
|
|
366
366
|
|
|
367
367
|
**IMPORTANT: Do NOT hand-write the final JSON file.** Instead:
|
|
368
368
|
1. Write a draft JSON to a temporary path (e.g., `.prizmkit/plans/feature-list.draft.json`)
|
|
@@ -110,7 +110,7 @@ PrizmKit supports any development scenario through the same skill chain. `/prizm
|
|
|
110
110
|
| `/prizmkit-plan` | First implementation planning step: run ahead of `/prizmkit-implement` to turn natural language into `spec.md` + `plan.md` with executable tasks. | "specify", "plan", "new task", "architect", "break it down" |
|
|
111
111
|
| `/prizmkit-implement` | Implementation step: use after `/prizmkit-plan` to execute `plan.md` tasks with TDD where applicable, task order, and checkpoints. | "implement", "build", "code it", "start coding" |
|
|
112
112
|
| `/prizmkit-test` | Risk-triggered quality gate: run after implementation when behavior, interfaces, data, security, or deploy risk requires tests and boundary coverage. | "test", "run tests", "verify", "quality check", "boundary tests" |
|
|
113
|
-
| `/prizmkit-code-review` | Full path quality gate:
|
|
113
|
+
| `/prizmkit-code-review` | Full path quality gate: the current Main Agent reviews and repairs the complete change in the active checkout without direct or indirect review delegation. | "review", "check code", "code review", "is it ready to commit" |
|
|
114
114
|
| `/prizmkit-retrospective` | Docs maintenance step: run after review/implementation when structure, interfaces, dependencies, behavior, or durable knowledge changed. | "retrospective", "retro", "update docs", "sync docs", "wrap up" |
|
|
115
115
|
| `/prizmkit-committer` | Final lifecycle commit step: use after required gates are satisfied; safely stages and creates a Conventional Commit without changing changelog by default. | "commit", "submit", "finish", "done" |
|
|
116
116
|
| `/prizmkit-prizm-docs` | Documentation system entry point: use for init/status/rebuild/validate/migrate or out-of-band repair, not normal development sync. | "initialize docs", "check docs", "rebuild docs", "validate docs", "docs drifted" |
|
|
@@ -5,7 +5,16 @@ description: "Review the complete current change in a bounded Main-Agent loop. A
|
|
|
5
5
|
|
|
6
6
|
# PrizmKit Code Review
|
|
7
7
|
|
|
8
|
-
Use one Main-Agent review loop. The Main Agent performs the complete review, filters candidate findings, repairs accepted findings, verifies the repairs, and decides the final result
|
|
8
|
+
Use one Main-Agent review loop. The current Main Agent is the only Code Review executor: it performs the complete review, filters candidate findings, repairs accepted findings, verifies the repairs, and decides the final result.
|
|
9
|
+
|
|
10
|
+
## Execution Boundary
|
|
11
|
+
|
|
12
|
+
- Do not delegate any part of Code Review directly or indirectly.
|
|
13
|
+
- Do not invoke another review skill or review workflow from inside this skill.
|
|
14
|
+
- Do not launch review work through a general-purpose execution unit or relabel it as a finder, verifier, audit, compatibility review, verification, or gap sweep.
|
|
15
|
+
- These restrictions apply for the entire review phase, including candidate discovery, evidence checks, repair verification, and final gap analysis.
|
|
16
|
+
- The Main Agent may directly use non-delegating read, search, edit, and test capabilities in the active workspace.
|
|
17
|
+
- `{artifact_dir}/review-report.md` is the only persisted review artifact. Do not append separate Review Notes to `context-snapshot.md`.
|
|
9
18
|
|
|
10
19
|
## When to Use
|
|
11
20
|
|
package/package.json
CHANGED
package/src/manifest.js
CHANGED
|
@@ -19,6 +19,7 @@ const MANIFEST_DIR = '.prizmkit';
|
|
|
19
19
|
* Read the manifest from a project directory.
|
|
20
20
|
* @param {string} projectRoot
|
|
21
21
|
* @returns {Promise<Object|null>} parsed manifest or null if not found
|
|
22
|
+
* @throws {Error} when a present manifest cannot be read or parsed
|
|
22
23
|
*/
|
|
23
24
|
export async function readManifest(projectRoot) {
|
|
24
25
|
const manifestPath = path.join(projectRoot, MANIFEST_DIR, MANIFEST_FILE);
|
|
@@ -26,9 +27,13 @@ export async function readManifest(projectRoot) {
|
|
|
26
27
|
return null;
|
|
27
28
|
}
|
|
28
29
|
try {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
const manifest = await fs.readJSON(manifestPath);
|
|
31
|
+
if (manifest === null || Array.isArray(manifest) || typeof manifest !== 'object') {
|
|
32
|
+
throw new TypeError('manifest root must be a JSON object');
|
|
33
|
+
}
|
|
34
|
+
return manifest;
|
|
35
|
+
} catch (error) {
|
|
36
|
+
throw new Error(`Failed to read PrizmKit manifest at ${manifestPath}: ${error.message}`, { cause: error });
|
|
32
37
|
}
|
|
33
38
|
}
|
|
34
39
|
|