specify-cli 0.12.7__tar.gz → 0.12.8__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 (459) hide show
  1. {specify_cli-0.12.7 → specify_cli-0.12.8}/CHANGELOG.md +15 -0
  2. {specify_cli-0.12.7 → specify_cli-0.12.8}/PKG-INFO +2 -2
  3. {specify_cli-0.12.7 → specify_cli-0.12.8}/README.md +1 -1
  4. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/community/extensions.md +1 -0
  5. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/reference/extensions.md +1 -1
  6. specify_cli-0.12.8/extensions/agent-context/scripts/python/update_agent_context.py +352 -0
  7. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/catalog.community.json +34 -0
  8. {specify_cli-0.12.7 → specify_cli-0.12.8}/pyproject.toml +1 -1
  9. {specify_cli-0.12.7 → specify_cli-0.12.8}/scripts/bash/common.sh +11 -2
  10. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/_github_http.py +8 -1
  11. specify_cli-0.12.8/src/specify_cli/_toml_string.py +60 -0
  12. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/agents.py +13 -12
  13. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/authentication/http.py +7 -1
  14. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/extensions/_commands.py +5 -1
  15. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/base.py +16 -11
  16. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/manifest.py +19 -4
  17. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/presets/_commands.py +10 -2
  18. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/workflows/_commands.py +5 -1
  19. specify_cli-0.12.8/tests/extensions/test_update_agent_context_python_parity.py +481 -0
  20. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_base_toml.py +12 -0
  21. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_manifest.py +37 -0
  22. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_authentication.py +16 -0
  23. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_extensions.py +42 -0
  24. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_github_http.py +17 -0
  25. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_presets.py +21 -0
  26. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_setup_plan_feature_json.py +65 -0
  27. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_workflows.py +17 -0
  28. {specify_cli-0.12.7 → specify_cli-0.12.8}/.devcontainer/devcontainer.json +0 -0
  29. {specify_cli-0.12.7 → specify_cli-0.12.8}/.devcontainer/post-create.sh +0 -0
  30. {specify_cli-0.12.7 → specify_cli-0.12.8}/.editorconfig +0 -0
  31. {specify_cli-0.12.7 → specify_cli-0.12.8}/.gitattributes +0 -0
  32. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/CODEOWNERS +0 -0
  33. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/ISSUE_TEMPLATE/agent_request.yml +0 -0
  34. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  35. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/ISSUE_TEMPLATE/bundle_submission.yml +0 -0
  36. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  37. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/ISSUE_TEMPLATE/extension_submission.yml +0 -0
  38. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  39. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/ISSUE_TEMPLATE/preset_submission.yml +0 -0
  40. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  41. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/aw/actions-lock.json +0 -0
  42. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/dependabot.yml +0 -0
  43. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/skills/add-community-extension/SKILL.md +0 -0
  44. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/workflows/RELEASE-PROCESS.md +0 -0
  45. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/workflows/add-community-extension.lock.yml +0 -0
  46. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/workflows/add-community-extension.md +0 -0
  47. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/workflows/add-community-preset.lock.yml +0 -0
  48. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/workflows/add-community-preset.md +0 -0
  49. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/workflows/bug-assess.lock.yml +0 -0
  50. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/workflows/bug-assess.md +0 -0
  51. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/workflows/bug-fix.lock.yml +0 -0
  52. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/workflows/bug-fix.md +0 -0
  53. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/workflows/bug-test.lock.yml +0 -0
  54. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/workflows/bug-test.md +0 -0
  55. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/workflows/catalog-assign.yml +0 -0
  56. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/workflows/codeql.yml +0 -0
  57. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/workflows/docs.yml +0 -0
  58. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/workflows/lint.yml +0 -0
  59. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/workflows/publish-pypi.yml +0 -0
  60. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/workflows/release-trigger.yml +0 -0
  61. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/workflows/release.yml +0 -0
  62. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/workflows/stale.yml +0 -0
  63. {specify_cli-0.12.7 → specify_cli-0.12.8}/.github/workflows/test.yml +0 -0
  64. {specify_cli-0.12.7 → specify_cli-0.12.8}/.gitignore +0 -0
  65. {specify_cli-0.12.7 → specify_cli-0.12.8}/.markdownlint-cli2.jsonc +0 -0
  66. {specify_cli-0.12.7 → specify_cli-0.12.8}/.zenodo.json +0 -0
  67. {specify_cli-0.12.7 → specify_cli-0.12.8}/AGENTS.md +0 -0
  68. {specify_cli-0.12.7 → specify_cli-0.12.8}/CITATION.cff +0 -0
  69. {specify_cli-0.12.7 → specify_cli-0.12.8}/CODE_OF_CONDUCT.md +0 -0
  70. {specify_cli-0.12.7 → specify_cli-0.12.8}/CONTRIBUTING.md +0 -0
  71. {specify_cli-0.12.7 → specify_cli-0.12.8}/DEVELOPMENT.md +0 -0
  72. {specify_cli-0.12.7 → specify_cli-0.12.8}/LICENSE +0 -0
  73. {specify_cli-0.12.7 → specify_cli-0.12.8}/SECURITY.md +0 -0
  74. {specify_cli-0.12.7 → specify_cli-0.12.8}/SUPPORT.md +0 -0
  75. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/.gitignore +0 -0
  76. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/README.md +0 -0
  77. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/community/bundles.md +0 -0
  78. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/community/friends.md +0 -0
  79. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/community/overview.md +0 -0
  80. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/community/presets.md +0 -0
  81. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/community/walkthroughs.md +0 -0
  82. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/concepts/complex-features.md +0 -0
  83. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/concepts/sdd.md +0 -0
  84. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/concepts/spec-persistence.md +0 -0
  85. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/docfx.json +0 -0
  86. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/guides/evolving-specs.md +0 -0
  87. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/guides/monorepo.md +0 -0
  88. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/index.md +0 -0
  89. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/install/air-gapped.md +0 -0
  90. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/install/one-time.md +0 -0
  91. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/install/pipx.md +0 -0
  92. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/install/uv.md +0 -0
  93. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/installation.md +0 -0
  94. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/local-development.md +0 -0
  95. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/quickstart.md +0 -0
  96. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/reference/authentication.md +0 -0
  97. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/reference/bundles.md +0 -0
  98. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/reference/core.md +0 -0
  99. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/reference/integrations.md +0 -0
  100. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/reference/overview.md +0 -0
  101. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/reference/presets.md +0 -0
  102. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/reference/workflows.md +0 -0
  103. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/template/public/main.css +0 -0
  104. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/toc.yml +0 -0
  105. {specify_cli-0.12.7 → specify_cli-0.12.8}/docs/upgrade.md +0 -0
  106. {specify_cli-0.12.7 → specify_cli-0.12.8}/examples/bundles/business-analyst/README.md +0 -0
  107. {specify_cli-0.12.7 → specify_cli-0.12.8}/examples/bundles/business-analyst/bundle.yml +0 -0
  108. {specify_cli-0.12.7 → specify_cli-0.12.8}/examples/bundles/developer/README.md +0 -0
  109. {specify_cli-0.12.7 → specify_cli-0.12.8}/examples/bundles/developer/bundle.yml +0 -0
  110. {specify_cli-0.12.7 → specify_cli-0.12.8}/examples/bundles/product-manager/README.md +0 -0
  111. {specify_cli-0.12.7 → specify_cli-0.12.8}/examples/bundles/product-manager/bundle.yml +0 -0
  112. {specify_cli-0.12.7 → specify_cli-0.12.8}/examples/bundles/security-researcher/README.md +0 -0
  113. {specify_cli-0.12.7 → specify_cli-0.12.8}/examples/bundles/security-researcher/bundle.yml +0 -0
  114. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/EXTENSION-API-REFERENCE.md +0 -0
  115. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/EXTENSION-DEVELOPMENT-GUIDE.md +0 -0
  116. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/EXTENSION-PUBLISHING-GUIDE.md +0 -0
  117. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/EXTENSION-USER-GUIDE.md +0 -0
  118. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/README.md +0 -0
  119. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/RFC-EXTENSION-SYSTEM.md +0 -0
  120. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/agent-context/README.md +0 -0
  121. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/agent-context/agent-context-config.yml +0 -0
  122. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/agent-context/agent-context-defaults.json +0 -0
  123. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/agent-context/commands/speckit.agent-context.update.md +0 -0
  124. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/agent-context/extension.yml +0 -0
  125. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/agent-context/scripts/bash/update-agent-context.sh +0 -0
  126. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/agent-context/scripts/powershell/update-agent-context.ps1 +0 -0
  127. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/bug/README.md +0 -0
  128. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/bug/commands/speckit.bug.assess.md +0 -0
  129. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/bug/commands/speckit.bug.fix.md +0 -0
  130. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/bug/commands/speckit.bug.test.md +0 -0
  131. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/bug/extension.yml +0 -0
  132. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/catalog.json +0 -0
  133. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/git/README.md +0 -0
  134. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/git/commands/speckit.git.commit.md +0 -0
  135. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/git/commands/speckit.git.feature.md +0 -0
  136. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/git/commands/speckit.git.initialize.md +0 -0
  137. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/git/commands/speckit.git.remote.md +0 -0
  138. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/git/commands/speckit.git.validate.md +0 -0
  139. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/git/config-template.yml +0 -0
  140. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/git/extension.yml +0 -0
  141. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/git/git-config.yml +0 -0
  142. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/git/scripts/bash/auto-commit.sh +0 -0
  143. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/git/scripts/bash/create-new-feature-branch.sh +0 -0
  144. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/git/scripts/bash/git-common.sh +0 -0
  145. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/git/scripts/bash/initialize-repo.sh +0 -0
  146. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/git/scripts/powershell/auto-commit.ps1 +0 -0
  147. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/git/scripts/powershell/create-new-feature-branch.ps1 +0 -0
  148. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/git/scripts/powershell/git-common.ps1 +0 -0
  149. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/git/scripts/powershell/initialize-repo.ps1 +0 -0
  150. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/selftest/commands/selftest.md +0 -0
  151. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/selftest/extension.yml +0 -0
  152. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/template/.gitignore +0 -0
  153. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/template/CHANGELOG.md +0 -0
  154. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/template/EXAMPLE-README.md +0 -0
  155. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/template/LICENSE +0 -0
  156. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/template/README.md +0 -0
  157. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/template/commands/example.md +0 -0
  158. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/template/config-template.yml +0 -0
  159. {specify_cli-0.12.7 → specify_cli-0.12.8}/extensions/template/extension.yml +0 -0
  160. {specify_cli-0.12.7 → specify_cli-0.12.8}/integrations/CONTRIBUTING.md +0 -0
  161. {specify_cli-0.12.7 → specify_cli-0.12.8}/integrations/README.md +0 -0
  162. {specify_cli-0.12.7 → specify_cli-0.12.8}/integrations/catalog.community.json +0 -0
  163. {specify_cli-0.12.7 → specify_cli-0.12.8}/integrations/catalog.json +0 -0
  164. {specify_cli-0.12.7 → specify_cli-0.12.8}/media/bootstrap-claude-code.gif +0 -0
  165. {specify_cli-0.12.7 → specify_cli-0.12.8}/media/logo_large.webp +0 -0
  166. {specify_cli-0.12.7 → specify_cli-0.12.8}/media/logo_small.webp +0 -0
  167. {specify_cli-0.12.7 → specify_cli-0.12.8}/media/spec-kit-video-header.jpg +0 -0
  168. {specify_cli-0.12.7 → specify_cli-0.12.8}/media/specify_cli.gif +0 -0
  169. {specify_cli-0.12.7 → specify_cli-0.12.8}/newsletters/2026-April.md +0 -0
  170. {specify_cli-0.12.7 → specify_cli-0.12.8}/newsletters/2026-February.md +0 -0
  171. {specify_cli-0.12.7 → specify_cli-0.12.8}/newsletters/2026-June.md +0 -0
  172. {specify_cli-0.12.7 → specify_cli-0.12.8}/newsletters/2026-March.md +0 -0
  173. {specify_cli-0.12.7 → specify_cli-0.12.8}/newsletters/2026-May.md +0 -0
  174. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/ARCHITECTURE.md +0 -0
  175. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/PUBLISHING.md +0 -0
  176. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/README.md +0 -0
  177. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/catalog.community.json +0 -0
  178. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/catalog.json +0 -0
  179. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/lean/README.md +0 -0
  180. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/lean/commands/speckit.constitution.md +0 -0
  181. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/lean/commands/speckit.implement.md +0 -0
  182. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/lean/commands/speckit.plan.md +0 -0
  183. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/lean/commands/speckit.specify.md +0 -0
  184. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/lean/commands/speckit.tasks.md +0 -0
  185. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/lean/preset.yml +0 -0
  186. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/scaffold/README.md +0 -0
  187. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/scaffold/commands/speckit.myext.myextcmd.md +0 -0
  188. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/scaffold/commands/speckit.specify.md +0 -0
  189. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/scaffold/preset.yml +0 -0
  190. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/scaffold/templates/myext-template.md +0 -0
  191. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/scaffold/templates/spec-template.md +0 -0
  192. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/self-test/commands/speckit.specify.md +0 -0
  193. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/self-test/commands/speckit.wrap-test.md +0 -0
  194. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/self-test/preset.yml +0 -0
  195. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/self-test/templates/agent-file-template.md +0 -0
  196. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/self-test/templates/checklist-template.md +0 -0
  197. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/self-test/templates/constitution-template.md +0 -0
  198. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/self-test/templates/plan-template.md +0 -0
  199. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/self-test/templates/spec-template.md +0 -0
  200. {specify_cli-0.12.7 → specify_cli-0.12.8}/presets/self-test/templates/tasks-template.md +0 -0
  201. {specify_cli-0.12.7 → specify_cli-0.12.8}/scripts/bash/check-prerequisites.sh +0 -0
  202. {specify_cli-0.12.7 → specify_cli-0.12.8}/scripts/bash/create-new-feature.sh +0 -0
  203. {specify_cli-0.12.7 → specify_cli-0.12.8}/scripts/bash/setup-plan.sh +0 -0
  204. {specify_cli-0.12.7 → specify_cli-0.12.8}/scripts/bash/setup-tasks.sh +0 -0
  205. {specify_cli-0.12.7 → specify_cli-0.12.8}/scripts/powershell/check-prerequisites.ps1 +0 -0
  206. {specify_cli-0.12.7 → specify_cli-0.12.8}/scripts/powershell/common.ps1 +0 -0
  207. {specify_cli-0.12.7 → specify_cli-0.12.8}/scripts/powershell/create-new-feature.ps1 +0 -0
  208. {specify_cli-0.12.7 → specify_cli-0.12.8}/scripts/powershell/setup-plan.ps1 +0 -0
  209. {specify_cli-0.12.7 → specify_cli-0.12.8}/scripts/powershell/setup-tasks.ps1 +0 -0
  210. {specify_cli-0.12.7 → specify_cli-0.12.8}/scripts/python/check_prerequisites.py +0 -0
  211. {specify_cli-0.12.7 → specify_cli-0.12.8}/scripts/python/common.py +0 -0
  212. {specify_cli-0.12.7 → specify_cli-0.12.8}/spec-driven.md +0 -0
  213. {specify_cli-0.12.7 → specify_cli-0.12.8}/spec-kit.code-workspace +0 -0
  214. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/__init__.py +0 -0
  215. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/_agent_config.py +0 -0
  216. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/_assets.py +0 -0
  217. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/_console.py +0 -0
  218. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/_init_options.py +0 -0
  219. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/_invocation_style.py +0 -0
  220. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/_project.py +0 -0
  221. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/_utils.py +0 -0
  222. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/_version.py +0 -0
  223. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/authentication/__init__.py +0 -0
  224. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/authentication/azure_devops.py +0 -0
  225. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/authentication/base.py +0 -0
  226. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/authentication/config.py +0 -0
  227. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/authentication/github.py +0 -0
  228. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/__init__.py +0 -0
  229. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/commands_impl/__init__.py +0 -0
  230. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/commands_impl/catalog_config.py +0 -0
  231. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/lib/__init__.py +0 -0
  232. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/lib/project.py +0 -0
  233. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/lib/versioning.py +0 -0
  234. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/lib/yamlio.py +0 -0
  235. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/models/__init__.py +0 -0
  236. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/models/catalog.py +0 -0
  237. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/models/manifest.py +0 -0
  238. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/models/records.py +0 -0
  239. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/services/__init__.py +0 -0
  240. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/services/adapters.py +0 -0
  241. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/services/catalog_stack.py +0 -0
  242. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/services/conflict.py +0 -0
  243. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/services/installer.py +0 -0
  244. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/services/packager.py +0 -0
  245. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/services/primitives.py +0 -0
  246. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/services/references.py +0 -0
  247. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/services/resolver.py +0 -0
  248. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/bundler/services/validator.py +0 -0
  249. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/catalogs.py +0 -0
  250. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/commands/__init__.py +0 -0
  251. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/commands/bundle/__init__.py +0 -0
  252. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/commands/init.py +0 -0
  253. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/extensions/__init__.py +0 -0
  254. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integration_runtime.py +0 -0
  255. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integration_scaffold.py +0 -0
  256. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integration_state.py +0 -0
  257. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integration_status.py +0 -0
  258. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/__init__.py +0 -0
  259. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/_commands.py +0 -0
  260. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/_helpers.py +0 -0
  261. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/_install_commands.py +0 -0
  262. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/_migrate_commands.py +0 -0
  263. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/_query_commands.py +0 -0
  264. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/_scaffold_commands.py +0 -0
  265. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/agy/__init__.py +0 -0
  266. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/amp/__init__.py +0 -0
  267. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/auggie/__init__.py +0 -0
  268. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/bob/__init__.py +0 -0
  269. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/catalog.py +0 -0
  270. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/claude/__init__.py +0 -0
  271. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/cline/__init__.py +0 -0
  272. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/codebuddy/__init__.py +0 -0
  273. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/codex/__init__.py +0 -0
  274. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/copilot/__init__.py +0 -0
  275. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/cursor_agent/__init__.py +0 -0
  276. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/devin/__init__.py +0 -0
  277. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/firebender/__init__.py +0 -0
  278. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/forge/__init__.py +0 -0
  279. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/gemini/__init__.py +0 -0
  280. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/generic/__init__.py +0 -0
  281. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/goose/__init__.py +0 -0
  282. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/hermes/__init__.py +0 -0
  283. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/junie/__init__.py +0 -0
  284. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/kilocode/__init__.py +0 -0
  285. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/kimi/__init__.py +0 -0
  286. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/kiro_cli/__init__.py +0 -0
  287. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/lingma/__init__.py +0 -0
  288. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/omp/__init__.py +0 -0
  289. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/opencode/__init__.py +0 -0
  290. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/pi/__init__.py +0 -0
  291. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/qodercli/__init__.py +0 -0
  292. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/qwen/__init__.py +0 -0
  293. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/rovodev/__init__.py +0 -0
  294. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/shai/__init__.py +0 -0
  295. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/tabnine/__init__.py +0 -0
  296. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/trae/__init__.py +0 -0
  297. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/vibe/__init__.py +0 -0
  298. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/zcode/__init__.py +0 -0
  299. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/integrations/zed/__init__.py +0 -0
  300. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/presets/__init__.py +0 -0
  301. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/shared_infra.py +0 -0
  302. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/workflows/__init__.py +0 -0
  303. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/workflows/base.py +0 -0
  304. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/workflows/catalog.py +0 -0
  305. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/workflows/engine.py +0 -0
  306. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/workflows/expressions.py +0 -0
  307. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/workflows/steps/__init__.py +0 -0
  308. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/workflows/steps/command/__init__.py +0 -0
  309. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/workflows/steps/do_while/__init__.py +0 -0
  310. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/workflows/steps/fan_in/__init__.py +0 -0
  311. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/workflows/steps/fan_out/__init__.py +0 -0
  312. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/workflows/steps/gate/__init__.py +0 -0
  313. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/workflows/steps/if_then/__init__.py +0 -0
  314. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/workflows/steps/init/__init__.py +0 -0
  315. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/workflows/steps/prompt/__init__.py +0 -0
  316. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/workflows/steps/shell/__init__.py +0 -0
  317. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/workflows/steps/switch/__init__.py +0 -0
  318. {specify_cli-0.12.7 → specify_cli-0.12.8}/src/specify_cli/workflows/steps/while_loop/__init__.py +0 -0
  319. {specify_cli-0.12.7 → specify_cli-0.12.8}/templates/checklist-template.md +0 -0
  320. {specify_cli-0.12.7 → specify_cli-0.12.8}/templates/commands/analyze.md +0 -0
  321. {specify_cli-0.12.7 → specify_cli-0.12.8}/templates/commands/checklist.md +0 -0
  322. {specify_cli-0.12.7 → specify_cli-0.12.8}/templates/commands/clarify.md +0 -0
  323. {specify_cli-0.12.7 → specify_cli-0.12.8}/templates/commands/constitution.md +0 -0
  324. {specify_cli-0.12.7 → specify_cli-0.12.8}/templates/commands/converge.md +0 -0
  325. {specify_cli-0.12.7 → specify_cli-0.12.8}/templates/commands/implement.md +0 -0
  326. {specify_cli-0.12.7 → specify_cli-0.12.8}/templates/commands/plan.md +0 -0
  327. {specify_cli-0.12.7 → specify_cli-0.12.8}/templates/commands/specify.md +0 -0
  328. {specify_cli-0.12.7 → specify_cli-0.12.8}/templates/commands/tasks.md +0 -0
  329. {specify_cli-0.12.7 → specify_cli-0.12.8}/templates/commands/taskstoissues.md +0 -0
  330. {specify_cli-0.12.7 → specify_cli-0.12.8}/templates/constitution-template.md +0 -0
  331. {specify_cli-0.12.7 → specify_cli-0.12.8}/templates/plan-template.md +0 -0
  332. {specify_cli-0.12.7 → specify_cli-0.12.8}/templates/spec-template.md +0 -0
  333. {specify_cli-0.12.7 → specify_cli-0.12.8}/templates/tasks-template.md +0 -0
  334. {specify_cli-0.12.7 → specify_cli-0.12.8}/templates/vscode-settings.json +0 -0
  335. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/__init__.py +0 -0
  336. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/auth_helpers.py +0 -0
  337. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/bundler_helpers.py +0 -0
  338. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/conftest.py +0 -0
  339. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/contract/test_bundle_cli.py +0 -0
  340. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/contract/test_catalog_schema.py +0 -0
  341. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/contract/test_manifest_schema.py +0 -0
  342. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/extensions/__init__.py +0 -0
  343. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/extensions/bug/__init__.py +0 -0
  344. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/extensions/bug/test_bug_extension.py +0 -0
  345. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/extensions/git/__init__.py +0 -0
  346. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/extensions/git/test_git_extension.py +0 -0
  347. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/extensions/test_agent_context_cli_free.py +0 -0
  348. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/extensions/test_extension_agent_context.py +0 -0
  349. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/extensions/test_update_agent_context_feature_json.py +0 -0
  350. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/hooks/TESTING.md +0 -0
  351. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/hooks/plan.md +0 -0
  352. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/hooks/spec.md +0 -0
  353. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/hooks/tasks.md +0 -0
  354. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/http_helpers.py +0 -0
  355. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integration/test_bundler_catalog_stack.py +0 -0
  356. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integration/test_bundler_init_install.py +0 -0
  357. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integration/test_bundler_install_flow.py +0 -0
  358. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integration/test_bundler_local_install.py +0 -0
  359. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integration/test_bundler_offline.py +0 -0
  360. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integration/test_bundler_security_paths.py +0 -0
  361. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/__init__.py +0 -0
  362. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/conftest.py +0 -0
  363. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_base.py +0 -0
  364. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_cli.py +0 -0
  365. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_extra_args.py +0 -0
  366. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_home_isolation.py +0 -0
  367. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_agy.py +0 -0
  368. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_amp.py +0 -0
  369. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_auggie.py +0 -0
  370. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_base_markdown.py +0 -0
  371. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_base_skills.py +0 -0
  372. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_base_yaml.py +0 -0
  373. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_bob.py +0 -0
  374. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_catalog.py +0 -0
  375. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_claude.py +0 -0
  376. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_cline.py +0 -0
  377. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_codebuddy.py +0 -0
  378. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_codex.py +0 -0
  379. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_copilot.py +0 -0
  380. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_cursor_agent.py +0 -0
  381. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_devin.py +0 -0
  382. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_firebender.py +0 -0
  383. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_forge.py +0 -0
  384. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_gemini.py +0 -0
  385. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_generic.py +0 -0
  386. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_goose.py +0 -0
  387. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_hermes.py +0 -0
  388. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_junie.py +0 -0
  389. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_kilocode.py +0 -0
  390. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_kimi.py +0 -0
  391. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_kiro_cli.py +0 -0
  392. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_lingma.py +0 -0
  393. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_omp.py +0 -0
  394. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_opencode.py +0 -0
  395. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_pi.py +0 -0
  396. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_qodercli.py +0 -0
  397. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_qwen.py +0 -0
  398. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_rovodev.py +0 -0
  399. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_scaffold.py +0 -0
  400. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_shai.py +0 -0
  401. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_state.py +0 -0
  402. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_subcommand.py +0 -0
  403. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_tabnine.py +0 -0
  404. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_trae.py +0 -0
  405. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_vibe.py +0 -0
  406. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_zcode.py +0 -0
  407. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_integration_zed.py +0 -0
  408. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/integrations/test_registry.py +0 -0
  409. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/self_upgrade_helpers.py +0 -0
  410. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_agent_config_consistency.py +0 -0
  411. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_branch_numbering.py +0 -0
  412. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_check_prerequisites_paths_only.py +0 -0
  413. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_check_prerequisites_python_parity.py +0 -0
  414. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_check_tool.py +0 -0
  415. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_cli_version.py +0 -0
  416. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_commands_package.py +0 -0
  417. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_console_imports.py +0 -0
  418. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_extension_registration.py +0 -0
  419. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_extension_skills.py +0 -0
  420. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_extension_update_hardening.py +0 -0
  421. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_github_workflows.py +0 -0
  422. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_init_dir.py +0 -0
  423. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_init_dir_cli.py +0 -0
  424. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_live_transient_windows.py +0 -0
  425. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_merge.py +0 -0
  426. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_post_process.py +0 -0
  427. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_ps1_encoding.py +0 -0
  428. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_registrar_path_traversal.py +0 -0
  429. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_self_upgrade_detection.py +0 -0
  430. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_self_upgrade_execution.py +0 -0
  431. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_self_upgrade_guidance.py +0 -0
  432. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_self_upgrade_verification.py +0 -0
  433. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_setup_plan_no_overwrite.py +0 -0
  434. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_setup_tasks.py +0 -0
  435. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_shared_infra_integrity.py +0 -0
  436. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_timestamp_branches.py +0 -0
  437. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_upgrade.py +0 -0
  438. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_utils.py +0 -0
  439. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_utils_assets_imports.py +0 -0
  440. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_version_imports.py +0 -0
  441. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/test_workflow_run_without_project.py +0 -0
  442. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/unit/test_bundler_adapters.py +0 -0
  443. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/unit/test_bundler_catalog_config.py +0 -0
  444. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/unit/test_bundler_conflict.py +0 -0
  445. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/unit/test_bundler_packager.py +0 -0
  446. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/unit/test_bundler_primitives.py +0 -0
  447. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/unit/test_bundler_records.py +0 -0
  448. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/unit/test_bundler_references.py +0 -0
  449. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/unit/test_bundler_resolver.py +0 -0
  450. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/unit/test_bundler_validator.py +0 -0
  451. {specify_cli-0.12.7 → specify_cli-0.12.8}/tests/unit/test_bundler_versioning.py +0 -0
  452. {specify_cli-0.12.7 → specify_cli-0.12.8}/workflows/ARCHITECTURE.md +0 -0
  453. {specify_cli-0.12.7 → specify_cli-0.12.8}/workflows/PUBLISHING.md +0 -0
  454. {specify_cli-0.12.7 → specify_cli-0.12.8}/workflows/README.md +0 -0
  455. {specify_cli-0.12.7 → specify_cli-0.12.8}/workflows/catalog.community.json +0 -0
  456. {specify_cli-0.12.7 → specify_cli-0.12.8}/workflows/catalog.json +0 -0
  457. {specify_cli-0.12.7 → specify_cli-0.12.8}/workflows/speckit/workflow.yml +0 -0
  458. {specify_cli-0.12.7 → specify_cli-0.12.8}/workflows/step-catalog.community.json +0 -0
  459. {specify_cli-0.12.7 → specify_cli-0.12.8}/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.8] - 2026-07-08
