specfact-cli 0.15.2__tar.gz → 0.15.3__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 (150) hide show
  1. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/PKG-INFO +1 -1
  2. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/pyproject.toml +1 -1
  3. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/prompts/specfact.03-review.md +9 -2
  4. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/__init__.py +1 -1
  5. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/__init__.py +1 -1
  6. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/commands/plan.py +30 -5
  7. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/.gitignore +0 -0
  8. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/LICENSE.md +0 -0
  9. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/README.md +0 -0
  10. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/mappings/node-async.yaml +0 -0
  11. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/mappings/python-async.yaml +0 -0
  12. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/mappings/speckit-default.yaml +0 -0
  13. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/prompts/shared/cli-enforcement.md +0 -0
  14. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/prompts/specfact.01-import.md +0 -0
  15. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/prompts/specfact.02-plan.md +0 -0
  16. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/prompts/specfact.04-sdd.md +0 -0
  17. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/prompts/specfact.05-enforce.md +0 -0
  18. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/prompts/specfact.06-sync.md +0 -0
  19. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/prompts/specfact.07-contracts.md +0 -0
  20. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/prompts/specfact.compare.md +0 -0
  21. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/prompts/specfact.validate.md +0 -0
  22. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/schemas/deviation.schema.json +0 -0
  23. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/schemas/plan.schema.json +0 -0
  24. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/schemas/protocol.schema.json +0 -0
  25. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/templates/github-action.yml.j2 +0 -0
  26. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/templates/plan.bundle.yaml.j2 +0 -0
  27. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/templates/pr-template.md.j2 +0 -0
  28. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/templates/protocol.yaml.j2 +0 -0
  29. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/resources/templates/telemetry.yaml.example +0 -0
  30. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/agents/__init__.py +0 -0
  31. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/agents/analyze_agent.py +0 -0
  32. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/agents/base.py +0 -0
  33. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/agents/plan_agent.py +0 -0
  34. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/agents/registry.py +0 -0
  35. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/agents/sync_agent.py +0 -0
  36. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/analyzers/__init__.py +0 -0
  37. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/analyzers/ambiguity_scanner.py +0 -0
  38. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/analyzers/code_analyzer.py +0 -0
  39. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/analyzers/constitution_evidence_extractor.py +0 -0
  40. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/analyzers/contract_extractor.py +0 -0
  41. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/analyzers/control_flow_analyzer.py +0 -0
  42. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/analyzers/graph_analyzer.py +0 -0
  43. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/analyzers/relationship_mapper.py +0 -0
  44. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/analyzers/requirement_extractor.py +0 -0
  45. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/analyzers/test_pattern_extractor.py +0 -0
  46. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/cli.py +0 -0
  47. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/commands/__init__.py +0 -0
  48. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/commands/analyze.py +0 -0
  49. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/commands/bridge.py +0 -0
  50. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/commands/drift.py +0 -0
  51. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/commands/enforce.py +0 -0
  52. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/commands/generate.py +0 -0
  53. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/commands/implement.py +0 -0
  54. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/commands/import_cmd.py +0 -0
  55. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/commands/init.py +0 -0
  56. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/commands/migrate.py +0 -0
  57. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/commands/repro.py +0 -0
  58. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/commands/run.py +0 -0
  59. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/commands/sdd.py +0 -0
  60. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/commands/spec.py +0 -0
  61. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/commands/sync.py +0 -0
  62. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/common/__init__.py +0 -0
  63. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/common/logger_setup.py +0 -0
  64. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/common/logging_utils.py +0 -0
  65. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/common/text_utils.py +0 -0
  66. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/common/utils.py +0 -0
  67. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/comparators/__init__.py +0 -0
  68. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/comparators/plan_comparator.py +0 -0
  69. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/enrichers/constitution_enricher.py +0 -0
  70. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/enrichers/plan_enricher.py +0 -0
  71. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/generators/__init__.py +0 -0
  72. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/generators/contract_generator.py +0 -0
  73. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/generators/openapi_extractor.py +0 -0
  74. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/generators/plan_generator.py +0 -0
  75. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/generators/protocol_generator.py +0 -0
  76. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/generators/report_generator.py +0 -0
  77. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/generators/task_generator.py +0 -0
  78. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/generators/test_to_openapi.py +0 -0
  79. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/generators/workflow_generator.py +0 -0
  80. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/importers/__init__.py +0 -0
  81. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/importers/speckit_converter.py +0 -0
  82. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/importers/speckit_scanner.py +0 -0
  83. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/integrations/__init__.py +0 -0
  84. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/integrations/specmatic.py +0 -0
  85. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/migrations/__init__.py +0 -0
  86. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/migrations/plan_migrator.py +0 -0
  87. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/models/__init__.py +0 -0
  88. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/models/bridge.py +0 -0
  89. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/models/deviation.py +0 -0
  90. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/models/enforcement.py +0 -0
  91. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/models/plan.py +0 -0
  92. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/models/project.py +0 -0
  93. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/models/protocol.py +0 -0
  94. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/models/quality.py +0 -0
  95. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/models/sdd.py +0 -0
  96. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/models/source_tracking.py +0 -0
  97. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/models/task.py +0 -0
  98. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/modes/__init__.py +0 -0
  99. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/modes/detector.py +0 -0
  100. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/modes/router.py +0 -0
  101. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/resources/semgrep/async.yml +0 -0
  102. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/resources/semgrep/code-quality.yml +0 -0
  103. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/resources/semgrep/feature-detection.yml +0 -0
  104. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/runtime.py +0 -0
  105. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/sync/__init__.py +0 -0
  106. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/sync/bridge_probe.py +0 -0
  107. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/sync/bridge_sync.py +0 -0
  108. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/sync/bridge_watch.py +0 -0
  109. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/sync/change_detector.py +0 -0
  110. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/sync/code_to_spec.py +0 -0
  111. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/sync/drift_detector.py +0 -0
  112. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/sync/repository_sync.py +0 -0
  113. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/sync/spec_to_code.py +0 -0
  114. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/sync/spec_to_tests.py +0 -0
  115. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/sync/speckit_sync.py +0 -0
  116. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/sync/watcher.py +0 -0
  117. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/sync/watcher_enhanced.py +0 -0
  118. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/telemetry.py +0 -0
  119. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/templates/__init__.py +0 -0
  120. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/templates/bridge_templates.py +0 -0
  121. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/templates/specification_templates.py +0 -0
  122. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/__init__.py +0 -0
  123. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/acceptance_criteria.py +0 -0
  124. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/bundle_loader.py +0 -0
  125. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/console.py +0 -0
  126. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/context_detection.py +0 -0
  127. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/enrichment_context.py +0 -0
  128. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/enrichment_parser.py +0 -0
  129. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/feature_keys.py +0 -0
  130. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/git.py +0 -0
  131. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/github_annotations.py +0 -0
  132. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/ide_setup.py +0 -0
  133. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/incremental_check.py +0 -0
  134. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/optional_deps.py +0 -0
  135. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/performance.py +0 -0
  136. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/progress.py +0 -0
  137. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/progressive_disclosure.py +0 -0
  138. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/prompts.py +0 -0
  139. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/sdd_discovery.py +0 -0
  140. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/source_scanner.py +0 -0
  141. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/structure.py +0 -0
  142. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/structured_io.py +0 -0
  143. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/suggestions.py +0 -0
  144. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/utils/yaml_utils.py +0 -0
  145. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/validators/__init__.py +0 -0
  146. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/validators/cli_first_validator.py +0 -0
  147. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/validators/contract_validator.py +0 -0
  148. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/validators/fsm.py +0 -0
  149. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/validators/repro_checker.py +0 -0
  150. {specfact_cli-0.15.2 → specfact_cli-0.15.3}/src/specfact_cli/validators/schema.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specfact-cli
