specify-cli 1.1.2__tar.gz → 1.1.3__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.
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.gitattributes +2 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/ISSUE_TEMPLATE/workflow_step_submission.yml +23 -9
- specify_cli-1.1.3/.github/scripts/validate_community_workflow_step.py +550 -0
- specify_cli-1.1.3/.github/skills/code-review/SKILL.md +14 -0
- specify_cli-1.1.3/.github/workflows/add-community-workflow-step.lock.yml +2033 -0
- specify_cli-1.1.3/.github/workflows/add-community-workflow-step.md +478 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/catalog-assign.yml +4 -2
- {specify_cli-1.1.2 → specify_cli-1.1.3}/CHANGELOG.md +25 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/CONTRIBUTING.md +46 -5
- {specify_cli-1.1.2 → specify_cli-1.1.3}/PKG-INFO +1 -1
- {specify_cli-1.1.2 → specify_cli-1.1.3}/bundles/bugfix/bundle.yml +2 -2
- {specify_cli-1.1.2 → specify_cli-1.1.3}/bundles/catalog.json +1 -1
- specify_cli-1.1.3/design/integration.md +420 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/design/workflow-step.md +24 -3
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/community/extensions.md +3 -1
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/community/overview.md +3 -2
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/community/presets.md +2 -1
- specify_cli-1.1.3/docs/community/workflow-steps.md +190 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/guides/agentic-sdlc.md +2 -1
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/installation.md +3 -2
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/reference/agentic-bugfix.md +4 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/reference/agentic-sdd.md +17 -6
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/reference/bundles.md +16 -8
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/reference/extensions.md +1 -1
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/reference/integrations.md +131 -10
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/reference/workflows.md +195 -3
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/EXTENSION-API-REFERENCE.md +11 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/EXTENSION-DEVELOPMENT-GUIDE.md +3 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/EXTENSION-USER-GUIDE.md +3 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/bug/README.md +23 -1
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/bug/commands/speckit.bug.assess.md +85 -5
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/bug/commands/speckit.bug.fix.md +80 -4
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/bug/commands/speckit.bug.test.md +80 -4
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/bug/extension.yml +1 -1
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/catalog.community.json +117 -13
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/catalog.json +2 -2
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/github/README.md +54 -9
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/github/extension.yml +1 -1
- specify_cli-1.1.3/integrations/CONTRIBUTING.md +191 -0
- specify_cli-1.1.3/integrations/README.md +174 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/catalog.community.json +47 -17
- {specify_cli-1.1.2 → specify_cli-1.1.3}/pyproject.toml +1 -1
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/__init__.py +16 -6
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/_init_options.py +4 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/agents.py +43 -17
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/artifacts/_commands.py +12 -1
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/artifacts/_mcp.py +14 -8
- specify_cli-1.1.3/src/specify_cli/artifacts/_operation_info.py +537 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/artifacts/command_info.py +39 -14
- specify_cli-1.1.3/src/specify_cli/artifacts/mcp_info.py +374 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/artifacts/models.py +3 -1
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/artifacts/resolution.py +10 -2
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/_commands.py +1 -1
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/adapters.py +25 -1
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/command_list.py +1 -1
- specify_cli-1.1.3/src/specify_cli/bundles/component_catalog.py +154 -0
- specify_cli-1.1.3/src/specify_cli/bundles/conflict.py +65 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/installer.py +115 -42
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/manifest.py +10 -2
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/primitives.py +115 -51
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/records.py +68 -11
- specify_cli-1.1.3/src/specify_cli/bundles/references.py +276 -0
- specify_cli-1.1.3/src/specify_cli/command_check.py +108 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/command_init.py +33 -6
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/events/__init__.py +48 -31
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/extensions/__init__.py +110 -61
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integration_state.py +4 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integration_status.py +17 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/__init__.py +56 -10
- specify_cli-1.1.3/src/specify_cli/integrations/_file_changes.py +47 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/_helpers.py +4 -0
- specify_cli-1.1.3/src/specify_cli/integrations/_lifecycle.py +598 -0
- specify_cli-1.1.3/src/specify_cli/integrations/_registration.py +24 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/base.py +23 -3
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/cline/__init__.py +3 -1
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/command_info.py +29 -8
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/command_install.py +24 -20
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/command_list.py +9 -7
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/command_search.py +1 -7
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/command_status.py +1 -1
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/command_switch.py +59 -55
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/command_uninstall.py +4 -1
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/command_upgrade.py +6 -1
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/command_use.py +3 -1
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/copilot/__init__.py +12 -4
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/hermes/__init__.py +21 -6
- specify_cli-1.1.3/src/specify_cli/integrations/installer.py +1039 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/junie/__init__.py +3 -1
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/kimi/__init__.py +25 -11
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/manifest.py +113 -43
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/_manager.py +24 -14
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/_manager_commands.py +9 -17
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/_manager_skills.py +20 -14
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/_registry.py +4 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/shared_infra.py +13 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/__init__.py +2 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/_commands.py +73 -14
- specify_cli-1.1.3/src/specify_cli/workflows/_execution.py +964 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/catalog/_domain.py +4 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/command_add.py +48 -23
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/command_resume.py +31 -8
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/command_run.py +17 -4
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/command_status.py +9 -0
- specify_cli-1.1.3/src/specify_cli/workflows/composition.py +176 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/engine.py +138 -483
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/command/__init__.py +2 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/command_add.py +26 -10
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/fan_in/__init__.py +19 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/fan_out/__init__.py +5 -7
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/gate/__init__.py +7 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/prompt/__init__.py +2 -0
- specify_cli-1.1.3/src/specify_cli/workflows/step/workflow/__init__.py +17 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/templates/commands/taskstoissues.md +9 -1
- specify_cli-1.1.3/tests/extensions/bug/test_bug_hooks.py +128 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/extensions/github/test_github_extension.py +13 -6
- specify_cli-1.1.3/tests/extensions/github/test_taskstoissues_deprecation.py +99 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_kimi.py +28 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_manifest.py +141 -0
- specify_cli-1.1.3/tests/specify_cli/artifacts/test_command_info.py +333 -0
- specify_cli-1.1.3/tests/specify_cli/artifacts/test_mcp_info.py +1235 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/artifacts/test_mcp_list.py +35 -6
- specify_cli-1.1.3/tests/specify_cli/artifacts/test_operation_info.py +690 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/helpers.py +8 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_command_info.py +23 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_command_install.py +5 -2
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_command_list.py +35 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_command_validate.py +79 -3
- specify_cli-1.1.3/tests/specify_cli/bundles/test_conflict.py +110 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_installer.py +394 -3
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_primitives.py +360 -39
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_records.py +84 -0
- specify_cli-1.1.3/tests/specify_cli/bundles/test_references.py +1428 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_validator.py +14 -1
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/test_catalog.py +3 -2
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/test_command_search.py +3 -2
- specify_cli-1.1.3/tests/specify_cli/integrations/test_installed_adapters.py +4639 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/test_lifecycle.py +23 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/mcp_server/test_server.py +8 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/mcp_server/test_stdio.py +17 -5
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/step/test_command_add.py +44 -1
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/test_catalog_versions.py +84 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/test_command_resume.py +25 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/test_command_status.py +195 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_github_workflows.py +48 -31
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_shared_infra_gitignore.py +8 -0
- specify_cli-1.1.3/tests/test_workflow_step_submission.py +1186 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_workflows.py +248 -91
- specify_cli-1.1.3/tests/workflows/test_composition_execution.py +3599 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/workflows/ARCHITECTURE.md +81 -7
- {specify_cli-1.1.2 → specify_cli-1.1.3}/workflows/PUBLISHING.md +1 -1
- {specify_cli-1.1.2 → specify_cli-1.1.3}/workflows/README.md +14 -2
- specify_cli-1.1.3/workflows/step-catalog.community.json +41 -0
- specify_cli-1.1.2/.github/skills/code-review/SKILL.md +0 -11
- specify_cli-1.1.2/design/integration.md +0 -110
- specify_cli-1.1.2/docs/community/workflow-steps.md +0 -129
- specify_cli-1.1.2/integrations/CONTRIBUTING.md +0 -142
- specify_cli-1.1.2/integrations/README.md +0 -129
- specify_cli-1.1.2/src/specify_cli/bundles/conflict.py +0 -54
- specify_cli-1.1.2/src/specify_cli/bundles/references.py +0 -127
- specify_cli-1.1.2/src/specify_cli/command_check.py +0 -55
- specify_cli-1.1.2/tests/specify_cli/artifacts/test_command_info.py +0 -152
- specify_cli-1.1.2/tests/specify_cli/bundles/test_conflict.py +0 -54
- specify_cli-1.1.2/tests/specify_cli/bundles/test_references.py +0 -112
- specify_cli-1.1.2/workflows/step-catalog.community.json +0 -6
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.devcontainer/devcontainer.json +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.devcontainer/post-create.sh +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.editorconfig +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/CODEOWNERS +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/ISSUE_TEMPLATE/agent_request.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/ISSUE_TEMPLATE/bundle_submission.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/ISSUE_TEMPLATE/extension_submission.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/ISSUE_TEMPLATE/preset_submission.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/aw/actions-lock.json +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/dependabot.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/scripts/check_extension_version_bump.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/scripts/check_security_requirements.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/scripts/validate_community_preset.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/security-audit-requirements.txt +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/skills/add-community-extension/SKILL.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/RELEASE-PROCESS.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/add-community-bundle.lock.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/add-community-bundle.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/add-community-extension.lock.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/add-community-extension.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/add-community-preset.lock.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/add-community-preset.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/bug-assess.lock.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/bug-assess.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/bug-fix.lock.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/bug-fix.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/bug-test.lock.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/bug-test.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/codeql.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/docs.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/extension-version-guard.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/feature-assess.lock.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/feature-assess.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/lint.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/publish-pypi.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/release-trigger.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/release.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/security.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/stale.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.github/workflows/test.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.gitignore +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.markdownlint-cli2.jsonc +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.pre-commit-config.yaml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/.zenodo.json +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/AGENTS.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/CITATION.cff +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/CODE_OF_CONDUCT.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/DEVELOPMENT.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/LICENSE +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/README.ja.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/README.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/README.zh-CN.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/SECURITY.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/SUPPORT.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/bundles/assess/README.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/bundles/assess/bundle.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/bundles/bugfix/README.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/bundles/catalog.community.json +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/design/cli.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/design/mcp.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/design/shared.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/.gitignore +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/README.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/community/bundles.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/community/friends.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/community/walkthroughs.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/concepts/complex-features.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/concepts/sdd.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/concepts/spec-of-specs.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/concepts/spec-persistence.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/docfx.json +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/guides/assessment.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/guides/bugfix.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/guides/contract-driven-development.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/guides/customization.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/guides/evolving-specs.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/guides/existing-projects.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/guides/monorepo.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/history.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/images/spec-kit-logo.webp +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/index.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/install/air-gapped.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/install/one-time.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/install/pipx.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/install/pypi.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/install/uv.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/local-development.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/quickstart.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/reference/agentic-assessment.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/reference/artifacts.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/reference/authentication.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/reference/core.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/reference/mcp.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/reference/overview.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/reference/presets.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/template/public/main.css +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/toc.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/docs/upgrade.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/examples/bundles/business-analyst/README.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/examples/bundles/business-analyst/bundle.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/examples/bundles/developer/README.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/examples/bundles/developer/bundle.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/examples/bundles/product-manager/README.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/examples/bundles/product-manager/bundle.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/examples/bundles/security-researcher/README.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/examples/bundles/security-researcher/bundle.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/EXTENSION-PUBLISHING-GUIDE.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/README.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/RFC-EXTENSION-SYSTEM.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/agent-context/README.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/agent-context/agent-context-config.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/agent-context/agent-context-defaults.json +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/agent-context/commands/speckit.agent-context.update.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/agent-context/extension.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/agent-context/scripts/bash/update-agent-context.sh +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/agent-context/scripts/powershell/update-agent-context.ps1 +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/agent-context/scripts/python/update_agent_context.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/assess/README.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/assess/commands/speckit.assess.decide.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/assess/commands/speckit.assess.define.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/assess/commands/speckit.assess.intake.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/assess/commands/speckit.assess.research.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/assess/commands/speckit.assess.shape.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/assess/extension.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/README.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/commands/speckit.git.commit.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/commands/speckit.git.feature.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/commands/speckit.git.initialize.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/commands/speckit.git.remote.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/commands/speckit.git.validate.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/config-template.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/extension.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/git-config.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/scripts/bash/auto-commit.sh +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/scripts/bash/create-new-feature-branch.sh +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/scripts/bash/git-common.sh +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/scripts/bash/initialize-repo.sh +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/scripts/powershell/auto-commit.ps1 +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/scripts/powershell/create-new-feature-branch.ps1 +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/scripts/powershell/git-common.ps1 +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/scripts/powershell/initialize-repo.ps1 +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/scripts/python/auto_commit.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/scripts/python/create_new_feature_branch.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/scripts/python/git_common.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/git/scripts/python/initialize_repo.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/github/commands/speckit.github.taskstoissues.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/github/scripts/bash/resolve-tasks.sh +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/github/scripts/powershell/resolve-tasks.ps1 +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/github/scripts/python/resolve_tasks.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/selftest/commands/selftest.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/selftest/extension.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/template/.gitignore +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/template/CHANGELOG.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/template/EXAMPLE-README.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/template/LICENSE +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/template/README.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/template/commands/example.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/template/config-template.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/extensions/template/extension.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/integrations/catalog.community.json +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/integrations/catalog.json +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/media/bootstrap-claude-code.gif +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/media/logo_large.webp +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/media/logo_small.webp +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/media/spec-kit-video-header.jpg +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/media/specify_cli.gif +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/newsletters/2026-April.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/newsletters/2026-August.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/newsletters/2026-February.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/newsletters/2026-July.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/newsletters/2026-June.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/newsletters/2026-March.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/newsletters/2026-May.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/newsletters/2026-September.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/ARCHITECTURE.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/PUBLISHING.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/README.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/catalog.json +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/constitution-sync/README.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/constitution-sync/commands/speckit.constitution.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/constitution-sync/preset.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/lean/README.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/lean/commands/speckit.constitution.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/lean/commands/speckit.implement.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/lean/commands/speckit.plan.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/lean/commands/speckit.specify.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/lean/commands/speckit.tasks.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/lean/preset.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/scaffold/README.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/scaffold/commands/speckit.myext.myextcmd.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/scaffold/commands/speckit.specify.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/scaffold/preset.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/scaffold/templates/myext-template.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/scaffold/templates/spec-template.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/self-test/commands/speckit.specify.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/self-test/commands/speckit.wrap-test.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/self-test/preset.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/self-test/templates/checklist-template.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/self-test/templates/constitution-template.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/self-test/templates/plan-template.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/self-test/templates/spec-template.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/presets/self-test/templates/tasks-template.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/scripts/bash/check-prerequisites.sh +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/scripts/bash/common.sh +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/scripts/bash/create-new-feature.sh +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/scripts/bash/resolve-template.sh +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/scripts/bash/setup-plan.sh +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/scripts/bash/setup-tasks.sh +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/scripts/powershell/check-prerequisites.ps1 +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/scripts/powershell/common.ps1 +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/scripts/powershell/create-new-feature.ps1 +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/scripts/powershell/resolve-template.ps1 +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/scripts/powershell/setup-plan.ps1 +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/scripts/powershell/setup-tasks.ps1 +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/scripts/python/check_prerequisites.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/scripts/python/common.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/scripts/python/create_new_feature.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/scripts/python/resolve_template.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/scripts/python/setup_plan.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/scripts/python/setup_tasks.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/spec-driven.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/spec-kit.code-workspace +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/_agent_config.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/_assets.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/_console.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/_download_security.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/_installed_info_json.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/_installed_list_json.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/_invocation_style.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/_operation_version.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/_project.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/_toml_string.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/_utils.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/_version.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/artifacts/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/artifacts/_identifiers.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/artifacts/_operation_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/artifacts/catalog.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/artifacts/command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/artifacts/command_lookup.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/artifacts/mcp_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/authentication/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/authentication/azure_devops.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/authentication/base.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/authentication/bitbucket.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/authentication/config.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/authentication/github.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/authentication/github_http.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/authentication/http.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundler.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/catalog/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/catalog/command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/catalog/command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/catalog/command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/catalog_config.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/catalog_stack.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/catalog_versions.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/catalogs.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/command_build.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/command_info.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/command_init.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/command_install.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/command_search.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/command_update.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/command_validate.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/packager.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/project.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/resolver.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/sources.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/validator.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/versioning.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/bundles/yamlio.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/catalogs.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/command_mcp.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/command_version.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/events/command_run.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/extensions/_catalog_versions.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/extensions/_command_update_artifacts.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/extensions/_command_update_discovery.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/extensions/_command_update_transaction.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/extensions/_commands.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/extensions/catalog/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/extensions/catalog/_helpers.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/extensions/catalog/command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/extensions/catalog/command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/extensions/catalog/command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/extensions/command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/extensions/command_disable.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/extensions/command_enable.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/extensions/command_info.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/extensions/command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/extensions/command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/extensions/command_search.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/extensions/command_set_priority.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/extensions/command_update.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integration_runtime.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/_catalog_versions.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/_command_scaffold_generation.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/_command_upgrade_layout.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/_commands.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/agy/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/alquimia/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/amp/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/auggie/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/bob/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/catalog/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/catalog/command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/catalog/command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/catalog/command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/claude/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/codebuddy/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/codex/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/command_code/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/command_scaffold.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/cursor_agent/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/devin/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/docker_agent/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/droid/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/dsh/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/firebender/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/forge/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/gemini/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/generic/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/goose/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/grok/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/kilocode/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/kiro_cli/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/lingma/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/mcode/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/muse/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/omp/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/opencode/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/pi/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/qodercli/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/qwen/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/rovodev/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/shai/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/tabnine/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/trae/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/vibe/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/zcode/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/integrations/zed/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/mcp_server/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/mcp_server/_worker.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/mcp_server/catalog.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/mcp_server/executor.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/mcp_server/server.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/mcp_version.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/_catalog.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/_catalog_versions.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/_commands.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/_manifest.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/_resolver.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/catalog/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/catalog/command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/catalog/command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/catalog/command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/command_disable.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/command_enable.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/command_info.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/command_resolve.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/command_search.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/command_set_priority.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/presets/command_update.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/selfs/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/selfs/command_check.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/selfs/command_upgrade.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/_command_resume_state.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/_command_run_ownership.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/base.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/catalog/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/catalog/_versions.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/catalog/command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/catalog/command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/catalog/command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/command_disable.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/command_enable.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/command_info.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/command_resolve.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/command_search.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/command_update.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/expressions.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/overlay/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/overlay/command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/overlay/command_disable.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/overlay/command_enable.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/overlay/command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/overlay/command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/overlay/command_set_priority.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/overlay/composer.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/overlay/layer_sources.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/overlay/merge.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/overlay/operations.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/overlay/resolver.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/overlay/schema.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/_helpers.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/catalog/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/catalog/_domain.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/catalog/_versions.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/catalog/command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/catalog/command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/catalog/command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/command_info.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/command_search.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/do_while/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/if_then/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/init/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/installer.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/shell/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/slot/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/switch/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/src/specify_cli/workflows/step/while_loop/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/templates/checklist-template.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/templates/commands/analyze.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/templates/commands/checklist.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/templates/commands/clarify.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/templates/commands/constitution.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/templates/commands/converge.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/templates/commands/implement.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/templates/commands/plan.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/templates/commands/specify.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/templates/commands/tasks.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/templates/constitution-template.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/templates/plan-template.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/templates/spec-template.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/templates/tasks-template.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/templates/vscode-settings.json +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/conftest.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/contract/test_bundled_extension_update_delivery.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/contract/test_bundled_extension_versions.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/contract/test_catalog_schema.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/contract/test_extension_version_guard_script.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/contract/test_firstparty_bundle_catalog_consistency.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/contract/test_manifest_schema.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/contract/test_wheel_bundled_presets.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/contract/test_wheel_bundled_workflows.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/contract/test_wheel_core_pack_scripts.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/extensions/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/extensions/assess/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/extensions/assess/test_assess_extension.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/extensions/bug/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/extensions/bug/test_bug_extension.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/extensions/git/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/extensions/git/test_git_extension.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/extensions/git/test_git_extension_python_parity.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/extensions/github/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/extensions/test_agent_context_cli_free.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/extensions/test_extension_agent_context.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/extensions/test_update_agent_context_feature_json.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/extensions/test_update_agent_context_python_parity.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/hooks/TESTING.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/hooks/plan.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/hooks/spec.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/hooks/tasks.md +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/http_helpers.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integration/test_preset_update_workflow.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/conftest.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_base.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_cli.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_extra_args.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_home_isolation.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_agy.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_alquimia.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_amp.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_auggie.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_base_markdown.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_base_skills.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_base_toml.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_base_yaml.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_bob.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_claude.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_cline.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_codebuddy.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_codex.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_command_code.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_copilot.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_cursor_agent.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_devin.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_docker_agent.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_droid.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_dsh.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_firebender.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_forge.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_gemini.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_generic.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_goose.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_grok.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_hermes.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_junie.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_kilocode.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_kiro_cli.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_lingma.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_mcode.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_muse.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_omp.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_opencode.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_pi.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_qodercli.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_qwen.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_rovodev.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_shai.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_state.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_tabnine.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_trae.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_vibe.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_zcode.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_integration_zed.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_registry.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/integrations/test_skill_frontmatter_quoting.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/lock_helpers.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/parity_helpers.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/artifacts/conftest.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/artifacts/helpers.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/artifacts/test_catalog.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/artifacts/test_catalog_parity.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/artifacts/test_command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/artifacts/test_command_lookup.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/artifacts/test_operation_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/artifacts/test_registration.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/authentication/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/authentication/helpers.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/authentication/test_authentication.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/authentication/test_github_http.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/_command_helpers.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/catalog/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/catalog/test_command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/catalog/test_command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/catalog/test_command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/conftest.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_adapters.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_bundles.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_catalog_config.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_catalog_stack.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_catalog_versions.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_command_build.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_command_init.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_command_install_version.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_command_search.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_command_update.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_commands.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_offline.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_packager.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_resolver.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_security_paths.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_sources.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_versioning.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/bundles/test_yamlio.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/events/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/events/test_command_run.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/events/test_events.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/_helpers.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/catalog/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/catalog/test_command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/catalog/test_command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/catalog/test_command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/conftest.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/test_catalog_versions.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/test_command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/test_command_add_path_traversal.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/test_command_disable.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/test_command_enable.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/test_command_info.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/test_command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/test_command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/test_command_search.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/test_command_set_priority.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/test_command_update.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/test_command_update_artifacts.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/test_command_update_discovery.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/extensions/test_command_update_transaction.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/_catalog_helpers.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/_helpers.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/_scaffold_helpers.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/catalog/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/catalog/test_command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/catalog/test_command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/catalog/test_command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/conftest.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/test_catalog_versions.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/test_command_info.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/test_command_install.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/test_command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/test_command_scaffold.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/test_command_scaffold_generation.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/test_command_status.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/test_command_switch.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/test_command_uninstall.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/test_command_upgrade.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/test_command_upgrade_layout.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/test_command_use.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/integrations/test_registration.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/mcp_server/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/mcp_server/test_catalog.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/mcp_server/test_executor.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/_fixtures.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/_helpers.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/catalog/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/catalog/test_command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/catalog/test_command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/catalog/test_command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/conftest.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/test_catalog.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/test_catalog_versions.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/test_command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/test_command_disable.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/test_command_enable.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/test_command_info.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/test_command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/test_command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/test_command_resolve.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/test_command_search.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/test_command_set_priority.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/test_command_update.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/test_domain_exports.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/test_manager.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/test_manager_commands.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/test_manager_skills.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/test_manifest.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/test_registration.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/test_registry.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/presets/test_resolver.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/self_upgrade_helpers.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/selfs/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/selfs/test_command_check.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/selfs/test_command_upgrade.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/test_agent_config.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/test_check_tool.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/test_command_check.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/test_command_init.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/test_command_mcp.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/test_command_version.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/test_mcp_version.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/test_operation_version.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/test_root_version_callback.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/test_version_detection.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/test_version_execution.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/test_version_guidance.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/test_version_imports.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/test_version_release.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/test_version_verification.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/catalog/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/catalog/test_command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/catalog/test_command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/catalog/test_command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/conftest.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/helpers.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/overlay/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/overlay/test_command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/overlay/test_command_disable.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/overlay/test_command_enable.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/overlay/test_command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/overlay/test_command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/overlay/test_command_set_priority.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/step/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/step/catalog/__init__.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/step/catalog/test_command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/step/catalog/test_command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/step/catalog/test_command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/step/catalog/test_registry.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/step/test_catalog_versions.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/step/test_command_info.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/step/test_command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/step/test_command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/step/test_command_search.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/step/test_installer.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/test_command_add.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/test_command_disable.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/test_command_enable.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/test_command_info.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/test_command_list.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/test_command_remove.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/test_command_resolve.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/test_command_resume_state.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/test_command_run.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/test_command_run_ownership.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/test_command_search.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/test_command_update.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/specify_cli/workflows/test_custom_steps.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_agent_config_consistency.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_branch_numbering.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_bug_fix_workflow.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_catalog_trust_docs.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_check_prerequisites_paths_only.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_check_prerequisites_python_parity.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_clarify_stage_gate.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_command_template_hooks.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_command_template_py_scripts.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_community_preset_validation.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_console_imports.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_constitution_template_sync_report.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_converge_template_scaffold.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_create_new_feature_python_parity.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_download_security.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_extension_registration.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_extension_skills.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_extensions.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_init_dir.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_init_dir_cli.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_installed_info_json.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_installed_list_json.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_live_transient_windows.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_merge.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_post_process.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_presets.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_ps1_encoding.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_registrar_path_traversal.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_resolve_template_python_parity.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_security_workflow.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_setup_plan_feature_json.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_setup_plan_no_overwrite.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_setup_plan_python_parity.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_setup_tasks.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_setup_tasks_python_parity.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_shared_infra_integrity.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_shared_infra_lock.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_skill_placeholder_py.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_specify_no_persist.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_specify_template_numbering.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_tasks_template_constraints.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_timestamp_branches.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_utils.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/test_utils_assets_imports.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/unit/test_condition_expression_block.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/workflows/conftest.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/workflows/test_bundled_bugfix_assess_workflows.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/workflows/test_bundled_speckit_workflow.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/workflows/test_overlay_composer.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/workflows/test_overlay_layer_sources.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/workflows/test_overlay_merge.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/workflows/test_overlay_schema.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/workflows/test_resolver_integration.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/tests/workflows/test_slot_step.py +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/workflows/assess/workflow.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/workflows/bugfix/workflow.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/workflows/catalog.community.json +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/workflows/catalog.json +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/workflows/speckit/workflow.yml +0 -0
- {specify_cli-1.1.2 → specify_cli-1.1.3}/workflows/step-catalog.json +0 -0
|
@@ -6,7 +6,7 @@ body:
|
|
|
6
6
|
- type: markdown
|
|
7
7
|
attributes:
|
|
8
8
|
value: |
|
|
9
|
-
Thanks for contributing a workflow step type! This form captures the package, release, and catalog metadata needed for
|
|
9
|
+
Thanks for contributing a workflow step type! This form captures the package, release, and catalog metadata needed for community catalog review.
|
|
10
10
|
|
|
11
11
|
**Before submitting:**
|
|
12
12
|
- Review the [Community Workflow Step Types guide](https://github.com/github/spec-kit/blob/main/docs/community/workflow-steps.md)
|
|
@@ -16,13 +16,13 @@ body:
|
|
|
16
16
|
- Provide version-pinned URLs and SHA-256 digests for every catalog-downloaded file
|
|
17
17
|
- Test the release artifact with `specify workflow step add <step-id> --from <download-url>`
|
|
18
18
|
|
|
19
|
-
**After submitting:** GitHub automatically applies only the `triage-must-have` intake verdict.
|
|
19
|
+
**After submitting:** GitHub automatically applies only the `triage-must-have` intake verdict. A maintainer applies `workflow-step-submission` during triage to start automated metadata validation. Opening the form alone does not start validation. Successful validation proposes a draft catalog pull request for maintainer review; submitted Python is never reviewed or executed by this automation.
|
|
20
20
|
|
|
21
21
|
- type: input
|
|
22
22
|
id: step-id
|
|
23
23
|
attributes:
|
|
24
24
|
label: Step Type ID
|
|
25
|
-
description: Exact catalog key and `step.type_key`;
|
|
25
|
+
description: Exact catalog key and `step.type_key`; use lowercase letters, digits, and hyphens in one safe path component, avoiding built-in types and Windows device names such as con, aux, com1, and lpt1
|
|
26
26
|
placeholder: "e.g., deploy"
|
|
27
27
|
validations:
|
|
28
28
|
required: true
|
|
@@ -76,7 +76,11 @@ body:
|
|
|
76
76
|
id: download-url
|
|
77
77
|
attributes:
|
|
78
78
|
label: Download URL
|
|
79
|
-
description:
|
|
79
|
+
description: >-
|
|
80
|
+
URL to the versioned step package archive; GitHub-generated tag archives support `.zip` and `.tar.gz`,
|
|
81
|
+
while named release assets may also use `.tgz`. The URL path must match `^[A-Za-z0-9._~+!/-]+$`;
|
|
82
|
+
percent escapes, spaces, query strings, fragments, and dot/traversal segments are rejected.
|
|
83
|
+
Tags have no slashes; `+` and `!` support PEP 440 local versions and epochs.
|
|
80
84
|
placeholder: "https://github.com/your-org/spec-kit-step-deploy/releases/download/v1.0.0/deploy-1.0.0.zip"
|
|
81
85
|
validations:
|
|
82
86
|
required: true
|
|
@@ -85,7 +89,10 @@ body:
|
|
|
85
89
|
id: step-yml-url
|
|
86
90
|
attributes:
|
|
87
91
|
label: step.yml URL
|
|
88
|
-
description:
|
|
92
|
+
description: >-
|
|
93
|
+
Exact tag-pinned raw GitHub HTTPS URL used as the catalog `step_yml_url` (or `url`).
|
|
94
|
+
The file path within the tag must match `^[A-Za-z0-9._~/-]+$`, without percent escapes or spaces;
|
|
95
|
+
tags may additionally contain `+` and `!`.
|
|
89
96
|
placeholder: "https://raw.githubusercontent.com/your-org/spec-kit-step-deploy/v1.0.0/step.yml"
|
|
90
97
|
validations:
|
|
91
98
|
required: true
|
|
@@ -94,7 +101,10 @@ body:
|
|
|
94
101
|
id: init-url
|
|
95
102
|
attributes:
|
|
96
103
|
label: __init__.py URL
|
|
97
|
-
description:
|
|
104
|
+
description: >-
|
|
105
|
+
Exact tag-pinned raw GitHub HTTPS URL used as the catalog `init_url`.
|
|
106
|
+
The file path within the tag must match `^[A-Za-z0-9._~/-]+$`, without percent escapes or spaces;
|
|
107
|
+
tags may additionally contain `+` and `!`.
|
|
98
108
|
placeholder: "https://raw.githubusercontent.com/your-org/spec-kit-step-deploy/v1.0.0/__init__.py"
|
|
99
109
|
validations:
|
|
100
110
|
required: true
|
|
@@ -104,9 +114,13 @@ body:
|
|
|
104
114
|
attributes:
|
|
105
115
|
label: Extra File URLs
|
|
106
116
|
description: >-
|
|
107
|
-
JSON mapping of every additional package-relative file path to its exact tag-pinned HTTPS URL.
|
|
117
|
+
JSON mapping of every additional package-relative file path to its exact tag-pinned raw GitHub HTTPS URL.
|
|
118
|
+
Package-relative keys and file paths within the tag must match `^[A-Za-z0-9._~/-]+$`;
|
|
119
|
+
percent escapes, spaces, query strings, and fragments are rejected. Tags may additionally contain `+` and `!`.
|
|
108
120
|
Paths must use forward slashes, be relative and non-empty, contain no empty, `.` or `..` segments,
|
|
109
|
-
and must not case-insensitively alias `step.yml` or `__init__.py
|
|
121
|
+
and must not case-insensitively alias `step.yml` or `__init__.py`, another file, or a package directory.
|
|
122
|
+
Case-insensitive aliases of `.git`, `__pycache__`, and `.DS_Store` are forbidden.
|
|
123
|
+
Enter `{}` when there are no extra files.
|
|
110
124
|
render: json
|
|
111
125
|
placeholder: |
|
|
112
126
|
{
|
|
@@ -183,7 +197,7 @@ body:
|
|
|
183
197
|
id: documentation
|
|
184
198
|
attributes:
|
|
185
199
|
label: Documentation URL
|
|
186
|
-
description: Tag-pinned documentation covering configuration, outputs, failure behavior, side effects, and an example workflow
|
|
200
|
+
description: Tag-pinned Markdown documentation (`.md`) covering configuration, outputs, failure behavior, side effects, and an example workflow; README.md is not required
|
|
187
201
|
placeholder: "https://github.com/your-org/spec-kit-step-deploy/blob/v1.0.0/README.md"
|
|
188
202
|
validations:
|
|
189
203
|
required: true
|
|
@@ -0,0 +1,550 @@
|
|
|
1
|
+
"""Validate submission identity and fetch a pinned step package without a shell.
|
|
2
|
+
|
|
3
|
+
Exit 1: submission defect; exit 2: environment blocker. Never imports submitted
|
|
4
|
+
code. Only the repository-owned installer is loaded to reuse its ID validator.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
import copy
|
|
9
|
+
import hashlib
|
|
10
|
+
import importlib.util
|
|
11
|
+
import json
|
|
12
|
+
import re
|
|
13
|
+
import subprocess
|
|
14
|
+
import tempfile
|
|
15
|
+
from functools import cache
|
|
16
|
+
from datetime import datetime, timezone
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from types import ModuleType
|
|
19
|
+
from typing import Any
|
|
20
|
+
from urllib.parse import urlsplit
|
|
21
|
+
|
|
22
|
+
ROOT = Path(__file__).resolve().parents[2]
|
|
23
|
+
MAX_FILE_BYTES = 10 * 1024 * 1024
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class SubmissionMismatch(Exception):
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Blocked(Exception):
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class GeneratedError(Exception):
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class DuplicateField(ValueError):
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def unique_json_fields(pairs: list[tuple[str, Any]]) -> dict[str, Any]:
|
|
43
|
+
result = {}
|
|
44
|
+
for key, value in pairs:
|
|
45
|
+
if key in result:
|
|
46
|
+
raise DuplicateField(f"Duplicate field '{key}' in JSON evidence")
|
|
47
|
+
result[key] = value
|
|
48
|
+
return result
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def field(data: dict[str, Any], key: str) -> str:
|
|
52
|
+
value = data.get(key)
|
|
53
|
+
if not isinstance(value, str) or not value:
|
|
54
|
+
raise SubmissionMismatch(f"missing or invalid {key}")
|
|
55
|
+
return value
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@cache
|
|
59
|
+
def load_installer() -> ModuleType:
|
|
60
|
+
path = ROOT / "src/specify_cli/workflows/step/installer.py"
|
|
61
|
+
spec = importlib.util.spec_from_file_location("community_step_installer", path)
|
|
62
|
+
if spec is None or spec.loader is None:
|
|
63
|
+
raise Blocked(f"cannot load repository-owned step validator at {path}")
|
|
64
|
+
installer = importlib.util.module_from_spec(spec)
|
|
65
|
+
try:
|
|
66
|
+
spec.loader.exec_module(installer)
|
|
67
|
+
except (ImportError, OSError) as exc:
|
|
68
|
+
raise Blocked(f"cannot load repository-owned step validator: {exc}") from exc
|
|
69
|
+
return installer
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def validate_identity(data: dict[str, Any]) -> tuple[str, str, str]:
|
|
73
|
+
step_id = field(data, "step_id")
|
|
74
|
+
if not re.fullmatch(r"[a-z][a-z0-9-]*", step_id):
|
|
75
|
+
raise SubmissionMismatch("Step ID must use lowercase letters, digits, and hyphens")
|
|
76
|
+
installer = load_installer()
|
|
77
|
+
try:
|
|
78
|
+
installer.validate_step_id(step_id)
|
|
79
|
+
except installer.StepInstallError as exc:
|
|
80
|
+
raise SubmissionMismatch(str(exc)) from exc
|
|
81
|
+
|
|
82
|
+
repository = field(data, "repository")
|
|
83
|
+
match = re.fullmatch(
|
|
84
|
+
r"https://github\.com/([A-Za-z0-9_-]+)/([A-Za-z0-9_.-]+)/?", repository
|
|
85
|
+
)
|
|
86
|
+
if not match or match[2] in (".", ".."):
|
|
87
|
+
raise SubmissionMismatch("invalid GitHub Repository URL")
|
|
88
|
+
version = field(data, "version")
|
|
89
|
+
tag = field(data, "release_tag")
|
|
90
|
+
try:
|
|
91
|
+
from packaging.version import InvalidVersion, Version
|
|
92
|
+
except ImportError as exc:
|
|
93
|
+
raise Blocked(f"cannot validate release versions: {exc}") from exc
|
|
94
|
+
try:
|
|
95
|
+
parsed_version = Version(version)
|
|
96
|
+
except InvalidVersion as exc:
|
|
97
|
+
raise SubmissionMismatch(f"invalid PEP 440 Version: {version}") from exc
|
|
98
|
+
if not re.fullmatch(r"[A-Za-z0-9._~+!-]+", tag):
|
|
99
|
+
raise SubmissionMismatch("Release Tag must match Version and contain no slashes")
|
|
100
|
+
candidates = [tag, *(tag[index + 1:] for index, char in enumerate(tag) if char == "-")]
|
|
101
|
+
for candidate in candidates:
|
|
102
|
+
try:
|
|
103
|
+
if Version(candidate) == parsed_version:
|
|
104
|
+
break
|
|
105
|
+
except InvalidVersion:
|
|
106
|
+
continue
|
|
107
|
+
else:
|
|
108
|
+
raise SubmissionMismatch("Release Tag must match Version")
|
|
109
|
+
download_url = field(data, "download_url")
|
|
110
|
+
if not re.fullmatch(r"https://github\.com/[A-Za-z0-9._~+!/-]+", download_url):
|
|
111
|
+
raise SubmissionMismatch("Download URL contains invalid characters or is not a GitHub URL")
|
|
112
|
+
download = urlsplit(download_url)
|
|
113
|
+
release_path = f"/{match[1]}/{match[2]}/releases/download/{tag}/"
|
|
114
|
+
archive_path = f"/{match[1]}/{match[2]}/archive/refs/tags/{tag}"
|
|
115
|
+
if (
|
|
116
|
+
download.scheme != "https"
|
|
117
|
+
or download.netloc != "github.com"
|
|
118
|
+
or download.query
|
|
119
|
+
or download.fragment
|
|
120
|
+
or not re.fullmatch(r"[A-Za-z0-9._~+!/-]+", download.path)
|
|
121
|
+
or any(part in (".", "..") for part in download.path.split("/"))
|
|
122
|
+
or not (
|
|
123
|
+
(
|
|
124
|
+
download.path.startswith(release_path)
|
|
125
|
+
and "/" not in download.path[len(release_path):]
|
|
126
|
+
and download.path.endswith((".zip", ".tar.gz", ".tgz"))
|
|
127
|
+
)
|
|
128
|
+
or download.path in {
|
|
129
|
+
archive_path + suffix for suffix in (".zip", ".tar.gz")
|
|
130
|
+
}
|
|
131
|
+
)
|
|
132
|
+
):
|
|
133
|
+
raise SubmissionMismatch("Download URL must pin an archive in the submitted repository and release")
|
|
134
|
+
return match[1], match[2], tag
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def validate_files(data: dict[str, Any]) -> dict[str, tuple[str, str]]:
|
|
138
|
+
owner, repo, tag = validate_identity(data)
|
|
139
|
+
entry = data.get("catalog_entry")
|
|
140
|
+
if not isinstance(entry, dict):
|
|
141
|
+
raise SubmissionMismatch("catalog_entry must be an object")
|
|
142
|
+
prefix = f"https://raw.githubusercontent.com/{owner}/{repo}/{tag}/"
|
|
143
|
+
|
|
144
|
+
def package_path(url: str) -> str:
|
|
145
|
+
if not url.startswith(prefix):
|
|
146
|
+
raise SubmissionMismatch("file URL must match the submitted repository and tag")
|
|
147
|
+
path = url[len(prefix):]
|
|
148
|
+
if (
|
|
149
|
+
not re.fullmatch(r"[A-Za-z0-9._~/-]+", path)
|
|
150
|
+
or any(part in ("", ".", "..") for part in path.split("/"))
|
|
151
|
+
):
|
|
152
|
+
raise SubmissionMismatch("file URL contains invalid characters or path segments")
|
|
153
|
+
return path
|
|
154
|
+
|
|
155
|
+
manifest_url = field(entry, "step_yml_url")
|
|
156
|
+
manifest_path = package_path(manifest_url)
|
|
157
|
+
if manifest_path.split("/")[-1] != "step.yml":
|
|
158
|
+
raise SubmissionMismatch("step_yml_url must end in step.yml")
|
|
159
|
+
directory = manifest_path.removesuffix("step.yml")
|
|
160
|
+
files = {"step.yml": manifest_url, "__init__.py": field(entry, "init_url")}
|
|
161
|
+
extra = entry.get("extra_files", {})
|
|
162
|
+
if not isinstance(extra, dict):
|
|
163
|
+
raise SubmissionMismatch("extra_files must be an object")
|
|
164
|
+
forbidden = {"", ".", ".."} | {
|
|
165
|
+
name.casefold() for name in load_installer().EXCLUDE_NAMES
|
|
166
|
+
}
|
|
167
|
+
for name, url in extra.items():
|
|
168
|
+
if (
|
|
169
|
+
not isinstance(name, str)
|
|
170
|
+
or not re.fullmatch(r"[A-Za-z0-9._~/-]+", name)
|
|
171
|
+
or any(part.casefold() in forbidden
|
|
172
|
+
for part in name.split("/"))
|
|
173
|
+
or name.casefold() in ("step.yml", "__init__.py")
|
|
174
|
+
):
|
|
175
|
+
raise SubmissionMismatch("invalid extra file path")
|
|
176
|
+
files[name] = url
|
|
177
|
+
installer = load_installer()
|
|
178
|
+
directories = set()
|
|
179
|
+
for name in files:
|
|
180
|
+
parts = name.split("/")
|
|
181
|
+
if len(parts) - 1 > installer._MAX_STEP_PACKAGE_DEPTH:
|
|
182
|
+
raise SubmissionMismatch(
|
|
183
|
+
f"package exceeds the {installer._MAX_STEP_PACKAGE_DEPTH}-level directory limit"
|
|
184
|
+
)
|
|
185
|
+
directories.update("/".join(parts[:depth]) for depth in range(1, len(parts)))
|
|
186
|
+
if len(files) + len(directories) > installer._MAX_STEP_PACKAGE_FILES:
|
|
187
|
+
raise SubmissionMismatch(
|
|
188
|
+
f"package exceeds the {installer._MAX_STEP_PACKAGE_FILES}-entry limit "
|
|
189
|
+
"(files and directories combined)"
|
|
190
|
+
)
|
|
191
|
+
folded_paths = {
|
|
192
|
+
tuple(part.casefold() for part in name.split("/")) for name in files
|
|
193
|
+
}
|
|
194
|
+
if len(folded_paths) != len(files):
|
|
195
|
+
raise SubmissionMismatch("case-insensitive duplicate package file path")
|
|
196
|
+
if any(
|
|
197
|
+
path[:depth] in folded_paths
|
|
198
|
+
for path in folded_paths
|
|
199
|
+
for depth in range(1, len(path))
|
|
200
|
+
):
|
|
201
|
+
raise SubmissionMismatch("case-insensitive file/directory path collision")
|
|
202
|
+
for name, url in files.items():
|
|
203
|
+
if not isinstance(url, str) or package_path(url) != directory + name:
|
|
204
|
+
raise SubmissionMismatch("file URL must match its package-relative path")
|
|
205
|
+
hashes = entry.get("sha256")
|
|
206
|
+
if (
|
|
207
|
+
not isinstance(hashes, dict)
|
|
208
|
+
or hashes.keys() != files.keys()
|
|
209
|
+
or any(not isinstance(value, str) or not re.fullmatch(r"[A-Fa-f0-9]{64}", value)
|
|
210
|
+
for value in hashes.values())
|
|
211
|
+
):
|
|
212
|
+
raise SubmissionMismatch("sha256 must pin exactly every package file")
|
|
213
|
+
return {name: (url, hashes[name].lower()) for name, url in files.items()}
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def validate_file(data: dict[str, Any]) -> tuple[str, str, str]:
|
|
217
|
+
files = validate_files(data)
|
|
218
|
+
name = field(data, "file")
|
|
219
|
+
if name not in files:
|
|
220
|
+
raise SubmissionMismatch("selected file is not in the proposed entry")
|
|
221
|
+
return name, *files[name]
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def fetch_file(
|
|
225
|
+
data: dict[str, Any], output: Path, *, remaining_bytes: int | None = None,
|
|
226
|
+
) -> dict[str, str]:
|
|
227
|
+
name, url, expected = validate_file(data)
|
|
228
|
+
limit = MAX_FILE_BYTES if remaining_bytes is None else min(MAX_FILE_BYTES, remaining_bytes)
|
|
229
|
+
|
|
230
|
+
def size_error() -> SubmissionMismatch:
|
|
231
|
+
if limit < MAX_FILE_BYTES:
|
|
232
|
+
return SubmissionMismatch(f"file exceeds the remaining cumulative package budget: {url}")
|
|
233
|
+
return SubmissionMismatch(f"file exceeds the 10 MiB limit: {url}")
|
|
234
|
+
|
|
235
|
+
try:
|
|
236
|
+
output.unlink(missing_ok=True)
|
|
237
|
+
result = subprocess.run(
|
|
238
|
+
[
|
|
239
|
+
"curl", "--disable", "--proto", "=https", "--max-time", "60",
|
|
240
|
+
"--max-filesize", str(max(1, limit)), "--silent", "--show-error",
|
|
241
|
+
"--write-out", "%{http_code}", "--output", str(output), url,
|
|
242
|
+
],
|
|
243
|
+
capture_output=True, text=True, check=False,
|
|
244
|
+
)
|
|
245
|
+
except OSError as exc:
|
|
246
|
+
raise Blocked(f"cannot download {url}: {exc}") from exc
|
|
247
|
+
status = result.stdout.strip()
|
|
248
|
+
if status != "200" and re.fullmatch(r"[1-5]\d\d", status):
|
|
249
|
+
if status in ("403", "407", "408", "429") or status.startswith("5"):
|
|
250
|
+
raise Blocked(f"HTTP {status} downloading {url}")
|
|
251
|
+
raise SubmissionMismatch(f"expected HTTP 200, received {status!r} from {url}")
|
|
252
|
+
if result.returncode == 63 and status == "200":
|
|
253
|
+
raise size_error()
|
|
254
|
+
if result.returncode:
|
|
255
|
+
raise Blocked(
|
|
256
|
+
f"curl exited {result.returncode} for {url}: {result.stderr.strip()}"
|
|
257
|
+
)
|
|
258
|
+
if status != "200":
|
|
259
|
+
raise Blocked(f"curl returned no valid HTTP status ({status!r}) for {url}")
|
|
260
|
+
try:
|
|
261
|
+
if output.stat().st_size > limit:
|
|
262
|
+
raise size_error()
|
|
263
|
+
payload = output.read_bytes()
|
|
264
|
+
except OSError as exc:
|
|
265
|
+
raise Blocked(f"cannot read downloaded {name}: {exc}") from exc
|
|
266
|
+
actual = hashlib.sha256(payload).hexdigest()
|
|
267
|
+
if actual != expected:
|
|
268
|
+
raise SubmissionMismatch(
|
|
269
|
+
f"SHA-256 mismatch for {name}: submitted {expected}, actual {actual}"
|
|
270
|
+
)
|
|
271
|
+
return {"file": name, "sha256": actual}
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def fetch_package(data: dict[str, Any], manifest_output: Path) -> dict[str, Any]:
|
|
275
|
+
files = validate_files(data)
|
|
276
|
+
limit = load_installer()._MAX_STEP_PACKAGE_BYTES
|
|
277
|
+
total = 0
|
|
278
|
+
hashes = {}
|
|
279
|
+
manifest = None
|
|
280
|
+
try:
|
|
281
|
+
manifest_output.unlink(missing_ok=True)
|
|
282
|
+
with tempfile.TemporaryDirectory(prefix="community-step-") as directory:
|
|
283
|
+
output = Path(directory) / "download"
|
|
284
|
+
for name in files:
|
|
285
|
+
result = fetch_file(
|
|
286
|
+
{**data, "file": name}, output, remaining_bytes=limit - total
|
|
287
|
+
)
|
|
288
|
+
size = output.stat().st_size
|
|
289
|
+
if name in ("step.yml", "__init__.py") and size == 0:
|
|
290
|
+
raise SubmissionMismatch(f"{name} must be nonempty")
|
|
291
|
+
total += size
|
|
292
|
+
if total > limit:
|
|
293
|
+
raise SubmissionMismatch(
|
|
294
|
+
f"package exceeds the {limit // (1024 * 1024)} MiB cumulative size limit"
|
|
295
|
+
)
|
|
296
|
+
hashes[name] = result["sha256"]
|
|
297
|
+
if name == "step.yml":
|
|
298
|
+
manifest = output.read_bytes()
|
|
299
|
+
if manifest is None:
|
|
300
|
+
raise Blocked("downloaded package manifest is unavailable")
|
|
301
|
+
manifest_output.write_bytes(manifest)
|
|
302
|
+
except OSError as exc:
|
|
303
|
+
raise Blocked(f"cannot stage downloaded package metadata: {exc}") from exc
|
|
304
|
+
return {"sha256": hashes, "bytes": total}
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
RELEASE_FIELDS = (
|
|
308
|
+
"url", "step_yml_url", "init_url", "extra_files", "sha256",
|
|
309
|
+
"requires", "provides", "download_url",
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def check_existing_release(record: dict[str, Any]) -> None:
|
|
314
|
+
url = record.get("step_yml_url", record.get("url"))
|
|
315
|
+
init = record.get("init_url")
|
|
316
|
+
extra = record.get("extra_files", {})
|
|
317
|
+
if (
|
|
318
|
+
not isinstance(url, str) or not url.strip()
|
|
319
|
+
or (init is None and not url.endswith("step.yml"))
|
|
320
|
+
or (init is not None and (not isinstance(init, str) or not init.strip()))
|
|
321
|
+
or not isinstance(extra, dict)
|
|
322
|
+
or any(
|
|
323
|
+
not isinstance(name, str)
|
|
324
|
+
or not re.fullmatch(r"[A-Za-z0-9._~/-]+", name)
|
|
325
|
+
or any(part in ("", ".", "..") for part in name.split("/"))
|
|
326
|
+
or name.casefold() in ("step.yml", "__init__.py")
|
|
327
|
+
or not isinstance(value, str) or not value.strip()
|
|
328
|
+
for name, value in extra.items()
|
|
329
|
+
)
|
|
330
|
+
):
|
|
331
|
+
raise Blocked("existing release has invalid file metadata; maintainer repair required")
|
|
332
|
+
hashes = record.get("sha256")
|
|
333
|
+
if (
|
|
334
|
+
not isinstance(hashes, dict)
|
|
335
|
+
or hashes.keys() != {"step.yml", "__init__.py", *extra}
|
|
336
|
+
or any(
|
|
337
|
+
not isinstance(value, str) or not re.fullmatch(r"[A-Fa-f0-9]{64}", value)
|
|
338
|
+
for value in hashes.values()
|
|
339
|
+
)
|
|
340
|
+
):
|
|
341
|
+
raise Blocked("existing release needs complete SHA-256 digests; maintainer repair required")
|
|
342
|
+
if any(key in record and not isinstance(record[key], dict) for key in ("requires", "provides")):
|
|
343
|
+
raise Blocked("existing release has invalid requirements or provides metadata")
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def catalog_snapshot(
|
|
347
|
+
data: dict[str, Any], original: dict[str, Any], receipt: dict[str, Any],
|
|
348
|
+
) -> dict[str, Any]:
|
|
349
|
+
files = validate_files(data)
|
|
350
|
+
expected_hashes = {name: digest for name, (_, digest) in files.items()}
|
|
351
|
+
byte_count = receipt.get("bytes")
|
|
352
|
+
if (
|
|
353
|
+
receipt.get("sha256") != expected_hashes
|
|
354
|
+
or not isinstance(byte_count, int) or isinstance(byte_count, bool)
|
|
355
|
+
or not 0 <= byte_count <= load_installer()._MAX_STEP_PACKAGE_BYTES
|
|
356
|
+
):
|
|
357
|
+
raise Blocked("download receipt does not match the submitted complete file digests")
|
|
358
|
+
entries = original.get("steps")
|
|
359
|
+
if not isinstance(entries, dict):
|
|
360
|
+
raise Blocked("original catalog has no steps object")
|
|
361
|
+
step_id = data["step_id"]
|
|
362
|
+
submitted = data["catalog_entry"]
|
|
363
|
+
if submitted.get("id") != step_id or submitted.get("version") != data["version"]:
|
|
364
|
+
raise SubmissionMismatch("catalog ID/version must match the submission")
|
|
365
|
+
canonical_fields = {
|
|
366
|
+
"name": "step_name",
|
|
367
|
+
"description": "description",
|
|
368
|
+
"author": "author",
|
|
369
|
+
"repository": "repository",
|
|
370
|
+
"download_url": "download_url",
|
|
371
|
+
"documentation": "documentation",
|
|
372
|
+
"license": "license",
|
|
373
|
+
}
|
|
374
|
+
for key, form_key in canonical_fields.items():
|
|
375
|
+
expected = field(data, form_key)
|
|
376
|
+
actual = field(submitted, key)
|
|
377
|
+
if not expected.strip() or not actual.strip() or actual != expected:
|
|
378
|
+
raise SubmissionMismatch(f"catalog {key} must match the canonical form value")
|
|
379
|
+
compatibility = field(data, "speckit_compatibility")
|
|
380
|
+
requires = submitted.get("requires")
|
|
381
|
+
if (
|
|
382
|
+
not compatibility.strip()
|
|
383
|
+
or not isinstance(requires, dict)
|
|
384
|
+
or requires.get("speckit_version") != compatibility
|
|
385
|
+
):
|
|
386
|
+
raise SubmissionMismatch("catalog requires.speckit_version must match Spec Kit Compatibility")
|
|
387
|
+
if "changelog" in data or "changelog" in submitted:
|
|
388
|
+
if field(submitted, "changelog") != field(data, "changelog"):
|
|
389
|
+
raise SubmissionMismatch("catalog changelog must match the canonical form value")
|
|
390
|
+
if submitted.get("verified") is not False:
|
|
391
|
+
raise SubmissionMismatch("community catalog verified must be false")
|
|
392
|
+
if "releases" in submitted or any(key.startswith("_") for key in submitted):
|
|
393
|
+
raise SubmissionMismatch("submitted entry must not supply history or internal fields")
|
|
394
|
+
previous = entries.get(step_id)
|
|
395
|
+
history = {}
|
|
396
|
+
entry = {}
|
|
397
|
+
timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT00:00:00Z")
|
|
398
|
+
if step_id in entries:
|
|
399
|
+
if not isinstance(previous, dict) or not isinstance(previous.get("created_at"), str):
|
|
400
|
+
raise Blocked("existing entry lacks valid original metadata/created_at")
|
|
401
|
+
from packaging.version import InvalidVersion, Version
|
|
402
|
+
|
|
403
|
+
try:
|
|
404
|
+
old_version = Version(field(previous, "version"))
|
|
405
|
+
except (InvalidVersion, SubmissionMismatch) as exc:
|
|
406
|
+
raise Blocked(f"existing entry has invalid version: {exc}") from exc
|
|
407
|
+
new_version = Version(data["version"])
|
|
408
|
+
if new_version < old_version:
|
|
409
|
+
raise SubmissionMismatch("version downgrade is not allowed")
|
|
410
|
+
existing_history = previous.get("releases", {})
|
|
411
|
+
if not isinstance(existing_history, dict):
|
|
412
|
+
raise Blocked("existing releases must be an object")
|
|
413
|
+
seen = {old_version}
|
|
414
|
+
for version, record in existing_history.items():
|
|
415
|
+
if not isinstance(version, str) or not isinstance(record, dict):
|
|
416
|
+
raise Blocked("existing release history has invalid version/record")
|
|
417
|
+
try:
|
|
418
|
+
normalized = Version(version)
|
|
419
|
+
except InvalidVersion as exc:
|
|
420
|
+
raise Blocked(f"existing history has invalid version: {version}") from exc
|
|
421
|
+
if normalized in seen:
|
|
422
|
+
raise Blocked("existing release history contains equivalent duplicate versions")
|
|
423
|
+
seen.add(normalized)
|
|
424
|
+
if {"id", "version", "releases", "_catalog_name", "_install_allowed"} & record.keys():
|
|
425
|
+
raise Blocked("existing historical release contains reserved fields")
|
|
426
|
+
check_existing_release(record)
|
|
427
|
+
history = copy.deepcopy(existing_history)
|
|
428
|
+
if new_version == old_version:
|
|
429
|
+
if data.get("metadata_only") is not True:
|
|
430
|
+
raise SubmissionMismatch("same-version updates require an explicit metadata-only correction")
|
|
431
|
+
for key in ("step_yml_url", "init_url", "extra_files", "sha256", "download_url"):
|
|
432
|
+
default = {} if key == "extra_files" else None
|
|
433
|
+
old_value = previous.get(
|
|
434
|
+
key, previous.get("url") if key == "step_yml_url" else default
|
|
435
|
+
)
|
|
436
|
+
if old_value != submitted.get(key, default):
|
|
437
|
+
raise SubmissionMismatch("same-version repairs cannot replace file URLs or digests")
|
|
438
|
+
else:
|
|
439
|
+
if new_version in seen:
|
|
440
|
+
raise SubmissionMismatch("new version already exists in preserved history")
|
|
441
|
+
check_existing_release(previous)
|
|
442
|
+
history[previous["version"]] = {
|
|
443
|
+
key: copy.deepcopy(previous[key]) for key in RELEASE_FIELDS if key in previous
|
|
444
|
+
}
|
|
445
|
+
entry = {
|
|
446
|
+
key: copy.deepcopy(value) for key, value in previous.items()
|
|
447
|
+
if key not in (*RELEASE_FIELDS, "releases")
|
|
448
|
+
}
|
|
449
|
+
entry.update(copy.deepcopy(submitted))
|
|
450
|
+
entry["sha256"] = expected_hashes
|
|
451
|
+
entry["created_at"] = previous["created_at"] if previous is not None else timestamp
|
|
452
|
+
entry["updated_at"] = timestamp
|
|
453
|
+
if previous is not None and ("releases" in previous or history):
|
|
454
|
+
entry["releases"] = history
|
|
455
|
+
expected_catalog = copy.deepcopy(original)
|
|
456
|
+
expected_catalog["steps"][step_id] = entry
|
|
457
|
+
expected_catalog["steps"] = dict(sorted(expected_catalog["steps"].items()))
|
|
458
|
+
expected_catalog["updated_at"] = timestamp
|
|
459
|
+
return {"step_id": step_id, "expected_catalog": expected_catalog}
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
def verify_generated_catalog(snapshot: dict[str, Any], catalog: dict[str, Any]) -> None:
|
|
463
|
+
expected = snapshot.get("expected_catalog")
|
|
464
|
+
if not isinstance(expected, dict) or not isinstance(expected.get("steps"), dict):
|
|
465
|
+
raise Blocked("catalog snapshot lacks expected catalog state")
|
|
466
|
+
if catalog != expected:
|
|
467
|
+
raise GeneratedError(
|
|
468
|
+
"generated catalog differs from validated snapshot; preserve current/history "
|
|
469
|
+
"digests, original metadata, unrelated entries, and timestamps"
|
|
470
|
+
)
|
|
471
|
+
if list(catalog["steps"]) != sorted(catalog["steps"]):
|
|
472
|
+
raise GeneratedError("generated catalog IDs must be sorted")
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
def read_json(
|
|
476
|
+
path: Path, error_type: type[Exception] = Blocked,
|
|
477
|
+
) -> dict[str, Any]:
|
|
478
|
+
try:
|
|
479
|
+
text = path.read_text(encoding="utf-8")
|
|
480
|
+
except (OSError, UnicodeError) as exc:
|
|
481
|
+
raise error_type(f"cannot read JSON evidence at {path}: {exc}") from exc
|
|
482
|
+
try:
|
|
483
|
+
value = json.loads(text, object_pairs_hook=unique_json_fields)
|
|
484
|
+
except (json.JSONDecodeError, DuplicateField) as exc:
|
|
485
|
+
raise error_type(f"invalid JSON evidence at {path}: {exc}") from exc
|
|
486
|
+
if not isinstance(value, dict):
|
|
487
|
+
raise error_type(f"JSON evidence must be an object: {path}")
|
|
488
|
+
return value
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
def main() -> int:
|
|
492
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
493
|
+
parser.add_argument("operation", choices=("identity", "fetch", "snapshot", "generated"))
|
|
494
|
+
parser.add_argument("--submission", required=True, type=Path)
|
|
495
|
+
parser.add_argument("--catalog", type=Path, default=ROOT / "workflows/step-catalog.community.json")
|
|
496
|
+
parser.add_argument("--snapshot", type=Path, default=Path("/tmp/gh-aw/step-catalog-snapshot.json"))
|
|
497
|
+
parser.add_argument("--receipt", type=Path, default=Path("/tmp/gh-aw/step-downloads.json"))
|
|
498
|
+
args = parser.parse_args()
|
|
499
|
+
try:
|
|
500
|
+
try:
|
|
501
|
+
text = args.submission.read_text(encoding="utf-8")
|
|
502
|
+
except (OSError, UnicodeError) as exc:
|
|
503
|
+
raise Blocked(f"cannot read submission: {exc}") from exc
|
|
504
|
+
try:
|
|
505
|
+
data = json.loads(text, object_pairs_hook=unique_json_fields)
|
|
506
|
+
except (json.JSONDecodeError, DuplicateField) as exc:
|
|
507
|
+
raise SubmissionMismatch(f"invalid submission JSON: {exc}") from exc
|
|
508
|
+
if not isinstance(data, dict):
|
|
509
|
+
raise SubmissionMismatch("submission JSON must be an object")
|
|
510
|
+
if args.operation == "identity":
|
|
511
|
+
validate_identity(data)
|
|
512
|
+
print("Identity validation passed")
|
|
513
|
+
elif args.operation == "fetch":
|
|
514
|
+
try:
|
|
515
|
+
args.receipt.unlink(missing_ok=True)
|
|
516
|
+
result = fetch_package(data, Path("/tmp/gh-aw/step-file.bin"))
|
|
517
|
+
args.receipt.write_text(json.dumps(result), encoding="utf-8")
|
|
518
|
+
except OSError as exc:
|
|
519
|
+
raise Blocked(f"cannot store download receipt: {exc}") from exc
|
|
520
|
+
print(json.dumps(result))
|
|
521
|
+
elif args.operation == "snapshot":
|
|
522
|
+
try:
|
|
523
|
+
args.snapshot.unlink(missing_ok=True)
|
|
524
|
+
except OSError as exc:
|
|
525
|
+
raise Blocked(f"cannot clear old catalog snapshot: {exc}") from exc
|
|
526
|
+
snapshot = catalog_snapshot(data, read_json(args.catalog), read_json(args.receipt))
|
|
527
|
+
try:
|
|
528
|
+
args.snapshot.write_text(json.dumps(snapshot, indent=2) + "\n", encoding="utf-8")
|
|
529
|
+
except OSError as exc:
|
|
530
|
+
raise Blocked(f"cannot store catalog snapshot: {exc}") from exc
|
|
531
|
+
print("Catalog snapshot created; history and download evidence validated")
|
|
532
|
+
else:
|
|
533
|
+
verify_generated_catalog(
|
|
534
|
+
read_json(args.snapshot), read_json(args.catalog, GeneratedError),
|
|
535
|
+
)
|
|
536
|
+
print("Generated catalog matches validated snapshot")
|
|
537
|
+
except SubmissionMismatch as exc:
|
|
538
|
+
print(f"FAILED: {exc}")
|
|
539
|
+
return 1
|
|
540
|
+
except Blocked as exc:
|
|
541
|
+
print(f"BLOCKED: {exc}")
|
|
542
|
+
return 2
|
|
543
|
+
except GeneratedError as exc:
|
|
544
|
+
print(f"GENERATED ERROR: {exc}")
|
|
545
|
+
return 3
|
|
546
|
+
return 0
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
if __name__ == "__main__":
|
|
550
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-review
|
|
3
|
+
description: Reviews Spec Kit code changes for consistency with applicable design documents, positive and negative test coverage, regression evidence for bug fixes, and consistent repository terminology. Use when reviewing a diff or pull request. Do not use for implementing changes or posting GitHub review actions.
|
|
4
|
+
argument-hint: 'Diff or pull request to review'
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Code Review
|
|
8
|
+
|
|
9
|
+
1. Ensure each code change has test cases that verify what the code should do and what it should prevent.
|
|
10
|
+
2. Ensure bug-fix pull requests include a regression test that demonstrates the bug was reproducible before the change and is fixed afterward; if the reviewer cannot run the comparison, use available evidence and state that limitation.
|
|
11
|
+
3. Ensure wording changes use repository-consistent terms; exclude community-authored catalog content and its generated documentation from this check.
|
|
12
|
+
4. Identify the affected domains and read the applicable documents in `design/` before evaluating architectural consistency. For CLI command changes, use `design/cli.md`; for agent integrations, use `design/integration.md`; for workflow step types, use `design/workflow-step.md`. Read other design documents when relevant, not every document for every PR.
|
|
13
|
+
5. Check the changes against the applicable design requirements, including implementation boundaries, ownership, lifecycle, and delivery requirements. Reference the documents rather than duplicating their rules in this skill. Cite the document and section for each reported mismatch.
|
|
14
|
+
6. Distinguish an unexplained design violation from an intentional design change. Evaluate the rationale and evidence for an intentional change; updating the design document alone does not establish that the implementation is justified.
|