specify-cli 0.12.14__tar.gz → 0.12.15__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.14 → specify_cli-0.12.15}/CHANGELOG.md +15 -0
  2. {specify_cli-0.12.14 → specify_cli-0.12.15}/PKG-INFO +1 -1
  3. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/community/extensions.md +2 -1
  4. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/community/presets.md +1 -1
  5. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/reference/workflows.md +26 -3
  6. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/catalog.community.json +54 -4
  7. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/catalog.community.json +8 -7
  8. {specify_cli-0.12.14 → specify_cli-0.12.15}/pyproject.toml +1 -1
  9. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/_github_http.py +30 -5
  10. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/_init_options.py +1 -1
  11. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/lib/yamlio.py +50 -2
  12. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/services/installer.py +32 -10
  13. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/extensions/__init__.py +65 -1
  14. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/base.py +31 -3
  15. specify_cli-0.12.15/src/specify_cli/workflows/_commands.py +3153 -0
  16. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/workflows/catalog.py +215 -30
  17. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/workflows/engine.py +118 -5
  18. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/contract/test_bundle_cli.py +39 -11
  19. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integration/test_bundler_install_flow.py +208 -2
  20. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_base_yaml.py +30 -0
  21. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_extensions.py +132 -0
  22. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_github_http.py +38 -0
  23. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_presets.py +5 -44
  24. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_workflows.py +5119 -74
  25. specify_cli-0.12.14/src/specify_cli/workflows/_commands.py +0 -1729
  26. {specify_cli-0.12.14 → specify_cli-0.12.15}/.devcontainer/devcontainer.json +0 -0
  27. {specify_cli-0.12.14 → specify_cli-0.12.15}/.devcontainer/post-create.sh +0 -0
  28. {specify_cli-0.12.14 → specify_cli-0.12.15}/.editorconfig +0 -0
  29. {specify_cli-0.12.14 → specify_cli-0.12.15}/.gitattributes +0 -0
  30. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/CODEOWNERS +0 -0
  31. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/ISSUE_TEMPLATE/agent_request.yml +0 -0
  32. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  33. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/ISSUE_TEMPLATE/bundle_submission.yml +0 -0
  34. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  35. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/ISSUE_TEMPLATE/extension_submission.yml +0 -0
  36. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  37. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/ISSUE_TEMPLATE/preset_submission.yml +0 -0
  38. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  39. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/aw/actions-lock.json +0 -0
  40. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/dependabot.yml +0 -0
  41. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/skills/add-community-extension/SKILL.md +0 -0
  42. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/workflows/RELEASE-PROCESS.md +0 -0
  43. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/workflows/add-community-extension.lock.yml +0 -0
  44. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/workflows/add-community-extension.md +0 -0
  45. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/workflows/add-community-preset.lock.yml +0 -0
  46. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/workflows/add-community-preset.md +0 -0
  47. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/workflows/bug-assess.lock.yml +0 -0
  48. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/workflows/bug-assess.md +0 -0
  49. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/workflows/bug-fix.lock.yml +0 -0
  50. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/workflows/bug-fix.md +0 -0
  51. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/workflows/bug-test.lock.yml +0 -0
  52. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/workflows/bug-test.md +0 -0
  53. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/workflows/catalog-assign.yml +0 -0
  54. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/workflows/codeql.yml +0 -0
  55. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/workflows/docs.yml +0 -0
  56. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/workflows/lint.yml +0 -0
  57. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/workflows/publish-pypi.yml +0 -0
  58. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/workflows/release-trigger.yml +0 -0
  59. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/workflows/release.yml +0 -0
  60. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/workflows/stale.yml +0 -0
  61. {specify_cli-0.12.14 → specify_cli-0.12.15}/.github/workflows/test.yml +0 -0
  62. {specify_cli-0.12.14 → specify_cli-0.12.15}/.gitignore +0 -0
  63. {specify_cli-0.12.14 → specify_cli-0.12.15}/.markdownlint-cli2.jsonc +0 -0
  64. {specify_cli-0.12.14 → specify_cli-0.12.15}/.pre-commit-config.yaml +0 -0
  65. {specify_cli-0.12.14 → specify_cli-0.12.15}/.zenodo.json +0 -0
  66. {specify_cli-0.12.14 → specify_cli-0.12.15}/AGENTS.md +0 -0
  67. {specify_cli-0.12.14 → specify_cli-0.12.15}/CITATION.cff +0 -0
  68. {specify_cli-0.12.14 → specify_cli-0.12.15}/CODE_OF_CONDUCT.md +0 -0
  69. {specify_cli-0.12.14 → specify_cli-0.12.15}/CONTRIBUTING.md +0 -0
  70. {specify_cli-0.12.14 → specify_cli-0.12.15}/DEVELOPMENT.md +0 -0
  71. {specify_cli-0.12.14 → specify_cli-0.12.15}/LICENSE +0 -0
  72. {specify_cli-0.12.14 → specify_cli-0.12.15}/README.md +0 -0
  73. {specify_cli-0.12.14 → specify_cli-0.12.15}/SECURITY.md +0 -0
  74. {specify_cli-0.12.14 → specify_cli-0.12.15}/SUPPORT.md +0 -0
  75. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/.gitignore +0 -0
  76. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/README.md +0 -0
  77. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/community/bundles.md +0 -0
  78. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/community/friends.md +0 -0
  79. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/community/overview.md +0 -0
  80. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/community/walkthroughs.md +0 -0
  81. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/concepts/complex-features.md +0 -0
  82. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/concepts/sdd.md +0 -0
  83. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/concepts/spec-persistence.md +0 -0
  84. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/docfx.json +0 -0
  85. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/guides/evolving-specs.md +0 -0
  86. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/guides/monorepo.md +0 -0
  87. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/index.md +0 -0
  88. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/install/air-gapped.md +0 -0
  89. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/install/one-time.md +0 -0
  90. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/install/pipx.md +0 -0
  91. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/install/uv.md +0 -0
  92. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/installation.md +0 -0
  93. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/local-development.md +0 -0
  94. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/quickstart.md +0 -0
  95. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/reference/authentication.md +0 -0
  96. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/reference/bundles.md +0 -0
  97. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/reference/core.md +0 -0
  98. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/reference/extensions.md +0 -0
  99. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/reference/integrations.md +0 -0
  100. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/reference/overview.md +0 -0
  101. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/reference/presets.md +0 -0
  102. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/template/public/main.css +0 -0
  103. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/toc.yml +0 -0
  104. {specify_cli-0.12.14 → specify_cli-0.12.15}/docs/upgrade.md +0 -0
  105. {specify_cli-0.12.14 → specify_cli-0.12.15}/examples/bundles/business-analyst/README.md +0 -0
  106. {specify_cli-0.12.14 → specify_cli-0.12.15}/examples/bundles/business-analyst/bundle.yml +0 -0
  107. {specify_cli-0.12.14 → specify_cli-0.12.15}/examples/bundles/developer/README.md +0 -0
  108. {specify_cli-0.12.14 → specify_cli-0.12.15}/examples/bundles/developer/bundle.yml +0 -0
  109. {specify_cli-0.12.14 → specify_cli-0.12.15}/examples/bundles/product-manager/README.md +0 -0
  110. {specify_cli-0.12.14 → specify_cli-0.12.15}/examples/bundles/product-manager/bundle.yml +0 -0
  111. {specify_cli-0.12.14 → specify_cli-0.12.15}/examples/bundles/security-researcher/README.md +0 -0
  112. {specify_cli-0.12.14 → specify_cli-0.12.15}/examples/bundles/security-researcher/bundle.yml +0 -0
  113. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/EXTENSION-API-REFERENCE.md +0 -0
  114. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/EXTENSION-DEVELOPMENT-GUIDE.md +0 -0
  115. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/EXTENSION-PUBLISHING-GUIDE.md +0 -0
  116. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/EXTENSION-USER-GUIDE.md +0 -0
  117. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/README.md +0 -0
  118. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/RFC-EXTENSION-SYSTEM.md +0 -0
  119. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/agent-context/README.md +0 -0
  120. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/agent-context/agent-context-config.yml +0 -0
  121. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/agent-context/agent-context-defaults.json +0 -0
  122. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/agent-context/commands/speckit.agent-context.update.md +0 -0
  123. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/agent-context/extension.yml +0 -0
  124. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/agent-context/scripts/bash/update-agent-context.sh +0 -0
  125. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/agent-context/scripts/powershell/update-agent-context.ps1 +0 -0
  126. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/agent-context/scripts/python/update_agent_context.py +0 -0
  127. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/bug/README.md +0 -0
  128. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/bug/commands/speckit.bug.assess.md +0 -0
  129. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/bug/commands/speckit.bug.fix.md +0 -0
  130. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/bug/commands/speckit.bug.test.md +0 -0
  131. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/bug/extension.yml +0 -0
  132. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/catalog.json +0 -0
  133. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/git/README.md +0 -0
  134. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/git/commands/speckit.git.commit.md +0 -0
  135. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/git/commands/speckit.git.feature.md +0 -0
  136. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/git/commands/speckit.git.initialize.md +0 -0
  137. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/git/commands/speckit.git.remote.md +0 -0
  138. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/git/commands/speckit.git.validate.md +0 -0
  139. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/git/config-template.yml +0 -0
  140. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/git/extension.yml +0 -0
  141. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/git/git-config.yml +0 -0
  142. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/git/scripts/bash/auto-commit.sh +0 -0
  143. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/git/scripts/bash/create-new-feature-branch.sh +0 -0
  144. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/git/scripts/bash/git-common.sh +0 -0
  145. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/git/scripts/bash/initialize-repo.sh +0 -0
  146. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/git/scripts/powershell/auto-commit.ps1 +0 -0
  147. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/git/scripts/powershell/create-new-feature-branch.ps1 +0 -0
  148. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/git/scripts/powershell/git-common.ps1 +0 -0
  149. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/git/scripts/powershell/initialize-repo.ps1 +0 -0
  150. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/selftest/commands/selftest.md +0 -0
  151. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/selftest/extension.yml +0 -0
  152. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/template/.gitignore +0 -0
  153. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/template/CHANGELOG.md +0 -0
  154. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/template/EXAMPLE-README.md +0 -0
  155. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/template/LICENSE +0 -0
  156. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/template/README.md +0 -0
  157. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/template/commands/example.md +0 -0
  158. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/template/config-template.yml +0 -0
  159. {specify_cli-0.12.14 → specify_cli-0.12.15}/extensions/template/extension.yml +0 -0
  160. {specify_cli-0.12.14 → specify_cli-0.12.15}/integrations/CONTRIBUTING.md +0 -0
  161. {specify_cli-0.12.14 → specify_cli-0.12.15}/integrations/README.md +0 -0
  162. {specify_cli-0.12.14 → specify_cli-0.12.15}/integrations/catalog.community.json +0 -0
  163. {specify_cli-0.12.14 → specify_cli-0.12.15}/integrations/catalog.json +0 -0
  164. {specify_cli-0.12.14 → specify_cli-0.12.15}/media/bootstrap-claude-code.gif +0 -0
  165. {specify_cli-0.12.14 → specify_cli-0.12.15}/media/logo_large.webp +0 -0
  166. {specify_cli-0.12.14 → specify_cli-0.12.15}/media/logo_small.webp +0 -0
  167. {specify_cli-0.12.14 → specify_cli-0.12.15}/media/spec-kit-video-header.jpg +0 -0
  168. {specify_cli-0.12.14 → specify_cli-0.12.15}/media/specify_cli.gif +0 -0
  169. {specify_cli-0.12.14 → specify_cli-0.12.15}/newsletters/2026-April.md +0 -0
  170. {specify_cli-0.12.14 → specify_cli-0.12.15}/newsletters/2026-February.md +0 -0
  171. {specify_cli-0.12.14 → specify_cli-0.12.15}/newsletters/2026-June.md +0 -0
  172. {specify_cli-0.12.14 → specify_cli-0.12.15}/newsletters/2026-March.md +0 -0
  173. {specify_cli-0.12.14 → specify_cli-0.12.15}/newsletters/2026-May.md +0 -0
  174. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/ARCHITECTURE.md +0 -0
  175. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/PUBLISHING.md +0 -0
  176. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/README.md +0 -0
  177. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/catalog.json +0 -0
  178. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/lean/README.md +0 -0
  179. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/lean/commands/speckit.constitution.md +0 -0
  180. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/lean/commands/speckit.implement.md +0 -0
  181. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/lean/commands/speckit.plan.md +0 -0
  182. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/lean/commands/speckit.specify.md +0 -0
  183. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/lean/commands/speckit.tasks.md +0 -0
  184. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/lean/preset.yml +0 -0
  185. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/scaffold/README.md +0 -0
  186. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/scaffold/commands/speckit.myext.myextcmd.md +0 -0
  187. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/scaffold/commands/speckit.specify.md +0 -0
  188. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/scaffold/preset.yml +0 -0
  189. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/scaffold/templates/myext-template.md +0 -0
  190. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/scaffold/templates/spec-template.md +0 -0
  191. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/self-test/commands/speckit.specify.md +0 -0
  192. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/self-test/commands/speckit.wrap-test.md +0 -0
  193. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/self-test/preset.yml +0 -0
  194. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/self-test/templates/checklist-template.md +0 -0
  195. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/self-test/templates/constitution-template.md +0 -0
  196. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/self-test/templates/plan-template.md +0 -0
  197. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/self-test/templates/spec-template.md +0 -0
  198. {specify_cli-0.12.14 → specify_cli-0.12.15}/presets/self-test/templates/tasks-template.md +0 -0
  199. {specify_cli-0.12.14 → specify_cli-0.12.15}/scripts/bash/check-prerequisites.sh +0 -0
  200. {specify_cli-0.12.14 → specify_cli-0.12.15}/scripts/bash/common.sh +0 -0
  201. {specify_cli-0.12.14 → specify_cli-0.12.15}/scripts/bash/create-new-feature.sh +0 -0
  202. {specify_cli-0.12.14 → specify_cli-0.12.15}/scripts/bash/setup-plan.sh +0 -0
  203. {specify_cli-0.12.14 → specify_cli-0.12.15}/scripts/bash/setup-tasks.sh +0 -0
  204. {specify_cli-0.12.14 → specify_cli-0.12.15}/scripts/powershell/check-prerequisites.ps1 +0 -0
  205. {specify_cli-0.12.14 → specify_cli-0.12.15}/scripts/powershell/common.ps1 +0 -0
  206. {specify_cli-0.12.14 → specify_cli-0.12.15}/scripts/powershell/create-new-feature.ps1 +0 -0
  207. {specify_cli-0.12.14 → specify_cli-0.12.15}/scripts/powershell/setup-plan.ps1 +0 -0
  208. {specify_cli-0.12.14 → specify_cli-0.12.15}/scripts/powershell/setup-tasks.ps1 +0 -0
  209. {specify_cli-0.12.14 → specify_cli-0.12.15}/scripts/python/check_prerequisites.py +0 -0
  210. {specify_cli-0.12.14 → specify_cli-0.12.15}/scripts/python/common.py +0 -0
  211. {specify_cli-0.12.14 → specify_cli-0.12.15}/spec-driven.md +0 -0
  212. {specify_cli-0.12.14 → specify_cli-0.12.15}/spec-kit.code-workspace +0 -0
  213. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/__init__.py +0 -0
  214. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/_agent_config.py +0 -0
  215. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/_assets.py +0 -0
  216. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/_console.py +0 -0
  217. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/_invocation_style.py +0 -0
  218. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/_project.py +0 -0
  219. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/_toml_string.py +0 -0
  220. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/_utils.py +0 -0
  221. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/_version.py +0 -0
  222. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/agents.py +0 -0
  223. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/authentication/__init__.py +0 -0
  224. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/authentication/azure_devops.py +0 -0
  225. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/authentication/base.py +0 -0
  226. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/authentication/config.py +0 -0
  227. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/authentication/github.py +0 -0
  228. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/authentication/http.py +0 -0
  229. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/__init__.py +0 -0
  230. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/commands_impl/__init__.py +0 -0
  231. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/commands_impl/catalog_config.py +0 -0
  232. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/lib/__init__.py +0 -0
  233. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/lib/project.py +0 -0
  234. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/lib/versioning.py +0 -0
  235. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/models/__init__.py +0 -0
  236. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/models/catalog.py +0 -0
  237. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/models/manifest.py +0 -0
  238. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/models/records.py +0 -0
  239. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/services/__init__.py +0 -0
  240. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/services/adapters.py +0 -0
  241. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/services/catalog_stack.py +0 -0
  242. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/services/conflict.py +0 -0
  243. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/services/packager.py +0 -0
  244. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/services/primitives.py +0 -0
  245. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/services/references.py +0 -0
  246. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/services/resolver.py +0 -0
  247. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/bundler/services/validator.py +0 -0
  248. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/catalogs.py +0 -0
  249. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/commands/__init__.py +0 -0
  250. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/commands/bundle/__init__.py +0 -0
  251. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/commands/init.py +0 -0
  252. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/extensions/_commands.py +0 -0
  253. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integration_runtime.py +0 -0
  254. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integration_scaffold.py +0 -0
  255. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integration_state.py +0 -0
  256. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integration_status.py +0 -0
  257. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/__init__.py +0 -0
  258. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/_commands.py +0 -0
  259. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/_helpers.py +0 -0
  260. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/_install_commands.py +0 -0
  261. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/_migrate_commands.py +0 -0
  262. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/_query_commands.py +0 -0
  263. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/_scaffold_commands.py +0 -0
  264. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/agy/__init__.py +0 -0
  265. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/amp/__init__.py +0 -0
  266. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/auggie/__init__.py +0 -0
  267. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/bob/__init__.py +0 -0
  268. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/catalog.py +0 -0
  269. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/claude/__init__.py +0 -0
  270. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/cline/__init__.py +0 -0
  271. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/codebuddy/__init__.py +0 -0
  272. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/codex/__init__.py +0 -0
  273. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/copilot/__init__.py +0 -0
  274. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/cursor_agent/__init__.py +0 -0
  275. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/devin/__init__.py +0 -0
  276. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/firebender/__init__.py +0 -0
  277. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/forge/__init__.py +0 -0
  278. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/gemini/__init__.py +0 -0
  279. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/generic/__init__.py +0 -0
  280. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/goose/__init__.py +0 -0
  281. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/hermes/__init__.py +0 -0
  282. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/junie/__init__.py +0 -0
  283. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/kilocode/__init__.py +0 -0
  284. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/kimi/__init__.py +0 -0
  285. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/kiro_cli/__init__.py +0 -0
  286. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/lingma/__init__.py +0 -0
  287. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/manifest.py +0 -0
  288. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/omp/__init__.py +0 -0
  289. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/opencode/__init__.py +0 -0
  290. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/pi/__init__.py +0 -0
  291. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/qodercli/__init__.py +0 -0
  292. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/qwen/__init__.py +0 -0
  293. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/rovodev/__init__.py +0 -0
  294. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/shai/__init__.py +0 -0
  295. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/tabnine/__init__.py +0 -0
  296. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/trae/__init__.py +0 -0
  297. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/vibe/__init__.py +0 -0
  298. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/zcode/__init__.py +0 -0
  299. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/integrations/zed/__init__.py +0 -0
  300. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/presets/__init__.py +0 -0
  301. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/presets/_commands.py +0 -0
  302. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/shared_infra.py +0 -0
  303. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/workflows/__init__.py +0 -0
  304. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/workflows/base.py +0 -0
  305. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/workflows/expressions.py +0 -0
  306. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/workflows/steps/__init__.py +0 -0
  307. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/workflows/steps/command/__init__.py +0 -0
  308. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/workflows/steps/do_while/__init__.py +0 -0
  309. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/workflows/steps/fan_in/__init__.py +0 -0
  310. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/workflows/steps/fan_out/__init__.py +0 -0
  311. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/workflows/steps/gate/__init__.py +0 -0
  312. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/workflows/steps/if_then/__init__.py +0 -0
  313. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/workflows/steps/init/__init__.py +0 -0
  314. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/workflows/steps/prompt/__init__.py +0 -0
  315. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/workflows/steps/shell/__init__.py +0 -0
  316. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/workflows/steps/switch/__init__.py +0 -0
  317. {specify_cli-0.12.14 → specify_cli-0.12.15}/src/specify_cli/workflows/steps/while_loop/__init__.py +0 -0
  318. {specify_cli-0.12.14 → specify_cli-0.12.15}/templates/checklist-template.md +0 -0
  319. {specify_cli-0.12.14 → specify_cli-0.12.15}/templates/commands/analyze.md +0 -0
  320. {specify_cli-0.12.14 → specify_cli-0.12.15}/templates/commands/checklist.md +0 -0
  321. {specify_cli-0.12.14 → specify_cli-0.12.15}/templates/commands/clarify.md +0 -0
  322. {specify_cli-0.12.14 → specify_cli-0.12.15}/templates/commands/constitution.md +0 -0
  323. {specify_cli-0.12.14 → specify_cli-0.12.15}/templates/commands/converge.md +0 -0
  324. {specify_cli-0.12.14 → specify_cli-0.12.15}/templates/commands/implement.md +0 -0
  325. {specify_cli-0.12.14 → specify_cli-0.12.15}/templates/commands/plan.md +0 -0
  326. {specify_cli-0.12.14 → specify_cli-0.12.15}/templates/commands/specify.md +0 -0
  327. {specify_cli-0.12.14 → specify_cli-0.12.15}/templates/commands/tasks.md +0 -0
  328. {specify_cli-0.12.14 → specify_cli-0.12.15}/templates/commands/taskstoissues.md +0 -0
  329. {specify_cli-0.12.14 → specify_cli-0.12.15}/templates/constitution-template.md +0 -0
  330. {specify_cli-0.12.14 → specify_cli-0.12.15}/templates/plan-template.md +0 -0
  331. {specify_cli-0.12.14 → specify_cli-0.12.15}/templates/spec-template.md +0 -0
  332. {specify_cli-0.12.14 → specify_cli-0.12.15}/templates/tasks-template.md +0 -0
  333. {specify_cli-0.12.14 → specify_cli-0.12.15}/templates/vscode-settings.json +0 -0
  334. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/__init__.py +0 -0
  335. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/auth_helpers.py +0 -0
  336. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/bundler_helpers.py +0 -0
  337. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/conftest.py +0 -0
  338. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/contract/test_catalog_schema.py +0 -0
  339. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/contract/test_manifest_schema.py +0 -0
  340. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/extensions/__init__.py +0 -0
  341. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/extensions/bug/__init__.py +0 -0
  342. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/extensions/bug/test_bug_extension.py +0 -0
  343. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/extensions/git/__init__.py +0 -0
  344. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/extensions/git/test_git_extension.py +0 -0
  345. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/extensions/test_agent_context_cli_free.py +0 -0
  346. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/extensions/test_extension_agent_context.py +0 -0
  347. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/extensions/test_update_agent_context_feature_json.py +0 -0
  348. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/extensions/test_update_agent_context_python_parity.py +0 -0
  349. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/hooks/TESTING.md +0 -0
  350. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/hooks/plan.md +0 -0
  351. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/hooks/spec.md +0 -0
  352. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/hooks/tasks.md +0 -0
  353. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/http_helpers.py +0 -0
  354. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integration/test_bundler_catalog_stack.py +0 -0
  355. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integration/test_bundler_init_install.py +0 -0
  356. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integration/test_bundler_local_install.py +0 -0
  357. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integration/test_bundler_offline.py +0 -0
  358. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integration/test_bundler_security_paths.py +0 -0
  359. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/__init__.py +0 -0
  360. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/conftest.py +0 -0
  361. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_base.py +0 -0
  362. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_cli.py +0 -0
  363. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_extra_args.py +0 -0
  364. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_home_isolation.py +0 -0
  365. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_agy.py +0 -0
  366. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_amp.py +0 -0
  367. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_auggie.py +0 -0
  368. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_base_markdown.py +0 -0
  369. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_base_skills.py +0 -0
  370. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_base_toml.py +0 -0
  371. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_bob.py +0 -0
  372. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_catalog.py +0 -0
  373. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_claude.py +0 -0
  374. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_cline.py +0 -0
  375. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_codebuddy.py +0 -0
  376. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_codex.py +0 -0
  377. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_copilot.py +0 -0
  378. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_cursor_agent.py +0 -0
  379. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_devin.py +0 -0
  380. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_firebender.py +0 -0
  381. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_forge.py +0 -0
  382. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_gemini.py +0 -0
  383. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_generic.py +0 -0
  384. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_goose.py +0 -0
  385. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_hermes.py +0 -0
  386. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_junie.py +0 -0
  387. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_kilocode.py +0 -0
  388. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_kimi.py +0 -0
  389. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_kiro_cli.py +0 -0
  390. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_lingma.py +0 -0
  391. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_omp.py +0 -0
  392. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_opencode.py +0 -0
  393. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_pi.py +0 -0
  394. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_qodercli.py +0 -0
  395. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_qwen.py +0 -0
  396. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_rovodev.py +0 -0
  397. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_scaffold.py +0 -0
  398. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_shai.py +0 -0
  399. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_state.py +0 -0
  400. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_subcommand.py +0 -0
  401. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_tabnine.py +0 -0
  402. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_trae.py +0 -0
  403. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_vibe.py +0 -0
  404. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_zcode.py +0 -0
  405. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_integration_zed.py +0 -0
  406. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_manifest.py +0 -0
  407. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_registry.py +0 -0
  408. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/integrations/test_skill_frontmatter_quoting.py +0 -0
  409. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/self_upgrade_helpers.py +0 -0
  410. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_agent_config_consistency.py +0 -0
  411. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_authentication.py +0 -0
  412. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_branch_numbering.py +0 -0
  413. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_check_prerequisites_paths_only.py +0 -0
  414. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_check_prerequisites_python_parity.py +0 -0
  415. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_check_tool.py +0 -0
  416. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_cli_version.py +0 -0
  417. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_command_template_py_scripts.py +0 -0
  418. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_commands_package.py +0 -0
  419. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_console_imports.py +0 -0
  420. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_extension_registration.py +0 -0
  421. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_extension_skills.py +0 -0
  422. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_extension_update_hardening.py +0 -0
  423. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_github_workflows.py +0 -0
  424. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_init_dir.py +0 -0
  425. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_init_dir_cli.py +0 -0
  426. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_live_transient_windows.py +0 -0
  427. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_merge.py +0 -0
  428. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_post_process.py +0 -0
  429. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_ps1_encoding.py +0 -0
  430. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_registrar_path_traversal.py +0 -0
  431. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_self_upgrade_detection.py +0 -0
  432. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_self_upgrade_execution.py +0 -0
  433. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_self_upgrade_guidance.py +0 -0
  434. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_self_upgrade_verification.py +0 -0
  435. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_setup_plan_feature_json.py +0 -0
  436. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_setup_plan_no_overwrite.py +0 -0
  437. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_setup_tasks.py +0 -0
  438. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_shared_infra_integrity.py +0 -0
  439. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_timestamp_branches.py +0 -0
  440. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_upgrade.py +0 -0
  441. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_utils.py +0 -0
  442. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_utils_assets_imports.py +0 -0
  443. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_version_imports.py +0 -0
  444. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/test_workflow_run_without_project.py +0 -0
  445. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/unit/test_bundler_adapters.py +0 -0
  446. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/unit/test_bundler_catalog_config.py +0 -0
  447. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/unit/test_bundler_conflict.py +0 -0
  448. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/unit/test_bundler_packager.py +0 -0
  449. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/unit/test_bundler_primitives.py +0 -0
  450. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/unit/test_bundler_records.py +0 -0
  451. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/unit/test_bundler_references.py +0 -0
  452. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/unit/test_bundler_resolver.py +0 -0
  453. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/unit/test_bundler_validator.py +0 -0
  454. {specify_cli-0.12.14 → specify_cli-0.12.15}/tests/unit/test_bundler_versioning.py +0 -0
  455. {specify_cli-0.12.14 → specify_cli-0.12.15}/workflows/ARCHITECTURE.md +0 -0
  456. {specify_cli-0.12.14 → specify_cli-0.12.15}/workflows/PUBLISHING.md +0 -0
  457. {specify_cli-0.12.14 → specify_cli-0.12.15}/workflows/README.md +0 -0
  458. {specify_cli-0.12.14 → specify_cli-0.12.15}/workflows/catalog.community.json +0 -0
  459. {specify_cli-0.12.14 → specify_cli-0.12.15}/workflows/catalog.json +0 -0
  460. {specify_cli-0.12.14 → specify_cli-0.12.15}/workflows/speckit/workflow.yml +0 -0
  461. {specify_cli-0.12.14 → specify_cli-0.12.15}/workflows/step-catalog.community.json +0 -0
  462. {specify_cli-0.12.14 → specify_cli-0.12.15}/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.15] - 2026-07-14
