specfact-cli 0.26.9__tar.gz → 0.26.10__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 (248) hide show
  1. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/.gitignore +4 -1
  2. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/PKG-INFO +1 -1
  3. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/pyproject.toml +1 -1
  4. specfact_cli-0.26.10/src/__init__.py +6 -0
  5. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/__init__.py +1 -1
  6. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/adapters/ado.py +14 -2
  7. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/adapters/openspec.py +11 -6
  8. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/adapters/openspec_parser.py +34 -1
  9. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/backlog/converter.py +18 -1
  10. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/commands/backlog_commands.py +4 -0
  11. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/models/backlog_item.py +5 -1
  12. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/models/bridge.py +1 -1
  13. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/sync/bridge_sync.py +14 -1
  14. specfact_cli-0.26.9/src/__init__.py +0 -6
  15. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/LICENSE.md +0 -0
  16. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/README.md +0 -0
  17. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/mappings/node-async.yaml +0 -0
  18. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/mappings/python-async.yaml +0 -0
  19. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/mappings/speckit-default.yaml +0 -0
  20. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/prompts/shared/cli-enforcement.md +0 -0
  21. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/prompts/specfact.01-import.md +0 -0
  22. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/prompts/specfact.02-plan.md +0 -0
  23. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/prompts/specfact.03-review.md +0 -0
  24. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/prompts/specfact.04-sdd.md +0 -0
  25. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/prompts/specfact.05-enforce.md +0 -0
  26. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/prompts/specfact.06-sync.md +0 -0
  27. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/prompts/specfact.07-contracts.md +0 -0
  28. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/prompts/specfact.backlog-refine.md +0 -0
  29. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/prompts/specfact.compare.md +0 -0
  30. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/prompts/specfact.sync-backlog.md +0 -0
  31. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/prompts/specfact.validate.md +0 -0
  32. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/schemas/deviation.schema.json +0 -0
  33. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/schemas/plan.schema.json +0 -0
  34. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/schemas/protocol.schema.json +0 -0
  35. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/backlog/defaults/defect_v1.yaml +0 -0
  36. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/backlog/defaults/enabler_v1.yaml +0 -0
  37. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/backlog/defaults/spike_v1.yaml +0 -0
  38. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/backlog/defaults/user_story_v1.yaml +0 -0
  39. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/backlog/field_mappings/ado_agile.yaml +0 -0
  40. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/backlog/field_mappings/ado_default.yaml +0 -0
  41. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/backlog/field_mappings/ado_kanban.yaml +0 -0
  42. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/backlog/field_mappings/ado_safe.yaml +0 -0
  43. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/backlog/field_mappings/ado_scrum.yaml +0 -0
  44. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/backlog/frameworks/safe/safe_feature_v1.yaml +0 -0
  45. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/backlog/frameworks/scrum/user_story_v1.yaml +0 -0
  46. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/backlog/personas/developer/developer_task_v1.yaml +0 -0
  47. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/backlog/personas/product-owner/user_story_v1.yaml +0 -0
  48. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/backlog/providers/ado/work_item_v1.yaml +0 -0
  49. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/github-action.yml.j2 +0 -0
  50. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/persona/architect.md.j2 +0 -0
  51. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/persona/developer.md.j2 +0 -0
  52. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/persona/product-owner.md.j2 +0 -0
  53. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/plan.bundle.yaml.j2 +0 -0
  54. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/pr-template.md.j2 +0 -0
  55. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/protocol.yaml.j2 +0 -0
  56. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/resources/templates/telemetry.yaml.example +0 -0
  57. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/adapters/__init__.py +0 -0
  58. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/adapters/backlog_base.py +0 -0
  59. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/adapters/base.py +0 -0
  60. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/adapters/github.py +0 -0
  61. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/adapters/registry.py +0 -0
  62. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/adapters/speckit.py +0 -0
  63. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/agents/__init__.py +0 -0
  64. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/agents/analyze_agent.py +0 -0
  65. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/agents/base.py +0 -0
  66. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/agents/plan_agent.py +0 -0
  67. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/agents/registry.py +0 -0
  68. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/agents/sync_agent.py +0 -0
  69. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/analyzers/__init__.py +0 -0
  70. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/analyzers/ambiguity_scanner.py +0 -0
  71. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/analyzers/code_analyzer.py +0 -0
  72. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/analyzers/constitution_evidence_extractor.py +0 -0
  73. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/analyzers/contract_extractor.py +0 -0
  74. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/analyzers/control_flow_analyzer.py +0 -0
  75. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/analyzers/graph_analyzer.py +0 -0
  76. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/analyzers/relationship_mapper.py +0 -0
  77. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/analyzers/requirement_extractor.py +0 -0
  78. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/analyzers/test_pattern_extractor.py +0 -0
  79. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/backlog/__init__.py +0 -0
  80. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/backlog/adapters/__init__.py +0 -0
  81. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/backlog/adapters/base.py +0 -0
  82. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/backlog/adapters/local_yaml_adapter.py +0 -0
  83. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/backlog/ai_refiner.py +0 -0
  84. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/backlog/filters.py +0 -0
  85. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/backlog/format_detector.py +0 -0
  86. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/backlog/formats/__init__.py +0 -0
  87. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/backlog/formats/base.py +0 -0
  88. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/backlog/formats/markdown_format.py +0 -0
  89. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/backlog/formats/structured_format.py +0 -0
  90. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/backlog/mappers/__init__.py +0 -0
  91. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/backlog/mappers/ado_mapper.py +0 -0
  92. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/backlog/mappers/base.py +0 -0
  93. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/backlog/mappers/github_mapper.py +0 -0
  94. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/backlog/mappers/template_config.py +0 -0
  95. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/backlog/template_detector.py +0 -0
  96. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/cli.py +0 -0
  97. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/commands/__init__.py +0 -0
  98. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/commands/analyze.py +0 -0
  99. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/commands/auth.py +0 -0
  100. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/commands/contract_cmd.py +0 -0
  101. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/commands/drift.py +0 -0
  102. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/commands/enforce.py +0 -0
  103. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/commands/generate.py +0 -0
  104. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/commands/import_cmd.py +0 -0
  105. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/commands/init.py +0 -0
  106. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/commands/migrate.py +0 -0
  107. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/commands/plan.py +0 -0
  108. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/commands/project_cmd.py +0 -0
  109. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/commands/repro.py +0 -0
  110. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/commands/sdd.py +0 -0
  111. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/commands/spec.py +0 -0
  112. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/commands/sync.py +0 -0
  113. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/commands/update.py +0 -0
  114. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/commands/validate.py +0 -0
  115. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/common/__init__.py +0 -0
  116. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/common/logger_setup.py +0 -0
  117. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/common/logging_utils.py +0 -0
  118. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/common/text_utils.py +0 -0
  119. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/common/utils.py +0 -0
  120. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/comparators/__init__.py +0 -0
  121. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/comparators/plan_comparator.py +0 -0
  122. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/contracts/__init__.py +0 -0
  123. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/contracts/crosshair_props.py +0 -0
  124. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/enrichers/constitution_enricher.py +0 -0
  125. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/enrichers/plan_enricher.py +0 -0
  126. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/generators/__init__.py +0 -0
  127. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/generators/contract_generator.py +0 -0
  128. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/generators/openapi_extractor.py +0 -0
  129. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/generators/persona_exporter.py +0 -0
  130. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/generators/plan_generator.py +0 -0
  131. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/generators/protocol_generator.py +0 -0
  132. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/generators/report_generator.py +0 -0
  133. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/generators/task_generator.py +0 -0
  134. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/generators/test_to_openapi.py +0 -0
  135. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/generators/workflow_generator.py +0 -0
  136. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/importers/__init__.py +0 -0
  137. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/importers/speckit_converter.py +0 -0
  138. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/importers/speckit_scanner.py +0 -0
  139. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/integrations/__init__.py +0 -0
  140. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/integrations/specmatic.py +0 -0
  141. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/merge/__init__.py +0 -0
  142. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/merge/resolver.py +0 -0
  143. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/migrations/__init__.py +0 -0
  144. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/migrations/plan_migrator.py +0 -0
  145. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/models/__init__.py +0 -0
  146. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/models/capabilities.py +0 -0
  147. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/models/change.py +0 -0
  148. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/models/contract.py +0 -0
  149. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/models/deviation.py +0 -0
  150. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/models/dor_config.py +0 -0
  151. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/models/enforcement.py +0 -0
  152. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/models/persona_template.py +0 -0
  153. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/models/plan.py +0 -0
  154. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/models/project.py +0 -0
  155. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/models/protocol.py +0 -0
  156. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/models/quality.py +0 -0
  157. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/models/sdd.py +0 -0
  158. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/models/source_tracking.py +0 -0
  159. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/models/task.py +0 -0
  160. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/modes/__init__.py +0 -0
  161. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/modes/detector.py +0 -0
  162. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/modes/router.py +0 -0
  163. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/parsers/__init__.py +0 -0
  164. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/parsers/persona_importer.py +0 -0
  165. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/resources/semgrep/async.yml +0 -0
  166. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/resources/semgrep/code-quality.yml +0 -0
  167. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/resources/semgrep/feature-detection.yml +0 -0
  168. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/runtime.py +0 -0
  169. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/sync/__init__.py +0 -0
  170. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/sync/bridge_probe.py +0 -0
  171. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/sync/bridge_watch.py +0 -0
  172. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/sync/change_detector.py +0 -0
  173. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/sync/code_to_spec.py +0 -0
  174. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/sync/drift_detector.py +0 -0
  175. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/sync/repository_sync.py +0 -0
  176. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/sync/spec_to_code.py +0 -0
  177. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/sync/spec_to_tests.py +0 -0
  178. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/sync/watcher.py +0 -0
  179. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/sync/watcher_enhanced.py +0 -0
  180. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/telemetry.py +0 -0
  181. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/templates/__init__.py +0 -0
  182. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/templates/bridge_templates.py +0 -0
  183. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/templates/defaults/defect_v1.yaml +0 -0
  184. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/templates/defaults/enabler_v1.yaml +0 -0
  185. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/templates/defaults/spike_v1.yaml +0 -0
  186. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/templates/defaults/user_story_v1.yaml +0 -0
  187. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/templates/frameworks/scrum/user_story_v1.yaml +0 -0
  188. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/templates/personas/product-owner/user_story_v1.yaml +0 -0
  189. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/templates/providers/ado/work_item_v1.yaml +0 -0
  190. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/templates/registry.py +0 -0
  191. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/templates/specification_templates.py +0 -0
  192. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/__init__.py +0 -0
  193. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/acceptance_criteria.py +0 -0
  194. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/auth_tokens.py +0 -0
  195. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/bundle_loader.py +0 -0
  196. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/code_change_detector.py +0 -0
  197. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/console.py +0 -0
  198. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/content_sanitizer.py +0 -0
  199. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/context_detection.py +0 -0
  200. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/enrichment_context.py +0 -0
  201. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/enrichment_parser.py +0 -0
  202. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/env_manager.py +0 -0
  203. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/feature_keys.py +0 -0
  204. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/git.py +0 -0
  205. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/github_annotations.py +0 -0
  206. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/ide_setup.py +0 -0
  207. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/incremental_check.py +0 -0
  208. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/metadata.py +0 -0
  209. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/optional_deps.py +0 -0
  210. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/performance.py +0 -0
  211. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/progress.py +0 -0
  212. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/progressive_disclosure.py +0 -0
  213. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/prompts.py +0 -0
  214. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/sdd_discovery.py +0 -0
  215. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/source_scanner.py +0 -0
  216. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/startup_checks.py +0 -0
  217. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/structure.py +0 -0
  218. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/structured_io.py +0 -0
  219. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/suggestions.py +0 -0
  220. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/terminal.py +0 -0
  221. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/utils/yaml_utils.py +0 -0
  222. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/__init__.py +0 -0
  223. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/agile_validation.py +0 -0
  224. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/change_proposal_integration.py +0 -0
  225. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/cli_first_validator.py +0 -0
  226. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/contract_validator.py +0 -0
  227. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/fsm.py +0 -0
  228. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/repro_checker.py +0 -0
  229. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/schema.py +0 -0
  230. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/sidecar/__init__.py +0 -0
  231. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/sidecar/contract_populator.py +0 -0
  232. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/sidecar/crosshair_runner.py +0 -0
  233. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/sidecar/crosshair_summary.py +0 -0
  234. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/sidecar/dependency_installer.py +0 -0
  235. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/sidecar/framework_detector.py +0 -0
  236. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/sidecar/frameworks/__init__.py +0 -0
  237. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/sidecar/frameworks/base.py +0 -0
  238. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/sidecar/frameworks/django.py +0 -0
  239. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/sidecar/frameworks/drf.py +0 -0
  240. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/sidecar/frameworks/fastapi.py +0 -0
  241. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/sidecar/frameworks/flask.py +0 -0
  242. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/sidecar/harness_generator.py +0 -0
  243. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/sidecar/models.py +0 -0
  244. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/sidecar/orchestrator.py +0 -0
  245. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/sidecar/specmatic_runner.py +0 -0
  246. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/validators/sidecar/unannotated_detector.py +0 -0
  247. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/versioning/__init__.py +0 -0
  248. {specfact_cli-0.26.9 → specfact_cli-0.26.10}/src/specfact_cli/versioning/analyzer.py +0 -0