6
+
7
+ ### Changed
8
+
9
+ - [extension] Add LLM Wiki extension to community catalog (#3361)
10
+ - Docs: Document missing CLI flags and integrations (#3182)
11
+ - Docs: Remove Cursor from CLI check list in README (#3184)
12
+ - feat(extensions): port update-agent-context to Python (#3387)
13
+ - fix(scripts): fall through to grep/sed when python3 is a broken stub in feature.json parser (#3312)
14
+ - fix(toml): escape control characters so generated command files parse (#3341)
15
+ - fix(cli): exit cleanly on malformed IPv6 URLs in `extension`/`preset`/`workflow add` (#3369)
16
+ - fix(github-http): return None on malformed GHES port instead of raising (#3379)
17
+ - fix(integrations): guard _sha256 against unreadable managed files (#3376)
18
+ - chore: release 0.12.7, begin 0.12.8.dev0 development (#3398)
19
+
5
20
  ## [0.12.7] - 2026-07-07
6
21
 
7
22
  ### Changed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specify-cli
3
- Version: 0.12.7
3
+ Version: 0.12.8
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
@@ -426,7 +426,7 @@ specify init . --force --integration copilot
426
426
  specify init --here --force --integration copilot
427
427
  ```
428
428
 
429
- The CLI will check that your selected agent's CLI tool is installed (for integrations that require a CLI), such as Claude Code, Gemini CLI, Qwen Code, opencode, Codex CLI, Qoder CLI, Tabnine CLI, Kiro CLI, Pi Coding Agent, Oh My Pi, Forge, Goose, Mistral Vibe, or ZCode. If you don't have the required tool installed, or you prefer to get the templates without checking for the right tools, use `--ignore-agent-tools` with your command:
429
+ The CLI checks that the selected integration's required CLI tool is installed on your machine when that integration has `requires_cli: True`. If you do not have the required tool installed, or you prefer to get the templates without checking for the right tools, use `--ignore-agent-tools` with your command:
430
430
 
431
431
  ```bash
432
432
  specify init <project_name> --integration copilot --ignore-agent-tools
@@ -406,7 +406,7 @@ specify init . --force --integration copilot
406
406
  specify init --here --force --integration copilot
407
407
  ```
408
408
 
409
- The CLI will check that your selected agent's CLI tool is installed (for integrations that require a CLI), such as Claude Code, Gemini CLI, Qwen Code, opencode, Codex CLI, Qoder CLI, Tabnine CLI, Kiro CLI, Pi Coding Agent, Oh My Pi, Forge, Goose, Mistral Vibe, or ZCode. If you don't have the required tool installed, or you prefer to get the templates without checking for the right tools, use `--ignore-agent-tools` with your command:
409
+ The CLI checks that the selected integration's required CLI tool is installed on your machine when that integration has `requires_cli: True`. If you do not have the required tool installed, or you prefer to get the templates without checking for the right tools, use `--ignore-agent-tools` with your command:
410
410
 
411
411
  ```bash
412
412
  specify init <project_name> --integration copilot --ignore-agent-tools
@@ -67,6 +67,7 @@ The following community-contributed extensions are available in [`catalog.commun
67
67
  | Jira Integration (Sync Engine) | Idempotent, drift-aware, fail-closed reconcile engine mirroring spec-kit specs into Jira (Epic per repo, Story per spec, Subtask per phase) | `integration` | Read+Write | [spec-kit-jira-sync](https://github.com/ashbrener/spec-kit-jira-sync) |
68
68
  | Learning Extension | Generate educational guides from implementations and enhance clarifications with mentoring context | `docs` | Read+Write | [spec-kit-learn](https://github.com/imviancagrace/spec-kit-learn) |
69
69
  | Linear Integration | Mirror spec-kit feature directories into Linear (filesystem → Linear, reconcile-based, unidirectional). | `integration` | Read+Write | [spec-kit-linear-sync](https://github.com/ashbrener/spec-kit-linear-sync) |
70
+ | LLM Wiki | LLM-maintained compounding project wiki: source ingestion, cited answers, and consistency linting | `docs` | Read+Write | [spec-kit-wiki](https://github.com/formin/spec-kit-wiki) |
70
71
  | Loop Engineering | Engineer safe autonomous agent loops for spec-driven development: a maker/checker split, externalized loop state, and stay-the-engineer guardrails against comprehension debt and cognitive surrender | `process` | Read+Write | [spec-kit-loop](https://github.com/formin/spec-kit-loop) |
71
72
  | MAQA — Multi-Agent & Quality Assurance | Coordinator → feature → QA agent workflow with parallel worktree-based implementation. Language-agnostic. Auto-detects installed board plugins. Optional CI gate. | `process` | Read+Write | [spec-kit-maqa-ext](https://github.com/GenieRobot/spec-kit-maqa-ext) |
72
73
  | MAQA Azure DevOps Integration | Azure DevOps Boards integration for MAQA — syncs User Stories and Task children as features progress | `integration` | Read+Write | [spec-kit-maqa-azure-devops](https://github.com/GenieRobot/spec-kit-maqa-azure-devops) |
@@ -26,7 +26,7 @@ specify extension add <name>
26
26
  | --------------- | -------------------------------------------------------- |
27
27
  | `--dev` | Install from a local directory (for development) |
28
28
  | `--from <url>` | Install from a custom URL instead of the catalog |
29
- | `--force` | Overwrite if already installed |
29
+ | `--force` | Overwrite if the extension is already installed |
30
30
  | `--priority <N>`| Resolution priority (default: 10; lower = higher precedence) |
31
31
 
32
32
  Installs an extension from the catalog, a URL, or a local directory. Extension commands are automatically registered with the currently installed AI coding agent integration.
@@ -0,0 +1,352 @@
1
+ #!/usr/bin/env python3
2
+ """Refresh the managed Spec Kit section in the coding agent's context file(s).
3
+
4
+ Python port of ``update-agent-context.sh`` / ``update-agent-context.ps1``.
5
+
6
+ Reads ``context_files`` or ``context_file``, plus ``context_markers.{start,end}``,
7
+ from the agent-context extension config:
8
+ .specify/extensions/agent-context/agent-context-config.yml
9
+
10
+ Usage: update_agent_context.py [plan_path]
11
+
12
+ When ``plan_path`` is omitted, the script derives it from
13
+ ``.specify/feature.json`` (written by /speckit-specify). Falls back to the most
14
+ recently modified ``specs/*/plan.md`` only when feature.json is absent or its
15
+ plan does not exist yet.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import json
21
+ import os
22
+ import re
23
+ import sys
24
+ from pathlib import Path
25
+
26
+ DEFAULT_START = "<!-- SPECKIT START -->"
27
+ DEFAULT_END = "<!-- SPECKIT END -->"
28
+
29
+
30
+ def _err(message: str) -> None:
31
+ print(message, file=sys.stderr)
32
+
33
+
34
+ def _get_str(obj: object, *keys: str) -> str:
35
+ node = obj
36
+ for key in keys:
37
+ if isinstance(node, dict) and key in node:
38
+ node = node[key]
39
+ else:
40
+ return ""
41
+ return node if isinstance(node, str) else ""
42
+
43
+
44
+ def _collect_context_files(data: dict, project_root: str) -> list[str]:
45
+ """Resolve the managed context files from config, mirroring the bash logic."""
46
+ context_files: list[str] = []
47
+ seen: set[str] = set()
48
+ case_insensitive = sys.platform.startswith(("win32", "cygwin", "msys"))
49
+
50
+ def add(value: object) -> None:
51
+ if not isinstance(value, str):
52
+ return
53
+ candidate = value.strip()
54
+ if not candidate:
55
+ return
56
+ key = candidate.casefold() if case_insensitive else candidate
57
+ if key in seen:
58
+ return
59
+ context_files.append(candidate)
60
+ seen.add(key)
61
+
62
+ raw_files = data.get("context_files")
63
+ if isinstance(raw_files, list):
64
+ for value in raw_files:
65
+ add(value)
66
+ if not context_files:
67
+ add(_get_str(data, "context_file"))
68
+ if not context_files:
69
+ # Self-seed: when the config declares no target, derive one from the
70
+ # active integration recorded in init-options.json, mapped through the
71
+ # bundled agent-context-defaults.json file. Independent of the Specify
72
+ # CLI by design.
73
+ integration_key = ""
74
+ try:
75
+ with open(
76
+ f"{project_root}/.specify/init-options.json", "r", encoding="utf-8"
77
+ ) as fh:
78
+ opts = json.load(fh)
79
+ if isinstance(opts, dict):
80
+ value = opts.get("integration") or opts.get("ai") or ""
81
+ integration_key = value if isinstance(value, str) else ""
82
+ except Exception:
83
+ integration_key = ""
84
+ if integration_key:
85
+ defaults_path = (
86
+ f"{project_root}/.specify/extensions/agent-context/"
87
+ "agent-context-defaults.json"
88
+ )
89
+ mapping = {}
90
+ try:
91
+ with open(defaults_path, "r", encoding="utf-8") as fh:
92
+ loaded = json.load(fh)
93
+ agents = loaded.get("agents", {}) if isinstance(loaded, dict) else {}
94
+ mapping = agents if isinstance(agents, dict) else {}
95
+ except Exception:
96
+ _err(
97
+ "agent-context: unable to read %s; cannot self-seed the context "
98
+ "file. Set context_file in the extension config." % defaults_path
99
+ )
100
+ mapping = {}
101
+ add(mapping.get(integration_key, "") or "")
102
+ if not context_files:
103
+ _err(
104
+ "agent-context: no default context file is known for integration "
105
+ "%s. Set context_file in the extension config to choose one."
106
+ % integration_key
107
+ )
108
+ return context_files
109
+
110
+
111
+ def _validate_context_file(project_root: str, context_file: str) -> str | None:
112
+ """Return an error message when the path escapes the project root."""
113
+ if context_file.startswith("/") or re.match(r"^[A-Za-z]:", context_file):
114
+ return (
115
+ "agent-context: context files must be project-relative paths; "
116
+ f"got '{context_file}'."
117
+ )
118
+ if "\\" in context_file:
119
+ return (
120
+ "agent-context: context files must not contain backslash separators; "
121
+ f"got '{context_file}'."
122
+ )
123
+ if ".." in context_file.split("/"):
124
+ return (
125
+ "agent-context: context files must not contain '..' path segments; "
126
+ f"got '{context_file}'."
127
+ )
128
+ root = Path(project_root).resolve()
129
+ target = (root / context_file).resolve()
130
+ try:
131
+ target.relative_to(root)
132
+ except ValueError:
133
+ return (
134
+ "agent-context: context file path resolves outside the project root; "
135
+ f"got '{context_file}'."
136
+ )
137
+ return None
138
+
139
+
140
+ def _resolve_plan_path(project_root: str) -> str:
141
+ """Derive the plan path: feature.json first, then the mtime fallback."""
142
+ plan_path = ""
143
+ feature_json = Path(project_root) / ".specify" / "feature.json"
144
+ if feature_json.is_file():
145
+ feature_dir = ""
146
+ try:
147
+ with open(feature_json, "r", encoding="utf-8") as fh:
148
+ data = json.load(fh)
149
+ value = data.get("feature_directory", "")
150
+ feature_dir = value if isinstance(value, str) else ""
151
+ except Exception:
152
+ feature_dir = ""
153
+ # Normalize backslashes (written by PS on Windows) before path ops.
154
+ feature_dir = feature_dir.replace("\\", "/").rstrip("/")
155
+ if feature_dir:
156
+ # feature_directory may be relative or absolute (absolute paths
157
+ # outside the project root are preserved as-is), including
158
+ # drive-qualified paths (C:/...) written by PowerShell on Windows.
159
+ if feature_dir.startswith("/") or re.match(r"^[A-Za-z]:/", feature_dir):
160
+ candidate = Path(feature_dir) / "plan.md"
161
+ else:
162
+ candidate = Path(project_root) / feature_dir / "plan.md"
163
+ if candidate.is_file():
164
+ # Resolve symlinks before comparing so paths like /var/… vs
165
+ # /private/var/… (macOS) are treated as equivalent.
166
+ root = Path(project_root).resolve()
167
+ resolved = candidate.resolve()
168
+ try:
169
+ plan_path = resolved.relative_to(root).as_posix()
170
+ except ValueError:
171
+ plan_path = resolved.as_posix()
172
+
173
+ if not plan_path:
174
+ root = Path(project_root).resolve()
175
+ plans = sorted(
176
+ (root / "specs").glob("*/plan.md"),
177
+ key=lambda p: p.stat().st_mtime,
178
+ reverse=True,
179
+ )
180
+ if plans:
181
+ try:
182
+ plan_path = plans[0].relative_to(root).as_posix()
183
+ except ValueError:
184
+ plan_path = ""
185
+ return plan_path
186
+
187
+
188
+ def _build_section(marker_start: str, marker_end: str, plan_path: str) -> str:
189
+ lines = [
190
+ marker_start,
191
+ "For additional context about technologies to be used, project structure,",
192
+ "shell commands, and other important information, read the current plan",
193
+ ]
194
+ if plan_path:
195
+ lines.append(f"at {plan_path}")
196
+ lines.append(marker_end)
197
+ return "\n".join(lines) + "\n"
198
+
199
+
200
+ def ensure_mdc_frontmatter(content: str) -> str:
201
+ """Ensure ``.mdc`` content has YAML frontmatter with ``alwaysApply: true``.
202
+
203
+ Cursor only auto-loads ``.mdc`` rule files that carry frontmatter with
204
+ ``alwaysApply: true``. Prepend it when missing, or repair the value while
205
+ preserving any existing frontmatter comments/formatting.
206
+ """
207
+ leading_ws = len(content) - len(content.lstrip())
208
+ leading = content[:leading_ws]
209
+ stripped = content[leading_ws:]
210
+
211
+ if not stripped.startswith("---"):
212
+ return "---\nalwaysApply: true\n---\n\n" + content
213
+
214
+ match = re.match(
215
+ r"^(---[ \t]*\r?\n)(.*?)(\r?\n---[ \t]*)(\r?\n|$)(.*)",
216
+ stripped,
217
+ re.DOTALL,
218
+ )
219
+ if not match:
220
+ return "---\nalwaysApply: true\n---\n\n" + content
221
+
222
+ opening, fm_text, closing, sep, rest = match.groups()
223
+ newline = "\r\n" if "\r\n" in opening else "\n"
224
+
225
+ if re.search(r"(?m)^[ \t]*alwaysApply[ \t]*:[ \t]*true[ \t]*(?:#.*)?$", fm_text):
226
+ return content
227
+
228
+ if re.search(r"(?m)^[ \t]*alwaysApply[ \t]*:", fm_text):
229
+ fm_text = re.sub(
230
+ r"(?m)^([ \t]*)alwaysApply[ \t]*:.*?([ \t]*(?:#.*)?)$",
231
+ r"\1alwaysApply: true\2",
232
+ fm_text,
233
+ count=1,
234
+ )
235
+ elif fm_text.strip():
236
+ fm_text = fm_text + newline + "alwaysApply: true"
237
+ else:
238
+ fm_text = "alwaysApply: true"
239
+
240
+ return f"{leading}{opening}{fm_text}{closing}{sep}{rest}"
241
+
242
+
243
+ def _upsert_section(
244
+ ctx_path: str, marker_start: str, marker_end: str, section: str
245
+ ) -> None:
246
+ """Insert or replace the managed section, then normalize and write."""
247
+ if os.path.exists(ctx_path):
248
+ with open(ctx_path, "r", encoding="utf-8-sig") as fh:
249
+ content = fh.read()
250
+ s = content.find(marker_start)
251
+ e = content.find(marker_end, s if s != -1 else 0)
252
+ if s != -1 and e != -1 and e > s:
253
+ end_of_marker = e + len(marker_end)
254
+ if end_of_marker < len(content) and content[end_of_marker] == "\r":
255
+ end_of_marker += 1
256
+ if end_of_marker < len(content) and content[end_of_marker] == "\n":
257
+ end_of_marker += 1
258
+ new_content = content[:s] + section + content[end_of_marker:]
259
+ elif s != -1:
260
+ new_content = content[:s] + section
261
+ elif e != -1:
262
+ end_of_marker = e + len(marker_end)
263
+ if end_of_marker < len(content) and content[end_of_marker] == "\r":
264
+ end_of_marker += 1
265
+ if end_of_marker < len(content) and content[end_of_marker] == "\n":
266
+ end_of_marker += 1
267
+ new_content = section + content[end_of_marker:]
268
+ else:
269
+ if content and not content.endswith("\n"):
270
+ content += "\n"
271
+ new_content = (content + "\n" + section) if content else section
272
+ else:
273
+ new_content = section
274
+
275
+ new_content = new_content.replace("\r\n", "\n").replace("\r", "\n")
276
+ if ctx_path.casefold().endswith(".mdc"):
277
+ new_content = ensure_mdc_frontmatter(new_content)
278
+ with open(ctx_path, "wb") as fh:
279
+ fh.write(new_content.encode("utf-8"))
280
+
281
+
282
+ def main(argv: list[str] | None = None) -> int:
283
+ args = sys.argv[1:] if argv is None else argv
284
+ project_root = os.getcwd()
285
+ ext_config = (
286
+ f"{project_root}/.specify/extensions/agent-context/agent-context-config.yml"
287
+ )
288
+
289
+ if not os.path.isfile(ext_config):
290
+ _err(f"agent-context: {ext_config} not found; nothing to do.")
291
+ return 0
292
+
293
+ try:
294
+ import yaml
295
+ except ImportError:
296
+ _err(
297
+ "agent-context: PyYAML is required to parse extension config but is "
298
+ "not available in the current Python environment.\n"
299
+ " To resolve: pip install pyyaml (or install it into the environment "
300
+ "used by python3).\n"
301
+ " Context file will not be updated until PyYAML is importable."
302
+ )
303
+ _err("agent-context: skipping update (see above for details).")
304
+ return 0
305
+
306
+ try:
307
+ with open(ext_config, "r", encoding="utf-8") as fh:
308
+ data = yaml.safe_load(fh)
309
+ except Exception as exc:
310
+ _err(
311
+ f"agent-context: unable to parse {ext_config} ({exc}); "
312
+ "cannot update context."
313
+ )
314
+ _err("agent-context: skipping update (see above for details).")
315
+ return 0
316
+ if not isinstance(data, dict):
317
+ data = {}
318
+
319
+ context_files = _collect_context_files(data, project_root)
320
+ if not context_files:
321
+ _err(
322
+ "agent-context: context_files/context_file not set in extension config; "
323
+ "nothing to do."
324
+ )
325
+ return 0
326
+
327
+ for context_file in context_files:
328
+ error = _validate_context_file(project_root, context_file)
329
+ if error:
330
+ _err(error)
331
+ return 1
332
+
333
+ marker_start = _get_str(data, "context_markers", "start") or DEFAULT_START
334
+ marker_end = _get_str(data, "context_markers", "end") or DEFAULT_END
335
+
336
+ plan_path = args[0] if args else ""
337
+ if not plan_path:
338
+ plan_path = _resolve_plan_path(project_root)
339
+
340
+ section = _build_section(marker_start, marker_end, plan_path)
341
+
342
+ for context_file in context_files:
343
+ ctx_path = os.path.join(project_root, context_file)
344
+ os.makedirs(os.path.dirname(ctx_path) or ".", exist_ok=True)
345
+ _upsert_section(ctx_path, marker_start, marker_end, section)
346
+ print(f"agent-context: updated {context_file}")
347
+
348
+ return 0
349
+
350
+
351
+ if __name__ == "__main__":
352
+ sys.exit(main())
@@ -4375,6 +4375,40 @@
4375
4375
  "created_at": "2026-04-13T00:00:00Z",
4376
4376
  "updated_at": "2026-04-13T00:00:00Z"
4377
4377
  },
4378
+ "wiki": {
4379
+ "name": "LLM Wiki",
4380
+ "id": "wiki",
4381
+ "description": "LLM-maintained compounding project wiki: source ingestion, cited answers, and consistency linting",
4382
+ "author": "formin",
4383
+ "version": "1.0.0",
4384
+ "download_url": "https://github.com/formin/spec-kit-wiki/archive/refs/tags/v1.0.0.zip",
4385
+ "repository": "https://github.com/formin/spec-kit-wiki",
4386
+ "homepage": "https://github.com/formin/spec-kit-wiki",
4387
+ "documentation": "https://github.com/formin/spec-kit-wiki/blob/main/README.md",
4388
+ "changelog": "https://github.com/formin/spec-kit-wiki/blob/main/CHANGELOG.md",
4389
+ "license": "MIT",
4390
+ "category": "docs",
4391
+ "effect": "read-write",
4392
+ "requires": {
4393
+ "speckit_version": ">=0.2.0"
4394
+ },
4395
+ "provides": {
4396
+ "commands": 5,
4397
+ "hooks": 2
4398
+ },
4399
+ "tags": [
4400
+ "wiki",
4401
+ "knowledge-base",
4402
+ "docs",
4403
+ "memory",
4404
+ "context-management"
4405
+ ],
4406
+ "verified": false,
4407
+ "downloads": 0,
4408
+ "stars": 0,
4409
+ "created_at": "2026-07-06T00:00:00Z",
4410
+ "updated_at": "2026-07-06T00:00:00Z"
4411
+ },
4378
4412
  "wireframe": {
4379
4413
  "name": "Wireframe Visual Feedback Loop",
4380
4414
  "id": "wireframe",
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "specify-cli"
3
- version = "0.12.7"
3
+ version = "0.12.8"
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"
@@ -97,17 +97,26 @@ read_feature_json_feature_directory() {
97
97
  local fj="$repo_root/.specify/feature.json"
98
98
  [[ -f "$fj" ]] || { printf '%s' ''; return 0; }
99
99
 
100
+ # Try parsers in order (jq -> python3 -> grep/sed), falling through on
101
+ # failure. Selection is by *parse success*, not mere availability: on
102
+ # Windows `python3` commonly resolves to the Microsoft Store App Execution
103
+ # Alias stub, which passes `command -v` but fails at runtime (exit 49), so
104
+ # an availability-gated `elif` would pick python3, swallow its failure, and
105
+ # never reach the grep/sed fallback -- leaving feature.json unreadable even
106
+ # though it is valid (issue #3304).
100
107
  local _fd=''
101
108
  if command -v jq >/dev/null 2>&1; then
102
109
  if ! _fd=$(jq -r '.feature_directory // empty' "$fj" 2>/dev/null); then
103
110
  _fd=''
104
111
  fi
105
- elif command -v python3 >/dev/null 2>&1; then
112
+ fi
113
+ if [[ -z "$_fd" ]] && command -v python3 >/dev/null 2>&1; then
106
114
  # Use Python so pretty-printed/multi-line JSON still parses correctly.
107
115
  if ! _fd=$(python3 -c "import json,sys; d=json.load(open(sys.argv[1])); v=d.get('feature_directory'); print(v if v else '')" "$fj" 2>/dev/null); then
108
116
  _fd=''
109
117
  fi
110
- else
118
+ fi
119
+ if [[ -z "$_fd" ]]; then
111
120
  # Last-resort single-line grep/sed fallback. The `|| true` guards against
112
121
  # grep returning 1 (no match) aborting under `set -e` / `pipefail`.
113
122
  _fd=$( { grep -E '"feature_directory"[[:space:]]*:' "$fj" 2>/dev/null || true; } \
@@ -127,7 +127,14 @@ def resolve_github_release_asset_api_url(
127
127
  if hostname == "github.com":
128
128
  api_base = "https://api.github.com"
129
129
  elif is_ghes:
130
- authority = hostname if parsed.port is None else f"{hostname}:{parsed.port}"
130
+ # ``parsed.port`` raises ValueError on a malformed port (e.g.
131
+ # ``host:notaport``); the function's contract is to return None for
132
+ # anything it can't resolve, not to raise.
133
+ try:
134
+ port = parsed.port
135
+ except ValueError:
136
+ return None
137
+ authority = hostname if port is None else f"{hostname}:{port}"
131
138
  api_base = f"{parsed.scheme}://{authority}/api/v3"
132
139
  else:
133
140
  return None
@@ -0,0 +1,60 @@
1
+ """Shared TOML string-escaping helpers.
2
+
3
+ Both TOML command renderers — ``TomlIntegration`` (gemini, tabnine) in
4
+ ``specify_cli.integrations.base`` and ``CommandRegistrar.render_toml_command``
5
+ (extension/preset commands) in ``specify_cli.agents`` — need the same rules for
6
+ detecting characters TOML forbids literally and for emitting a fully-escaped
7
+ basic string. Keeping one implementation here avoids the two drifting apart if
8
+ the escaping rules change again.
9
+ """
10
+ from __future__ import annotations
11
+
12
+
13
+ def has_illegal_toml_control(value: str) -> bool:
14
+ """True when *value* contains a character TOML forbids literally.
15
+
16
+ TOML basic/literal strings (single- or multi-line) allow tab and, in the
17
+ multiline forms, newlines — but every other control character
18
+ (``U+0000``–``U+001F`` and ``U+007F``) must be ``\\u``-escaped, which only a
19
+ basic string can do. A bare carriage return counts too: a multiline basic
20
+ string treats ``\\r`` as a newline only when paired into ``\\r\\n``; a lone
21
+ ``\\r`` is an illegal control character.
22
+ """
23
+ length = len(value)
24
+ for i, ch in enumerate(value):
25
+ code = ord(ch)
26
+ if ch == "\r":
27
+ # Only a CR that is part of a CRLF newline is allowed literally.
28
+ if i + 1 < length and value[i + 1] == "\n":
29
+ continue
30
+ return True
31
+ if (code < 0x20 and ch not in ("\t", "\n")) or code == 0x7F:
32
+ return True
33
+ return False
34
+
35
+
36
+ def escape_toml_basic(value: str) -> str:
37
+ """Render *value* as a single-line basic string, escaping everything.
38
+
39
+ Always valid TOML: backslash/quote are escaped, the common control chars
40
+ use their short escapes, and any remaining control character is emitted as
41
+ a ``\\uXXXX`` sequence.
42
+ """
43
+ out: list[str] = []
44
+ for ch in value:
45
+ code = ord(ch)
46
+ if ch == "\\":
47
+ out.append("\\\\")
48
+ elif ch == '"':
49
+ out.append('\\"')
50
+ elif ch == "\n":
51
+ out.append("\\n")
52
+ elif ch == "\r":
53
+ out.append("\\r")
54
+ elif ch == "\t":
55
+ out.append("\\t")
56
+ elif code < 0x20 or code == 0x7F:
57
+ out.append(f"\\u{code:04x}")
58
+ else:
59
+ out.append(ch)
60
+ return '"' + "".join(out) + '"'
@@ -16,6 +16,8 @@ from typing import Any, Dict, List, Optional
16
16
  import yaml
17
17
 
18
18
  from ._init_options import is_ai_skills_enabled, load_init_options
19
+ from ._toml_string import escape_toml_basic as _escape_toml_basic
20
+ from ._toml_string import has_illegal_toml_control as _has_illegal_toml_control
19
21
  from ._utils import relative_extension_path_violation
20
22
 
21
23
 
@@ -258,7 +260,12 @@ class CommandRegistrar:
258
260
  # ``C:\\Users\\...`` whose ``\\U`` reads as an invalid unicode escape) would
259
261
  # produce unparseable TOML — route those to the *literal* form ('''...'''),
260
262
  # which does not process escapes, or to the escaped basic string.
261
- if '"""' not in body and "\\" not in body:
263
+ # Control characters (U+0000–U+001F except tab/newline, U+007F) and a bare
264
+ # CR are illegal in every TOML string form, so a body containing them must
265
+ # go to the escaped basic string regardless of which delimiters it uses.
266
+ if self._has_illegal_toml_control(body):
267
+ toml_lines.append(f"prompt = {self._render_basic_toml_string(body)}")
268
+ elif '"""' not in body and "\\" not in body:
262
269
  toml_lines.append('prompt = """')
263
270
  toml_lines.append(body)
264
271
  toml_lines.append('"""')
@@ -271,17 +278,11 @@ class CommandRegistrar:
271
278
 
272
279
  return "\n".join(toml_lines)
273
280
 
274
- @staticmethod
275
- def _render_basic_toml_string(value: str) -> str:
276
- """Render *value* as a TOML basic string literal."""
277
- escaped = (
278
- value.replace("\\", "\\\\")
279
- .replace('"', '\\"')
280
- .replace("\n", "\\n")
281
- .replace("\r", "\\r")
282
- .replace("\t", "\\t")
283
- )
284
- return f'"{escaped}"'
281
+ # Control-char detection and basic-string escaping are shared with the
282
+ # gemini/tabnine renderer in ``specify_cli.integrations.base`` via
283
+ # ``specify_cli._toml_string`` so the two never drift apart.
284
+ _has_illegal_toml_control = staticmethod(_has_illegal_toml_control)
285
+ _render_basic_toml_string = staticmethod(_escape_toml_basic)
285
286
 
286
287
  def render_yaml_command(
287
288
  self,
@@ -73,6 +73,13 @@ class _StripAuthOnRedirect(urllib.request.HTTPRedirectHandler):
73
73
  self._redirect_validator = redirect_validator
74
74
 
75
75
  def redirect_request(self, req, fp, code, msg, headers, newurl):
76
+ try:
77
+ new_parsed = urlparse(newurl)
78
+ except ValueError as exc:
79
+ # Malformed redirect target (e.g. unterminated IPv6 bracket).
80
+ # Surface as URLError so callers' download error handling applies.
81
+ raise urllib.error.URLError(f"malformed redirect URL: {exc}") from exc
82
+
76
83
  if self._redirect_validator is not None:
77
84
  self._redirect_validator(req.full_url, newurl)
78
85
 
@@ -83,7 +90,6 @@ class _StripAuthOnRedirect(urllib.request.HTTPRedirectHandler):
83
90
  new_req = super().redirect_request(req, fp, code, msg, headers, newurl)
84
91
  if new_req is not None:
85
92
  old_scheme = urlparse(req.full_url).scheme
86
- new_parsed = urlparse(newurl)
87
93
  hostname = (new_parsed.hostname or "").lower()
88
94
  is_https_downgrade = old_scheme == "https" and new_parsed.scheme != "https"
89
95
  if _hostname_in_hosts(hostname, self._hosts) and not is_https_downgrade:
@@ -426,7 +426,11 @@ def extension_add(
426
426
  if from_url and not dev:
427
427
  from urllib.parse import urlparse
428
428
 
429
- parsed = urlparse(from_url)
429
+ try:
430
+ parsed = urlparse(from_url)
431
+ except ValueError:
432
+ console.print(f"[red]Error:[/red] Invalid URL: {_escape_markup(from_url)}")
433
+ raise typer.Exit(1)
430
434
  is_localhost = parsed.hostname in ("localhost", "127.0.0.1", "::1")
431
435
 
432
436
  if parsed.scheme != "https" and not (parsed.scheme == "http" and is_localhost):