specfact-cli 0.7.0__tar.gz → 0.9.0__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 (118) hide show
  1. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/PKG-INFO +24 -5
  2. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/README.md +23 -4
  3. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/pyproject.toml +1 -1
  4. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/__init__.py +1 -1
  5. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/__init__.py +1 -1
  6. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/analyzers/ambiguity_scanner.py +12 -12
  7. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/analyzers/constitution_evidence_extractor.py +14 -5
  8. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/analyzers/contract_extractor.py +1 -1
  9. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/cli.py +3 -2
  10. specfact_cli-0.9.0/src/specfact_cli/commands/enforce.py +389 -0
  11. specfact_cli-0.9.0/src/specfact_cli/commands/generate.py +197 -0
  12. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/commands/import_cmd.py +222 -127
  13. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/commands/plan.py +989 -326
  14. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/commands/sync.py +277 -168
  15. specfact_cli-0.9.0/src/specfact_cli/generators/contract_generator.py +308 -0
  16. specfact_cli-0.9.0/src/specfact_cli/models/__init__.py +84 -0
  17. specfact_cli-0.9.0/src/specfact_cli/models/bridge.py +203 -0
  18. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/models/deviation.py +7 -0
  19. specfact_cli-0.9.0/src/specfact_cli/models/project.py +417 -0
  20. specfact_cli-0.9.0/src/specfact_cli/models/sdd.py +116 -0
  21. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/sync/__init__.py +9 -0
  22. specfact_cli-0.9.0/src/specfact_cli/sync/bridge_probe.py +365 -0
  23. specfact_cli-0.9.0/src/specfact_cli/sync/bridge_sync.py +508 -0
  24. specfact_cli-0.9.0/src/specfact_cli/sync/bridge_watch.py +449 -0
  25. specfact_cli-0.9.0/src/specfact_cli/templates/__init__.py +14 -0
  26. specfact_cli-0.9.0/src/specfact_cli/templates/bridge_templates.py +244 -0
  27. specfact_cli-0.9.0/src/specfact_cli/utils/bundle_loader.py +339 -0
  28. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/structure.py +171 -1
  29. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/structured_io.py +3 -5
  30. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/validators/__init__.py +8 -0
  31. specfact_cli-0.9.0/src/specfact_cli/validators/contract_validator.py +159 -0
  32. specfact_cli-0.7.0/src/specfact_cli/commands/enforce.py +0 -96
  33. specfact_cli-0.7.0/src/specfact_cli/models/__init__.py +0 -34
  34. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/.gitignore +0 -0
  35. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/LICENSE.md +0 -0
  36. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/mappings/node-async.yaml +0 -0
  37. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/mappings/python-async.yaml +0 -0
  38. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/mappings/speckit-default.yaml +0 -0
  39. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-enforce.md +0 -0
  40. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-import-from-code.md +0 -0
  41. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-plan-add-feature.md +0 -0
  42. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-plan-add-story.md +0 -0
  43. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-plan-compare.md +0 -0
  44. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-plan-init.md +0 -0
  45. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-plan-promote.md +0 -0
  46. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-plan-review.md +0 -0
  47. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-plan-select.md +0 -0
  48. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-plan-update-feature.md +0 -0
  49. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-plan-update-idea.md +0 -0
  50. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-repro.md +0 -0
  51. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-sync.md +0 -0
  52. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/schemas/deviation.schema.json +0 -0
  53. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/schemas/plan.schema.json +0 -0
  54. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/schemas/protocol.schema.json +0 -0
  55. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/templates/github-action.yml.j2 +0 -0
  56. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/templates/plan.bundle.yaml.j2 +0 -0
  57. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/templates/pr-template.md.j2 +0 -0
  58. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/templates/protocol.yaml.j2 +0 -0
  59. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/templates/telemetry.yaml.example +0 -0
  60. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/agents/__init__.py +0 -0
  61. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/agents/analyze_agent.py +0 -0
  62. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/agents/base.py +0 -0
  63. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/agents/plan_agent.py +0 -0
  64. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/agents/registry.py +0 -0
  65. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/agents/sync_agent.py +0 -0
  66. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/analyzers/__init__.py +0 -0
  67. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/analyzers/code_analyzer.py +0 -0
  68. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/analyzers/control_flow_analyzer.py +0 -0
  69. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/analyzers/requirement_extractor.py +0 -0
  70. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/analyzers/test_pattern_extractor.py +0 -0
  71. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/commands/__init__.py +0 -0
  72. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/commands/constitution.py +0 -0
  73. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/commands/init.py +0 -0
  74. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/commands/repro.py +0 -0
  75. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/common/__init__.py +0 -0
  76. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/common/logger_setup.py +0 -0
  77. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/common/logging_utils.py +0 -0
  78. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/common/text_utils.py +0 -0
  79. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/common/utils.py +0 -0
  80. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/comparators/__init__.py +0 -0
  81. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/comparators/plan_comparator.py +0 -0
  82. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/enrichers/constitution_enricher.py +0 -0
  83. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/enrichers/plan_enricher.py +0 -0
  84. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/generators/__init__.py +0 -0
  85. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/generators/plan_generator.py +0 -0
  86. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/generators/protocol_generator.py +0 -0
  87. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/generators/report_generator.py +0 -0
  88. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/generators/workflow_generator.py +0 -0
  89. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/importers/__init__.py +0 -0
  90. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/importers/speckit_converter.py +0 -0
  91. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/importers/speckit_scanner.py +0 -0
  92. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/migrations/__init__.py +0 -0
  93. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/migrations/plan_migrator.py +0 -0
  94. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/models/enforcement.py +0 -0
  95. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/models/plan.py +0 -0
  96. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/models/protocol.py +0 -0
  97. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/modes/__init__.py +0 -0
  98. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/modes/detector.py +0 -0
  99. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/modes/router.py +0 -0
  100. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/resources/semgrep/async.yml +0 -0
  101. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/runtime.py +0 -0
  102. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/sync/repository_sync.py +0 -0
  103. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/sync/speckit_sync.py +0 -0
  104. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/sync/watcher.py +0 -0
  105. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/telemetry.py +0 -0
  106. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/__init__.py +0 -0
  107. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/acceptance_criteria.py +0 -0
  108. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/console.py +0 -0
  109. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/enrichment_parser.py +0 -0
  110. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/feature_keys.py +0 -0
  111. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/git.py +0 -0
  112. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/github_annotations.py +0 -0
  113. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/ide_setup.py +0 -0
  114. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/prompts.py +0 -0
  115. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/yaml_utils.py +0 -0
  116. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/validators/fsm.py +0 -0
  117. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/validators/repro_checker.py +0 -0
  118. {specfact_cli-0.7.0 → specfact_cli-0.9.0}/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.7.0
