specfact-cli 0.26.16__tar.gz → 0.26.17__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 (249) hide show
  1. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/PKG-INFO +1 -1
  2. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/pyproject.toml +1 -1
  3. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/__init__.py +1 -1
  4. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/__init__.py +1 -1
  5. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/analyzers/ambiguity_scanner.py +5 -9
  6. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/commands/backlog_commands.py +126 -53
  7. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/generators/report_generator.py +2 -2
  8. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/merge/resolver.py +8 -8
  9. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/models/bridge.py +2 -2
  10. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/models/change.py +2 -2
  11. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/models/contract.py +2 -2
  12. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/models/deviation.py +3 -3
  13. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/models/enforcement.py +3 -3
  14. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/models/persona_template.py +2 -2
  15. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/models/project.py +2 -2
  16. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/models/task.py +3 -3
  17. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/modes/detector.py +2 -2
  18. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/runtime.py +2 -2
  19. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/env_manager.py +2 -2
  20. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/structured_io.py +2 -2
  21. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/sidecar/crosshair_summary.py +2 -2
  22. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/sidecar/frameworks/django.py +3 -6
  23. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/sidecar/frameworks/fastapi.py +3 -6
  24. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/sidecar/frameworks/flask.py +3 -6
  25. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/sidecar/models.py +2 -2
  26. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/versioning/analyzer.py +2 -2
  27. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/.gitignore +0 -0
  28. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/LICENSE.md +0 -0
  29. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/README.md +0 -0
  30. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/mappings/node-async.yaml +0 -0
  31. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/mappings/python-async.yaml +0 -0
  32. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/mappings/speckit-default.yaml +0 -0
  33. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/prompts/shared/cli-enforcement.md +0 -0
  34. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/prompts/specfact.01-import.md +0 -0
  35. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/prompts/specfact.02-plan.md +0 -0
  36. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/prompts/specfact.03-review.md +0 -0
  37. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/prompts/specfact.04-sdd.md +0 -0
  38. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/prompts/specfact.05-enforce.md +0 -0
  39. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/prompts/specfact.06-sync.md +0 -0
  40. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/prompts/specfact.07-contracts.md +0 -0
  41. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/prompts/specfact.backlog-daily.md +0 -0
  42. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/prompts/specfact.backlog-refine.md +0 -0
  43. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/prompts/specfact.compare.md +0 -0
  44. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/prompts/specfact.sync-backlog.md +0 -0
  45. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/prompts/specfact.validate.md +0 -0
  46. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/schemas/deviation.schema.json +0 -0
  47. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/schemas/plan.schema.json +0 -0
  48. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/schemas/protocol.schema.json +0 -0
  49. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/backlog/defaults/defect_v1.yaml +0 -0
  50. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/backlog/defaults/enabler_v1.yaml +0 -0
  51. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/backlog/defaults/spike_v1.yaml +0 -0
  52. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/backlog/defaults/user_story_v1.yaml +0 -0
  53. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/backlog/field_mappings/ado_agile.yaml +0 -0
  54. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/backlog/field_mappings/ado_default.yaml +0 -0
  55. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/backlog/field_mappings/ado_kanban.yaml +0 -0
  56. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/backlog/field_mappings/ado_safe.yaml +0 -0
  57. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/backlog/field_mappings/ado_scrum.yaml +0 -0
  58. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/backlog/frameworks/safe/safe_feature_v1.yaml +0 -0
  59. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/backlog/frameworks/scrum/user_story_v1.yaml +0 -0
  60. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/backlog/personas/developer/developer_task_v1.yaml +0 -0
  61. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/backlog/personas/product-owner/user_story_v1.yaml +0 -0
  62. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/backlog/providers/ado/work_item_v1.yaml +0 -0
  63. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/github-action.yml.j2 +0 -0
  64. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/persona/architect.md.j2 +0 -0
  65. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/persona/developer.md.j2 +0 -0
  66. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/persona/product-owner.md.j2 +0 -0
  67. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/plan.bundle.yaml.j2 +0 -0
  68. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/pr-template.md.j2 +0 -0
  69. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/protocol.yaml.j2 +0 -0
  70. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/resources/templates/telemetry.yaml.example +0 -0
  71. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/__main__.py +0 -0
  72. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/adapters/__init__.py +0 -0
  73. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/adapters/ado.py +0 -0
  74. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/adapters/backlog_base.py +0 -0
  75. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/adapters/base.py +0 -0
  76. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/adapters/github.py +0 -0
  77. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/adapters/openspec.py +0 -0
  78. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/adapters/openspec_parser.py +0 -0
  79. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/adapters/registry.py +0 -0
  80. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/adapters/speckit.py +0 -0
  81. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/agents/__init__.py +0 -0
  82. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/agents/analyze_agent.py +0 -0
  83. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/agents/base.py +0 -0
  84. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/agents/plan_agent.py +0 -0
  85. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/agents/registry.py +0 -0
  86. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/agents/sync_agent.py +0 -0
  87. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/analyzers/__init__.py +0 -0
  88. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/analyzers/code_analyzer.py +0 -0
  89. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/analyzers/constitution_evidence_extractor.py +0 -0
  90. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/analyzers/contract_extractor.py +0 -0
  91. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/analyzers/control_flow_analyzer.py +0 -0
  92. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/analyzers/graph_analyzer.py +0 -0
  93. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/analyzers/relationship_mapper.py +0 -0
  94. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/analyzers/requirement_extractor.py +0 -0
  95. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/analyzers/test_pattern_extractor.py +0 -0
  96. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/backlog/__init__.py +0 -0
  97. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/backlog/adapters/__init__.py +0 -0
  98. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/backlog/adapters/base.py +0 -0
  99. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/backlog/adapters/local_yaml_adapter.py +0 -0
  100. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/backlog/ai_refiner.py +0 -0
  101. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/backlog/converter.py +0 -0
  102. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/backlog/filters.py +0 -0
  103. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/backlog/format_detector.py +0 -0
  104. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/backlog/formats/__init__.py +0 -0
  105. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/backlog/formats/base.py +0 -0
  106. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/backlog/formats/markdown_format.py +0 -0
  107. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/backlog/formats/structured_format.py +0 -0
  108. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/backlog/mappers/__init__.py +0 -0
  109. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/backlog/mappers/ado_mapper.py +0 -0
  110. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/backlog/mappers/base.py +0 -0
  111. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/backlog/mappers/github_mapper.py +0 -0
  112. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/backlog/mappers/template_config.py +0 -0
  113. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/backlog/template_detector.py +0 -0
  114. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/cli.py +0 -0
  115. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/commands/__init__.py +0 -0
  116. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/commands/analyze.py +0 -0
  117. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/commands/auth.py +0 -0
  118. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/commands/contract_cmd.py +0 -0
  119. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/commands/drift.py +0 -0
  120. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/commands/enforce.py +0 -0
  121. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/commands/generate.py +0 -0
  122. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/commands/import_cmd.py +0 -0
  123. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/commands/init.py +0 -0
  124. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/commands/migrate.py +0 -0
  125. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/commands/plan.py +0 -0
  126. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/commands/project_cmd.py +0 -0
  127. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/commands/repro.py +0 -0
  128. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/commands/sdd.py +0 -0
  129. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/commands/spec.py +0 -0
  130. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/commands/sync.py +0 -0
  131. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/commands/update.py +0 -0
  132. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/commands/validate.py +0 -0
  133. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/common/__init__.py +0 -0
  134. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/common/logger_setup.py +0 -0
  135. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/common/logging_utils.py +0 -0
  136. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/common/text_utils.py +0 -0
  137. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/common/utils.py +0 -0
  138. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/comparators/__init__.py +0 -0
  139. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/comparators/plan_comparator.py +0 -0
  140. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/contracts/__init__.py +0 -0
  141. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/contracts/crosshair_props.py +0 -0
  142. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/enrichers/constitution_enricher.py +0 -0
  143. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/enrichers/plan_enricher.py +0 -0
  144. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/generators/__init__.py +0 -0
  145. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/generators/contract_generator.py +0 -0
  146. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/generators/openapi_extractor.py +0 -0
  147. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/generators/persona_exporter.py +0 -0
  148. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/generators/plan_generator.py +0 -0
  149. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/generators/protocol_generator.py +0 -0
  150. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/generators/task_generator.py +0 -0
  151. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/generators/test_to_openapi.py +0 -0
  152. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/generators/workflow_generator.py +0 -0
  153. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/importers/__init__.py +0 -0
  154. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/importers/speckit_converter.py +0 -0
  155. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/importers/speckit_scanner.py +0 -0
  156. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/integrations/__init__.py +0 -0
  157. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/integrations/specmatic.py +0 -0
  158. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/merge/__init__.py +0 -0
  159. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/migrations/__init__.py +0 -0
  160. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/migrations/plan_migrator.py +0 -0
  161. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/models/__init__.py +0 -0
  162. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/models/backlog_item.py +0 -0
  163. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/models/capabilities.py +0 -0
  164. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/models/dor_config.py +0 -0
  165. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/models/plan.py +0 -0
  166. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/models/protocol.py +0 -0
  167. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/models/quality.py +0 -0
  168. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/models/sdd.py +0 -0
  169. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/models/source_tracking.py +0 -0
  170. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/modes/__init__.py +0 -0
  171. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/modes/router.py +0 -0
  172. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/parsers/__init__.py +0 -0
  173. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/parsers/persona_importer.py +0 -0
  174. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/resources/semgrep/async.yml +0 -0
  175. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/resources/semgrep/code-quality.yml +0 -0
  176. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/resources/semgrep/feature-detection.yml +0 -0
  177. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/sync/__init__.py +0 -0
  178. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/sync/bridge_probe.py +0 -0
  179. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/sync/bridge_sync.py +0 -0
  180. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/sync/bridge_watch.py +0 -0
  181. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/sync/change_detector.py +0 -0
  182. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/sync/code_to_spec.py +0 -0
  183. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/sync/drift_detector.py +0 -0
  184. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/sync/repository_sync.py +0 -0
  185. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/sync/spec_to_code.py +0 -0
  186. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/sync/spec_to_tests.py +0 -0
  187. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/sync/watcher.py +0 -0
  188. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/sync/watcher_enhanced.py +0 -0
  189. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/telemetry.py +0 -0
  190. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/templates/__init__.py +0 -0
  191. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/templates/bridge_templates.py +0 -0
  192. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/templates/defaults/defect_v1.yaml +0 -0
  193. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/templates/defaults/enabler_v1.yaml +0 -0
  194. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/templates/defaults/spike_v1.yaml +0 -0
  195. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/templates/defaults/user_story_v1.yaml +0 -0
  196. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/templates/frameworks/scrum/user_story_v1.yaml +0 -0
  197. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/templates/personas/product-owner/user_story_v1.yaml +0 -0
  198. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/templates/providers/ado/work_item_v1.yaml +0 -0
  199. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/templates/registry.py +0 -0
  200. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/templates/specification_templates.py +0 -0
  201. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/__init__.py +0 -0
  202. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/acceptance_criteria.py +0 -0
  203. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/auth_tokens.py +0 -0
  204. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/bundle_loader.py +0 -0
  205. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/code_change_detector.py +0 -0
  206. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/console.py +0 -0
  207. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/content_sanitizer.py +0 -0
  208. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/context_detection.py +0 -0
  209. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/enrichment_context.py +0 -0
  210. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/enrichment_parser.py +0 -0
  211. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/feature_keys.py +0 -0
  212. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/git.py +0 -0
  213. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/github_annotations.py +0 -0
  214. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/ide_setup.py +0 -0
  215. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/incremental_check.py +0 -0
  216. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/metadata.py +0 -0
  217. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/optional_deps.py +0 -0
  218. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/performance.py +0 -0
  219. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/progress.py +0 -0
  220. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/progressive_disclosure.py +0 -0
  221. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/prompts.py +0 -0
  222. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/sdd_discovery.py +0 -0
  223. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/source_scanner.py +0 -0
  224. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/startup_checks.py +0 -0
  225. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/structure.py +0 -0
  226. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/suggestions.py +0 -0
  227. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/terminal.py +0 -0
  228. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/utils/yaml_utils.py +0 -0
  229. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/__init__.py +0 -0
  230. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/agile_validation.py +0 -0
  231. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/change_proposal_integration.py +0 -0
  232. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/cli_first_validator.py +0 -0
  233. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/contract_validator.py +0 -0
  234. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/fsm.py +0 -0
  235. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/repro_checker.py +0 -0
  236. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/schema.py +0 -0
  237. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/sidecar/__init__.py +0 -0
  238. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/sidecar/contract_populator.py +0 -0
  239. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/sidecar/crosshair_runner.py +0 -0
  240. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/sidecar/dependency_installer.py +0 -0
  241. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/sidecar/framework_detector.py +0 -0
  242. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/sidecar/frameworks/__init__.py +0 -0
  243. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/sidecar/frameworks/base.py +0 -0
  244. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/sidecar/frameworks/drf.py +0 -0
  245. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/sidecar/harness_generator.py +0 -0
  246. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/sidecar/orchestrator.py +0 -0
  247. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/sidecar/specmatic_runner.py +0 -0
  248. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/validators/sidecar/unannotated_detector.py +0 -0
  249. {specfact_cli-0.26.16 → specfact_cli-0.26.17}/src/specfact_cli/versioning/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specfact-cli
