specify-cli 0.12.12__tar.gz → 0.12.13__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 (462) hide show
  1. {specify_cli-0.12.12 → specify_cli-0.12.13}/CHANGELOG.md +15 -0
  2. {specify_cli-0.12.12 → specify_cli-0.12.13}/PKG-INFO +2 -2
  3. {specify_cli-0.12.12 → specify_cli-0.12.13}/README.md +1 -1
  4. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/install/one-time.md +2 -1
  5. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/install/pipx.md +2 -1
  6. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/installation.md +1 -1
  7. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/ARCHITECTURE.md +1 -2
  8. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/self-test/preset.yml +0 -6
  9. {specify_cli-0.12.12 → specify_cli-0.12.13}/pyproject.toml +1 -1
  10. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/agents.py +49 -0
  11. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/extensions/__init__.py +5 -0
  12. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/kiro_cli/__init__.py +1 -0
  13. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/presets/__init__.py +40 -2
  14. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/workflows/expressions.py +22 -2
  15. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/workflows/steps/if_then/__init__.py +2 -2
  16. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/workflows/steps/shell/__init__.py +43 -20
  17. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/workflows/steps/switch/__init__.py +14 -0
  18. {specify_cli-0.12.12 → specify_cli-0.12.13}/templates/commands/constitution.md +1 -1
  19. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_kiro_cli.py +3 -0
  20. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_extension_skills.py +59 -0
  21. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_extensions.py +179 -0
  22. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_presets.py +334 -1
  23. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_workflows.py +221 -101
  24. {specify_cli-0.12.12 → specify_cli-0.12.13}/workflows/README.md +6 -0
  25. specify_cli-0.12.12/presets/self-test/templates/agent-file-template.md +0 -9
  26. {specify_cli-0.12.12 → specify_cli-0.12.13}/.devcontainer/devcontainer.json +0 -0
  27. {specify_cli-0.12.12 → specify_cli-0.12.13}/.devcontainer/post-create.sh +0 -0
  28. {specify_cli-0.12.12 → specify_cli-0.12.13}/.editorconfig +0 -0
  29. {specify_cli-0.12.12 → specify_cli-0.12.13}/.gitattributes +0 -0
  30. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/CODEOWNERS +0 -0
  31. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/ISSUE_TEMPLATE/agent_request.yml +0 -0
  32. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  33. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/ISSUE_TEMPLATE/bundle_submission.yml +0 -0
  34. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  35. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/ISSUE_TEMPLATE/extension_submission.yml +0 -0
  36. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  37. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/ISSUE_TEMPLATE/preset_submission.yml +0 -0
  38. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  39. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/aw/actions-lock.json +0 -0
  40. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/dependabot.yml +0 -0
  41. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/skills/add-community-extension/SKILL.md +0 -0
  42. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/workflows/RELEASE-PROCESS.md +0 -0
  43. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/workflows/add-community-extension.lock.yml +0 -0
  44. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/workflows/add-community-extension.md +0 -0
  45. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/workflows/add-community-preset.lock.yml +0 -0
  46. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/workflows/add-community-preset.md +0 -0
  47. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/workflows/bug-assess.lock.yml +0 -0
  48. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/workflows/bug-assess.md +0 -0
  49. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/workflows/bug-fix.lock.yml +0 -0
  50. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/workflows/bug-fix.md +0 -0
  51. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/workflows/bug-test.lock.yml +0 -0
  52. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/workflows/bug-test.md +0 -0
  53. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/workflows/catalog-assign.yml +0 -0
  54. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/workflows/codeql.yml +0 -0
  55. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/workflows/docs.yml +0 -0
  56. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/workflows/lint.yml +0 -0
  57. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/workflows/publish-pypi.yml +0 -0
  58. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/workflows/release-trigger.yml +0 -0
  59. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/workflows/release.yml +0 -0
  60. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/workflows/stale.yml +0 -0
  61. {specify_cli-0.12.12 → specify_cli-0.12.13}/.github/workflows/test.yml +0 -0
  62. {specify_cli-0.12.12 → specify_cli-0.12.13}/.gitignore +0 -0
  63. {specify_cli-0.12.12 → specify_cli-0.12.13}/.markdownlint-cli2.jsonc +0 -0
  64. {specify_cli-0.12.12 → specify_cli-0.12.13}/.pre-commit-config.yaml +0 -0
  65. {specify_cli-0.12.12 → specify_cli-0.12.13}/.zenodo.json +0 -0
  66. {specify_cli-0.12.12 → specify_cli-0.12.13}/AGENTS.md +0 -0
  67. {specify_cli-0.12.12 → specify_cli-0.12.13}/CITATION.cff +0 -0
  68. {specify_cli-0.12.12 → specify_cli-0.12.13}/CODE_OF_CONDUCT.md +0 -0
  69. {specify_cli-0.12.12 → specify_cli-0.12.13}/CONTRIBUTING.md +0 -0
  70. {specify_cli-0.12.12 → specify_cli-0.12.13}/DEVELOPMENT.md +0 -0
  71. {specify_cli-0.12.12 → specify_cli-0.12.13}/LICENSE +0 -0
  72. {specify_cli-0.12.12 → specify_cli-0.12.13}/SECURITY.md +0 -0
  73. {specify_cli-0.12.12 → specify_cli-0.12.13}/SUPPORT.md +0 -0
  74. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/.gitignore +0 -0
  75. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/README.md +0 -0
  76. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/community/bundles.md +0 -0
  77. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/community/extensions.md +0 -0
  78. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/community/friends.md +0 -0
  79. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/community/overview.md +0 -0
  80. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/community/presets.md +0 -0
  81. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/community/walkthroughs.md +0 -0
  82. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/concepts/complex-features.md +0 -0
  83. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/concepts/sdd.md +0 -0
  84. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/concepts/spec-persistence.md +0 -0
  85. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/docfx.json +0 -0
  86. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/guides/evolving-specs.md +0 -0
  87. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/guides/monorepo.md +0 -0
  88. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/index.md +0 -0
  89. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/install/air-gapped.md +0 -0
  90. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/install/uv.md +0 -0
  91. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/local-development.md +0 -0
  92. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/quickstart.md +0 -0
  93. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/reference/authentication.md +0 -0
  94. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/reference/bundles.md +0 -0
  95. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/reference/core.md +0 -0
  96. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/reference/extensions.md +0 -0
  97. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/reference/integrations.md +0 -0
  98. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/reference/overview.md +0 -0
  99. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/reference/presets.md +0 -0
  100. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/reference/workflows.md +0 -0
  101. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/template/public/main.css +0 -0
  102. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/toc.yml +0 -0
  103. {specify_cli-0.12.12 → specify_cli-0.12.13}/docs/upgrade.md +0 -0
  104. {specify_cli-0.12.12 → specify_cli-0.12.13}/examples/bundles/business-analyst/README.md +0 -0
  105. {specify_cli-0.12.12 → specify_cli-0.12.13}/examples/bundles/business-analyst/bundle.yml +0 -0
  106. {specify_cli-0.12.12 → specify_cli-0.12.13}/examples/bundles/developer/README.md +0 -0
  107. {specify_cli-0.12.12 → specify_cli-0.12.13}/examples/bundles/developer/bundle.yml +0 -0
  108. {specify_cli-0.12.12 → specify_cli-0.12.13}/examples/bundles/product-manager/README.md +0 -0
  109. {specify_cli-0.12.12 → specify_cli-0.12.13}/examples/bundles/product-manager/bundle.yml +0 -0
  110. {specify_cli-0.12.12 → specify_cli-0.12.13}/examples/bundles/security-researcher/README.md +0 -0
  111. {specify_cli-0.12.12 → specify_cli-0.12.13}/examples/bundles/security-researcher/bundle.yml +0 -0
  112. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/EXTENSION-API-REFERENCE.md +0 -0
  113. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/EXTENSION-DEVELOPMENT-GUIDE.md +0 -0
  114. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/EXTENSION-PUBLISHING-GUIDE.md +0 -0
  115. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/EXTENSION-USER-GUIDE.md +0 -0
  116. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/README.md +0 -0
  117. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/RFC-EXTENSION-SYSTEM.md +0 -0
  118. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/agent-context/README.md +0 -0
  119. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/agent-context/agent-context-config.yml +0 -0
  120. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/agent-context/agent-context-defaults.json +0 -0
  121. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/agent-context/commands/speckit.agent-context.update.md +0 -0
  122. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/agent-context/extension.yml +0 -0
  123. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/agent-context/scripts/bash/update-agent-context.sh +0 -0
  124. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/agent-context/scripts/powershell/update-agent-context.ps1 +0 -0
  125. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/agent-context/scripts/python/update_agent_context.py +0 -0
  126. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/bug/README.md +0 -0
  127. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/bug/commands/speckit.bug.assess.md +0 -0
  128. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/bug/commands/speckit.bug.fix.md +0 -0
  129. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/bug/commands/speckit.bug.test.md +0 -0
  130. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/bug/extension.yml +0 -0
  131. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/catalog.community.json +0 -0
  132. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/catalog.json +0 -0
  133. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/git/README.md +0 -0
  134. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/git/commands/speckit.git.commit.md +0 -0
  135. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/git/commands/speckit.git.feature.md +0 -0
  136. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/git/commands/speckit.git.initialize.md +0 -0
  137. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/git/commands/speckit.git.remote.md +0 -0
  138. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/git/commands/speckit.git.validate.md +0 -0
  139. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/git/config-template.yml +0 -0
  140. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/git/extension.yml +0 -0
  141. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/git/git-config.yml +0 -0
  142. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/git/scripts/bash/auto-commit.sh +0 -0
  143. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/git/scripts/bash/create-new-feature-branch.sh +0 -0
  144. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/git/scripts/bash/git-common.sh +0 -0
  145. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/git/scripts/bash/initialize-repo.sh +0 -0
  146. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/git/scripts/powershell/auto-commit.ps1 +0 -0
  147. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/git/scripts/powershell/create-new-feature-branch.ps1 +0 -0
  148. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/git/scripts/powershell/git-common.ps1 +0 -0
  149. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/git/scripts/powershell/initialize-repo.ps1 +0 -0
  150. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/selftest/commands/selftest.md +0 -0
  151. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/selftest/extension.yml +0 -0
  152. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/template/.gitignore +0 -0
  153. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/template/CHANGELOG.md +0 -0
  154. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/template/EXAMPLE-README.md +0 -0
  155. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/template/LICENSE +0 -0
  156. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/template/README.md +0 -0
  157. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/template/commands/example.md +0 -0
  158. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/template/config-template.yml +0 -0
  159. {specify_cli-0.12.12 → specify_cli-0.12.13}/extensions/template/extension.yml +0 -0
  160. {specify_cli-0.12.12 → specify_cli-0.12.13}/integrations/CONTRIBUTING.md +0 -0
  161. {specify_cli-0.12.12 → specify_cli-0.12.13}/integrations/README.md +0 -0
  162. {specify_cli-0.12.12 → specify_cli-0.12.13}/integrations/catalog.community.json +0 -0
  163. {specify_cli-0.12.12 → specify_cli-0.12.13}/integrations/catalog.json +0 -0
  164. {specify_cli-0.12.12 → specify_cli-0.12.13}/media/bootstrap-claude-code.gif +0 -0
  165. {specify_cli-0.12.12 → specify_cli-0.12.13}/media/logo_large.webp +0 -0
  166. {specify_cli-0.12.12 → specify_cli-0.12.13}/media/logo_small.webp +0 -0
  167. {specify_cli-0.12.12 → specify_cli-0.12.13}/media/spec-kit-video-header.jpg +0 -0
  168. {specify_cli-0.12.12 → specify_cli-0.12.13}/media/specify_cli.gif +0 -0
  169. {specify_cli-0.12.12 → specify_cli-0.12.13}/newsletters/2026-April.md +0 -0
  170. {specify_cli-0.12.12 → specify_cli-0.12.13}/newsletters/2026-February.md +0 -0
  171. {specify_cli-0.12.12 → specify_cli-0.12.13}/newsletters/2026-June.md +0 -0
  172. {specify_cli-0.12.12 → specify_cli-0.12.13}/newsletters/2026-March.md +0 -0
  173. {specify_cli-0.12.12 → specify_cli-0.12.13}/newsletters/2026-May.md +0 -0
  174. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/PUBLISHING.md +0 -0
  175. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/README.md +0 -0
  176. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/catalog.community.json +0 -0
  177. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/catalog.json +0 -0
  178. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/lean/README.md +0 -0
  179. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/lean/commands/speckit.constitution.md +0 -0
  180. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/lean/commands/speckit.implement.md +0 -0
  181. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/lean/commands/speckit.plan.md +0 -0
  182. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/lean/commands/speckit.specify.md +0 -0
  183. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/lean/commands/speckit.tasks.md +0 -0
  184. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/lean/preset.yml +0 -0
  185. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/scaffold/README.md +0 -0
  186. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/scaffold/commands/speckit.myext.myextcmd.md +0 -0
  187. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/scaffold/commands/speckit.specify.md +0 -0
  188. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/scaffold/preset.yml +0 -0
  189. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/scaffold/templates/myext-template.md +0 -0
  190. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/scaffold/templates/spec-template.md +0 -0
  191. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/self-test/commands/speckit.specify.md +0 -0
  192. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/self-test/commands/speckit.wrap-test.md +0 -0
  193. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/self-test/templates/checklist-template.md +0 -0
  194. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/self-test/templates/constitution-template.md +0 -0
  195. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/self-test/templates/plan-template.md +0 -0
  196. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/self-test/templates/spec-template.md +0 -0
  197. {specify_cli-0.12.12 → specify_cli-0.12.13}/presets/self-test/templates/tasks-template.md +0 -0
  198. {specify_cli-0.12.12 → specify_cli-0.12.13}/scripts/bash/check-prerequisites.sh +0 -0
  199. {specify_cli-0.12.12 → specify_cli-0.12.13}/scripts/bash/common.sh +0 -0
  200. {specify_cli-0.12.12 → specify_cli-0.12.13}/scripts/bash/create-new-feature.sh +0 -0
  201. {specify_cli-0.12.12 → specify_cli-0.12.13}/scripts/bash/setup-plan.sh +0 -0
  202. {specify_cli-0.12.12 → specify_cli-0.12.13}/scripts/bash/setup-tasks.sh +0 -0
  203. {specify_cli-0.12.12 → specify_cli-0.12.13}/scripts/powershell/check-prerequisites.ps1 +0 -0
  204. {specify_cli-0.12.12 → specify_cli-0.12.13}/scripts/powershell/common.ps1 +0 -0
  205. {specify_cli-0.12.12 → specify_cli-0.12.13}/scripts/powershell/create-new-feature.ps1 +0 -0
  206. {specify_cli-0.12.12 → specify_cli-0.12.13}/scripts/powershell/setup-plan.ps1 +0 -0
  207. {specify_cli-0.12.12 → specify_cli-0.12.13}/scripts/powershell/setup-tasks.ps1 +0 -0
  208. {specify_cli-0.12.12 → specify_cli-0.12.13}/scripts/python/check_prerequisites.py +0 -0
  209. {specify_cli-0.12.12 → specify_cli-0.12.13}/scripts/python/common.py +0 -0
  210. {specify_cli-0.12.12 → specify_cli-0.12.13}/spec-driven.md +0 -0
  211. {specify_cli-0.12.12 → specify_cli-0.12.13}/spec-kit.code-workspace +0 -0
  212. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/__init__.py +0 -0
  213. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/_agent_config.py +0 -0
  214. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/_assets.py +0 -0
  215. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/_console.py +0 -0
  216. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/_github_http.py +0 -0
  217. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/_init_options.py +0 -0
  218. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/_invocation_style.py +0 -0
  219. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/_project.py +0 -0
  220. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/_toml_string.py +0 -0
  221. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/_utils.py +0 -0
  222. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/_version.py +0 -0
  223. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/authentication/__init__.py +0 -0
  224. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/authentication/azure_devops.py +0 -0
  225. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/authentication/base.py +0 -0
  226. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/authentication/config.py +0 -0
  227. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/authentication/github.py +0 -0
  228. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/authentication/http.py +0 -0
  229. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/__init__.py +0 -0
  230. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/commands_impl/__init__.py +0 -0
  231. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/commands_impl/catalog_config.py +0 -0
  232. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/lib/__init__.py +0 -0
  233. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/lib/project.py +0 -0
  234. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/lib/versioning.py +0 -0
  235. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/lib/yamlio.py +0 -0
  236. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/models/__init__.py +0 -0
  237. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/models/catalog.py +0 -0
  238. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/models/manifest.py +0 -0
  239. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/models/records.py +0 -0
  240. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/services/__init__.py +0 -0
  241. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/services/adapters.py +0 -0
  242. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/services/catalog_stack.py +0 -0
  243. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/services/conflict.py +0 -0
  244. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/services/installer.py +0 -0
  245. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/services/packager.py +0 -0
  246. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/services/primitives.py +0 -0
  247. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/services/references.py +0 -0
  248. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/services/resolver.py +0 -0
  249. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/bundler/services/validator.py +0 -0
  250. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/catalogs.py +0 -0
  251. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/commands/__init__.py +0 -0
  252. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/commands/bundle/__init__.py +0 -0
  253. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/commands/init.py +0 -0
  254. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/extensions/_commands.py +0 -0
  255. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integration_runtime.py +0 -0
  256. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integration_scaffold.py +0 -0
  257. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integration_state.py +0 -0
  258. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integration_status.py +0 -0
  259. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/__init__.py +0 -0
  260. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/_commands.py +0 -0
  261. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/_helpers.py +0 -0
  262. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/_install_commands.py +0 -0
  263. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/_migrate_commands.py +0 -0
  264. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/_query_commands.py +0 -0
  265. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/_scaffold_commands.py +0 -0
  266. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/agy/__init__.py +0 -0
  267. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/amp/__init__.py +0 -0
  268. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/auggie/__init__.py +0 -0
  269. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/base.py +0 -0
  270. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/bob/__init__.py +0 -0
  271. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/catalog.py +0 -0
  272. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/claude/__init__.py +0 -0
  273. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/cline/__init__.py +0 -0
  274. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/codebuddy/__init__.py +0 -0
  275. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/codex/__init__.py +0 -0
  276. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/copilot/__init__.py +0 -0
  277. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/cursor_agent/__init__.py +0 -0
  278. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/devin/__init__.py +0 -0
  279. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/firebender/__init__.py +0 -0
  280. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/forge/__init__.py +0 -0
  281. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/gemini/__init__.py +0 -0
  282. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/generic/__init__.py +0 -0
  283. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/goose/__init__.py +0 -0
  284. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/hermes/__init__.py +0 -0
  285. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/junie/__init__.py +0 -0
  286. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/kilocode/__init__.py +0 -0
  287. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/kimi/__init__.py +0 -0
  288. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/lingma/__init__.py +0 -0
  289. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/manifest.py +0 -0
  290. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/omp/__init__.py +0 -0
  291. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/opencode/__init__.py +0 -0
  292. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/pi/__init__.py +0 -0
  293. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/qodercli/__init__.py +0 -0
  294. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/qwen/__init__.py +0 -0
  295. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/rovodev/__init__.py +0 -0
  296. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/shai/__init__.py +0 -0
  297. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/tabnine/__init__.py +0 -0
  298. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/trae/__init__.py +0 -0
  299. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/vibe/__init__.py +0 -0
  300. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/zcode/__init__.py +0 -0
  301. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/integrations/zed/__init__.py +0 -0
  302. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/presets/_commands.py +0 -0
  303. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/shared_infra.py +0 -0
  304. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/workflows/__init__.py +0 -0
  305. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/workflows/_commands.py +0 -0
  306. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/workflows/base.py +0 -0
  307. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/workflows/catalog.py +0 -0
  308. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/workflows/engine.py +0 -0
  309. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/workflows/steps/__init__.py +0 -0
  310. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/workflows/steps/command/__init__.py +0 -0
  311. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/workflows/steps/do_while/__init__.py +0 -0
  312. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/workflows/steps/fan_in/__init__.py +0 -0
  313. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/workflows/steps/fan_out/__init__.py +0 -0
  314. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/workflows/steps/gate/__init__.py +0 -0
  315. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/workflows/steps/init/__init__.py +0 -0
  316. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/workflows/steps/prompt/__init__.py +0 -0
  317. {specify_cli-0.12.12 → specify_cli-0.12.13}/src/specify_cli/workflows/steps/while_loop/__init__.py +0 -0
  318. {specify_cli-0.12.12 → specify_cli-0.12.13}/templates/checklist-template.md +0 -0
  319. {specify_cli-0.12.12 → specify_cli-0.12.13}/templates/commands/analyze.md +0 -0
  320. {specify_cli-0.12.12 → specify_cli-0.12.13}/templates/commands/checklist.md +0 -0
  321. {specify_cli-0.12.12 → specify_cli-0.12.13}/templates/commands/clarify.md +0 -0
  322. {specify_cli-0.12.12 → specify_cli-0.12.13}/templates/commands/converge.md +0 -0
  323. {specify_cli-0.12.12 → specify_cli-0.12.13}/templates/commands/implement.md +0 -0
  324. {specify_cli-0.12.12 → specify_cli-0.12.13}/templates/commands/plan.md +0 -0
  325. {specify_cli-0.12.12 → specify_cli-0.12.13}/templates/commands/specify.md +0 -0
  326. {specify_cli-0.12.12 → specify_cli-0.12.13}/templates/commands/tasks.md +0 -0
  327. {specify_cli-0.12.12 → specify_cli-0.12.13}/templates/commands/taskstoissues.md +0 -0
  328. {specify_cli-0.12.12 → specify_cli-0.12.13}/templates/constitution-template.md +0 -0
  329. {specify_cli-0.12.12 → specify_cli-0.12.13}/templates/plan-template.md +0 -0
  330. {specify_cli-0.12.12 → specify_cli-0.12.13}/templates/spec-template.md +0 -0
  331. {specify_cli-0.12.12 → specify_cli-0.12.13}/templates/tasks-template.md +0 -0
  332. {specify_cli-0.12.12 → specify_cli-0.12.13}/templates/vscode-settings.json +0 -0
  333. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/__init__.py +0 -0
  334. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/auth_helpers.py +0 -0
  335. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/bundler_helpers.py +0 -0
  336. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/conftest.py +0 -0
  337. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/contract/test_bundle_cli.py +0 -0
  338. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/contract/test_catalog_schema.py +0 -0
  339. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/contract/test_manifest_schema.py +0 -0
  340. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/extensions/__init__.py +0 -0
  341. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/extensions/bug/__init__.py +0 -0
  342. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/extensions/bug/test_bug_extension.py +0 -0
  343. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/extensions/git/__init__.py +0 -0
  344. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/extensions/git/test_git_extension.py +0 -0
  345. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/extensions/test_agent_context_cli_free.py +0 -0
  346. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/extensions/test_extension_agent_context.py +0 -0
  347. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/extensions/test_update_agent_context_feature_json.py +0 -0
  348. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/extensions/test_update_agent_context_python_parity.py +0 -0
  349. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/hooks/TESTING.md +0 -0
  350. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/hooks/plan.md +0 -0
  351. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/hooks/spec.md +0 -0
  352. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/hooks/tasks.md +0 -0
  353. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/http_helpers.py +0 -0
  354. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integration/test_bundler_catalog_stack.py +0 -0
  355. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integration/test_bundler_init_install.py +0 -0
  356. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integration/test_bundler_install_flow.py +0 -0
  357. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integration/test_bundler_local_install.py +0 -0
  358. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integration/test_bundler_offline.py +0 -0
  359. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integration/test_bundler_security_paths.py +0 -0
  360. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/__init__.py +0 -0
  361. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/conftest.py +0 -0
  362. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_base.py +0 -0
  363. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_cli.py +0 -0
  364. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_extra_args.py +0 -0
  365. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_home_isolation.py +0 -0
  366. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_agy.py +0 -0
  367. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_amp.py +0 -0
  368. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_auggie.py +0 -0
  369. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_base_markdown.py +0 -0
  370. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_base_skills.py +0 -0
  371. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_base_toml.py +0 -0
  372. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_base_yaml.py +0 -0
  373. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_bob.py +0 -0
  374. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_catalog.py +0 -0
  375. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_claude.py +0 -0
  376. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_cline.py +0 -0
  377. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_codebuddy.py +0 -0
  378. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_codex.py +0 -0
  379. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_copilot.py +0 -0
  380. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_cursor_agent.py +0 -0
  381. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_devin.py +0 -0
  382. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_firebender.py +0 -0
  383. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_forge.py +0 -0
  384. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_gemini.py +0 -0
  385. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_generic.py +0 -0
  386. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_goose.py +0 -0
  387. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_hermes.py +0 -0
  388. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_junie.py +0 -0
  389. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_kilocode.py +0 -0
  390. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_kimi.py +0 -0
  391. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_lingma.py +0 -0
  392. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_omp.py +0 -0
  393. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_opencode.py +0 -0
  394. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_pi.py +0 -0
  395. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_qodercli.py +0 -0
  396. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_qwen.py +0 -0
  397. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_rovodev.py +0 -0
  398. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_scaffold.py +0 -0
  399. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_shai.py +0 -0
  400. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_state.py +0 -0
  401. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_subcommand.py +0 -0
  402. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_tabnine.py +0 -0
  403. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_trae.py +0 -0
  404. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_vibe.py +0 -0
  405. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_zcode.py +0 -0
  406. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_integration_zed.py +0 -0
  407. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_manifest.py +0 -0
  408. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_registry.py +0 -0
  409. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/integrations/test_skill_frontmatter_quoting.py +0 -0
  410. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/self_upgrade_helpers.py +0 -0
  411. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_agent_config_consistency.py +0 -0
  412. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_authentication.py +0 -0
  413. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_branch_numbering.py +0 -0
  414. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_check_prerequisites_paths_only.py +0 -0
  415. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_check_prerequisites_python_parity.py +0 -0
  416. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_check_tool.py +0 -0
  417. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_cli_version.py +0 -0
  418. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_command_template_py_scripts.py +0 -0
  419. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_commands_package.py +0 -0
  420. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_console_imports.py +0 -0
  421. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_extension_registration.py +0 -0
  422. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_extension_update_hardening.py +0 -0
  423. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_github_http.py +0 -0
  424. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_github_workflows.py +0 -0
  425. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_init_dir.py +0 -0
  426. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_init_dir_cli.py +0 -0
  427. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_live_transient_windows.py +0 -0
  428. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_merge.py +0 -0
  429. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_post_process.py +0 -0
  430. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_ps1_encoding.py +0 -0
  431. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_registrar_path_traversal.py +0 -0
  432. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_self_upgrade_detection.py +0 -0
  433. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_self_upgrade_execution.py +0 -0
  434. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_self_upgrade_guidance.py +0 -0
  435. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_self_upgrade_verification.py +0 -0
  436. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_setup_plan_feature_json.py +0 -0
  437. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_setup_plan_no_overwrite.py +0 -0
  438. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_setup_tasks.py +0 -0
  439. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_shared_infra_integrity.py +0 -0
  440. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_timestamp_branches.py +0 -0
  441. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_upgrade.py +0 -0
  442. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_utils.py +0 -0
  443. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_utils_assets_imports.py +0 -0
  444. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_version_imports.py +0 -0
  445. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/test_workflow_run_without_project.py +0 -0
  446. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/unit/test_bundler_adapters.py +0 -0
  447. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/unit/test_bundler_catalog_config.py +0 -0
  448. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/unit/test_bundler_conflict.py +0 -0
  449. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/unit/test_bundler_packager.py +0 -0
  450. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/unit/test_bundler_primitives.py +0 -0
  451. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/unit/test_bundler_records.py +0 -0
  452. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/unit/test_bundler_references.py +0 -0
  453. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/unit/test_bundler_resolver.py +0 -0
  454. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/unit/test_bundler_validator.py +0 -0
  455. {specify_cli-0.12.12 → specify_cli-0.12.13}/tests/unit/test_bundler_versioning.py +0 -0
  456. {specify_cli-0.12.12 → specify_cli-0.12.13}/workflows/ARCHITECTURE.md +0 -0
  457. {specify_cli-0.12.12 → specify_cli-0.12.13}/workflows/PUBLISHING.md +0 -0
  458. {specify_cli-0.12.12 → specify_cli-0.12.13}/workflows/catalog.community.json +0 -0
  459. {specify_cli-0.12.12 → specify_cli-0.12.13}/workflows/catalog.json +0 -0
  460. {specify_cli-0.12.12 → specify_cli-0.12.13}/workflows/speckit/workflow.yml +0 -0
  461. {specify_cli-0.12.12 → specify_cli-0.12.13}/workflows/step-catalog.community.json +0 -0
  462. {specify_cli-0.12.12 → specify_cli-0.12.13}/workflows/step-catalog.json +0 -0
