specfact-cli 0.47.6__tar.gz → 0.47.11__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 (278) hide show
  1. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/.gitignore +1 -0
  2. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/PKG-INFO +1 -1
  3. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/pyproject.toml +3 -1
  4. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/bundled-module-registry/index.json +3 -3
  5. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/__init__.py +1 -1
  6. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/__init__.py +1 -1
  7. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/adapters/ado.py +2 -2
  8. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/generators/persona_exporter.py +1 -1
  9. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/generators/plan_generator.py +1 -1
  10. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/generators/protocol_generator.py +1 -1
  11. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/generators/report_generator.py +1 -1
  12. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/generators/workflow_generator.py +1 -1
  13. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/modules/module_registry/module-package.yaml +3 -3
  14. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/modules/module_registry/src/commands.py +12 -4
  15. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/registry/dependency_resolver.py +11 -8
  16. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/registry/module_installer.py +1 -1
  17. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/telemetry.py +10 -4
  18. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/suggestions.py +4 -4
  19. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/LICENSE +0 -0
  20. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/README.md +0 -0
  21. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/keys/README.md +0 -0
  22. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/keys/module-signing-public.pem +0 -0
  23. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/mappings/node-async.yaml +0 -0
  24. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/mappings/python-async.yaml +0 -0
  25. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/mappings/speckit-default.yaml +0 -0
  26. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/schemas/deviation.schema.json +0 -0
  27. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/schemas/plan.schema.json +0 -0
  28. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/schemas/protocol.schema.json +0 -0
  29. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/templates/github-action.yml.j2 +0 -0
  30. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/templates/persona/architect.md.j2 +0 -0
  31. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/templates/persona/developer.md.j2 +0 -0
  32. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/templates/persona/product-owner.md.j2 +0 -0
  33. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/templates/plan.bundle.yaml.j2 +0 -0
  34. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/templates/policies/kanban.yaml +0 -0
  35. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/templates/policies/mixed.yaml +0 -0
  36. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/templates/policies/safe.yaml +0 -0
  37. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/templates/policies/scrum.yaml +0 -0
  38. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/templates/pr-template.md.j2 +0 -0
  39. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/templates/protocol.yaml.j2 +0 -0
  40. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/resources/templates/telemetry.yaml.example +0 -0
  41. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/__main__.py +0 -0
  42. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/adapters/__init__.py +0 -0
  43. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/adapters/backlog_base.py +0 -0
  44. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/adapters/base.py +0 -0
  45. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/adapters/github.py +0 -0
  46. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/adapters/openspec.py +0 -0
  47. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/adapters/openspec_parser.py +0 -0
  48. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/adapters/registry.py +0 -0
  49. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/adapters/speckit.py +0 -0
  50. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/agents/__init__.py +0 -0
  51. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/agents/analyze_agent.py +0 -0
  52. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/agents/base.py +0 -0
  53. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/agents/plan_agent.py +0 -0
  54. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/agents/registry.py +0 -0
  55. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/agents/sync_agent.py +0 -0
  56. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/analyzers/__init__.py +0 -0
  57. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/analyzers/ambiguity_scanner.py +0 -0
  58. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/analyzers/code_analyzer.py +0 -0
  59. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/analyzers/constitution_evidence_extractor.py +0 -0
  60. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/analyzers/contract_extractor.py +0 -0
  61. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/analyzers/control_flow_analyzer.py +0 -0
  62. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/analyzers/graph_analyzer.py +0 -0
  63. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/analyzers/relationship_mapper.py +0 -0
  64. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/analyzers/requirement_extractor.py +0 -0
  65. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/analyzers/test_pattern_extractor.py +0 -0
  66. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/backlog/__init__.py +0 -0
  67. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/backlog/adapters/__init__.py +0 -0
  68. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/backlog/adapters/base.py +0 -0
  69. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/backlog/converter.py +0 -0
  70. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/backlog/filters.py +0 -0
  71. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/backlog/mappers/__init__.py +0 -0
  72. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/backlog/mappers/ado_mapper.py +0 -0
  73. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/backlog/mappers/base.py +0 -0
  74. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/backlog/mappers/github_mapper.py +0 -0
  75. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/backlog/mappers/template_config.py +0 -0
  76. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/cli.py +0 -0
  77. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/commands/__init__.py +0 -0
  78. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/commands/_bundle_shim.py +0 -0
  79. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/commands/analyze.py +0 -0
  80. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/commands/contract_cmd.py +0 -0
  81. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/commands/drift.py +0 -0
  82. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/commands/enforce.py +0 -0
  83. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/commands/generate.py +0 -0
  84. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/commands/import_cmd.py +0 -0
  85. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/commands/init.py +0 -0
  86. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/commands/migrate.py +0 -0
  87. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/commands/plan.py +0 -0
  88. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/commands/project_cmd.py +0 -0
  89. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/commands/repro.py +0 -0
  90. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/commands/sdd.py +0 -0
  91. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/commands/spec.py +0 -0
  92. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/commands/sync.py +0 -0
  93. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/commands/update.py +0 -0
  94. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/commands/validate.py +0 -0
  95. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/common/__init__.py +0 -0
  96. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/common/bundle_factory.py +0 -0
  97. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/common/logger_setup.py +0 -0
  98. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/common/logging_utils.py +0 -0
  99. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/common/text_utils.py +0 -0
  100. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/common/utils.py +0 -0
  101. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/comparators/__init__.py +0 -0
  102. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/comparators/plan_comparator.py +0 -0
  103. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/contracts/__init__.py +0 -0
  104. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/contracts/crosshair_props.py +0 -0
  105. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/contracts/module_interface.py +0 -0
  106. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/enrichers/constitution_enricher.py +0 -0
  107. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/enrichers/plan_enricher.py +0 -0
  108. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/generators/__init__.py +0 -0
  109. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/generators/contract_generator.py +0 -0
  110. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/generators/openapi_extractor.py +0 -0
  111. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/generators/task_generator.py +0 -0
  112. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/generators/test_to_openapi.py +0 -0
  113. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/groups/__init__.py +0 -0
  114. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/groups/codebase_group.py +0 -0
  115. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/groups/govern_group.py +0 -0
  116. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/groups/member_group.py +0 -0
  117. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/groups/project_group.py +0 -0
  118. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/groups/spec_group.py +0 -0
  119. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/importers/__init__.py +0 -0
  120. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/importers/speckit_converter.py +0 -0
  121. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/importers/speckit_scanner.py +0 -0
  122. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/integrations/__init__.py +0 -0
  123. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/integrations/specmatic.py +0 -0
  124. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/merge/__init__.py +0 -0
  125. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/merge/resolver.py +0 -0
  126. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/migrations/__init__.py +0 -0
  127. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/migrations/plan_migrator.py +0 -0
  128. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/models/__init__.py +0 -0
  129. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/models/backlog_item.py +0 -0
  130. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/models/bridge.py +0 -0
  131. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/models/capabilities.py +0 -0
  132. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/models/change.py +0 -0
  133. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/models/contract.py +0 -0
  134. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/models/deviation.py +0 -0
  135. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/models/dor_config.py +0 -0
  136. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/models/enforcement.py +0 -0
  137. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/models/module_package.py +0 -0
  138. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/models/persona_template.py +0 -0
  139. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/models/plan.py +0 -0
  140. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/models/project.py +0 -0
  141. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/models/protocol.py +0 -0
  142. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/models/quality.py +0 -0
  143. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/models/sdd.py +0 -0
  144. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/models/source_tracking.py +0 -0
  145. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/models/task.py +0 -0
  146. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/models/validation.py +0 -0
  147. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/modes/__init__.py +0 -0
  148. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/modes/detector.py +0 -0
  149. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/modes/router.py +0 -0
  150. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/modules/__init__.py +0 -0
  151. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/modules/_bundle_import.py +0 -0
  152. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/modules/init/module-package.yaml +0 -0
  153. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/modules/init/src/__init__.py +0 -0
  154. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/modules/init/src/app.py +0 -0
  155. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/modules/init/src/commands.py +0 -0
  156. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/modules/init/src/first_run_selection.py +0 -0
  157. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/modules/module_io_shim.py +0 -0
  158. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/modules/module_registry/src/__init__.py +0 -0
  159. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/modules/module_registry/src/app.py +0 -0
  160. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/modules/upgrade/module-package.yaml +0 -0
  161. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/modules/upgrade/src/__init__.py +0 -0
  162. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/modules/upgrade/src/app.py +0 -0
  163. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/modules/upgrade/src/commands.py +0 -0
  164. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/parsers/__init__.py +0 -0
  165. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/parsers/persona_importer.py +0 -0
  166. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/registry/__init__.py +0 -0
  167. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/registry/alias_manager.py +0 -0
  168. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/registry/bootstrap.py +0 -0
  169. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/registry/bridge_registry.py +0 -0
  170. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/registry/crypto_validator.py +0 -0
  171. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/registry/custom_registries.py +0 -0
  172. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/registry/extension_registry.py +0 -0
  173. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/registry/help_cache.py +0 -0
  174. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/registry/marketplace_client.py +0 -0
  175. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/registry/metadata.py +0 -0
  176. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/registry/module_availability.py +0 -0
  177. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/registry/module_discovery.py +0 -0
  178. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/registry/module_grouping.py +0 -0
  179. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/registry/module_lifecycle.py +0 -0
  180. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/registry/module_packages.py +0 -0
  181. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/registry/module_security.py +0 -0
  182. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/registry/module_state.py +0 -0
  183. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/registry/registry.py +0 -0
  184. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/resources/semgrep/async.yml +0 -0
  185. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/resources/semgrep/code-quality.yml +0 -0
  186. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/resources/semgrep/feature-detection.yml +0 -0
  187. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/runtime.py +0 -0
  188. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/sync/__init__.py +0 -0
  189. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/sync/bridge_probe.py +0 -0
  190. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/sync/bridge_sync.py +0 -0
  191. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/sync/bridge_sync_openspec_md_parse.py +0 -0
  192. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/sync/bridge_sync_requirement_from_proposal.py +0 -0
  193. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/sync/bridge_sync_requirement_helpers.py +0 -0
  194. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/sync/bridge_sync_tasks_from_proposal.py +0 -0
  195. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/sync/bridge_sync_what_changes_format.py +0 -0
  196. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/sync/bridge_sync_write_openspec_from_proposal.py +0 -0
  197. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/sync/bridge_watch.py +0 -0
  198. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/sync/change_detector.py +0 -0
  199. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/sync/code_to_spec.py +0 -0
  200. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/sync/drift_detector.py +0 -0
  201. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/sync/repository_sync.py +0 -0
  202. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/sync/spec_to_code.py +0 -0
  203. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/sync/spec_to_tests.py +0 -0
  204. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/sync/watcher.py +0 -0
  205. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/sync/watcher_enhanced.py +0 -0
  206. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/templates/__init__.py +0 -0
  207. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/templates/defaults/defect_v1.yaml +0 -0
  208. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/templates/defaults/enabler_v1.yaml +0 -0
  209. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/templates/defaults/spike_v1.yaml +0 -0
  210. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/templates/defaults/user_story_v1.yaml +0 -0
  211. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/templates/frameworks/scrum/user_story_v1.yaml +0 -0
  212. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/templates/personas/product-owner/user_story_v1.yaml +0 -0
  213. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/templates/providers/ado/work_item_v1.yaml +0 -0
  214. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/templates/registry.py +0 -0
  215. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/templates/specification_templates.py +0 -0
  216. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/__init__.py +0 -0
  217. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/acceptance_criteria.py +0 -0
  218. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/auth_tokens.py +0 -0
  219. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/bundle_converters.py +0 -0
  220. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/bundle_loader.py +0 -0
  221. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/code_change_detector.py +0 -0
  222. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/console.py +0 -0
  223. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/content_sanitizer.py +0 -0
  224. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/context_detection.py +0 -0
  225. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/contract_predicates.py +0 -0
  226. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/enrichment_context.py +0 -0
  227. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/enrichment_parser.py +0 -0
  228. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/env_manager.py +0 -0
  229. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/feature_keys.py +0 -0
  230. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/git.py +0 -0
  231. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/github_annotations.py +0 -0
  232. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/icontract_helpers.py +0 -0
  233. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/ide_setup.py +0 -0
  234. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/incremental_check.py +0 -0
  235. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/metadata.py +0 -0
  236. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/optional_deps.py +0 -0
  237. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/performance.py +0 -0
  238. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/persona_ownership.py +0 -0
  239. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/progress.py +0 -0
  240. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/progressive_disclosure.py +0 -0
  241. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/project_artifact_write.py +0 -0
  242. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/prompts.py +0 -0
  243. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/sdd_discovery.py +0 -0
  244. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/source_scanner.py +0 -0
  245. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/startup_checks.py +0 -0
  246. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/structure.py +0 -0
  247. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/structured_io.py +0 -0
  248. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/terminal.py +0 -0
  249. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/utils/yaml_utils.py +0 -0
  250. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validation/__init__.py +0 -0
  251. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validation/command_audit.py +0 -0
  252. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/__init__.py +0 -0
  253. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/agile_validation.py +0 -0
  254. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/change_proposal_integration.py +0 -0
  255. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/cli_first_validator.py +0 -0
  256. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/contract_validator.py +0 -0
  257. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/fsm.py +0 -0
  258. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/repro_checker.py +0 -0
  259. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/schema.py +0 -0
  260. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/sidecar/__init__.py +0 -0
  261. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/sidecar/contract_populator.py +0 -0
  262. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/sidecar/crosshair_runner.py +0 -0
  263. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/sidecar/crosshair_summary.py +0 -0
  264. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/sidecar/dependency_installer.py +0 -0
  265. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/sidecar/framework_detector.py +0 -0
  266. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/sidecar/frameworks/__init__.py +0 -0
  267. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/sidecar/frameworks/base.py +0 -0
  268. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/sidecar/frameworks/django.py +0 -0
  269. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/sidecar/frameworks/drf.py +0 -0
  270. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/sidecar/frameworks/fastapi.py +0 -0
  271. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/sidecar/frameworks/flask.py +0 -0
  272. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/sidecar/harness_generator.py +0 -0
  273. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/sidecar/models.py +0 -0
  274. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/sidecar/orchestrator.py +0 -0
  275. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/sidecar/specmatic_runner.py +0 -0
  276. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/validators/sidecar/unannotated_detector.py +0 -0
  277. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/versioning/__init__.py +0 -0
  278. {specfact_cli-0.47.6 → specfact_cli-0.47.11}/src/specfact_cli/versioning/analyzer.py +0 -0
