prizmkit 1.1.110 → 1.1.112
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/agents/prizm-dev-team-reviewer.md +15 -0
- package/bundled/dev-pipeline/prizmkit_runtime/interoperability.py +1 -0
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +55 -76
- package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +283 -421
- package/bundled/dev-pipeline/scripts/generate-recovery-prompt.py +1 -1
- package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +259 -481
- package/bundled/dev-pipeline/scripts/init-bugfix-pipeline.py +34 -0
- package/bundled/dev-pipeline/scripts/init-pipeline.py +12 -0
- package/bundled/dev-pipeline/scripts/init-refactor-pipeline.py +24 -1
- package/bundled/dev-pipeline/scripts/prompt_framework.py +312 -0
- package/bundled/dev-pipeline/scripts/update-bug-status.py +87 -20
- package/bundled/dev-pipeline/scripts/update-feature-status.py +82 -16
- package/bundled/dev-pipeline/scripts/update-refactor-status.py +68 -28
- package/bundled/dev-pipeline/scripts/utils.py +171 -0
- package/bundled/dev-pipeline/templates/bootstrap-prompt.md +1 -1
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +10 -18
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +14 -25
- package/bundled/dev-pipeline/templates/bug-fix-list-schema.json +9 -1
- package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +11 -8
- package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +122 -182
- package/bundled/dev-pipeline/templates/sections/bugfix-artifacts.md +16 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-critical-paths.md +12 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-mission.md +9 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-commit-report.md +31 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-critic.md +22 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-diagnose-plan.md +23 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-implement.md +20 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-init.md +9 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-manual-verification.md +15 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-phase-review.md +29 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-reminders.md +11 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-session-context.md +7 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-session-status.md +31 -0
- package/bundled/dev-pipeline/templates/sections/bugfix-task-contract.md +40 -0
- package/bundled/dev-pipeline/templates/sections/checkpoint-system.md +1 -1
- package/bundled/dev-pipeline/templates/sections/failure-capture.md +2 -2
- package/bundled/dev-pipeline/templates/sections/phase-browser-verification-auto.md +1 -1
- package/bundled/dev-pipeline/templates/sections/refactor-artifacts.md +17 -0
- package/bundled/dev-pipeline/templates/sections/refactor-critical-paths.md +13 -0
- package/bundled/dev-pipeline/templates/sections/refactor-mission.md +9 -0
- package/bundled/dev-pipeline/templates/sections/refactor-phase-commit-report.md +37 -0
- package/bundled/dev-pipeline/templates/sections/refactor-phase-critic.md +22 -0
- package/bundled/dev-pipeline/templates/sections/refactor-phase-implement.md +16 -0
- package/bundled/dev-pipeline/templates/sections/refactor-phase-init.md +9 -0
- package/bundled/dev-pipeline/templates/sections/refactor-phase-plan.md +22 -0
- package/bundled/dev-pipeline/templates/sections/refactor-phase-review.md +19 -0
- package/bundled/dev-pipeline/templates/sections/refactor-reminders.md +11 -0
- package/bundled/dev-pipeline/templates/sections/refactor-session-context.md +7 -0
- package/bundled/dev-pipeline/templates/sections/refactor-session-status.md +28 -0
- package/bundled/dev-pipeline/templates/sections/refactor-task-contract.md +52 -0
- package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +122 -5
- package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +122 -0
- package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +124 -0
- package/bundled/dev-pipeline/tests/test_python_runner_parity.py +197 -0
- package/bundled/dev-pipeline/tests/test_unified_cli.py +7 -3
- package/bundled/dev-pipeline/tests/test_utils.py +66 -1
- package/bundled/skills/_metadata.json +1 -1
- package/bundled/skills/app-planner/SKILL.md +8 -7
- package/bundled/skills/app-planner/references/project-brief-guide.md +2 -2
- package/bundled/skills/app-planner/references/rules/backend/derivation-rules.md +1 -1
- package/bundled/skills/app-planner/references/rules/frontend/derivation-rules.md +1 -1
- package/bundled/skills/app-planner/references/rules-configuration.md +53 -26
- package/bundled/skills/bug-fix-workflow/SKILL.md +191 -336
- package/bundled/skills/bug-planner/SKILL.md +6 -5
- package/bundled/skills/bug-planner/references/critic-and-verification.md +3 -3
- package/bundled/skills/bug-planner/references/schema-validation.md +2 -1
- package/bundled/skills/bug-planner/scripts/validate-bug-list.py +30 -1
- package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +16 -16
- package/bundled/skills/bugfix-pipeline-launcher/references/configuration.md +2 -2
- package/bundled/skills/feature-pipeline-launcher/SKILL.md +19 -11
- package/bundled/skills/feature-planner/SKILL.md +9 -11
- package/bundled/skills/feature-planner/assets/planning-guide.md +1 -1
- package/bundled/skills/feature-planner/references/decomposition-patterns.md +1 -1
- package/bundled/skills/feature-planner/references/error-recovery.md +2 -1
- package/bundled/skills/feature-planner/references/incremental-feature-planning.md +2 -2
- package/bundled/skills/feature-planner/references/new-project-planning.md +35 -39
- package/bundled/skills/feature-planner/scripts/validate-and-generate.py +1 -1
- package/bundled/skills/feature-workflow/SKILL.md +169 -298
- package/bundled/skills/prizmkit/SKILL.md +103 -57
- package/bundled/skills/prizmkit-code-review/SKILL.md +97 -94
- package/bundled/skills/prizmkit-code-review/references/review-report-template.md +1 -0
- package/bundled/skills/prizmkit-code-review/references/reviewer-agent-prompt.md +13 -1
- package/bundled/skills/prizmkit-committer/SKILL.md +59 -47
- package/bundled/skills/prizmkit-deploy/SKILL.md +162 -381
- package/bundled/skills/prizmkit-deploy/references/ssh-adapter-flow.md +220 -0
- package/bundled/skills/prizmkit-implement/SKILL.md +51 -40
- package/bundled/skills/prizmkit-init/SKILL.md +4 -3
- package/bundled/skills/prizmkit-plan/SKILL.md +85 -70
- package/bundled/skills/prizmkit-prizm-docs/SKILL.md +94 -73
- package/bundled/skills/prizmkit-prizm-docs/assets/prizm-docs-format.md +20 -18
- package/bundled/skills/prizmkit-prizm-docs/references/op-update.md +18 -14
- package/bundled/skills/prizmkit-retrospective/SKILL.md +56 -48
- package/bundled/skills/prizmkit-retrospective/references/structural-sync-steps.md +79 -27
- package/bundled/skills/prizmkit-test/SKILL.md +138 -141
- package/bundled/skills/prizmkit-test/references/examples.md +10 -8
- package/bundled/skills/prizmkit-test/references/test-generation-steps.md +1 -1
- package/bundled/skills/prizmkit-test/references/test-report-template.md +2 -2
- package/bundled/skills/recovery-workflow/SKILL.md +195 -256
- package/bundled/skills/recovery-workflow/evals/evals.json +21 -13
- package/bundled/skills/recovery-workflow/references/detection.md +48 -39
- package/bundled/skills/recovery-workflow/scripts/detect-recovery-state.py +258 -322
- package/bundled/skills/refactor-pipeline-launcher/SKILL.md +29 -11
- package/bundled/skills/refactor-planner/SKILL.md +2 -2
- package/bundled/skills/refactor-planner/references/behavior-preservation.md +24 -19
- package/bundled/skills/refactor-planner/references/fast-path.md +2 -4
- package/bundled/skills/refactor-planner/references/planning-phases.md +2 -2
- package/bundled/skills/refactor-workflow/SKILL.md +173 -307
- package/package.json +1 -1
- package/src/scaffold.js +5 -0
- package/bundled/dev-pipeline/templates/agent-prompts/reviewer-review.md +0 -6
- package/bundled/skills/feature-workflow/references/brainstorm-guide.md +0 -137
- package/bundled/skills/refactor-workflow/references/brainstorm-guide.md +0 -116
|
@@ -10,6 +10,7 @@ from pathlib import Path
|
|
|
10
10
|
from generate_bootstrap_prompt import (
|
|
11
11
|
ACTIVE_AGENT_PROMPTS,
|
|
12
12
|
compute_feature_slug,
|
|
13
|
+
detect_test_commands,
|
|
13
14
|
find_feature,
|
|
14
15
|
format_acceptance_criteria,
|
|
15
16
|
format_ac_checklist,
|
|
@@ -883,7 +884,8 @@ class TestDirectOrchestratorImplementationPrompts:
|
|
|
883
884
|
assert FORBIDDEN_DEV_FIX_PLACEHOLDER not in replacements
|
|
884
885
|
assert FORBIDDEN_DEV_RESUME_PLACEHOLDER not in replacements
|
|
885
886
|
assert "{{AGENT_PROMPT_CRITIC_PLAN_CHALLENGE}}" in replacements
|
|
886
|
-
assert "{{AGENT_PROMPT_REVIEWER_REVIEW}}" in replacements
|
|
887
|
+
assert "{{AGENT_PROMPT_REVIEWER_REVIEW}}" not in replacements
|
|
888
|
+
assert (templates_dir / "agent-prompts" / "reviewer-review.md").exists() is False
|
|
887
889
|
assert (templates_dir / "agent-prompts" / "dev-implement.md").exists() is False
|
|
888
890
|
assert (templates_dir / "agent-prompts" / FORBIDDEN_DEV_FIX_PROMPT).exists() is False
|
|
889
891
|
assert (templates_dir / "agent-prompts" / FORBIDDEN_DEV_RESUME_PROMPT).exists() is False
|
|
@@ -922,9 +924,19 @@ class TestDirectOrchestratorImplementationPrompts:
|
|
|
922
924
|
assert "Implement — Orchestrator Direct" in rendered
|
|
923
925
|
assert "Spawn Dev subagent" not in rendered
|
|
924
926
|
assert "Spawn Dev agent" not in rendered
|
|
927
|
+
assert "Spawn Reviewer agent" not in rendered
|
|
928
|
+
assert "Reviewer Agent Def" not in rendered
|
|
929
|
+
assert "subagent_type=\"prizm-dev-team-reviewer\"" not in rendered
|
|
925
930
|
assert "Implement — Dev" not in rendered
|
|
926
931
|
assert "{{AGENT_PROMPT_DEV_IMPLEMENT}}" not in rendered
|
|
932
|
+
assert "{{AGENT_PROMPT_REVIEWER_REVIEW}}" not in rendered
|
|
933
|
+
assert "reviewer-review.md" not in rendered
|
|
927
934
|
assert "dev-implement.md" not in rendered
|
|
935
|
+
assert "Bug Fix Documentation Policy" not in rendered
|
|
936
|
+
assert "For bug-fix sessions" not in rendered
|
|
937
|
+
assert "fix(<scope>)" not in rendered
|
|
938
|
+
assert "port check 3000" not in rendered
|
|
939
|
+
assert "localhost:3000" not in rendered
|
|
928
940
|
assert FORBIDDEN_REVIEW_DEV_FIX not in rendered
|
|
929
941
|
assert FORBIDDEN_REVIEWER_DEV_SPAWN not in rendered
|
|
930
942
|
assert FORBIDDEN_EXPLORE_SUBAGENT not in rendered
|
|
@@ -1214,6 +1226,19 @@ class TestHeadlessPromptCleanupF033:
|
|
|
1214
1226
|
assert ".prizmkit-test-started" in prompt
|
|
1215
1227
|
assert "{{RUNTIME_HELPER_CMD}}" not in prompt
|
|
1216
1228
|
assert "prizmkit-runtime-helper.py" in prompt
|
|
1229
|
+
# Anti-Bash guardrails for bugfix/refactor branches (F-039)
|
|
1230
|
+
if "Bug ID" in prompt:
|
|
1231
|
+
assert "{{RUNTIME_HELPER_CMD}}" not in prompt
|
|
1232
|
+
assert "prizmkit-runtime-helper.py" in prompt
|
|
1233
|
+
assert "2>/dev/null" not in prompt
|
|
1234
|
+
assert "lsof -ti" not in prompt
|
|
1235
|
+
assert "which " not in prompt # no which-command shell glue
|
|
1236
|
+
if "Refactor ID" in prompt:
|
|
1237
|
+
assert "{{RUNTIME_HELPER_CMD}}" not in prompt
|
|
1238
|
+
assert "prizmkit-runtime-helper.py" in prompt
|
|
1239
|
+
assert "2>/dev/null" not in prompt
|
|
1240
|
+
assert "lsof -ti" not in prompt
|
|
1241
|
+
assert "which " not in prompt # no which-command shell glue
|
|
1217
1242
|
assert "python3 {{INIT_SCRIPT_PATH}}" not in prompt
|
|
1218
1243
|
|
|
1219
1244
|
def test_legacy_feature_templates_are_clean_when_rendered(self, tmp_path):
|
|
@@ -1297,7 +1322,6 @@ class TestHeadlessPromptCleanupF033:
|
|
|
1297
1322
|
refactor_prompt = _render_refactor_prompt(tmp_path / "refactor-mixed", platform="claude")
|
|
1298
1323
|
|
|
1299
1324
|
assert replacements["{{REVIEWER_SUBAGENT_PATH}}"].endswith(".claude/agents/prizm-dev-team-reviewer.md")
|
|
1300
|
-
assert ".claude/agents/prizm-dev-team-reviewer.md" in refactor_prompt
|
|
1301
1325
|
assert ".codex/agents/prizm-dev-team-reviewer.toml" not in refactor_prompt
|
|
1302
1326
|
|
|
1303
1327
|
def test_bugfix_refactor_explicit_codex_override(self, tmp_path, monkeypatch):
|
|
@@ -1319,7 +1343,6 @@ class TestHeadlessPromptCleanupF033:
|
|
|
1319
1343
|
refactor_prompt = _render_refactor_prompt(tmp_path / "refactor-codex", platform="claude", explicit_platform="codex")
|
|
1320
1344
|
|
|
1321
1345
|
assert replacements["{{REVIEWER_SUBAGENT_PATH}}"].endswith(".codex/agents/prizm-dev-team-reviewer.toml")
|
|
1322
|
-
assert ".codex/agents/prizm-dev-team-reviewer.toml" in refactor_prompt
|
|
1323
1346
|
assert ".claude/agents/prizm-dev-team-reviewer.md" not in refactor_prompt
|
|
1324
1347
|
|
|
1325
1348
|
def test_explicit_codex_env_still_renders_codex_critic_path(self, tmp_path, monkeypatch):
|
|
@@ -1385,7 +1408,9 @@ class TestFeatureBootstrapShellExtraction:
|
|
|
1385
1408
|
assert "executable version opencli --arg=--version" in prompt
|
|
1386
1409
|
assert "process start --pid-file .prizmkit/state/browser-dev-server.pid" in prompt
|
|
1387
1410
|
assert "process cleanup-pid <pid-from-.prizmkit/state/browser-dev-server.pid>" in prompt
|
|
1388
|
-
assert "port check <DEV_PORT>" in prompt
|
|
1411
|
+
assert "port check <DEV_PORT>" in prompt
|
|
1412
|
+
assert "port check 3000" not in prompt
|
|
1413
|
+
assert "localhost:3000" not in prompt
|
|
1389
1414
|
|
|
1390
1415
|
def test_rendered_legacy_tier_feature_prompts_use_runtime_helper_not_extracted_bash(self, tmp_path):
|
|
1391
1416
|
cases = [
|
|
@@ -1405,7 +1430,8 @@ class TestFeatureBootstrapShellExtraction:
|
|
|
1405
1430
|
self.assert_shell_extracted_operations_removed(prompt)
|
|
1406
1431
|
assert "process start --pid-file .prizmkit/state/browser-dev-server.pid" in prompt
|
|
1407
1432
|
assert "process cleanup-pid <pid-from-.prizmkit/state/browser-dev-server.pid>" in prompt
|
|
1408
|
-
assert "port check 3000" in prompt
|
|
1433
|
+
assert "port check 3000" not in prompt
|
|
1434
|
+
assert "localhost:3000" not in prompt
|
|
1409
1435
|
|
|
1410
1436
|
def test_legacy_tier_specific_extracted_operations_map_to_helper_commands(self, tmp_path):
|
|
1411
1437
|
tier1 = _render_feature_prompt(
|
|
@@ -1436,3 +1462,94 @@ class TestFeatureBootstrapShellExtraction:
|
|
|
1436
1462
|
assert "text search . --pattern \"123-prompt-cleanup\" --json" in tier3
|
|
1437
1463
|
assert "text count .prizmkit/specs/123-prompt-cleanup/plan.md --pattern \"- [ ]\"" in tier3
|
|
1438
1464
|
assert "Check if feature already committed by inspecting recent git history" in tier3
|
|
1465
|
+
|
|
1466
|
+
|
|
1467
|
+
# ---------------------------------------------------------------------------
|
|
1468
|
+
# detect_test_commands
|
|
1469
|
+
# ---------------------------------------------------------------------------
|
|
1470
|
+
|
|
1471
|
+
import json as _json
|
|
1472
|
+
|
|
1473
|
+
class TestDetectTestCommands:
|
|
1474
|
+
def test_no_package_json_returns_empty(self, tmp_path):
|
|
1475
|
+
"""When no package.json exists, no npm test emitted."""
|
|
1476
|
+
result = detect_test_commands(str(tmp_path))
|
|
1477
|
+
assert "npm test" not in result
|
|
1478
|
+
assert "pnpm test" not in result
|
|
1479
|
+
assert "yarn test" not in result
|
|
1480
|
+
|
|
1481
|
+
def test_package_json_no_test_script(self, tmp_path):
|
|
1482
|
+
"""package.json exists but has no test script → no npm test emitted."""
|
|
1483
|
+
pkg = tmp_path / "package.json"
|
|
1484
|
+
pkg.write_text(_json.dumps({"name": "test", "scripts": {"start": "node index.js"}}), encoding="utf-8")
|
|
1485
|
+
result = detect_test_commands(str(tmp_path))
|
|
1486
|
+
# Bug: current code returns "npm test" even with no test script
|
|
1487
|
+
assert "npm test" not in result, (
|
|
1488
|
+
"Should NOT emit npm test when package.json has no test script"
|
|
1489
|
+
)
|
|
1490
|
+
|
|
1491
|
+
def test_package_json_with_test_script(self, tmp_path):
|
|
1492
|
+
"""package.json with scripts.test → emits npm test."""
|
|
1493
|
+
pkg = tmp_path / "package.json"
|
|
1494
|
+
pkg.write_text(_json.dumps({"name": "test", "scripts": {"test": "vitest run"}}), encoding="utf-8")
|
|
1495
|
+
result = detect_test_commands(str(tmp_path))
|
|
1496
|
+
# Current code returns "npm test" (hardcoded), but at minimum it should
|
|
1497
|
+
# still return something test-like. After fix, it becomes "npm test"
|
|
1498
|
+
assert "npm test" in result, (
|
|
1499
|
+
"Should emit npm test when package.json has test script"
|
|
1500
|
+
)
|
|
1501
|
+
|
|
1502
|
+
def test_package_json_non_test_scripts_only(self, tmp_path):
|
|
1503
|
+
"""package.json exists but scripts only has non-test entries."""
|
|
1504
|
+
pkg = tmp_path / "package.json"
|
|
1505
|
+
pkg.write_text(_json.dumps({"name": "test", "scripts": {"build": "tsc", "start": "node dist/index.js"}}), encoding="utf-8")
|
|
1506
|
+
result = detect_test_commands(str(tmp_path))
|
|
1507
|
+
assert "npm test" not in result, (
|
|
1508
|
+
"Should NOT emit npm test when no test-related scripts exist"
|
|
1509
|
+
)
|
|
1510
|
+
|
|
1511
|
+
def test_pnpm_detected_from_lockfile(self, tmp_path):
|
|
1512
|
+
"""pnpm-lock.yaml → emits pnpm test when test script exists."""
|
|
1513
|
+
pkg = tmp_path / "package.json"
|
|
1514
|
+
pkg.write_text(_json.dumps({"name": "test", "scripts": {"test": "vitest"}}), encoding="utf-8")
|
|
1515
|
+
(tmp_path / "pnpm-lock.yaml").write_text("", encoding="utf-8")
|
|
1516
|
+
result = detect_test_commands(str(tmp_path))
|
|
1517
|
+
assert "pnpm test" in result
|
|
1518
|
+
|
|
1519
|
+
def test_yarn_detected_from_lockfile(self, tmp_path):
|
|
1520
|
+
"""yarn.lock → emits yarn test when test script exists."""
|
|
1521
|
+
pkg = tmp_path / "package.json"
|
|
1522
|
+
pkg.write_text(_json.dumps({"name": "test", "scripts": {"test": "jest"}}), encoding="utf-8")
|
|
1523
|
+
(tmp_path / "yarn.lock").write_text("", encoding="utf-8")
|
|
1524
|
+
result = detect_test_commands(str(tmp_path))
|
|
1525
|
+
assert "yarn test" in result
|
|
1526
|
+
|
|
1527
|
+
def test_corrupt_package_json_graceful_fallback(self, tmp_path):
|
|
1528
|
+
"""Corrupt/unparseable package.json → skip JS detection gracefully."""
|
|
1529
|
+
(tmp_path / "package.json").write_text("not valid json {{{", encoding="utf-8")
|
|
1530
|
+
result = detect_test_commands(str(tmp_path))
|
|
1531
|
+
# Should not crash, should not emit npm test
|
|
1532
|
+
assert "npm test" not in result
|
|
1533
|
+
|
|
1534
|
+
def test_non_js_detections_preserved(self, tmp_path):
|
|
1535
|
+
"""Go, Rust, Python, Makefile detections unchanged."""
|
|
1536
|
+
(tmp_path / "go.mod").write_text("", encoding="utf-8")
|
|
1537
|
+
(tmp_path / "Cargo.toml").write_text("", encoding="utf-8")
|
|
1538
|
+
(tmp_path / "setup.py").write_text("", encoding="utf-8")
|
|
1539
|
+
makefile = tmp_path / "Makefile"
|
|
1540
|
+
makefile.write_text("test:\n\tpytest\n", encoding="utf-8")
|
|
1541
|
+
result = detect_test_commands(str(tmp_path))
|
|
1542
|
+
assert "go test ./..." in result
|
|
1543
|
+
assert "cargo test" in result
|
|
1544
|
+
assert "pytest" in result
|
|
1545
|
+
assert "make test" in result
|
|
1546
|
+
|
|
1547
|
+
def test_package_json_test_unit_script_only(self, tmp_path):
|
|
1548
|
+
"""package.json with test:unit but no test → fallback to available test script."""
|
|
1549
|
+
pkg = tmp_path / "package.json"
|
|
1550
|
+
pkg.write_text(_json.dumps({"name": "test", "scripts": {"test:unit": "vitest run"}}), encoding="utf-8")
|
|
1551
|
+
(tmp_path / "package-lock.json").write_text("", encoding="utf-8")
|
|
1552
|
+
result = detect_test_commands(str(tmp_path))
|
|
1553
|
+
# Should detect test:unit as a viable test script
|
|
1554
|
+
assert "npm run test:unit" in result
|
|
1555
|
+
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
from argparse import Namespace
|
|
4
4
|
from pathlib import Path
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
5
7
|
|
|
6
8
|
from generate_bugfix_prompt import (
|
|
7
9
|
build_replacements,
|
|
@@ -303,3 +305,123 @@ def test_template_source_is_clean_for_headless_prompt_contract():
|
|
|
303
305
|
content = Path("dev-pipeline/templates/bugfix-bootstrap-prompt.md").read_text(encoding="utf-8")
|
|
304
306
|
for forbidden in HEADLESS_FORBIDDEN_PROMPT_STRINGS:
|
|
305
307
|
assert forbidden not in content
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
# ---------------------------------------------------------------------------
|
|
311
|
+
# Anti-Bash regression guardrails (F-039)
|
|
312
|
+
# Note: grep -n, sed -n, grep -q, wc -l excluded — referenced in bugfix context
|
|
313
|
+
# budget rules as AI tool hints, not as operational shell snippets.
|
|
314
|
+
# | sed (trailing space) only matches pipe-to-sed operational patterns.
|
|
315
|
+
# ---------------------------------------------------------------------------
|
|
316
|
+
|
|
317
|
+
RETIRED_EXTRACTED_SNIPPETS_BUGFIX = [
|
|
318
|
+
"find . -maxdepth",
|
|
319
|
+
"| sed ",
|
|
320
|
+
r"grep -c '^\- \[ \]'",
|
|
321
|
+
"2>/dev/null",
|
|
322
|
+
"/dev/null",
|
|
323
|
+
"$DEV_PORT",
|
|
324
|
+
"$!",
|
|
325
|
+
"$HOME",
|
|
326
|
+
"if [ ",
|
|
327
|
+
"which playwright-cli",
|
|
328
|
+
"which opencli",
|
|
329
|
+
"lsof -ti",
|
|
330
|
+
"xargs",
|
|
331
|
+
" kill -",
|
|
332
|
+
"kill -",
|
|
333
|
+
"|| echo",
|
|
334
|
+
"mkdir -p",
|
|
335
|
+
"touch .prizmkit",
|
|
336
|
+
]
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def _render_bugfix_prompt(tmp_path, platform="claude"):
|
|
340
|
+
"""Render a complete bugfix prompt through the generator."""
|
|
341
|
+
from generate_bugfix_prompt import main as bugfix_main
|
|
342
|
+
|
|
343
|
+
project = tmp_path / "bugfix-anti-bash"
|
|
344
|
+
project.mkdir(parents=True)
|
|
345
|
+
(project / ".prizmkit").mkdir(exist_ok=True)
|
|
346
|
+
(project / ".prizmkit" / "config.json").write_text(
|
|
347
|
+
json.dumps({"platform": platform, "ai_cli": platform}), encoding="utf-8"
|
|
348
|
+
)
|
|
349
|
+
_ensure_agent_files(project)
|
|
350
|
+
bug_list = project / ".prizmkit" / "plans" / "bug-fix-list.json"
|
|
351
|
+
bug_list.parent.mkdir(parents=True)
|
|
352
|
+
bug_list.write_text(json.dumps({
|
|
353
|
+
"bugs": [{"id": "B-001", "title": "Broken", "description": "Fix it",
|
|
354
|
+
"acceptance_criteria": ["Works"]}],
|
|
355
|
+
"global_context": {"language": "Python"},
|
|
356
|
+
}), encoding="utf-8")
|
|
357
|
+
output = project / "bugfix-prompt.md"
|
|
358
|
+
old_argv = os.sys.argv
|
|
359
|
+
old_platform = os.environ.get("PRIZMKIT_PLATFORM")
|
|
360
|
+
try:
|
|
361
|
+
os.environ.pop("PRIZMKIT_PLATFORM", None)
|
|
362
|
+
os.sys.argv = [
|
|
363
|
+
"generate-bugfix-prompt.py",
|
|
364
|
+
"--bug-list", str(bug_list),
|
|
365
|
+
"--bug-id", "B-001",
|
|
366
|
+
"--session-id", "session-1",
|
|
367
|
+
"--run-id", "run-1",
|
|
368
|
+
"--retry-count", "0",
|
|
369
|
+
"--resume-phase", "null",
|
|
370
|
+
"--state-dir", str(project / ".prizmkit" / "state" / "bugfix"),
|
|
371
|
+
"--project-root", str(project),
|
|
372
|
+
"--output", str(output),
|
|
373
|
+
]
|
|
374
|
+
try:
|
|
375
|
+
bugfix_main()
|
|
376
|
+
except SystemExit as exc:
|
|
377
|
+
if exc.code not in (0, None):
|
|
378
|
+
raise
|
|
379
|
+
finally:
|
|
380
|
+
os.sys.argv = old_argv
|
|
381
|
+
if old_platform is None:
|
|
382
|
+
os.environ.pop("PRIZMKIT_PLATFORM", None)
|
|
383
|
+
else:
|
|
384
|
+
os.environ["PRIZMKIT_PLATFORM"] = old_platform
|
|
385
|
+
return output.read_text(encoding="utf-8")
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def _ensure_agent_files(project, platforms=None):
|
|
389
|
+
"""Create minimal agent files so platform resolution succeeds."""
|
|
390
|
+
if platforms is None:
|
|
391
|
+
platforms = ("claude", "codex")
|
|
392
|
+
for plat in platforms:
|
|
393
|
+
platform_dir = ".codex" if plat == "codex" else ".claude"
|
|
394
|
+
suffix = ".toml" if plat == "codex" else ".md"
|
|
395
|
+
agents_dir = project / platform_dir / "agents"
|
|
396
|
+
agents_dir.mkdir(parents=True, exist_ok=True)
|
|
397
|
+
for name in ("dev", "reviewer", "critic"):
|
|
398
|
+
(agents_dir / f"prizm-dev-team-{name}{suffix}").write_text("agent\n", encoding="utf-8")
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
class TestBugfixBootstrapShellExtraction:
|
|
402
|
+
"""Regression guardrails: bugfix rendered prompts and source use helper, not shell."""
|
|
403
|
+
|
|
404
|
+
def test_rendered_bugfix_prompt_uses_runtime_helper_not_extracted_bash(self, tmp_path):
|
|
405
|
+
prompt = _render_bugfix_prompt(tmp_path)
|
|
406
|
+
for snippet in RETIRED_EXTRACTED_SNIPPETS_BUGFIX:
|
|
407
|
+
assert snippet not in prompt, f"Retired shell snippet found in bugfix prompt: {snippet}"
|
|
408
|
+
assert "{{RUNTIME_HELPER_CMD}}" not in prompt
|
|
409
|
+
assert "python" in prompt.lower()
|
|
410
|
+
assert ".prizmkit/dev-pipeline/scripts/prizmkit-runtime-helper.py" in prompt
|
|
411
|
+
assert "artifact ensure-dir .prizmkit/bugfix/B-001" in prompt
|
|
412
|
+
assert "text contains .prizmkit/bugfix/B-001/review-report.md --pattern \"## Verdict\"" in prompt
|
|
413
|
+
|
|
414
|
+
def test_bugfix_template_source_is_clean_of_helper_covered_snippets(self):
|
|
415
|
+
content = Path("dev-pipeline/templates/bugfix-bootstrap-prompt.md").read_text(encoding="utf-8")
|
|
416
|
+
for snippet in RETIRED_EXTRACTED_SNIPPETS_BUGFIX:
|
|
417
|
+
assert snippet not in content, f"Shell snippet in bugfix template: {snippet}"
|
|
418
|
+
|
|
419
|
+
def test_continuation_source_is_clean_of_helper_covered_snippets(self):
|
|
420
|
+
content = Path("dev-pipeline/scripts/continuation.py").read_text(encoding="utf-8")
|
|
421
|
+
for snippet in RETIRED_EXTRACTED_SNIPPETS_BUGFIX:
|
|
422
|
+
assert snippet not in content, f"Shell snippet in continuation.py: {snippet}"
|
|
423
|
+
|
|
424
|
+
def test_bugfix_generator_source_is_clean_of_helper_covered_snippets(self):
|
|
425
|
+
content = Path("dev-pipeline/scripts/generate-bugfix-prompt.py").read_text(encoding="utf-8")
|
|
426
|
+
for snippet in RETIRED_EXTRACTED_SNIPPETS_BUGFIX:
|
|
427
|
+
assert snippet not in content, f"Shell snippet in generate-bugfix-prompt.py: {snippet}"
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from argparse import Namespace
|
|
4
4
|
from pathlib import Path
|
|
5
|
+
import os
|
|
5
6
|
|
|
6
7
|
from continuation import append_continuation_handoff
|
|
7
8
|
from generate_refactor_prompt import (
|
|
@@ -194,3 +195,126 @@ def test_template_source_is_clean_for_headless_prompt_contract():
|
|
|
194
195
|
content = Path("dev-pipeline/templates/refactor-bootstrap-prompt.md").read_text(encoding="utf-8")
|
|
195
196
|
for forbidden in HEADLESS_FORBIDDEN_PROMPT_STRINGS:
|
|
196
197
|
assert forbidden not in content
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
# ---------------------------------------------------------------------------
|
|
201
|
+
# Anti-Bash regression guardrails (F-039)
|
|
202
|
+
# Note: grep -n, sed -n, grep -q, wc -l excluded — may appear in cross-pipeline
|
|
203
|
+
# context budget rules as AI tool hints, not as operational shell snippets.
|
|
204
|
+
# | sed (trailing space) only matches pipe-to-sed operational patterns.
|
|
205
|
+
# ---------------------------------------------------------------------------
|
|
206
|
+
|
|
207
|
+
RETIRED_EXTRACTED_SNIPPETS_REFACTOR = [
|
|
208
|
+
"find . -maxdepth",
|
|
209
|
+
"| sed ",
|
|
210
|
+
r"grep -c '^\- \[ \]'",
|
|
211
|
+
"2>/dev/null",
|
|
212
|
+
"/dev/null",
|
|
213
|
+
"$DEV_PORT",
|
|
214
|
+
"$!",
|
|
215
|
+
"$HOME",
|
|
216
|
+
"if [ ",
|
|
217
|
+
"which playwright-cli",
|
|
218
|
+
"which opencli",
|
|
219
|
+
"lsof -ti",
|
|
220
|
+
"xargs",
|
|
221
|
+
" kill -",
|
|
222
|
+
"kill -",
|
|
223
|
+
"|| echo",
|
|
224
|
+
"mkdir -p",
|
|
225
|
+
"touch .prizmkit",
|
|
226
|
+
]
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _render_refactor_prompt_full(tmp_path, platform="claude"):
|
|
230
|
+
"""Render a complete refactor prompt through the generator."""
|
|
231
|
+
import json, os
|
|
232
|
+
from generate_refactor_prompt import main as refactor_main
|
|
233
|
+
|
|
234
|
+
project = tmp_path / "refactor-anti-bash"
|
|
235
|
+
project.mkdir(parents=True)
|
|
236
|
+
(project / ".prizmkit").mkdir(exist_ok=True)
|
|
237
|
+
(project / ".prizmkit" / "config.json").write_text(
|
|
238
|
+
json.dumps({"platform": platform, "ai_cli": platform}), encoding="utf-8"
|
|
239
|
+
)
|
|
240
|
+
# Ensure agent files
|
|
241
|
+
for plat in ("claude", "codex"):
|
|
242
|
+
platform_dir = ".codex" if plat == "codex" else ".claude"
|
|
243
|
+
suffix = ".toml" if plat == "codex" else ".md"
|
|
244
|
+
agents_dir = project / platform_dir / "agents"
|
|
245
|
+
agents_dir.mkdir(parents=True, exist_ok=True)
|
|
246
|
+
for name in ("dev", "reviewer", "critic"):
|
|
247
|
+
(agents_dir / f"prizm-dev-team-{name}{suffix}").write_text("agent\n", encoding="utf-8")
|
|
248
|
+
|
|
249
|
+
refactor_list = project / ".prizmkit" / "plans" / "refactor-list.json"
|
|
250
|
+
refactor_list.parent.mkdir(parents=True)
|
|
251
|
+
refactor_list.write_text(json.dumps({
|
|
252
|
+
"refactors": [{
|
|
253
|
+
"id": "R-001", "title": "Restructure", "description": "Preserve behavior",
|
|
254
|
+
"acceptance_criteria": ["Behavior preserved"],
|
|
255
|
+
"scope": {"files": ["src/a.py"], "modules": ["src"]},
|
|
256
|
+
}],
|
|
257
|
+
"global_context": {"language": "Python"},
|
|
258
|
+
}), encoding="utf-8")
|
|
259
|
+
output = project / "refactor-prompt.md"
|
|
260
|
+
old_argv = os.sys.argv
|
|
261
|
+
old_platform = os.environ.get("PRIZMKIT_PLATFORM")
|
|
262
|
+
try:
|
|
263
|
+
os.environ.pop("PRIZMKIT_PLATFORM", None)
|
|
264
|
+
os.sys.argv = [
|
|
265
|
+
"generate-refactor-prompt.py",
|
|
266
|
+
"--refactor-list", str(refactor_list),
|
|
267
|
+
"--refactor-id", "R-001",
|
|
268
|
+
"--session-id", "session-1",
|
|
269
|
+
"--run-id", "run-1",
|
|
270
|
+
"--retry-count", "0",
|
|
271
|
+
"--resume-phase", "null",
|
|
272
|
+
"--state-dir", str(project / ".prizmkit" / "state" / "refactor"),
|
|
273
|
+
"--output", str(output),
|
|
274
|
+
]
|
|
275
|
+
old_cwd = os.getcwd()
|
|
276
|
+
os.chdir(project)
|
|
277
|
+
try:
|
|
278
|
+
try:
|
|
279
|
+
refactor_main()
|
|
280
|
+
except SystemExit as exc:
|
|
281
|
+
if exc.code not in (0, None):
|
|
282
|
+
raise
|
|
283
|
+
finally:
|
|
284
|
+
os.chdir(old_cwd)
|
|
285
|
+
finally:
|
|
286
|
+
os.sys.argv = old_argv
|
|
287
|
+
if old_platform is None:
|
|
288
|
+
os.environ.pop("PRIZMKIT_PLATFORM", None)
|
|
289
|
+
else:
|
|
290
|
+
os.environ["PRIZMKIT_PLATFORM"] = old_platform
|
|
291
|
+
return output.read_text(encoding="utf-8")
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
class TestRefactorBootstrapShellExtraction:
|
|
295
|
+
"""Regression guardrails: refactor rendered prompts and source use helper, not shell."""
|
|
296
|
+
|
|
297
|
+
def test_rendered_refactor_prompt_uses_runtime_helper_not_extracted_bash(self, tmp_path):
|
|
298
|
+
prompt = _render_refactor_prompt_full(tmp_path)
|
|
299
|
+
for snippet in RETIRED_EXTRACTED_SNIPPETS_REFACTOR:
|
|
300
|
+
assert snippet not in prompt, f"Retired shell snippet found in refactor prompt: {snippet}"
|
|
301
|
+
assert "{{RUNTIME_HELPER_CMD}}" not in prompt
|
|
302
|
+
assert "python" in prompt.lower()
|
|
303
|
+
assert ".prizmkit/dev-pipeline/scripts/prizmkit-runtime-helper.py" in prompt
|
|
304
|
+
assert "artifact ensure-dir .prizmkit/refactor/R-001" in prompt
|
|
305
|
+
assert "text contains .prizmkit/refactor/R-001/review-report.md --pattern \"## Verdict\"" in prompt
|
|
306
|
+
|
|
307
|
+
def test_refactor_template_source_is_clean_of_helper_covered_snippets(self):
|
|
308
|
+
content = Path("dev-pipeline/templates/refactor-bootstrap-prompt.md").read_text(encoding="utf-8")
|
|
309
|
+
for snippet in RETIRED_EXTRACTED_SNIPPETS_REFACTOR:
|
|
310
|
+
assert snippet not in content, f"Shell snippet in refactor template: {snippet}"
|
|
311
|
+
|
|
312
|
+
def test_continuation_source_is_clean_of_helper_covered_snippets(self):
|
|
313
|
+
content = Path("dev-pipeline/scripts/continuation.py").read_text(encoding="utf-8")
|
|
314
|
+
for snippet in RETIRED_EXTRACTED_SNIPPETS_REFACTOR:
|
|
315
|
+
assert snippet not in content, f"Shell snippet in continuation.py: {snippet}"
|
|
316
|
+
|
|
317
|
+
def test_refactor_generator_source_is_clean_of_helper_covered_snippets(self):
|
|
318
|
+
content = Path("dev-pipeline/scripts/generate-refactor-prompt.py").read_text(encoding="utf-8")
|
|
319
|
+
for snippet in RETIRED_EXTRACTED_SNIPPETS_REFACTOR:
|
|
320
|
+
assert snippet not in content, f"Shell snippet in generate-refactor-prompt.py: {snippet}"
|