prizmkit 1.1.119 → 1.1.120
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/bin/create-prizmkit.js +1 -5
- package/bundled/VERSION.json +3 -3
- package/bundled/dev-pipeline/README.md +41 -38
- package/bundled/dev-pipeline/assets/skill-subagent-integration.md +76 -0
- package/bundled/dev-pipeline/prizmkit_runtime/config.py +2 -8
- package/bundled/dev-pipeline/prizmkit_runtime/interoperability.py +1 -1
- package/bundled/dev-pipeline/prizmkit_runtime/platform_detection.py +3 -3
- package/bundled/dev-pipeline/prizmkit_runtime/runners.py +45 -3
- package/bundled/dev-pipeline/prizmkit_runtime/sessions.py +28 -6
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +60 -102
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +1 -19
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +1 -19
- package/bundled/dev-pipeline/scripts/{init-dev-team.py → init-change-artifact.py} +6 -16
- package/bundled/dev-pipeline/scripts/parse-stream-progress.py +364 -76
- package/bundled/dev-pipeline/scripts/utils.py +1 -1
- package/bundled/dev-pipeline/templates/bootstrap-prompt.md +2 -2
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +7 -9
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-review.md +2 -2
- package/bundled/dev-pipeline/templates/sections/context-budget-rules.md +1 -1
- package/bundled/dev-pipeline/templates/sections/critical-paths-agent.md +0 -1
- package/bundled/dev-pipeline/templates/sections/critical-paths-full.md +0 -2
- package/bundled/dev-pipeline/templates/sections/phase-commit-full.md +8 -1
- package/bundled/dev-pipeline/templates/sections/phase-implement-agent.md +6 -7
- package/bundled/dev-pipeline/templates/sections/phase-implement-full.md +6 -7
- package/bundled/dev-pipeline/templates/sections/phase-implement-lite.md +4 -2
- package/bundled/dev-pipeline/templates/sections/phase-review-agent.md +2 -2
- package/bundled/dev-pipeline/templates/sections/phase-review-full.md +4 -2
- package/bundled/dev-pipeline/templates/sections/phase-specify-plan-full.md +20 -0
- package/bundled/dev-pipeline/templates/sections/refactor-phase-review.md +2 -2
- package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +204 -141
- package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +16 -10
- package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +2 -13
- package/bundled/dev-pipeline/tests/test_python_runner_parity.py +13 -14
- package/bundled/dev-pipeline/tests/test_unified_cli.py +205 -6
- package/bundled/skills/_metadata.json +1 -1
- package/bundled/skills/app-planner/SKILL.md +2 -2
- package/bundled/skills/app-planner/references/architecture-decisions.md +1 -3
- package/bundled/skills/prizmkit-code-review/SKILL.md +16 -14
- package/bundled/skills/prizmkit-code-review/references/reviewer-agent-prompt.md +9 -9
- package/bundled/skills/prizmkit-implement/SKILL.md +21 -1
- package/bundled/skills/prizmkit-implement/references/implementation-subagent-procedure.md +67 -0
- package/package.json +1 -1
- package/src/clean.js +12 -8
- package/src/config.js +24 -42
- package/src/index.js +1 -10
- package/src/manifest.js +3 -9
- package/src/metadata.js +0 -26
- package/src/prompts.js +0 -13
- package/src/scaffold.js +76 -201
- package/src/upgrade.js +16 -33
- package/bundled/adapters/claude/agent-adapter.js +0 -96
- package/bundled/adapters/claude/team-adapter.js +0 -183
- package/bundled/adapters/codebuddy/agent-adapter.js +0 -42
- package/bundled/adapters/codebuddy/team-adapter.js +0 -46
- package/bundled/adapters/codex/agent-adapter.js +0 -38
- package/bundled/adapters/codex/team-adapter.js +0 -37
- package/bundled/agents/prizm-dev-team-dev.md +0 -123
- package/bundled/agents/prizm-dev-team-reviewer.md +0 -113
- package/bundled/dev-pipeline/assets/prizm-dev-team-integration.md +0 -65
- package/bundled/dev-pipeline/templates/bootstrap-tier1.md +0 -436
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +0 -510
- package/bundled/team/prizm-dev-team.json +0 -27
|
@@ -17,6 +17,7 @@ from generate_bootstrap_prompt import (
|
|
|
17
17
|
format_global_context,
|
|
18
18
|
get_completed_dependencies,
|
|
19
19
|
determine_pipeline_mode,
|
|
20
|
+
determine_legacy_template_mode,
|
|
20
21
|
process_conditional_blocks,
|
|
21
22
|
process_mode_blocks,
|
|
22
23
|
assemble_sections,
|
|
@@ -235,7 +236,7 @@ class TestExplicitProjectRoot:
|
|
|
235
236
|
)
|
|
236
237
|
assert not replacements["{{SESSION_STATUS_PATH}}"].startswith(str(execution_root.resolve()))
|
|
237
238
|
assert replacements["{{PROJECT_BRIEF}}"] == "worktree brief"
|
|
238
|
-
assert
|
|
239
|
+
assert "{{" + "DEV_" + "SUBAGENT_PATH" + "}}" not in replacements
|
|
239
240
|
assert replacements["{{SESSION_LOG_PATH}}"].endswith(
|
|
240
241
|
".prizmkit/state/features/F-001/sessions/session-1/logs/session.log"
|
|
241
242
|
)
|
|
@@ -254,9 +255,6 @@ class TestExplicitProjectRoot:
|
|
|
254
255
|
feature_list.parent.mkdir(parents=True)
|
|
255
256
|
state_dir.mkdir(parents=True)
|
|
256
257
|
execution_root.mkdir(parents=True)
|
|
257
|
-
(execution_root / ".claude" / "agents").mkdir(parents=True)
|
|
258
|
-
(execution_root / ".claude" / "agents" / "prizm-dev-team-dev.md").write_text("dev", encoding="utf-8")
|
|
259
|
-
(execution_root / ".claude" / "agents" / "prizm-dev-team-reviewer.md").write_text("reviewer", encoding="utf-8")
|
|
260
258
|
feature_list.write_text(
|
|
261
259
|
json.dumps({"features": [{"id": "F-001", "title": "Worktree Prompt", "estimated_complexity": "medium", "status": "pending"}]}),
|
|
262
260
|
encoding="utf-8",
|
|
@@ -285,7 +283,7 @@ class TestExplicitProjectRoot:
|
|
|
285
283
|
"--output",
|
|
286
284
|
str(output_path),
|
|
287
285
|
"--template",
|
|
288
|
-
str(pipeline_root / "templates" / "bootstrap-
|
|
286
|
+
str(pipeline_root / "templates" / "bootstrap-tier3.md"),
|
|
289
287
|
],
|
|
290
288
|
)
|
|
291
289
|
|
|
@@ -332,20 +330,16 @@ class TestGetCompletedDependencies:
|
|
|
332
330
|
# ---------------------------------------------------------------------------
|
|
333
331
|
|
|
334
332
|
class TestDeterminePipelineMode:
|
|
335
|
-
def
|
|
336
|
-
|
|
333
|
+
def test_all_complexities_use_unified_full_guidance(self):
|
|
334
|
+
for complexity in ("low", "medium", "high", "critical", "banana", None):
|
|
335
|
+
assert determine_pipeline_mode(complexity) == "full"
|
|
337
336
|
|
|
338
|
-
def
|
|
339
|
-
assert
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
assert
|
|
343
|
-
|
|
344
|
-
def test_critical(self):
|
|
345
|
-
assert determine_pipeline_mode("critical") == "full"
|
|
346
|
-
|
|
347
|
-
def test_unknown(self):
|
|
348
|
-
assert determine_pipeline_mode("banana") == "lite"
|
|
337
|
+
def test_legacy_template_mode_mapping_remains_available_for_custom_templates(self):
|
|
338
|
+
assert determine_legacy_template_mode("low") == "lite"
|
|
339
|
+
assert determine_legacy_template_mode("medium") == "lite"
|
|
340
|
+
assert determine_legacy_template_mode("high") == "standard"
|
|
341
|
+
assert determine_legacy_template_mode("critical") == "full"
|
|
342
|
+
assert determine_legacy_template_mode("banana") == "lite"
|
|
349
343
|
|
|
350
344
|
|
|
351
345
|
# ---------------------------------------------------------------------------
|
|
@@ -807,10 +801,6 @@ class TestHeadlessRecoveryReframing:
|
|
|
807
801
|
deleted_title = "Session " + "Checkpoint Awareness"
|
|
808
802
|
active_paths = [
|
|
809
803
|
Path("dev-pipeline/scripts/generate-bootstrap-prompt.py"),
|
|
810
|
-
Path("dev-pipeline/scripts/generate-bugfix-prompt.py"),
|
|
811
|
-
Path("dev-pipeline/scripts/generate-refactor-prompt.py"),
|
|
812
|
-
Path("dev-pipeline/templates/bootstrap-tier1.md"),
|
|
813
|
-
Path("dev-pipeline/templates/bootstrap-tier2.md"),
|
|
814
804
|
Path("dev-pipeline/templates/bootstrap-tier3.md"),
|
|
815
805
|
Path("dev-pipeline/templates/bugfix-bootstrap-prompt.md"),
|
|
816
806
|
Path("dev-pipeline/templates/refactor-bootstrap-prompt.md"),
|
|
@@ -894,33 +884,32 @@ class TestDirectOrchestratorImplementationPrompts:
|
|
|
894
884
|
assert FORBIDDEN_TWENTY_STEP not in rendered
|
|
895
885
|
assert "Reviewer Agent → filter → orchestrator fix" in rendered
|
|
896
886
|
|
|
897
|
-
def
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
assert FORBIDDEN_TWENTY_STEP not in rendered
|
|
887
|
+
def test_retained_tier3_fallback_template_uses_direct_orchestrator_implementation(self):
|
|
888
|
+
rendered = Path("dev-pipeline/templates/bootstrap-tier3.md").read_text(encoding="utf-8")
|
|
889
|
+
|
|
890
|
+
assert "/prizmkit-implement" in rendered
|
|
891
|
+
assert "Implement — Orchestrator Direct" in rendered
|
|
892
|
+
assert "Spawn Dev subagent" not in rendered
|
|
893
|
+
assert "Spawn Dev agent" not in rendered
|
|
894
|
+
assert "Spawn Reviewer agent" not in rendered
|
|
895
|
+
assert "Reviewer Agent Def" not in rendered
|
|
896
|
+
assert "subagent_type=\"" + "-".join(["prizm", "dev", "team", "reviewer"]) + "\"" not in rendered
|
|
897
|
+
assert "Implement — Dev" not in rendered
|
|
898
|
+
assert "{{AGENT_PROMPT_DEV_IMPLEMENT}}" not in rendered
|
|
899
|
+
assert "{{AGENT_PROMPT_REVIEWER_REVIEW}}" not in rendered
|
|
900
|
+
assert "reviewer-review.md" not in rendered
|
|
901
|
+
assert "dev-implement.md" not in rendered
|
|
902
|
+
assert "Bug Fix Documentation Policy" not in rendered
|
|
903
|
+
assert "For bug-fix sessions" not in rendered
|
|
904
|
+
assert "fix(<scope>)" not in rendered
|
|
905
|
+
assert "port check 3000" not in rendered
|
|
906
|
+
assert "localhost:3000" not in rendered
|
|
907
|
+
assert FORBIDDEN_REVIEW_DEV_FIX not in rendered
|
|
908
|
+
assert FORBIDDEN_REVIEWER_DEV_SPAWN not in rendered
|
|
909
|
+
assert FORBIDDEN_EXPLORE_SUBAGENT not in rendered
|
|
910
|
+
assert FORBIDDEN_TEST_CMD_PLACEHOLDER not in rendered
|
|
911
|
+
assert FORBIDDEN_THREE_STRIKE not in rendered
|
|
912
|
+
assert FORBIDDEN_TWENTY_STEP not in rendered
|
|
924
913
|
|
|
925
914
|
|
|
926
915
|
# ---------------------------------------------------------------------------
|
|
@@ -1008,23 +997,18 @@ def _write_feature_list(path, feature):
|
|
|
1008
997
|
path.write_text(json.dumps({"features": [feature], "global_context": {"language": "Python"}}), encoding="utf-8")
|
|
1009
998
|
|
|
1010
999
|
|
|
1011
|
-
def _render_feature_prompt(tmp_path, mode="standard", template=None, platform="claude", browser_interaction=None):
|
|
1000
|
+
def _render_feature_prompt(tmp_path, mode="standard", template=None, platform="claude", browser_interaction=None, complexity=None):
|
|
1012
1001
|
project = tmp_path / "project"
|
|
1013
1002
|
project.mkdir(parents=True)
|
|
1014
1003
|
(project / ".prizmkit" / "plans").mkdir(parents=True)
|
|
1015
1004
|
(project / ".prizmkit" / "config.json").write_text(
|
|
1016
1005
|
json.dumps({"platform": platform, "ai_cli": platform}), encoding="utf-8"
|
|
1017
1006
|
)
|
|
1018
|
-
for platform_dir, suffix in ((".claude", ".md"), (".codex", ".toml")):
|
|
1019
|
-
agents_dir = project / platform_dir / "agents"
|
|
1020
|
-
agents_dir.mkdir(parents=True)
|
|
1021
|
-
for name in ("dev", "reviewer"):
|
|
1022
|
-
(agents_dir / f"prizm-dev-team-{name}{suffix}").write_text("agent\n", encoding="utf-8")
|
|
1023
1007
|
feature = {
|
|
1024
1008
|
"id": "F-123",
|
|
1025
1009
|
"title": "Prompt Cleanup",
|
|
1026
1010
|
"description": "Clean prompt text",
|
|
1027
|
-
"estimated_complexity": {"lite": "low", "standard": "medium", "full": "high"}[mode],
|
|
1011
|
+
"estimated_complexity": complexity or {"lite": "low", "standard": "medium", "full": "high"}[mode],
|
|
1028
1012
|
"acceptance_criteria": ["Prompts are clean"],
|
|
1029
1013
|
}
|
|
1030
1014
|
if browser_interaction is not None:
|
|
@@ -1046,7 +1030,10 @@ def _render_feature_prompt(tmp_path, mode="standard", template=None, platform="c
|
|
|
1046
1030
|
"--mode", mode,
|
|
1047
1031
|
]
|
|
1048
1032
|
if template:
|
|
1049
|
-
|
|
1033
|
+
template_path = Path(template)
|
|
1034
|
+
if not template_path.is_absolute():
|
|
1035
|
+
template_path = Path("dev-pipeline/templates") / template_path
|
|
1036
|
+
args.extend(["--template", str(template_path)])
|
|
1050
1037
|
old_argv = os.sys.argv
|
|
1051
1038
|
old_platform = os.environ.get("PRIZMKIT_PLATFORM")
|
|
1052
1039
|
try:
|
|
@@ -1065,14 +1052,23 @@ def _render_feature_prompt(tmp_path, mode="standard", template=None, platform="c
|
|
|
1065
1052
|
return output.read_text(encoding="utf-8")
|
|
1066
1053
|
|
|
1067
1054
|
|
|
1068
|
-
def
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1055
|
+
def _ensure_skill_files(project, platforms=None):
|
|
1056
|
+
"""Create minimal skill files so platform resolution succeeds."""
|
|
1057
|
+
if platforms is None:
|
|
1058
|
+
platforms = ("claude", "codex")
|
|
1059
|
+
for plat in platforms:
|
|
1060
|
+
if plat == "codex":
|
|
1061
|
+
skill_dir = project / ".agents" / "skills" / "prizmkit"
|
|
1062
|
+
skill_dir.mkdir(parents=True, exist_ok=True)
|
|
1063
|
+
(skill_dir / "SKILL.md").write_text("skill\n", encoding="utf-8")
|
|
1064
|
+
elif plat == "codebuddy":
|
|
1065
|
+
skill_dir = project / ".codebuddy" / "skills" / "prizmkit"
|
|
1066
|
+
skill_dir.mkdir(parents=True, exist_ok=True)
|
|
1067
|
+
(skill_dir / "SKILL.md").write_text("skill\n", encoding="utf-8")
|
|
1068
|
+
else:
|
|
1069
|
+
command_dir = project / ".claude" / "commands"
|
|
1070
|
+
command_dir.mkdir(parents=True, exist_ok=True)
|
|
1071
|
+
(command_dir / "prizmkit.md").write_text("skill\n", encoding="utf-8")
|
|
1076
1072
|
|
|
1077
1073
|
|
|
1078
1074
|
def _render_bugfix_prompt(
|
|
@@ -1087,7 +1083,7 @@ def _render_bugfix_prompt(
|
|
|
1087
1083
|
(project / ".prizmkit" / "config.json").write_text(
|
|
1088
1084
|
json.dumps({"platform": platform, "ai_cli": platform}), encoding="utf-8"
|
|
1089
1085
|
)
|
|
1090
|
-
|
|
1086
|
+
_ensure_skill_files(project)
|
|
1091
1087
|
bug_list = project / ".prizmkit" / "plans" / "bug-fix-list.json"
|
|
1092
1088
|
bug_list.parent.mkdir(parents=True)
|
|
1093
1089
|
bug = {"id": "B-001", "title": "Broken", "description": "Fix it", "acceptance_criteria": ["Works"]}
|
|
@@ -1140,7 +1136,7 @@ def _render_refactor_prompt(tmp_path, platform="claude", explicit_platform=None,
|
|
|
1140
1136
|
(project / ".prizmkit" / "config.json").write_text(
|
|
1141
1137
|
json.dumps({"platform": platform, "ai_cli": platform}), encoding="utf-8"
|
|
1142
1138
|
)
|
|
1143
|
-
|
|
1139
|
+
_ensure_skill_files(project)
|
|
1144
1140
|
refactor_list = project / ".prizmkit" / "plans" / "refactor-list.json"
|
|
1145
1141
|
refactor_list.parent.mkdir(parents=True)
|
|
1146
1142
|
refactor = {
|
|
@@ -1190,6 +1186,100 @@ def _render_refactor_prompt(tmp_path, platform="claude", explicit_platform=None,
|
|
|
1190
1186
|
return output.read_text(encoding="utf-8")
|
|
1191
1187
|
|
|
1192
1188
|
|
|
1189
|
+
class TestFeaturePromptUnifiedFullGuidance:
|
|
1190
|
+
def test_default_sections_prompt_uses_full_guidance_for_all_complexities(self, tmp_path):
|
|
1191
|
+
prompts = {
|
|
1192
|
+
complexity: _render_feature_prompt(
|
|
1193
|
+
tmp_path / f"complexity-{complexity}",
|
|
1194
|
+
mode="lite",
|
|
1195
|
+
complexity=complexity,
|
|
1196
|
+
)
|
|
1197
|
+
for complexity in ("low", "medium", "high", "critical")
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
for complexity, prompt in prompts.items():
|
|
1201
|
+
assert f"**Complexity**: {complexity}" in prompt
|
|
1202
|
+
assert "## Task Contract" in prompt
|
|
1203
|
+
assert "## Workflow Checkpoint System" in prompt
|
|
1204
|
+
assert "### Specify + Plan (Full Workflow)" in prompt
|
|
1205
|
+
assert "### Plan Self-Check — Orchestrator Direct" in prompt
|
|
1206
|
+
assert "### Scoped Feature Test Gate — PrizmKit Test" in prompt
|
|
1207
|
+
assert "## Test Failure Recovery Protocol" in prompt
|
|
1208
|
+
assert "Boundary Matrix" in prompt
|
|
1209
|
+
assert "### Browser Verification — MANDATORY" in prompt
|
|
1210
|
+
assert "### TERMINAL STOP — Commit Completed" in prompt
|
|
1211
|
+
assert "# Dev-Pipeline Session Bootstrap — Tier 1" not in prompt
|
|
1212
|
+
assert "# Dev-Pipeline Session Bootstrap — Tier 2" not in prompt
|
|
1213
|
+
assert "### Phase 0: SKIP (already initialized)" not in prompt
|
|
1214
|
+
|
|
1215
|
+
# The complexity value remains planning metadata, but guidance markers are
|
|
1216
|
+
# the same full/tier3-equivalent composition for every complexity.
|
|
1217
|
+
def test_cli_mode_override_does_not_downgrade_default_sections_guidance(self, tmp_path):
|
|
1218
|
+
prompt = _render_feature_prompt(tmp_path / "mode-lite", mode="lite", complexity="low")
|
|
1219
|
+
|
|
1220
|
+
assert "{{PIPELINE_MODE}}" not in prompt
|
|
1221
|
+
assert "### Specify + Plan (Full Workflow)" in prompt
|
|
1222
|
+
assert "### Plan Self-Check — Orchestrator Direct" in prompt
|
|
1223
|
+
assert "### Phase 0: SKIP (already initialized)" not in prompt
|
|
1224
|
+
|
|
1225
|
+
def test_explicit_custom_template_override_still_renders(self, tmp_path):
|
|
1226
|
+
custom = tmp_path / "custom-template.md"
|
|
1227
|
+
custom.write_text(
|
|
1228
|
+
"CUSTOM {{FEATURE_ID}} {{FEATURE_TITLE}} {{COMPLEXITY}} {{IF_FRESH_START}}fresh{{END_IF_FRESH_START}}",
|
|
1229
|
+
encoding="utf-8",
|
|
1230
|
+
)
|
|
1231
|
+
|
|
1232
|
+
prompt = _render_feature_prompt(
|
|
1233
|
+
tmp_path / "custom-template-project",
|
|
1234
|
+
mode="lite",
|
|
1235
|
+
complexity="low",
|
|
1236
|
+
template=custom,
|
|
1237
|
+
)
|
|
1238
|
+
|
|
1239
|
+
assert prompt == "CUSTOM F-123 Prompt Cleanup low fresh"
|
|
1240
|
+
|
|
1241
|
+
def test_fallback_without_sections_prefers_tier3_then_bootstrap_prompt(self, tmp_path, monkeypatch):
|
|
1242
|
+
import generate_bootstrap_prompt as gbp
|
|
1243
|
+
|
|
1244
|
+
original_isdir = os.path.isdir
|
|
1245
|
+
original_isfile = os.path.isfile
|
|
1246
|
+
requested = []
|
|
1247
|
+
|
|
1248
|
+
def fake_isdir(path):
|
|
1249
|
+
if str(path).endswith(os.path.join("templates", "sections")):
|
|
1250
|
+
return False
|
|
1251
|
+
return original_isdir(path)
|
|
1252
|
+
|
|
1253
|
+
def fake_isfile(path):
|
|
1254
|
+
requested.append(Path(path).name)
|
|
1255
|
+
return original_isfile(path)
|
|
1256
|
+
|
|
1257
|
+
monkeypatch.setattr(gbp.os.path, "isdir", fake_isdir)
|
|
1258
|
+
monkeypatch.setattr(gbp.os.path, "isfile", fake_isfile)
|
|
1259
|
+
prompt = _render_feature_prompt(tmp_path / "fallback-tier3", mode="lite", complexity="low")
|
|
1260
|
+
|
|
1261
|
+
assert requested.index("bootstrap-tier3.md") < requested.index("bootstrap-prompt.md") if "bootstrap-prompt.md" in requested else True
|
|
1262
|
+
assert "# Dev-Pipeline Session Bootstrap — Tier 3" in prompt
|
|
1263
|
+
assert "bootstrap-tier1.md" not in requested
|
|
1264
|
+
assert "bootstrap-tier2.md" not in requested
|
|
1265
|
+
|
|
1266
|
+
requested.clear()
|
|
1267
|
+
|
|
1268
|
+
def fake_isfile_without_tier3(path):
|
|
1269
|
+
requested.append(Path(path).name)
|
|
1270
|
+
if Path(path).name == "bootstrap-tier3.md":
|
|
1271
|
+
return False
|
|
1272
|
+
return original_isfile(path)
|
|
1273
|
+
|
|
1274
|
+
monkeypatch.setattr(gbp.os.path, "isfile", fake_isfile_without_tier3)
|
|
1275
|
+
prompt = _render_feature_prompt(tmp_path / "fallback-bootstrap-prompt", mode="lite", complexity="low")
|
|
1276
|
+
|
|
1277
|
+
assert "bootstrap-tier3.md" in requested
|
|
1278
|
+
assert "bootstrap-tier1.md" not in requested
|
|
1279
|
+
assert "bootstrap-tier2.md" not in requested
|
|
1280
|
+
assert "# Dev-Pipeline Fallback Bootstrap Prompt" in prompt
|
|
1281
|
+
|
|
1282
|
+
|
|
1193
1283
|
class TestBrowserBlockingPromptPolicy:
|
|
1194
1284
|
def test_feature_bugfix_refactor_blocking_browser_policy_stops_before_commit(self, tmp_path):
|
|
1195
1285
|
browser_interaction = {
|
|
@@ -1282,21 +1372,24 @@ class TestHeadlessPromptCleanupF033:
|
|
|
1282
1372
|
assert "which " not in prompt # no which-command shell glue
|
|
1283
1373
|
assert "python3 {{INIT_SCRIPT_PATH}}" not in prompt
|
|
1284
1374
|
|
|
1285
|
-
def
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1375
|
+
def test_retained_tier3_template_is_clean_when_rendered(self, tmp_path):
|
|
1376
|
+
prompt = _render_feature_prompt(tmp_path / "bootstrap-tier3.md", mode="full", template="bootstrap-tier3.md")
|
|
1377
|
+
for forbidden in HEADLESS_FORBIDDEN_PROMPT_STRINGS:
|
|
1378
|
+
assert forbidden not in prompt
|
|
1379
|
+
assert "prizmkit-test-gate.py" not in prompt
|
|
1380
|
+
assert "python3 {{INIT_SCRIPT_PATH}}" not in prompt
|
|
1381
|
+
assert "which playwright-cli" not in prompt
|
|
1382
|
+
assert "lsof -ti" not in prompt
|
|
1383
|
+
assert "sed -nE" not in prompt
|
|
1384
|
+
assert ".prizmkit-test-started" in prompt
|
|
1385
|
+
assert "{{RUNTIME_HELPER_CMD}}" not in prompt
|
|
1386
|
+
assert "prizmkit-runtime-helper.py" in prompt
|
|
1387
|
+
|
|
1388
|
+
def test_retired_tier1_tier2_templates_are_removed(self):
|
|
1389
|
+
assert not Path("dev-pipeline/templates/bootstrap-tier1.md").exists()
|
|
1390
|
+
assert not Path("dev-pipeline/templates/bootstrap-tier2.md").exists()
|
|
1391
|
+
|
|
1392
|
+
def test_retained_tier3_template_with_browser_blocks_is_shell_free(self, tmp_path):
|
|
1300
1393
|
forbidden = [
|
|
1301
1394
|
"python3 {{INIT_SCRIPT_PATH}}",
|
|
1302
1395
|
"which playwright-cli",
|
|
@@ -1308,21 +1401,15 @@ class TestHeadlessPromptCleanupF033:
|
|
|
1308
1401
|
"opencli doctor 2>/dev/null ||",
|
|
1309
1402
|
"echo \"=== playwright-cli ===\" &&",
|
|
1310
1403
|
]
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
template=template,
|
|
1321
|
-
browser_interaction={"tool": "auto", "verify_steps": ["Open the page"]},
|
|
1322
|
-
)
|
|
1323
|
-
assert "prizmkit-runtime-helper.py" in prompt
|
|
1324
|
-
for snippet in forbidden:
|
|
1325
|
-
assert snippet not in prompt
|
|
1404
|
+
prompt = _render_feature_prompt(
|
|
1405
|
+
tmp_path / "browser-bootstrap-tier3.md",
|
|
1406
|
+
mode="full",
|
|
1407
|
+
template="bootstrap-tier3.md",
|
|
1408
|
+
browser_interaction={"tool": "auto", "verify_steps": ["Open the page"]},
|
|
1409
|
+
)
|
|
1410
|
+
assert "prizmkit-runtime-helper.py" in prompt
|
|
1411
|
+
for snippet in forbidden:
|
|
1412
|
+
assert snippet not in prompt
|
|
1326
1413
|
|
|
1327
1414
|
def test_bugfix_refactor_share_claude_platform_resolution(self, tmp_path, monkeypatch):
|
|
1328
1415
|
from generate_bugfix_prompt import build_replacements as bugfix_build_replacements
|
|
@@ -1334,7 +1421,7 @@ class TestHeadlessPromptCleanupF033:
|
|
|
1334
1421
|
(bug_project / ".prizmkit" / "config.json").write_text(
|
|
1335
1422
|
json.dumps({"platform": "claude", "ai_cli": "claude"}), encoding="utf-8"
|
|
1336
1423
|
)
|
|
1337
|
-
|
|
1424
|
+
_ensure_skill_files(bug_project)
|
|
1338
1425
|
args = Namespace(
|
|
1339
1426
|
bug_id="B-001", session_id="session-1", run_id="run-1",
|
|
1340
1427
|
retry_count="0", resume_phase="null", state_dir=None,
|
|
@@ -1346,15 +1433,15 @@ class TestHeadlessPromptCleanupF033:
|
|
|
1346
1433
|
)
|
|
1347
1434
|
refactor_prompt = _render_refactor_prompt(tmp_path / "refactor-mixed", platform="claude")
|
|
1348
1435
|
|
|
1349
|
-
assert
|
|
1350
|
-
assert "
|
|
1436
|
+
assert "{{" + "REVIEWER_" + "SUBAGENT_PATH" + "}}" not in replacements
|
|
1437
|
+
assert "reviewer-agent-prompt.md" in refactor_prompt
|
|
1351
1438
|
|
|
1352
1439
|
def test_bugfix_refactor_explicit_codex_override(self, tmp_path, monkeypatch):
|
|
1353
1440
|
from generate_bugfix_prompt import build_replacements as bugfix_build_replacements
|
|
1354
1441
|
|
|
1355
1442
|
bug_project = tmp_path / "bugfix-codex-replacements"
|
|
1356
1443
|
bug_project.mkdir()
|
|
1357
|
-
|
|
1444
|
+
_ensure_skill_files(bug_project)
|
|
1358
1445
|
monkeypatch.setenv("PRIZMKIT_PLATFORM", "codex")
|
|
1359
1446
|
args = Namespace(
|
|
1360
1447
|
bug_id="B-001", session_id="session-1", run_id="run-1",
|
|
@@ -1367,8 +1454,8 @@ class TestHeadlessPromptCleanupF033:
|
|
|
1367
1454
|
)
|
|
1368
1455
|
refactor_prompt = _render_refactor_prompt(tmp_path / "refactor-codex", platform="claude", explicit_platform="codex")
|
|
1369
1456
|
|
|
1370
|
-
assert
|
|
1371
|
-
assert "
|
|
1457
|
+
assert "{{" + "REVIEWER_" + "SUBAGENT_PATH" + "}}" not in replacements
|
|
1458
|
+
assert "reviewer-agent-prompt.md" in refactor_prompt
|
|
1372
1459
|
|
|
1373
1460
|
|
|
1374
1461
|
class TestFeatureBootstrapShellExtraction:
|
|
@@ -1427,49 +1514,25 @@ class TestFeatureBootstrapShellExtraction:
|
|
|
1427
1514
|
assert "port check 3000" not in prompt
|
|
1428
1515
|
assert "localhost:3000" not in prompt
|
|
1429
1516
|
|
|
1430
|
-
def
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
for template, mode in cases:
|
|
1437
|
-
prompt = _render_feature_prompt(
|
|
1438
|
-
tmp_path / f"legacy-{template}",
|
|
1439
|
-
mode=mode,
|
|
1440
|
-
template=template,
|
|
1441
|
-
browser_interaction={"tool": "playwright-cli", "verify_steps": ["Open the page"]},
|
|
1442
|
-
)
|
|
1443
|
-
|
|
1444
|
-
self.assert_shell_extracted_operations_removed(prompt)
|
|
1445
|
-
assert "process start --pid-file .prizmkit/state/browser-dev-server.pid" in prompt
|
|
1446
|
-
assert "process cleanup-pid <pid-from-.prizmkit/state/browser-dev-server.pid>" in prompt
|
|
1447
|
-
assert "port check 3000" not in prompt
|
|
1448
|
-
assert "localhost:3000" not in prompt
|
|
1449
|
-
|
|
1450
|
-
def test_legacy_tier_specific_extracted_operations_map_to_helper_commands(self, tmp_path):
|
|
1451
|
-
tier1 = _render_feature_prompt(
|
|
1452
|
-
tmp_path / "legacy-tier1-helper-map",
|
|
1453
|
-
mode="lite",
|
|
1454
|
-
template="bootstrap-tier1.md",
|
|
1455
|
-
)
|
|
1456
|
-
assert "artifact tree . --max-depth 2" in tier1
|
|
1457
|
-
assert "text contains .gitignore --pattern \"/binary-name\"" in tier1
|
|
1458
|
-
assert "NEEDS_IGNORE_ENTRY" in tier1
|
|
1459
|
-
|
|
1460
|
-
tier2 = _render_feature_prompt(
|
|
1461
|
-
tmp_path / "legacy-tier2-helper-map",
|
|
1462
|
-
mode="standard",
|
|
1463
|
-
template="bootstrap-tier2.md",
|
|
1517
|
+
def test_rendered_retained_tier3_feature_prompt_uses_runtime_helper_not_extracted_bash(self, tmp_path):
|
|
1518
|
+
prompt = _render_feature_prompt(
|
|
1519
|
+
tmp_path / "legacy-bootstrap-tier3.md",
|
|
1520
|
+
mode="full",
|
|
1521
|
+
template="bootstrap-tier3.md",
|
|
1522
|
+
browser_interaction={"tool": "playwright-cli", "verify_steps": ["Open the page"]},
|
|
1464
1523
|
)
|
|
1465
|
-
assert "artifact exists .prizmkit/specs/123-prompt-cleanup/failure-log.md" in tier2
|
|
1466
|
-
assert "artifact tree . --max-depth 2" in tier2
|
|
1467
|
-
assert "text count .prizmkit/specs/123-prompt-cleanup/plan.md --pattern \"- [ ]\"" in tier2
|
|
1468
1524
|
|
|
1525
|
+
self.assert_shell_extracted_operations_removed(prompt)
|
|
1526
|
+
assert "process start --pid-file .prizmkit/state/browser-dev-server.pid" in prompt
|
|
1527
|
+
assert "process cleanup-pid <pid-from-.prizmkit/state/browser-dev-server.pid>" in prompt
|
|
1528
|
+
assert "port check 3000" not in prompt
|
|
1529
|
+
assert "localhost:3000" not in prompt
|
|
1530
|
+
|
|
1531
|
+
def test_retained_tier3_specific_extracted_operations_map_to_helper_commands(self, tmp_path):
|
|
1469
1532
|
tier3 = _render_feature_prompt(
|
|
1470
1533
|
tmp_path / "legacy-tier3-helper-map",
|
|
1471
1534
|
mode="full",
|
|
1472
|
-
|
|
1535
|
+
template="bootstrap-tier3.md",
|
|
1473
1536
|
)
|
|
1474
1537
|
assert "text search . --pattern \"123-prompt-cleanup\" --json" in tier3
|
|
1475
1538
|
assert "text count .prizmkit/specs/123-prompt-cleanup/plan.md --pattern \"- [ ]\"" in tier3
|
|
@@ -196,7 +196,7 @@ class TestExplicitProjectRoot:
|
|
|
196
196
|
"sessions" / "session-1" / "session-status.json"
|
|
197
197
|
)
|
|
198
198
|
assert not replacements["{{SESSION_STATUS_PATH}}"].startswith(str(execution_root.resolve()))
|
|
199
|
-
assert
|
|
199
|
+
assert "{{" + "DEV_" + "SUBAGENT_PATH" + "}}" not in replacements
|
|
200
200
|
assert replacements["{{SESSION_LOG_PATH}}"].endswith(
|
|
201
201
|
".prizmkit/state/bugfix/B-001/sessions/session-1/logs/session.log"
|
|
202
202
|
)
|
|
@@ -360,7 +360,7 @@ def _render_bugfix_prompt(tmp_path, platform="claude"):
|
|
|
360
360
|
(project / ".prizmkit" / "config.json").write_text(
|
|
361
361
|
json.dumps({"platform": platform, "ai_cli": platform}), encoding="utf-8"
|
|
362
362
|
)
|
|
363
|
-
|
|
363
|
+
_ensure_skill_files(project)
|
|
364
364
|
bug_list = project / ".prizmkit" / "plans" / "bug-fix-list.json"
|
|
365
365
|
bug_list.parent.mkdir(parents=True)
|
|
366
366
|
bug_list.write_text(json.dumps({
|
|
@@ -399,17 +399,23 @@ def _render_bugfix_prompt(tmp_path, platform="claude"):
|
|
|
399
399
|
return output.read_text(encoding="utf-8")
|
|
400
400
|
|
|
401
401
|
|
|
402
|
-
def
|
|
403
|
-
"""Create minimal
|
|
402
|
+
def _ensure_skill_files(project, platforms=None):
|
|
403
|
+
"""Create minimal skill files so platform resolution succeeds."""
|
|
404
404
|
if platforms is None:
|
|
405
405
|
platforms = ("claude", "codex")
|
|
406
406
|
for plat in platforms:
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
407
|
+
if plat == "codex":
|
|
408
|
+
skill_dir = project / ".agents" / "skills" / "prizmkit"
|
|
409
|
+
skill_dir.mkdir(parents=True, exist_ok=True)
|
|
410
|
+
(skill_dir / "SKILL.md").write_text("skill\n", encoding="utf-8")
|
|
411
|
+
elif plat == "codebuddy":
|
|
412
|
+
skill_dir = project / ".codebuddy" / "skills" / "prizmkit"
|
|
413
|
+
skill_dir.mkdir(parents=True, exist_ok=True)
|
|
414
|
+
(skill_dir / "SKILL.md").write_text("skill\n", encoding="utf-8")
|
|
415
|
+
else:
|
|
416
|
+
command_dir = project / ".claude" / "commands"
|
|
417
|
+
command_dir.mkdir(parents=True, exist_ok=True)
|
|
418
|
+
(command_dir / "prizmkit.md").write_text("skill\n", encoding="utf-8")
|
|
413
419
|
|
|
414
420
|
|
|
415
421
|
class TestBugfixBootstrapShellExtraction:
|
|
@@ -82,10 +82,7 @@ class TestExplicitProjectRoot:
|
|
|
82
82
|
)
|
|
83
83
|
|
|
84
84
|
assert replacements["{{PROJECT_ROOT}}"] == str(project.resolve())
|
|
85
|
-
assert
|
|
86
|
-
".claude/agents/prizm-dev-team-reviewer.md"
|
|
87
|
-
)
|
|
88
|
-
assert replacements["{{REVIEWER_SUBAGENT_PATH}}"].startswith(str(project.resolve()))
|
|
85
|
+
assert "{{" + "REVIEWER_" + "SUBAGENT_PATH" + "}}" not in replacements
|
|
89
86
|
assert replacements["{{SESSION_STATUS_PATH}}"] == str(
|
|
90
87
|
project / ".prizmkit" / "state" / "refactor" / "R-001" /
|
|
91
88
|
"sessions" / "session-1" / "session-status.json"
|
|
@@ -126,7 +123,7 @@ class TestExplicitProjectRoot:
|
|
|
126
123
|
"sessions" / "session-1" / "session-status.json"
|
|
127
124
|
)
|
|
128
125
|
assert not replacements["{{SESSION_STATUS_PATH}}"].startswith(str(execution_root.resolve()))
|
|
129
|
-
assert
|
|
126
|
+
assert "{{" + "DEV_" + "SUBAGENT_PATH" + "}}" not in replacements
|
|
130
127
|
assert "### Checkpoint Update Helper" in replacements["{{CHECKPOINT_SYSTEM}}"]
|
|
131
128
|
assert "{{CHECKPOINT_PYTHON_CMD}}" in replacements["{{CHECKPOINT_SYSTEM}}"]
|
|
132
129
|
assert "pipeline progress mechanism" not in replacements["{{CHECKPOINT_SYSTEM}}"]
|
|
@@ -234,14 +231,6 @@ def _render_refactor_prompt_full(tmp_path, platform="claude"):
|
|
|
234
231
|
(project / ".prizmkit" / "config.json").write_text(
|
|
235
232
|
json.dumps({"platform": platform, "ai_cli": platform}), encoding="utf-8"
|
|
236
233
|
)
|
|
237
|
-
# Ensure agent files
|
|
238
|
-
for plat in ("claude", "codex"):
|
|
239
|
-
platform_dir = ".codex" if plat == "codex" else ".claude"
|
|
240
|
-
suffix = ".toml" if plat == "codex" else ".md"
|
|
241
|
-
agents_dir = project / platform_dir / "agents"
|
|
242
|
-
agents_dir.mkdir(parents=True, exist_ok=True)
|
|
243
|
-
for name in ("dev", "reviewer"):
|
|
244
|
-
(agents_dir / f"prizm-dev-team-{name}{suffix}").write_text("agent\n", encoding="utf-8")
|
|
245
234
|
|
|
246
235
|
refactor_list = project / ".prizmkit" / "plans" / "refactor-list.json"
|
|
247
236
|
refactor_list.parent.mkdir(parents=True)
|