3
- Version: 0.26.16
3
+ Version: 0.26.17
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.16"
7
+ version = "0.26.17"
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"
@@ -3,4 +3,4 @@ SpecFact CLI - Spec→Contract→Sentinel tool for contract-driven development.
3
3
  """
4
4
 
5
5
  # Package version: keep in sync with pyproject.toml, setup.py, src/specfact_cli/__init__.py
6
- __version__ = "0.26.16"
6
+ __version__ = "0.26.17"
@@ -9,6 +9,6 @@ This package provides command-line tools for:
9
9
  - Validating reproducibility
10
10
  """
11
11
 
12
- __version__ = "0.26.16"
12
+ __version__ = "0.26.17"
13
13
 
14
14
  __all__ = ["__version__"]
@@ -10,7 +10,7 @@ from __future__ import annotations
10
10
  import ast
11
11
  import re
12
12
  from dataclasses import dataclass
13
- from enum import Enum
13
+ from enum import StrEnum
14
14
  from pathlib import Path
15
15
 
16
16
  from beartype import beartype
@@ -19,7 +19,7 @@ from icontract import ensure, require
19
19
  from specfact_cli.models.plan import PlanBundle
20
20
 
21
21
 
22
- class AmbiguityStatus(str, Enum):
22
+ class AmbiguityStatus(StrEnum):
23
23
  """Ambiguity status levels."""