@@ -118,6 +118,7 @@ docs/internal/
118
118
  .codex/skills/openspec-*/
119
119
  !.codex/skills/openspec-workflows/
120
120
  .agents/skills/
121
+ !.agents/skills/openspec-workflows/
121
122
  skills-lock.json
122
123
 
123
124
  .vibe/skills/openspec-*/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specfact-cli
3
- Version: 0.47.6
3
+ Version: 0.47.11
4
4
  Summary: AI-bloat defense CLI for Python teams. Run deterministic code review, cleanup forecasts, and spec/contract evidence for AI-assisted and brownfield delivery.
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.47.6"
7
+ version = "0.47.11"
8
8
  description = "AI-bloat defense CLI for Python teams. Run deterministic code review, cleanup forecasts, and spec/contract evidence for AI-assisted and brownfield delivery."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -234,6 +234,8 @@ format = "ruff check . --fix && ruff format ."
234
234
  # Code scanning (Semgrep)
235
235
  # Semgrep 1.38+ deprecated implicit .semgrep.yml discovery; always pass --config explicitly.
236
236
  # Script must not be named `semgrep` (Hatch treats that as circular expansion with the semgrep CLI).
237
+ semgrep-sast = "semgrep scan --config tools/semgrep/sast.yml {args}"
238
+ semgrep-sast-gate = "python scripts/semgrep_sast_gate.py {args}"
237
239
  semgrep-full = "semgrep --config tools/semgrep {args}"