3
+ Version: 0.9.0
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
@@ -317,6 +317,23 @@ A brownfield-first CLI that **reverse engineers your legacy code** into document
317
317
  - ✅ **Runtime contract enforcement** → Prevent regressions during modernization
318
318
  - ✅ **Symbolic execution** → Discover hidden edge cases with CrossHair
319
319
  - ✅ **Works offline** → No cloud required, fully local
320
+ - ✅ **CLI integrations** → Works seamlessly with VS Code, Cursor, GitHub Actions, and any agentic workflow
321
+
322
+ ---
323
+
324
+ ## 🔌 CLI Integrations
325
+
326
+ SpecFact CLI works with your existing tools—no new platform to learn. See real bugs that were caught and fixed through different integrations:
327
+
328
+ - ✅ **VS Code** - Catch async bugs before you commit
329
+ - ✅ **Cursor** - Prevent regressions during AI-assisted refactoring
330
+ - ✅ **GitHub Actions** - Block bad code from merging
331
+ - ✅ **Pre-commit Hooks** - Validate code locally before pushing
332
+ - ✅ **AI Assistants** - Find edge cases AI might miss
333
+
334
+ 👉 **[Integration Showcases](docs/examples/integration-showcases/)** - Real examples of bugs fixed via CLI integrations
335
+
336
+ **Core USP**: Pure CLI-first approach—works offline, no account required, zero vendor lock-in. Regularly showcases successful integrations that fix bugs not detected by other tools.
320
337
 
321
338
  ---
322
339
 
@@ -326,7 +343,7 @@ A brownfield-first CLI that **reverse engineers your legacy code** into document
326
343
 