@@ -96,7 +96,10 @@ docs/internal/
96
96
  # Ignore .specify artifacts
97
97
  .specify/
98
98
  .cursor/commands/speckit.*
99
- specs/
99
+ /specs/
100
+
101
+ # Include openspec/specs/ directory
102
+ !openspec/
100
103
 
101
104
  # Ignore specfact-cli prompt templates
102
105
  .cursor/commands/specfact-*
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specfact-cli
3
- Version: 0.26.9
3
+ Version: 0.26.10
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.9"
7
+ version = "0.26.10"
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"
@@ -0,0 +1,6 @@
1
+ """
2
+ SpecFact CLI - Spec→Contract→Sentinel tool for contract-driven development.
3
+ """
4
+
5
+ # Package version: keep in sync with pyproject.toml, setup.py, src/specfact_cli/__init__.py
6
+ __version__ = "0.26.10"
@@ -9,6 +9,6 @@ This package provides command-line tools for:
9
9
  - Validating reproducibility
10
10
  """
11
11
 
12
- __version__ = "0.26.8"
12
+ __version__ = "0.26.10"
13
13
 
14
14
  __all__ = ["__version__"]
@@ -2938,7 +2938,13 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
2938
2938
  from specfact_cli.backlog.converter import convert_ado_work_item_to_backlog_item
2939
2939
 
2940
2940
  for work_item in work_items_data.get("value", []):
2941
- backlog_item = convert_ado_work_item_to_backlog_item(work_item, provider="ado")
2941
+ backlog_item = convert_ado_work_item_to_backlog_item(
2942
+ work_item,
2943
+ provider="ado",
2944
+ base_url=self.base_url,
2945
+ org=self.org,
2946
+ project_name=self.project,
2947
+ )
2942
2948
  items.append(backlog_item)
2943
2949
 
2944
2950
  # Apply post-fetch filters that ADO API doesn't support directly
@@ -3258,4 +3264,10 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
3258
3264
  # Convert back to BacklogItem
3259
3265
  from specfact_cli.backlog.converter import convert_ado_work_item_to_backlog_item
3260
3266
 
3261
- return convert_ado_work_item_to_backlog_item(updated_work_item, provider="ado")
3267
+ return convert_ado_work_item_to_backlog_item(
3268
+ updated_work_item,
3269
+ provider="ado",
3270
+ base_url=self.base_url,
3271
+ org=self.org,
3272
+ project_name=self.project,
3273
+ )
@@ -57,11 +57,12 @@ class OpenSpecAdapter(BridgeAdapter):
57
57
  if bridge_config and bridge_config.external_base_path:
58
58
  base_path = bridge_config.external_base_path
59
59
 
60
- # Check for OpenSpec structure
60
+ # Check for OpenSpec structure (OPSX: config.yaml; legacy: project.md; or specs dir)
61
+ config_yaml = base_path / "openspec" / "config.yaml"
61
62
  project_md = base_path / "openspec" / "project.md"
62
63
  specs_dir = base_path / "openspec" / "specs"
63
64
 
64
- return project_md.exists() or (specs_dir.exists() and specs_dir.is_dir())
65
+ return config_yaml.exists() or project_md.exists() or (specs_dir.exists() and specs_dir.is_dir())
65
66
 
66
67
  @beartype
67
68
  @require(lambda repo_path: repo_path.exists(), "Repository path must exist")
@@ -179,8 +180,9 @@ class OpenSpecAdapter(BridgeAdapter):
179
180
  """
