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.
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/PKG-INFO +24 -5
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/README.md +23 -4
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/pyproject.toml +1 -1
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/__init__.py +1 -1
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/__init__.py +1 -1
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/analyzers/ambiguity_scanner.py +12 -12
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/analyzers/constitution_evidence_extractor.py +14 -5
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/analyzers/contract_extractor.py +1 -1
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/cli.py +3 -2
- specfact_cli-0.9.0/src/specfact_cli/commands/enforce.py +389 -0
- specfact_cli-0.9.0/src/specfact_cli/commands/generate.py +197 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/commands/import_cmd.py +222 -127
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/commands/plan.py +989 -326
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/commands/sync.py +277 -168
- specfact_cli-0.9.0/src/specfact_cli/generators/contract_generator.py +308 -0
- specfact_cli-0.9.0/src/specfact_cli/models/__init__.py +84 -0
- specfact_cli-0.9.0/src/specfact_cli/models/bridge.py +203 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/models/deviation.py +7 -0
- specfact_cli-0.9.0/src/specfact_cli/models/project.py +417 -0
- specfact_cli-0.9.0/src/specfact_cli/models/sdd.py +116 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/sync/__init__.py +9 -0
- specfact_cli-0.9.0/src/specfact_cli/sync/bridge_probe.py +365 -0
- specfact_cli-0.9.0/src/specfact_cli/sync/bridge_sync.py +508 -0
- specfact_cli-0.9.0/src/specfact_cli/sync/bridge_watch.py +449 -0
- specfact_cli-0.9.0/src/specfact_cli/templates/__init__.py +14 -0
- specfact_cli-0.9.0/src/specfact_cli/templates/bridge_templates.py +244 -0
- specfact_cli-0.9.0/src/specfact_cli/utils/bundle_loader.py +339 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/structure.py +171 -1
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/structured_io.py +3 -5
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/validators/__init__.py +8 -0
- specfact_cli-0.9.0/src/specfact_cli/validators/contract_validator.py +159 -0
- specfact_cli-0.7.0/src/specfact_cli/commands/enforce.py +0 -96
- specfact_cli-0.7.0/src/specfact_cli/models/__init__.py +0 -34
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/.gitignore +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/LICENSE.md +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/mappings/node-async.yaml +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/mappings/python-async.yaml +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/mappings/speckit-default.yaml +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-enforce.md +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-import-from-code.md +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-plan-add-feature.md +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-plan-add-story.md +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-plan-compare.md +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-plan-init.md +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-plan-promote.md +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-plan-review.md +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-plan-select.md +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-plan-update-feature.md +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-plan-update-idea.md +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-repro.md +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/prompts/specfact-sync.md +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/schemas/deviation.schema.json +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/schemas/plan.schema.json +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/schemas/protocol.schema.json +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/templates/github-action.yml.j2 +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/templates/plan.bundle.yaml.j2 +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/templates/pr-template.md.j2 +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/templates/protocol.yaml.j2 +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/resources/templates/telemetry.yaml.example +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/agents/__init__.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/agents/analyze_agent.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/agents/base.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/agents/plan_agent.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/agents/registry.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/agents/sync_agent.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/analyzers/__init__.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/analyzers/code_analyzer.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/analyzers/control_flow_analyzer.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/analyzers/requirement_extractor.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/analyzers/test_pattern_extractor.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/commands/__init__.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/commands/constitution.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/commands/init.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/commands/repro.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/common/__init__.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/common/logger_setup.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/common/logging_utils.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/common/text_utils.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/common/utils.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/comparators/__init__.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/comparators/plan_comparator.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/enrichers/constitution_enricher.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/enrichers/plan_enricher.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/generators/__init__.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/generators/plan_generator.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/generators/protocol_generator.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/generators/report_generator.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/generators/workflow_generator.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/importers/__init__.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/importers/speckit_converter.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/importers/speckit_scanner.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/migrations/__init__.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/migrations/plan_migrator.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/models/enforcement.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/models/plan.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/models/protocol.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/modes/__init__.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/modes/detector.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/modes/router.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/resources/semgrep/async.yml +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/runtime.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/sync/repository_sync.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/sync/speckit_sync.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/sync/watcher.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/telemetry.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/__init__.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/acceptance_criteria.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/console.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/enrichment_parser.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/feature_keys.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/git.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/github_annotations.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/ide_setup.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/prompts.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/utils/yaml_utils.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/validators/fsm.py +0 -0
- {specfact_cli-0.7.0 → specfact_cli-0.9.0}/src/specfact_cli/validators/repro_checker.py +0 -0
- {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.
|
|
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
|
|
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
|
|
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
|
+
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"
|
|
@@ -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(
|
|
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(
|
|
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(
|
|
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
|
|
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")
|