specfact-cli 0.13.2__tar.gz → 0.13.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.
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/PKG-INFO +1 -1
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/pyproject.toml +1 -1
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/resources/prompts/specfact.01-import.md +1 -0
- specfact_cli-0.13.3/resources/prompts/specfact.07-contracts.md +310 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/resources/prompts/specfact.validate.md +5 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/__init__.py +1 -1
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/__init__.py +1 -1
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/commands/analyze.py +108 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/utils/ide_setup.py +1 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/.gitignore +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/LICENSE.md +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/README.md +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/resources/mappings/node-async.yaml +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/resources/mappings/python-async.yaml +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/resources/mappings/speckit-default.yaml +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/resources/prompts/shared/cli-enforcement.md +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/resources/prompts/specfact.02-plan.md +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/resources/prompts/specfact.03-review.md +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/resources/prompts/specfact.04-sdd.md +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/resources/prompts/specfact.05-enforce.md +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/resources/prompts/specfact.06-sync.md +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/resources/prompts/specfact.compare.md +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/resources/schemas/deviation.schema.json +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/resources/schemas/plan.schema.json +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/resources/schemas/protocol.schema.json +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/resources/templates/github-action.yml.j2 +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/resources/templates/plan.bundle.yaml.j2 +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/resources/templates/pr-template.md.j2 +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/resources/templates/protocol.yaml.j2 +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/resources/templates/telemetry.yaml.example +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/agents/__init__.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/agents/analyze_agent.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/agents/base.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/agents/plan_agent.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/agents/registry.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/agents/sync_agent.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/analyzers/__init__.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/analyzers/ambiguity_scanner.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/analyzers/code_analyzer.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/analyzers/constitution_evidence_extractor.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/analyzers/contract_extractor.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/analyzers/control_flow_analyzer.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/analyzers/graph_analyzer.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/analyzers/relationship_mapper.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/analyzers/requirement_extractor.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/analyzers/test_pattern_extractor.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/cli.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/commands/__init__.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/commands/bridge.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/commands/drift.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/commands/enforce.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/commands/generate.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/commands/implement.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/commands/import_cmd.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/commands/init.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/commands/migrate.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/commands/plan.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/commands/repro.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/commands/run.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/commands/sdd.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/commands/spec.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/commands/sync.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/common/__init__.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/common/logger_setup.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/common/logging_utils.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/common/text_utils.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/common/utils.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/comparators/__init__.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/comparators/plan_comparator.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/enrichers/constitution_enricher.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/enrichers/plan_enricher.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/generators/__init__.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/generators/contract_generator.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/generators/openapi_extractor.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/generators/plan_generator.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/generators/protocol_generator.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/generators/report_generator.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/generators/task_generator.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/generators/test_to_openapi.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/generators/workflow_generator.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/importers/__init__.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/importers/speckit_converter.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/importers/speckit_scanner.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/integrations/__init__.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/integrations/specmatic.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/migrations/__init__.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/migrations/plan_migrator.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/models/__init__.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/models/bridge.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/models/deviation.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/models/enforcement.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/models/plan.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/models/project.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/models/protocol.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/models/quality.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/models/sdd.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/models/source_tracking.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/models/task.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/modes/__init__.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/modes/detector.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/modes/router.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/resources/semgrep/async.yml +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/resources/semgrep/code-quality.yml +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/resources/semgrep/feature-detection.yml +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/runtime.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/sync/__init__.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/sync/bridge_probe.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/sync/bridge_sync.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/sync/bridge_watch.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/sync/change_detector.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/sync/code_to_spec.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/sync/drift_detector.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/sync/repository_sync.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/sync/spec_to_code.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/sync/spec_to_tests.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/sync/speckit_sync.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/sync/watcher.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/telemetry.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/templates/__init__.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/templates/bridge_templates.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/utils/__init__.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/utils/acceptance_criteria.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/utils/bundle_loader.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/utils/console.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/utils/enrichment_context.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/utils/enrichment_parser.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/utils/feature_keys.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/utils/git.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/utils/github_annotations.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/utils/incremental_check.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/utils/optional_deps.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/utils/progress.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/utils/prompts.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/utils/sdd_discovery.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/utils/source_scanner.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/utils/structure.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/utils/structured_io.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/utils/yaml_utils.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/validators/__init__.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/validators/contract_validator.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/validators/fsm.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/validators/repro_checker.py +0 -0
- {specfact_cli-0.13.2 → specfact_cli-0.13.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.13.
|
|
3
|
+
Version: 0.13.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.13.
|
|
7
|
+
version = "0.13.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"
|
|
@@ -33,6 +33,7 @@ Import codebase → plan bundle. CLI extracts routes/schemas/relationships/contr
|
|
|
33
33
|
- Read `.specfact/projects/<bundle>/enrichment_context.md`
|
|
34
34
|
- Enrich: business context, "why" reasoning, missing acceptance criteria
|
|
35
35
|
- Validate: contracts vs code, feature/story alignment
|
|
36
|
+
- Save enrichment report to `.specfact/reports/enrichment/` (if created)
|
|
36
37
|
|
|
37
38
|
3. **Present**: Bundle location, report path, summary (features/stories/contracts/relationships)
|
|
38
39
|
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Analyze contract coverage, generate enhancement prompts, and apply contracts sequentially with careful review.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# SpecFact Contract Enhancement Workflow
|
|
6
|
+
|
|
7
|
+
## User Input
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
$ARGUMENTS
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
You **MUST** consider the user input before proceeding (if not empty).
|
|
14
|
+
|
|
15
|
+
## Purpose
|
|
16
|
+
|
|
17
|
+
Complete contract enhancement workflow: analyze coverage → generate prompts → apply contracts sequentially with careful review.
|
|
18
|
+
|
|
19
|
+
**When to use:** After codebase analysis, when adding contracts to existing code, improving contract coverage.
|
|
20
|
+
|
|
21
|
+
**Quick:** `/specfact.07-contracts` (uses active plan) or `/specfact.07-contracts legacy-api`
|
|
22
|
+
|
|
23
|
+
## Parameters
|
|
24
|
+
|
|
25
|
+
### Target/Input
|
|
26
|
+
|
|
27
|
+
- `bundle NAME` (optional argument) - Project bundle name (e.g., legacy-api, auth-module). Default: active plan (set via `plan select`)
|
|
28
|
+
- `--repo PATH` - Repository path. Default: current directory (.)
|
|
29
|
+
- `--apply CONTRACTS` - Contract types to apply: 'all-contracts', 'beartype', 'icontract', 'crosshair', or comma-separated list. Default: 'all-contracts'
|
|
30
|
+
- `--min-priority PRIORITY` - Minimum priority for files to process: 'high', 'medium', 'low'. Default: 'low' (process all files missing contracts)
|
|
31
|
+
|
|
32
|
+
### Behavior/Options
|
|
33
|
+
|
|
34
|
+
- `--no-interactive` - Non-interactive mode (for CI/CD). Default: False (interactive mode with careful review)
|
|
35
|
+
- `--auto-apply` - Automatically apply contracts after validation (skips confirmation). Default: False (requires confirmation)
|
|
36
|
+
- `--batch-size INT` - Number of files to process before pausing for review. Default: 1 (one file at a time for careful review)
|
|
37
|
+
|
|
38
|
+
## Workflow
|
|
39
|
+
|
|
40
|
+
### Step 1: Analyze Contract Coverage
|
|
41
|
+
|
|
42
|
+
**First, identify files missing contracts:**
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
specfact analyze contracts --repo <repo-path> --bundle <bundle-name>
|
|
46
|
+
# Uses active plan if bundle not specified
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Parse the output to identify:**
|
|
50
|
+
- Files missing beartype (marked with ✗)
|
|
51
|
+
- Files missing icontract (marked with ✗)
|
|
52
|
+
- Files missing crosshair (marked with ✗ or dim ✗)
|
|
53
|
+
- Files that need attention (prioritized in the table)
|
|
54
|
+
|
|
55
|
+
**Extract file list:**
|
|
56
|
+
- Focus on files marked with ✗ for beartype or icontract
|
|
57
|
+
- Crosshair is optional (marked with dim ✗), but can be included if user requests
|
|
58
|
+
- Filter out pure data model files (they use Pydantic validation)
|
|
59
|
+
|
|
60
|
+
**Present summary:**
|
|
61
|
+
- Total files analyzed
|
|
62
|
+
- Files missing contracts (by type)
|
|
63
|
+
- Files recommended for enhancement
|
|
64
|
+
|
|
65
|
+
### Step 2: Generate Enhancement Prompts
|
|
66
|
+
|
|
67
|
+
**For each file missing contracts, generate a prompt:**
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
specfact generate contracts-prompt <file-path> --apply <contract-types> --bundle <bundle-name>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Important:**
|
|
74
|
+
- Generate prompts for ALL files missing contracts (or based on --min-priority)
|
|
75
|
+
- Prompts are saved to `.specfact/projects/<bundle-name>/prompts/enhance-<filename>-<contracts>.md`
|
|
76
|
+
- If no bundle, prompts saved to `.specfact/prompts/`
|
|
77
|
+
- Each prompt file contains instructions for the AI IDE to enhance the file
|
|
78
|
+
|
|
79
|
+
**Present prompt generation summary:**
|
|
80
|
+
- Number of prompts generated
|
|
81
|
+
- Location of prompt files
|
|
82
|
+
- List of files ready for enhancement
|
|
83
|
+
|
|
84
|
+
### Step 3: User Review and Selection
|
|
85
|
+
|
|
86
|
+
**Present files for user selection:**
|
|
87
|
+
|
|
88
|
+
```text
|
|
89
|
+
Files ready for contract enhancement:
|
|
90
|
+
1. src/auth/login.py (missing: beartype, icontract)
|
|
91
|
+
2. src/api/users.py (missing: beartype, icontract, crosshair)
|
|
92
|
+
3. src/utils/helpers.py (missing: beartype)
|
|
93
|
+
...
|
|
94
|
+
|
|
95
|
+
Select files to enhance (comma-separated numbers, 'all', or 'skip'):
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**Wait for user input:**
|
|
99
|
+
- If user selects specific files, process only those
|
|
100
|
+
- If user selects 'all', process all files sequentially
|
|
101
|
+
- If user selects 'skip', move to next step or exit
|
|
102
|
+
|
|
103
|
+
**In non-interactive mode:**
|
|
104
|
+
- Process all files automatically (or based on --min-priority)
|
|
105
|
+
- Still process sequentially (one at a time) for careful validation
|
|
106
|
+
|
|
107
|
+
### Step 4: Apply Contracts Sequentially
|
|
108
|
+
|
|
109
|
+
**For each selected file, apply contracts one at a time:**
|
|
110
|
+
|
|
111
|
+
**4.1: Read the prompt file**
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# Prompt file location: .specfact/projects/<bundle-name>/prompts/enhance-<filename>-<contracts>.md
|
|
115
|
+
# Or: .specfact/prompts/enhance-<filename>-<contracts>.md
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**4.2: Enhance the code using AI IDE**
|
|
119
|
+
|
|
120
|
+
- Read the original file
|
|
121
|
+
- Apply contracts according to the prompt instructions
|
|
122
|
+
- Write enhanced code to temporary file: `enhanced_<filename>.py`
|
|
123
|
+
- **DO NOT modify the original file directly**
|
|
124
|
+
|
|
125
|
+
**4.3: Validate enhanced code**
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
specfact generate contracts-apply enhanced_<filename>.py --original <original-file-path>
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Validation includes:**
|
|
132
|
+
- File size check
|
|
133
|
+
- Syntax validation
|
|
134
|
+
- AST structure comparison
|
|
135
|
+
- Contract imports verification
|
|
136
|
+
- Code quality checks (ruff, pylint, basedpyright, mypy if available)
|
|
137
|
+
- Test execution (scoped to relevant test files)
|
|
138
|
+
|
|
139
|
+
**4.4: Handle validation results**
|
|
140
|
+
|
|
141
|
+
**If validation fails:**
|
|
142
|
+
- Review error messages
|
|
143
|
+
- Fix issues in enhanced code
|
|
144
|
+
- Re-validate (up to 3 attempts)
|
|
145
|
+
- If still failing after 3 attempts, skip this file and continue to next
|
|
146
|
+
|
|
147
|
+
**If validation succeeds:**
|
|
148
|
+
- Show diff preview (what will change)
|
|
149
|
+
- If `--auto-apply` is False, ask for confirmation:
|
|
150
|
+
```text
|
|
151
|
+
Validation passed. Apply changes to <original-file>? (y/n):
|
|
152
|
+
```
|
|
153
|
+
- If confirmed (or `--auto-apply` is True), apply changes automatically
|
|
154
|
+
- If not confirmed, skip this file and continue to next
|
|
155
|
+
|
|
156
|
+
**4.5: Pause for review (if --batch-size > 1)**
|
|
157
|
+
|
|
158
|
+
After processing `--batch-size` files, pause and show summary:
|
|
159
|
+
```text
|
|
160
|
+
Processed 3/10 files:
|
|
161
|
+
✓ src/auth/login.py - Contracts applied successfully
|
|
162
|
+
✓ src/api/users.py - Contracts applied successfully
|
|
163
|
+
⏭ src/utils/helpers.py - Skipped (user declined)
|
|
164
|
+
|
|
165
|
+
Continue with next batch? (y/n):
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Step 5: Final Summary
|
|
169
|
+
|
|
170
|
+
**After all files processed, show final summary:**
|
|
171
|
+
|
|
172
|
+
```text
|
|
173
|
+
Contract Enhancement Complete
|
|
174
|
+
|
|
175
|
+
Summary:
|
|
176
|
+
- Files analyzed: 25
|
|
177
|
+
- Files processed: 18
|
|
178
|
+
- Files enhanced: 15
|
|
179
|
+
- Files skipped: 3
|
|
180
|
+
- Files failed: 0
|
|
181
|
+
|
|
182
|
+
Enhanced files:
|
|
183
|
+
✓ src/auth/login.py (beartype, icontract)
|
|
184
|
+
✓ src/api/users.py (beartype, icontract, crosshair)
|
|
185
|
+
...
|
|
186
|
+
|
|
187
|
+
Next steps:
|
|
188
|
+
1. Verify contract coverage: specfact analyze contracts --bundle <bundle-name>
|
|
189
|
+
2. Run full test suite: pytest (or your project's test command)
|
|
190
|
+
3. Review changes: git diff
|
|
191
|
+
4. Commit enhanced code
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## CLI Enforcement
|
|
195
|
+
|
|
196
|
+
**CRITICAL**: Always use SpecFact CLI commands. See [CLI Enforcement Rules](./shared/cli-enforcement.md) for details.
|
|
197
|
+
|
|
198
|
+
**Rules:**
|
|
199
|
+
- Execute CLI commands in sequence (analyze → generate → apply)
|
|
200
|
+
- Never modify `.specfact/` directly
|
|
201
|
+
- Always validate before applying changes
|
|
202
|
+
- Process files sequentially for careful review
|
|
203
|
+
- Use `--no-interactive` only in CI/CD environments
|
|
204
|
+
- Use CLI output as grounding for all operations
|
|
205
|
+
|
|
206
|
+
## Expected Output
|
|
207
|
+
|
|
208
|
+
### Step 1: Analysis Results
|
|
209
|
+
|
|
210
|
+
```text
|
|
211
|
+
Contract Coverage Analysis: legacy-api
|
|
212
|
+
Repository: /path/to/repo
|
|
213
|
+
|
|
214
|
+
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━┓
|
|
215
|
+
┃ File ┃ beartype ┃ icontract ┃ crosshair ┃ Coverage ┃
|
|
216
|
+
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━┩
|
|
217
|
+
│ src/auth/login.py │ ✗ │ ✗ │ ✗ │ 0% │
|
|
218
|
+
│ src/api/users.py │ ✗ │ ✗ │ ✗ │ 0% │
|
|
219
|
+
...
|
|
220
|
+
|
|
221
|
+
Summary:
|
|
222
|
+
Files analyzed: 25
|
|
223
|
+
Files with beartype: 7 (28.0%)
|
|
224
|
+
Files with icontract: 7 (28.0%)
|
|
225
|
+
Files with crosshair: 2 (8.0%)
|
|
226
|
+
|
|
227
|
+
Found 18 files missing contracts.
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Step 2: Prompt Generation
|
|
231
|
+
|
|
232
|
+
```text
|
|
233
|
+
Generating enhancement prompts...
|
|
234
|
+
|
|
235
|
+
✓ Generated prompt for: src/auth/login.py
|
|
236
|
+
Location: .specfact/projects/legacy-api/prompts/enhance-login.py-all-contracts.md
|
|
237
|
+
|
|
238
|
+
✓ Generated prompt for: src/api/users.py
|
|
239
|
+
Location: .specfact/projects/legacy-api/prompts/enhance-users.py-all-contracts.md
|
|
240
|
+
|
|
241
|
+
...
|
|
242
|
+
|
|
243
|
+
✓ Generated 18 prompts successfully
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Step 3: User Selection
|
|
247
|
+
|
|
248
|
+
```text
|
|
249
|
+
Files ready for contract enhancement:
|
|
250
|
+
1. src/auth/login.py (missing: beartype, icontract, crosshair)
|
|
251
|
+
2. src/api/users.py (missing: beartype, icontract, crosshair)
|
|
252
|
+
3. src/utils/helpers.py (missing: beartype)
|
|
253
|
+
...
|
|
254
|
+
|
|
255
|
+
Select files to enhance (comma-separated numbers, 'all', or 'skip'): all
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Step 4: Sequential Application
|
|
259
|
+
|
|
260
|
+
```text
|
|
261
|
+
Processing file 1/18: src/auth/login.py
|
|
262
|
+
|
|
263
|
+
[Reading prompt file...]
|
|
264
|
+
[Enhancing code with AI IDE...]
|
|
265
|
+
[Writing enhanced code to: enhanced_login.py]
|
|
266
|
+
|
|
267
|
+
Validating enhanced code...
|
|
268
|
+
✓ File size check: passed
|
|
269
|
+
✓ Syntax validation: passed
|
|
270
|
+
✓ AST structure: passed (15 definitions preserved)
|
|
271
|
+
✓ Contract imports: verified
|
|
272
|
+
✓ Code quality checks: passed (ruff, pylint)
|
|
273
|
+
✓ Tests: 12/12 passed
|
|
274
|
+
|
|
275
|
+
Diff preview:
|
|
276
|
+
+ from beartype import beartype
|
|
277
|
+
+ from icontract import require, ensure
|
|
278
|
+
...
|
|
279
|
+
|
|
280
|
+
Apply changes to src/auth/login.py? (y/n): y
|
|
281
|
+
✓ Contracts applied successfully
|
|
282
|
+
|
|
283
|
+
[Pausing for review... Press Enter to continue to next file]
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Common Patterns
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
/specfact.07-contracts # Uses active plan, all-contracts, interactive
|
|
290
|
+
/specfact.07-contracts legacy-api # Specific bundle
|
|
291
|
+
/specfact.07-contracts --apply beartype,icontract # Specific contract types
|
|
292
|
+
/specfact.07-contracts --min-priority high # Only high-priority files
|
|
293
|
+
/specfact.07-contracts --batch-size 3 # Process 3 files before pausing
|
|
294
|
+
/specfact.07-contracts --auto-apply # Auto-apply after validation (no confirmation)
|
|
295
|
+
/specfact.07-contracts --no-interactive # CI/CD mode (still sequential for safety)
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## Important Notes
|
|
299
|
+
|
|
300
|
+
1. **Sequential Processing**: Files are processed one at a time (or in small batches) to allow careful review
|
|
301
|
+
2. **Validation Required**: All enhanced code must pass validation before applying
|
|
302
|
+
3. **User Control**: User can skip files, pause between files, or stop the process
|
|
303
|
+
4. **Data Model Files**: Pure Pydantic/dataclass files are automatically excluded (they use Pydantic validation)
|
|
304
|
+
5. **Prompt Location**: Prompts are saved to bundle-specific directories when bundle is provided
|
|
305
|
+
6. **Temporary Files**: Enhanced code is written to temporary files (`enhanced_<filename>.py`) for validation before applying
|
|
306
|
+
|
|
307
|
+
## Context
|
|
308
|
+
|
|
309
|
+
{ARGS}
|
|
310
|
+
|
|
@@ -64,6 +64,11 @@ specfact repro --repo <path> [--verbose] [--fail-fast] [--fix] [--budget <second
|
|
|
64
64
|
|
|
65
65
|
**CRITICAL**: Always use SpecFact CLI commands. See [CLI Enforcement Rules](./shared/cli-enforcement.md) for details.
|
|
66
66
|
|
|
67
|
+
**Rules:**
|
|
68
|
+
- Execute CLI first - never create artifacts directly
|
|
69
|
+
- Never modify `.specfact/` directly
|
|
70
|
+
- Use CLI output as grounding for validation results
|
|
71
|
+
|
|
67
72
|
## Expected Output
|
|
68
73
|
|
|
69
74
|
### Success
|
|
@@ -7,6 +7,7 @@ contract coverage, code quality metrics, and enhancement opportunities.
|
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
+
import ast
|
|
10
11
|
from pathlib import Path
|
|
11
12
|
|
|
12
13
|
import typer
|
|
@@ -207,6 +208,30 @@ def _analyze_file_quality(file_path: Path) -> CodeQuality:
|
|
|
207
208
|
with file_path.open(encoding="utf-8") as f:
|
|
208
209
|
content = f.read()
|
|
209
210
|
|
|
211
|
+
# Quick check: if file is in models/ directory, likely a data model file
|
|
212
|
+
# This avoids expensive AST parsing for most data model files
|
|
213
|
+
file_str = str(file_path)
|
|
214
|
+
is_models_dir = "/models/" in file_str or "\\models\\" in file_str
|
|
215
|
+
|
|
216
|
+
# For files in models/ directory, do quick AST check to confirm
|
|
217
|
+
if is_models_dir:
|
|
218
|
+
try:
|
|
219
|
+
import ast
|
|
220
|
+
|
|
221
|
+
tree = ast.parse(content, filename=str(file_path))
|
|
222
|
+
# Quick check: if only BaseModel classes with no business logic, skip contract check
|
|
223
|
+
if _is_pure_data_model_file(tree):
|
|
224
|
+
return CodeQuality(
|
|
225
|
+
beartype=True, # Pydantic provides type validation
|
|
226
|
+
icontract=True, # Pydantic provides validation (Field validators)
|
|
227
|
+
crosshair=False, # CrossHair not typically used for data models
|
|
228
|
+
coverage=0.0,
|
|
229
|
+
)
|
|
230
|
+
except (SyntaxError, ValueError):
|
|
231
|
+
# If AST parsing fails, fall through to normal check
|
|
232
|
+
pass
|
|
233
|
+
|
|
234
|
+
# Check for contract decorators in content
|
|
210
235
|
has_beartype = "beartype" in content or "@beartype" in content
|
|
211
236
|
has_icontract = "icontract" in content or "@require" in content or "@ensure" in content
|
|
212
237
|
has_crosshair = "crosshair" in content.lower()
|
|
@@ -223,3 +248,86 @@ def _analyze_file_quality(file_path: Path) -> CodeQuality:
|
|
|
223
248
|
except Exception:
|
|
224
249
|
# Return default quality if analysis fails
|
|
225
250
|
return CodeQuality()
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def _is_pure_data_model_file(tree: ast.AST) -> bool:
|
|
254
|
+
"""
|
|
255
|
+
Quick check if file contains only pure data models (Pydantic BaseModel, dataclasses) with no business logic.
|
|
256
|
+
|
|
257
|
+
Returns:
|
|
258
|
+
True if file is pure data models, False otherwise
|
|
259
|
+
"""
|
|
260
|
+
has_pydantic_models = False
|
|
261
|
+
has_dataclasses = False
|
|
262
|
+
has_business_logic = False
|
|
263
|
+
|
|
264
|
+
# Standard methods that don't need contracts (including common helper methods)
|
|
265
|
+
standard_methods = {
|
|
266
|
+
"__init__",
|
|
267
|
+
"__str__",
|
|
268
|
+
"__repr__",
|
|
269
|
+
"__eq__",
|
|
270
|
+
"__hash__",
|
|
271
|
+
"model_dump",
|
|
272
|
+
"model_validate",
|
|
273
|
+
"dict",
|
|
274
|
+
"json",
|
|
275
|
+
"copy",
|
|
276
|
+
"update",
|
|
277
|
+
# Common helper methods on data models (convenience methods, not business logic)
|
|
278
|
+
"compute_summary",
|
|
279
|
+
"update_summary",
|
|
280
|
+
"to_dict",
|
|
281
|
+
"from_dict",
|
|
282
|
+
"validate",
|
|
283
|
+
"serialize",
|
|
284
|
+
"deserialize",
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
# Check module-level functions and class methods separately
|
|
288
|
+
# First, collect all classes and check their methods
|
|
289
|
+
for node in ast.walk(tree):
|
|
290
|
+
if isinstance(node, ast.ClassDef):
|
|
291
|
+
# Check methods in this class
|
|
292
|
+
for item in node.body:
|
|
293
|
+
if isinstance(item, (ast.FunctionDef, ast.AsyncFunctionDef)) and item.name not in standard_methods:
|
|
294
|
+
# Non-standard method - likely business logic
|
|
295
|
+
has_business_logic = True
|
|
296
|
+
break
|
|
297
|
+
if has_business_logic:
|
|
298
|
+
break
|
|
299
|
+
|
|
300
|
+
# Then check for module-level functions (functions not inside any class)
|
|
301
|
+
if not has_business_logic and isinstance(tree, ast.Module):
|
|
302
|
+
# Get all top-level nodes (module body)
|
|
303
|
+
for node in tree.body:
|
|
304
|
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) and not node.name.startswith(
|
|
305
|
+
"_"
|
|
306
|
+
): # Public functions
|
|
307
|
+
has_business_logic = True
|
|
308
|
+
break
|
|
309
|
+
|
|
310
|
+
# Check for Pydantic models and dataclasses
|
|
311
|
+
for node in ast.walk(tree):
|
|
312
|
+
if isinstance(node, ast.ClassDef):
|
|
313
|
+
for base in node.bases:
|
|
314
|
+
if isinstance(base, ast.Name) and base.id == "BaseModel":
|
|
315
|
+
has_pydantic_models = True
|
|
316
|
+
break
|
|
317
|
+
if isinstance(base, ast.Attribute) and base.attr == "BaseModel":
|
|
318
|
+
has_pydantic_models = True
|
|
319
|
+
break
|
|
320
|
+
|
|
321
|
+
for decorator in node.decorator_list:
|
|
322
|
+
if (isinstance(decorator, ast.Name) and decorator.id == "dataclass") or (
|
|
323
|
+
isinstance(decorator, ast.Attribute) and decorator.attr == "dataclass"
|
|
324
|
+
):
|
|
325
|
+
has_dataclasses = True
|
|
326
|
+
break
|
|
327
|
+
|
|
328
|
+
# Business logic check is done above (methods and module-level functions)
|
|
329
|
+
|
|
330
|
+
# File is pure data model if:
|
|
331
|
+
# 1. Has Pydantic models or dataclasses
|
|
332
|
+
# 2. No business logic methods or functions
|
|
333
|
+
return (has_pydantic_models or has_dataclasses) and not has_business_logic
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/analyzers/contract_extractor.py
RENAMED
|
File without changes
|
{specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/analyzers/control_flow_analyzer.py
RENAMED
|
File without changes
|
|
File without changes
|
{specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/analyzers/relationship_mapper.py
RENAMED
|
File without changes
|
{specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/analyzers/requirement_extractor.py
RENAMED
|
File without changes
|
{specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/analyzers/test_pattern_extractor.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/enrichers/constitution_enricher.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/generators/contract_generator.py
RENAMED
|
File without changes
|
{specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/generators/openapi_extractor.py
RENAMED
|
File without changes
|
|
File without changes
|
{specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/generators/protocol_generator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/generators/workflow_generator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/resources/semgrep/code-quality.yml
RENAMED
|
File without changes
|
{specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/resources/semgrep/feature-detection.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{specfact_cli-0.13.2 → specfact_cli-0.13.3}/src/specfact_cli/validators/contract_validator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|