180
181
  config = BridgeConfig.preset_openspec()
181
182
 
182
- # Check if OpenSpec is in external repo
183
- if not (repo_path / "openspec" / "project.md").exists():
183
+ # Check if OpenSpec is in external repo (OPSX: config.yaml; legacy: project.md)
184
+ openspec_dir = repo_path / "openspec"
185
+ if not (openspec_dir / "config.yaml").exists() and not (openspec_dir / "project.md").exists():
184
186
  # Try to find external OpenSpec (this is a simple heuristic)
185
187
  # In practice, external_base_path should be provided via CLI option
186
188
  pass
@@ -422,10 +424,13 @@ class OpenSpecAdapter(BridgeAdapter):
422
424
  bridge_config: BridgeConfig | None,
423
425
  base_path: Path | None,
424
426
  ) -> None:
425
- """Import project context from OpenSpec project.md."""
427
+ """Import project context from OpenSpec project.md (legacy) or config.yaml (OPSX)."""
426
428
  from specfact_cli.models.plan import Idea
427
429
 
428
- parsed = self.parser.parse_project_md(project_md_path)
430
+ if project_md_path.name == "config.yaml" or project_md_path.suffix in (".yaml", ".yml"):
431
+ parsed = self.parser.parse_config_yaml(project_md_path)
432
+ else:
433
+ parsed = self.parser.parse_project_md(project_md_path)
429
434
 