3
- Version: 0.15.2
3
+ Version: 0.15.3
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.15.2"
7
+ version = "0.15.3"
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"
@@ -101,6 +101,7 @@ The recommendation helps less-experienced users make informed decisions.
101
101
  - `--list-questions` - Output questions in JSON format. Default: False
102
102
  - `--output-questions PATH` - Save questions directly to file (JSON format). Use with `--list-questions` to save instead of stdout. Default: None
103
103
  - `--list-findings` - Output all findings in structured format. Default: False
104
+ - `--output-findings PATH` - Save findings directly to file (JSON/YAML format). Use with `--list-findings` to save instead of stdout. Default: None
104
105
  - `--findings-format FORMAT` - Output format: json, yaml, or table. Default: json for non-interactive, table for interactive
105
106
 
106
107
  ### Behavior/Options
@@ -150,7 +151,11 @@ specfact plan review [<bundle-name>] --list-questions --output-questions /tmp/qu
150
151
  ```bash
151
152
  # Get findings (saves to stdout - can redirect to /tmp/)
152
153
  # Use /tmp/ to avoid polluting the codebase
154
+ # Option 1: Redirect output (includes CLI banner - not recommended)
153
155
  specfact plan review [<bundle-name>] --list-findings --findings-format json --no-interactive > /tmp/findings.json
156
+
157
+ # Option 2: Save directly to file (recommended - clean JSON only)
158
+ specfact plan review [<bundle-name>] --list-findings --output-findings /tmp/findings.json --no-interactive
154
159
  ```
