specfact-cli 0.46.2__tar.gz → 0.46.9__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.46.2 → specfact_cli-0.46.9}/PKG-INFO +11 -10
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/README.md +4 -3
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/pyproject.toml +40 -25
- specfact_cli-0.46.9/resources/bundled-module-registry/index.json +20 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/__init__.py +1 -1
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/__init__.py +1 -1
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/analyzers/code_analyzer.py +27 -7
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/analyzers/graph_analyzer.py +33 -39
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/cli.py +23 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/modules/init/module-package.yaml +3 -3
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/modules/init/src/commands.py +33 -13
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/modules/module_registry/module-package.yaml +3 -3
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/modules/module_registry/src/commands.py +73 -8
- specfact_cli-0.46.9/src/specfact_cli/registry/module_availability.py +214 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/registry/module_discovery.py +104 -33
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/registry/module_installer.py +46 -4
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/registry/module_packages.py +22 -5
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/optional_deps.py +19 -16
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/project_artifact_write.py +7 -6
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/.gitignore +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/LICENSE +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/resources/keys/README.md +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/resources/keys/module-signing-public.pem +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/resources/mappings/node-async.yaml +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/resources/mappings/python-async.yaml +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/resources/mappings/speckit-default.yaml +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/resources/schemas/deviation.schema.json +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/resources/schemas/plan.schema.json +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/resources/schemas/protocol.schema.json +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/resources/templates/github-action.yml.j2 +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/resources/templates/persona/architect.md.j2 +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/resources/templates/persona/developer.md.j2 +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/resources/templates/persona/product-owner.md.j2 +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/resources/templates/plan.bundle.yaml.j2 +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/resources/templates/policies/kanban.yaml +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/resources/templates/policies/mixed.yaml +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/resources/templates/policies/safe.yaml +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/resources/templates/policies/scrum.yaml +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/resources/templates/pr-template.md.j2 +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/resources/templates/protocol.yaml.j2 +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/resources/templates/telemetry.yaml.example +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/__main__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/adapters/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/adapters/ado.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/adapters/backlog_base.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/adapters/base.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/adapters/github.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/adapters/openspec.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/adapters/openspec_parser.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/adapters/registry.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/adapters/speckit.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/agents/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/agents/analyze_agent.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/agents/base.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/agents/plan_agent.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/agents/registry.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/agents/sync_agent.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/analyzers/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/analyzers/ambiguity_scanner.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/analyzers/constitution_evidence_extractor.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/analyzers/contract_extractor.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/analyzers/control_flow_analyzer.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/analyzers/relationship_mapper.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/analyzers/requirement_extractor.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/analyzers/test_pattern_extractor.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/backlog/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/backlog/adapters/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/backlog/adapters/base.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/backlog/converter.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/backlog/filters.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/backlog/mappers/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/backlog/mappers/ado_mapper.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/backlog/mappers/base.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/backlog/mappers/github_mapper.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/backlog/mappers/template_config.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/commands/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/commands/_bundle_shim.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/commands/analyze.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/commands/contract_cmd.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/commands/drift.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/commands/enforce.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/commands/generate.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/commands/import_cmd.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/commands/init.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/commands/migrate.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/commands/plan.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/commands/project_cmd.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/commands/repro.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/commands/sdd.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/commands/spec.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/commands/sync.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/commands/update.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/commands/validate.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/common/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/common/bundle_factory.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/common/logger_setup.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/common/logging_utils.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/common/text_utils.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/common/utils.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/comparators/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/comparators/plan_comparator.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/contracts/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/contracts/crosshair_props.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/contracts/module_interface.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/enrichers/constitution_enricher.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/enrichers/plan_enricher.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/generators/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/generators/contract_generator.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/generators/openapi_extractor.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/generators/persona_exporter.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/generators/plan_generator.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/generators/protocol_generator.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/generators/report_generator.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/generators/task_generator.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/generators/test_to_openapi.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/generators/workflow_generator.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/groups/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/groups/codebase_group.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/groups/govern_group.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/groups/member_group.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/groups/project_group.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/groups/spec_group.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/importers/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/importers/speckit_converter.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/importers/speckit_scanner.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/integrations/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/integrations/specmatic.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/merge/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/merge/resolver.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/migrations/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/migrations/plan_migrator.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/models/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/models/backlog_item.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/models/bridge.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/models/capabilities.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/models/change.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/models/contract.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/models/deviation.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/models/dor_config.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/models/enforcement.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/models/module_package.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/models/persona_template.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/models/plan.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/models/project.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/models/protocol.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/models/quality.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/models/sdd.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/models/source_tracking.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/models/task.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/models/validation.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/modes/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/modes/detector.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/modes/router.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/modules/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/modules/_bundle_import.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/modules/init/src/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/modules/init/src/app.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/modules/init/src/first_run_selection.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/modules/module_io_shim.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/modules/module_registry/src/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/modules/module_registry/src/app.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/modules/upgrade/module-package.yaml +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/modules/upgrade/src/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/modules/upgrade/src/app.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/modules/upgrade/src/commands.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/parsers/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/parsers/persona_importer.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/registry/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/registry/alias_manager.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/registry/bootstrap.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/registry/bridge_registry.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/registry/crypto_validator.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/registry/custom_registries.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/registry/dependency_resolver.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/registry/extension_registry.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/registry/help_cache.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/registry/marketplace_client.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/registry/metadata.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/registry/module_grouping.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/registry/module_lifecycle.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/registry/module_security.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/registry/module_state.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/registry/registry.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/resources/semgrep/async.yml +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/resources/semgrep/code-quality.yml +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/resources/semgrep/feature-detection.yml +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/runtime.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/sync/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/sync/bridge_probe.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/sync/bridge_sync.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/sync/bridge_sync_openspec_md_parse.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/sync/bridge_sync_requirement_from_proposal.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/sync/bridge_sync_requirement_helpers.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/sync/bridge_sync_tasks_from_proposal.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/sync/bridge_sync_what_changes_format.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/sync/bridge_sync_write_openspec_from_proposal.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/sync/bridge_watch.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/sync/change_detector.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/sync/code_to_spec.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/sync/drift_detector.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/sync/repository_sync.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/sync/spec_to_code.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/sync/spec_to_tests.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/sync/watcher.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/sync/watcher_enhanced.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/telemetry.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/templates/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/templates/defaults/defect_v1.yaml +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/templates/defaults/enabler_v1.yaml +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/templates/defaults/spike_v1.yaml +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/templates/defaults/user_story_v1.yaml +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/templates/frameworks/scrum/user_story_v1.yaml +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/templates/personas/product-owner/user_story_v1.yaml +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/templates/providers/ado/work_item_v1.yaml +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/templates/registry.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/templates/specification_templates.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/acceptance_criteria.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/auth_tokens.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/bundle_converters.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/bundle_loader.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/code_change_detector.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/console.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/content_sanitizer.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/context_detection.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/contract_predicates.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/enrichment_context.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/enrichment_parser.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/env_manager.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/feature_keys.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/git.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/github_annotations.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/icontract_helpers.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/ide_setup.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/incremental_check.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/metadata.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/performance.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/persona_ownership.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/progress.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/progressive_disclosure.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/prompts.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/sdd_discovery.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/source_scanner.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/startup_checks.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/structure.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/structured_io.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/suggestions.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/terminal.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/utils/yaml_utils.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validation/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validation/command_audit.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/agile_validation.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/change_proposal_integration.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/cli_first_validator.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/contract_validator.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/fsm.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/repro_checker.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/schema.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/sidecar/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/sidecar/contract_populator.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/sidecar/crosshair_runner.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/sidecar/crosshair_summary.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/sidecar/dependency_installer.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/sidecar/framework_detector.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/sidecar/frameworks/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/sidecar/frameworks/base.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/sidecar/frameworks/django.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/sidecar/frameworks/drf.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/sidecar/frameworks/fastapi.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/sidecar/frameworks/flask.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/sidecar/harness_generator.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/sidecar/models.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/sidecar/orchestrator.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/sidecar/specmatic_runner.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/validators/sidecar/unannotated_detector.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/src/specfact_cli/versioning/__init__.py +0 -0
- {specfact_cli-0.46.2 → specfact_cli-0.46.9}/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.46.
|
|
3
|
+
Version: 0.46.9
|
|
4
4
|
Summary: The swiss knife CLI for agile DevOps teams. Keep backlog, specs, tests, and code in sync with validation and contract enforcement for new projects and long-lived codebases.
|
|
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
|
|
@@ -224,12 +224,12 @@ Classifier: Topic :: Software Development :: Testing
|
|
|
224
224
|
Requires-Python: >=3.11
|
|
225
225
|
Requires-Dist: azure-identity>=1.17.1
|
|
226
226
|
Requires-Dist: beartype>=0.22.4
|
|
227
|
+
Requires-Dist: commentjson>=0.9.0
|
|
227
228
|
Requires-Dist: cryptography>=43.0.0
|
|
228
229
|
Requires-Dist: gitpython>=3.1.45
|
|
229
230
|
Requires-Dist: graphviz>=0.20.1
|
|
230
231
|
Requires-Dist: icontract>=2.7.1
|
|
231
232
|
Requires-Dist: jinja2>=3.1.6
|
|
232
|
-
Requires-Dist: json5>=0.9.28
|
|
233
233
|
Requires-Dist: jsonschema>=4.23.0
|
|
234
234
|
Requires-Dist: networkx>=3.4.2
|
|
235
235
|
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.27.0
|
|
@@ -248,16 +248,18 @@ Provides-Extra: contracts
|
|
|
248
248
|
Requires-Dist: crosshair-tool>=0.0.97; extra == 'contracts'
|
|
249
249
|
Requires-Dist: hypothesis>=6.142.4; extra == 'contracts'
|
|
250
250
|
Provides-Extra: dev
|
|
251
|
+
Requires-Dist: bandit>=1.7.0; extra == 'dev'
|
|
251
252
|
Requires-Dist: basedpyright>=1.32.1; extra == 'dev'
|
|
252
|
-
Requires-Dist: bearer>=3.1.0; extra == 'dev'
|
|
253
253
|
Requires-Dist: beartype>=0.22.4; extra == 'dev'
|
|
254
254
|
Requires-Dist: crosshair-tool>=0.0.97; extra == 'dev'
|
|
255
255
|
Requires-Dist: graphviz>=0.20.1; extra == 'dev'
|
|
256
256
|
Requires-Dist: hypothesis>=6.142.4; extra == 'dev'
|
|
257
257
|
Requires-Dist: icontract>=2.7.1; extra == 'dev'
|
|
258
258
|
Requires-Dist: isort>=7.0.0; extra == 'dev'
|
|
259
|
+
Requires-Dist: pip-audit>=2.0.0; extra == 'dev'
|
|
260
|
+
Requires-Dist: pip-licenses>=4.0.0; extra == 'dev'
|
|
259
261
|
Requires-Dist: pip-tools>=7.5.1; extra == 'dev'
|
|
260
|
-
Requires-Dist:
|
|
262
|
+
Requires-Dist: pycg==0.0.7; extra == 'dev'
|
|
261
263
|
Requires-Dist: pylint>=4.0.2; extra == 'dev'
|
|
262
264
|
Requires-Dist: pytest-asyncio>=1.2.0; extra == 'dev'
|
|
263
265
|
Requires-Dist: pytest-cov>=7.0.0; extra == 'dev'
|
|
@@ -271,10 +273,8 @@ Requires-Dist: setuptools<82,>=69.0.0; extra == 'dev'
|
|
|
271
273
|
Requires-Dist: tomlkit>=0.13.3; extra == 'dev'
|
|
272
274
|
Requires-Dist: types-pyyaml>=6.0.12.20250516; extra == 'dev'
|
|
273
275
|
Provides-Extra: enhanced-analysis
|
|
274
|
-
Requires-Dist: bearer>=3.1.0; extra == 'enhanced-analysis'
|
|
275
276
|
Requires-Dist: graphviz>=0.20.1; extra == 'enhanced-analysis'
|
|
276
|
-
Requires-Dist:
|
|
277
|
-
Requires-Dist: syft>=0.9.5; extra == 'enhanced-analysis'
|
|
277
|
+
Requires-Dist: pycg==0.0.7; extra == 'enhanced-analysis'
|
|
278
278
|
Provides-Extra: scanning
|
|
279
279
|
Requires-Dist: semgrep>=1.144.0; extra == 'scanning'
|
|
280
280
|
Description-Content-Type: text/markdown
|
|
@@ -308,7 +308,7 @@ uvx specfact-cli code review run --path . --scope full
|
|
|
308
308
|
**Sample output:**
|
|
309
309
|
|
|
310
310
|
```text
|
|
311
|
-
SpecFact CLI - v0.46.
|
|
311
|
+
SpecFact CLI - v0.46.4
|
|
312
312
|
|
|
313
313
|
Running Ruff checks...
|
|
314
314
|
Running Radon complexity checks...
|
|
@@ -367,14 +367,15 @@ This repository uses a **modular** local hook layout (parity with `specfact-cli-
|
|
|
367
367
|
separate verify / format / YAML / Markdown / workflow / lint / Block 2 hooks). If you copy
|
|
368
368
|
[`.pre-commit-config.yaml`](.pre-commit-config.yaml) into another repo, you must also vendor the
|
|
369
369
|
referenced `scripts/*.sh` entrypoints (at minimum `scripts/pre-commit-quality-checks.sh`,
|
|
370
|
-
`scripts/pre-commit-verify-modules.sh`,
|
|
370
|
+
`scripts/pre-commit-verify-modules.sh`, `scripts/module-verify-policy.sh`, and
|
|
371
|
+
`scripts/git-branch-module-signature-flag.sh`) so hook
|
|
371
372
|
`entry:` paths resolve. Alternatively, skip vendoring the modular file and use the remote hook below.
|
|
372
373
|
|
|
373
374
|
For a **single-hook** setup in downstream repos, keep using the stable id and script shim:
|
|
374
375
|
|
|
375
376
|
```yaml
|
|
376
377
|
- repo: https://github.com/nold-ai/specfact-cli
|
|
377
|
-
rev: v0.46.
|
|
378
|
+
rev: v0.46.4
|
|
378
379
|
hooks:
|
|
379
380
|
- id: specfact-smart-checks
|
|
380
381
|
```
|
|
@@ -27,7 +27,7 @@ uvx specfact-cli code review run --path . --scope full
|
|
|
27
27
|
**Sample output:**
|
|
28
28
|
|
|
29
29
|
```text
|
|
30
|
-
SpecFact CLI - v0.46.
|
|
30
|
+
SpecFact CLI - v0.46.4
|
|
31
31
|
|
|
32
32
|
Running Ruff checks...
|
|
33
33
|
Running Radon complexity checks...
|
|
@@ -86,14 +86,15 @@ This repository uses a **modular** local hook layout (parity with `specfact-cli-
|
|
|
86
86
|
separate verify / format / YAML / Markdown / workflow / lint / Block 2 hooks). If you copy
|
|
87
87
|
[`.pre-commit-config.yaml`](.pre-commit-config.yaml) into another repo, you must also vendor the
|
|
88
88
|
referenced `scripts/*.sh` entrypoints (at minimum `scripts/pre-commit-quality-checks.sh`,
|
|
89
|
-
`scripts/pre-commit-verify-modules.sh`,
|
|
89
|
+
`scripts/pre-commit-verify-modules.sh`, `scripts/module-verify-policy.sh`, and
|
|
90
|
+
`scripts/git-branch-module-signature-flag.sh`) so hook
|
|
90
91
|
`entry:` paths resolve. Alternatively, skip vendoring the modular file and use the remote hook below.
|
|
91
92
|
|
|
92
93
|
For a **single-hook** setup in downstream repos, keep using the stable id and script shim:
|
|
93
94
|
|
|
94
95
|
```yaml
|
|
95
96
|
- repo: https://github.com/nold-ai/specfact-cli
|
|
96
|
-
rev: v0.46.
|
|
97
|
+
rev: v0.46.4
|
|
97
98
|
hooks:
|
|
98
99
|
- id: specfact-smart-checks
|
|
99
100
|
```
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "specfact-cli"
|
|
7
|
-
version = "0.46.
|
|
7
|
+
version = "0.46.9"
|
|
8
8
|
description = "The swiss knife CLI for agile DevOps teams. Keep backlog, specs, tests, and code in sync with validation and contract enforcement for new projects and long-lived codebases."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -77,6 +77,7 @@ dependencies = [
|
|
|
77
77
|
"graphviz>=0.20.1", # Graph visualization (requires system Graphviz: apt-get install graphviz)
|
|
78
78
|
|
|
79
79
|
# Git operations
|
|
80
|
+
# gitpython: CVE history (CVE-2022-24439, CVE-2023-41040, CVE-2023-40590). Phase 2: replace with dulwich.
|
|
80
81
|
"gitpython>=3.1.45",
|
|
81
82
|
|
|
82
83
|
# YAML utilities
|
|
@@ -84,8 +85,8 @@ dependencies = [
|
|
|
84
85
|
|
|
85
86
|
# Schema validation
|
|
86
87
|
"jsonschema>=4.23.0",
|
|
87
|
-
# VS Code settings.json is
|
|
88
|
-
"
|
|
88
|
+
# VS Code settings.json is JSONC (comments + trailing commas); commentjson (MIT) strips them, delegates to stdlib json
|
|
89
|
+
"commentjson>=0.9.0",
|
|
89
90
|
|
|
90
91
|
# Contract-First (runtime decorators; exploration tools are optional extra `contracts`)
|
|
91
92
|
"icontract>=2.7.1", # Design-by-contract decorators
|
|
@@ -114,13 +115,13 @@ dev = [
|
|
|
114
115
|
"pytest-xdist>=3.8.0",
|
|
115
116
|
"basedpyright>=1.32.1",
|
|
116
117
|
"isort>=7.0.0",
|
|
117
|
-
"pylint>=4.0.2",
|
|
118
|
+
"pylint>=4.0.2", # GPL-2.0-or-later — dev-only exception (not in module manifests). Phase 2: replace with ruff --select ALL.
|
|
118
119
|
"ruff>=0.14.2",
|
|
119
120
|
"radon>=6.0.1",
|
|
120
121
|
"tomlkit>=0.13.3", # Style-preserving TOML library (recommended successor to pytoml)
|
|
121
122
|
"types-PyYAML>=6.0.12.20250516",
|
|
122
123
|
"pip-tools>=7.5.1",
|
|
123
|
-
"semgrep>=1.144.0", #
|
|
124
|
+
"semgrep>=1.144.0", # LGPL-2.1 — required for code analysis; invoked as subprocess (accepted exception)
|
|
124
125
|
|
|
125
126
|
# Same contract exploration stack as [contracts] (extras cannot self-reference)
|
|
126
127
|
"crosshair-tool>=0.0.97",
|
|
@@ -131,11 +132,14 @@ dev = [
|
|
|
131
132
|
"beartype>=0.22.4",
|
|
132
133
|
|
|
133
134
|
# Enhanced Analysis Tools (for local development)
|
|
134
|
-
# Note: syft excluded from dev/test due to rich version conflict with semgrep
|
|
135
|
-
# Install separately: pip install specfact-cli[enhanced-analysis] if needed
|
|
136
135
|
"graphviz>=0.20.1", # Graph visualization (requires system Graphviz: apt-get install graphviz)
|
|
137
|
-
"
|
|
138
|
-
|
|
136
|
+
"pycg==0.0.7", # Python call graph analysis (Apache-2.0; replaces removed GPL-2.0 pyan3; pin avoids 0.0.8)
|
|
137
|
+
# Removed from dev: pyan3 (GPL-2.0) and bearer (wrong PyPI package; SaaS auth, not scanner)
|
|
138
|
+
# syft removed — wrong PyPI package (OpenMined ML framework, not Anchore SBOM)
|
|
139
|
+
"bandit>=1.7.0", # SAST scanner (MIT)
|
|
140
|
+
"pip-licenses>=4.0.0", # License enumeration for compliance gate (MIT)
|
|
141
|
+
"pip-audit>=2.0.0", # CVE audit via OSV database (Apache-2.0)
|
|
142
|
+
# pylint: GPL-2.0-or-later — dev-only exception (not in module manifests). Phase 2: replace with ruff --select ALL.
|
|
139
143
|
]
|
|
140
144
|
|
|
141
145
|
scanning = [
|
|
@@ -144,9 +148,8 @@ scanning = [
|
|
|
144
148
|
|
|
145
149
|
enhanced-analysis = [
|
|
146
150
|
"graphviz>=0.20.1", # Graph visualization (requires system Graphviz: apt-get install graphviz)
|
|
147
|
-
"
|
|
148
|
-
|
|
149
|
-
"bearer>=3.1.0", # Data flow analysis for security
|
|
151
|
+
"pycg==0.0.7", # Python call graph analysis (Apache-2.0; replaces removed GPL-2.0 pyan3; pin avoids 0.0.8)
|
|
152
|
+
# Removed from enhanced-analysis: pyan3 (GPL-2.0), bearer, and syft (wrong PyPI packages)
|
|
150
153
|
]
|
|
151
154
|
|
|
152
155
|
# Note: Specmatic integration (specfact spec commands) requires the Specmatic CLI tool
|
|
@@ -188,29 +191,37 @@ dependencies = [
|
|
|
188
191
|
"pylint>=4.0.2",
|
|
189
192
|
"ruff>=0.14.2",
|
|
190
193
|
"radon>=6.0.1",
|
|
191
|
-
"yamllint>=1.37.1",
|
|
192
|
-
"semgrep>=1.144.0", #
|
|
194
|
+
"yamllint>=1.37.1", # GPL-3.0-or-later — dev/test-only exception. Phase 2: replace with non-GPL YAML lint path.
|
|
195
|
+
"semgrep>=1.144.0", # LGPL-2.1 — required for code analysis; invoked as subprocess (accepted exception)
|
|
193
196
|
# Contract-First Development Dependencies
|
|
194
197
|
"icontract>=2.7.1",
|
|
195
|
-
"beartype>=0.22.4",
|
|
198
|
+
"beartype>=0.22.4",
|
|
196
199
|
"crosshair-tool>=0.0.97",
|
|
197
200
|
"hypothesis>=6.142.4",
|
|
198
201
|
# Enhanced Analysis Tools (for local development)
|
|
199
|
-
# Note: syft excluded from dev/test due to rich version conflict with semgrep
|
|
200
|
-
# Install separately: pip install specfact-cli[enhanced-analysis] if needed
|
|
201
202
|
"graphviz>=0.20.1", # Graph visualization (requires system Graphviz: apt-get install graphviz)
|
|
202
|
-
"
|
|
203
|
-
|
|
203
|
+
"pycg==0.0.7", # Python call graph analysis (Apache-2.0; replaces removed GPL-2.0 pyan3; pin avoids 0.0.8)
|
|
204
|
+
# Removed from Hatch default: pyan3 (GPL-2.0), bearer, and syft (wrong PyPI packages)
|
|
205
|
+
"bandit>=1.7.0", # SAST scanner (MIT)
|
|
206
|
+
"pip-licenses>=4.0.0", # License enumeration for compliance gate (MIT)
|
|
207
|
+
"pip-audit>=2.0.0", # CVE audit via OSV database (Apache-2.0)
|
|
208
|
+
# pylint: GPL-2.0-or-later — dev-only exception (not in module manifests). Phase 2: replace with ruff --select ALL.
|
|
204
209
|
]
|
|
205
210
|
|
|
206
211
|
[tool.hatch.envs.default.scripts]
|
|
207
212
|
validate-prompts = "python tools/validate_prompts.py"
|
|
213
|
+
# Security and license compliance gates
|
|
214
|
+
bandit-scan = "bandit -r src/ -ll"
|
|
215
|
+
license-check = "python scripts/check_license_compliance.py"
|
|
216
|
+
# Wrap pip-audit so JSON parsing and CVSS threshold checks fail closed.
|
|
217
|
+
security-audit = "python scripts/security_audit_gate.py"
|
|
208
218
|
# Development scripts
|
|
209
219
|
test = "pytest {args}"
|
|
210
220
|
test-cov = "pytest --cov=src --cov-report=term-missing {args}"
|
|
211
221
|
type-check = "basedpyright --pythonpath $(python -c 'import sys; print(sys.executable)') {args}"
|
|
212
222
|
# basedpyright --level error: suppress warning noise in pre-commit (Block 1 runs `hatch run lint`).
|
|
213
223
|
lint = "ruff format . --check && basedpyright --level error --pythonpath $(python -c 'import sys; print(sys.executable)') && ruff check . && pylint src tests tools && python scripts/verify_safe_project_writes.py"
|
|
224
|
+
lint-changed = "python scripts/run_changed_lint.py {args}"
|
|
214
225
|
governance = "pylint src tests tools --reports=y --output-format=parseable"
|
|
215
226
|
format = "ruff check . --fix && ruff format ."
|
|
216
227
|
|
|
@@ -261,10 +272,15 @@ smart-test-e2e = "python tools/smart_test_coverage.py run --level e2e {args}"
|
|
|
261
272
|
smart-test-full = "python tools/smart_test_coverage.py run --level full {args}"
|
|
262
273
|
smart-test-auto = "python tools/smart_test_coverage.py run --level auto {args}"
|
|
263
274
|
|
|
275
|
+
# Bundled module verify (flags from scripts/module-verify-policy.sh via run_verify_modules_policy.sh)
|
|
276
|
+
verify-modules-signature = "bash scripts/run_verify_modules_policy.sh strict {args}"
|
|
277
|
+
verify-modules-signature-pr = "bash scripts/run_verify_modules_policy.sh pr {args}"
|
|
278
|
+
verify-modules-signature-push = "bash scripts/run_verify_modules_policy.sh push-orchestrator {args}"
|
|
279
|
+
|
|
264
280
|
# Module migration pre-deletion gate
|
|
265
281
|
verify-removal-gate = [
|
|
266
282
|
"python scripts/verify-bundle-published.py --modules project,plan,import_cmd,sync,migrate,backlog,policy_engine,analyze,drift,validate,repro,contract,spec,sdd,generate,enforce,patch_mode",
|
|
267
|
-
"
|
|
283
|
+
"hatch run verify-modules-signature",
|
|
268
284
|
]
|
|
269
285
|
export-change-github = "python scripts/export-change-to-github.py {args}"
|
|
270
286
|
|
|
@@ -314,13 +330,12 @@ dependencies = [
|
|
|
314
330
|
"beartype>=0.22.4",
|
|
315
331
|
"crosshair-tool>=0.0.97",
|
|
316
332
|
"hypothesis>=6.142.4",
|
|
317
|
-
"yamllint>=1.37.1",
|
|
333
|
+
"yamllint>=1.37.1", # GPL-3.0-or-later — dev/test-only exception. Phase 2: replace with non-GPL YAML lint path.
|
|
318
334
|
# Enhanced Analysis Tools (for testing)
|
|
319
|
-
# Note: syft excluded from test due to rich version conflict with semgrep
|
|
320
|
-
# Install separately: pip install specfact-cli[enhanced-analysis] if needed
|
|
321
335
|
"graphviz>=0.20.1", # Graph visualization (requires system Graphviz: apt-get install graphviz)
|
|
322
|
-
"
|
|
323
|
-
|
|
336
|
+
"pycg==0.0.7", # Python call graph analysis (Apache-2.0; replaces removed GPL-2.0 pyan3; pin avoids 0.0.8)
|
|
337
|
+
# Removed from Hatch test: pyan3 (GPL-2.0), bearer, and syft (wrong PyPI packages)
|
|
338
|
+
"commentjson>=0.9.0", # JSONC parser (MIT; replaces json5 for VS Code settings JSONC support)
|
|
324
339
|
]
|
|
325
340
|
dev-mode = true
|
|
326
341
|
parallel = true
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"modules": [
|
|
3
|
+
{
|
|
4
|
+
"id": "init",
|
|
5
|
+
"latest_version": "0.1.30"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"id": "upgrade",
|
|
9
|
+
"latest_version": "0.1.4"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"id": "module-registry",
|
|
13
|
+
"latest_version": "0.1.19"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"id": "bundle-mapper",
|
|
17
|
+
"latest_version": "0.1.9"
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -32,6 +32,24 @@ from specfact_cli.utils.feature_keys import to_classname_key, to_sequential_key
|
|
|
32
32
|
console = Console()
|
|
33
33
|
|
|
34
34
|
|
|
35
|
+
def _ensure_semgrep_runtime_dir(repo_path: Path, relative: str) -> str:
|
|
36
|
+
"""Create and return a stable repo-local runtime directory for Semgrep."""
|
|
37
|
+
path = (repo_path / relative).resolve()
|
|
38
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
39
|
+
return str(path)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _build_semgrep_env(repo_path: Path) -> dict[str, str]:
|
|
43
|
+
"""Build a repo-local Semgrep runtime env so CLI startup stays deterministic."""
|
|
44
|
+
env = dict(os.environ)
|
|
45
|
+
env["XDG_CONFIG_HOME"] = _ensure_semgrep_runtime_dir(repo_path, ".specfact/config")
|
|
46
|
+
env["XDG_CACHE_HOME"] = _ensure_semgrep_runtime_dir(repo_path, ".specfact/cache")
|
|
47
|
+
env["SEMGREP_VERSION_CACHE_PATH"] = _ensure_semgrep_runtime_dir(repo_path, ".specfact/cache/semgrep")
|
|
48
|
+
semgrep_log_dir = _ensure_semgrep_runtime_dir(repo_path, ".specfact/logs")
|
|
49
|
+
env["SEMGREP_LOG_FILE"] = str((Path(semgrep_log_dir) / "semgrep.log").resolve())
|
|
50
|
+
return env
|
|
51
|
+
|
|
52
|
+
|
|
35
53
|
@dataclass
|
|
36
54
|
class _SemgrepFeatureBuckets:
|
|
37
55
|
api_endpoints: list[str] = field(default_factory=list)
|
|
@@ -457,6 +475,7 @@ class CodeAnalyzer:
|
|
|
457
475
|
capture_output=True,
|
|
458
476
|
text=True,
|
|
459
477
|
timeout=5, # Increased timeout to 5s (Semgrep may need time to initialize)
|
|
478
|
+
env=_build_semgrep_env(self.repo_path),
|
|
460
479
|
)
|
|
461
480
|
return result.returncode == 0
|
|
462
481
|
except (FileNotFoundError, subprocess.TimeoutExpired, OSError):
|
|
@@ -507,16 +526,16 @@ class CodeAnalyzer:
|
|
|
507
526
|
}
|
|
508
527
|
)
|
|
509
528
|
|
|
510
|
-
# Dependency Graph Analysis (requires
|
|
511
|
-
|
|
529
|
+
# Dependency Graph Analysis (requires pycg and networkx)
|
|
530
|
+
pycg_available, _ = check_cli_tool_available("pycg")
|
|
512
531
|
networkx_available = check_python_package_available("networkx")
|
|
513
|
-
graph_enabled =
|
|
532
|
+
graph_enabled = pycg_available and networkx_available
|
|
514
533
|
graph_used = graph_enabled # Used if both dependencies are available
|
|
515
534
|
|
|
516
|
-
if not
|
|
517
|
-
reason = "
|
|
518
|
-
elif not
|
|
519
|
-
reason = "
|
|
535
|
+
if not pycg_available and not networkx_available:
|
|
536
|
+
reason = "pycg and networkx not installed (install: pip install pycg networkx)"
|
|
537
|
+
elif not pycg_available:
|
|
538
|
+
reason = "pycg not installed (install: pip install pycg)"
|
|
520
539
|
elif not networkx_available:
|
|
521
540
|
reason = "networkx not installed (install: pip install networkx)"
|
|
522
541
|
else:
|
|
@@ -566,6 +585,7 @@ class CodeAnalyzer:
|
|
|
566
585
|
capture_output=True,
|
|
567
586
|
text=True,
|
|
568
587
|
timeout=timeout,
|
|
588
|
+
env=_build_semgrep_env(self.repo_path),
|
|
569
589
|
)
|
|
570
590
|
|
|
571
591
|
# Semgrep may return non-zero for valid findings
|
|
@@ -3,6 +3,8 @@ Graph-based dependency and call graph analysis.
|
|
|
3
3
|
|
|
4
4
|
Enhances AST and Semgrep analysis with graph-based dependency tracking,
|
|
5
5
|
call graph extraction, and architecture visualization.
|
|
6
|
+
|
|
7
|
+
Call graph extraction uses pycg (MIT) via subprocess. pyan3 (GPL-2.0) removed.
|
|
6
8
|
"""
|
|
7
9
|
|
|
8
10
|
from __future__ import annotations
|
|
@@ -28,7 +30,7 @@ class GraphAnalyzer:
|
|
|
28
30
|
"""
|
|
29
31
|
Graph-based dependency and call graph analysis.
|
|
30
32
|
|
|
31
|
-
Uses
|
|
33
|
+
Uses pycg for call graphs, NetworkX for dependency graphs,
|
|
32
34
|
and provides graph-based insights to complement AST and Semgrep.
|
|
33
35
|
"""
|
|
34
36
|
|
|
@@ -55,7 +57,7 @@ class GraphAnalyzer:
|
|
|
55
57
|
@ensure(lambda result: isinstance(result, dict), "Must return dict")
|
|
56
58
|
def extract_call_graph(self, file_path: Path) -> dict[str, list[str]]:
|
|
57
59
|
"""
|
|
58
|
-
Extract call graph using
|
|
60
|
+
Extract call graph using pycg (MIT).
|
|
59
61
|
|
|
60
62
|
Args:
|
|
61
63
|
file_path: Path to Python file
|
|
@@ -63,75 +65,67 @@ class GraphAnalyzer:
|
|
|
63
65
|
Returns:
|
|
64
66
|
Dictionary mapping function names to list of called functions
|
|
65
67
|
"""
|
|
66
|
-
# Check if pyan3 is available using utility function
|
|
67
68
|
from specfact_cli.utils.optional_deps import check_cli_tool_available
|
|
68
69
|
|
|
69
|
-
is_available, _ = check_cli_tool_available("
|
|
70
|
+
is_available, _ = check_cli_tool_available("pycg")
|
|
70
71
|
if not is_available:
|
|
71
|
-
#
|
|
72
|
+
# pycg not available — return empty (graceful degradation)
|
|
72
73
|
return {}
|
|
73
74
|
|
|
74
|
-
# Run
|
|
75
|
-
with tempfile.NamedTemporaryFile(mode="w", suffix=".
|
|
76
|
-
|
|
75
|
+
# Run pycg to generate JSON call graph
|
|
76
|
+
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as json_file:
|
|
77
|
+
json_path = Path(json_file.name)
|
|
77
78
|
try:
|
|
78
79
|
result = subprocess.run(
|
|
79
|
-
["
|
|
80
|
-
stdout=dot_file,
|
|
80
|
+
["pycg", "--package", str(self.repo_path), str(file_path), "--output", str(json_path)],
|
|
81
81
|
stderr=subprocess.PIPE,
|
|
82
82
|
text=True,
|
|
83
|
-
timeout=15,
|
|
83
|
+
timeout=15,
|
|
84
84
|
)
|
|
85
85
|
|
|
86
86
|
if result.returncode == 0:
|
|
87
|
-
|
|
88
|
-
call_graph = self._parse_dot_file(dot_path)
|
|
87
|
+
call_graph = self._parse_pycg_json(json_path)
|
|
89
88
|
file_key = str(file_path.relative_to(self.repo_path))
|
|
90
89
|
self.call_graphs[file_key] = call_graph
|
|
91
90
|
return call_graph
|
|
92
91
|
finally:
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
dot_path.unlink()
|
|
92
|
+
if json_path.exists():
|
|
93
|
+
json_path.unlink()
|
|
96
94
|
|
|
97
95
|
return {}
|
|
98
96
|
|
|
99
97
|
@beartype
|
|
100
|
-
@require(lambda
|
|
98
|
+
@require(lambda json_path: isinstance(json_path, Path), "JSON path must be Path")
|
|
101
99
|
@ensure(lambda result: isinstance(result, dict), "Must return dict")
|
|
102
|
-
def
|
|
100
|
+
def _parse_pycg_json(self, json_path: Path) -> dict[str, list[str]]:
|
|
103
101
|
"""
|
|
104
|
-
Parse
|
|
102
|
+
Parse pycg JSON output into caller → [callees] format.
|
|
103
|
+
|
|
104
|
+
PyCG's simple JSON format is an adjacency list: edge ``(src, dst)`` is
|
|
105
|
+
``dst`` in the list for key ``src`` (caller → callees). See PyCG README
|
|
106
|
+
"Simple JSON format".
|
|
105
107
|
|
|
106
108
|
Args:
|
|
107
|
-
|
|
109
|
+
json_path: Path to pycg JSON output file
|
|
108
110
|
|
|
109
111
|
Returns:
|
|
110
112
|
Dictionary mapping function names to list of called functions
|
|
111
113
|
"""
|
|
112
|
-
|
|
114
|
+
import json
|
|
113
115
|
|
|
114
|
-
if not
|
|
116
|
+
if not json_path.exists():
|
|
115
117
|
return {}
|
|
116
118
|
|
|
117
119
|
try:
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
for match in matches:
|
|
127
|
-
caller = match.group(1)
|
|
128
|
-
callee = match.group(2)
|
|
129
|
-
# Filter out internal Python functions (start with __)
|
|
120
|
+
raw: dict[str, list[str]] = json.loads(json_path.read_text(encoding="utf-8"))
|
|
121
|
+
except (json.JSONDecodeError, UnicodeDecodeError, OSError):
|
|
122
|
+
return {}
|
|
123
|
+
|
|
124
|
+
call_graph: dict[str, list[str]] = defaultdict(list)
|
|
125
|
+
for caller, callees in raw.items():
|
|
126
|
+
for callee in callees:
|
|
130
127
|
if not caller.startswith("__") and not callee.startswith("__"):
|
|
131
128
|
call_graph[caller].append(callee)
|
|
132
|
-
except (UnicodeDecodeError, Exception):
|
|
133
|
-
# Skip if parsing fails
|
|
134
|
-
pass
|
|
135
129
|
|
|
136
130
|
return dict(call_graph)
|
|
137
131
|
|
|
@@ -209,7 +203,7 @@ class GraphAnalyzer:
|
|
|
209
203
|
wait_on_shutdown: bool,
|
|
210
204
|
progress_callback: Any | None,
|
|
211
205
|
) -> None:
|
|
212
|
-
"""Populate graph with edges derived from
|
|
206
|
+
"""Populate graph with edges derived from pycg call graphs (parallel phase 2)."""
|
|
213
207
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
214
208
|
|
|
215
209
|
loaded_contents = self._load_python_file_contents_index(python_files)
|
|
@@ -238,7 +232,7 @@ class GraphAnalyzer:
|
|
|
238
232
|
"""
|
|
239
233
|
Build comprehensive dependency graph using NetworkX.
|
|
240
234
|
|
|
241
|
-
Combines AST-based imports with
|
|
235
|
+
Combines AST-based imports with pycg call graphs for complete
|
|
242
236
|
dependency tracking.
|
|
243
237
|
|
|
244
238
|
Args:
|
|
@@ -66,6 +66,7 @@ from specfact_cli.registry import CommandRegistry
|
|
|
66
66
|
from specfact_cli.registry.alias_manager import resolve_command
|
|
67
67
|
from specfact_cli.registry.bootstrap import register_builtin_commands
|
|
68
68
|
from specfact_cli.registry.metadata import CommandMetadata
|
|
69
|
+
from specfact_cli.registry.module_availability import ModuleAvailabilityStatus, classify_module_availability
|
|
69
70
|
from specfact_cli.runtime import get_configured_console, init_debug_log_file, set_debug_mode
|
|
70
71
|
from specfact_cli.utils.progressive_disclosure import ProgressiveDisclosureGroup
|
|
71
72
|
from specfact_cli.utils.structured_io import StructuredFormat
|
|
@@ -124,6 +125,28 @@ def _print_missing_bundle_command_help(invoked: str) -> None:
|
|
|
124
125
|
module_id = _INVOKED_TO_MARKETPLACE_MODULE.get(invoked)
|
|
125
126
|
console = get_configured_console()
|
|
126
127
|
if module_id is not None:
|
|
128
|
+
availability = classify_module_availability(module_id=module_id, command_name=invoked)
|
|
129
|
+
if availability.status is ModuleAvailabilityStatus.DISABLED:
|
|
130
|
+
console.print(
|
|
131
|
+
f"[bold red]Module '{availability.module_id or module_id}' is installed but disabled.[/bold red]\n"
|
|
132
|
+
f"The [bold]{invoked}[/bold] command group is provided by that module. "
|
|
133
|
+
f"Enable with [bold]{availability.recovery_command}[/bold]."
|
|
134
|
+
)
|
|
135
|
+
return
|
|
136
|
+
if availability.status is ModuleAvailabilityStatus.SKIPPED:
|
|
137
|
+
console.print(
|
|
138
|
+
f"[bold red]Module '{availability.module_id or module_id}' is installed but skipped.[/bold red]\n"
|
|
139
|
+
f"Reason: {availability.reason}. "
|
|
140
|
+
"Inspect with [bold]specfact module list --show-origin[/bold]."
|
|
141
|
+
)
|
|
142
|
+
return
|
|
143
|
+
if availability.status is ModuleAvailabilityStatus.SHADOWED:
|
|
144
|
+
console.print(
|
|
145
|
+
f"[bold red]Module '{availability.module_id or module_id}' is shadowed in this workspace.[/bold red]\n"
|
|
146
|
+
f"Shadowed by: {availability.shadowed_by}. "
|
|
147
|
+
"Inspect with [bold]specfact module list --show-origin[/bold]."
|
|
148
|
+
)
|
|
149
|
+
return
|
|
127
150
|
console.print(
|
|
128
151
|
f"[bold red]Module '{module_id}' is not installed.[/bold red]\n"
|
|
129
152
|
f"The [bold]{invoked}[/bold] command group is provided by that module. "
|
{specfact_cli-0.46.2 → specfact_cli-0.46.9}/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.31
|
|
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:0f7bc54a823bea14033fcb143ecb6c83d2bca2b5da661f03a0b545100acebe5b
|
|
21
|
+
signature: dTatkqgBUtti4tL/pmcFBZY9bsJ61gY/V0lP9gZU8Y5W3YWK+wpgRx1oewlAmfKzkxca2NhalKcjLACQjTNvAA==
|