327
344
  ```bash
328
345
  # Zero-install (just run it)
329
- uvx --from specfact-cli specfact --help
346
+ uvx specfact-cli@latest --help
330
347
 
331
348
  # Or install with pip
332
349
  pip install specfact-cli
@@ -353,13 +370,13 @@ That's it! 🎉
353
370
 
354
371
  ## See It In Action
355
372
 
356
- We ran SpecFact CLI **on itself** to prove it works:
373
+ We ran SpecFact CLI **on itself** to prove it works with legacy code:
357
374
 
358
- - ⚡ Analyzed 32 Python files → Discovered **32 features** and **81 stories** in **3 seconds**
375
+ - ⚡ Analyzed 32 legacy Python files → Discovered **32 features** and **81 stories** in **3 seconds**
359
376
  - 🚫 Set enforcement to "balanced" → **Blocked 2 HIGH violations** (as configured)
360
377
  - 📊 Compared manual vs auto-derived plans → Found **24 deviations** in **5 seconds**
361
378
 
362
- **Total time**: < 10 seconds | **Total value**: Found real naming inconsistencies and undocumented features
379
+ **Total time**: < 10 seconds | **Total value**: Found real naming inconsistencies and undocumented features in legacy codebase
363
380
 
364
381
  👉 **[Read the complete example](docs/examples/dogfooding-specfact-cli.md)** with actual commands and outputs
365
382
 
@@ -369,6 +386,8 @@ We ran SpecFact CLI **on itself** to prove it works:
369
386
 
370
387
  **New to SpecFact?** Start with the [Getting Started Guide](docs/getting-started/README.md)
371
388
 
389
+ **Want to see integrations?** Check out [Integration Showcases](docs/examples/integration-showcases/) - Real bugs fixed via VS Code, Cursor, GitHub Actions
390
+
372
391
  **Tried Spec-Kit?** See [How SpecFact Compares to Spec-Kit](docs/guides/speckit-comparison.md) and [The Journey: From Spec-Kit to SpecFact](docs/guides/speckit-journey.md)
373
392
 
374
393
  **Need help?** Browse the [Documentation Hub](docs/README.md)
@@ -51,6 +51,23 @@ A brownfield-first CLI that **reverse engineers your legacy code** into document
51
51
  - ✅ **Runtime contract enforcement** → Prevent regressions during modernization
52
52
  - ✅ **Symbolic execution** → Discover hidden edge cases with CrossHair
53
53
  - ✅ **Works offline** → No cloud required, fully local
54
+ - ✅ **CLI integrations** → Works seamlessly with VS Code, Cursor, GitHub Actions, and any agentic workflow
55
+
56
+ ---
57
+
58
+ ## 🔌 CLI Integrations
59
+
60
+ SpecFact CLI works with your existing tools—no new platform to learn. See real bugs that were caught and fixed through different integrations:
61
+
62
+ - ✅ **VS Code** - Catch async bugs before you commit
63
+ - ✅ **Cursor** - Prevent regressions during AI-assisted refactoring
64
+ - ✅ **GitHub Actions** - Block bad code from merging
65
+ - ✅ **Pre-commit Hooks** - Validate code locally before pushing
66
+ - ✅ **AI Assistants** - Find edge cases AI might miss
67
+
68
+ 👉 **[Integration Showcases](docs/examples/integration-showcases/)** - Real examples of bugs fixed via CLI integrations
69
+
70
+ **Core USP**: Pure CLI-first approach—works offline, no account required, zero vendor lock-in. Regularly showcases successful integrations that fix bugs not detected by other tools.
54
71
 
55
72
  ---
56
73
 
@@ -60,7 +77,7 @@ A brownfield-first CLI that **reverse engineers your legacy code** into document
60
77
 
61
78
  ```bash
62
79
  # Zero-install (just run it)
63
- uvx --from specfact-cli specfact --help
80
+ uvx specfact-cli@latest --help
64
81
 
65
82
  # Or install with pip
66
83
  pip install specfact-cli
@@ -87,13 +104,13 @@ That's it! 🎉
87
104
 
88
105
  ## See It In Action
89
106
 
90
- We ran SpecFact CLI **on itself** to prove it works:
107
+ We ran SpecFact CLI **on itself** to prove it works with legacy code:
91
108
 
92
- - ⚡ Analyzed 32 Python files → Discovered **32 features** and **81 stories** in **3 seconds**
109
+ - ⚡ Analyzed 32 legacy Python files → Discovered **32 features** and **81 stories** in **3 seconds**
93
110
  - 🚫 Set enforcement to "balanced" → **Blocked 2 HIGH violations** (as configured)