155
160
 
156
161
  **Note**: The `--output-questions` option saves questions directly to a file, avoiding the need for complex JSON parsing. The ambiguity scanner now recognizes the simplified format (e.g., "Must verify X works correctly (see contract examples)") as valid and will not flag it as vague.
@@ -362,7 +367,8 @@ When in copilot mode, follow this three-phase workflow:
362
367
 
363
368
  ```bash
364
369
  # Option 1: Get findings (redirect to /tmp/ to avoid polluting codebase)
365
- specfact plan review [<bundle-name>] --list-findings --findings-format json --no-interactive > /tmp/findings.json
370
+ # Option 1: Save findings directly to file (recommended - clean JSON only)
371
+ specfact plan review [<bundle-name>] --list-findings --output-findings /tmp/findings.json --no-interactive
366
372
 
367
373
  # Option 2: Get questions and save directly to /tmp/ (recommended - avoids JSON parsing)
368
374
  specfact plan review [<bundle-name>] --list-questions --output-questions /tmp/questions.json --no-interactive
@@ -513,6 +519,7 @@ Create one with: specfact plan init legacy-api
513
519
  # Get findings first
514
520
  /specfact.03-review --list-findings # List all findings
515
521
  /specfact.03-review --list-findings --findings-format json # JSON format for enrichment
522
+ /specfact.03-review --list-findings --output-findings /tmp/findings.json # Save findings to file (clean JSON)
516
523
 
517
524
  # Interactive review
518
525
  /specfact.03-review # Uses active plan (default: 5 questions per session)
@@ -557,7 +564,7 @@ Create one with: specfact plan init legacy-api
557
564
  2. **Get findings** (optional, for comprehensive analysis - use `/tmp/`):
558
565
 
559
566
  ```bash
