specfact-cli 0.47.11__tar.gz → 0.49.1__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.
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/PKG-INFO +1 -1
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/pyproject.toml +1 -1
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/bundled-module-registry/index.json +3 -3
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/__init__.py +1 -1
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/__init__.py +1 -1
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/analyzers/code_analyzer.py +3 -2
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/__init__.py +30 -0
- specfact_cli-0.49.1/src/specfact_cli/models/requirements.py +183 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/init/module-package.yaml +3 -3
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/init/src/commands.py +21 -10
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/init/src/first_run_selection.py +280 -2
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/module_discovery.py +16 -2
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/.gitignore +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/LICENSE +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/README.md +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/keys/README.md +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/keys/module-signing-public.pem +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/mappings/node-async.yaml +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/mappings/python-async.yaml +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/mappings/speckit-default.yaml +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/schemas/deviation.schema.json +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/schemas/plan.schema.json +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/schemas/protocol.schema.json +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/github-action.yml.j2 +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/persona/architect.md.j2 +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/persona/developer.md.j2 +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/persona/product-owner.md.j2 +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/plan.bundle.yaml.j2 +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/policies/kanban.yaml +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/policies/mixed.yaml +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/policies/safe.yaml +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/policies/scrum.yaml +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/pr-template.md.j2 +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/protocol.yaml.j2 +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/telemetry.yaml.example +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/__main__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/adapters/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/adapters/ado.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/adapters/backlog_base.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/adapters/base.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/adapters/github.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/adapters/openspec.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/adapters/openspec_parser.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/adapters/registry.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/adapters/speckit.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/agents/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/agents/analyze_agent.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/agents/base.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/agents/plan_agent.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/agents/registry.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/agents/sync_agent.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/analyzers/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/analyzers/ambiguity_scanner.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/analyzers/constitution_evidence_extractor.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/analyzers/contract_extractor.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/analyzers/control_flow_analyzer.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/analyzers/graph_analyzer.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/analyzers/relationship_mapper.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/analyzers/requirement_extractor.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/analyzers/test_pattern_extractor.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/backlog/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/backlog/adapters/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/backlog/adapters/base.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/backlog/converter.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/backlog/filters.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/backlog/mappers/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/backlog/mappers/ado_mapper.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/backlog/mappers/base.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/backlog/mappers/github_mapper.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/backlog/mappers/template_config.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/cli.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/_bundle_shim.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/analyze.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/contract_cmd.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/drift.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/enforce.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/generate.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/import_cmd.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/init.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/migrate.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/plan.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/project_cmd.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/repro.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/sdd.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/spec.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/sync.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/update.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/validate.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/common/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/common/bundle_factory.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/common/logger_setup.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/common/logging_utils.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/common/text_utils.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/common/utils.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/comparators/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/comparators/plan_comparator.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/contracts/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/contracts/crosshair_props.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/contracts/module_interface.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/enrichers/constitution_enricher.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/enrichers/plan_enricher.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/generators/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/generators/contract_generator.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/generators/openapi_extractor.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/generators/persona_exporter.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/generators/plan_generator.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/generators/protocol_generator.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/generators/report_generator.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/generators/task_generator.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/generators/test_to_openapi.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/generators/workflow_generator.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/groups/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/groups/codebase_group.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/groups/govern_group.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/groups/member_group.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/groups/project_group.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/groups/spec_group.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/importers/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/importers/speckit_converter.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/importers/speckit_scanner.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/integrations/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/integrations/specmatic.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/merge/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/merge/resolver.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/migrations/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/migrations/plan_migrator.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/backlog_item.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/bridge.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/capabilities.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/change.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/contract.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/deviation.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/dor_config.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/enforcement.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/module_package.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/persona_template.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/plan.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/project.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/protocol.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/quality.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/sdd.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/source_tracking.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/task.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/validation.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modes/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modes/detector.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modes/router.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/_bundle_import.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/init/src/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/init/src/app.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/module_io_shim.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/module_registry/module-package.yaml +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/module_registry/src/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/module_registry/src/app.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/module_registry/src/commands.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/upgrade/module-package.yaml +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/upgrade/src/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/upgrade/src/app.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/upgrade/src/commands.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/parsers/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/parsers/persona_importer.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/alias_manager.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/bootstrap.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/bridge_registry.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/crypto_validator.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/custom_registries.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/dependency_resolver.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/extension_registry.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/help_cache.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/marketplace_client.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/metadata.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/module_availability.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/module_grouping.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/module_installer.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/module_lifecycle.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/module_packages.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/module_security.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/module_state.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/registry.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/resources/semgrep/async.yml +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/resources/semgrep/code-quality.yml +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/resources/semgrep/feature-detection.yml +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/runtime.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/bridge_probe.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/bridge_sync.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/bridge_sync_openspec_md_parse.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/bridge_sync_requirement_from_proposal.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/bridge_sync_requirement_helpers.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/bridge_sync_tasks_from_proposal.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/bridge_sync_what_changes_format.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/bridge_sync_write_openspec_from_proposal.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/bridge_watch.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/change_detector.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/code_to_spec.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/drift_detector.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/repository_sync.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/spec_to_code.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/spec_to_tests.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/watcher.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/watcher_enhanced.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/telemetry.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/templates/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/templates/defaults/defect_v1.yaml +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/templates/defaults/enabler_v1.yaml +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/templates/defaults/spike_v1.yaml +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/templates/defaults/user_story_v1.yaml +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/templates/frameworks/scrum/user_story_v1.yaml +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/templates/personas/product-owner/user_story_v1.yaml +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/templates/providers/ado/work_item_v1.yaml +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/templates/registry.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/templates/specification_templates.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/acceptance_criteria.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/auth_tokens.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/bundle_converters.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/bundle_loader.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/code_change_detector.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/console.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/content_sanitizer.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/context_detection.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/contract_predicates.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/enrichment_context.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/enrichment_parser.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/env_manager.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/feature_keys.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/git.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/github_annotations.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/icontract_helpers.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/ide_setup.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/incremental_check.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/metadata.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/optional_deps.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/performance.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/persona_ownership.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/progress.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/progressive_disclosure.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/project_artifact_write.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/prompts.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/sdd_discovery.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/source_scanner.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/startup_checks.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/structure.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/structured_io.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/suggestions.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/terminal.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/yaml_utils.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validation/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validation/command_audit.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/agile_validation.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/change_proposal_integration.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/cli_first_validator.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/contract_validator.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/fsm.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/repro_checker.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/schema.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/contract_populator.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/crosshair_runner.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/crosshair_summary.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/dependency_installer.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/framework_detector.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/frameworks/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/frameworks/base.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/frameworks/django.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/frameworks/drf.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/frameworks/fastapi.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/frameworks/flask.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/harness_generator.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/models.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/orchestrator.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/specmatic_runner.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/unannotated_detector.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/versioning/__init__.py +0 -0
- {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/versioning/analyzer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: specfact-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.49.1
|
|
4
4
|
Summary: AI-bloat defense CLI for Python teams. Run deterministic code review, cleanup forecasts, and spec/contract evidence for AI-assisted and brownfield delivery.
|
|
5
5
|
Project-URL: Homepage, https://github.com/nold-ai/specfact-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/nold-ai/specfact-cli.git
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "specfact-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.49.1"
|
|
8
8
|
description = "AI-bloat defense CLI for Python teams. Run deterministic code review, cleanup forecasts, and spec/contract evidence for AI-assisted and brownfield delivery."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"modules": [
|
|
3
3
|
{
|
|
4
|
-
"checksum_sha256": "
|
|
5
|
-
"download_url": "https://github.com/nold-ai/specfact-cli/releases/download/init-0.1.
|
|
4
|
+
"checksum_sha256": "2ffe401e068883086f2df2beed8e9d328db9f0802deb3c69212b0594bfa1be75",
|
|
5
|
+
"download_url": "https://github.com/nold-ai/specfact-cli/releases/download/init-0.1.41.tar.gz",
|
|
6
6
|
"id": "init",
|
|
7
|
-
"latest_version": "0.1.
|
|
7
|
+
"latest_version": "0.1.41"
|
|
8
8
|
},
|
|
9
9
|
{
|
|
10
10
|
"checksum_sha256": "35c592374b209224af9a826c21efa66947cc16bf680b20ee0463f44bee4f9b59",
|
|
@@ -128,10 +128,11 @@ class CodeAnalyzer:
|
|
|
128
128
|
def _resolve_analyzer_entry_point(repo_path: Path, entry_point: Path | None) -> Path | None:
|
|
129
129
|
if entry_point is None:
|
|
130
130
|
return None
|
|
131
|
-
|
|
131
|
+
resolved_repo_path = repo_path.resolve()
|
|
132
|
+
resolved = entry_point.resolve() if entry_point.is_absolute() else (resolved_repo_path / entry_point).resolve()
|
|
132
133
|
if not resolved.exists():
|
|
133
134
|
raise ValueError(f"Entry point does not exist: {resolved}")
|
|
134
|
-
if not
|
|
135
|
+
if not resolved.is_relative_to(resolved_repo_path):
|
|
135
136
|
raise ValueError(f"Entry point must be within repository: {resolved}")
|
|
136
137
|
return resolved
|
|
137
138
|
|
|
@@ -37,6 +37,22 @@ from specfact_cli.models.project import (
|
|
|
37
37
|
SectionLock,
|
|
38
38
|
)
|
|
39
39
|
from specfact_cli.models.protocol import Protocol, Transition
|
|
40
|
+
from specfact_cli.models.requirements import (
|
|
41
|
+
REQUIREMENTS_INPUT_SCHEMA_VERSION,
|
|
42
|
+
BusinessRule,
|
|
43
|
+
RequirementCompletenessFinding,
|
|
44
|
+
RequirementCompletenessSeverity,
|
|
45
|
+
RequirementConstraint,
|
|
46
|
+
RequirementConstraintType,
|
|
47
|
+
RequirementEvidenceLink,
|
|
48
|
+
RequirementEvidenceLinkType,
|
|
49
|
+
RequirementInput,
|
|
50
|
+
RequirementsInputExtensionPayload,
|
|
51
|
+
RequirementSourceReference,
|
|
52
|
+
RequirementSourceType,
|
|
53
|
+
load_requirements_input_extension,
|
|
54
|
+
requirements_input_extension_payload,
|
|
55
|
+
)
|
|
40
56
|
from specfact_cli.models.sdd import (
|
|
41
57
|
SDDCoverageThresholds,
|
|
42
58
|
SDDEnforcementBudget,
|
|
@@ -49,6 +65,7 @@ from specfact_cli.models.source_tracking import SourceTracking
|
|
|
49
65
|
|
|
50
66
|
|
|
51
67
|
__all__ = [
|
|
68
|
+
"REQUIREMENTS_INPUT_SCHEMA_VERSION",
|
|
52
69
|
"AdapterType",
|
|
53
70
|
"ArtifactMapping",
|
|
54
71
|
"BridgeConfig",
|
|
@@ -57,6 +74,7 @@ __all__ = [
|
|
|
57
74
|
"BundleManifest",
|
|
58
75
|
"BundleVersions",
|
|
59
76
|
"Business",
|
|
77
|
+
"BusinessRule",
|
|
60
78
|
"ChangeArchive",
|
|
61
79
|
"ChangeProposal",
|
|
62
80
|
"ChangeTracking",
|
|
@@ -84,6 +102,16 @@ __all__ = [
|
|
|
84
102
|
"Protocol",
|
|
85
103
|
"ProtocolIndex",
|
|
86
104
|
"Release",
|
|
105
|
+
"RequirementCompletenessFinding",
|
|
106
|
+
"RequirementCompletenessSeverity",
|
|
107
|
+
"RequirementConstraint",
|
|
108
|
+
"RequirementConstraintType",
|
|
109
|
+
"RequirementEvidenceLink",
|
|
110
|
+
"RequirementEvidenceLinkType",
|
|
111
|
+
"RequirementInput",
|
|
112
|
+
"RequirementSourceReference",
|
|
113
|
+
"RequirementSourceType",
|
|
114
|
+
"RequirementsInputExtensionPayload",
|
|
87
115
|
"SDDCoverageThresholds",
|
|
88
116
|
"SDDEnforcementBudget",
|
|
89
117
|
"SDDHow",
|
|
@@ -100,4 +128,6 @@ __all__ = [
|
|
|
100
128
|
"TemplateSection",
|
|
101
129
|
"Transition",
|
|
102
130
|
"ValidationReport",
|
|
131
|
+
"load_requirements_input_extension",
|
|
132
|
+
"requirements_input_extension_payload",
|
|
103
133
|
]
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"""Requirement evidence input models.
|
|
2
|
+
|
|
3
|
+
These models normalize upstream requirement context for validation evidence.
|
|
4
|
+
They do not make SpecFact the authoring system or source of truth for
|
|
5
|
+
requirements.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from enum import StrEnum
|
|
11
|
+
from typing import Any, Literal, cast
|
|
12
|
+
|
|
13
|
+
from beartype import beartype
|
|
14
|
+
from icontract import ensure, require
|
|
15
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
REQUIREMENTS_INPUT_SCHEMA_VERSION = "1"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class RequirementSourceType(StrEnum):
|
|
22
|
+
"""Supported upstream source reference types."""
|
|
23
|
+
|
|
24
|
+
ISSUE = "issue"
|
|
25
|
+
DOCUMENT = "document"
|
|
26
|
+
OPENSPEC_CHANGE = "openspec_change"
|
|
27
|
+
SPECKIT_SPEC = "speckit_spec"
|
|
28
|
+
FILE = "file"
|
|
29
|
+
BACKLOG_ITEM = "backlog_item"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class RequirementEvidenceLinkType(StrEnum):
|
|
33
|
+
"""Kinds of downstream evidence linked from a requirement input."""
|
|
34
|
+
|
|
35
|
+
ARCHITECTURE = "architecture"
|
|
36
|
+
SPEC = "spec"
|
|
37
|
+
CODE = "code"
|
|
38
|
+
TEST = "test"
|
|
39
|
+
VALIDATION = "validation"
|
|
40
|
+
REQUIREMENT = "requirement"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class RequirementConstraintType(StrEnum):
|
|
44
|
+
"""Supported requirement constraint categories."""
|
|
45
|
+
|
|
46
|
+
PERFORMANCE = "performance"
|
|
47
|
+
SECURITY = "security"
|
|
48
|
+
INTEGRATION = "integration"
|
|
49
|
+
COMPLIANCE = "compliance"
|
|
50
|
+
UX = "ux"
|
|
51
|
+
OPERATIONAL = "operational"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class RequirementCompletenessSeverity(StrEnum):
|
|
55
|
+
"""Advisory completeness finding severity."""
|
|
56
|
+
|
|
57
|
+
INFO = "info"
|
|
58
|
+
WARNING = "warning"
|
|
59
|
+
ERROR = "error"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@beartype
|
|
63
|
+
class RequirementSourceReference(BaseModel):
|
|
64
|
+
"""Reference to an upstream requirement source."""
|
|
65
|
+
|
|
66
|
+
model_config = ConfigDict(use_enum_values=True)
|
|
67
|
+
|
|
68
|
+
source_type: RequirementSourceType = Field(..., description="Type of upstream requirement source")
|
|
69
|
+
locator: str = Field(..., min_length=1, description="Source locator such as URL, file path, or change ID")
|
|
70
|
+
title: str | None = Field(default=None, description="Human-readable source title")
|
|
71
|
+
revision: str | None = Field(default=None, description="Optional source revision, commit, or version")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@beartype
|
|
75
|
+
class BusinessRule(BaseModel):
|
|
76
|
+
"""Business rule imported from upstream requirement context."""
|
|
77
|
+
|
|
78
|
+
rule_id: str = Field(..., min_length=1, description="Stable business rule identifier")
|
|
79
|
+
name: str = Field(..., min_length=1, description="Rule name")
|
|
80
|
+
given: str = Field(..., min_length=1, description="Given clause for validation scenario context")
|
|
81
|
+
when: str = Field(..., min_length=1, description="When clause for validation scenario context")
|
|
82
|
+
then: str = Field(..., min_length=1, description="Then clause for validation scenario context")
|
|
83
|
+
priority: str | None = Field(default=None, description="Optional upstream priority such as MoSCoW")
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@beartype
|
|
87
|
+
class RequirementConstraint(BaseModel):
|
|
88
|
+
"""Constraint imported from upstream requirement context."""
|
|
89
|
+
|
|
90
|
+
model_config = ConfigDict(use_enum_values=True)
|
|
91
|
+
|
|
92
|
+
constraint_id: str = Field(..., min_length=1, description="Stable constraint identifier")
|
|
93
|
+
constraint_type: RequirementConstraintType = Field(..., description="Constraint category")
|
|
94
|
+
statement: str = Field(..., min_length=1, description="Constraint statement")
|
|
95
|
+
validation_criteria: list[str] = Field(default_factory=list, description="Criteria used to validate constraint")
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@beartype
|
|
99
|
+
class RequirementEvidenceLink(BaseModel):
|
|
100
|
+
"""Link from requirement input to downstream validation evidence."""
|
|
101
|
+
|
|
102
|
+
model_config = ConfigDict(use_enum_values=True)
|
|
103
|
+
|
|
104
|
+
link_type: RequirementEvidenceLinkType = Field(..., description="Evidence target category")
|
|
105
|
+
target: str = Field(..., min_length=1, description="Evidence target locator")
|
|
106
|
+
relation: str = Field(default="references", min_length=1, description="Relationship to the target")
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@beartype
|
|
110
|
+
class RequirementCompletenessFinding(BaseModel):
|
|
111
|
+
"""Profile-aware completeness finding stored as advisory evidence."""
|
|
112
|
+
|
|
113
|
+
model_config = ConfigDict(use_enum_values=True)
|
|
114
|
+
|
|
115
|
+
profile: str = Field(..., min_length=1, description="Profile that produced this finding")
|
|
116
|
+
severity: RequirementCompletenessSeverity = Field(..., description="Finding severity")
|
|
117
|
+
field_path: str = Field(..., min_length=1, description="Requirement field path")
|
|
118
|
+
message: str = Field(..., min_length=1, description="Human-readable completeness guidance")
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@beartype
|
|
122
|
+
class RequirementInput(BaseModel):
|
|
123
|
+
"""Normalized requirement context consumed by validation evidence."""
|
|
124
|
+
|
|
125
|
+
schema_version: Literal["1"] = Field(..., description="Requirement input schema version")
|
|
126
|
+
requirement_id: str = Field(..., min_length=1, description="Stable requirement identifier")
|
|
127
|
+
title: str = Field(..., min_length=1, description="Requirement title")
|
|
128
|
+
summary: str | None = Field(default=None, description="Optional upstream requirement summary")
|
|
129
|
+
sources: list[RequirementSourceReference] = Field(
|
|
130
|
+
...,
|
|
131
|
+
min_length=1,
|
|
132
|
+
description="Upstream requirement source references",
|
|
133
|
+
)
|
|
134
|
+
business_rules: list[BusinessRule] = Field(default_factory=list, description="Imported business rules")
|
|
135
|
+
constraints: list[RequirementConstraint] = Field(default_factory=list, description="Imported constraints")
|
|
136
|
+
evidence_links: list[RequirementEvidenceLink] = Field(default_factory=list, description="Evidence target links")
|
|
137
|
+
completeness_findings: list[RequirementCompletenessFinding] = Field(
|
|
138
|
+
default_factory=list,
|
|
139
|
+
description="Profile-aware advisory completeness findings",
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@beartype
|
|
144
|
+
class RequirementsInputExtensionPayload(BaseModel):
|
|
145
|
+
"""Serializable ProjectBundle extension payload for requirement inputs."""
|
|
146
|
+
|
|
147
|
+
schema_version: Literal["1"] = Field(..., description="Requirements extension payload schema version")
|
|
148
|
+
requirements: list[RequirementInput] = Field(default_factory=list, description="Requirement input records")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _payload_has_schema_version(result: dict[str, Any]) -> bool:
|
|
152
|
+
return result.get("schema_version") == REQUIREMENTS_INPUT_SCHEMA_VERSION
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _payload_has_requirements_list(result: dict[str, Any]) -> bool:
|
|
156
|
+
return isinstance(result.get("requirements"), list)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _payload_is_valid_extension(payload: dict[str, Any]) -> bool:
|
|
160
|
+
try:
|
|
161
|
+
RequirementsInputExtensionPayload.model_validate(payload)
|
|
162
|
+
except ValueError:
|
|
163
|
+
return False
|
|
164
|
+
return True
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@beartype
|
|
168
|
+
@require(lambda records: all(isinstance(record, RequirementInput) for record in records))
|
|
169
|
+
@ensure(_payload_has_schema_version)
|
|
170
|
+
@ensure(_payload_has_requirements_list)
|
|
171
|
+
def requirements_input_extension_payload(records: list[RequirementInput]) -> dict[str, Any]:
|
|
172
|
+
"""Return a JSON-serializable ProjectBundle extension payload."""
|
|
173
|
+
payload = RequirementsInputExtensionPayload(schema_version=REQUIREMENTS_INPUT_SCHEMA_VERSION, requirements=records)
|
|
174
|
+
return cast(dict[str, Any], payload.model_dump(mode="json"))
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@beartype
|
|
178
|
+
@require(lambda payload: isinstance(payload, dict))
|
|
179
|
+
@require(_payload_is_valid_extension)
|
|
180
|
+
@ensure(lambda result: all(isinstance(record, RequirementInput) for record in result))
|
|
181
|
+
def load_requirements_input_extension(payload: dict[str, Any]) -> list[RequirementInput]:
|
|
182
|
+
"""Load requirement input records from a ProjectBundle extension payload."""
|
|
183
|
+
return RequirementsInputExtensionPayload.model_validate(payload).requirements
|
{specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/init/module-package.yaml
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
name: init
|
|
2
|
-
version: 0.1.
|
|
2
|
+
version: 0.1.41
|
|
3
3
|
commands:
|
|
4
4
|
- init
|
|
5
5
|
category: core
|
|
@@ -17,5 +17,5 @@ publisher:
|
|
|
17
17
|
description: Initialize SpecFact workspace and bootstrap local configuration.
|
|
18
18
|
license: Apache-2.0
|
|
19
19
|
integrity:
|
|
20
|
-
checksum: sha256:
|
|
21
|
-
signature:
|
|
20
|
+
checksum: sha256:7ad9c0b623f52a55b45f35adf9576bea1fd47edcd3005ed2354188a6a6ea20f5
|
|
21
|
+
signature: 7ED3ulYnu2VsJvPN/rEVLFHdVdBoiqJg1a8kR1FpWTmz9ZILrT/+NYq3CtnwGIvZscD/8CEBLBqKt1+0fCqZCQ==
|
|
@@ -48,14 +48,7 @@ from specfact_cli.utils.ide_setup import (
|
|
|
48
48
|
)
|
|
49
49
|
|
|
50
50
|
|
|
51
|
-
VALID_PROFILES: frozenset[str] = frozenset(
|
|
52
|
-
{
|
|
53
|
-
"solo-developer",
|
|
54
|
-
"backlog-team",
|
|
55
|
-
"api-first-team",
|
|
56
|
-
"enterprise-full-stack",
|
|
57
|
-
}
|
|
58
|
-
)
|
|
51
|
+
VALID_PROFILES: frozenset[str] = frozenset(first_run_selection.get_valid_profile_names())
|
|
59
52
|
PROFILE_BUNDLES: dict[str, list[str]] = first_run_selection.PROFILE_PRESETS
|
|
60
53
|
|
|
61
54
|
install_bundles_for_init = first_run_selection.install_bundles_for_init
|
|
@@ -709,6 +702,21 @@ def init_ide(
|
|
|
709
702
|
console.print(f"[green]Updated VS Code settings:[/green] {settings_path}")
|
|
710
703
|
|
|
711
704
|
|
|
705
|
+
def _write_profile_config_or_exit(repo_path: Path, profile: str) -> None:
|
|
706
|
+
try:
|
|
707
|
+
first_run_selection.write_profile_config(repo_path, profile)
|
|
708
|
+
except ValueError as e:
|
|
709
|
+
console.print(f"[red]Error:[/red] {e}")
|
|
710
|
+
raise typer.Exit(1) from e
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
def _apply_explicit_profile_or_install(repo_path: Path, profile: str | None, install: str | None) -> list[str]:
|
|
714
|
+
enabled_module_ids = _apply_profile_or_install_bundles(profile, install)
|
|
715
|
+
if profile is not None:
|
|
716
|
+
_write_profile_config_or_exit(repo_path, profile)
|
|
717
|
+
return enabled_module_ids
|
|
718
|
+
|
|
719
|
+
|
|
712
720
|
@app.callback(invoke_without_command=True)
|
|
713
721
|
@require(lambda repo: _is_valid_repo_path(repo), "Repo path must exist and be directory")
|
|
714
722
|
@ensure(lambda result: result is None, "Command should return None")
|
|
@@ -725,7 +733,10 @@ def init(
|
|
|
725
733
|
profile: str | None = typer.Option(
|
|
726
734
|
None,
|
|
727
735
|
"--profile",
|
|
728
|
-
help=
|
|
736
|
+
help=(
|
|
737
|
+
"Validation tier or legacy workflow preset: solo, startup, mid_size, enterprise, "
|
|
738
|
+
"solo-developer, backlog-team, api-first-team, enterprise-full-stack"
|
|
739
|
+
),
|
|
729
740
|
),
|
|
730
741
|
install: str | None = typer.Option(
|
|
731
742
|
None,
|
|
@@ -750,7 +761,7 @@ def init(
|
|
|
750
761
|
|
|
751
762
|
enabled_module_ids: list[str] = []
|
|
752
763
|
if profile is not None or install is not None:
|
|
753
|
-
enabled_module_ids =
|
|
764
|
+
enabled_module_ids = _apply_explicit_profile_or_install(repo_path, profile, install)
|
|
754
765
|
elif is_first_run(user_root=INIT_USER_MODULES_ROOT) and is_non_interactive():
|
|
755
766
|
console.print(
|
|
756
767
|
"[red]Error:[/red] In CI/CD (non-interactive) mode, first-run init requires "
|