430
435
  # Create Idea if it doesn't exist
431
436
  if not hasattr(project_bundle, "idea") or project_bundle.idea is None:
@@ -2,7 +2,8 @@
2
2
  OpenSpec parser for adapter-specific OpenSpec format parsing.
3
3
 
4
4
  This module provides parsing functionality for OpenSpec artifacts:
5
- - project.md (project context)
5
+ - project.md (project context, legacy)
6
+ - config.yaml (OPSX project context)
6
7
  - spec.md (feature specifications)
7
8
  - proposal.md (change proposals)
8
9
  - spec.md with ADDED/MODIFIED/REMOVED markers (delta specs)
@@ -13,6 +14,7 @@ from __future__ import annotations
13
14
  from pathlib import Path
14
15
  from typing import Any
15
16
 
17
+ import yaml
16
18
  from beartype import beartype
17
19
  from icontract import ensure, require
18
20
 
@@ -55,6 +57,37 @@ class OpenSpecParser:
55
57
  # Return None on parse error (consistent with missing file)
56
58
  return None
57
59
 
60
+ @beartype
61
+ @require(lambda path: isinstance(path, Path), "Path must be Path")
62
+ @ensure(lambda result: result is None or isinstance(result, dict), "Must return dict or None")
63
+ def parse_config_yaml(self, path: Path) -> dict[str, Any] | None:
64
+ """
65
+ Parse OpenSpec OPSX config.yaml (project context).
66
+
67
+ Args:
68
+ path: Path to openspec/config.yaml file
69
+
70
+ Returns:
71
+ Dictionary compatible with project context import:
72
+ - "context": List of context string(s) from context: block
73
+ - "purpose": Optional (empty list if not in YAML)
74
+ - "raw_content": Full file content
75
+ """
76
+ if not path.exists():
77
+ return None
78
+
79
+ try:
80
+ content = path.read_text(encoding="utf-8")
81
+ data = yaml.safe_load(content) or {}
82
+ result: dict[str, Any] = {"purpose": [], "context": [], "raw_content": content}
83
+ if isinstance(data.get("context"), str):
84
+ result["context"] = [data["context"].strip()]
85
+ elif isinstance(data.get("context"), list):
86
+ result["context"] = [str(c).strip() for c in data["context"] if c]
87
+ return result
88
+ except Exception:
89
+ return None
90
+
58
91
  @beartype