94
111
  - 📊 Compared manual vs auto-derived plans → Found **24 deviations** in **5 seconds**
95
112
 
96
- **Total time**: < 10 seconds | **Total value**: Found real naming inconsistencies and undocumented features
113
+ **Total time**: < 10 seconds | **Total value**: Found real naming inconsistencies and undocumented features in legacy codebase
97
114
 
98
115
  👉 **[Read the complete example](docs/examples/dogfooding-specfact-cli.md)** with actual commands and outputs
99
116
 
@@ -103,6 +120,8 @@ We ran SpecFact CLI **on itself** to prove it works:
103
120
 
104
121
  **New to SpecFact?** Start with the [Getting Started Guide](docs/getting-started/README.md)
105
122
 
123
+ **Want to see integrations?** Check out [Integration Showcases](docs/examples/integration-showcases/) - Real bugs fixed via VS Code, Cursor, GitHub Actions
124
+
106
125
  **Tried Spec-Kit?** See [How SpecFact Compares to Spec-Kit](docs/guides/speckit-comparison.md) and [The Journey: From Spec-Kit to SpecFact](docs/guides/speckit-journey.md)
107
126
 
108
127
  **Need help?** Browse the [Documentation Hub](docs/README.md)
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "specfact-cli"
7
- version = "0.7.0"
7
+ version = "0.9.0"
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
  # Define the package version (kept in sync with pyproject.toml and setup.py)
6
- __version__ = "0.7.0"
6
+ __version__ = "0.9.0"
@@ -9,6 +9,6 @@ This package provides command-line tools for:
9
9
  - Validating reproducibility
