pactkit 2.6.0__tar.gz → 2.7.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.
Files changed (316) hide show
  1. {pactkit-2.6.0 → pactkit-2.7.0}/.opencode/pactkit.yaml +12 -1
  2. {pactkit-2.6.0 → pactkit-2.7.0}/CHANGELOG.md +21 -0
  3. {pactkit-2.6.0 → pactkit-2.7.0}/PKG-INFO +2 -1
  4. {pactkit-2.6.0 → pactkit-2.7.0}/pyproject.toml +2 -1
  5. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/__init__.py +1 -1
  6. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/config.py +13 -0
  7. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/generators/deployer.py +40 -10
  8. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/lazy_visualize.py +2 -8
  9. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/profiles.py +22 -1
  10. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/skills/board.py +4 -0
  11. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/skills/visualize.py +1 -1
  12. {pactkit-2.6.0 → pactkit-2.7.0}/tests/e2e/cli/test_cli_e2e.py +11 -8
  13. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_command_frontmatter.py +2 -1
  14. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_config.py +2 -1
  15. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_deployer_cleanup.py +5 -2
  16. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_pdca_slim.py +4 -2
  17. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_profiles.py +7 -3
  18. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_render_prompt.py +6 -5
  19. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_selective_deploy.py +20 -13
  20. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_sprint_command.py +10 -7
  21. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story031_git_init_guard.py +3 -2
  22. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story032_greenfield_redirect.py +3 -2
  23. pactkit-2.7.0/tests/unit/test_story059_codex_removal.py +68 -0
  24. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim011_command_rules.py +12 -10
  25. pactkit-2.7.0/tests/unit/test_story_slim060_codex_profile.py +77 -0
  26. pactkit-2.7.0/tests/unit/test_story_slim063.py +162 -0
  27. pactkit-2.6.0/tests/unit/test_story059_codex_removal.py +0 -90
  28. {pactkit-2.6.0 → pactkit-2.7.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  29. {pactkit-2.6.0 → pactkit-2.7.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  30. {pactkit-2.6.0 → pactkit-2.7.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  31. {pactkit-2.6.0 → pactkit-2.7.0}/.github/dependabot.yml +0 -0
  32. {pactkit-2.6.0 → pactkit-2.7.0}/.github/workflows/ci.yml +0 -0
  33. {pactkit-2.6.0 → pactkit-2.7.0}/.github/workflows/pactkit.yml +0 -0
  34. {pactkit-2.6.0 → pactkit-2.7.0}/.github/workflows/publish.yml +0 -0
  35. {pactkit-2.6.0 → pactkit-2.7.0}/.gitignore +0 -0
  36. {pactkit-2.6.0 → pactkit-2.7.0}/AGENTS.md +0 -0
  37. {pactkit-2.6.0 → pactkit-2.7.0}/CODE_OF_CONDUCT.md +0 -0
  38. {pactkit-2.6.0 → pactkit-2.7.0}/CONTRIBUTING.md +0 -0
  39. {pactkit-2.6.0 → pactkit-2.7.0}/LICENSE +0 -0
  40. {pactkit-2.6.0 → pactkit-2.7.0}/README.md +0 -0
  41. {pactkit-2.6.0 → pactkit-2.7.0}/SECURITY.md +0 -0
  42. {pactkit-2.6.0 → pactkit-2.7.0}/docs/assets/logo.png +0 -0
  43. {pactkit-2.6.0 → pactkit-2.7.0}/docs/guides/codex-integration-preresearch.md +0 -0
  44. {pactkit-2.6.0 → pactkit-2.7.0}/docs/guides/tool-integration-checklist.md +0 -0
  45. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-001.md +0 -0
  46. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-002.md +0 -0
  47. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-003.md +0 -0
  48. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-004.md +0 -0
  49. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-005.md +0 -0
  50. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-006.md +0 -0
  51. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-007.md +0 -0
  52. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-008.md +0 -0
  53. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-009.md +0 -0
  54. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-010.md +0 -0
  55. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-011.md +0 -0
  56. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-012.md +0 -0
  57. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-013.md +0 -0
  58. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-014.md +0 -0
  59. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-015.md +0 -0
  60. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-016.md +0 -0
  61. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-017.md +0 -0
  62. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-018.md +0 -0
  63. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-019.md +0 -0
  64. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-020.md +0 -0
  65. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-021.md +0 -0
  66. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-022.md +0 -0
  67. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-023.md +0 -0
  68. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-024.md +0 -0
  69. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-025.md +0 -0
  70. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-026.md +0 -0
  71. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-027.md +0 -0
  72. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-028.md +0 -0
  73. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-029.md +0 -0
  74. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-030.md +0 -0
  75. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-031.md +0 -0
  76. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-032.md +0 -0
  77. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-033.md +0 -0
  78. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-034.md +0 -0
  79. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-035.md +0 -0
  80. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-slim-001.md +0 -0
  81. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-slim-002.md +0 -0
  82. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-slim-003.md +0 -0
  83. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-slim-004.md +0 -0
  84. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-slim-005.md +0 -0
  85. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-slim-006.md +0 -0
  86. {pactkit-2.6.0 → pactkit-2.7.0}/docs/specs/BUG-slim-007.md +0 -0
  87. {pactkit-2.6.0 → pactkit-2.7.0}/docs/test_cases/BUG-001_case.md +0 -0
  88. {pactkit-2.6.0 → pactkit-2.7.0}/docs/test_cases/BUG-002_case.md +0 -0
  89. {pactkit-2.6.0 → pactkit-2.7.0}/opencode.json +0 -0
  90. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/__main__.py +0 -0
  91. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/backfill.py +0 -0
  92. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/cleaners.py +0 -0
  93. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/cli.py +0 -0
  94. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/context_gen.py +0 -0
  95. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/coverage_gate.py +0 -0
  96. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/doctor.py +0 -0
  97. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/generators/__init__.py +0 -0
  98. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/generators/adapter.py +0 -0
  99. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/generators/deploy_base.py +0 -0
  100. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/guards.py +0 -0
  101. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/id_generator.py +0 -0
  102. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/invariants.py +0 -0
  103. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/issue_sync.py +0 -0
  104. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/lessons.py +0 -0
  105. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/lint_runner.py +0 -0
  106. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/prompts/__init__.py +0 -0
  107. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/prompts/agents.py +0 -0
  108. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/prompts/commands.py +0 -0
  109. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/prompts/references.py +0 -0
  110. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/prompts/rules.py +0 -0
  111. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/prompts/skills.py +0 -0
  112. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/prompts/workflows.py +0 -0
  113. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/regression.py +0 -0
  114. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/schemas.py +0 -0
  115. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/scripts.py +0 -0
  116. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/sec_scope.py +0 -0
  117. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/skills/__init__.py +0 -0
  118. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/skills/scaffold.py +0 -0
  119. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/skills/spec_linter.py +0 -0
  120. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/spec_status.py +0 -0
  121. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/test_mapper.py +0 -0
  122. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/utils.py +0 -0
  123. {pactkit-2.6.0 → pactkit-2.7.0}/src/pactkit/validators.py +0 -0
  124. {pactkit-2.6.0 → pactkit-2.7.0}/tests/conftest.py +0 -0
  125. {pactkit-2.6.0 → pactkit-2.7.0}/tests/e2e/__init__.py +0 -0
  126. {pactkit-2.6.0 → pactkit-2.7.0}/tests/e2e/cli/__init__.py +0 -0
  127. {pactkit-2.6.0 → pactkit-2.7.0}/tests/integration/__init__.py +0 -0
  128. {pactkit-2.6.0 → pactkit-2.7.0}/tests/integration/test_deploy_classic.py +0 -0
  129. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_agent_features.py +0 -0
  130. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_agent_frontmatter.py +0 -0
  131. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_agents_enrichment.py +0 -0
  132. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_board_bug027.py +0 -0
  133. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_board_sections.py +0 -0
  134. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug001_skill_path.py +0 -0
  135. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug002_plugin_paths.py +0 -0
  136. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug003_multi_import.py +0 -0
  137. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug004_dead_set.py +0 -0
  138. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug005_archive_taskless.py +0 -0
  139. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug006_scan_excludes.py +0 -0
  140. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug007_stale_trace_refs.py +0 -0
  141. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug008_stale_command_refs.py +0 -0
  142. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug009_project_config_backfill.py +0 -0
  143. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug010_rewrite_yaml.py +0 -0
  144. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug011_stale_refs.py +0 -0
  145. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug012_call_graph_filter.py +0 -0
  146. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug013_config_single_source.py +0 -0
  147. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug014_version_hygiene.py +0 -0
  148. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug017_project_init_playbook.py +0 -0
  149. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug018_issue_tracker_verification.py +0 -0
  150. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug019_venv_deployment.py +0 -0
  151. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug020_claude_md_backup.py +0 -0
  152. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug025_release_delegation.py +0 -0
  153. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug026_version_sync.py +0 -0
  154. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug028_ghost_refs.py +0 -0
  155. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug029_stack_detection_fallback.py +0 -0
  156. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug030_spec_lint_cli.py +0 -0
  157. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug031_docstring_accuracy.py +0 -0
  158. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug034_plan_metadata_template.py +0 -0
  159. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug_021.py +0 -0
  160. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug_022.py +0 -0
  161. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug_023.py +0 -0
  162. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug_024.py +0 -0
  163. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug_slim001_env_detection.py +0 -0
  164. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug_slim002_instruction_collision.py +0 -0
  165. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug_slim003.py +0 -0
  166. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug_slim004.py +0 -0
  167. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug_slim005.py +0 -0
  168. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_bug_slim006.py +0 -0
  169. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_check_command.py +0 -0
  170. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_command_visualize_modes.py +0 -0
  171. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_config_auto_merge.py +0 -0
  172. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_constitution_sharpening.py +0 -0
  173. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_create_skill.py +0 -0
  174. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_cross_flow_matrix.py +0 -0
  175. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_deploy_base.py +0 -0
  176. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_deployer_plugin.py +0 -0
  177. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_design_command.py +0 -0
  178. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_done_gates.py +0 -0
  179. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_draw_prompt.py +0 -0
  180. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_draw_references.py +0 -0
  181. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_drawio_mcp.py +0 -0
  182. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_home_path_fix.py +0 -0
  183. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_hotfix_command.py +0 -0
  184. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_init_guard.py +0 -0
  185. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_lang_profiles.py +0 -0
  186. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_list_stories.py +0 -0
  187. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_mcp_integration.py +0 -0
  188. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_model_config.py +0 -0
  189. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_modular_constitution.py +0 -0
  190. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_multi_prefix.py +0 -0
  191. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_project_visibility.py +0 -0
  192. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_prompt_cli_refs.py +0 -0
  193. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_prompt_structural_invariants.py +0 -0
  194. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_prompts_package.py +0 -0
  195. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_release.py +0 -0
  196. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_release_field.py +0 -0
  197. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_release_v110.py +0 -0
  198. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_review_command.py +0 -0
  199. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_rules_enrichment.py +0 -0
  200. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_scaffold.py +0 -0
  201. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_scaffold_developer_prefix.py +0 -0
  202. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_schemas.py +0 -0
  203. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_script_extraction.py +0 -0
  204. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_session_context.py +0 -0
  205. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_skill_structure.py +0 -0
  206. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_skills_enrichment.py +0 -0
  207. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_smart_regression.py +0 -0
  208. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_stack_references.py +0 -0
  209. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_status_command.py +0 -0
  210. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_statusline.py +0 -0
  211. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story014_release.py +0 -0
  212. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story015_ci_lint_gate.py +0 -0
  213. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story016_claude_md.py +0 -0
  214. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story017_init_claude_md.py +0 -0
  215. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story018_arch_staleness.py +0 -0
  216. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story019_bailout.py +0 -0
  217. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story020_horizon.py +0 -0
  218. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story021_rfc.py +0 -0
  219. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story022_decision_tree.py +0 -0
  220. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story023_test_quality.py +0 -0
  221. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story024_native_agent.py +0 -0
  222. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story025_ci_pipeline.py +0 -0
  223. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story026_issue_tracker.py +0 -0
  224. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story027_hooks.py +0 -0
  225. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story028_rule_scoping.py +0 -0
  226. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story029_doctor.py +0 -0
  227. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story030_lint.py +0 -0
  228. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story033_config_backfill.py +0 -0
  229. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story034_plan_config_refresh.py +0 -0
  230. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story035_readme_docs.py +0 -0
  231. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story037_regression_fix.py +0 -0
  232. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story038_call_graph_update.py +0 -0
  233. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story039_venv_config.py +0 -0
  234. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story040_layered_claude_md.py +0 -0
  235. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story042_spec_linter.py +0 -0
  236. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story043_active_clarify.py +0 -0
  237. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story044_consistency_check.py +0 -0
  238. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story045_auto_pr.py +0 -0
  239. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story046_agent_adapter.py +0 -0
  240. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story047_enterprise_flags.py +0 -0
  241. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story048_worktree_isolation.py +0 -0
  242. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story049_community_standards.py +0 -0
  243. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story050_doc_only_shortcut.py +0 -0
  244. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story051_workflow_streamlining.py +0 -0
  245. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story052_conditional_github_release.py +0 -0
  246. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story053_impact_regression.py +0 -0
  247. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story055_commands.py +0 -0
  248. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story055_config.py +0 -0
  249. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story055_spec_linter.py +0 -0
  250. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story056_commands.py +0 -0
  251. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story056_config.py +0 -0
  252. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story057_implicit_cleanup.py +0 -0
  253. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story058_opencode_extraction.py +0 -0
  254. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story058_routing_fix.py +0 -0
  255. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story060_init_hang.py +0 -0
  256. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story061_remove_thinking.py +0 -0
  257. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story062_mcp_recommendations.py +0 -0
  258. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story063_prompt_slimming.py +0 -0
  259. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story064_venv_local_md.py +0 -0
  260. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story065_sprint_model.py +0 -0
  261. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story072_developer_prefix.py +0 -0
  262. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim009_lazy_rules.py +0 -0
  263. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim010_dry_refactor.py +0 -0
  264. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim012_ci.py +0 -0
  265. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim014_clean.py +0 -0
  266. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim014_context.py +0 -0
  267. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim014_guard.py +0 -0
  268. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim014_lazy_viz.py +0 -0
  269. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim014_next_id.py +0 -0
  270. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim014_regression.py +0 -0
  271. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim014_sec_scope.py +0 -0
  272. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim014_validators.py +0 -0
  273. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim015_doctor.py +0 -0
  274. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim016_testmap_lint.py +0 -0
  275. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim017.py +0 -0
  276. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim018.py +0 -0
  277. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim019_plan_subphases.py +0 -0
  278. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim020_explore_stall_fix.py +0 -0
  279. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim021.py +0 -0
  280. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim022.py +0 -0
  281. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim023.py +0 -0
  282. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim024.py +0 -0
  283. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim025.py +0 -0
  284. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim026.py +0 -0
  285. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim027.py +0 -0
  286. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim028.py +0 -0
  287. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim029.py +0 -0
  288. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim030.py +0 -0
  289. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim031.py +0 -0
  290. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim032.py +0 -0
  291. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim033.py +0 -0
  292. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim034.py +0 -0
  293. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim035.py +0 -0
  294. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim036.py +0 -0
  295. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim037.py +0 -0
  296. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim038.py +0 -0
  297. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim039.py +0 -0
  298. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim040.py +0 -0
  299. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim041.py +0 -0
  300. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim042.py +0 -0
  301. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim043.py +0 -0
  302. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim044.py +0 -0
  303. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim045.py +0 -0
  304. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim046.py +0 -0
  305. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim047.py +0 -0
  306. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim048.py +0 -0
  307. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim049.py +0 -0
  308. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim051.py +0 -0
  309. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim052.py +0 -0
  310. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim053.py +0 -0
  311. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim054.py +0 -0
  312. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim055.py +0 -0
  313. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_story_slim056.py +0 -0
  314. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_tools.py +0 -0
  315. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_update_task.py +0 -0
  316. {pactkit-2.6.0 → pactkit-2.7.0}/tests/unit/test_visualize_modes.py +0 -0
@@ -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.6.0"
5
+ version: "2.6.1"
6
6
  stack: python
7
7
  root: .
8
8
  developer: "slim"
@@ -45,6 +45,17 @@ skills:
45
45
  - pactkit-trace
46
46
  - pactkit-visualize
47
47
  - pactkit-analyze
48
+ - project-act
49
+ - project-check
50
+ - project-clarify
51
+ - project-design
52
+ - project-done
53
+ - project-hotfix
54
+ - project-init
55
+ - project-plan
56
+ - project-pr
57
+ - project-release
58
+ - project-sprint
48
59
 
49
60
  # Rules — constitution modules
50
61
  rules:
@@ -4,6 +4,27 @@ 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.7.0] - 2026-03-27
8
+
9
+ ### Added
10
+ - **Commands → Skills Migration** (STORY-slim-063) — 11 PDCA commands now deploy as `skills/{name}/SKILL.md` subdirectories instead of flat `commands/{name}.md` files for Claude Code format. `VALID_SKILLS` expanded from 10 to 21 entries (10 embedded + 11 commands).
11
+ - **Legacy Command Cleanup** — `_cleanup_legacy_commands()` auto-removes old `project-*.md` from `commands/` on upgrade, preserving non-PactKit files.
12
+ - **Codex FormatProfile** (STORY-slim-060) — Re-added `codex` profile to core for thin adapter pattern support (`pactkit-codex` package).
13
+
14
+ ### Fixed
15
+ - **board.py update_task** (HOTFIX-slim-061) — `update_task` now recognizes bullet-format Done entries (`- **STORY-xxx**:`), not just heading format.
16
+ - **visualize --lazy focus** (HOTFIX-slim-062) — Removed hardcoded `--focus cli` refresh; added stem matching for focus target resolution.
17
+
18
+ ### Changed
19
+ - **Deploy summary** — Output now shows unified `Skills (embedded + commands)` count instead of separate Commands/Skills lines.
20
+ - **Cross-format isolation** — OpenCode and Codex profiles unaffected; commands still deploy as flat `.md` files for non-classic formats.
21
+
22
+ ## [2.6.1] - 2026-03-26
23
+
24
+ ### Fixed
25
+ - **OpenCode backward compatibility** — `pactkit-opencode` added as core dependency so `pip install pactkit` automatically includes OpenCode deployment support. Users upgrading from 2.5.0 no longer lose `--format opencode`.
26
+ - **Version sync** — `pactkit-opencode` version aligned to 2.6.0 to match core versioning.
27
+
7
28
  ## [2.6.0] - 2026-03-26
8
29
 
9
30
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pactkit
3
- Version: 2.6.0
3
+ Version: 2.7.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,6 +21,7 @@ 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-opencode>=2.6.0
24
25
  Requires-Dist: pyyaml>=6.0
25
26
  Provides-Extra: multilang
26
27
  Requires-Dist: tree-sitter-go>=0.25; extra == 'multilang'
@@ -4,13 +4,14 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pactkit"
7
- version = "2.6.0"
7
+ version = "2.7.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.6.0",
14
15
  ]
15
16
 
16
17
  authors = [
@@ -1,3 +1,3 @@
1
1
  """PactKit - Spec-driven agentic DevOps toolkit."""
2
2
 
3
- __version__ = "2.6.0"
3
+ __version__ = "2.7.0"
@@ -47,6 +47,7 @@ VALID_COMMANDS = frozenset(
47
47
 
48
48
  VALID_SKILLS = frozenset(
49
49
  {
50
+ # Embedded skills (auto-invoked by commands)
50
51
  "pactkit-visualize",
51
52
  "pactkit-board",
52
53
  "pactkit-scaffold",
@@ -57,6 +58,18 @@ VALID_SKILLS = frozenset(
57
58
  "pactkit-review",
58
59
  "pactkit-release",
59
60
  "pactkit-analyze",
61
+ # PDCA commands (STORY-slim-063: migrated from commands/ to skills/)
62
+ "project-plan",
63
+ "project-act",
64
+ "project-check",
65
+ "project-done",
66
+ "project-init",
67
+ "project-sprint",
68
+ "project-hotfix",
69
+ "project-design",
70
+ "project-clarify",
71
+ "project-release",
72
+ "project-pr",
60
73
  }
61
74
  )
62
75
 
@@ -314,7 +314,9 @@ def _deploy_classic(config=None, target=None):
314
314
  _deploy_claude_md(claude_root, enabled_rules)
315
315
  agent_models = config.get("agent_models", {})
316
316
  n_agents = _deploy_agents(agents_dir, enabled_agents, profile=classic_profile, agent_models=agent_models)
317
- n_commands = _deploy_commands(commands_dir, enabled_commands, profile=classic_profile, config=config)
317
+ # STORY-slim-063: Deploy commands as skills (to skills_dir, not commands_dir)
318
+ _cleanup_legacy_commands(commands_dir)
319
+ n_commands = _deploy_commands(skills_dir, enabled_commands, profile=classic_profile, config=config)
318
320
 
319
321
  # Deploy CI pipeline if configured (STORY-025)
320
322
  ci_config = config.get("ci", {})
@@ -334,16 +336,15 @@ def _deploy_classic(config=None, target=None):
334
336
  if target is None:
335
337
  _generate_project_claude_md(config)
336
338
 
337
- # Summary
339
+ # Summary — STORY-slim-063: commands are now deployed as skills
338
340
  total_agents = len(VALID_AGENTS)
339
- total_commands = len(VALID_COMMANDS)
340
341
  total_skills = len(VALID_SKILLS)
341
342
  total_rules = len(VALID_RULES)
342
343
 
343
344
  print(
344
345
  f"\n✅ Deployed: {n_agents}/{total_agents} Agents, "
345
- f"{n_commands}/{total_commands} Commands, "
346
- f"{n_skills}/{total_skills} Skills, "
346
+ f"{n_skills + n_commands}/{total_skills} Skills "
347
+ f"({n_skills} embedded + {n_commands} commands), "
347
348
  f"{n_rules}/{total_rules} Rules"
348
349
  )
349
350
  _print_mcp_recommendations()
@@ -484,6 +485,19 @@ def _cleanup_legacy(skills_dir):
484
485
  legacy.unlink()
485
486
 
486
487
 
488
+ def _cleanup_legacy_commands(commands_dir):
489
+ """Remove legacy project-*.md files from commands/ (STORY-slim-063).
490
+
491
+ After migration, commands are deployed as skills. Old flat .md files
492
+ in commands/ would be shadowed but should be cleaned up.
493
+ Non-PactKit files (e.g., ultra-think.md) are preserved.
494
+ """
495
+ if not commands_dir.exists():
496
+ return
497
+ for f in commands_dir.glob("project-*.md"):
498
+ f.unlink()
499
+
500
+
487
501
  def _migrate_from_scafpy(claude_root):
488
502
  """Migrate legacy scafpy-* remnants to pactkit-* naming.
489
503
 
@@ -792,11 +806,22 @@ def _deploy_commands(
792
806
  # e.g. 'project-plan' -> 'project-plan.md'
793
807
  enabled_filenames = {f"{cmd}.md" for cmd in enabled_commands}
794
808
 
795
- # Clean managed command files not in enabled set
809
+ # STORY-slim-063: For classic format, commands deploy as skills (subdirectory/SKILL.md).
810
+ # For other formats (plugin/marketplace), keep flat .md files.
811
+ _deploy_as_skill = profile.name == "classic" and _legacy_prefix is None
812
+
813
+ # Clean managed command files/dirs not in enabled set
796
814
  if commands_dir.exists():
797
- for f in commands_dir.glob("*.md"):
798
- if f.name.startswith("project-") and f.name not in enabled_filenames:
799
- f.unlink()
815
+ if _deploy_as_skill:
816
+ # Clean skill subdirectories for commands no longer enabled
817
+ for d in commands_dir.iterdir():
818
+ if d.is_dir() and d.name.startswith("project-") and d.name not in enabled_set:
819
+ import shutil
820
+ shutil.rmtree(d)
821
+ else:
822
+ for f in commands_dir.glob("*.md"):
823
+ if f.name.startswith("project-") and f.name not in enabled_filenames:
824
+ f.unlink()
800
825
 
801
826
  # Deploy enabled commands
802
827
  deployed = 0
@@ -820,7 +845,12 @@ def _deploy_commands(
820
845
  if _legacy_prefix is None
821
846
  else _rewrite_skills_prefix(content, _effective_prefix)
822
847
  )
823
- atomic_write(commands_dir / filename, rendered)
848
+
849
+ if _deploy_as_skill:
850
+ # STORY-slim-063: Write as skills_dir/{name}/SKILL.md
851
+ atomic_write(commands_dir / cmd_name / "SKILL.md", rendered)
852
+ else:
853
+ atomic_write(commands_dir / filename, rendered)
824
854
  deployed += 1
825
855
 
826
856
  return deployed
@@ -110,11 +110,5 @@ def run_visualize_graphs(project_root: Path) -> None:
110
110
  subprocess.run([sys.executable, str(viz_script), "visualize", mode_flag, mode],
111
111
  cwd=str(project_root))
112
112
 
113
- # Refresh focus graphs if they exist
114
- graph_dir = project_root / "docs" / "architecture" / "graphs"
115
- if (graph_dir / "focus_file_graph.mmd").exists():
116
- subprocess.run([sys.executable, str(viz_script), "visualize", "--focus", "cli"],
117
- cwd=str(project_root))
118
- if (graph_dir / "focus_call_graph.mmd").exists():
119
- subprocess.run([sys.executable, str(viz_script), "visualize", "--focus", "cli", mode_flag, "call"],
120
- cwd=str(project_root))
113
+ # Focus graphs are user-generated on demand (--focus <target>), not auto-refreshed.
114
+ # Removed hardcoded --focus cli refresh (HOTFIX-slim-062).
@@ -146,6 +146,26 @@ FORMAT_PROFILES: dict[str, FormatProfile] = {
146
146
  supports_mcp=True,
147
147
  skills_path_var="~/.config/opencode/skills",
148
148
  ),
149
+ "codex": FormatProfile(
150
+ name="codex",
151
+ display_name="Codex CLI",
152
+ global_config_dir="~/.codex",
153
+ project_config_dir=".codex",
154
+ skills_dir="~/.codex/skills",
155
+ agents_dir="~/.codex/agents",
156
+ commands_dir="~/.codex/prompts",
157
+ rules_dir="~/.codex/rules",
158
+ project_instructions_file="AGENTS.md",
159
+ global_instructions_file="AGENTS.md",
160
+ pactkit_yaml_path=".codex/pactkit.yaml",
161
+ agent_format="md",
162
+ rules_import_style="inline",
163
+ excluded_agent_fields=frozenset({"permissionMode", "memory", "skills", "hooks"}),
164
+ has_custom_commands=True,
165
+ supports_model_routing=False,
166
+ supports_mcp=True,
167
+ skills_path_var="~/.codex/skills",
168
+ ),
149
169
  }
150
170
 
151
171
  # Deployment modes that are not environment formats
@@ -155,9 +175,10 @@ _DEPLOYMENT_MODES: frozenset[str] = frozenset({"plugin", "marketplace"})
155
175
  VALID_FORMATS: frozenset[str] = frozenset(FORMAT_PROFILES.keys()) | _DEPLOYMENT_MODES
156
176
 
157
177
  # Ordered candidate paths for pactkit.yaml discovery (first existing wins)
158
- # Order = preference: OpenCode > Classic
178
+ # Order = preference: OpenCode > Codex > Classic
159
179
  PACTKIT_YAML_CANDIDATES: list[str] = [
160
180
  FORMAT_PROFILES["opencode"].pactkit_yaml_path,
181
+ FORMAT_PROFILES["codex"].pactkit_yaml_path,
161
182
  FORMAT_PROFILES["classic"].pactkit_yaml_path,
162
183
  ]
163
184
 
@@ -189,6 +189,10 @@ def update_task(sid, tasks_list):
189
189
  story_pat = rf"(#{{3,4}} \[?{re.escape(sid)}\]?:?.*?)(?=\n#{{3,4}} |\Z)"
190
190
  story_match = re.search(story_pat, content, re.DOTALL)
191
191
  if not story_match:
192
+ # Fallback: check if story exists as a bullet in the Done section
193
+ done_pos = content.find(_DONE)
194
+ if done_pos != -1 and re.search(rf"\*\*{re.escape(sid)}\*\*", content[done_pos:]):
195
+ return f"✅ Already done: {sid} (all tasks complete)"
192
196
  return f"❌ Story {sid} not found"
193
197
  story_block = story_match.group(1)
194
198
 
@@ -600,7 +600,7 @@ def _build_file_graph(root, all_files, module_index, file_to_node, focus, depth=
600
600
  target_ids = set()
601
601
  for f, nid in file_to_node.items():
602
602
  rel = str(f.relative_to(root))
603
- if rel == focus or rel.endswith('/' + focus):
603
+ if rel == focus or rel.endswith('/' + focus) or f.stem == focus:
604
604
  target_ids.add(nid)
605
605
  if not target_ids:
606
606
  return None, f"❌ Focus target '{focus}' not found. (Scanned {len(all_files)} files)"
@@ -117,13 +117,14 @@ class TestInitClassicFormat:
117
117
  assert len(agent_files) >= 1
118
118
 
119
119
  def test_init_creates_command_files(self, tmp_path):
120
- """pactkit init creates command playbook files."""
120
+ """pactkit init creates command playbook files (STORY-slim-063: now in skills/ subdirs)."""
121
121
  target = tmp_path / "classic_deploy"
122
122
  run_pactkit("init", "-t", str(target))
123
123
 
124
- commands_dir = target / "commands"
125
- command_files = list(commands_dir.glob("*.md"))
126
- assert len(command_files) >= 1
124
+ skills_dir = target / "skills"
125
+ # Commands are now deployed as skills/{name}/SKILL.md
126
+ command_skill_files = list(skills_dir.glob("project-*/SKILL.md"))
127
+ assert len(command_skill_files) >= 1
127
128
 
128
129
 
129
130
  @pytest.mark.e2e
@@ -260,14 +261,16 @@ class TestDeploymentCompleteness:
260
261
  assert deployed == set(VALID_AGENTS)
261
262
 
262
263
  def test_all_commands_deployed(self, deploy_target):
263
- """AC2: Exactly 11 commands deployed, names match VALID_COMMANDS exactly."""
264
+ """AC2: Exactly 11 commands deployed as skills/{name}/SKILL.md (STORY-slim-063)."""
264
265
  from pactkit.config import VALID_COMMANDS
265
- commands_dir = deploy_target / "commands"
266
- deployed = {f.stem for f in commands_dir.glob("*.md")}
266
+ skills_dir = deploy_target / "skills"
267
+ # Commands are now deployed as skills/{name}/SKILL.md subdirectories
268
+ deployed = {d.name for d in skills_dir.iterdir()
269
+ if d.is_dir() and d.name.startswith("project-")}
267
270
  assert deployed == set(VALID_COMMANDS)
268
271
 
269
272
  def test_all_skills_deployed_with_skill_md(self, deploy_target):
270
- """AC3: Exactly 10 skill dirs deployed, each contains SKILL.md."""
273
+ """AC3: Exactly 21 skill dirs deployed (10 embedded + 11 commands), each contains SKILL.md."""
271
274
  from pactkit.config import VALID_SKILLS
272
275
  skills_dir = deploy_target / "skills"
273
276
  deployed_dirs = {d.name for d in skills_dir.iterdir() if d.is_dir()}
@@ -112,7 +112,8 @@ class TestDeployedCommandFiles:
112
112
  from pactkit.generators.deployer import deploy
113
113
  deploy(mode='expert')
114
114
 
115
- check_file = tmp_path / '.claude' / 'commands' / 'project-check.md'
115
+ # STORY-slim-063: commands are now deployed as skills/{name}/SKILL.md
116
+ check_file = tmp_path / '.claude' / 'skills' / 'project-check' / 'SKILL.md'
116
117
  assert check_file.exists()
117
118
  content = check_file.read_text()
118
119
  fm = _parse_frontmatter(content)
@@ -43,8 +43,9 @@ class TestGetDefaultConfig:
43
43
  assert len(cfg["commands"]) == 11
44
44
 
45
45
  def test_default_skills_count(self):
46
+ # STORY-slim-063: VALID_SKILLS now includes 11 commands migrated to skills/ subdirs
46
47
  cfg = _config().get_default_config()
47
- assert len(cfg["skills"]) == 10
48
+ assert len(cfg["skills"]) == 21
48
49
 
49
50
  def test_default_rules_count(self):
50
51
  """9 rule modules (added 09-sectional-write)."""
@@ -76,11 +76,14 @@ class TestScenario1_StaleCommandsCleaned:
76
76
  assert not (cmds / "project-old-removed.md").exists()
77
77
 
78
78
  def test_current_commands_all_exist(self, tmp_path):
79
+ # STORY-slim-063: commands are now deployed as skills/{name}/SKILL.md
79
80
  _run_deploy(tmp_path)
80
- cmds = tmp_path / ".claude" / "commands"
81
+ skills_dir = tmp_path / ".claude" / "skills"
81
82
 
82
83
  for filename in COMMANDS_CONTENT:
83
- assert (cmds / filename).is_file(), f"Missing: {filename}"
84
+ cmd_name = filename.removesuffix(".md")
85
+ assert (skills_dir / cmd_name / "SKILL.md").is_file(), \
86
+ f"Missing: skills/{cmd_name}/SKILL.md"
84
87
 
85
88
 
86
89
  class TestScenario2_UserCommandsPreserved:
@@ -97,8 +97,9 @@ class TestSkillPromotion:
97
97
  }
98
98
 
99
99
  def test_valid_skills_count(self):
100
+ # STORY-slim-063: VALID_SKILLS expanded to 21 (10 embedded + 11 commands)
100
101
  cfg = _config()
101
- assert len(cfg.VALID_SKILLS) == 10
102
+ assert len(cfg.VALID_SKILLS) == 21
102
103
 
103
104
  def test_new_skills_present(self):
104
105
  cfg = _config()
@@ -136,9 +137,10 @@ class TestSkillPromotion:
136
137
  f"{var_name} should have YAML frontmatter"
137
138
 
138
139
  def test_default_config_has_10_skills(self):
140
+ # STORY-slim-063: default config skills now includes all 21 (10 embedded + 11 commands)
139
141
  cfg = _config()
140
142
  default = cfg.get_default_config()
141
- assert len(default['skills']) == 10
143
+ assert len(default['skills']) == 21
142
144
 
143
145
  def test_default_config_has_9_commands(self):
144
146
  """STORY-051: default config now has 11 commands (added project-release, project-pr)."""
@@ -109,11 +109,15 @@ class TestFormatProfilesRegistry:
109
109
  assert p.supports_model_routing is True
110
110
  assert p.pactkit_yaml_path == ".opencode/pactkit.yaml"
111
111
 
112
- def test_codex_profile_removed(self):
113
- """STORY-slim-059: codex profile no longer exists."""
112
+ def test_codex_profile_exists(self):
113
+ """STORY-slim-060: codex profile registered for thin adapter."""
114
114
  from pactkit.profiles import FORMAT_PROFILES
115
115
 
116
- assert "codex" not in FORMAT_PROFILES
116
+ assert "codex" in FORMAT_PROFILES
117
+ p = FORMAT_PROFILES["codex"]
118
+ assert p.name == "codex"
119
+ assert p.display_name == "Codex CLI"
120
+ assert p.global_config_dir == "~/.codex"
117
121
 
118
122
  def test_classic_excluded_fields(self):
119
123
  from pactkit.profiles import FORMAT_PROFILES
@@ -285,16 +285,17 @@ class TestDeployedOutputIntegration:
285
285
  assert "{VISUALIZE_CMD}" not in content
286
286
 
287
287
  def test_classic_command_has_classic_path(self, tmp_path):
288
- """Classic commands should have ~/.claude/skills/ references."""
288
+ """Classic commands should have ~/.claude/skills/ references (STORY-slim-063: now skills subdirs)."""
289
289
  from pactkit.generators.deployer import _deploy_commands
290
290
  from pactkit.profiles import get_profile
291
291
 
292
- cmd_dir = tmp_path / "commands"
293
- cmd_dir.mkdir()
292
+ skills_dir = tmp_path / "skills"
293
+ skills_dir.mkdir()
294
294
  profile = get_profile("classic")
295
- _deploy_commands(cmd_dir, ["project-done"], profile=profile)
295
+ _deploy_commands(skills_dir, ["project-done"], profile=profile)
296
296
 
297
- done_cmd = cmd_dir / "project-done.md"
297
+ # STORY-slim-063: deployed as skills_dir/{name}/SKILL.md
298
+ done_cmd = skills_dir / "project-done" / "SKILL.md"
298
299
  assert done_cmd.exists()
299
300
  content = done_cmd.read_text()
300
301
  assert "~/.claude/skills" in content
@@ -42,10 +42,13 @@ class TestFullConfigDeploysAll:
42
42
  assert (agents_dir / f"{name}.md").is_file(), f"Missing agent: {name}"
43
43
 
44
44
  def test_all_commands_deployed(self, tmp_path):
45
+ # STORY-slim-063: commands are now deployed as skills/{name}/SKILL.md
45
46
  claude = _run_deploy(tmp_path, config=get_default_config())
46
- cmds_dir = claude / "commands"
47
+ skills_dir = claude / "skills"
47
48
  for filename in COMMANDS_CONTENT:
48
- assert (cmds_dir / filename).is_file(), f"Missing command: {filename}"
49
+ cmd_name = filename.removesuffix(".md")
50
+ assert (skills_dir / cmd_name / "SKILL.md").is_file(), \
51
+ f"Missing command skill: skills/{cmd_name}/SKILL.md"
49
52
 
50
53
  def test_all_skills_deployed(self, tmp_path):
51
54
  claude = _run_deploy(tmp_path, config=get_default_config())
@@ -123,19 +126,20 @@ class TestPartialAgentConfig:
123
126
 
124
127
  class TestPartialCommandConfig:
125
128
  def test_only_selected_commands_deployed(self, tmp_path):
129
+ # STORY-slim-063: commands are now deployed as skills/{name}/SKILL.md
126
130
  cfg = get_default_config()
127
131
  cfg["commands"] = ["project-plan", "project-act", "project-done"]
128
132
 
129
133
  claude = _run_deploy(tmp_path, config=cfg)
130
- cmds_dir = claude / "commands"
134
+ skills_dir = claude / "skills"
131
135
 
132
- assert (cmds_dir / "project-plan.md").is_file()
133
- assert (cmds_dir / "project-act.md").is_file()
134
- assert (cmds_dir / "project-done.md").is_file()
136
+ assert (skills_dir / "project-plan" / "SKILL.md").is_file()
137
+ assert (skills_dir / "project-act" / "SKILL.md").is_file()
138
+ assert (skills_dir / "project-done" / "SKILL.md").is_file()
135
139
 
136
140
  # Others should NOT exist
137
- assert not (cmds_dir / "project-check.md").exists()
138
- assert not (cmds_dir / "project-sprint.md").exists()
141
+ assert not (skills_dir / "project-check" / "SKILL.md").exists()
142
+ assert not (skills_dir / "project-sprint" / "SKILL.md").exists()
139
143
 
140
144
  def test_user_custom_command_preserved(self, tmp_path):
141
145
  claude = tmp_path / ".claude"
@@ -235,16 +239,18 @@ class TestConfigAutoGeneration:
235
239
 
236
240
  class TestDeploymentSummary:
237
241
  def test_summary_printed_full(self, tmp_path, capsys):
238
- # STORY-051: 11 commands (added project-release, project-pr)
242
+ # STORY-slim-063: summary format changed to unified Skills count
243
+ # "21/21 Skills (10 embedded + 11 commands)"
239
244
  _run_deploy(tmp_path, config=get_default_config())
240
245
  output = capsys.readouterr().out
241
246
  assert "9/9 Agents" in output
242
- assert "11/11 Commands" in output
243
- assert "10/10 Skills" in output
247
+ assert "21/21 Skills" in output
248
+ assert "10 embedded" in output
249
+ assert "11 commands" in output
244
250
  assert "8/8 Rules" in output or "9/9 Rules" in output # 9 rules after 09-sectional-write
245
251
 
246
252
  def test_summary_printed_partial(self, tmp_path, capsys):
247
- # STORY-051: total commands is now 11
253
+ # STORY-slim-063: partial deploy — commands counted within Skills line
248
254
  cfg = get_default_config()
249
255
  cfg["agents"] = ["system-architect", "senior-developer"]
250
256
  cfg["commands"] = ["project-plan", "project-act", "project-done"]
@@ -252,7 +258,8 @@ class TestDeploymentSummary:
252
258
  _run_deploy(tmp_path, config=cfg)
253
259
  output = capsys.readouterr().out
254
260
  assert "2/9 Agents" in output
255
- assert "3/11 Commands" in output
261
+ # 10 embedded skills + 3 commands = 13 total skills deployed out of 21
262
+ assert "13/21 Skills" in output
256
263
 
257
264
 
258
265
  # ===========================================================================
@@ -145,13 +145,15 @@ class TestSprintDeployment:
145
145
  """Scenario 6: 部署后文件存在且正确"""
146
146
 
147
147
  def test_sprint_file_deployed(self, tmp_path):
148
+ # STORY-slim-063: commands are now deployed as skills/{name}/SKILL.md
148
149
  _deploy(tmp_path)
149
- sprint_file = tmp_path / '.claude' / 'commands' / 'project-sprint.md'
150
- assert sprint_file.exists(), 'project-sprint.md 未部署'
150
+ sprint_file = tmp_path / '.claude' / 'skills' / 'project-sprint' / 'SKILL.md'
151
+ assert sprint_file.exists(), 'project-sprint/SKILL.md 未部署'
151
152
 
152
153
  def test_deployed_sprint_has_frontmatter(self, tmp_path):
154
+ # STORY-slim-063: commands are now deployed as skills/{name}/SKILL.md
153
155
  _deploy(tmp_path)
154
- sprint_file = tmp_path / '.claude' / 'commands' / 'project-sprint.md'
156
+ sprint_file = tmp_path / '.claude' / 'skills' / 'project-sprint' / 'SKILL.md'
155
157
  content = sprint_file.read_text()
156
158
  fm = _parse_frontmatter(content)
157
159
  assert 'description' in fm
@@ -184,14 +186,15 @@ class TestBackwardCompatibility:
184
186
  assert agent in AGENTS_EXPERT, f'现有 Agent {agent} 丢失'
185
187
 
186
188
  def test_all_existing_commands_deployed(self, tmp_path):
189
+ # STORY-slim-063: commands are now deployed as skills/{name}/SKILL.md
187
190
  _deploy(tmp_path)
188
- commands_dir = tmp_path / '.claude' / 'commands'
191
+ skills_dir = tmp_path / '.claude' / 'skills'
189
192
  expected = [
190
- 'project-plan.md', 'project-act.md', 'project-check.md',
191
- 'project-done.md', 'project-init.md',
193
+ 'project-plan', 'project-act', 'project-check',
194
+ 'project-done', 'project-init',
192
195
  ]
193
196
  for cmd in expected:
194
- assert (commands_dir / cmd).exists(), f'部署后 {cmd} 丢失'
197
+ assert (skills_dir / cmd / 'SKILL.md').exists(), f'部署后 skills/{cmd}/SKILL.md 丢失'
195
198
 
196
199
 
197
200
  # =============================================================================
@@ -84,12 +84,13 @@ class TestAC4DeclineWarning:
84
84
  class TestDeployedInitCommand:
85
85
 
86
86
  def test_deployed_init_contains_git_guard(self, tmp_path):
87
- """Deployed project-init.md contains git guard section."""
87
+ """Deployed project-init/SKILL.md contains git guard section (STORY-slim-063)."""
88
88
  from pactkit.config import get_default_config
89
89
  from pactkit.generators.deployer import deploy
90
90
  config = get_default_config()
91
91
  deploy(config=config, target=str(tmp_path / '.claude'))
92
- init_file = tmp_path / '.claude' / 'commands' / 'project-init.md'
92
+ # STORY-slim-063: commands are now deployed as skills/{name}/SKILL.md
93
+ init_file = tmp_path / '.claude' / 'skills' / 'project-init' / 'SKILL.md'
93
94
  assert init_file.exists()
94
95
  content = init_file.read_text()
95
96
  assert 'git' in content.lower()
@@ -92,12 +92,13 @@ class TestAC4UserConfirmation:
92
92
  class TestDeployedPlanCommand:
93
93
 
94
94
  def test_deployed_plan_contains_greenfield(self, tmp_path):
95
- """Deployed project-plan.md contains greenfield heuristic."""
95
+ """Deployed project-plan/SKILL.md contains greenfield heuristic (STORY-slim-063)."""
96
96
  from pactkit.config import get_default_config
97
97
  from pactkit.generators.deployer import deploy
98
98
  config = get_default_config()
99
99
  deploy(config=config, target=str(tmp_path / '.claude'))
100
- plan_file = tmp_path / '.claude' / 'commands' / 'project-plan.md'
100
+ # STORY-slim-063: commands are now deployed as skills/{name}/SKILL.md
101
+ plan_file = tmp_path / '.claude' / 'skills' / 'project-plan' / 'SKILL.md'
101
102
  assert plan_file.exists()
102
103
  content = plan_file.read_text()
103
104
  assert 'greenfield' in content.lower() or 'Greenfield' in content