238
240
  scan = "semgrep --config tools/semgrep/async.yml {args}"
239
241
  scan-all = "semgrep --config tools/semgrep/async.yml ."
@@ -13,10 +13,10 @@
13
13
  "latest_version": "0.1.21"
14
14
  },
15
15
  {
16
- "checksum_sha256": "79359da27cb1c734a928a453a786b626e7b06654f515f32ead0cf96fa8e70bc2",
17
- "download_url": "https://github.com/nold-ai/specfact-cli/releases/download/module-registry-0.1.26.tar.gz",
16
+ "checksum_sha256": "2552567a090d15826d8439ffb9242e0bf002bbe92296bc894e17ca0ba6a773f8",
17
+ "download_url": "https://github.com/nold-ai/specfact-cli/releases/download/module-registry-0.1.32.tar.gz",
18
18
  "id": "module-registry",
19
- "latest_version": "0.1.26"
19
+ "latest_version": "0.1.32"
20
20
  },
21
21
  {
22
22
  "id": "bundle-mapper",
@@ -3,4 +3,4 @@ SpecFact CLI - AI-bloat defense CLI for Python teams.
3
3
  """
4
4
 
5
5
  # Package version: keep in sync with pyproject.toml, setup.py, src/specfact_cli/__init__.py
6
- __version__ = "0.47.6"
6
+ __version__ = "0.47.11"
@@ -76,6 +76,6 @@ def _install_progressive_disclosure() -> None:
76
76
  # keeps missing-command and missing-parameter UX consistent outside the root CLI too.
77
77
  _install_progressive_disclosure()
78
78
 
79
- __version__ = "0.47.6"
79
+ __version__ = "0.47.11"
80
80
 
81
81
  __all__ = ["__version__"]
@@ -1986,7 +1986,7 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
1986
1986
  return cast(
1987
1987
  Any,
1988
1988
  self._request_with_retry(
1989
- lambda: requests.post(url, **request_kwargs),
1989
+ lambda: requests.post(url, **request_kwargs), # nosec B113 - request_kwargs always includes timeout.
1990
1990
  retry_on_ambiguous_transport=retry_on_ambiguous_transport,
1991
1991
  ),
1992
1992
  )
@@ -2129,7 +2129,7 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
2129
2129
  change_id_escaped = change_id.replace("'", "''")
2130
2130
  wiql = {
2131
2131
  "query": (
2132
- "Select [System.Id] From WorkItems "
2132
+ "Select [System.Id] From WorkItems " # nosec B608 - WIQL uses escaped literals, not SQL.
2133
2133
  f"Where [System.TeamProject] = '{project_escaped}' "
2134
2134
  f"And [System.Description] Contains 'OpenSpec Change Proposal: `{change_id_escaped}`'"
2135
2135
  )
@@ -90,7 +90,7 @@ class PersonaExporter:
90
90
  self.project_templates_dir = project_templates_dir
91
91
 
92
92
  # Create Jinja2 environment with fallback support
93
- self.env = Environment(
93
+ self.env = Environment( # nosec B701 - exports trusted Markdown templates, not HTML.
94
94
  loader=FileSystemLoader(
95
95
  [str(self.templates_dir)] + ([str(self.project_templates_dir)] if project_templates_dir else [])
96
96
  ),
@@ -33,7 +33,7 @@ class PlanGenerator:
33
33
  templates_dir = Path(__file__).parent.parent.parent.parent / "resources" / "templates"
34
34
 
35
35
  self.templates_dir = Path(templates_dir)
36
- self.env = Environment(
36
+ self.env = Environment( # nosec B701 - generates trusted text/YAML workflow templates, not HTML.
37
37
  loader=FileSystemLoader(self.templates_dir),
38
38
  # Must be False: trim_blocks removes the newline after {% endraw %}, merging `if:` with `run:`.
39
39
  trim_blocks=False,
@@ -32,7 +32,7 @@ class ProtocolGenerator:
32
32
  templates_dir = Path(__file__).parent.parent.parent.parent / "resources" / "templates"
33
33
 
34
34
  self.templates_dir = Path(templates_dir)
35
- self.env = Environment(
35
+ self.env = Environment( # nosec B701 - generates trusted protocol Markdown, not HTML.
36
36
  loader=FileSystemLoader(self.templates_dir),
37
37
  trim_blocks=True,
38
38
  lstrip_blocks=True,
@@ -43,7 +43,7 @@ class ReportGenerator:
43
43
  templates_dir = Path(__file__).parent.parent.parent.parent / "resources" / "templates"
44
44
 
45
45
  self.templates_dir = Path(templates_dir)
46
- self.env = Environment(
46
+ self.env = Environment( # nosec B701 - generates trusted validation reports, not HTML.
47
47
  loader=FileSystemLoader(self.templates_dir),
48
48
  trim_blocks=True,
49
49
  lstrip_blocks=True,
@@ -38,7 +38,7 @@ class WorkflowGenerator:
38
38
  templates_dir = Path(__file__).parent.parent.parent.parent / "resources" / "templates"
39
39
 
40
40
  self.templates_dir = Path(templates_dir)
41
- self.env = Environment(
41
+ self.env = Environment( # nosec B701 - generates trusted text/YAML workflow templates, not HTML.
42
42
  loader=FileSystemLoader(self.templates_dir),
43
43
  # Must be False: trim_blocks removes the newline after {% endraw %}, merging `if:` with `run:`.
44
44
  trim_blocks=False,
@@ -1,5 +1,5 @@
1
1
  name: module-registry
2
- version: 0.1.26
2
+ version: 0.1.32
3
3
  commands:
4
4
  - module
5
5
  category: core
@@ -17,5 +17,5 @@ publisher:
17
17
  description: 'Manage modules: search, list, show, install, and upgrade.'
18
18
  license: Apache-2.0
19
19
  integrity:
20
- checksum: sha256:52a65869fb3d2d36910308c954e0ba199cb1c73f24136ee0d4aa7254f0996a22
21
- signature: Uo2eJ40HiWBqe77N8gjiDg7zGhsvJE/hN82+Jcto7yUoqbH7bidLw9DfVQ0CrJfgM9Y0XHAUS1+LMyPr1jAaBg==
20
+ checksum: sha256:a707de59cb2a706bad96a30415b693df0905cc67edf9238c0e9d601cc5b6af70
21
+ signature: GREOnCQAXmZvwN0s+2T6wwhPFTYiDchy/V7uut9uMHZjevK7ZDBxbTPZJhGjb1ndX7pkaL+/TfyNOuh/9AUDDw==
@@ -16,7 +16,7 @@ import typer
16
16
  import yaml
17
17
  from beartype import beartype
18
18
  from click.exceptions import Exit as ClickExit
19
- from icontract import require
19
+ from icontract import ensure, require
20
20
  from packaging.version import InvalidVersion, Version
21
21
  from rich.console import Console
22
22
  from rich.table import Table
@@ -54,13 +54,21 @@ from specfact_cli.registry.module_packages import get_discovered_modules_for_sta
54
54
  from specfact_cli.registry.module_security import ensure_publisher_trusted, is_official_publisher
55
55
  from specfact_cli.registry.module_state import read_modules_state, write_modules_state
56
56
  from specfact_cli.registry.registry import CommandRegistry
57
- from specfact_cli.runtime import is_non_interactive
57
+ from specfact_cli.runtime import is_non_interactive, refresh_loaded_module_consoles
58
58
 
59
59
 
60
60
  app = typer.Typer(help="Manage marketplace modules")
61
61
  console = Console()
62
62
 
63
63
 
64
+ @app.callback()
65
+ @beartype
66
+ @ensure(lambda result: result is None, "module registry callback returns None")
67
+ def module_registry_callback() -> None:
68
+ """Prepare invocation-local output streams for direct module command tests."""
69
+ refresh_loaded_module_consoles()
70
+
71
+
64
72
  def _module_upgrade_show_spinner() -> bool:
65
73
  """Rich Live/spinner breaks some tests; mirror ``utils.progress`` test-mode detection."""
66
74
  return os.environ.get("TEST_MODE") != "true" and os.environ.get("PYTEST_CURRENT_TEST") is None
@@ -386,10 +394,10 @@ def _install_one(module_id: str, params: _InstallOneParams) -> bool:
386
394
  except Exception as exc:
387
395
  console.print(f"[red]Failed installing {normalized}: {exc}[/red]")
388
396
  return False
389
- console.print(f"[green]Installed[/green] {normalized} -> {installed_path}")
397
+ typer.echo(f"Installed {normalized} -> {installed_path}")
390
398
  publisher = _publisher_from_module_id(normalized)
391
399
  if is_official_publisher(publisher):
392
- console.print(f"Verified: official ({publisher})")
400
+ typer.echo(f"Verified: official ({publisher})")
393
401
  return True
394
402
 
395
403
 
@@ -127,15 +127,18 @@ def _collect_constraints(modules: list[ModulePackageMetadata]) -> list[str]:
127
127
  seen: set[str] = set()
128
128
  for meta in modules:
129
129
  for d in meta.pip_dependencies or []:
130
- if d.strip() and d not in seen:
131
- constraints.append(d.strip())
132
- seen.add(d)
130
+ normalized = d.strip()
131
+ if normalized and normalized not in seen:
132
+ constraints.append(normalized)
133
+ seen.add(normalized)
133
134
  for vd in meta.pip_dependencies_versioned or []:
134
- spec = vd.version_specifier or ""
135
- s = f"{vd.name}{spec}" if spec else vd.name
136
- if s not in seen:
137
- constraints.append(s)
138
- seen.add(s)
135
+ name = vd.name.strip()
136
+ spec = (vd.version_specifier or "").strip()
137
+ s = f"{name}{spec}" if spec else name
138
+ normalized = s.strip()
139
+ if normalized and normalized not in seen:
140
+ constraints.append(normalized)
141
+ seen.add(normalized)
139
142
  return constraints
140
143
 
141
144
 
@@ -825,7 +825,7 @@ def _extract_marketplace_archive(archive_path: Path, extract_root: Path) -> None
825
825
  try:
826
826
  archive.extractall(path=extract_root, members=members, filter="data")
827
827
  except TypeError:
828
- archive.extractall(path=extract_root, members=members)
828
+ archive.extractall(path=extract_root, members=members) # nosec B202 - members were validated above.
829
829
 
830
830
 
831
831
  def _load_first_extracted_module_manifest(extract_root: Path) -> tuple[Path, dict[str, Any]]:
@@ -14,6 +14,7 @@ import json
14
14
  import logging
15
15
  import os
16
16
  import sys
17
+ import tempfile
17
18
  import time
18
19
  from collections.abc import MutableMapping
19
20
  from contextlib import contextmanager, suppress
@@ -677,6 +678,11 @@ def test_telemetry_settings_from_env_property() -> None:
677
678
  assert isinstance(settings.opt_in_source, str)
678
679
 
679
680
 
681
+ def _crosshair_temp_log_path() -> Path:
682
+ """Return a unique local telemetry log path for property tests."""
683
+ return Path(tempfile.gettempdir()) / f"test_telemetry-{uuid4().hex}.log"
684
+
685
+
680
686
  @beartype
681
687
  @require(lambda enabled: isinstance(enabled, bool), "enabled must be a bool")
682
688
  def test_telemetry_manager_init_property(enabled: bool) -> None:
@@ -685,7 +691,7 @@ def test_telemetry_manager_init_property(enabled: bool) -> None:
685
691
  enabled=enabled,
686
692
  endpoint=None,
687
693
  headers={},
688
- local_path=Path("/tmp/test_telemetry.log"),
694
+ local_path=_crosshair_temp_log_path(),
689
695
  debug=False,
690
696
  opt_in_source="disabled",
691
697
  )
@@ -752,7 +758,7 @@ def test_telemetry_manager_normalize_value_property(value: Any) -> None:
752
758
  @require(lambda event: isinstance(event, Mapping), "event must be a Mapping")
753
759
  def test_telemetry_manager_write_local_event_property(event: Mapping[str, Any]) -> None:
754
760
  """CrossHair property test for TelemetryManager._write_local_event."""
755
- manager = TelemetryManager(TelemetrySettings(enabled=False, local_path=Path("/tmp/test_telemetry.log")))
761
+ manager = TelemetryManager(TelemetrySettings(enabled=False, local_path=_crosshair_temp_log_path()))
756
762
  # This test verifies the function doesn't raise exceptions
757
763
  # Actual file writing is tested in integration tests
758
764
  with suppress(OSError): # Expected in some test environments
@@ -763,7 +769,7 @@ def test_telemetry_manager_write_local_event_property(event: Mapping[str, Any])
763
769
  @require(lambda event: isinstance(event, MutableMapping), "event must be a MutableMapping")
764
770
  def test_telemetry_manager_emit_event_property(event: MutableMapping[str, Any]) -> None:
765
771
  """CrossHair property test for TelemetryManager._emit_event."""
766
- manager = TelemetryManager(TelemetrySettings(enabled=False, local_path=Path("/tmp/test_telemetry.log")))
772
+ manager = TelemetryManager(TelemetrySettings(enabled=False, local_path=_crosshair_temp_log_path()))
767
773
  manager._emit_event(event)
768
774
  assert manager._last_event is not None
769
775
  assert isinstance(manager._last_event, dict)
@@ -779,7 +785,7 @@ def test_telemetry_manager_track_command_property(command: str, initial_metadata
779
785
  """CrossHair property test for TelemetryManager.track_command."""
780
786
  if not command or len(command) == 0:
781
787
  return # Skip invalid inputs
782
- manager = TelemetryManager(TelemetrySettings(enabled=True, local_path=Path("/tmp/test_telemetry.log")))
788
+ manager = TelemetryManager(TelemetrySettings(enabled=True, local_path=_crosshair_temp_log_path()))
783
789
  try:
784
790
  with manager.track_command(command, initial_metadata) as record:
785
791
  assert callable(record)
@@ -52,7 +52,7 @@ def suggest_next_steps(repo_path: Path, context: ProjectContext | None = None) -
52
52
 
53
53
  # Analysis suggestions
54
54
  if context.has_plan and context.contract_coverage < 0.5:
55
- suggestions.append("specfact analyze --bundle <name> # Analyze contract coverage")
55
+ suggestions.append("specfact code analyze contracts --bundle <name> # Analyze contract coverage")
56
56
  suggestions.append("specfact code import --repo . <name> # Update the project bundle from code")
57
57
 
58
58
  # Specmatic integration suggestions
@@ -95,8 +95,8 @@ def suggest_fixes(error_message: str, context: ProjectContext | None = None) ->
95
95
 
96
96
  # Contract validation errors
97
97
  if "contract" in error_lower and ("violation" in error_lower or "invalid" in error_lower):
98
- suggestions.append("specfact analyze --bundle <name> # Analyze contract violations")
99
- suggestions.append("specfact repro --bundle <name> # Run validation suite")
98
+ suggestions.append("specfact code analyze contracts --bundle <name> # Analyze contract violations")
99
+ suggestions.append("specfact code repro --repo . # Run validation suite")
100
100
 
101
101
  # Specmatic errors
102
102
  if "specmatic" in error_lower or "openapi" in error_lower:
@@ -126,7 +126,7 @@ def suggest_improvements(context: ProjectContext) -> list[str]:
126
126
 
127
127
  # Low contract coverage
128
128
  if context.contract_coverage < 0.3:
129
- suggestions.append("specfact analyze --bundle <name> # Identify missing contracts")
129
+ suggestions.append("specfact code analyze contracts --bundle <name> # Identify missing contracts")
130
130
  suggestions.append("specfact code import --repo . <name> # Extract contracts from code")
131
131
 
132
132
  # Missing OpenAPI specs
File without changes
File without changes