specfact-cli 0.25.1__tar.gz → 0.25.2__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.25.1 → specfact_cli-0.25.2}/PKG-INFO +1 -1
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/pyproject.toml +1 -1
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/__init__.py +1 -1
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/__init__.py +1 -1
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/adapters/ado.py +32 -4
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/adapters/github.py +40 -8
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/sync/bridge_sync.py +1582 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/.gitignore +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/LICENSE.md +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/README.md +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/mappings/node-async.yaml +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/mappings/python-async.yaml +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/mappings/speckit-default.yaml +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/prompts/shared/cli-enforcement.md +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/prompts/specfact.01-import.md +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/prompts/specfact.02-plan.md +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/prompts/specfact.03-review.md +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/prompts/specfact.04-sdd.md +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/prompts/specfact.05-enforce.md +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/prompts/specfact.06-sync.md +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/prompts/specfact.07-contracts.md +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/prompts/specfact.compare.md +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/prompts/specfact.sync-backlog.md +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/prompts/specfact.validate.md +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/schemas/deviation.schema.json +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/schemas/plan.schema.json +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/schemas/protocol.schema.json +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/github-action.yml.j2 +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/persona/architect.md.j2 +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/persona/developer.md.j2 +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/persona/product-owner.md.j2 +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/plan.bundle.yaml.j2 +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/pr-template.md.j2 +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/protocol.yaml.j2 +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/sidecar/STRUCTURE.md +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/sidecar/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/sidecar/common/README.md +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/sidecar/common/adapters.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/sidecar/common/bindings.yaml.example +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/sidecar/common/crosshair_plugin.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/sidecar/common/generate_harness.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/sidecar/common/harness_contracts.py.example +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/sidecar/common/populate_contracts.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/sidecar/common/run_sidecar.sh +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/sidecar/common/sidecar-init.sh +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/sidecar/frameworks/django/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/sidecar/frameworks/django/crosshair_django_wrapper.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/sidecar/frameworks/django/django_form_extractor.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/sidecar/frameworks/django/django_url_extractor.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/sidecar/frameworks/drf/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/sidecar/frameworks/drf/drf_serializer_extractor.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/sidecar/frameworks/fastapi/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/sidecar/frameworks/fastapi/fastapi_route_extractor.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/resources/templates/telemetry.yaml.example +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/adapters/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/adapters/backlog_base.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/adapters/base.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/adapters/openspec.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/adapters/openspec_parser.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/adapters/registry.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/adapters/speckit.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/agents/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/agents/analyze_agent.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/agents/base.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/agents/plan_agent.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/agents/registry.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/agents/sync_agent.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/analyzers/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/analyzers/ambiguity_scanner.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/analyzers/code_analyzer.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/analyzers/constitution_evidence_extractor.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/analyzers/contract_extractor.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/analyzers/control_flow_analyzer.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/analyzers/graph_analyzer.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/analyzers/relationship_mapper.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/analyzers/requirement_extractor.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/analyzers/test_pattern_extractor.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/cli.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/commands/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/commands/analyze.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/commands/contract_cmd.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/commands/drift.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/commands/enforce.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/commands/generate.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/commands/import_cmd.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/commands/init.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/commands/migrate.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/commands/plan.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/commands/project_cmd.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/commands/repro.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/commands/sdd.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/commands/spec.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/commands/sync.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/commands/validate.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/common/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/common/logger_setup.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/common/logging_utils.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/common/text_utils.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/common/utils.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/comparators/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/comparators/plan_comparator.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/enrichers/constitution_enricher.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/enrichers/plan_enricher.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/generators/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/generators/contract_generator.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/generators/openapi_extractor.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/generators/persona_exporter.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/generators/plan_generator.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/generators/protocol_generator.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/generators/report_generator.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/generators/task_generator.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/generators/test_to_openapi.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/generators/workflow_generator.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/importers/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/importers/speckit_converter.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/importers/speckit_scanner.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/integrations/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/integrations/specmatic.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/merge/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/merge/resolver.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/migrations/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/migrations/plan_migrator.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/models/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/models/bridge.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/models/capabilities.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/models/change.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/models/contract.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/models/deviation.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/models/enforcement.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/models/persona_template.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/models/plan.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/models/project.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/models/protocol.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/models/quality.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/models/sdd.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/models/source_tracking.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/models/task.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/modes/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/modes/detector.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/modes/router.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/parsers/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/parsers/persona_importer.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/resources/semgrep/async.yml +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/resources/semgrep/code-quality.yml +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/resources/semgrep/feature-detection.yml +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/runtime.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/sync/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/sync/bridge_probe.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/sync/bridge_watch.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/sync/change_detector.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/sync/code_to_spec.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/sync/drift_detector.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/sync/repository_sync.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/sync/spec_to_code.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/sync/spec_to_tests.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/sync/watcher.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/sync/watcher_enhanced.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/telemetry.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/templates/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/templates/bridge_templates.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/templates/specification_templates.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/acceptance_criteria.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/bundle_loader.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/code_change_detector.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/console.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/content_sanitizer.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/context_detection.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/enrichment_context.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/enrichment_parser.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/env_manager.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/feature_keys.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/git.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/github_annotations.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/ide_setup.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/incremental_check.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/optional_deps.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/performance.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/progress.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/progressive_disclosure.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/prompts.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/sdd_discovery.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/source_scanner.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/structure.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/structured_io.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/suggestions.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/terminal.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/utils/yaml_utils.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/agile_validation.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/change_proposal_integration.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/cli_first_validator.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/contract_validator.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/fsm.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/repro_checker.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/schema.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/sidecar/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/sidecar/contract_populator.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/sidecar/crosshair_runner.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/sidecar/crosshair_summary.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/sidecar/dependency_installer.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/sidecar/framework_detector.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/sidecar/frameworks/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/sidecar/frameworks/base.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/sidecar/frameworks/django.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/sidecar/frameworks/drf.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/sidecar/frameworks/fastapi.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/sidecar/frameworks/flask.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/sidecar/harness_generator.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/sidecar/models.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/sidecar/orchestrator.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/sidecar/specmatic_runner.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/validators/sidecar/unannotated_detector.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/src/specfact_cli/versioning/__init__.py +0 -0
- {specfact_cli-0.25.1 → specfact_cli-0.25.2}/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.25.
|
|
3
|
+
Version: 0.25.2
|
|
4
4
|
Summary: Brownfield-first CLI: Reverse engineer legacy Python → specs → enforced contracts. Automate legacy code documentation and prevent modernization regressions.
|
|
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.25.
|
|
7
|
+
version = "0.25.2"
|
|
8
8
|
description = "Brownfield-first CLI: Reverse engineer legacy Python → specs → enforced contracts. Automate legacy code documentation and prevent modernization regressions."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -210,12 +210,13 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin):
|
|
|
210
210
|
|
|
211
211
|
description = ""
|
|
212
212
|
rationale = ""
|
|
213
|
+
impact = ""
|
|
213
214
|
|
|
214
215
|
# Parse markdown sections (Why, What Changes)
|
|
215
216
|
if description_raw:
|
|
216
217
|
# Extract "Why" section (stop at What Changes or OpenSpec footer)
|
|
217
218
|
why_match = re.search(
|
|
218
|
-
r"##\s+Why\s*\n(.*?)(?=\n##\s+What\s+Changes\s|\n---\s*\n\*OpenSpec Change Proposal:|\Z)",
|
|
219
|
+
r"##\s+Why\s*\n(.*?)(?=\n##\s+What\s+Changes\s|\n##\s+Impact\s|\n---\s*\n\*OpenSpec Change Proposal:|\Z)",
|
|
219
220
|
description_raw,
|
|
220
221
|
re.DOTALL | re.IGNORECASE,
|
|
221
222
|
)
|
|
@@ -224,7 +225,7 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin):
|
|
|
224
225
|
|
|
225
226
|
# Extract "What Changes" section (stop at OpenSpec footer)
|
|
226
227
|
what_match = re.search(
|
|
227
|
-
r"##\s+What\s+Changes\s*\n(.*?)(?=\n---\s*\n\*OpenSpec Change Proposal:|\Z)",
|
|
228
|
+
r"##\s+What\s+Changes\s*\n(.*?)(?=\n##\s+Impact\s|\n---\s*\n\*OpenSpec Change Proposal:|\Z)",
|
|
228
229
|
description_raw,
|
|
229
230
|
re.DOTALL | re.IGNORECASE,
|
|
230
231
|
)
|
|
@@ -235,6 +236,14 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin):
|
|
|
235
236
|
body_clean = re.sub(r"\n---\s*\n\*OpenSpec Change Proposal:.*", "", description_raw, flags=re.DOTALL)
|
|
236
237
|
description = body_clean.strip()
|
|
237
238
|
|
|
239
|
+
impact_match = re.search(
|
|
240
|
+
r"##\s+Impact\s*\n(.*?)(?=\n---\s*\n\*OpenSpec Change Proposal:|\Z)",
|
|
241
|
+
description_raw,
|
|
242
|
+
re.DOTALL | re.IGNORECASE,
|
|
243
|
+
)
|
|
244
|
+
if impact_match:
|
|
245
|
+
impact = impact_match.group(1).strip()
|
|
246
|
+
|
|
238
247
|
# Extract change ID from OpenSpec metadata footer or work item ID
|
|
239
248
|
change_id = None
|
|
240
249
|
if description_raw:
|
|
@@ -306,6 +315,7 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin):
|
|
|
306
315
|
"title": title,
|
|
307
316
|
"description": description,
|
|
308
317
|
"rationale": rationale,
|
|
318
|
+
"impact": impact,
|
|
309
319
|
"status": status,
|
|
310
320
|
"created_at": created_at,
|
|
311
321
|
"timeline": timeline,
|
|
@@ -1208,6 +1218,7 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin):
|
|
|
1208
1218
|
title = proposal_data.get("title", "Untitled Change Proposal")
|
|
1209
1219
|
description = proposal_data.get("description", "")
|
|
1210
1220
|
rationale = proposal_data.get("rationale", "")
|
|
1221
|
+
impact = proposal_data.get("impact", "")
|
|
1211
1222
|
status = proposal_data.get("status", "proposed")
|
|
1212
1223
|
change_id = proposal_data.get("change_id", "unknown")
|
|
1213
1224
|
raw_title, raw_body = self._extract_raw_fields(proposal_data)
|
|
@@ -1243,8 +1254,16 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin):
|
|
|
1243
1254
|
body_parts.append(line)
|
|
1244
1255
|
body_parts.append("") # Blank line
|
|
1245
1256
|
|
|
1257
|
+
if impact:
|
|
1258
|
+
body_parts.append("## Impact")
|
|
1259
|
+
body_parts.append("")
|
|
1260
|
+
impact_lines = impact.strip().split("\n")
|
|
1261
|
+
for line in impact_lines:
|
|
1262
|
+
body_parts.append(line)
|
|
1263
|
+
body_parts.append("")
|
|
1264
|
+
|
|
1246
1265
|
# If no content, add placeholder
|
|
1247
|
-
if not body_parts or (not rationale and not description):
|
|
1266
|
+
if not body_parts or (not rationale and not description and not impact):
|
|
1248
1267
|
body_parts.append("No description provided.")
|
|
1249
1268
|
body_parts.append("")
|
|
1250
1269
|
|
|
@@ -1450,6 +1469,7 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin):
|
|
|
1450
1469
|
title = proposal_data.get("title", "Untitled Change Proposal")
|
|
1451
1470
|
description = proposal_data.get("description", "")
|
|
1452
1471
|
rationale = proposal_data.get("rationale", "")
|
|
1472
|
+
impact = proposal_data.get("impact", "")
|
|
1453
1473
|
status = proposal_data.get("status", "proposed")
|
|
1454
1474
|
change_id = proposal_data.get("change_id", "unknown")
|
|
1455
1475
|
raw_title, raw_body = self._extract_raw_fields(proposal_data)
|
|
@@ -1485,8 +1505,16 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin):
|
|
|
1485
1505
|
body_parts.append(line)
|
|
1486
1506
|
body_parts.append("") # Blank line
|
|
1487
1507
|
|
|
1508
|
+
if impact:
|
|
1509
|
+
body_parts.append("## Impact")
|
|
1510
|
+
body_parts.append("")
|
|
1511
|
+
impact_lines = impact.strip().split("\n")
|
|
1512
|
+
for line in impact_lines:
|
|
1513
|
+
body_parts.append(line)
|
|
1514
|
+
body_parts.append("")
|
|
1515
|
+
|
|
1488
1516
|
# If no content, add placeholder
|
|
1489
|
-
if not body_parts or (not rationale and not description):
|
|
1517
|
+
if not body_parts or (not rationale and not description and not impact):
|
|
1490
1518
|
body_parts.append("No description provided.")
|
|
1491
1519
|
body_parts.append("")
|
|
1492
1520
|
|
|
@@ -225,12 +225,13 @@ class GitHubAdapter(BridgeAdapter, BacklogAdapterMixin):
|
|
|
225
225
|
body = item_data.get("body", "") or ""
|
|
226
226
|
description = ""
|
|
227
227
|
rationale = ""
|
|
228
|
+
impact = ""
|
|
228
229
|
|
|
229
230
|
# Parse markdown sections (Why, What Changes)
|
|
230
231
|
if body:
|
|
231
232
|
# Extract "Why" section (stop at What Changes or OpenSpec footer)
|
|
232
233
|
why_match = re.search(
|
|
233
|
-
r"##\s+Why\s*\n(.*?)(?=\n##\s+What\s+Changes\s|\n---\s*\n\*OpenSpec Change Proposal:|\Z)",
|
|
234
|
+
r"##\s+Why\s*\n(.*?)(?=\n##\s+What\s+Changes\s|\n##\s+Impact\s|\n---\s*\n\*OpenSpec Change Proposal:|\Z)",
|
|
234
235
|
body,
|
|
235
236
|
re.DOTALL | re.IGNORECASE,
|
|
236
237
|
)
|
|
@@ -239,7 +240,7 @@ class GitHubAdapter(BridgeAdapter, BacklogAdapterMixin):
|
|
|
239
240
|
|
|
240
241
|
# Extract "What Changes" section (stop at OpenSpec footer)
|
|
241
242
|
what_match = re.search(
|
|
242
|
-
r"##\s+What\s+Changes\s*\n(.*?)(?=\n---\s*\n\*OpenSpec Change Proposal:|\Z)",
|
|
243
|
+
r"##\s+What\s+Changes\s*\n(.*?)(?=\n##\s+Impact\s|\n---\s*\n\*OpenSpec Change Proposal:|\Z)",
|
|
243
244
|
body,
|
|
244
245
|
re.DOTALL | re.IGNORECASE,
|
|
245
246
|
)
|
|
@@ -250,6 +251,14 @@ class GitHubAdapter(BridgeAdapter, BacklogAdapterMixin):
|
|
|
250
251
|
body_clean = re.sub(r"\n---\s*\n\*OpenSpec Change Proposal:.*", "", body, flags=re.DOTALL)
|
|
251
252
|
description = body_clean.strip()
|
|
252
253
|
|
|
254
|
+
impact_match = re.search(
|
|
255
|
+
r"##\s+Impact\s*\n(.*?)(?=\n---\s*\n\*OpenSpec Change Proposal:|\Z)",
|
|
256
|
+
body,
|
|
257
|
+
re.DOTALL | re.IGNORECASE,
|
|
258
|
+
)
|
|
259
|
+
if impact_match:
|
|
260
|
+
impact = impact_match.group(1).strip()
|
|
261
|
+
|
|
253
262
|
# Extract change ID from OpenSpec metadata footer or issue number
|
|
254
263
|
change_id = None
|
|
255
264
|
if body:
|
|
@@ -330,6 +339,7 @@ class GitHubAdapter(BridgeAdapter, BacklogAdapterMixin):
|
|
|
330
339
|
"title": title,
|
|
331
340
|
"description": description,
|
|
332
341
|
"rationale": rationale,
|
|
342
|
+
"impact": impact,
|
|
333
343
|
"status": status,
|
|
334
344
|
"created_at": created_at,
|
|
335
345
|
"timeline": timeline,
|
|
@@ -922,6 +932,7 @@ class GitHubAdapter(BridgeAdapter, BacklogAdapterMixin):
|
|
|
922
932
|
title = proposal_data.get("title", "Untitled Change Proposal")
|
|
923
933
|
description = proposal_data.get("description", "")
|
|
924
934
|
rationale = proposal_data.get("rationale", "")
|
|
935
|
+
impact = proposal_data.get("impact", "")
|
|
925
936
|
status = proposal_data.get("status", "proposed")
|
|
926
937
|
change_id = proposal_data.get("change_id", "unknown")
|
|
927
938
|
raw_title, raw_body = self._extract_raw_fields(proposal_data)
|
|
@@ -959,14 +970,24 @@ class GitHubAdapter(BridgeAdapter, BacklogAdapterMixin):
|
|
|
959
970
|
body_parts.append(line)
|
|
960
971
|
body_parts.append("") # Blank line
|
|
961
972
|
|
|
973
|
+
# Add Impact section if present
|
|
974
|
+
if impact:
|
|
975
|
+
body_parts.append("## Impact")
|
|
976
|
+
body_parts.append("")
|
|
977
|
+
impact_lines = impact.strip().split("\n")
|
|
978
|
+
for line in impact_lines:
|
|
979
|
+
body_parts.append(line)
|
|
980
|
+
body_parts.append("")
|
|
981
|
+
|
|
962
982
|
# If no content, add placeholder
|
|
963
983
|
if not body_parts or (not rationale and not description):
|
|
964
984
|
body_parts.append("No description provided.")
|
|
965
985
|
body_parts.append("")
|
|
966
986
|
|
|
967
|
-
# Add OpenSpec metadata footer
|
|
968
|
-
|
|
969
|
-
|
|
987
|
+
# Add OpenSpec metadata footer (avoid duplicates)
|
|
988
|
+
if not any("OpenSpec Change Proposal:" in line for line in body_parts):
|
|
989
|
+
body_parts.append("---")
|
|
990
|
+
body_parts.append(f"*OpenSpec Change Proposal: `{change_id}`*")
|
|
970
991
|
|
|
971
992
|
body = "\n".join(body_parts)
|
|
972
993
|
|
|
@@ -1172,6 +1193,7 @@ class GitHubAdapter(BridgeAdapter, BacklogAdapterMixin):
|
|
|
1172
1193
|
title = proposal_data.get("title", "Untitled Change Proposal")
|
|
1173
1194
|
description = proposal_data.get("description", "")
|
|
1174
1195
|
rationale = proposal_data.get("rationale", "")
|
|
1196
|
+
impact = proposal_data.get("impact", "")
|
|
1175
1197
|
change_id = proposal_data.get("change_id", "unknown")
|
|
1176
1198
|
status = proposal_data.get("status", "proposed")
|
|
1177
1199
|
raw_title, raw_body = self._extract_raw_fields(proposal_data)
|
|
@@ -1238,6 +1260,15 @@ class GitHubAdapter(BridgeAdapter, BacklogAdapterMixin):
|
|
|
1238
1260
|
body_parts.append(line)
|
|
1239
1261
|
body_parts.append("") # Blank line
|
|
1240
1262
|
|
|
1263
|
+
# Add Impact section if present
|
|
1264
|
+
if impact:
|
|
1265
|
+
body_parts.append("## Impact")
|
|
1266
|
+
body_parts.append("")
|
|
1267
|
+
impact_lines = impact.strip().split("\n")
|
|
1268
|
+
for line in impact_lines:
|
|
1269
|
+
body_parts.append(line)
|
|
1270
|
+
body_parts.append("") # Blank line
|
|
1271
|
+
|
|
1241
1272
|
# If no content, add placeholder
|
|
1242
1273
|
if not body_parts or (not rationale and not description):
|
|
1243
1274
|
body_parts.append("No description provided.")
|
|
@@ -1252,9 +1283,10 @@ class GitHubAdapter(BridgeAdapter, BacklogAdapterMixin):
|
|
|
1252
1283
|
body_parts.append("") # Blank line before preserved section
|
|
1253
1284
|
body_parts.append(preserved_clean)
|
|
1254
1285
|
|
|
1255
|
-
# Add OpenSpec metadata footer
|
|
1256
|
-
|
|
1257
|
-
|
|
1286
|
+
# Add OpenSpec metadata footer (avoid duplicates)
|
|
1287
|
+
if not any("OpenSpec Change Proposal:" in line for line in body_parts):
|
|
1288
|
+
body_parts.append("---")
|
|
1289
|
+
body_parts.append(f"*OpenSpec Change Proposal: `{change_id}`*")
|
|
1258
1290
|
|
|
1259
1291
|
body = "\n".join(body_parts)
|
|
1260
1292
|
|