@@ -2,6 +2,21 @@
2
2
 
3
3
  <!-- insert new changelog below this comment -->
4
4
 
5
+ ## [0.12.13] - 2026-07-13
6
+
7
+ ### Changed
8
+
9
+ - fix(workflows): fail switch step on non-mapping cases instead of crashing (#3481)
10
+ - Cleanup agent-file-template.md (#2579)
11
+ - fix: mark Kiro integration as multi-install safe (#3472)
12
+ - fix: rewrite extension-relative subdir paths in generated command bodies (#3444)
13
+ - fix(templates): point constitution sync checklist at installed command files (#3418)
14
+ - feat(workflows): make shell step timeout configurable (#3327) (#3328)
15
+ - docs: clarify that release tags keep the leading v prefix (#3463)
16
+ - fix(workflows): don't crash on membership test against a non-iterable (#3448)
17
+ - fix(workflows): if-step validate accepts falsy non-list else (#3264)
18
+ - chore: release 0.12.12, begin 0.12.13.dev0 development (#3490)
19
+
5
20
  ## [0.12.12] - 2026-07-13
6
21
 
7
22
  ### Changed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specify-cli
3
- Version: 0.12.12
3
+ Version: 0.12.13
4
4
  Summary: Specify CLI, part of GitHub Spec Kit. A tool to bootstrap your projects for Spec-Driven Development (SDD).
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.11
@@ -65,7 +65,7 @@ Spec-Driven Development **flips the script** on traditional software development
65
65
 
66
66
  ### 1. Install Specify CLI
67
67
 
68
- Requires **[uv](https://docs.astral.sh/uv/)** ([install uv](./docs/install/uv.md)). Replace `vX.Y.Z` with the latest tag from [Releases](https://github.com/github/spec-kit/releases):
68
+ Requires **[uv](https://docs.astral.sh/uv/)** ([install uv](./docs/install/uv.md)). Replace `vX.Y.Z` with the latest release tag from [Releases](https://github.com/github/spec-kit/releases) — keep the leading `v` (for example, `v0.12.11`, not `0.12.11`):
69
69
 
70
70
  ```bash
71
71
  uv tool install specify-cli --from git+https://github.com/github/spec-kit.git@vX.Y.Z
@@ -45,7 +45,7 @@ Spec-Driven Development **flips the script** on traditional software development
45
45
 
46
46
  ### 1. Install Specify CLI
47
47
 
48
- Requires **[uv](https://docs.astral.sh/uv/)** ([install uv](./docs/install/uv.md)). Replace `vX.Y.Z` with the latest tag from [Releases](https://github.com/github/spec-kit/releases):
48
+ Requires **[uv](https://docs.astral.sh/uv/)** ([install uv](./docs/install/uv.md)). Replace `vX.Y.Z` with the latest release tag from [Releases](https://github.com/github/spec-kit/releases) — keep the leading `v` (for example, `v0.12.11`, not `0.12.11`):
49
49
 
50
50
  ```bash
51
51
  uv tool install specify-cli --from git+https://github.com/github/spec-kit.git@vX.Y.Z
@@ -11,7 +11,8 @@ If you want to try Spec Kit without installing it permanently, use `uvx` to run
11
11
  # Create a new project (latest from main)
12
12
  uvx --from git+https://github.com/github/spec-kit.git specify init <PROJECT_NAME>
13
13
 
14
- # Or target a specific release (replace vX.Y.Z with a tag from Releases)
14
+ # Or target a specific release (replace vX.Y.Z with a tag from Releases;
15
+ # keep the leading v, e.g. v0.12.11 not 0.12.11)
15
16
  uvx --from git+https://github.com/github/spec-kit.git@vX.Y.Z specify init <PROJECT_NAME>
16
17
 
17
18
  # Initialize in the current directory
@@ -7,7 +7,8 @@
7
7
  Pin a specific release tag for stability (check [Releases](https://github.com/github/spec-kit/releases) for the latest):
8
8
 
9
9
  ```bash
10
- # Install a specific stable release (recommended — replace vX.Y.Z with the latest tag)
10
+ # Install a specific stable release (recommended — replace vX.Y.Z with the
11
+ # latest tag, keeping the leading v, e.g. v0.12.11 not 0.12.11)
11
12
  pipx install git+https://github.com/github/spec-kit.git@vX.Y.Z
12
13
 
13
14
  # Or install latest from main (may include unreleased changes)
@@ -15,7 +15,7 @@
15
15
 
16
16
  ### Persistent Installation (Recommended)
17
17
 
18
- Install once and use everywhere. Replace `vX.Y.Z` with a tag from [Releases](https://github.com/github/spec-kit/releases):
18
+ Install once and use everywhere. Replace `vX.Y.Z` with a release tag from [Releases](https://github.com/github/spec-kit/releases) — keep the leading `v` (for example, `v0.12.11`, not `0.12.11`):
19
19
 
20
20
  > [!NOTE]
21
21
  > The command below requires **[uv](https://docs.astral.sh/uv/)**. If you see `command not found: uv`, [install uv first](./install/uv.md).
@@ -158,8 +158,7 @@ presets/
158
158
  ├── plan-template.md
159
159
  ├── tasks-template.md
160
160
  ├── checklist-template.md
161
- ├── constitution-template.md
162
- └── agent-file-template.md
161
+ └── constitution-template.md
163
162
  ```
164
163
 
165
164
  ## Module Structure
@@ -44,12 +44,6 @@ provides:
44
44
  description: "Self-test constitution template"
45
45
  replaces: "constitution-template"
46
46
 
47
- - type: "template"
48
- name: "agent-file-template"
49
- file: "templates/agent-file-template.md"
50
- description: "Self-test agent file template"
51
- replaces: "agent-file-template"
52
-
53
47
  - type: "command"
54
48
  name: "speckit.specify"
55
49
  file: "commands/speckit.specify.md"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "specify-cli"
3
- version = "0.12.12"
3
+ version = "0.12.13"
4
4
  description = "Specify CLI, part of GitHub Spec Kit. A tool to bootstrap your projects for Spec-Driven Development (SDD)."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -213,6 +213,52 @@ class CommandRegistrar:
213
213
  ".specify.specify/", ".specify/"
214
214
  )
215
215
 
216
+ @staticmethod
217
+ def rewrite_extension_paths(
218
+ text: str, extension_id: str, extension_dir: Path
219
+ ) -> str:
220
+ """Rewrite extension-relative paths to their installed locations.
221
+
222
+ Extension command bodies reference bundled files relative to the
223
+ extension root (e.g. ``agents/control/commander.md``). After install
224
+ those files live under ``.specify/extensions/<id>/``, so bare
225
+ references would resolve against the workspace root and never be
226
+ found (#2101).
227
+
228
+ Only directories that actually exist inside *extension_dir* are
229
+ rewritten, keeping the behaviour conservative and avoiding false
230
+ positives on prose. ``commands`` (slash-command sources), ``specs``
231
+ (user project artifacts) and dot-directories are never rewritten.
232
+ """
233
+ if not isinstance(text, str) or not text:
234
+ return text
235
+
236
+ skip = {"commands", ".git", "specs"}
237
+ try:
238
+ subdirs = [
239
+ entry.name
240
+ for entry in extension_dir.iterdir()
241
+ if entry.is_dir()
242
+ and entry.name not in skip
243
+ and not entry.name.startswith(".")
244
+ ]
245
+ except OSError:
246
+ return text
247
+
248
+ for subdir in subdirs:
249
+ # Only rewrite relative references (subdir/... or ./subdir/...);
250
+ # absolute paths like /subdir/... keep their meaning. Use a
251
+ # callable replacement: subdir/extension_id come from the
252
+ # filesystem and could contain backslashes or "\1"-like
253
+ # sequences, which would corrupt a string replacement template.
254
+ replacement = f".specify/extensions/{extension_id}/{subdir}/"
255
+ text = re.sub(
256
+ r'(^|[\s`"\'(])(?:\./)?' + re.escape(subdir) + "/",
257
+ lambda m: m.group(1) + replacement,
258
+ text,
259
+ )
260
+ return text
261
+
216
262
  def render_markdown_command(
217
263
  self, frontmatter: dict, body: str, source_id: str, context_note: str = None
218
264
  ) -> str:
@@ -639,6 +685,9 @@ class CommandRegistrar:
639
685
  frontmatter[key] = core_frontmatter[key]
640
686
  frontmatter.pop("strategy", None)
641
687
 
688
+ if extension_id:
689
+ body = self.rewrite_extension_paths(body, extension_id, source_root)
690
+
642
691
  frontmatter = self._adjust_script_paths(
643
692
  frontmatter, extension_id=extension_id
644
693
  )
@@ -1078,6 +1078,11 @@ class ExtensionManager:
1078
1078
  frontmatter = registrar._adjust_script_paths(
1079
1079
  frontmatter, extension_id=manifest.id
1080
1080
  )
1081
+ # Mirror the register_commands() rewrite (#2101): resolve
1082
+ # extension-relative subdir references (agents/, knowledge-base/,
1083
+ # etc.) to their installed .specify/extensions/<id>/ location
1084
+ # before the generic placeholder/path resolution below.
1085
+ body = registrar.rewrite_extension_paths(body, manifest.id, extension_dir)
1081
1086
  body = registrar.resolve_skill_placeholders(
1082
1087
  selected_ai, frontmatter, body, self.project_root, extension_id=manifest.id
1083
1088
  )
@@ -13,6 +13,7 @@ _KIRO_ARG_FALLBACK = "(the user will provide the argument in this conversation)"
13
13
 
14
14
  class KiroCliIntegration(MarkdownIntegration):
15
15
  key = "kiro-cli"
16
+ multi_install_safe = True
16
17
  config = {
17
18
  "name": "Kiro CLI",
18
19
  "folder": ".kiro/",
@@ -778,6 +778,7 @@ class PresetManager:
778
778
  matching_cmds, ext_id, ext_dir,
779
779
  self.project_root,
780
780
  context_note=f"\n<!-- Extension: {ext_id} -->\n<!-- Config: .specify/extensions/{ext_id}/ -->\n",
781
+ extension_id=ext_id,
781
782
  )
782
783
  registered = True
783
784
  except Exception:
@@ -1199,6 +1200,8 @@ class PresetManager:
1199
1200
  "command_name": cmd_name,
1200
1201
  "source_file": source_file,
1201
1202
  "source": f"extension:{manifest.id}",
1203
+ "extension_id": manifest.id,
1204
+ "extension_dir": ext_root,
1202
1205
  }
1203
1206
  modern_skill_name, legacy_skill_name = self._skill_names_for_command(cmd_name)
1204
1207
  restore_index.setdefault(modern_skill_name, restore_info)
@@ -1463,6 +1466,17 @@ class PresetManager:
1463
1466
  if extension_restore:
1464
1467
  content = extension_restore["source_file"].read_text(encoding="utf-8")
1465
1468
  frontmatter, body = registrar.parse_frontmatter(content)
1469
+ # Mirror the register-time rewrite (#2101): resolve
1470
+ # extension-relative subdir references (agents/,
1471
+ # knowledge-base/, etc.) to their installed location before
1472
+ # the generic placeholder resolution below, otherwise
1473
+ # restoring after a preset override removal would leave
1474
+ # bare, unresolvable paths in the skill body.
1475
+ body = registrar.rewrite_extension_paths(
1476
+ body,
1477
+ extension_restore["extension_id"],
1478
+ extension_restore["extension_dir"],
1479
+ )
1466
1480
  if isinstance(selected_ai, str):
1467
1481
  body = registrar.resolve_skill_placeholders(
1468
1482
  selected_ai, frontmatter, body, self.project_root
@@ -3038,6 +3052,8 @@ class PresetResolver:
3038
3052
  "path": candidate,
3039
3053
  "source": source,
3040
3054
  "strategy": "replace",
3055
+ "extension_id": ext_id,
3056
+ "extension_dir": ext_dir,
3041
3057
  })
3042
3058
 
3043
3059
  # Priority 4: Core templates (always "replace")
@@ -3157,10 +3173,32 @@ class PresetResolver:
3157
3173
  if not layers:
3158
3174
  return None
3159
3175
 
3176
+ def _read_layer_content(layer: Dict[str, Any]) -> str:
3177
+ """Read a layer's raw text, rewriting extension-relative subdir
3178
+ references (agents/, knowledge-base/, etc.) to their installed
3179
+ location when the layer is extension-provided (#2101).
3180
+
3181
+ Extension layers are always inserted with strategy "replace"
3182
+ (see collect_all_layers), so a layer only ever needs this
3183
+ rewrite when it wins outright above or serves as the
3184
+ composition base below — never as a mid-stack composing
3185
+ (append/prepend/wrap) layer.
3186
+ """
3187
+ text = layer["path"].read_text(encoding="utf-8")
3188
+ extension_id = layer.get("extension_id")
3189
+ extension_dir = layer.get("extension_dir")
3190
+ if extension_id and extension_dir:
3191
+ from ..agents import CommandRegistrar
3192
+
3193
+ text = CommandRegistrar.rewrite_extension_paths(
3194
+ text, extension_id, extension_dir
3195
+ )
3196
+ return text
3197
+
3160
3198
  # If the top (highest-priority) layer is replace, it wins entirely —
3161
3199
  # lower layers are irrelevant regardless of their strategies.
3162
3200
  if layers[0]["strategy"] == "replace":
3163
- return layers[0]["path"].read_text(encoding="utf-8")
3201
+ return _read_layer_content(layers[0])
3164
3202
 
3165
3203
  # Composition: build content bottom-up from the effective base.
3166
3204
  # The base is the nearest replace layer scanning from highest priority
@@ -3183,7 +3221,7 @@ class PresetResolver:
3183
3221
 
3184
3222
  # Convert to reversed_layers index
3185
3223
  base_reversed_idx = len(layers) - 1 - base_layer_idx
3186
- content = layers[base_layer_idx]["path"].read_text(encoding="utf-8")
3224
+ content = _read_layer_content(layers[base_layer_idx])
3187
3225
  # Compose only the layers above the base (higher priority = lower index in layers,
3188
3226
  # higher index in reversed_layers). Process bottom-up from base+1.
3189
3227
  start_idx = base_reversed_idx + 1
@@ -464,9 +464,9 @@ def _evaluate_simple_expression(expr: str, namespace: dict[str, Any]) -> Any:
464
464
  if op == "<=":
465
465
  return _safe_compare(left, right, "<=")
466
466
  if op == " in ":
467
- return left in right if right is not None else False
467
+ return _safe_membership(left, right, negate=False)
468
468
  if op == " not in ":
469
- return left not in right if right is not None else True
469
+ return _safe_membership(left, right, negate=True)
470
470
 
471
471
  # Numeric literal
472
472
  try:
@@ -511,6 +511,26 @@ def _coerce_number(value: Any) -> Any:
511
511
  return value
512
512
 
513
513
 
514
+ def _safe_membership(left: Any, right: Any, *, negate: bool) -> bool:
515
+ """Safely evaluate ``left in right`` (or ``not in``) without crashing.
516
+
517
+ ``left in right`` raises ``TypeError`` whenever the operands don't support
518
+ membership testing — most commonly a non-iterable right operand (``None``,
519
+ an int, a bool), but also cases like an unhashable ``left`` against a set.
520
+ In every such case the membership relation is undefined, so treat it as
521
+ ``False`` (``not in`` as ``True``) rather than leaking the error out of the
522
+ evaluator and crashing the whole workflow. Mirrors the graceful
523
+ ``TypeError`` handling in ``_safe_compare`` for the ordering operators, and
524
+ generalizes the previous ``right is not None`` guard to any operand pair
525
+ that can't be membership-tested.
526
+ """
527
+ try:
528
+ contained = left in right
529
+ except TypeError:
530
+ contained = False
531
+ return not contained if negate else contained
532
+
533
+
514
534
  def _safe_compare(left: Any, right: Any, op: str) -> bool:
515
535
  """Compare two values for ordering, coercing numeric strings when possible.
516
536
 
@@ -47,8 +47,8 @@ class IfThenStep(StepBase):
47
47
  errors.append(
48
48
  f"If step {config.get('id', '?')!r}: 'then' must be a list of steps."
49
49
  )
50
- else_branch = config.get("else", [])
51
- if else_branch and not isinstance(else_branch, list):
50
+ else_branch = config.get("else")
51
+ if else_branch is not None and not isinstance(else_branch, list):
52
52
  errors.append(
53
53
  f"If step {config.get('id', '?')!r}: 'else' must be a list of steps."
54
54
  )
@@ -3,6 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import json
6
+ import math
6
7
  import subprocess
7
8
  from typing import Any
8
9
 
@@ -25,15 +26,20 @@ class ShellStep(StepBase):
25
26
  run_cmd = str(run_cmd)
26
27
 
27
28
  cwd = context.project_root or "."
28
- # Defensive: the engine does not auto-validate step config, so an
29
- # invalid ``timeout`` (string, None, ...) would otherwise raise a
30
- # TypeError from subprocess.run() and crash the whole run. Mirror
31
- # the engine's handling of unvalidated ``continue_on_error`` by
32
- # only honoring well-formed values and falling back to the default.
29
+ # Per-step execution timeout in seconds; defaults to 300 for backward
30
+ # compatibility. The engine does not auto-validate step config, so
31
+ # validate here as well — a caller that skips WorkflowEngine.validate()
32
+ # must fail the step cleanly rather than crash subprocess.run() with a
33
+ # TypeError (or silently coerce ``timeout: true`` to a 1s duration,
34
+ # since bool is an int subclass).
33
35
  timeout = config.get("timeout", 300)
34
- if isinstance(timeout, bool) or not isinstance(timeout, int) or timeout <= 0:
35
- timeout = 300
36
-
36
+ timeout_error = self._timeout_error(config)
37
+ if timeout_error is not None:
38
+ return StepResult(
39
+ status=StepStatus.FAILED,
40
+ error=timeout_error,
41
+ output={"exit_code": -1, "stdout": "", "stderr": "invalid timeout"},
42
+ )
37
43
  # NOTE: shell=True is required to support pipes, redirects, and
38
44
  # multi-command expressions in workflow YAML. Workflow authors
39
45
  # control commands; catalog-installed workflows should be reviewed
@@ -92,6 +98,32 @@ class ShellStep(StepBase):
92
98
  output={"exit_code": -1, "stdout": "", "stderr": str(exc)},
93
99
  )
94
100
 
101
+ @staticmethod
102
+ def _timeout_error(config: dict[str, Any]) -> str | None:
103
+ """Return an error message if ``config['timeout']`` is invalid, else None.
104
+
105
+ Shared by execute() and validate() so both paths reject the same
106
+ values with the same message. An absent ``timeout`` is valid (the
107
+ default is used). bool is a subclass of int, but ``timeout: true`` is a
108
+ config error rather than a duration, so it is rejected explicitly.
109
+ Non-finite floats (YAML ``.inf``/``.nan``) pass a plain ``> 0`` check
110
+ but would raise in subprocess.run(), so they are rejected too.
111
+ """
112
+ if "timeout" not in config:
113
+ return None
114
+ timeout = config["timeout"]
115
+ if (
116
+ isinstance(timeout, bool)
117
+ or not isinstance(timeout, (int, float))
118
+ or not math.isfinite(timeout)
119
+ or timeout <= 0
120
+ ):
121
+ return (
122
+ f"Shell step {config.get('id', '?')!r}: 'timeout' must be a "
123
+ f"positive number of seconds, got {timeout!r}."
124
+ )
125
+ return None
126
+
95
127
  def validate(self, config: dict[str, Any]) -> list[str]:
96
128
  errors = super().validate(config)
97
129
  if "run" not in config:
@@ -114,16 +146,7 @@ class ShellStep(StepBase):
114
146
  f"Shell step {config.get('id', '?')!r}: 'output_format' must "
115
147
  f"be 'json' when present, got {output_format!r}."
116
148
  )
117
- if "timeout" in config:
118
- timeout = config["timeout"]
119
- # bool is an int subclass, so reject it explicitly.
120
- if (
121
- isinstance(timeout, bool)
122
- or not isinstance(timeout, int)
123
- or timeout <= 0
124
- ):
125
- errors.append(
126
- f"Shell step {config.get('id', '?')!r}: 'timeout' must be a "
127
- f"positive integer (seconds) when present, got {timeout!r}."
128
- )
149
+ timeout_error = self._timeout_error(config)
150
+ if timeout_error is not None:
151
+ errors.append(timeout_error)
129
152
  return errors
@@ -26,6 +26,20 @@ class SwitchStep(StepBase):
26
26
  str_value = str(value) if value is not None else ""
27
27
 
28
28
  cases = config.get("cases", {})
29
+ if not isinstance(cases, dict):
30
+ # The engine does not auto-validate step config, so an unvalidated
31
+ # run with a non-mapping ``cases`` (a list/scalar authoring mistake)
32
+ # would otherwise raise AttributeError from ``.items()`` below and
33
+ # crash the whole run. Fail this step loudly instead, mirroring the
34
+ # fan-out step's non-list ``items`` handling.
35
+ return StepResult(
36
+ status=StepStatus.FAILED,
37
+ error=(
38
+ f"Switch step {config.get('id', '?')!r}: 'cases' must be a "
39
+ f"mapping, got {type(cases).__name__}."
40
+ ),
41
+ output={"matched_case": None, "expression_value": value},
42
+ )
29
43
  for case_key, case_steps in cases.items():
30
44
  if str(case_key) == str_value:
31
45
  return StepResult(
@@ -81,7 +81,7 @@ Follow this execution flow:
81
81
  - Read `.specify/templates/plan-template.md` and ensure any "Constitution Check" or rules align with updated principles.
82
82
  - Read `.specify/templates/spec-template.md` for scope/requirements alignment—update if constitution adds/removes mandatory sections or constraints.
83
83
  - Read `.specify/templates/tasks-template.md` and ensure task categorization reflects new or removed principle-driven task types (e.g., observability, versioning, testing discipline).
84
- - Read each command file in `.specify/templates/commands/*.md` (including this one) to verify no outdated references (agent-specific names like CLAUDE only) remain when generic guidance is required.
84
+ - Read each installed Spec Kit command file for your agent (including this one) — named `speckit.*` or `speckit-*` (dot or hyphen depending on the agent), or laid out as `speckit-<name>/SKILL.md` for skills-based integrations, e.g. in `.github/agents/`, `.github/skills/`, `.claude/skills/`, or your agent's equivalent commands directory — to verify no outdated references (CLAUDE-only or other agent-specific names) remain when generic guidance is required.
85
85
  - Read any runtime guidance docs (e.g., `README.md`, `docs/quickstart.md`, or agent-specific guidance files if present). Update references to principles changed.
86
86
 
87
87
  5. Produce a Sync Impact Report (prepend as an HTML comment at top of the constitution file after update):
@@ -42,6 +42,9 @@ class TestKiroCliIntegration(MarkdownIntegrationTests):
42
42
  COMMANDS_SUBDIR = "prompts"
43
43
  REGISTRAR_DIR = ".kiro/prompts"
44
44
 
45
+ def test_declares_multi_install_safe(self):
46
+ assert get_integration(self.KEY).multi_install_safe is True
47
+
45
48
  def test_registrar_config(self):
46
49
  """Override base assertion: kiro-cli uses a prose fallback for args
47
50
  because Kiro CLI file-based prompts do not natively substitute
@@ -911,6 +911,65 @@ class TestExtensionSkillRegistration:
911
911
  assert ".specify/scripts/bash/resolve-skill.sh" not in content
912
912
  assert ".specify/scripts/bash/ensure-skills.sh" not in content
913
913
 
914
+ def test_skill_registration_rewrites_extension_subdir_paths(self, project_dir, temp_dir):
915
+ """Auto-registered skills should resolve extension-relative subdir
916
+ references (agents/, knowledge-base/) to their installed location,
917
+ matching the rewrite already applied by register_commands() (#2101)."""
918
+ _create_init_options(project_dir, ai="claude", ai_skills=True)
919
+ skills_dir = _create_skills_dir(project_dir, ai="claude")
920
+
921
+ ext_dir = temp_dir / "path-ext"
922
+ ext_dir.mkdir()
923
+ manifest_data = {
924
+ "schema_version": "1.0",
925
+ "extension": {
926
+ "id": "path-ext",
927
+ "name": "Path Extension",
928
+ "version": "1.0.0",
929
+ "description": "Test",
930
+ },
931
+ "requires": {"speckit_version": ">=0.1.0"},
932
+ "provides": {
933
+ "commands": [
934
+ {
935
+ "name": "speckit.path-ext.run",
936
+ "file": "commands/run.md",
937
+ "description": "Run command",
938
+ }
939
+ ]
940
+ },
941
+ }
942
+ with open(ext_dir / "extension.yml", "w") as f:
943
+ yaml.safe_dump(manifest_data, f)
944
+
945
+ (ext_dir / "commands").mkdir()
946
+ (ext_dir / "agents" / "control").mkdir(parents=True)
947
+ (ext_dir / "agents" / "control" / "commander.md").write_text("# Commander\n")
948
+ (ext_dir / "knowledge-base").mkdir()
949
+ (ext_dir / "knowledge-base" / "agent-scores.yaml").write_text("scores: {}\n")
950
+ (ext_dir / "templates").mkdir()
951
+ (ext_dir / "templates" / "kill-report.md").write_text("# Kill Report\n")
952
+
953
+ (ext_dir / "commands" / "run.md").write_text(
954
+ "---\n"
955
+ "description: Run command\n"
956
+ "---\n\n"
957
+ "Read agents/control/commander.md and knowledge-base/agent-scores.yaml.\n"
958
+ "Use templates/kill-report.md as the report template.\n"
959
+ )
960
+
961
+ manager = ExtensionManager(project_dir)
962
+ manager.install_from_directory(ext_dir, "0.1.0", register_commands=False)
963
+
964
+ content = (skills_dir / "speckit-path-ext-run" / "SKILL.md").read_text()
965
+ assert ".specify/extensions/path-ext/agents/control/commander.md" in content
966
+ assert ".specify/extensions/path-ext/knowledge-base/agent-scores.yaml" in content
967
+ # extension's own templates/ dir must resolve under the extension,
968
+ # not the project-level .specify/templates/
969
+ assert ".specify/extensions/path-ext/templates/kill-report.md" in content
970
+ assert "Read agents/control" not in content
971
+ assert "and knowledge-base/" not in content
972
+
914
973
  def test_missing_command_file_skipped(self, skills_project, temp_dir):
915
974
  """Commands with missing source files should be skipped gracefully."""
916
975
  project_dir, skills_dir = skills_project