6
+
7
+ ### Changed
8
+
9
+ - Update Autonomous Run Governance preset to v0.1.4 (#3511)
10
+ - fix(workflows): raise catalog error, not raw ValueError, on a malformed catalog URL (#3484)
11
+ - fix(workflows): evaluate 'in'/'not in' safely on a non-iterable right operand (#3447) (#3468)
12
+ - fix: add trailing newline to init-options.json output (#3509)
13
+ - feat(workflows): align workflow CLI with extension command surface (#3419)
14
+ - fix(extensions): stop env-var config leaking across prefix-colliding extension IDs (#3497)
15
+ - fix(integrations): escape control characters in goose recipe YAML renderer (#3384)
16
+ - [extension] Update DocGuard — CDD Enforcement extension to v0.32.0 (#3489)
17
+ - [extension] Add Multi-Repo Branch Sync extension to community catalog (#3411)
18
+ - chore: release 0.12.14, begin 0.12.15.dev0 development (#3506)
19
+
5
20
  ## [0.12.14] - 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.14
3
+ Version: 0.12.15
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
@@ -51,7 +51,7 @@ The following community-contributed extensions are available in [`catalog.commun
51
51
  | Confluence Extension | Create a doc in Confluence summarizing the specifications and planning files | `integration` | Read+Write | [spec-kit-confluence](https://github.com/aaronrsun/spec-kit-confluence) |
52
52
  | Cost Tracker | Track real LLM dollar cost across SDD workflows — per-feature budgets, per-integration comparison, and finance-ready exports | `visibility` | Read+Write | [spec-kit-cost](https://github.com/Quratulain-bilal/spec-kit-cost) |
53
53
  | Data Model Diagram | Generates Mermaid ER diagrams from Spec Kit data models after planning | `docs` | Read+Write | [spec-kit-data-model-diagram](https://github.com/benizzio/spec-kit-data-model-diagram) |
54
- | DocGuard — CDD Enforcement | The only doc-integrity engine with an MCP server, SARIF output, and a deterministic zero-LLM core. Validates, scores, and traces documentation against code — 24 validators, stable finding codes, GitHub Action with PR annotations, spec-kit hooks. Pure Node.js, one pinned dep. | `docs` | Read+Write | [spec-kit-docguard](https://github.com/raccioly/docguard) |
54
+ | DocGuard — CDD Enforcement | Doc-integrity engine with MCP server, SARIF output, and zero-LLM core. Validates, scores, and traces documentation against code — 24 validators, stable finding codes, spec-kit hooks. Pure Node.js. | `docs` | Read+Write | [spec-kit-docguard](https://github.com/raccioly/docguard) |
55
55
  | EARS Requirements Syntax | Author, lint, and convert requirements using EARS - the five industry-standard sentence patterns for unambiguous, testable requirements | `docs` | Read+Write | [spec-kit-ears](https://github.com/dhruv-15-03/spec-kit-ears) |
56
56
  | Extensify | Create and validate extensions and extension catalogs | `process` | Read+Write | [extensify](https://github.com/mnriem/spec-kit-extensions/tree/main/extensify) |
57
57
  | Fix Findings | Automated analyze-fix-reanalyze loop that resolves spec findings until clean | `code` | Read+Write | [spec-kit-fix-findings](https://github.com/Quratulain-bilal/spec-kit-fix-findings) |
@@ -84,6 +84,7 @@ The following community-contributed extensions are available in [`catalog.commun
84
84
  | MemoryLint | Evidence-driven instruction drift checker: audits agent memory files for boundary, reality, conflict, and redundancy drift. | `process` | Read+Write | [memorylint](https://github.com/RbBtSn0w/spec-kit-extensions/tree/main/memorylint) |
85
85
  | Microsoft 365 Integration | Fetch Teams messages, meeting transcripts, and SharePoint/OneDrive files as local Markdown for spec generation | `integration` | Read+Write | [spec-kit-m365](https://github.com/BenBtg/spec-kit-m365) |
86
86
  | Multi-Model Review | Cross-model Spec Kit handoffs for spec authoring, implementation routing, and review. | `process` | Read+Write | [multi-model-review](https://github.com/formin/multi-model-review) |
87
+ | Multi-Repo Branch Sync | Creates the feature branch in affected sub-repositories and git submodules via plan/tasks hooks | `process` | Read+Write | [multi-repo-sync](https://github.com/fyloss/spec-kit-multi-repo-sync) |
87
88
  | Multi-Sites Spec Kit | Multi-site aware specify command with per-site spec folders, auto-increment, and Drupal support | `process` | Read+Write | [spec-kit-multi-sites](https://github.com/teeyo/spec-kit-multi-sites) |
88
89
  | .NET Framework to Modern .NET Migration | Orchestrate end-to-end .NET Framework to modern .NET migration across 7 phases, with SDD lifecycle integration | `process` | Read+Write | [spec-kit-fx-to-net](https://github.com/RogerBestMsft/spec-kit-FxToNet) |
89
90
  | Onboard | Contextual onboarding and progressive growth for developers new to spec-kit projects. Explains specs, maps dependencies, validates understanding, and guides the next step | `process` | Read+Write | [spec-kit-onboard](https://github.com/dmux/spec-kit-onboard) |
@@ -11,7 +11,7 @@ The following community-contributed presets customize how Spec Kit behaves — o
11
11
  | Agent Parity Governance | Adds shared-guidance parity, audit-ready Spec-Kit run evidence, and agent-neutral model-routing guidance across a project's declared AI-agent instruction surfaces so agent guidance does not drift. | 6 templates, 3 commands | — | [spec-kit-preset-agent-parity-governance](https://github.com/hindermath/spec-kit-preset-agent-parity-governance) |
12
12
  | AIDE In-Place Migration | Adapts the AIDE extension workflow for in-place technology migrations (X → Y pattern) — adds migration objectives, verification gates, knowledge documents, and behavioral equivalence criteria | 2 templates, 8 commands | AIDE extension | [spec-kit-presets](https://github.com/mnriem/spec-kit-presets) |
13
13
  | Architecture Governance | Adds secure software architecture, STRIDE+CAPEC threat modeling, arc42 security cross-cutting concepts, S-ADRs, Zero Trust applicability, OWASP SAMM governance, BSI C3A cloud autonomy, BSI C5 cloud compliance assurance, and audit-ready Spec Kit run evidence | 13 templates, 3 commands | — | [spec-kit-preset-architecture-governance](https://github.com/hindermath/spec-kit-preset-architecture-governance) |
14
- | Autonomous Run Governance | Adds permission-bounded, evidence-first governance for autonomous Spec Kit delivery, convergence, resume, closeout, and retrospective learning. | 10 templates, 2 commands | — | [spec-kit-preset-autonomous-run-governance](https://github.com/hindermath/spec-kit-preset-autonomous-run-governance) |
14
+ | Autonomous Run Governance | Adds permission-bounded, evidence-first governance for autonomous Spec Kit delivery, convergence, resume, closeout, and retrospective learning. | 12 templates, 2 commands, 2 scripts | — | [spec-kit-preset-autonomous-run-governance](https://github.com/hindermath/spec-kit-preset-autonomous-run-governance) |
15
15
  | Canon Core | Adapts original Spec Kit workflow to work together with Canon extension | 2 templates, 8 commands | — | [spec-kit-canon](https://github.com/maximiliamus/spec-kit-canon) |
16
16
  | Claude AskUserQuestion | Upgrades `/speckit.clarify` and `/speckit.checklist` on Claude Code from Markdown-table prompts to the native AskUserQuestion picker, with a recommended option and reasoning on every question | 2 commands | — | [spec-kit-preset-claude-ask-questions](https://github.com/0xrafasec/spec-kit-preset-claude-ask-questions) |
17
17
  | Command Density | Compacts the nine core Spec Kit command prompts while preserving scripts, handoffs, placeholders, hook output blocks, and rule structure | 9 commands | — | [spec-kit-preset-command-density](https://github.com/Xopoko/spec-kit-preset-command-density) |
@@ -86,8 +86,30 @@ Lists workflows installed in the current project.
86
86
  specify workflow add <source>
87
87
  ```
88
88
 
89
+ | Option | Description |
90
+ | --------------- | ------------------------------------------------------ |
91
+ | `--dev` | Install from a local workflow YAML file or directory |
92
+ | `--from <url>` | Install from a custom URL (`<source>` names the expected workflow ID) |
93
+
89
94
  Installs a workflow from the catalog, a URL (HTTPS required), or a local file path.
90
95
 
96
+ ## Update Workflows
97
+
98
+ ```bash
99
+ specify workflow update [workflow_id]
100
+ ```
101
+
102
+ Updates one installed catalog workflow — or all of them when no ID is given — to the latest catalog version. Prompts for confirmation and keeps the installed copy if a download or validation fails.
103
+
104
+ ## Enable or Disable a Workflow
105
+
106
+ ```bash
107
+ specify workflow enable <workflow_id>
108
+ specify workflow disable <workflow_id>
109
+ ```
110
+
111
+ Disabled workflows stay installed and listed (marked `[disabled]`) but refuse to run until re-enabled.
112
+
91
113
  ## Remove a Workflow
92
114
 
93
115
  ```bash
@@ -102,9 +124,10 @@ Removes an installed workflow from the project.
102
124
  specify workflow search [query]
103
125
  ```
104
126
 
105
- | Option | Description |
106
- | ------- | --------------- |
107
- | `--tag` | Filter by tag |
127
+ | Option | Description |
128
+ | ---------- | ----------------- |
129
+ | `--tag` | Filter by tag |
130
+ | `--author` | Filter by author |
108
131
 
109
132
  Searches all active catalogs for workflows matching the query.
110
133
 
@@ -1106,10 +1106,10 @@
1106
1106
  "docguard": {
1107
1107
  "name": "DocGuard — CDD Enforcement",
1108
1108
  "id": "docguard",
1109
- "description": "The only doc-integrity engine with an MCP server, SARIF output, and a deterministic zero-LLM core. Validates, scores, and traces documentation against code — 24 validators, stable finding codes, GitHub Action with PR annotations, spec-kit hooks. Pure Node.js, one pinned dep.",
1109
+ "description": "Doc-integrity engine with MCP server, SARIF output, and zero-LLM core. Validates, scores, and traces documentation against code — 24 validators, stable finding codes, spec-kit hooks. Pure Node.js.",
1110
1110
  "author": "raccioly",
1111
- "version": "0.30.0",
1112
- "download_url": "https://github.com/raccioly/docguard/releases/download/v0.30.0/spec-kit-docguard-v0.30.0.zip",
1111
+ "version": "0.32.0",
1112
+ "download_url": "https://github.com/raccioly/docguard/releases/download/v0.32.0/spec-kit-docguard-v0.32.0.zip",
1113
1113
  "repository": "https://github.com/raccioly/docguard",
1114
1114
  "homepage": "https://www.npmjs.com/package/docguard-cli",
1115
1115
  "documentation": "https://github.com/raccioly/docguard/blob/main/extensions/spec-kit-docguard/README.md",
@@ -1124,6 +1124,14 @@
1124
1124
  "name": "node",
1125
1125
  "version": ">=18.0.0",
1126
1126
  "required": true
1127
+ },
1128
+ {
1129
+ "name": "npx",
1130
+ "required": true
1131
+ },
1132
+ {
1133
+ "name": "specify",
1134
+ "required": false
1127
1135
  }
1128
1136
  ]
1129
1137
  },
@@ -1145,7 +1153,7 @@
1145
1153
  "downloads": 0,
1146
1154
  "stars": 0,
1147
1155
  "created_at": "2026-03-13T00:00:00Z",
1148
- "updated_at": "2026-07-06T00:00:00Z"
1156
+ "updated_at": "2026-07-13T00:00:00Z"
1149
1157
  },
1150
1158
  "doctor": {
1151
1159
  "name": "Project Health Check",
@@ -2458,6 +2466,48 @@
2458
2466
  "created_at": "2026-05-04T02:51:52Z",
2459
2467
  "updated_at": "2026-06-18T00:00:00Z"
2460
2468
  },
2469
+ "multi-repo-sync": {
2470
+ "name": "Multi-Repo Branch Sync",
2471
+ "id": "multi-repo-sync",
2472
+ "description": "Creates the feature branch in affected sub-repositories and git submodules via plan/tasks hooks",
2473
+ "author": "Fyloss",
2474
+ "version": "1.0.0",
2475
+ "download_url": "https://github.com/fyloss/spec-kit-multi-repo-sync/releases/download/v1.0.0/spec-kit-multi-repo-sync.zip",
2476
+ "sha256": "12a5c7392145b4424b20715aaa3d8b6a8218c143dea596873e344146c1a76ba0",
2477
+ "repository": "https://github.com/fyloss/spec-kit-multi-repo-sync",
2478
+ "homepage": "https://github.com/fyloss/spec-kit-multi-repo-sync",
2479
+ "documentation": "https://github.com/fyloss/spec-kit-multi-repo-sync/blob/main/README.md",
2480
+ "changelog": "https://github.com/fyloss/spec-kit-multi-repo-sync/blob/main/CHANGELOG.md",
2481
+ "license": "MIT",
2482
+ "category": "process",
2483
+ "effect": "read-write",
2484
+ "requires": {
2485
+ "speckit_version": ">=0.2.0",
2486
+ "tools": [
2487
+ {
2488
+ "name": "git",
2489
+ "version": ">=2.31",
2490
+ "required": true
2491
+ }
2492
+ ]
2493
+ },
2494
+ "provides": {
2495
+ "commands": 3,
2496
+ "hooks": 2
2497
+ },
2498
+ "tags": [
2499
+ "git",
2500
+ "branching",
2501
+ "multi-repo",
2502
+ "submodules",
2503
+ "workflow"
2504
+ ],
2505
+ "verified": false,
2506
+ "downloads": 0,
2507
+ "stars": 0,
2508
+ "created_at": "2026-07-13T00:00:00Z",
2509
+ "updated_at": "2026-07-13T00:00:00Z"
2510
+ },
2461
2511
  "multi-sites": {
2462
2512
  "name": "Multi-Sites Spec Kit",
2463
2513
  "id": "multi-sites",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schema_version": "1.0",
3
- "updated_at": "2026-07-13T00:00:00Z",
3
+ "updated_at": "2026-07-14T00:00:00Z",
4
4
  "catalog_url": "https://raw.githubusercontent.com/github/spec-kit/main/presets/catalog.community.json",
5
5
  "presets": {
6
6
  "a11y-governance": {
@@ -134,20 +134,21 @@
134
134
  "autonomous-run-governance": {
135
135
  "name": "Autonomous Run Governance",
136
136
  "id": "autonomous-run-governance",
137
- "version": "0.1.1",
137
+ "version": "0.1.4",
138
138
  "description": "Adds permission-bounded, evidence-first governance for autonomous Spec Kit delivery, convergence, resume, closeout, and retrospective learning.",
139
139
  "author": "Thorsten Hindermann",
140
140
  "repository": "https://github.com/hindermath/spec-kit-preset-autonomous-run-governance",
141
- "download_url": "https://github.com/hindermath/spec-kit-preset-autonomous-run-governance/archive/refs/tags/v0.1.1.zip",
141
+ "download_url": "https://github.com/hindermath/spec-kit-preset-autonomous-run-governance/archive/refs/tags/v0.1.4.zip",
142
142
  "homepage": "https://github.com/hindermath/spec-kit-preset-autonomous-run-governance",
143
- "documentation": "https://github.com/hindermath/spec-kit-preset-autonomous-run-governance/blob/main/README.md",
143
+ "documentation": "https://github.com/hindermath/spec-kit-preset-autonomous-run-governance/blob/v0.1.4/README.md",
144
144
  "license": "MIT",
145
145
  "requires": {
146
146
  "speckit_version": ">=0.8.3"
147
147
  },
148
148
  "provides": {
149
- "templates": 10,
150
- "commands": 2
149
+ "templates": 12,
150
+ "commands": 2,
151
+ "scripts": 2
151
152
  },
152
153
  "tags": [
153
154
  "autonomous",
@@ -157,7 +158,7 @@
157
158
  "retrospective"
158
159
  ],
159
160
  "created_at": "2026-07-13T00:00:00Z",
160
- "updated_at": "2026-07-13T00:00:00Z"
161
+ "updated_at": "2026-07-14T00:00:00Z"
161
162
  },
162
163
  "canon-core": {
163
164
  "name": "Canon Core",
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "specify-cli"
3
- version = "0.12.14"
3
+ version = "0.12.15"
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"
@@ -24,6 +24,7 @@ GITHUB_HOSTS = frozenset({
24
24
  "api.github.com",
25
25
  "codeload.github.com",
26
26
  })
27
+ _MAX_RELEASE_METADATA_BYTES = 5 * 1024 * 1024
27
28
 
28
29
 
29
30
  def build_github_request(url: str) -> urllib.request.Request:
@@ -68,6 +69,8 @@ def resolve_github_release_asset_api_url(
68
69
  open_url_fn: Callable,
69
70
  timeout: int = 60,
70
71
  github_hosts: tuple[str, ...] = (),
72
+ redirect_validator: Callable[[str, str], None] | None = None,
73
+ max_metadata_bytes: int = _MAX_RELEASE_METADATA_BYTES,
71
74
  ) -> Optional[str]:
72
75
  """Resolve a GitHub release browser-download URL to its REST API asset URL.
73
76
 
@@ -91,6 +94,8 @@ def resolve_github_release_asset_api_url(
91
94
  authenticated release-metadata lookup.
92
95
  timeout: Per-request timeout in seconds.
93
96
  github_hosts: Host patterns to treat as GitHub Enterprise Server.
97
+ redirect_validator: Optional policy applied to metadata redirects.
98
+ max_metadata_bytes: Maximum release-metadata response size.
94
99
  """
95
100
  import json
96
101
  import urllib.error
@@ -149,13 +154,33 @@ def resolve_github_release_asset_api_url(
149
154
  release_url = f"{api_base}/repos/{owner}/{repo}/releases/tags/{encoded_tag}"
150
155
 
151
156
  try:
152
- with open_url_fn(release_url, timeout=timeout) as response:
153
- release_data = json.loads(response.read())
154
- except (urllib.error.URLError, json.JSONDecodeError):
157
+ open_kwargs = {"timeout": timeout}
158
+ if redirect_validator is not None:
159
+ open_kwargs["redirect_validator"] = redirect_validator
160
+ with open_url_fn(release_url, **open_kwargs) as response:
161
+ raw_release_data = response.read(max_metadata_bytes + 1)
162
+ if len(raw_release_data) > max_metadata_bytes:
163
+ raise ValueError("GitHub release metadata exceeds size limit")
164
+ release_data = json.loads(raw_release_data)
165
+ except (
166
+ urllib.error.URLError,
167
+ json.JSONDecodeError,
168
+ TypeError,
169
+ ValueError,
170
+ ):
155
171
  return None
156
172
 
157
- for asset in release_data.get("assets", []):
158
- if asset.get("name") == asset_name and asset.get("url"):
173
+ if not isinstance(release_data, dict):
174
+ return None
175
+ assets = release_data.get("assets", [])
176
+ if not isinstance(assets, list):
177
+ return None
178
+ for asset in assets:
179
+ if (
180
+ isinstance(asset, dict)
181
+ and asset.get("name") == asset_name
182
+ and asset.get("url")
183
+ ):
159
184
  return str(asset["url"])
160
185
 
161
186
  return None
@@ -14,7 +14,7 @@ def save_init_options(project_path: Path, options: dict[str, Any]) -> None:
14
14
  dest = project_path / INIT_OPTIONS_FILE
15
15
  dest.parent.mkdir(parents=True, exist_ok=True)
16
16
  dest.write_text(
17
- json.dumps(options, indent=2, sort_keys=True, ensure_ascii=False),
17
+ json.dumps(options, indent=2, sort_keys=True, ensure_ascii=False) + "\n",
18
18
  encoding="utf-8",
19
19
  )
20
20
 
@@ -10,6 +10,8 @@ from __future__ import annotations
10
10
  import json
11
11
  import os
12
12
  import re
13
+ import stat
14
+ import tempfile
13
15
  from pathlib import Path, PurePosixPath
14
16
  from typing import Any
15
17
 
@@ -87,17 +89,63 @@ def loads_json(text: str, *, origin: str = "<string>") -> Any:
87
89
 
88
90
 
89
91
  def dump_json(path: Path, data: Any, *, within: Path | None = None) -> Path:
90
- """Write *data* as pretty JSON to *path* (optionally confined to *within*)."""
92
+ """Atomically write pretty JSON to *path* (optionally confined to *within*)."""
91
93
  path = Path(path)
92
94
  if within is not None:
93
95
  path = ensure_within(within, path)
96
+ fd = -1
97
+ temp_path: Path | None = None
94
98
  try:
95
99
  path.parent.mkdir(parents=True, exist_ok=True)
96
- with path.open("w", encoding="utf-8") as handle:
100
+ fd, temp_name = tempfile.mkstemp(
101
+ dir=path.parent,
102
+ prefix=f".{path.name}.",
103
+ suffix=".tmp",
104
+ )
105
+ temp_path = Path(temp_name)
106
+ with os.fdopen(os.dup(fd), "w", encoding="utf-8") as handle:
97
107
  json.dump(data, handle, indent=2, sort_keys=False)
98
108
  handle.write("\n")
109
+
110
+ try:
111
+ if path.exists():
112
+ existing = path.stat(follow_symlinks=False)
113
+ if stat.S_ISREG(existing.st_mode) and hasattr(os, "fchmod"):
114
+ os.fchmod(fd, stat.S_IMODE(existing.st_mode))
115
+ if stat.S_ISREG(existing.st_mode) and hasattr(os, "fchown"):
116
+ try:
117
+ os.fchown(fd, existing.st_uid, existing.st_gid)
118
+ except PermissionError:
119
+ pass
120
+ except OSError:
121
+ pass
122
+
123
+ staged = os.stat(temp_path, follow_symlinks=False)
124
+ opened = os.fstat(fd)
125
+ if (
126
+ not stat.S_ISREG(staged.st_mode)
127
+ or staged.st_dev != opened.st_dev
128
+ or staged.st_ino != opened.st_ino
129
+ ):
130
+ raise OSError("staged JSON file changed before commit")
131
+
132
+ os.close(fd)
133
+ fd = -1
134
+ os.replace(temp_path, path)
135
+ temp_path = None
99
136
  except OSError as exc:
100
137
  raise BundlerError(f"Could not write {path}: {exc}") from exc
138
+ finally:
139
+ if fd >= 0:
140
+ try:
141
+ os.close(fd)
142
+ except OSError:
143
+ pass
144
+ if temp_path is not None:
145
+ try:
146
+ temp_path.unlink(missing_ok=True)
147
+ except OSError:
148
+ pass
101
149
  return path
102
150
 
103
151
 
@@ -187,19 +187,41 @@ def remove_bundle(
187
187
 
188
188
  still_needed = components_still_needed(records, exclude_bundle_id=bundle_id)
189
189
  result = InstallResult(bundle_id=bundle_id)
190
+ remove_attempted = False
190
191
 
191
- for component in target.contributed_components:
192
- key = (component.kind, component.id)
193
- if key in still_needed:
194
- result.skipped.append(component)
195
- continue
196
- if installer.is_installed(project_root, component):
197
- installer.remove(project_root, component)
198
- result.uninstalled.append(component)
192
+ try:
193
+ for component in target.contributed_components:
194
+ key = (component.kind, component.id)
195
+ if key in still_needed:
196
+ result.skipped.append(component)
197
+ continue
198
+ if installer.is_installed(project_root, component):
199
+ remove_attempted = True
200
+ installer.remove(project_root, component)
201
+ result.uninstalled.append(component)
202
+ save_records(project_root, remove_record(records, bundle_id))
203
+ except Exception as exc: # noqa: BLE001
204
+ if result.uninstalled:
205
+ detail = (
206
+ f"{len(result.uninstalled)} component(s) were already removed "
207
+ "before this failure; the bundle record was left unchanged, "
208
+ "so the project may be partially uninstalled."
209
+ )
210
+ elif remove_attempted:
211
+ detail = (
212
+ "No components were removed, but the failing component may "
213
+ "have made partial changes before raising, so the project "
214
+ "may be partially uninstalled."
215
+ )
199
216
  else:
200
- result.skipped.append(component)
217
+ detail = (
218
+ "No components were removed and no removal was attempted; "
219
+ "the bundle record was left unchanged."
220
+ )
221
+ raise BundlerError(
222
+ f"Failed to remove bundle '{bundle_id}': {exc}. {detail}"
223
+ ) from exc
201
224
 
202
- save_records(project_root, remove_record(records, bundle_id))
203
225
  return result
204
226
 
205
227
 
@@ -2737,6 +2737,36 @@ class ConfigManager:
2737
2737
  config_file = self.extension_dir / "local-config.yml"
2738
2738
  return self._load_yaml_config(config_file)
2739
2739
 
2740
+ def _sibling_extension_ids(self) -> list[str]:
2741
+ """Return IDs of other extensions installed alongside this one.
2742
+
2743
+ Sourced from ``ExtensionRegistry`` (``.specify/extensions/.registry``)
2744
+ rather than a directory scan: ``ExtensionManager.remove(...,
2745
+ keep_config=True)`` deliberately preserves the extension directory
2746
+ while dropping the registry entry, so a directory scan would treat
2747
+ that config-only leftover as an installed sibling and keep silently
2748
+ absorbing its ``SPECKIT_<sibling>_*`` env vars into no one. The
2749
+ registry is the source of truth for "installed".
2750
+
2751
+ Returns an empty list if the registry is missing or corrupted
2752
+ (fresh project, ad-hoc test harness) so ``_get_env_config`` degrades
2753
+ to its pre-fix behaviour rather than crashing. ``UnicodeError`` is
2754
+ caught alongside ``OSError`` because ``ExtensionRegistry._load()``
2755
+ opens the file in text mode and only handles ``JSONDecodeError`` /
2756
+ ``FileNotFoundError``, so a registry file with non-UTF-8 bytes would
2757
+ otherwise surface a ``UnicodeDecodeError`` here and break *every*
2758
+ config read instead of degrading gracefully.
2759
+
2760
+ Used by ``_get_env_config`` to detect env vars whose remainder claims
2761
+ a longer, sibling-owned prefix (e.g. ``SPECKIT_GIT_HOOKS_URL`` is
2762
+ owned by ``git-hooks`` when it is co-installed with ``git``).
2763
+ """
2764
+ extensions_dir = self.project_root / ".specify" / "extensions"
2765
+ try:
2766
+ return list(ExtensionRegistry(extensions_dir).keys())
2767
+ except (OSError, UnicodeError):
2768
+ return []
2769
+
2740
2770
  def _get_env_config(self) -> Dict[str, Any]:
2741
2771
  """Get configuration from environment variables.
2742
2772
 
@@ -2756,15 +2786,49 @@ class ConfigManager:
2756
2786
  ext_id_upper = self.extension_id.replace("-", "_").upper()
2757
2787
  prefix = f"SPECKIT_{ext_id_upper}_"
2758
2788
 
2789
+ # Cross-extension prefix collision: because ``_`` doubles as both the
2790
+ # separator between the extension ID and the config path *and* the
2791
+ # substitute for ``-`` inside an extension ID, an env var like
2792
+ # ``SPECKIT_GIT_HOOKS_URL`` begins with *both* the ``SPECKIT_GIT_``
2793
+ # prefix of the ``git`` extension and the ``SPECKIT_GIT_HOOKS_`` prefix
2794
+ # of a co-installed ``git-hooks`` extension. It logically belongs to
2795
+ # the extension whose normalized ID is the longer, more specific match
2796
+ # — otherwise config intended for one extension silently surfaces
2797
+ # inside another and can drive hooks that only inspect
2798
+ # ``config.<field> is set``. Build the list of sibling-owned
2799
+ # remainder-prefixes here so a later env var can be skipped if it
2800
+ # matches one.
2801
+ sibling_prefixes: list[str] = []
2802
+ for sibling_id in self._sibling_extension_ids():
2803
+ if sibling_id == self.extension_id:
2804
+ continue
2805
+ sib_upper = sibling_id.replace("-", "_").upper()
2806
+ # A sibling collides only when its normalized ID *extends* our own
2807
+ # (i.e. starts with ``<US>_``). ``git`` vs ``not-git`` is not a
2808
+ # collision; ``git`` vs ``git-hooks`` is.
2809
+ if sib_upper.startswith(ext_id_upper + "_"):
2810
+ # The portion of the env-var *remainder* the sibling claims,
2811
+ # including the trailing ``_`` so a shorter ID that shares a
2812
+ # non-boundary prefix cannot false-positive (e.g. sibling
2813
+ # ``hook`` would not eat env vars under key ``hooks``).
2814
+ sibling_prefixes.append(sib_upper[len(ext_id_upper) + 1 :] + "_")
2815
+
2759
2816
  for key, value in os.environ.items():
2760
2817
  if not key.startswith(prefix):
2761
2818
  continue
2762
2819
 
2820
+ remainder = key[len(prefix) :]
2821
+ # Skip when a longer sibling ID claims this var — see the block
2822
+ # above. Keeps ``SPECKIT_GIT_HOOKS_URL`` out of the ``git``
2823
+ # extension's config when ``git-hooks`` is co-installed.
2824
+ if any(remainder.startswith(sp) for sp in sibling_prefixes):
2825
+ continue
2826
+
2763
2827
  # Remove prefix and split into parts. Drop empty components from a
2764
2828
  # malformed name (e.g. ``SPECKIT_<EXT>_`` with no key, or
2765
2829
  # consecutive underscores ``SPECKIT_X__Y``) so we never create an
2766
2830
  # entry under an empty key.
2767
- config_path = [p for p in key[len(prefix) :].lower().split("_") if p]
2831
+ config_path = [p for p in remainder.lower().split("_") if p]
2768
2832
  if not config_path:
2769
2833
  continue
2770
2834
 
@@ -1122,6 +1122,17 @@ class TomlIntegration(IntegrationBase):
1122
1122
  # YamlIntegration — YAML-format agents (Goose)
1123
1123
  # ---------------------------------------------------------------------------
1124
1124
 
1125
+ # Characters a YAML literal block scalar cannot carry: C0 controls other
1126
+ # than tab/LF (a bare CR acts as a line break inside the scalar), DEL, the
1127
+ # C1 range, lone UTF-16 surrogates, and the non-characters U+FFFE/U+FFFF.
1128
+ # NEL (U+0085) is YAML-printable but, like LS/PS (U+2028/U+2029), YAML 1.1
1129
+ # treats it as a line break, which corrupts the block scalar's structure
1130
+ # just the same, so all three are included.
1131
+ _YAML_BLOCK_SCALAR_UNSAFE = re.compile(
1132
+ r"[\x00-\x08\x0b-\x1f\x7f-\x9f\u2028\u2029\ud800-\udfff\ufffe\uffff]"
1133
+ )
1134
+
1135
+
1125
1136
  class YamlIntegration(IntegrationBase):
1126
1137
  """Concrete base for integrations that use YAML recipe format.
1127
1138
 
@@ -1227,9 +1238,9 @@ class YamlIntegration(IntegrationBase):
1227
1238
  def _render_yaml(cls, title: str, description: str, body: str, source_id: str) -> str:
1228
1239
  """Render a YAML recipe file from title, description, and body.
1229
1240
 
1230
- Produces a Goose-compatible recipe with a literal block scalar
1231
- for the prompt content. Uses ``yaml.safe_dump()`` for the
1232
- header fields to ensure proper escaping.
1241
+ Produces a Goose-compatible recipe with a literal block scalar for
1242
+ normal prompt content, or an escaped quoted scalar when control
1243
+ characters require it. Uses ``yaml.safe_dump()`` for the header fields.
1233
1244
  """
1234
1245
  header = cls._build_yaml_header(title, description)
1235
1246
 
@@ -1240,6 +1251,23 @@ class YamlIntegration(IntegrationBase):
1240
1251
  default_flow_style=False,
1241
1252
  ).strip()
1242
1253
 
1254
+ # YAML forbids C0 control characters (except tab and newline) and
1255
+ # DEL in every scalar form, and a bare CR acts as a line break
1256
+ # inside a block scalar. A literal block scalar emits such bytes
1257
+ # verbatim, producing a recipe the YAML parser rejects, so fall
1258
+ # back to an escaped double-quoted scalar for those bodies.
1259
+ if _YAML_BLOCK_SCALAR_UNSAFE.search(body):
1260
+ prompt_yaml = yaml.safe_dump(
1261
+ {"prompt": body}, allow_unicode=True, default_style='"', width=sys.maxsize
1262
+ ).strip()
1263
+ lines = [
1264
+ header_yaml,
1265
+ prompt_yaml,
1266
+ "",
1267
+ f"# Source: {source_id}",
1268
+ ]
1269
+ return "\n".join(lines) + "\n"
1270
+
1243
1271
  # Indent the body for YAML block scalar. Use an explicit indentation
1244
1272
  # indicator ("|2") rather than a bare "|": YAML infers a plain block
1245
1273
  # scalar's indentation from its first non-empty line, so a body whose