560
- specfact plan review [<bundle-name>] --list-findings --findings-format json --no-interactive > /tmp/findings.json
567
+ specfact plan review [<bundle-name>] --list-findings --output-findings /tmp/findings.json --no-interactive
561
568
  ```
562
569
 
563
570
  3. **LLM reasoning and user selection** (REQUIRED for partial findings):
@@ -3,4 +3,4 @@ SpecFact CLI - Spec→Contract→Sentinel tool for contract-driven development.
3
3
  """
4
4
 
5
5
  # Define the package version (kept in sync with pyproject.toml and setup.py)
6
- __version__ = "0.14.2"
6
+ __version__ = "0.15.3"
@@ -9,6 +9,6 @@ This package provides command-line tools for:
9
9
  - Validating reproducibility
10
10
  """
11
11
 
12
- __version__ = "0.15.2"
12
+ __version__ = "0.15.3"
13
13
 
14
14
  __all__ = ["__version__"]
@@ -2985,6 +2985,7 @@ def _output_findings(
2985
2985
  report: Any, # AmbiguityReport (imported locally to avoid circular dependency)
2986
2986
  findings_format: str | None,
2987
2987
  is_non_interactive: bool,
2988
+ output_path: Path | None = None,
2988
2989
  ) -> None:
2989
2990
  """
2990
2991
  Output findings in structured format or table.
@@ -2993,9 +2994,15 @@ def _output_findings(
2993
2994
  report: Ambiguity report
2994
2995
  findings_format: Output format (json, yaml, table)
2995
2996
  is_non_interactive: Whether in non-interactive mode
2997
+ output_path: Optional file path to save findings. If None, outputs to stdout.
2996
2998
  """
2999
+ from rich.console import Console
3000
+ from rich.table import Table
3001
+
2997
3002
  from specfact_cli.analyzers.ambiguity_scanner import AmbiguityStatus
2998
3003
 
3004
+ console = Console()
3005
+
2999
3006
  # Determine output format
3000
3007
  output_format_str = findings_format
3001
3008
  if not output_format_str:
@@ -3069,7 +3076,7 @@ def _output_findings(
3069
3076
  import sys
3070
3077
 
3071
3078
  if output_format_str == "json":
3072
- sys.stdout.write(json.dumps(findings_data, indent=2))
3079
+ formatted_output = json.dumps(findings_data, indent=2) + "\n"
3073
3080
  else: # yaml
3074
3081
  from ruamel.yaml import YAML
3075
3082
 
@@ -3080,9 +3087,20 @@ def _output_findings(
3080
3087
 
3081
3088
  output = StringIO()
3082
3089
  yaml.dump(findings_data, output)
3083
- sys.stdout.write(output.getvalue())
3084
- sys.stdout.write("\n")
3085
- sys.stdout.flush()
3090
+ formatted_output = output.getvalue()
3091
+
3092
+ if output_path:
3093
+ # Save to file
3094
+ output_path.parent.mkdir(parents=True, exist_ok=True)
3095
+ output_path.write_text(formatted_output, encoding="utf-8")
3096
+ from rich.console import Console
3097
+
3098
+ console = Console()
3099
+ console.print(f"[green]✓[/green] Findings saved to: {output_path}")
3100
+ else:
3101
+ # Output to stdout
3102
+ sys.stdout.write(formatted_output)
3103
+ sys.stdout.flush()
3086
3104
  else:
3087
3105
  print_error(f"Invalid findings format: {findings_format}. Must be 'json', 'yaml', or 'table'")
3088
3106
  raise typer.Exit(1)
@@ -3987,6 +4005,11 @@ def review(
3987
4005
  case_sensitive=False,
3988
4006
  hidden=True, # Hidden by default, shown with --help-advanced
3989
4007
  ),
4008
+ output_findings: Path | None = typer.Option(
4009
+ None,
4010
+ "--output-findings",
4011
+ help="Save findings to file (JSON/YAML format). If --list-findings is also set, findings are saved to file instead of stdout. Default: None",
4012
+ ),
3990
4013
  # Behavior/Options
3991
4014
  no_interactive: bool = typer.Option(
3992
4015
  False,
@@ -4031,7 +4054,9 @@ def review(
4031
4054
  specfact plan review legacy-api
4032
4055
  specfact plan review auth-module --max-questions 3 --category "Functional Scope"
4033
4056
  specfact plan review legacy-api --list-questions # Output questions as JSON
4057
+ specfact plan review legacy-api --list-questions --output-questions /tmp/questions.json # Save questions to file
4034
4058
  specfact plan review legacy-api --list-findings --findings-format json # Output all findings as JSON
4059
+ specfact plan review legacy-api --list-findings --output-findings /tmp/findings.json # Save findings to file
4035
4060
  specfact plan review legacy-api --answers '{"Q001": "answer1", "Q002": "answer2"}' # Non-interactive
4036
4061
  """
4037
4062
  from rich.console import Console
@@ -4095,7 +4120,7 @@ def review(
4095
4120
 
4096
4121
  # Handle --list-findings mode
4097
4122
  if list_findings:
4098
- _output_findings(report, findings_format, is_non_interactive)
4123
+ _output_findings(report, findings_format, is_non_interactive, output_findings)
4099
4124
  raise typer.Exit(0)
4100
4125
 
4101
4126
  # Show initial coverage summary BEFORE questions (so user knows what's missing)
File without changes
File without changes
File without changes