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.
Files changed (234) hide show
  1. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/PKG-INFO +1 -1
  2. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/pyproject.toml +1 -1
  3. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.backlog-refine.md +47 -3
  4. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/__init__.py +1 -1
  5. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/__init__.py +1 -1
  6. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/adapters/ado.py +198 -9
  7. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/.gitignore +0 -0
  8. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/LICENSE.md +0 -0
  9. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/README.md +0 -0
  10. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/mappings/node-async.yaml +0 -0
  11. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/mappings/python-async.yaml +0 -0
  12. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/mappings/speckit-default.yaml +0 -0
  13. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/shared/cli-enforcement.md +0 -0
  14. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.01-import.md +0 -0
  15. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.02-plan.md +0 -0
  16. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.03-review.md +0 -0
  17. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.04-sdd.md +0 -0
  18. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.05-enforce.md +0 -0
  19. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.06-sync.md +0 -0
  20. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.07-contracts.md +0 -0
  21. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.compare.md +0 -0
  22. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.sync-backlog.md +0 -0
  23. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/prompts/specfact.validate.md +0 -0
  24. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/schemas/deviation.schema.json +0 -0
  25. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/schemas/plan.schema.json +0 -0
  26. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/schemas/protocol.schema.json +0 -0
  27. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/defaults/defect_v1.yaml +0 -0
  28. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/defaults/enabler_v1.yaml +0 -0
  29. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/defaults/spike_v1.yaml +0 -0
  30. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/defaults/user_story_v1.yaml +0 -0
  31. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/frameworks/safe/safe_feature_v1.yaml +0 -0
  32. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/frameworks/scrum/user_story_v1.yaml +0 -0
  33. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/personas/developer/developer_task_v1.yaml +0 -0
  34. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/personas/product-owner/user_story_v1.yaml +0 -0
  35. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/backlog/providers/ado/work_item_v1.yaml +0 -0
  36. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/github-action.yml.j2 +0 -0
  37. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/persona/architect.md.j2 +0 -0
  38. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/persona/developer.md.j2 +0 -0
  39. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/persona/product-owner.md.j2 +0 -0
  40. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/plan.bundle.yaml.j2 +0 -0
  41. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/pr-template.md.j2 +0 -0
  42. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/protocol.yaml.j2 +0 -0
  43. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/resources/templates/telemetry.yaml.example +0 -0
  44. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/adapters/__init__.py +0 -0
  45. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/adapters/backlog_base.py +0 -0
  46. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/adapters/base.py +0 -0
  47. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/adapters/github.py +0 -0
  48. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/adapters/openspec.py +0 -0
  49. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/adapters/openspec_parser.py +0 -0
  50. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/adapters/registry.py +0 -0
  51. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/adapters/speckit.py +0 -0
  52. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/agents/__init__.py +0 -0
  53. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/agents/analyze_agent.py +0 -0
  54. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/agents/base.py +0 -0
  55. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/agents/plan_agent.py +0 -0
  56. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/agents/registry.py +0 -0
  57. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/agents/sync_agent.py +0 -0
  58. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/__init__.py +0 -0
  59. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/ambiguity_scanner.py +0 -0
  60. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/code_analyzer.py +0 -0
  61. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/constitution_evidence_extractor.py +0 -0
  62. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/contract_extractor.py +0 -0
  63. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/control_flow_analyzer.py +0 -0
  64. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/graph_analyzer.py +0 -0
  65. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/relationship_mapper.py +0 -0
  66. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/requirement_extractor.py +0 -0
  67. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/analyzers/test_pattern_extractor.py +0 -0
  68. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/__init__.py +0 -0
  69. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/adapters/__init__.py +0 -0
  70. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/adapters/base.py +0 -0
  71. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/adapters/local_yaml_adapter.py +0 -0
  72. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/ai_refiner.py +0 -0
  73. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/converter.py +0 -0
  74. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/filters.py +0 -0
  75. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/format_detector.py +0 -0
  76. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/formats/__init__.py +0 -0
  77. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/formats/base.py +0 -0
  78. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/formats/markdown_format.py +0 -0
  79. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/formats/structured_format.py +0 -0
  80. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/backlog/template_detector.py +0 -0
  81. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/cli.py +0 -0
  82. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/__init__.py +0 -0
  83. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/analyze.py +0 -0
  84. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/auth.py +0 -0
  85. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/backlog_commands.py +0 -0
  86. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/contract_cmd.py +0 -0
  87. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/drift.py +0 -0
  88. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/enforce.py +0 -0
  89. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/generate.py +0 -0
  90. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/import_cmd.py +0 -0
  91. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/init.py +0 -0
  92. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/migrate.py +0 -0
  93. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/plan.py +0 -0
  94. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/project_cmd.py +0 -0
  95. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/repro.py +0 -0
  96. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/sdd.py +0 -0
  97. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/spec.py +0 -0
  98. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/sync.py +0 -0
  99. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/commands/validate.py +0 -0
  100. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/common/__init__.py +0 -0
  101. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/common/logger_setup.py +0 -0
  102. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/common/logging_utils.py +0 -0
  103. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/common/text_utils.py +0 -0
  104. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/common/utils.py +0 -0
  105. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/comparators/__init__.py +0 -0
  106. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/comparators/plan_comparator.py +0 -0
  107. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/contracts/__init__.py +0 -0
  108. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/contracts/crosshair_props.py +0 -0
  109. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/enrichers/constitution_enricher.py +0 -0
  110. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/enrichers/plan_enricher.py +0 -0
  111. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/generators/__init__.py +0 -0
  112. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/generators/contract_generator.py +0 -0
  113. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/generators/openapi_extractor.py +0 -0
  114. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/generators/persona_exporter.py +0 -0
  115. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/generators/plan_generator.py +0 -0
  116. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/generators/protocol_generator.py +0 -0
  117. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/generators/report_generator.py +0 -0
  118. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/generators/task_generator.py +0 -0
  119. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/generators/test_to_openapi.py +0 -0
  120. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/generators/workflow_generator.py +0 -0
  121. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/importers/__init__.py +0 -0
  122. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/importers/speckit_converter.py +0 -0
  123. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/importers/speckit_scanner.py +0 -0
  124. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/integrations/__init__.py +0 -0
  125. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/integrations/specmatic.py +0 -0
  126. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/merge/__init__.py +0 -0
  127. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/merge/resolver.py +0 -0
  128. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/migrations/__init__.py +0 -0
  129. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/migrations/plan_migrator.py +0 -0
  130. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/__init__.py +0 -0
  131. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/backlog_item.py +0 -0
  132. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/bridge.py +0 -0
  133. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/capabilities.py +0 -0
  134. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/change.py +0 -0
  135. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/contract.py +0 -0
  136. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/deviation.py +0 -0
  137. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/dor_config.py +0 -0
  138. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/enforcement.py +0 -0
  139. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/persona_template.py +0 -0
  140. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/plan.py +0 -0
  141. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/project.py +0 -0
  142. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/protocol.py +0 -0
  143. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/quality.py +0 -0
  144. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/sdd.py +0 -0
  145. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/source_tracking.py +0 -0
  146. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/models/task.py +0 -0
  147. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/modes/__init__.py +0 -0
  148. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/modes/detector.py +0 -0
  149. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/modes/router.py +0 -0
  150. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/parsers/__init__.py +0 -0
  151. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/parsers/persona_importer.py +0 -0
  152. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/resources/semgrep/async.yml +0 -0
  153. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/resources/semgrep/code-quality.yml +0 -0
  154. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/resources/semgrep/feature-detection.yml +0 -0
  155. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/runtime.py +0 -0
  156. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/__init__.py +0 -0
  157. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/bridge_probe.py +0 -0
  158. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/bridge_sync.py +0 -0
  159. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/bridge_watch.py +0 -0
  160. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/change_detector.py +0 -0
  161. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/code_to_spec.py +0 -0
  162. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/drift_detector.py +0 -0
  163. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/repository_sync.py +0 -0
  164. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/spec_to_code.py +0 -0
  165. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/spec_to_tests.py +0 -0
  166. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/watcher.py +0 -0
  167. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/sync/watcher_enhanced.py +0 -0
  168. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/telemetry.py +0 -0
  169. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/__init__.py +0 -0
  170. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/bridge_templates.py +0 -0
  171. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/defaults/defect_v1.yaml +0 -0
  172. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/defaults/enabler_v1.yaml +0 -0
  173. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/defaults/spike_v1.yaml +0 -0
  174. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/defaults/user_story_v1.yaml +0 -0
  175. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/frameworks/scrum/user_story_v1.yaml +0 -0
  176. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/personas/product-owner/user_story_v1.yaml +0 -0
  177. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/providers/ado/work_item_v1.yaml +0 -0
  178. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/registry.py +0 -0
  179. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/templates/specification_templates.py +0 -0
  180. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/__init__.py +0 -0
  181. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/acceptance_criteria.py +0 -0
  182. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/auth_tokens.py +0 -0
  183. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/bundle_loader.py +0 -0
  184. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/code_change_detector.py +0 -0
  185. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/console.py +0 -0
  186. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/content_sanitizer.py +0 -0
  187. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/context_detection.py +0 -0
  188. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/enrichment_context.py +0 -0
  189. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/enrichment_parser.py +0 -0
  190. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/env_manager.py +0 -0
  191. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/feature_keys.py +0 -0
  192. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/git.py +0 -0
  193. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/github_annotations.py +0 -0
  194. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/ide_setup.py +0 -0
  195. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/incremental_check.py +0 -0
  196. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/optional_deps.py +0 -0
  197. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/performance.py +0 -0
  198. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/progress.py +0 -0
  199. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/progressive_disclosure.py +0 -0
  200. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/prompts.py +0 -0
  201. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/sdd_discovery.py +0 -0
  202. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/source_scanner.py +0 -0
  203. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/structure.py +0 -0
  204. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/structured_io.py +0 -0
  205. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/suggestions.py +0 -0
  206. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/terminal.py +0 -0
  207. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/utils/yaml_utils.py +0 -0
  208. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/__init__.py +0 -0
  209. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/agile_validation.py +0 -0
  210. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/change_proposal_integration.py +0 -0
  211. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/cli_first_validator.py +0 -0
  212. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/contract_validator.py +0 -0
  213. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/fsm.py +0 -0
  214. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/repro_checker.py +0 -0
  215. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/schema.py +0 -0
  216. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/__init__.py +0 -0
  217. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/contract_populator.py +0 -0
  218. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/crosshair_runner.py +0 -0
  219. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/crosshair_summary.py +0 -0
  220. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/dependency_installer.py +0 -0
  221. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/framework_detector.py +0 -0
  222. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/frameworks/__init__.py +0 -0
  223. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/frameworks/base.py +0 -0
  224. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/frameworks/django.py +0 -0
  225. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/frameworks/drf.py +0 -0
  226. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/frameworks/fastapi.py +0 -0
  227. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/frameworks/flask.py +0 -0
  228. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/harness_generator.py +0 -0
  229. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/models.py +0 -0
  230. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/orchestrator.py +0 -0
  231. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/specmatic_runner.py +0 -0
  232. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/validators/sidecar/unannotated_detector.py +0 -0
  233. {specfact_cli-0.26.1 → specfact_cli-0.26.2}/src/specfact_cli/versioning/__init__.py +0 -0
  234. {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.1
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.1"
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-token TOKEN` - Azure DevOps PAT (optional, uses AZURE_DEVOPS_TOKEN env var if not provided)
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 in specific sprint (requires ado-org and ado-project)
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}
@@ -3,4 +3,4 @@ SpecFact CLI - Spec→Contract→Sentinel tool for contract-driven development.
3
3
  """
4
4
 
5
5
  # Define the package version (kept in sync with pyproject.toml and setup.py)
6
- __version__ = "0.26.1"
6
+ __version__ = "0.26.2"
@@ -9,6 +9,6 @@ This package provides command-line tools for:
9
9
  - Validating reproducibility
10
10
  """
11
11
 
12
- __version__ = "0.26.1"
12
+ __version__ = "0.26.2"
13
13
 
14
14
  __all__ = ["__version__"]
@@ -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
- self.base_url = base_url or "https://dev.azure.com"
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
- wiql_parts = ["SELECT [System.Id], [System.Title], [System.State]"]
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
- url = f"{self.base_url}/{self.org}/{self.project}/_apis/wit/wiql"
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
- response = requests.post(url, headers=headers, json=payload, timeout=30)
2258
- response.raise_for_status()
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
- url = f"{self.base_url}/{self.org}/{self.project}/_apis/wit/workitems"
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
- response = requests.get(url, headers=headers, params=params, timeout=30)
2278
- response.raise_for_status()
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"{self.base_url}/{self.org}/{self.project}/_apis/wit/workitems/{work_item_id}"
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