specfact-cli 0.26.1__tar.gz → 0.26.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.26.1 → specfact_cli-0.26.2}/PKG-INFO +1 -1
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/pyproject.toml +1 -1
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.backlog-refine.md +47 -3
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/__init__.py +1 -1
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/__init__.py +1 -1
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/adapters/ado.py +198 -9
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/.gitignore +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/LICENSE.md +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/README.md +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/mappings/node-async.yaml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/mappings/python-async.yaml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/mappings/speckit-default.yaml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/shared/cli-enforcement.md +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.01-import.md +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.02-plan.md +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.03-review.md +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.04-sdd.md +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.05-enforce.md +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.06-sync.md +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.07-contracts.md +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.compare.md +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.sync-backlog.md +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.validate.md +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/schemas/deviation.schema.json +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/schemas/plan.schema.json +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/schemas/protocol.schema.json +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/defaults/defect_v1.yaml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/defaults/enabler_v1.yaml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/defaults/spike_v1.yaml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/defaults/user_story_v1.yaml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/frameworks/safe/safe_feature_v1.yaml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/frameworks/scrum/user_story_v1.yaml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/personas/developer/developer_task_v1.yaml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/personas/product-owner/user_story_v1.yaml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/providers/ado/work_item_v1.yaml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/github-action.yml.j2 +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/persona/architect.md.j2 +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/persona/developer.md.j2 +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/persona/product-owner.md.j2 +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/plan.bundle.yaml.j2 +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/pr-template.md.j2 +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/protocol.yaml.j2 +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/telemetry.yaml.example +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/adapters/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/adapters/backlog_base.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/adapters/base.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/adapters/github.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/adapters/openspec.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/adapters/openspec_parser.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/adapters/registry.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/adapters/speckit.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/agents/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/agents/analyze_agent.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/agents/base.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/agents/plan_agent.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/agents/registry.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/agents/sync_agent.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/ambiguity_scanner.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/code_analyzer.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/constitution_evidence_extractor.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/contract_extractor.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/control_flow_analyzer.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/graph_analyzer.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/relationship_mapper.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/requirement_extractor.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/test_pattern_extractor.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/adapters/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/adapters/base.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/adapters/local_yaml_adapter.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/ai_refiner.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/converter.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/filters.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/format_detector.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/formats/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/formats/base.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/formats/markdown_format.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/formats/structured_format.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/template_detector.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/cli.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/analyze.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/auth.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/backlog_commands.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/contract_cmd.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/drift.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/enforce.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/generate.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/import_cmd.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/init.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/migrate.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/plan.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/project_cmd.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/repro.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/sdd.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/spec.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/sync.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/validate.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/common/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/common/logger_setup.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/common/logging_utils.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/common/text_utils.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/common/utils.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/comparators/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/comparators/plan_comparator.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/contracts/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/contracts/crosshair_props.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/enrichers/constitution_enricher.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/enrichers/plan_enricher.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/generators/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/generators/contract_generator.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/generators/openapi_extractor.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/generators/persona_exporter.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/generators/plan_generator.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/generators/protocol_generator.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/generators/report_generator.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/generators/task_generator.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/generators/test_to_openapi.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/generators/workflow_generator.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/importers/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/importers/speckit_converter.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/importers/speckit_scanner.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/integrations/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/integrations/specmatic.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/merge/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/merge/resolver.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/migrations/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/migrations/plan_migrator.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/backlog_item.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/bridge.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/capabilities.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/change.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/contract.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/deviation.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/dor_config.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/enforcement.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/persona_template.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/plan.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/project.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/protocol.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/quality.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/sdd.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/source_tracking.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/task.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/modes/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/modes/detector.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/modes/router.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/parsers/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/parsers/persona_importer.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/resources/semgrep/async.yml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/resources/semgrep/code-quality.yml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/resources/semgrep/feature-detection.yml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/runtime.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/bridge_probe.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/bridge_sync.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/bridge_watch.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/change_detector.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/code_to_spec.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/drift_detector.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/repository_sync.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/spec_to_code.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/spec_to_tests.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/watcher.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/watcher_enhanced.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/telemetry.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/bridge_templates.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/defaults/defect_v1.yaml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/defaults/enabler_v1.yaml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/defaults/spike_v1.yaml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/defaults/user_story_v1.yaml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/frameworks/scrum/user_story_v1.yaml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/personas/product-owner/user_story_v1.yaml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/providers/ado/work_item_v1.yaml +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/registry.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/specification_templates.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/acceptance_criteria.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/auth_tokens.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/bundle_loader.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/code_change_detector.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/console.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/content_sanitizer.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/context_detection.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/enrichment_context.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/enrichment_parser.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/env_manager.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/feature_keys.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/git.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/github_annotations.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/ide_setup.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/incremental_check.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/optional_deps.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/performance.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/progress.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/progressive_disclosure.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/prompts.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/sdd_discovery.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/source_scanner.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/structure.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/structured_io.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/suggestions.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/terminal.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/yaml_utils.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/agile_validation.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/change_proposal_integration.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/cli_first_validator.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/contract_validator.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/fsm.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/repro_checker.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/schema.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/contract_populator.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/crosshair_runner.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/crosshair_summary.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/dependency_installer.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/framework_detector.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/frameworks/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/frameworks/base.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/frameworks/django.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/frameworks/drf.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/frameworks/fastapi.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/frameworks/flask.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/harness_generator.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/models.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/orchestrator.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/specmatic_runner.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/unannotated_detector.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/versioning/__init__.py +0 -0
- {specfact_cli-0.26.1 → specfact_cli-0.26.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.26.
|
|
3
|
+
Version: 0.26.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.26.
|
|
7
|
+
version = "0.26.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"
|
|
@@ -36,9 +36,23 @@ Refine backlog items from DevOps tools (GitHub Issues, Azure DevOps, etc.) into
|
|
|
36
36
|
|
|
37
37
|
**Azure DevOps Adapter:**
|
|
38
38
|
|
|
39
|
-
- `--ado-org ORG` - Azure DevOps organization (required for ADO adapter)
|
|
39
|
+
- `--ado-org ORG` - Azure DevOps organization or collection name (required for ADO adapter, except when collection is in base_url)
|
|
40
40
|
- `--ado-project PROJECT` - Azure DevOps project (required for ADO adapter)
|
|
41
|
-
- `--ado-
|
|
41
|
+
- `--ado-base-url URL` - Azure DevOps base URL (optional, defaults to `https://dev.azure.com` for cloud)
|
|
42
|
+
- **Cloud**: `https://dev.azure.com` (default)
|
|
43
|
+
- **On-premise**: `https://server` or `https://server/tfs/collection` (if collection included)
|
|
44
|
+
- `--ado-token TOKEN` - Azure DevOps PAT (optional, uses AZURE_DEVOPS_TOKEN env var or stored token if not provided)
|
|
45
|
+
|
|
46
|
+
**ADO Configuration Notes:**
|
|
47
|
+
|
|
48
|
+
- **Cloud (Azure DevOps Services)**: Always requires `--ado-org` and `--ado-project`. Base URL defaults to `https://dev.azure.com`.
|
|
49
|
+
- **On-premise (Azure DevOps Server)**:
|
|
50
|
+
- If base URL includes collection (e.g., `https://server/tfs/DefaultCollection`), `--ado-org` is optional.
|
|
51
|
+
- If base URL doesn't include collection, provide collection name via `--ado-org`.
|
|
52
|
+
- **API Endpoints**:
|
|
53
|
+
- WIQL queries use POST to `{base_url}/{org}/{project}/_apis/wit/wiql?api-version=7.1` (project-level)
|
|
54
|
+
- Work items batch GET uses `{base_url}/{org}/_apis/wit/workitems?ids={ids}&api-version=7.1` (organization-level)
|
|
55
|
+
- The `api-version` parameter is **required** for all ADO API calls
|
|
42
56
|
|
|
43
57
|
### Filters
|
|
44
58
|
|
|
@@ -234,9 +248,15 @@ Items updated in remote backlog:
|
|
|
234
248
|
# Refine GitHub issues with feature label (requires repo-owner and repo-name)
|
|
235
249
|
/specfact.backlog-refine --adapter github --repo-owner nold-ai --repo-name specfact-cli --labels feature
|
|
236
250
|
|
|
237
|
-
# Refine ADO work items
|
|
251
|
+
# Refine ADO work items (Azure DevOps Services - cloud)
|
|
238
252
|
/specfact.backlog-refine --adapter ado --ado-org my-org --ado-project my-project --sprint "Sprint 1"
|
|
239
253
|
|
|
254
|
+
# Refine ADO work items (Azure DevOps Server - on-premise, collection in base_url)
|
|
255
|
+
/specfact.backlog-refine --adapter ado --ado-base-url "https://devops.company.com/tfs/DefaultCollection" --ado-project my-project --state Active
|
|
256
|
+
|
|
257
|
+
# Refine ADO work items (Azure DevOps Server - on-premise, collection provided)
|
|
258
|
+
/specfact.backlog-refine --adapter ado --ado-base-url "https://devops.company.com" --ado-org "DefaultCollection" --ado-project my-project --state Active
|
|
259
|
+
|
|
240
260
|
# Refine with Scrum framework and Product Owner persona
|
|
241
261
|
/specfact.backlog-refine --adapter github --repo-owner nold-ai --repo-name specfact-cli --framework scrum --persona product-owner
|
|
242
262
|
|
|
@@ -263,6 +283,30 @@ Items updated in remote backlog:
|
|
|
263
283
|
# specfact sync bridge --adapter github --repo-owner my-org --repo-name my-repo --mode bidirectional
|
|
264
284
|
```
|
|
265
285
|
|
|
286
|
+
## Troubleshooting
|
|
287
|
+
|
|
288
|
+
### ADO API Errors
|
|
289
|
+
|
|
290
|
+
**Error: "No HTTP resource was found that matches the request URI"**
|
|
291
|
+
|
|
292
|
+
- **Cause**: Missing `api-version` parameter or incorrect URL format
|
|
293
|
+
- **Solution**: Ensure `api-version=7.1` is included in all ADO API URLs. Check base URL format for on-premise installations.
|
|
294
|
+
|
|
295
|
+
**Error: "The requested resource does not support http method 'GET'"**
|
|
296
|
+
|
|
297
|
+
- **Cause**: Attempting to use GET on WIQL endpoint (which requires POST)
|
|
298
|
+
- **Solution**: WIQL queries must use POST method with JSON body containing the query. This is handled automatically by SpecFact CLI.
|
|
299
|
+
|
|
300
|
+
**Error: Organization removed from request string**
|
|
301
|
+
|
|
302
|
+
- **Cause**: Incorrect base URL format (may already include organization/collection)
|
|
303
|
+
- **Solution**: For on-premise, check if base URL already includes collection. If yes, omit `--ado-org` or adjust base URL accordingly.
|
|
304
|
+
|
|
305
|
+
**Error: "Azure DevOps API token required"**
|
|
306
|
+
|
|
307
|
+
- **Cause**: Missing authentication token
|
|
308
|
+
- **Solution**: Provide token via `--ado-token`, `AZURE_DEVOPS_TOKEN` environment variable, or use `specfact auth azure-devops` for device code flow.
|
|
309
|
+
|
|
266
310
|
## Context
|
|
267
311
|
|
|
268
312
|
{ARGS}
|
|
@@ -84,9 +84,100 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
|
|
|
84
84
|
self.auth_scheme = None
|
|
85
85
|
|
|
86
86
|
# Base URL defaults to Azure DevOps Services (cloud)
|
|
87
|
-
|
|
87
|
+
# Normalize base_url: remove trailing slashes
|
|
88
|
+
# Note: For Azure DevOps Services (cloud), base_url should be "https://dev.azure.com"
|
|
89
|
+
# For Azure DevOps Server (on-premise), base_url might be "https://server" or "https://server/collection"
|
|
90
|
+
raw_base_url = base_url or "https://dev.azure.com"
|
|
91
|
+
self.base_url = raw_base_url.rstrip("/")
|
|
88
92
|
self.work_item_type = work_item_type
|
|
89
93
|
|
|
94
|
+
def _is_on_premise(self) -> bool:
|
|
95
|
+
"""
|
|
96
|
+
Detect if this is Azure DevOps Server (on-premise) vs Azure DevOps Services (cloud).
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
True if on-premise (base_url doesn't contain dev.azure.com), False if cloud
|
|
100
|
+
"""
|
|
101
|
+
return "dev.azure.com" not in self.base_url.lower()
|
|
102
|
+
|
|
103
|
+
def _build_ado_url(self, path: str, api_version: str = "7.1") -> str:
|
|
104
|
+
"""
|
|
105
|
+
Build Azure DevOps API URL with proper formatting.
|
|
106
|
+
|
|
107
|
+
Supports both:
|
|
108
|
+
- Azure DevOps Services (cloud): https://dev.azure.com/{org}/{project}/_apis/...
|
|
109
|
+
- Azure DevOps Server (on-premise): https://{server}/tfs/{collection}/{project}/_apis/...
|
|
110
|
+
or https://{server}/{collection}/{project}/_apis/...
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
path: API path (e.g., "_apis/wit/workitems", "_apis/wit/wiql")
|
|
114
|
+
api_version: API version (default: "7.1")
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
Full URL with proper format based on cloud vs on-premise
|
|
118
|
+
|
|
119
|
+
Note:
|
|
120
|
+
For on-premise, if base_url already includes /tfs/{collection} or /{collection},
|
|
121
|
+
it won't add org again. For cloud, always adds {org}/{project}.
|
|
122
|
+
"""
|
|
123
|
+
if not self.project:
|
|
124
|
+
raise ValueError(f"project required to build ADO URL (project={self.project!r})")
|
|
125
|
+
|
|
126
|
+
# Normalize base_url (remove trailing slashes)
|
|
127
|
+
base_url_normalized = self.base_url.rstrip("/")
|
|
128
|
+
|
|
129
|
+
# Normalize path (remove leading slashes)
|
|
130
|
+
path_normalized = path.lstrip("/")
|
|
131
|
+
|
|
132
|
+
is_on_premise = self._is_on_premise()
|
|
133
|
+
|
|
134
|
+
if is_on_premise:
|
|
135
|
+
# Azure DevOps Server (on-premise)
|
|
136
|
+
# Format could be:
|
|
137
|
+
# - https://server/tfs/collection/{project}/_apis/... (older TFS format)
|
|
138
|
+
# - https://server/collection/{project}/_apis/... (newer format)
|
|
139
|
+
# - https://server/{project}/_apis/... (if collection in base_url)
|
|
140
|
+
|
|
141
|
+
base_lower = base_url_normalized.lower()
|
|
142
|
+
has_tfs = "/tfs/" in base_lower
|
|
143
|
+
|
|
144
|
+
# Check if base_url already includes a collection path
|
|
145
|
+
# If base_url contains /tfs/ or has more than just protocol + domain, collection is likely included
|
|
146
|
+
parts = [p for p in base_url_normalized.rstrip("/").split("/") if p and p not in ["http:", "https:"]]
|
|
147
|
+
# Collection is in base_url if:
|
|
148
|
+
# 1. It contains /tfs/ (older TFS format: server/tfs/collection)
|
|
149
|
+
# 2. It has more than 1 part after protocol (e.g., server/collection)
|
|
150
|
+
has_collection_in_base = has_tfs or len(parts) > 1
|
|
151
|
+
|
|
152
|
+
if has_collection_in_base:
|
|
153
|
+
# Collection already in base_url, just add project
|
|
154
|
+
url = f"{base_url_normalized}/{self.project}/{path_normalized}?api-version={api_version}"
|
|
155
|
+
elif self.org:
|
|
156
|
+
# Collection not in base_url, need to add it
|
|
157
|
+
# For on-premise, typically use /tfs/{collection} format unless explicitly newer format
|
|
158
|
+
# But if base_url doesn't have /tfs/, use newer format
|
|
159
|
+
if "/tfs" in base_url_normalized.lower() or not has_tfs:
|
|
160
|
+
# If base_url mentions tfs anywhere or we're not sure, use /tfs/ format
|
|
161
|
+
# Actually, if has_tfs is False, we should use newer format
|
|
162
|
+
url = f"{base_url_normalized}/{self.org}/{self.project}/{path_normalized}?api-version={api_version}"
|
|
163
|
+
else:
|
|
164
|
+
# Use /tfs/ format for older TFS servers
|
|
165
|
+
url = f"{base_url_normalized}/tfs/{self.org}/{self.project}/{path_normalized}?api-version={api_version}"
|
|
166
|
+
else:
|
|
167
|
+
# No org provided, assume collection is in base_url or use project directly
|
|
168
|
+
console.print(
|
|
169
|
+
"[yellow]Warning:[/yellow] On-premise detected but org (collection) not provided. Assuming collection is in base_url."
|
|
170
|
+
)
|
|
171
|
+
url = f"{base_url_normalized}/{self.project}/{path_normalized}?api-version={api_version}"
|
|
172
|
+
else:
|
|
173
|
+
# Azure DevOps Services (cloud)
|
|
174
|
+
# Format: https://dev.azure.com/{org}/{project}/_apis/...
|
|
175
|
+
if not self.org:
|
|
176
|
+
raise ValueError(f"org required for Azure DevOps Services (cloud) (org={self.org!r})")
|
|
177
|
+
url = f"{base_url_normalized}/{self.org}/{self.project}/{path_normalized}?api-version={api_version}"
|
|
178
|
+
|
|
179
|
+
return url
|
|
180
|
+
|
|
90
181
|
# BacklogAdapterMixin abstract method implementations
|
|
91
182
|
|
|
92
183
|
@beartype
|
|
@@ -2223,8 +2314,11 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
|
|
|
2223
2314
|
raise ValueError(msg)
|
|
2224
2315
|
|
|
2225
2316
|
# Build WIQL (Work Item Query Language) query
|
|
2226
|
-
|
|
2317
|
+
# WIQL syntax: SELECT fields FROM WorkItems WHERE conditions
|
|
2318
|
+
# Use @project macro to reference the project context in project-scoped queries
|
|
2319
|
+
wiql_parts = ["SELECT [System.Id], [System.Title], [System.State], [System.WorkItemType]"]
|
|
2227
2320
|
wiql_parts.append("FROM WorkItems")
|
|
2321
|
+
# Use @project macro for project context (ADO automatically resolves this in project-scoped queries)
|
|
2228
2322
|
wiql_parts.append("WHERE [System.TeamProject] = @project")
|
|
2229
2323
|
|
|
2230
2324
|
conditions = []
|
|
@@ -2247,15 +2341,44 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
|
|
|
2247
2341
|
wiql = " ".join(wiql_parts)
|
|
2248
2342
|
|
|
2249
2343
|
# Execute WIQL query
|
|
2250
|
-
|
|
2344
|
+
# POST to project-level endpoint: {org}/{project}/_apis/wit/wiql?api-version=7.1
|
|
2345
|
+
url = self._build_ado_url("_apis/wit/wiql", api_version="7.1")
|
|
2251
2346
|
headers = {
|
|
2252
2347
|
"Authorization": f"{self.auth_scheme} {self.api_token}" if self.auth_scheme else f"Basic {self.api_token}",
|
|
2253
2348
|
"Content-Type": "application/json",
|
|
2349
|
+
"Accept": "application/json",
|
|
2254
2350
|
}
|
|
2255
2351
|
payload = {"query": wiql}
|
|
2256
2352
|
|
|
2257
|
-
|
|
2258
|
-
|
|
2353
|
+
# Debug: Log URL construction for troubleshooting
|
|
2354
|
+
console.print(f"[dim]ADO WIQL URL: {url}[/dim]")
|
|
2355
|
+
|
|
2356
|
+
try:
|
|
2357
|
+
response = requests.post(url, headers=headers, json=payload, timeout=30)
|
|
2358
|
+
response.raise_for_status()
|
|
2359
|
+
except requests.HTTPError as e:
|
|
2360
|
+
# Provide better error message with URL details
|
|
2361
|
+
error_detail = ""
|
|
2362
|
+
if e.response is not None:
|
|
2363
|
+
try:
|
|
2364
|
+
error_json = e.response.json()
|
|
2365
|
+
error_detail = f"\nResponse: {error_json}"
|
|
2366
|
+
except Exception:
|
|
2367
|
+
error_detail = f"\nResponse status: {e.response.status_code}"
|
|
2368
|
+
|
|
2369
|
+
error_msg = (
|
|
2370
|
+
f"Azure DevOps API error: {e}{error_detail}\n"
|
|
2371
|
+
f"URL: {url}\n"
|
|
2372
|
+
f"Organization: {self.org}\n"
|
|
2373
|
+
f"Project: {self.project}\n"
|
|
2374
|
+
f"Base URL: {self.base_url}\n"
|
|
2375
|
+
f"Expected format: https://dev.azure.com/{{org}}/{{project}}/_apis/wit/wiql?api-version=7.1\n"
|
|
2376
|
+
f"If using Azure DevOps Server (on-premise), base_url format may differ."
|
|
2377
|
+
)
|
|
2378
|
+
# Create new exception with better message
|
|
2379
|
+
new_exception = requests.HTTPError(error_msg)
|
|
2380
|
+
new_exception.response = e.response
|
|
2381
|
+
raise new_exception from e
|
|
2259
2382
|
query_result = response.json()
|
|
2260
2383
|
|
|
2261
2384
|
work_item_ids = [item["id"] for item in query_result.get("workItems", [])]
|
|
@@ -2264,18 +2387,84 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
|
|
|
2264
2387
|
return []
|
|
2265
2388
|
|
|
2266
2389
|
# Fetch work item details
|
|
2390
|
+
# Note: GET workitems by IDs uses organization-level endpoint, not project-level
|
|
2391
|
+
# Format: https://dev.azure.com/{organization}/_apis/wit/workitems?ids={ids}&api-version={version}
|
|
2267
2392
|
items: list[BacklogItem] = []
|
|
2268
2393
|
batch_size = 200 # ADO API limit
|
|
2269
2394
|
|
|
2395
|
+
# Build organization-level URL for work items batch fetch
|
|
2396
|
+
base_url_normalized = self.base_url.rstrip("/")
|
|
2397
|
+
is_on_premise = self._is_on_premise()
|
|
2398
|
+
|
|
2399
|
+
# For work items batch GET, URL is at organization level (not project level)
|
|
2400
|
+
if is_on_premise:
|
|
2401
|
+
# On-premise: if base_url has collection, use it; otherwise add org
|
|
2402
|
+
parts = [p for p in base_url_normalized.split("/") if p and p not in ["http:", "https:"]]
|
|
2403
|
+
has_collection_in_base = "/tfs/" in base_url_normalized.lower() or len(parts) > 1
|
|
2404
|
+
|
|
2405
|
+
if has_collection_in_base:
|
|
2406
|
+
# Collection already in base_url
|
|
2407
|
+
workitems_base_url = base_url_normalized
|
|
2408
|
+
elif self.org:
|
|
2409
|
+
# Need to add collection
|
|
2410
|
+
if "/tfs" in base_url_normalized.lower():
|
|
2411
|
+
workitems_base_url = f"{base_url_normalized}/tfs/{self.org}"
|
|
2412
|
+
else:
|
|
2413
|
+
workitems_base_url = f"{base_url_normalized}/{self.org}"
|
|
2414
|
+
else:
|
|
2415
|
+
workitems_base_url = base_url_normalized
|
|
2416
|
+
else:
|
|
2417
|
+
# Cloud: organization level
|
|
2418
|
+
if not self.org:
|
|
2419
|
+
raise ValueError(f"org required for Azure DevOps Services (cloud) (org={self.org!r})")
|
|
2420
|
+
workitems_base_url = f"{base_url_normalized}/{self.org}"
|
|
2421
|
+
|
|
2270
2422
|
for i in range(0, len(work_item_ids), batch_size):
|
|
2271
2423
|
batch = work_item_ids[i : i + batch_size]
|
|
2272
2424
|
ids_str = ",".join(str(wi_id) for wi_id in batch)
|
|
2273
2425
|
|
|
2274
|
-
|
|
2426
|
+
# Work items batch GET is at organization level, not project level
|
|
2427
|
+
# Format: {org}/_apis/wit/workitems?ids={ids}&api-version=7.1
|
|
2428
|
+
url = f"{workitems_base_url}/_apis/wit/workitems?api-version=7.1"
|
|
2275
2429
|
params = {"ids": ids_str, "$expand": "all"}
|
|
2276
2430
|
|
|
2277
|
-
|
|
2278
|
-
|
|
2431
|
+
# Headers for work items batch GET (organization-level endpoint)
|
|
2432
|
+
workitems_headers = {
|
|
2433
|
+
"Authorization": f"{self.auth_scheme} {self.api_token}"
|
|
2434
|
+
if self.auth_scheme
|
|
2435
|
+
else f"Basic {self.api_token}",
|
|
2436
|
+
"Accept": "application/json",
|
|
2437
|
+
}
|
|
2438
|
+
|
|
2439
|
+
# Debug: Log URL construction for troubleshooting
|
|
2440
|
+
console.print(f"[dim]ADO WorkItems URL: {url}&ids={ids_str}[/dim]")
|
|
2441
|
+
|
|
2442
|
+
try:
|
|
2443
|
+
response = requests.get(url, headers=workitems_headers, params=params, timeout=30)
|
|
2444
|
+
response.raise_for_status()
|
|
2445
|
+
except requests.HTTPError as e:
|
|
2446
|
+
# Provide better error message with URL details
|
|
2447
|
+
error_detail = ""
|
|
2448
|
+
if e.response is not None:
|
|
2449
|
+
try:
|
|
2450
|
+
error_json = e.response.json()
|
|
2451
|
+
error_detail = f"\nResponse: {error_json}"
|
|
2452
|
+
except Exception:
|
|
2453
|
+
error_detail = f"\nResponse status: {e.response.status_code}"
|
|
2454
|
+
|
|
2455
|
+
error_msg = (
|
|
2456
|
+
f"Azure DevOps API error: {e}{error_detail}\n"
|
|
2457
|
+
f"URL: {url}\n"
|
|
2458
|
+
f"Organization: {self.org}\n"
|
|
2459
|
+
f"Project: {self.project}\n"
|
|
2460
|
+
f"Base URL: {self.base_url}\n"
|
|
2461
|
+
f"Expected format: https://dev.azure.com/{{org}}/{{project}}/_apis/wit/workitems?ids={{ids}}&api-version=7.1\n"
|
|
2462
|
+
f"If using Azure DevOps Server (on-premise), base_url format may differ."
|
|
2463
|
+
)
|
|
2464
|
+
# Create new exception with better message
|
|
2465
|
+
new_exception = requests.HTTPError(error_msg)
|
|
2466
|
+
new_exception.response = e.response
|
|
2467
|
+
raise new_exception from e
|
|
2279
2468
|
work_items_data = response.json()
|
|
2280
2469
|
|
|
2281
2470
|
# Convert ADO work items to BacklogItem
|
|
@@ -2354,7 +2543,7 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
|
|
|
2354
2543
|
raise ValueError(msg)
|
|
2355
2544
|
|
|
2356
2545
|
work_item_id = int(item.id)
|
|
2357
|
-
url = f"
|
|
2546
|
+
url = self._build_ado_url(f"_apis/wit/workitems/{work_item_id}", api_version="7.1")
|
|
2358
2547
|
headers = {
|
|
2359
2548
|
"Authorization": f"{self.auth_scheme} {self.api_token}" if self.auth_scheme else f"Basic {self.api_token}",
|
|
2360
2549
|
"Content-Type": "application/json-patch+json",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/defaults/defect_v1.yaml
RENAMED
|
File without changes
|
{specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/defaults/enabler_v1.yaml
RENAMED
|
File without changes
|
{specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/defaults/spike_v1.yaml
RENAMED
|
File without changes
|
{specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/defaults/user_story_v1.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/contract_extractor.py
RENAMED
|
File without changes
|
{specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/control_flow_analyzer.py
RENAMED
|
File without changes
|
|
File without changes
|
{specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/relationship_mapper.py
RENAMED
|
File without changes
|
{specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/requirement_extractor.py
RENAMED
|
File without changes
|
{specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/test_pattern_extractor.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/adapters/local_yaml_adapter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/formats/markdown_format.py
RENAMED
|
File without changes
|
{specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/formats/structured_format.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|