59
92
  @require(lambda path: isinstance(path, Path), "Path must be Path")
60
93
  @ensure(lambda result: result is None or isinstance(result, dict), "Must return dict or None")
@@ -10,6 +10,7 @@ from __future__ import annotations
10
10
  from datetime import UTC, datetime
11
11
  from pathlib import Path
12
12
  from typing import Any
13
+ from urllib.parse import quote
13
14
 
14
15
  from beartype import beartype
15
16
  from icontract import ensure, require
@@ -157,7 +158,12 @@ def convert_github_issue_to_backlog_item(item_data: dict[str, Any], provider: st
157
158
  @require(lambda provider: isinstance(provider, str) and len(provider) > 0, "Provider must be non-empty string")
158
159
  @ensure(lambda result: isinstance(result, BacklogItem), "Must return BacklogItem")
159
160
  def convert_ado_work_item_to_backlog_item(
160
- item_data: dict[str, Any], provider: str = "ado", custom_mapping_file: str | Path | None = None
161
+ item_data: dict[str, Any],
162
+ provider: str = "ado",
163
+ custom_mapping_file: str | Path | None = None,
164
+ base_url: str | None = None,
165
+ org: str | None = None,
166
+ project_name: str | None = None,
161
167
  ) -> BacklogItem:
162
168
  """
163
169
  Convert Azure DevOps work item data to BacklogItem.
@@ -167,6 +173,10 @@ def convert_ado_work_item_to_backlog_item(
167
173
  Args:
168
174
  item_data: ADO work item data from API (dict)
169
175
  provider: Provider name (default: "ado")
176
+ custom_mapping_file: Optional path to custom ADO field mapping file.
177
+ base_url: ADO base URL (e.g. https://dev.azure.com) for canonical URL.
178
+ org: ADO organization name for canonical URL.
179
+ project_name: ADO project name (URL-encoded in canonical URL) for opening in browser.
170
180
 
171
181
  Returns:
172
182
  BacklogItem instance with normalized fields
@@ -294,10 +304,17 @@ def convert_ado_work_item_to_backlog_item(
294
304
  "_links": item_data.get("_links", {}),
295
305
  }
296
306
 
307
+ canonical_url = None
308
+ if base_url and org and project_name:
309
+ base = base_url.rstrip("/")
310
+ encoded_project = quote(project_name, safe="")
311
+ canonical_url = f"{base}/{org}/{encoded_project}/_workitems/edit/{work_item_id}"
312
+
297
313
  return BacklogItem(
298
314
  id=work_item_id,
299
315
  provider=provider,
300
316
  url=url,
317
+ canonical_url=canonical_url,
301
318
  title=title,
302
319
  body_markdown=body_markdown,
303
320
  state=state,
@@ -635,6 +635,8 @@ def refine(
635
635
  export_content += f"## Item {idx}: {item.title}\n\n"
636
636
  export_content += f"**ID**: {item.id}\n"
637
637
  export_content += f"**URL**: {item.url}\n"
638
+ if item.canonical_url:
639
+ export_content += f"**Canonical URL**: {item.canonical_url}\n"
638
640
  export_content += f"**State**: {item.state}\n"
639
641
  export_content += f"**Provider**: {item.provider}\n"
640
642
 
@@ -806,6 +808,8 @@ def refine(
806
808
  console.print("\n[bold]Preview Mode: Full Item Details[/bold]")
807
809
  console.print(f"[bold]Title:[/bold] {item.title}")
808
810
  console.print(f"[bold]URL:[/bold] {item.url}")
811
+ if item.canonical_url:
812
+ console.print(f"[bold]Canonical URL:[/bold] {item.canonical_url}")
809
813
  console.print(f"[bold]State:[/bold] {item.state}")
810
814
  console.print(f"[bold]Provider:[/bold] {item.provider}")
811
815
  console.print(f"[bold]Assignee:[/bold] {', '.join(item.assignees) if item.assignees else 'Unassigned'}")
@@ -32,7 +32,11 @@ class BacklogItem(BaseModel):
32
32
  # Identity fields
33
33
  id: str = Field(..., description="Backlog item identifier (provider-specific)")
34
34
  provider: str = Field(..., description="Provider name (github, ado, jira, linear, etc.)")
35
- url: str = Field(..., description="Backlog item URL")
35
+ url: str = Field(..., description="Backlog item URL (API or provider URL)")
36
+ canonical_url: str | None = Field(
37
+ default=None,
38
+ description="User-friendly URL for opening in browser (e.g. ADO: org/project-name/_workitems/edit/id)",
39
+ )
36
40
 
37
41
  # Content fields
38
42
  title: str = Field(..., description="Backlog item title")
@@ -499,7 +499,7 @@ class BridgeConfig(BaseModel):
499
499
  Returns:
500
500
  BridgeConfig for OpenSpec integration with artifact mappings for:
501
501
  - specification: openspec/specs/{feature_id}/spec.md
502
- - project_context: openspec/project.md
502
+ - project_context: openspec/config.yaml (OPSX) if present, else openspec/project.md (legacy)
503
503
  - change_proposal: openspec/changes/{change_name}/proposal.md
504
504
  - change_tasks: openspec/changes/{change_name}/tasks.md
505
505
  - change_spec_delta: openspec/changes/{change_name}/specs/{feature_id}/spec.md
@@ -31,7 +31,7 @@ from rich.progress import Progress
31
31
  from rich.table import Table
32
32
 
33
33
  from specfact_cli.adapters.registry import AdapterRegistry
34
- from specfact_cli.models.bridge import BridgeConfig
34
+ from specfact_cli.models.bridge import AdapterType, BridgeConfig
35
35
  from specfact_cli.runtime import get_configured_console
36
36
  from specfact_cli.sync.bridge_probe import BridgeProbe
37
37
  from specfact_cli.utils.bundle_loader import load_project_bundle, save_project_bundle
@@ -188,6 +188,19 @@ class BridgeSync:
188
188
  msg = "Bridge config not initialized"
189
189
  raise ValueError(msg)
190
190
 
191
+ base_path = self.repo_path
192
+ if self.bridge_config.external_base_path is not None:
193
+ base_path = self.bridge_config.external_base_path
194
+
195
+ if artifact_key == "project_context" and self.bridge_config.adapter == AdapterType.OPENSPEC:
196
+ config_yaml = base_path / "openspec" / "config.yaml"
197
+ project_md = base_path / "openspec" / "project.md"
198
+ if config_yaml.exists():
199
+ return config_yaml
200
+ if project_md.exists():
201
+ return project_md
202
+ return project_md
203
+
191
204
  context = {
192
205
  "feature_id": feature_id,
193
206
  "bundle_name": bundle_name,
@@ -1,6 +0,0 @@
1
- """
2
- SpecFact CLI - Spec→Contract→Sentinel tool for contract-driven development.
3
- """
4
-
5
- # Define the package version (kept in sync with pyproject.toml and setup.py)
6
- __version__ = "0.26.7"
File without changes
File without changes