24
24
 
25
25
  CLEAR = "Clear"
@@ -27,7 +27,7 @@ class AmbiguityStatus(str, Enum):
27
27
  MISSING = "Missing"
28
28
 
29
29
 
30
- class TaxonomyCategory(str, Enum):
30
+ class TaxonomyCategory(StrEnum):
31
31
  """Taxonomy categories for ambiguity detection."""
32
32
 
33
33
  FUNCTIONAL_SCOPE = "Functional Scope & Behavior"
@@ -910,12 +910,8 @@ class AmbiguityScanner:
910
910
  # Look for role/permission constants (e.g., ADMIN = "admin")
911
911
  if (
912
912
  "role" in attr_name or "permission" in attr_name
913
- ) and isinstance(item.value, (ast.Str, ast.Constant)):
914
- role_value = (
915
- item.value.s
916
- if isinstance(item.value, ast.Str)
917
- else item.value
918
- )
913
+ ) and isinstance(item.value, ast.Constant):
914
+ role_value = item.value.value
919
915
  if isinstance(role_value, str) and len(role_value) > 2:
920
916
  role_clean = role_value.strip().lower()
921
917
  if (
@@ -168,8 +168,8 @@ def _load_standup_config() -> dict[str, Any]:
168
168
  with open(path, encoding="utf-8") as f:
169
169
  data = yaml.safe_load(f) or {}
170
170
  config = dict(data.get("standup", data))
171
- except Exception:
172
- pass
171
+ except Exception as exc:
172
+ debug_log_operation("config_load", str(path), "error", error=repr(exc))
173
173
  break
174
174
  if os.environ.get("SPECFACT_STANDUP_STATE"):
175
175
  config["default_state"] = os.environ["SPECFACT_STANDUP_STATE"]
@@ -203,8 +203,8 @@ def _load_backlog_config() -> dict[str, Any]:
203
203
  config = dict(nested) if isinstance(nested, dict) else {}
204
204
  else:
205
205
  config = dict(data) if isinstance(data, dict) else {}
206
- except Exception:
207
- pass
206
+ except Exception as exc:
207
+ debug_log_operation("config_load", str(path), "error", error=repr(exc))
208
208
  break
209
209
  return config
210
210
 
@@ -378,20 +378,66 @@ def _format_daily_item_detail(item: BacklogItem, comments: list[str]) -> str:
378
378
  return "\n".join(parts)
379
379
 
380
380
 
381
+ def _collect_comment_annotations(
382
+ adapter: str,
383
+ items: list[BacklogItem],
384
+ *,
385
+ repo_owner: str | None,
386
+ repo_name: str | None,
387
+ github_token: str | None,
388
+ ado_org: str | None,
389
+ ado_project: str | None,
390
+ ado_token: str | None,
391
+ ) -> dict[str, list[str]]:
392
+ """
393
+ Collect comment annotations for backlog items when the adapter supports get_comments().
394
+
395
+ Returns a mapping of item ID -> list of comment strings. Returns empty dict if not supported.
396
+ """
397
+ comments_by_item_id: dict[str, list[str]] = {}
398
+ try:
399
+ adapter_kwargs = _build_adapter_kwargs(
400
+ adapter,
401
+ repo_owner=repo_owner,
402
+ repo_name=repo_name,
403
+ github_token=github_token,
404
+ ado_org=ado_org,
405
+ ado_project=ado_project,
406
+ ado_token=ado_token,
407
+ )
408
+ registry = AdapterRegistry()
409
+ adapter_instance = registry.get_adapter(adapter, **adapter_kwargs)
410
+ if not isinstance(adapter_instance, BacklogAdapter):
411
+ return comments_by_item_id
412
+ get_comments_fn = getattr(adapter_instance, "get_comments", None)
413
+ if not callable(get_comments_fn):
414
+ return comments_by_item_id
415
+ for item in items:
416
+ with contextlib.suppress(Exception):
417
+ raw = get_comments_fn(item)
418
+ comments_by_item_id[item.id] = list(raw) if isinstance(raw, list) else []
419
+ except Exception:
420
+ return comments_by_item_id
421
+ return comments_by_item_id
422
+
423
+
381
424
  @beartype
382
425
  def _build_copilot_export_content(
383
426
  items: list[BacklogItem],
384
427
  include_value_score: bool = False,
428
+ include_comments: bool = False,
429
+ comments_by_item_id: dict[str, list[str]] | None = None,
385
430
  ) -> str:
386
431
  """
387
432
  Build Markdown content for Copilot export: one section per item.
388
433
 
389
434
  Per item: ID, title, status, assignees, last updated, progress summary (standup fields),
390
- blockers, and optionally value score.
435
+ blockers, optional value score, and optionally description/comments when enabled.
391
436
  """
392
437
  lines: list[str] = []
393
438
  lines.append("# Daily standup – Copilot export")
394
439
  lines.append("")
440
+ comments_map = comments_by_item_id or {}
395
441
  for item in items:
396
442
  lines.append(f"## {item.id} - {item.title}")
397
443
  lines.append("")
@@ -402,11 +448,26 @@ def _build_copilot_export_content(
402
448
  item.updated_at.strftime("%Y-%m-%d %H:%M") if hasattr(item.updated_at, "strftime") else str(item.updated_at)
403
449
  )
404
450
  lines.append(f"- **Last updated:** {updated}")
451
+ if include_comments:
452
+ body = (item.body_markdown or "").strip()
453
+ if body:
454
+ snippet = body[:_SUMMARIZE_BODY_TRUNCATE]
455
+ if len(body) > _SUMMARIZE_BODY_TRUNCATE:
456
+ snippet += "\n..."
457
+ lines.append("- **Description:**")
458
+ for line in snippet.splitlines():
459
+ lines.append(f" {line}" if line else " ")
405
460
  yesterday, today, blockers = _parse_standup_from_body(item.body_markdown or "")
406
461
  if yesterday or today:
407
462
  lines.append(f"- **Progress:** Yesterday: {yesterday or '—'}; Today: {today or '—'}")
408
463
  if blockers:
409
464
  lines.append(f"- **Blockers:** {blockers}")
465
+ if include_comments:
466
+ item_comments = comments_map.get(item.id, [])
467
+ if item_comments:
468
+ lines.append("- **Comments (annotations):**")
469
+ for c in item_comments:
470
+ lines.append(f" - {c}")
410
471
  if item.story_points is not None:
411
472
  lines.append(f"- **Story points:** {item.story_points}")
412
473
  if item.priority is not None:
@@ -428,19 +489,25 @@ def _build_summarize_prompt_content(
428
489
  filter_context: dict[str, Any],
429
490
  include_value_score: bool = False,
430
491
  comments_by_item_id: dict[str, list[str]] | None = None,
492
+ include_comments: bool = False,
431
493
  ) -> str:
432
494
  """
433
495
  Build prompt content for standup summary: instruction + filter context + per-item data.
434
496
 
435
- Includes body (description) and annotations (comments) per item so an LLM can produce
436
- a meaningful summary. For use with slash command (e.g. specfact.daily) or copy-paste to Copilot.
497
+ When include_comments is True, includes body (description) and annotations (comments) per item
498
+ so an LLM can produce a meaningful summary. When False, only metadata (id, title, status,
499
+ assignees, last updated) is included to avoid leaking sensitive or large context.
500
+ For use with slash command (e.g. specfact.daily) or copy-paste to Copilot.
437
501
  """
438
502
  lines: list[str] = []
439
503
  lines.append("--- BEGIN STANDUP PROMPT ---")
440
504
  lines.append("Generate a concise daily standup summary from the following data.")
441
- lines.append(
442
- "Include: current focus, blockers, and pending items. Use each item's description and comments for context. Keep it short and actionable."
443
- )
505
+ if include_comments:
506
+ lines.append(
507
+ "Include: current focus, blockers, and pending items. Use each item's description and comments for context. Keep it short and actionable."
508
+ )
509
+ else:
510
+ lines.append("Include: current focus and pending items from the metadata below. Keep it short and actionable.")
444
511
  lines.append("")
445
512
  lines.append("## Filter context")
446
513
  lines.append(f"- Adapter: {filter_context.get('adapter', '—')}")
@@ -449,7 +516,8 @@ def _build_summarize_prompt_content(
449
516
  lines.append(f"- Assignee: {filter_context.get('assignee', '—')}")
450
517
  lines.append(f"- Limit: {filter_context.get('limit', '—')}")
451
518
  lines.append("")
452
- lines.append("## Standup data (with description and comments)")
519
+ data_header = "Standup data (with description and comments)" if include_comments else "Standup data (metadata only)"
520
+ lines.append(f"## {data_header}")
453
521
  lines.append("")
454
522
  comments_map = comments_by_item_id or {}
455
523
  for item in items:
@@ -462,24 +530,25 @@ def _build_summarize_prompt_content(
462
530
  item.updated_at.strftime("%Y-%m-%d %H:%M") if hasattr(item.updated_at, "strftime") else str(item.updated_at)
463
531
  )
464
532
  lines.append(f"- **Last updated:** {updated}")
465
- body = (item.body_markdown or "").strip()
466
- if body:
467
- snippet = body[:_SUMMARIZE_BODY_TRUNCATE]
468
- if len(body) > _SUMMARIZE_BODY_TRUNCATE:
469
- snippet += "\n..."
470
- lines.append("- **Description:**")
471
- lines.append(snippet)
472
- lines.append("")
473
- yesterday, today, blockers = _parse_standup_from_body(item.body_markdown or "")
474
- if yesterday or today:
475
- lines.append(f"- **Progress:** Yesterday: {yesterday or '—'}; Today: {today or '—'}")
476
- if blockers:
477
- lines.append(f"- **Blockers:** {blockers}")
478
- item_comments = comments_map.get(item.id, [])
479
- if item_comments:
480
- lines.append("- **Comments (annotations):**")
481
- for c in item_comments:
482
- lines.append(f" - {c}")
533
+ if include_comments:
534
+ body = (item.body_markdown or "").strip()
535
+ if body:
536
+ snippet = body[:_SUMMARIZE_BODY_TRUNCATE]
537
+ if len(body) > _SUMMARIZE_BODY_TRUNCATE:
538
+ snippet += "\n..."
539
+ lines.append("- **Description:**")
540
+ lines.append(snippet)
541
+ lines.append("")
542
+ yesterday, today, blockers = _parse_standup_from_body(item.body_markdown or "")
543
+ if yesterday or today:
544
+ lines.append(f"- **Progress:** Yesterday: {yesterday or '—'}; Today: {today or '—'}")
545
+ if blockers:
546
+ lines.append(f"- **Blockers:** {blockers}")
547
+ item_comments = comments_map.get(item.id, [])
548
+ if item_comments:
549
+ lines.append("- **Comments (annotations):**")
550
+ for c in item_comments:
551
+ lines.append(f" - {c}")
483
552
  if item.story_points is not None:
484
553
  lines.append(f"- **Story points:** {item.story_points}")
485
554
  if item.priority is not None:
@@ -559,7 +628,7 @@ def _run_interactive_daily(
559
628
  console.print(Panel(detail, title=f"Story: {item.id}", border_style="cyan"))
560
629
 
561
630
  if suggest_next and n > 1:
562
- pending = [i for i in items if not i.assignees or item.story_points is not None]
631
+ pending = [i for i in items if not i.assignees or i.story_points is not None]
563
632
  if pending:
564
633
  best: BacklogItem | None = None
565
634
  best_score: float = -1.0
@@ -1030,6 +1099,12 @@ def daily(
1030
1099
  "--copilot-export",
1031
1100
  help="Write summarized progress per story to a file for Copilot slash-command use during standup.",
1032
1101
  ),
1102
+ include_comments: bool = typer.Option(
1103
+ False,
1104
+ "--comments",
1105
+ "--annotations",
1106
+ help="Include item comments/annotations in summarize/copilot export (adapter must support get_comments).",
1107
+ ),
1033
1108
  summarize: bool = typer.Option(
1034
1109
  False,
1035
1110
  "--summarize",
@@ -1118,10 +1193,28 @@ def daily(
1118
1193
  console.print("[yellow]No backlog items found.[/yellow]")
1119
1194
  return
1120
1195
 
1196
+ comments_by_item_id: dict[str, list[str]] = {}
1197
+ if include_comments and (copilot_export is not None or summarize or summarize_to is not None):
1198
+ comments_by_item_id = _collect_comment_annotations(
1199
+ adapter,
1200
+ filtered,
1201
+ repo_owner=repo_owner,
1202
+ repo_name=repo_name,
1203
+ github_token=github_token,
1204
+ ado_org=ado_org,
1205
+ ado_project=ado_project,
1206
+ ado_token=ado_token,
1207
+ )
1208
+
1121
1209
  if copilot_export is not None:
1122
1210
  include_score = suggest_next or bool(standup_config.get("suggest_next"))
1123
1211
  export_path = Path(copilot_export)
1124
- content = _build_copilot_export_content(filtered, include_value_score=include_score)
1212
+ content = _build_copilot_export_content(
1213
+ filtered,
1214
+ include_value_score=include_score,
1215
+ include_comments=include_comments,
1216
+ comments_by_item_id=comments_by_item_id or None,
1217
+ )
1125
1218
  export_path.write_text(content, encoding="utf-8")
1126
1219
  console.print(f"[dim]Exported {len(filtered)} item(s) to {export_path}[/dim]")
1127
1220
 
@@ -1134,32 +1227,12 @@ def daily(
1134
1227
  "assignee": effective_assignee or "—",
1135
1228
  "limit": effective_limit,
1136
1229
  }
1137
- comments_by_item_id: dict[str, list[str]] = {}
1138
- try:
1139
- adapter_kwargs_sum = _build_adapter_kwargs(
1140
- adapter,
1141
- repo_owner=repo_owner,
1142
- repo_name=repo_name,
1143
- github_token=github_token,
1144
- ado_org=ado_org,
1145
- ado_project=ado_project,
1146
- ado_token=ado_token,
1147
- )
1148
- registry_sum = AdapterRegistry()
1149
- adapter_instance_sum = registry_sum.get_adapter(adapter, **adapter_kwargs_sum)
1150
- get_comments_fn = getattr(adapter_instance_sum, "get_comments", None)
1151
- if callable(get_comments_fn):
1152
- for it in filtered:
1153
- with contextlib.suppress(Exception):
1154
- raw = get_comments_fn(it)
1155
- comments_by_item_id[it.id] = list(raw) if isinstance(raw, list) else []
1156
- except Exception:
1157
- pass
1158
1230
  content = _build_summarize_prompt_content(
1159
1231
  filtered,
1160
1232
  filter_context=filter_ctx,
1161
1233
  include_value_score=include_score,
1162
1234
  comments_by_item_id=comments_by_item_id or None,
1235
+ include_comments=include_comments,
1163
1236
  )
1164
1237
  if summarize_to:
1165
1238
  Path(summarize_to).write_text(content, encoding="utf-8")
@@ -1245,7 +1318,7 @@ def daily(
1245
1318
  end_date = dt.strptime(str(sprint_end)[:10], "%Y-%m-%d").date()
1246
1319
  console.print(f"[dim]{_format_sprint_end_header(end_date)}[/dim]")
1247
1320
  except (ValueError, TypeError):
1248
- pass
1321
+ console.print("[dim]Sprint end date could not be parsed; header skipped.[/dim]")
1249
1322
 
1250
1323
  def _add_standup_rows_to_table(tbl: Table, row_list: list[dict[str, Any]], include_pri: bool) -> None:
1251
1324
  for r in row_list:
@@ -3,7 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import json
6
- from enum import Enum
6
+ from enum import StrEnum
7
7
  from pathlib import Path
8
8
 
9
9
  from beartype import beartype
@@ -14,7 +14,7 @@ from specfact_cli.models.deviation import Deviation, DeviationReport, Validation
14
14
  from specfact_cli.utils.structured_io import StructuredFormat, dump_structured_file
15
15
 
16
16
 
17
- class ReportFormat(str, Enum):
17
+ class ReportFormat(StrEnum):
18
18
  """Report output format."""
19
19
 
20
20
  MARKDOWN = "markdown"
@@ -8,7 +8,7 @@ enabling automatic conflict resolution based on section ownership.
8
8
  from __future__ import annotations
9
9
 
10
10
  from dataclasses import dataclass
11
- from enum import Enum
11
+ from enum import StrEnum
12
12
  from typing import Any
13
13
 
14
14
  from beartype import beartype
@@ -17,7 +17,7 @@ from icontract import ensure, require
17
17
  from specfact_cli.models.project import BundleManifest, ProjectBundle
18
18
 
19
19
 
20
- class MergeStrategy(str, Enum):
20
+ class MergeStrategy(StrEnum):
21
21
  """Merge resolution strategy."""
22
22
 
23
23
  AUTO = "auto" # Automatic resolution based on persona ownership
@@ -102,7 +102,7 @@ class PersonaMergeResolver:
102
102
  if self._sections_disjoint(ours, theirs):
103
103
  # No conflicts - merge all changes
104
104
  merged = self._merge_sections(base, ours, theirs)
105
- return MergeResolution(merged_bundle=merged, conflicts=[], auto_resolved=0, manual_resolved=0, unresolved=0)
105
+ return MergeResolution(merged, [], 0, 0, 0)
106
106
 
107
107
  # Rule 2: Find conflicts and resolve based on persona ownership
108
108
  field_conflicts = self._find_conflicts(base, ours, theirs)
@@ -161,11 +161,11 @@ class PersonaMergeResolver:
161
161
  conflicts.append(conflict)
162
162
 
163
163
  return MergeResolution(
164
- merged_bundle=merged,
165
- conflicts=conflicts,
166
- auto_resolved=auto_resolved,
167
- manual_resolved=manual_resolved,
168
- unresolved=unresolved,
164
+ merged,
165
+ conflicts,
166
+ auto_resolved,
167
+ manual_resolved,
168
+ unresolved,
169
169
  )
170
170
 
171
171
  @beartype
@@ -9,7 +9,7 @@ future tool integrations using the same interface pattern.
9
9
 
10
10
  from __future__ import annotations
11
11
 
12
- from enum import Enum
12
+ from enum import StrEnum
13
13
  from pathlib import Path
14
14
 
15
15
  from beartype import beartype
@@ -19,7 +19,7 @@ from pydantic import BaseModel, Field
19
19
  from specfact_cli.utils.structured_io import StructuredFormat, dump_structured_file, load_structured_file
20
20
 
21
21
 
22
- class AdapterType(str, Enum):
22
+ class AdapterType(StrEnum):
23
23
  """Supported adapter types."""
24
24
 
25
25
  SPECKIT = "speckit"
@@ -12,7 +12,7 @@ ensuring they remain adapter-agnostic.
12
12
 
13
13
  from __future__ import annotations
14
14
 
15
- from enum import Enum
15
+ from enum import StrEnum
16
16
  from typing import Any
17
17
 
18
18
  from icontract import ensure, require
@@ -22,7 +22,7 @@ from specfact_cli.models.plan import Feature
22
22
  from specfact_cli.models.source_tracking import SourceTracking
23
23
 
24
24
 
25
- class ChangeType(str, Enum):
25
+ class ChangeType(StrEnum):
26
26
  """Change type for delta specs (tool-agnostic)."""
27
27
 
28
28
  ADDED = "added"
@@ -17,7 +17,7 @@ stored in bundle-specific contracts/ directories and linked to features.
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- from enum import Enum
20
+ from enum import StrEnum
21
21
  from pathlib import Path
22
22
  from typing import Any
23
23
 
@@ -26,7 +26,7 @@ from icontract import ensure, require
26
26
  from pydantic import BaseModel, Field
27
27
 
28
28
 
29
- class ContractStatus(str, Enum):
29
+ class ContractStatus(StrEnum):
30
30
  """Contract status levels."""
31
31
 
32
32
  DRAFT = "draft" # Initial contract, not validated
@@ -7,14 +7,14 @@ protocols, and actual implementation following the CLI-First specification.
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
- from enum import Enum
10
+ from enum import StrEnum
11
11
 
12
12
  from beartype import beartype
13
13
  from icontract import ensure, require
14
14
  from pydantic import BaseModel, Field
15
15
 
16
16
 
17
- class DeviationSeverity(str, Enum):
17
+ class DeviationSeverity(StrEnum):
18
18
  """Deviation severity level."""
19
19
 
20
20
  HIGH = "HIGH"
@@ -22,7 +22,7 @@ class DeviationSeverity(str, Enum):
22
22
  LOW = "LOW"
23
23
 
24
24
 
25
- class DeviationType(str, Enum):
25
+ class DeviationType(StrEnum):
26
26
  """Type of deviation."""
27
27
 
28
28
  MISSING_FEATURE = "missing_feature"
@@ -1,13 +1,13 @@
1
1
  """Enforcement configuration models for quality gates."""
2
2
 
3
- from enum import Enum
3
+ from enum import StrEnum
4
4
 
5
5
  from beartype import beartype
6
6
  from icontract import ensure, require
7
7
  from pydantic import BaseModel, Field
8
8
 
9
9
 
10
- class EnforcementAction(str, Enum):
10
+ class EnforcementAction(StrEnum):
11
11
  """Actions that can be taken when a deviation is detected."""
12
12
 
13
13
  BLOCK = "BLOCK" # Fail the validation (exit code 1)
@@ -15,7 +15,7 @@ class EnforcementAction(str, Enum):
15
15
  LOG = "LOG" # Only log, no warning (exit code 0)
16
16
 
17
17
 
18
- class EnforcementPreset(str, Enum):
18
+ class EnforcementPreset(StrEnum):
19
19
  """Predefined enforcement presets."""
20
20
 
21
21
  MINIMAL = "minimal" # Log everything, never block
@@ -8,7 +8,7 @@ for persona-specific Markdown artifacts.
8
8
 
9
9
  from __future__ import annotations
10
10
 
11
- from enum import Enum
11
+ from enum import StrEnum
12
12
  from typing import Any
13
13
 
14
14
  from beartype import beartype
@@ -16,7 +16,7 @@ from icontract import ensure, require
16
16
  from pydantic import BaseModel, Field
17
17
 
18
18
 
19
- class SectionType(str, Enum):
19
+ class SectionType(StrEnum):
20
20
  """Section type classification."""
21
21
 
22
22
  REQUIRED = "required" # Must be present in export/import
@@ -13,7 +13,7 @@ import os
13
13
  from collections.abc import Callable
14
14
  from concurrent.futures import ThreadPoolExecutor, as_completed
15
15
  from datetime import UTC, datetime
16
- from enum import Enum
16
+ from enum import StrEnum
17
17
  from pathlib import Path
18
18
  from typing import Any
19
19
 
@@ -33,7 +33,7 @@ from specfact_cli.models.plan import (
33
33
  )
34
34
 
35
35
 
36
- class BundleFormat(str, Enum):
36
+ class BundleFormat(StrEnum):
37
37
  """Bundle format types."""
38
38
 
39
39
  MONOLITHIC = "monolithic" # Single file with all aspects
@@ -7,14 +7,14 @@ plan bundles and SDD manifests.
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
- from enum import Enum
10
+ from enum import StrEnum
11
11
 
12
12
  from beartype import beartype
13
13
  from icontract import ensure, require
14
14
  from pydantic import BaseModel, Field
15
15
 
16
16
 
17
- class TaskPhase(str, Enum):
17
+ class TaskPhase(StrEnum):
18
18
  """Task execution phases."""
19
19
 
20
20
  SETUP = "setup" # Project structure, dependencies, config
@@ -23,7 +23,7 @@ class TaskPhase(str, Enum):
23
23
  POLISH = "polish" # Tests, docs, optimization
24
24
 
25
25
 
26
- class TaskStatus(str, Enum):
26
+ class TaskStatus(StrEnum):
27
27
  """Task completion status."""
28
28
 
29
29
  PENDING = "pending"
@@ -8,13 +8,13 @@ based on environment and explicit flags.
8
8
  from __future__ import annotations
9
9
 
10
10
  import os
11
- from enum import Enum
11
+ from enum import StrEnum
12
12
 
13
13
  from beartype import beartype
14
14
  from icontract import ensure, require
15
15
 
16
16
 
17
- class OperationalMode(str, Enum):
17
+ class OperationalMode(StrEnum):
18
18
  """Operational modes for SpecFact CLI."""
19
19
 
20
20
  CICD = "cicd"
@@ -12,7 +12,7 @@ import json
12
12
  import logging
13
13
  import os
14
14
  import sys
15
- from enum import Enum
15
+ from enum import StrEnum
16
16
  from logging.handlers import RotatingFileHandler
17
17
  from typing import Any
18
18
 
@@ -34,7 +34,7 @@ DEBUG_LOG_DATEFMT = "%Y-%m-%d %H:%M:%S"
34
34
  DEBUG_LOG_FORMAT = "%(asctime)s | %(message)s"
35
35
 
36
36
 
37
- class TerminalMode(str, Enum):
37
+ class TerminalMode(StrEnum):
38
38
  """Terminal output modes for Rich Console and Progress."""
39
39
 
40
40
  GRAPHICAL = "graphical" # Full Rich features (colors, animations)
@@ -10,14 +10,14 @@ from __future__ import annotations
10
10
 
11
11
  import shutil
12
12
  from dataclasses import dataclass
13
- from enum import Enum
13
+ from enum import StrEnum
14
14
  from pathlib import Path
15
15
 
16
16
  from beartype import beartype
17
17
  from icontract import ensure, require
18
18
 
19
19
 
20
- class EnvManager(str, Enum):
20
+ class EnvManager(StrEnum):
21
21
  """Python environment manager types."""
22
22
 
23
23
  HATCH = "hatch"