10
10
  """
11
11
 
12
- __version__ = "0.7.0"
12
+ __version__ = "0.9.0"
13
13
 
14
14
  __all__ = ["__version__"]
@@ -197,7 +197,7 @@ class AmbiguityScanner:
197
197
  description=f"Feature {feature.key} has no outcomes specified",
198
198
  impact=0.6,
199
199
  uncertainty=0.5,
200
- question=f"What are the expected outcomes for feature {feature.key}?",
200
+ question=f"What are the expected outcomes for feature {feature.key} ({feature.title})?",
201
201
  related_sections=[f"features.{feature.key}.outcomes"],
202
202
  )
203
203
  )
@@ -228,7 +228,7 @@ class AmbiguityScanner:
228
228
  description=f"Feature {feature.key} mentions data but has no constraints",
229
229
  impact=0.5,
230
230
  uncertainty=0.6,
231
- question=f"What are the data model constraints for feature {feature.key}?",
231
+ question=f"What are the data model constraints for feature {feature.key} ({feature.title})?",
232
232
  related_sections=[f"features.{feature.key}.constraints"],
233
233
  )
234
234
  )
@@ -262,7 +262,7 @@ class AmbiguityScanner:
262
262
  description=f"Story {story.key} mentions UX but lacks error handling",
263
263
  impact=0.5,
264
264
  uncertainty=0.4,
265
- question=f"What error/empty states should be handled for story {story.key}?",
265
+ question=f"What error/empty states should be handled for story {story.key} ({story.title})?",
266
266
  related_sections=[f"features.{feature.key}.stories.{story.key}.acceptance"],
267
267
  )
268
268
  )
@@ -321,7 +321,7 @@ class AmbiguityScanner:
321
321
  description=f"Feature {feature.key} mentions integration but has no constraints",
322
322
  impact=0.6,
323
323
  uncertainty=0.5,
324
- question=f"What are the external dependency constraints and failure modes for feature {feature.key}?",
324
+ question=f"What are the external dependency constraints and failure modes for feature {feature.key} ({feature.title})?",
325
325
  related_sections=[f"features.{feature.key}.constraints"],
326
326
  )
327
327
  )
@@ -354,7 +354,7 @@ class AmbiguityScanner:
354
354
  description=f"Story {story.key} has limited acceptance criteria, may be missing edge cases",
355
355
  impact=0.4,
356
356
  uncertainty=0.5,
357
- question=f"What edge cases or negative scenarios should be handled for story {story.key}?",
357
+ question=f"What edge cases or negative scenarios should be handled for story {story.key} ({story.title})?",
358
358
  related_sections=[f"features.{feature.key}.stories.{story.key}.acceptance"],
359
359
  )
360
360
  )
@@ -424,7 +424,7 @@ class AmbiguityScanner:
424
424
  description=f"Story {story.key} has no acceptance criteria",
425
425
  impact=0.8,
426
426
  uncertainty=0.7,
427
- question=f"What are the testable acceptance criteria for story {story.key}?",
427
+ question=f"What are the testable acceptance criteria for story {story.key} ({story.title})?",
428
428
  related_sections=[f"features.{feature.key}.stories.{story.key}.acceptance"],
429
429
  )
430
430
  )
@@ -459,7 +459,7 @@ class AmbiguityScanner:
459
459
  description=f"Story {story.key} has vague acceptance criteria: {', '.join(vague_criteria[:2])}",
460
460
  impact=0.7,
461
461
  uncertainty=0.6,
462
- question=f"Story {story.key} has vague acceptance criteria. Should these be converted to testable Given/When/Then format?",
462
+ question=f"Story {story.key} ({story.title}) has vague acceptance criteria. Should these be converted to testable Given/When/Then format?",
463
463
  related_sections=[f"features.{feature.key}.stories.{story.key}.acceptance"],
464
464
  )
465
465
  )
@@ -486,7 +486,7 @@ class AmbiguityScanner:
486
486
  description=f"Story {story.key} acceptance criteria may not be testable",
487
487
  impact=0.5,
488
488
  uncertainty=0.4,
489
- question=f"Are the acceptance criteria for story {story.key} measurable and testable?",
489
+ question=f"Are the acceptance criteria for story {story.key} ({story.title}) measurable and testable?",
490
490
  related_sections=[f"features.{feature.key}.stories.{story.key}.acceptance"],
491
491
  )
492
492
  )
@@ -508,7 +508,7 @@ class AmbiguityScanner:
508
508
  description=f"Feature {feature.key} has no stories",
509
509
  impact=0.9,
510
510
  uncertainty=0.8,
511
- question=f"What user stories are needed for feature {feature.key}?",
511
+ question=f"What user stories are needed for feature {feature.key} ({feature.title})?",
512
512
  related_sections=[f"features.{feature.key}.stories"],
513
513
  )
514
514
  )
@@ -522,7 +522,7 @@ class AmbiguityScanner:
522
522
  description=f"Feature {feature.key} has no acceptance criteria",
523
523
  impact=0.7,
524
524
  uncertainty=0.6,
525
- question=f"What are the acceptance criteria for feature {feature.key}?",
525
+ question=f"What are the acceptance criteria for feature {feature.key} ({feature.title})?",
526
526
  related_sections=[f"features.{feature.key}.acceptance"],
527
527
  )
528
528
  )
@@ -558,7 +558,7 @@ class AmbiguityScanner:
558
558
  description=f"Feature {feature.key} has incomplete requirement: '{outcome}' (missing verb/action)",
559
559
  impact=0.6,
560
560
  uncertainty=0.5,
561
- question=f"Feature {feature.key} requirement '{outcome}' appears incomplete. What should the system do?",
561
+ question=f"Feature {feature.key} ({feature.title}) requirement '{outcome}' appears incomplete. What should the system do?",
562
562
  related_sections=[f"features.{feature.key}.outcomes"],
563
563
  )
564
564
  )
@@ -593,7 +593,7 @@ class AmbiguityScanner:
593
593
  description=f"Story {story.key} has generic tasks without implementation details: {', '.join(generic_tasks[:2])}",
594
594
  impact=0.4,
595
595
  uncertainty=0.3,
596
- question=f"Story {story.key} has generic tasks. Should these include file paths, method names, or component references?",
596
+ question=f"Story {story.key} ({story.title}) has generic tasks. Should these include file paths, method names, or component references?",
597
597
  related_sections=[f"features.{feature.key}.stories.{story.key}.tasks"],
598
598
  )
599
599
  )
@@ -62,7 +62,10 @@ class ConstitutionEvidenceExtractor:
62
62
  self.repo_path = Path(repo_path)
63
63
 
64
64
  @beartype
65
- @require(lambda repo_path: repo_path is None or repo_path.exists(), "Repository path must exist if provided")
65
+ @require(
66
+ lambda repo_path: repo_path is None or (isinstance(repo_path, Path) and repo_path.exists()),
67
+ "Repository path must exist if provided",
68
+ )
66
69
  @ensure(lambda result: isinstance(result, dict), "Must return dict")
67
70
  def extract_article_vii_evidence(self, repo_path: Path | None = None) -> dict[str, Any]:
68
71
  """
