pactkit 2.7.0__tar.gz → 2.8.0__tar.gz
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.
- {pactkit-2.7.0 → pactkit-2.8.0}/.github/workflows/publish.yml +2 -2
- {pactkit-2.7.0 → pactkit-2.8.0}/.opencode/pactkit.yaml +4 -4
- {pactkit-2.7.0 → pactkit-2.8.0}/CHANGELOG.md +17 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/PKG-INFO +3 -2
- {pactkit-2.7.0 → pactkit-2.8.0}/pyproject.toml +3 -2
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/__init__.py +1 -1
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/config.py +5 -27
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/doctor.py +28 -25
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/generators/deployer.py +4 -4
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/prompts/commands.py +15 -4
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug013_config_single_source.py +4 -4
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_config.py +7 -3
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_config_auto_merge.py +6 -7
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_selective_deploy.py +1 -1
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story033_config_backfill.py +3 -3
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story063_prompt_slimming.py +2 -1
- {pactkit-2.7.0 → pactkit-2.8.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/.github/dependabot.yml +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/.github/workflows/ci.yml +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/.github/workflows/pactkit.yml +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/.gitignore +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/AGENTS.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/CODE_OF_CONDUCT.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/CONTRIBUTING.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/LICENSE +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/README.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/SECURITY.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/assets/logo.png +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/guides/codex-integration-preresearch.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/guides/tool-integration-checklist.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-001.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-002.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-003.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-004.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-005.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-006.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-007.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-008.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-009.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-010.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-011.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-012.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-013.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-014.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-015.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-016.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-017.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-018.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-019.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-020.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-021.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-022.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-023.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-024.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-025.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-026.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-027.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-028.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-029.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-030.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-031.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-032.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-033.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-034.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-035.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-slim-001.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-slim-002.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-slim-003.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-slim-004.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-slim-005.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-slim-006.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/specs/BUG-slim-007.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/test_cases/BUG-001_case.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/docs/test_cases/BUG-002_case.md +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/opencode.json +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/__main__.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/backfill.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/cleaners.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/cli.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/context_gen.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/coverage_gate.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/generators/__init__.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/generators/adapter.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/generators/deploy_base.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/guards.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/id_generator.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/invariants.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/issue_sync.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/lazy_visualize.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/lessons.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/lint_runner.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/profiles.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/prompts/__init__.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/prompts/agents.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/prompts/references.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/prompts/rules.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/prompts/skills.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/prompts/workflows.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/regression.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/schemas.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/scripts.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/sec_scope.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/skills/__init__.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/skills/board.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/skills/scaffold.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/skills/spec_linter.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/skills/visualize.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/spec_status.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/test_mapper.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/utils.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/src/pactkit/validators.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/conftest.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/e2e/__init__.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/e2e/cli/__init__.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/e2e/cli/test_cli_e2e.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/integration/__init__.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/integration/test_deploy_classic.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_agent_features.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_agent_frontmatter.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_agents_enrichment.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_board_bug027.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_board_sections.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug001_skill_path.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug002_plugin_paths.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug003_multi_import.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug004_dead_set.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug005_archive_taskless.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug006_scan_excludes.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug007_stale_trace_refs.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug008_stale_command_refs.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug009_project_config_backfill.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug010_rewrite_yaml.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug011_stale_refs.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug012_call_graph_filter.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug014_version_hygiene.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug017_project_init_playbook.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug018_issue_tracker_verification.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug019_venv_deployment.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug020_claude_md_backup.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug025_release_delegation.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug026_version_sync.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug028_ghost_refs.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug029_stack_detection_fallback.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug030_spec_lint_cli.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug031_docstring_accuracy.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug034_plan_metadata_template.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug_021.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug_022.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug_023.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug_024.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug_slim001_env_detection.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug_slim002_instruction_collision.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug_slim003.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug_slim004.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug_slim005.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_bug_slim006.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_check_command.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_command_frontmatter.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_command_visualize_modes.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_constitution_sharpening.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_create_skill.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_cross_flow_matrix.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_deploy_base.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_deployer_cleanup.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_deployer_plugin.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_design_command.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_done_gates.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_draw_prompt.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_draw_references.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_drawio_mcp.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_home_path_fix.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_hotfix_command.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_init_guard.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_lang_profiles.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_list_stories.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_mcp_integration.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_model_config.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_modular_constitution.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_multi_prefix.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_pdca_slim.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_profiles.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_project_visibility.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_prompt_cli_refs.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_prompt_structural_invariants.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_prompts_package.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_release.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_release_field.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_release_v110.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_render_prompt.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_review_command.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_rules_enrichment.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_scaffold.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_scaffold_developer_prefix.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_schemas.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_script_extraction.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_session_context.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_skill_structure.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_skills_enrichment.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_smart_regression.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_sprint_command.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_stack_references.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_status_command.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_statusline.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story014_release.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story015_ci_lint_gate.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story016_claude_md.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story017_init_claude_md.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story018_arch_staleness.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story019_bailout.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story020_horizon.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story021_rfc.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story022_decision_tree.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story023_test_quality.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story024_native_agent.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story025_ci_pipeline.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story026_issue_tracker.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story027_hooks.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story028_rule_scoping.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story029_doctor.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story030_lint.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story031_git_init_guard.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story032_greenfield_redirect.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story034_plan_config_refresh.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story035_readme_docs.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story037_regression_fix.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story038_call_graph_update.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story039_venv_config.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story040_layered_claude_md.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story042_spec_linter.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story043_active_clarify.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story044_consistency_check.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story045_auto_pr.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story046_agent_adapter.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story047_enterprise_flags.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story048_worktree_isolation.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story049_community_standards.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story050_doc_only_shortcut.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story051_workflow_streamlining.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story052_conditional_github_release.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story053_impact_regression.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story055_commands.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story055_config.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story055_spec_linter.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story056_commands.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story056_config.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story057_implicit_cleanup.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story058_opencode_extraction.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story058_routing_fix.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story059_codex_removal.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story060_init_hang.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story061_remove_thinking.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story062_mcp_recommendations.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story064_venv_local_md.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story065_sprint_model.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story072_developer_prefix.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim009_lazy_rules.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim010_dry_refactor.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim011_command_rules.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim012_ci.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim014_clean.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim014_context.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim014_guard.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim014_lazy_viz.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim014_next_id.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim014_regression.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim014_sec_scope.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim014_validators.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim015_doctor.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim016_testmap_lint.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim017.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim018.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim019_plan_subphases.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim020_explore_stall_fix.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim021.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim022.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim023.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim024.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim025.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim026.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim027.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim028.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim029.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim030.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim031.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim032.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim033.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim034.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim035.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim036.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim037.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim038.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim039.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim040.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim041.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim042.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim043.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim044.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim045.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim046.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim047.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim048.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim049.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim051.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim052.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim053.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim054.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim055.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim056.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim060_codex_profile.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_story_slim063.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_tools.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_update_task.py +0 -0
- {pactkit-2.7.0 → pactkit-2.8.0}/tests/unit/test_visualize_modes.py +0 -0
|
@@ -27,8 +27,8 @@ jobs:
|
|
|
27
27
|
- name: Install dependencies
|
|
28
28
|
run: |
|
|
29
29
|
python -m pip install --upgrade pip
|
|
30
|
-
pip install -e ".[dev]" || pip install -e .
|
|
31
|
-
pip install pytest ruff
|
|
30
|
+
pip install --no-deps -e ".[dev]" || pip install --no-deps -e .
|
|
31
|
+
pip install pyyaml pytest ruff
|
|
32
32
|
|
|
33
33
|
- name: Lint
|
|
34
34
|
run: ruff check src/ tests/
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# Edit this file to customize which components are deployed.
|
|
3
3
|
# Remove items from a list to disable them. Default: all enabled.
|
|
4
4
|
|
|
5
|
-
version: "2.
|
|
5
|
+
version: "2.8.0"
|
|
6
6
|
stack: python
|
|
7
7
|
root: .
|
|
8
8
|
developer: "slim"
|
|
@@ -23,18 +23,19 @@ agents:
|
|
|
23
23
|
commands:
|
|
24
24
|
- project-act
|
|
25
25
|
- project-check
|
|
26
|
+
- project-clarify
|
|
26
27
|
- project-design
|
|
27
28
|
- project-done
|
|
28
29
|
- project-hotfix
|
|
29
30
|
- project-init
|
|
30
31
|
- project-plan
|
|
31
|
-
- project-sprint
|
|
32
|
-
- project-clarify
|
|
33
32
|
- project-pr
|
|
34
33
|
- project-release
|
|
34
|
+
- project-sprint
|
|
35
35
|
|
|
36
36
|
# Skills — tool scripts
|
|
37
37
|
skills:
|
|
38
|
+
- pactkit-analyze
|
|
38
39
|
- pactkit-board
|
|
39
40
|
- pactkit-doctor
|
|
40
41
|
- pactkit-draw
|
|
@@ -44,7 +45,6 @@ skills:
|
|
|
44
45
|
- pactkit-status
|
|
45
46
|
- pactkit-trace
|
|
46
47
|
- pactkit-visualize
|
|
47
|
-
- pactkit-analyze
|
|
48
48
|
- project-act
|
|
49
49
|
- project-check
|
|
50
50
|
- project-clarify
|
|
@@ -4,6 +4,23 @@ All notable changes to PactKit will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
Format follows [Keep a Changelog](https://keepachangelog.com/).
|
|
6
6
|
|
|
7
|
+
## [2.8.0] - 2026-03-27
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **3-IDE default install** — `pip install pactkit` now installs all three IDE adapters (Claude Code + OpenCode + Codex) out of the box.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **OpenCode command architecture** — Reverted OpenCode from skills-only back to `commands/` + `skills/` dual architecture. OpenCode auto-discovers commands from `commands/*.md` (invoked via `/project-plan`), while embedded skills in `skills/` are loaded by AI agent on demand. `opencode.json` command entries now only contain model routing (no `template` field — it was incorrectly treated as file path, but is actually inline text).
|
|
14
|
+
- **Spec version confusion** — `/project-plan` Phase 3.2a no longer reads version from `pactkit.yaml` (PactKit toolkit version). Now explicitly reads from project's package manifest (`pyproject.toml`, `package.json`, `Cargo.toml`).
|
|
15
|
+
- **OpenCode path isolation** — All deployed OpenCode files reference `~/.config/opencode/` paths, CLI commands replaced with `python3 ~/.config/opencode/skills/*/scripts/*.py` invocations.
|
|
16
|
+
- **pactkit.yaml simplification** — Removed redundant component lists (agents/commands/skills/rules) from yaml template. Absence = deploy all from `VALID_*` sets. `pactkit doctor` drift check skips absent keys.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- **Cross-IDE command architecture**:
|
|
20
|
+
- Claude Code: skills-only (`skills/project-*/SKILL.md`), prefix `/`
|
|
21
|
+
- OpenCode: commands + skills (`commands/project-*.md` + `skills/pactkit-*/SKILL.md`), prefix `/`
|
|
22
|
+
- Codex: skills-only (`skills/project-*/SKILL.md`), prefix `$`
|
|
23
|
+
|
|
7
24
|
## [2.7.0] - 2026-03-27
|
|
8
25
|
|
|
9
26
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pactkit
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.8.0
|
|
4
4
|
Summary: Spec-driven agentic DevOps toolkit for AI coding assistants
|
|
5
5
|
Project-URL: Homepage, https://pactkit.dev
|
|
6
6
|
Project-URL: Repository, https://github.com/pactkit/pactkit-public
|
|
@@ -21,7 +21,8 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
21
21
|
Classifier: Topic :: Software Development :: Build Tools
|
|
22
22
|
Classifier: Topic :: Software Development :: Quality Assurance
|
|
23
23
|
Requires-Python: >=3.10
|
|
24
|
-
Requires-Dist: pactkit-
|
|
24
|
+
Requires-Dist: pactkit-codex>=2.8.0
|
|
25
|
+
Requires-Dist: pactkit-opencode>=2.8.0
|
|
25
26
|
Requires-Dist: pyyaml>=6.0
|
|
26
27
|
Provides-Extra: multilang
|
|
27
28
|
Requires-Dist: tree-sitter-go>=0.25; extra == 'multilang'
|
|
@@ -4,14 +4,15 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pactkit"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.8.0"
|
|
8
8
|
description = "Spec-driven agentic DevOps toolkit for AI coding assistants"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
11
11
|
requires-python = ">=3.10"
|
|
12
12
|
dependencies = [
|
|
13
13
|
"pyyaml>=6.0",
|
|
14
|
-
"pactkit-opencode>=2.
|
|
14
|
+
"pactkit-opencode>=2.8.0",
|
|
15
|
+
"pactkit-codex>=2.8.0",
|
|
15
16
|
]
|
|
16
17
|
|
|
17
18
|
authors = [
|
|
@@ -448,14 +448,12 @@ def auto_merge_config_file(path: Union[Path, str]) -> list[str]:
|
|
|
448
448
|
added: list[str] = []
|
|
449
449
|
|
|
450
450
|
# --- List-type keys: merge new items ---
|
|
451
|
+
# If a list key is absent from yaml, it means "deploy all" (VALID_* default).
|
|
452
|
+
# Only merge if the user explicitly provides a list (opt-in customization).
|
|
451
453
|
for key, valid_set in _REGISTRY.items():
|
|
452
454
|
user_list = user_data.get(key)
|
|
453
455
|
if user_list is None:
|
|
454
|
-
#
|
|
455
|
-
excluded_items = set(exclude.get(key, []) or [])
|
|
456
|
-
new_items = sorted(item for item in valid_set if item not in excluded_items)
|
|
457
|
-
user_data[key] = new_items
|
|
458
|
-
added.append(f"section: {key}")
|
|
456
|
+
# Key absent = deploy all by default. No backfill needed.
|
|
459
457
|
continue
|
|
460
458
|
if not isinstance(user_list, list):
|
|
461
459
|
continue
|
|
@@ -900,34 +898,14 @@ def generate_default_yaml() -> str:
|
|
|
900
898
|
cfg = get_default_config()
|
|
901
899
|
lines = [
|
|
902
900
|
"# PactKit Configuration",
|
|
903
|
-
"#
|
|
904
|
-
"#
|
|
901
|
+
"# All agents, commands, skills, and rules are deployed by default.",
|
|
902
|
+
"# To exclude specific items, add an exclude list (e.g., exclude_skills: [pactkit-draw]).",
|
|
905
903
|
"",
|
|
906
904
|
f'version: "{cfg["version"]}"',
|
|
907
905
|
f"stack: {cfg['stack']}",
|
|
908
906
|
f"root: {cfg['root']}",
|
|
909
907
|
f'developer: "{cfg["developer"]}"',
|
|
910
|
-
"",
|
|
911
|
-
"# Agents — AI role definitions",
|
|
912
|
-
"agents:",
|
|
913
908
|
]
|
|
914
|
-
for a in cfg["agents"]:
|
|
915
|
-
lines.append(f" - {a}")
|
|
916
|
-
|
|
917
|
-
lines.extend(["", "# Commands — PDCA playbooks"])
|
|
918
|
-
lines.append("commands:")
|
|
919
|
-
for c in cfg["commands"]:
|
|
920
|
-
lines.append(f" - {c}")
|
|
921
|
-
|
|
922
|
-
lines.extend(["", "# Skills — tool scripts"])
|
|
923
|
-
lines.append("skills:")
|
|
924
|
-
for s in cfg["skills"]:
|
|
925
|
-
lines.append(f" - {s}")
|
|
926
|
-
|
|
927
|
-
lines.extend(["", "# Rules — constitution modules"])
|
|
928
|
-
lines.append("rules:")
|
|
929
|
-
for r in cfg["rules"]:
|
|
930
|
-
lines.append(f" - {r}")
|
|
931
909
|
|
|
932
910
|
ci = cfg.get("ci", {})
|
|
933
911
|
lines.extend(["", "# CI/CD — set provider to github or gitlab to generate pipeline config"])
|
|
@@ -55,6 +55,10 @@ def check_orphaned_specs(project_root: Path) -> dict:
|
|
|
55
55
|
def check_config_drift(project_root: Path) -> dict:
|
|
56
56
|
"""Compare pactkit.yaml declared items vs deployed files.
|
|
57
57
|
|
|
58
|
+
Only checks deployment drift when the yaml explicitly declares
|
|
59
|
+
component lists (agents, commands, skills, rules). Default behavior
|
|
60
|
+
(no lists) means "deploy all from VALID_* sets" — no drift possible.
|
|
61
|
+
|
|
58
62
|
Returns:
|
|
59
63
|
{"missing_deployments": [{"type": ..., "name": ...}]}
|
|
60
64
|
"""
|
|
@@ -69,33 +73,32 @@ def check_config_drift(project_root: Path) -> dict:
|
|
|
69
73
|
with open(yaml_path, encoding="utf-8") as f:
|
|
70
74
|
data = yaml.safe_load(f) or {}
|
|
71
75
|
|
|
72
|
-
config_dir = yaml_path.parent # .claude/ or .opencode/
|
|
76
|
+
config_dir = yaml_path.parent # .claude/ or .opencode/ or .codex/
|
|
73
77
|
missing: list[dict] = []
|
|
74
78
|
|
|
75
|
-
#
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
for
|
|
83
|
-
|
|
84
|
-
if not
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
missing.append({"type": "rule", "name": rule})
|
|
79
|
+
# Only check drift for explicitly declared lists.
|
|
80
|
+
# If the key is absent, it means "deploy all" — no drift to check.
|
|
81
|
+
_CHECKS = [
|
|
82
|
+
("agents", "agents", ".md"),
|
|
83
|
+
("commands", "commands", ".md"),
|
|
84
|
+
("rules", "rules", ".md"),
|
|
85
|
+
]
|
|
86
|
+
for key, subdir, suffix in _CHECKS:
|
|
87
|
+
declared = data.get(key)
|
|
88
|
+
if not isinstance(declared, list):
|
|
89
|
+
continue
|
|
90
|
+
for item in declared:
|
|
91
|
+
if not (config_dir / subdir / f"{item}{suffix}").exists():
|
|
92
|
+
missing.append({"type": key.rstrip("s"), "name": item})
|
|
93
|
+
|
|
94
|
+
# Skills: check as directory or .md file
|
|
95
|
+
declared_skills = data.get("skills")
|
|
96
|
+
if isinstance(declared_skills, list):
|
|
97
|
+
for skill in declared_skills:
|
|
98
|
+
skill_dir = config_dir / "skills" / skill
|
|
99
|
+
skill_file = config_dir / "skills" / f"{skill}.md"
|
|
100
|
+
if not skill_dir.is_dir() and not skill_file.exists():
|
|
101
|
+
missing.append({"type": "skill", "name": skill})
|
|
99
102
|
|
|
100
103
|
return {"missing_deployments": missing}
|
|
101
104
|
|
|
@@ -301,10 +301,10 @@ def _deploy_classic(config=None, target=None):
|
|
|
301
301
|
d.mkdir(parents=True, exist_ok=True)
|
|
302
302
|
|
|
303
303
|
# Deploy components filtered by config
|
|
304
|
-
enabled_skills = config.get("skills",
|
|
305
|
-
enabled_rules = config.get("rules",
|
|
306
|
-
enabled_agents = config.get("agents",
|
|
307
|
-
enabled_commands = config.get("commands",
|
|
304
|
+
enabled_skills = config.get("skills", sorted(VALID_SKILLS))
|
|
305
|
+
enabled_rules = config.get("rules", sorted(VALID_RULES))
|
|
306
|
+
enabled_agents = config.get("agents", sorted(VALID_AGENTS))
|
|
307
|
+
enabled_commands = config.get("commands", sorted(VALID_COMMANDS))
|
|
308
308
|
|
|
309
309
|
classic_profile = get_profile("classic")
|
|
310
310
|
n_skills = _deploy_skills(skills_dir, enabled_skills, profile=classic_profile)
|
|
@@ -90,7 +90,7 @@ allowed-tools: [Read, Write, Edit, Bash, Glob, Grep]
|
|
|
90
90
|
1. **Scaffold**: Run `{SCAFFOLD_CMD} create_spec "{ID}" "{title}"` to generate `docs/specs/{ID}.md` from SPEC_TEMPLATE. This creates all sections, tables, and Given/When/Then skeleton — format is guaranteed by Code.
|
|
91
91
|
2. **Read**: Read `docs/specs/{ID}.md` to see the scaffolded template.
|
|
92
92
|
3. **Edit placeholders** (use Edit tool, NOT Write):
|
|
93
|
-
- Edit `Release | TBD` → `Release | {version}` (
|
|
93
|
+
- Edit `Release | TBD` → `Release | {version}` (from `pyproject.toml`/`package.json`, NOT `{PACTKIT_YAML}`)
|
|
94
94
|
- Edit `(Description of the problem or feature)` → actual Background content from your Trace findings
|
|
95
95
|
- Edit `## Target Call Chain` placeholder → actual call chain from Phase 1
|
|
96
96
|
- Edit `### R1: (Requirement Name) (MUST)` → actual requirements using RFC 2119 keywords (MUST/SHOULD/MAY). Add more R{N} sections as needed.
|
|
@@ -519,18 +519,28 @@ description: "Standalone requirement clarification before planning"
|
|
|
519
519
|
allowed-tools: [Read, Bash, Glob, Grep]
|
|
520
520
|
---
|
|
521
521
|
|
|
522
|
-
# Command: Clarify (v1.
|
|
522
|
+
# Command: Clarify (v1.1.0)
|
|
523
523
|
- **Usage**: `/project-clarify "$ARGUMENTS"`
|
|
524
524
|
- **Agent**: System Architect
|
|
525
525
|
|
|
526
|
-
> **PURPOSE**: Standalone requirement clarification. Run before `/project-plan` to surface ambiguities and
|
|
526
|
+
> **PURPOSE**: Standalone requirement clarification. Run before `/project-plan` to surface ambiguities and assess risks upfront.
|
|
527
527
|
|
|
528
528
|
## Phase 1: Ambiguity Analysis
|
|
529
529
|
1. Analyze `$ARGUMENTS` against the AMBIGUITY_SIGNALS checklist (same as Plan Phase 0.7).
|
|
530
530
|
2. Generate 3–6 structured questions (Scope, Users, Constraints, Scale, Edge Cases, Non-Goals).
|
|
531
531
|
3. Ask questions in the user's language.
|
|
532
532
|
|
|
533
|
-
## Phase 2:
|
|
533
|
+
## Phase 2: Pre-mortem Risk Probe
|
|
534
|
+
> **PURPOSE**: Reverse thinking — identify how the plan could fail before it starts.
|
|
535
|
+
1. Based on `$ARGUMENTS` and Phase 1 findings, generate 1–2 pre-mortem questions (pick the most relevant):
|
|
536
|
+
- "If this feature is deemed a failure 1 month after launch, what is the most likely reason?"
|
|
537
|
+
- "What assumptions does this plan rely on? Which assumption is the most fragile?"
|
|
538
|
+
- "What will the person maintaining this code in 6 months complain about the most?"
|
|
539
|
+
- "What is the most likely integration point to break?"
|
|
540
|
+
2. Ask in the user's language, together with Phase 1 questions.
|
|
541
|
+
3. Total questions across Phase 1 + Phase 2 MUST NOT exceed 6. If Phase 1 already has 5–6, pick only 1 pre-mortem question. If Phase 1 has ≤ 4, pick up to 2.
|
|
542
|
+
|
|
543
|
+
## Phase 3: Clarified Brief Output
|
|
534
544
|
1. After user responses, produce a **Clarified Brief**:
|
|
535
545
|
```markdown
|
|
536
546
|
## Clarified Brief: {feature name}
|
|
@@ -540,6 +550,7 @@ allowed-tools: [Read, Bash, Glob, Grep]
|
|
|
540
550
|
- **Scale**: {performance expectations}
|
|
541
551
|
- **Edge Cases**: {failure scenarios and expected behavior}
|
|
542
552
|
- **Non-Goals**: {explicitly excluded}
|
|
553
|
+
- **Risks**: {top 1-2 identified risks from pre-mortem}
|
|
543
554
|
```
|
|
544
555
|
2. Output: "Ready for Plan. Run: `/project-plan \\"{clarified brief summary}\\"`"
|
|
545
556
|
""",
|
|
@@ -154,10 +154,10 @@ class TestAC2NewConfigAtProjectPath:
|
|
|
154
154
|
'Full config should be generated at $CWD/.claude/pactkit.yaml'
|
|
155
155
|
|
|
156
156
|
generated = yaml.safe_load(project_yaml.read_text())
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
assert '
|
|
160
|
-
assert '
|
|
157
|
+
# Component lists (agents, commands, skills, rules) are no longer in yaml —
|
|
158
|
+
# default is "deploy all" from VALID_* sets. Only operational config remains.
|
|
159
|
+
assert 'stack' in generated, 'Generated config should have stack'
|
|
160
|
+
assert 'version' in generated, 'Generated config should have version'
|
|
161
161
|
|
|
162
162
|
def test_no_config_at_global_path(self, tmp_path):
|
|
163
163
|
from pactkit.generators.deployer import deploy
|
|
@@ -223,11 +223,15 @@ class TestGenerateDefaultYaml:
|
|
|
223
223
|
parsed = yaml.safe_load(result)
|
|
224
224
|
assert isinstance(parsed, dict)
|
|
225
225
|
|
|
226
|
-
def
|
|
226
|
+
def test_roundtrip_contains_core_keys(self):
|
|
227
|
+
"""Generated YAML has operational config but not component lists."""
|
|
227
228
|
result = _config().generate_default_yaml()
|
|
228
229
|
parsed = yaml.safe_load(result)
|
|
229
|
-
|
|
230
|
-
assert
|
|
230
|
+
assert "stack" in parsed
|
|
231
|
+
assert "version" in parsed
|
|
232
|
+
# Component lists omitted — default is "deploy all" from VALID_* sets
|
|
233
|
+
for key in ("agents", "commands", "skills", "rules"):
|
|
234
|
+
assert key not in parsed
|
|
231
235
|
|
|
232
236
|
def test_contains_comments(self):
|
|
233
237
|
result = _config().generate_default_yaml()
|
|
@@ -246,8 +246,8 @@ class TestBackwardCompatibility:
|
|
|
246
246
|
added = cfg.auto_merge_config_file(yaml_path)
|
|
247
247
|
assert added == []
|
|
248
248
|
|
|
249
|
-
def
|
|
250
|
-
"""
|
|
249
|
+
def test_yaml_with_only_scalar_keys_no_backfill(self, tmp_path):
|
|
250
|
+
"""Missing list keys are NOT backfilled — absence means 'deploy all'."""
|
|
251
251
|
cfg = _config()
|
|
252
252
|
yaml_path = tmp_path / 'pactkit.yaml'
|
|
253
253
|
_write_yaml(yaml_path, {
|
|
@@ -260,11 +260,10 @@ class TestBackwardCompatibility:
|
|
|
260
260
|
})
|
|
261
261
|
|
|
262
262
|
added = cfg.auto_merge_config_file(yaml_path)
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
assert
|
|
267
|
-
assert 'section: rules' in section_reports
|
|
263
|
+
# No list backfill — missing keys mean "deploy all"
|
|
264
|
+
list_keys = {'agents', 'commands', 'skills', 'rules'}
|
|
265
|
+
list_backfills = [r for r in added if any(r == f'section: {k}' for k in list_keys)]
|
|
266
|
+
assert len(list_backfills) == 0
|
|
268
267
|
|
|
269
268
|
def test_full_list_nothing_added(self, tmp_path):
|
|
270
269
|
"""If user already has all VALID items and sections, nothing is added."""
|
|
@@ -229,7 +229,7 @@ class TestConfigAutoGeneration:
|
|
|
229
229
|
yaml_path = claude / "pactkit.yaml"
|
|
230
230
|
parsed = yaml.safe_load(yaml_path.read_text())
|
|
231
231
|
assert parsed is not None
|
|
232
|
-
assert "
|
|
232
|
+
assert "stack" in parsed
|
|
233
233
|
|
|
234
234
|
|
|
235
235
|
# ===========================================================================
|
|
@@ -233,13 +233,13 @@ class TestAC4BackfillReport:
|
|
|
233
233
|
assert len(section_reports) == 0
|
|
234
234
|
|
|
235
235
|
def test_reports_multiple_sections(self, tmp_path):
|
|
236
|
-
"""All missing sections reported when
|
|
236
|
+
"""All missing non-list sections reported when absent."""
|
|
237
237
|
yaml_path = tmp_path / 'pactkit.yaml'
|
|
238
238
|
yaml_path.write_text('stack: python\nversion: "1.2.0"\nroot: .\n')
|
|
239
239
|
result = auto_merge_config_file(yaml_path)
|
|
240
240
|
section_reports = [r for r in result if r.startswith('section:')]
|
|
241
|
-
#
|
|
242
|
-
assert len(section_reports) ==
|
|
241
|
+
# 12 non-list sections only (list-type keys no longer backfilled)
|
|
242
|
+
assert len(section_reports) == 12
|
|
243
243
|
|
|
244
244
|
|
|
245
245
|
# ===========================================================================
|
|
@@ -197,7 +197,8 @@ class TestAC6DevRefGhostResolved:
|
|
|
197
197
|
# AC7: Total Prompt Size Reduced >= 15%
|
|
198
198
|
# ---------------------------------------------------------------------------
|
|
199
199
|
# STORY-slim-050: bumped +393 for Done smart regression gate (R2)
|
|
200
|
-
|
|
200
|
+
# HOTFIX: bumped +875 for Clarify pre-mortem risk probe
|
|
201
|
+
BASELINE_TOTAL_CHARS = 74850
|
|
201
202
|
|
|
202
203
|
|
|
203
204
|
class TestAC7PromptSizeReduced:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|