@@ -145,7 +148,7 @@ class ConstitutionEvidenceExtractor:
145
148
  )
146
149
  else:
147
150
  status = "FAIL"
148
- issues = []
151
+ issues: list[str] = []
149
152
  if not depth_pass:
150
153
  issues.append(
151
154
  f"deep directory structure (max depth: {max_depth}, threshold: {self.MAX_DIRECTORY_DEPTH})"
@@ -167,7 +170,10 @@ class ConstitutionEvidenceExtractor:
167
170
  }
168
171
 
169
172
  @beartype
170
- @require(lambda repo_path: repo_path is None or repo_path.exists(), "Repository path must exist if provided")
173
+ @require(
174
+ lambda repo_path: repo_path is None or (isinstance(repo_path, Path) and repo_path.exists()),
175
+ "Repository path must exist if provided",
176
+ )
171
177
  @ensure(lambda result: isinstance(result, dict), "Must return dict")
172
178
  def extract_article_viii_evidence(self, repo_path: Path | None = None) -> dict[str, Any]:
173
179
  """
@@ -252,7 +258,7 @@ class ConstitutionEvidenceExtractor:
252
258
  rationale = "No framework abstractions detected (direct library usage)"
253
259
  else:
254
260
  status = "FAIL"
255
- issues = []
261
+ issues: list[str] = []
256
262
  if frameworks_detected:
257
263
  issues.append(f"framework abstractions detected ({', '.join(frameworks_detected)})")
258
264
  if abstraction_layers > self.MAX_ABSTRACTION_LAYERS:
@@ -271,7 +277,10 @@ class ConstitutionEvidenceExtractor:
271
277
  }
272
278
 
273
279
  @beartype
274
- @require(lambda repo_path: repo_path is None or repo_path.exists(), "Repository path must exist if provided")
280
+ @require(
281
+ lambda repo_path: repo_path is None or (isinstance(repo_path, Path) and repo_path.exists()),
282
+ "Repository path must exist if provided",
283
+ )
275
284
  @ensure(lambda result: isinstance(result, dict), "Must return dict")
276
285
  def extract_article_ix_evidence(self, repo_path: Path | None = None) -> dict[str, Any]:
277
286
  """
@@ -303,7 +303,7 @@ class ContractExtractor:
303
303
  @ensure(lambda result: isinstance(result, str), "Must return string")
304
304
  def _op_to_string(self, op: ast.cmpop) -> str:
305
305
  """Convert AST comparison operator to string."""
306
- op_map = {
306
+ op_map: dict[type[Any], str] = {
307
307
  ast.Eq: "==",
308
308
  ast.NotEq: "!=",
309
309
  ast.Lt: "<",
@@ -53,7 +53,7 @@ from rich.panel import Panel
53
53
  from specfact_cli import __version__, runtime
54
54
 
55
55
  # Import command modules
56
- from specfact_cli.commands import constitution, enforce, import_cmd, init, plan, repro, sync
56
+ from specfact_cli.commands import constitution, enforce, generate, import_cmd, init, plan, repro, sync
57
57
  from specfact_cli.modes import OperationalMode, detect_mode
58
58
  from specfact_cli.utils.structured_io import StructuredFormat
59
59
 
@@ -291,8 +291,9 @@ app.add_typer(
291
291
  name="constitution",
292
292
  help="Manage project constitutions (Spec-Kit compatibility layer)",
293
293
  )
294
- app.add_typer(import_cmd.app, name="import", help="Import codebases and Spec-Kit projects")
294
+ app.add_typer(import_cmd.app, name="import", help="Import codebases and external tool projects (e.g., Spec-Kit, Linear, Jira)")
295
295
  app.add_typer(plan.app, name="plan", help="Manage development plans")
296
+ app.add_typer(generate.app, name="generate", help="Generate artifacts from SDD and plans")
296
297
  app.add_typer(enforce.app, name="enforce", help="Configure quality gates")
297
298
  app.add_typer(repro.app, name="repro", help="Run validation suite")
298
299
  app.add_typer(sync.app, name="sync", help="Synchronize Spec-Kit artifacts and repository changes")