specfact-cli 0.4.0__py3-none-any.whl
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.
Potentially problematic release.
This version of specfact-cli might be problematic. Click here for more details.
- specfact_cli/__init__.py +14 -0
- specfact_cli/agents/__init__.py +23 -0
- specfact_cli/agents/analyze_agent.py +392 -0
- specfact_cli/agents/base.py +95 -0
- specfact_cli/agents/plan_agent.py +202 -0
- specfact_cli/agents/registry.py +176 -0
- specfact_cli/agents/sync_agent.py +133 -0
- specfact_cli/analyzers/__init__.py +10 -0
- specfact_cli/analyzers/code_analyzer.py +775 -0
- specfact_cli/cli.py +397 -0
- specfact_cli/commands/__init__.py +7 -0
- specfact_cli/commands/enforce.py +87 -0
- specfact_cli/commands/import_cmd.py +355 -0
- specfact_cli/commands/init.py +119 -0
- specfact_cli/commands/plan.py +1090 -0
- specfact_cli/commands/repro.py +172 -0
- specfact_cli/commands/sync.py +408 -0
- specfact_cli/common/__init__.py +24 -0
- specfact_cli/common/logger_setup.py +673 -0
- specfact_cli/common/logging_utils.py +41 -0
- specfact_cli/common/text_utils.py +52 -0
- specfact_cli/common/utils.py +48 -0
- specfact_cli/comparators/__init__.py +10 -0
- specfact_cli/comparators/plan_comparator.py +391 -0
- specfact_cli/generators/__init__.py +13 -0
- specfact_cli/generators/plan_generator.py +105 -0
- specfact_cli/generators/protocol_generator.py +115 -0
- specfact_cli/generators/report_generator.py +200 -0
- specfact_cli/generators/workflow_generator.py +111 -0
- specfact_cli/importers/__init__.py +6 -0
- specfact_cli/importers/speckit_converter.py +773 -0
- specfact_cli/importers/speckit_scanner.py +704 -0
- specfact_cli/models/__init__.py +32 -0
- specfact_cli/models/deviation.py +105 -0
- specfact_cli/models/enforcement.py +150 -0
- specfact_cli/models/plan.py +97 -0
- specfact_cli/models/protocol.py +28 -0
- specfact_cli/modes/__init__.py +18 -0
- specfact_cli/modes/detector.py +126 -0
- specfact_cli/modes/router.py +153 -0
- specfact_cli/sync/__init__.py +11 -0
- specfact_cli/sync/repository_sync.py +279 -0
- specfact_cli/sync/speckit_sync.py +388 -0
- specfact_cli/utils/__init__.py +57 -0
- specfact_cli/utils/console.py +69 -0
- specfact_cli/utils/feature_keys.py +213 -0
- specfact_cli/utils/git.py +241 -0
- specfact_cli/utils/ide_setup.py +381 -0
- specfact_cli/utils/prompts.py +179 -0
- specfact_cli/utils/structure.py +496 -0
- specfact_cli/utils/yaml_utils.py +200 -0
- specfact_cli/validators/__init__.py +19 -0
- specfact_cli/validators/fsm.py +260 -0
- specfact_cli/validators/repro_checker.py +320 -0
- specfact_cli/validators/schema.py +200 -0
- specfact_cli-0.4.0.dist-info/METADATA +332 -0
- specfact_cli-0.4.0.dist-info/RECORD +60 -0
- specfact_cli-0.4.0.dist-info/WHEEL +4 -0
- specfact_cli-0.4.0.dist-info/entry_points.txt +2 -0
- specfact_cli-0.4.0.dist-info/licenses/LICENSE.md +55 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Schema validation module.
|
|
3
|
+
|
|
4
|
+
This module provides schema validation for plan bundles and protocols.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
import jsonschema
|
|
13
|
+
import yaml
|
|
14
|
+
from beartype import beartype
|
|
15
|
+
from icontract import ensure, require
|
|
16
|
+
from pydantic import ValidationError
|
|
17
|
+
|
|
18
|
+
from specfact_cli.models.deviation import Deviation, DeviationSeverity, DeviationType, ValidationReport
|
|
19
|
+
from specfact_cli.models.plan import PlanBundle
|
|
20
|
+
from specfact_cli.models.protocol import Protocol
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class SchemaValidator:
|
|
24
|
+
"""Schema validator for plan bundles and protocols."""
|
|
25
|
+
|
|
26
|
+
def __init__(self, schemas_dir: Path | None = None):
|
|
27
|
+
"""
|
|
28
|
+
Initialize schema validator.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
schemas_dir: Directory containing JSON schemas (default: resources/schemas)
|
|
32
|
+
"""
|
|
33
|
+
if schemas_dir is None:
|
|
34
|
+
# Default to resources/schemas relative to project root
|
|
35
|
+
schemas_dir = Path(__file__).parent.parent.parent.parent / "resources" / "schemas"
|
|
36
|
+
|
|
37
|
+
self.schemas_dir = Path(schemas_dir)
|
|
38
|
+
self._schemas: dict[str, dict] = {}
|
|
39
|
+
|
|
40
|
+
def _load_schema(self, schema_name: str) -> dict:
|
|
41
|
+
"""
|
|
42
|
+
Load JSON schema from file.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
schema_name: Name of the schema file (with or without .schema.json extension)
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
Loaded schema dict
|
|
49
|
+
|
|
50
|
+
Raises:
|
|
51
|
+
FileNotFoundError: If schema file doesn't exist
|
|
52
|
+
"""
|
|
53
|
+
if schema_name not in self._schemas:
|
|
54
|
+
# Handle both "plan" and "plan.schema.json" as input
|
|
55
|
+
if schema_name.endswith(".schema.json"):
|
|
56
|
+
schema_path = self.schemas_dir / schema_name
|
|
57
|
+
elif schema_name.endswith(".json"):
|
|
58
|
+
# Just add .schema if only .json is present
|
|
59
|
+
schema_path = self.schemas_dir / schema_name.replace(".json", ".schema.json")
|
|
60
|
+
else:
|
|
61
|
+
# Add full suffix
|
|
62
|
+
schema_path = self.schemas_dir / f"{schema_name}.schema.json"
|
|
63
|
+
|
|
64
|
+
if not schema_path.exists():
|
|
65
|
+
raise FileNotFoundError(f"Schema file not found: {schema_path}")
|
|
66
|
+
|
|
67
|
+
with open(schema_path, encoding="utf-8") as f:
|
|
68
|
+
self._schemas[schema_name] = json.load(f)
|
|
69
|
+
|
|
70
|
+
return self._schemas[schema_name]
|
|
71
|
+
|
|
72
|
+
@beartype
|
|
73
|
+
@require(lambda data: isinstance(data, dict), "Data must be dictionary")
|
|
74
|
+
@require(
|
|
75
|
+
lambda schema_name: isinstance(schema_name, str) and len(schema_name) > 0,
|
|
76
|
+
"Schema name must be non-empty string",
|
|
77
|
+
)
|
|
78
|
+
@ensure(lambda result: isinstance(result, ValidationReport), "Must return ValidationReport")
|
|
79
|
+
def validate_json_schema(self, data: dict, schema_name: str) -> ValidationReport:
|
|
80
|
+
"""
|
|
81
|
+
Validate data against JSON schema.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
data: Data to validate
|
|
85
|
+
schema_name: Name of the schema (e.g., 'plan', 'protocol', 'deviation')
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
Validation report
|
|
89
|
+
"""
|
|
90
|
+
report = ValidationReport()
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
schema = self._load_schema(schema_name)
|
|
94
|
+
jsonschema.validate(instance=data, schema=schema)
|
|
95
|
+
|
|
96
|
+
except jsonschema.ValidationError as e:
|
|
97
|
+
deviation = Deviation(
|
|
98
|
+
type=DeviationType.FSM_MISMATCH, # Generic type for schema violations
|
|
99
|
+
severity=DeviationSeverity.HIGH,
|
|
100
|
+
description=f"Schema validation failed: {e.message}",
|
|
101
|
+
location=f"${'.'.join(str(p) for p in e.path)}" if e.path else "root",
|
|
102
|
+
fix_hint=f"Expected {e.validator}: {e.validator_value}",
|
|
103
|
+
)
|
|
104
|
+
report.add_deviation(deviation)
|
|
105
|
+
|
|
106
|
+
except FileNotFoundError as e:
|
|
107
|
+
deviation = Deviation(
|
|
108
|
+
type=DeviationType.FSM_MISMATCH,
|
|
109
|
+
severity=DeviationSeverity.HIGH,
|
|
110
|
+
description=str(e),
|
|
111
|
+
location="schema",
|
|
112
|
+
fix_hint="Ensure the schema file exists in the schemas directory",
|
|
113
|
+
)
|
|
114
|
+
report.add_deviation(deviation)
|
|
115
|
+
|
|
116
|
+
return report
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@beartype
|
|
120
|
+
@ensure(
|
|
121
|
+
lambda result: isinstance(result, ValidationReport)
|
|
122
|
+
or (isinstance(result, tuple) and len(result) == 3 and isinstance(result[0], bool)),
|
|
123
|
+
"Must return ValidationReport or tuple[bool, str | None, PlanBundle | None]",
|
|
124
|
+
)
|
|
125
|
+
def validate_plan_bundle(
|
|
126
|
+
plan_or_path: PlanBundle | Path,
|
|
127
|
+
) -> ValidationReport | tuple[bool, str | None, PlanBundle | None]:
|
|
128
|
+
"""
|
|
129
|
+
Validate a plan bundle model or YAML file.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
plan_or_path: PlanBundle model or Path to plan bundle YAML file
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
ValidationReport if model provided, tuple of (is_valid, error_message, parsed_bundle) if path provided
|
|
136
|
+
"""
|
|
137
|
+
# If it's already a model, just return success report
|
|
138
|
+
if isinstance(plan_or_path, PlanBundle):
|
|
139
|
+
report = ValidationReport()
|
|
140
|
+
# Could add additional validation logic here if needed
|
|
141
|
+
return report
|
|
142
|
+
|
|
143
|
+
# Otherwise treat as path
|
|
144
|
+
path = plan_or_path
|
|
145
|
+
try:
|
|
146
|
+
with path.open("r") as f:
|
|
147
|
+
data = yaml.safe_load(f)
|
|
148
|
+
|
|
149
|
+
bundle = PlanBundle(**data)
|
|
150
|
+
return True, None, bundle
|
|
151
|
+
|
|
152
|
+
except FileNotFoundError:
|
|
153
|
+
return False, f"File not found: {path}", None
|
|
154
|
+
except yaml.YAMLError as e:
|
|
155
|
+
return False, f"YAML parsing error: {e}", None
|
|
156
|
+
except ValidationError as e:
|
|
157
|
+
return False, f"Validation error: {e}", None
|
|
158
|
+
except Exception as e:
|
|
159
|
+
return False, f"Unexpected error: {e}", None
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@beartype
|
|
163
|
+
@ensure(
|
|
164
|
+
lambda result: isinstance(result, ValidationReport)
|
|
165
|
+
or (isinstance(result, tuple) and len(result) == 3 and isinstance(result[0], bool)),
|
|
166
|
+
"Must return ValidationReport or tuple[bool, str | None, Protocol | None]",
|
|
167
|
+
)
|
|
168
|
+
def validate_protocol(protocol_or_path: Protocol | Path) -> ValidationReport | tuple[bool, str | None, Protocol | None]:
|
|
169
|
+
"""
|
|
170
|
+
Validate a protocol model or YAML file.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
protocol_or_path: Protocol model or Path to protocol YAML file
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
ValidationReport if model provided, tuple of (is_valid, error_message, parsed_protocol) if path provided
|
|
177
|
+
"""
|
|
178
|
+
# If it's already a model, just return success report
|
|
179
|
+
if isinstance(protocol_or_path, Protocol):
|
|
180
|
+
report = ValidationReport()
|
|
181
|
+
# Could add additional validation logic here if needed
|
|
182
|
+
return report
|
|
183
|
+
|
|
184
|
+
# Otherwise treat as path
|
|
185
|
+
path = protocol_or_path
|
|
186
|
+
try:
|
|
187
|
+
with path.open("r") as f:
|
|
188
|
+
data = yaml.safe_load(f)
|
|
189
|
+
|
|
190
|
+
protocol = Protocol(**data)
|
|
191
|
+
return True, None, protocol
|
|
192
|
+
|
|
193
|
+
except FileNotFoundError:
|
|
194
|
+
return False, f"File not found: {path}", None
|
|
195
|
+
except yaml.YAMLError as e:
|
|
196
|
+
return False, f"YAML parsing error: {e}", None
|
|
197
|
+
except ValidationError as e:
|
|
198
|
+
return False, f"Validation error: {e}", None
|
|
199
|
+
except Exception as e:
|
|
200
|
+
return False, f"Unexpected error: {e}", None
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: specfact-cli
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: SpecFact CLI - Spec→Contract→Sentinel tool for contract-driven development with automated quality gates
|
|
5
|
+
Project-URL: Homepage, https://github.com/nold-ai/specfact-cli
|
|
6
|
+
Project-URL: Repository, https://github.com/nold-ai/specfact-cli.git
|
|
7
|
+
Project-URL: Documentation, https://github.com/nold-ai/specfact-cli#readme
|
|
8
|
+
Project-URL: Issues, https://github.com/nold-ai/specfact-cli/issues
|
|
9
|
+
Author-email: "NOLD AI (Owner: Dominikus Nold)" <hello@noldai.com>
|
|
10
|
+
License: # Sustainable Use License
|
|
11
|
+
|
|
12
|
+
Version 1.0
|
|
13
|
+
|
|
14
|
+
## Acceptance
|
|
15
|
+
|
|
16
|
+
By using the software, you agree to all of the terms and conditions below.
|
|
17
|
+
|
|
18
|
+
## Copyright License
|
|
19
|
+
|
|
20
|
+
The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations below.
|
|
21
|
+
|
|
22
|
+
## Limitations
|
|
23
|
+
|
|
24
|
+
You may use or modify the software only for your own internal business purposes or for non-commercial or personal use. You may distribute the software or provide it to others only if you do so free of charge for non-commercial purposes. You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensor's trademarks is subject to applicable law.
|
|
25
|
+
|
|
26
|
+
## Patents
|
|
27
|
+
|
|
28
|
+
The licensor grants you a license, under any patent claims the licensor can license, or becomes able to license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case subject to the limitations and conditions in this license. This license does not cover any patent claims that you cause to be infringed by modifications or additions to the software. If you or your company make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
|
|
29
|
+
|
|
30
|
+
## Notices
|
|
31
|
+
|
|
32
|
+
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms. If you modify the software, you must include in any modified copies of the software a prominent notice stating that you have modified the software.
|
|
33
|
+
|
|
34
|
+
## No Other Rights
|
|
35
|
+
|
|
36
|
+
These terms do not imply any licenses other than those expressly granted in these terms.
|
|
37
|
+
|
|
38
|
+
## Termination
|
|
39
|
+
|
|
40
|
+
If you use the software in violation of these terms, such use is not licensed, and your license will automatically terminate. If the licensor provides you with a notice of your violation, and you cease all violation of this license no later than 30 days after you receive that notice, your license will be reinstated retroactively. However, if you violate these terms after such reinstatement, any additional violation of these terms will cause your license to terminate automatically and permanently.
|
|
41
|
+
|
|
42
|
+
## No Liability
|
|
43
|
+
|
|
44
|
+
As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.
|
|
45
|
+
|
|
46
|
+
## Definitions
|
|
47
|
+
|
|
48
|
+
The "licensor" is Nold AI (Owner: Dominikus Nold).
|
|
49
|
+
|
|
50
|
+
The "software" is the SpecFact CLI software the licensor makes available under these terms, including any portion of it.
|
|
51
|
+
|
|
52
|
+
"You" refers to the individual or entity agreeing to these terms.
|
|
53
|
+
|
|
54
|
+
"Your company" is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. Control means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
|
|
55
|
+
|
|
56
|
+
"Your license" is the license granted to you for the software under these terms.
|
|
57
|
+
|
|
58
|
+
"Use" means anything you do with the software requiring your license.
|
|
59
|
+
|
|
60
|
+
"Trademark" means trademarks, service marks, and similar rights.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
Copyright (c) 2025 Nold AI (Owner: Dominikus Nold)
|
|
65
|
+
License-File: LICENSE.md
|
|
66
|
+
Keywords: async,beartype,cli,contract-driven-development,contracts,crosshair,icontract,property-based-testing,quality-gates,spec-first,specfact,state-machine,tdd
|
|
67
|
+
Classifier: Development Status :: 4 - Beta
|
|
68
|
+
Classifier: Intended Audience :: Developers
|
|
69
|
+
Classifier: License :: Other/Proprietary License
|
|
70
|
+
Classifier: Programming Language :: Python :: 3
|
|
71
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
72
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
73
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
74
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
75
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
76
|
+
Classifier: Topic :: Software Development :: Testing
|
|
77
|
+
Requires-Python: >=3.11
|
|
78
|
+
Requires-Dist: beartype>=0.22.4
|
|
79
|
+
Requires-Dist: crosshair-tool>=0.0.97
|
|
80
|
+
Requires-Dist: gitpython>=3.1.45
|
|
81
|
+
Requires-Dist: hypothesis>=6.142.4
|
|
82
|
+
Requires-Dist: icontract>=2.7.1
|
|
83
|
+
Requires-Dist: jinja2>=3.1.6
|
|
84
|
+
Requires-Dist: jsonschema>=4.23.0
|
|
85
|
+
Requires-Dist: networkx>=3.4.2
|
|
86
|
+
Requires-Dist: pydantic>=2.12.3
|
|
87
|
+
Requires-Dist: python-dotenv>=1.2.1
|
|
88
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
89
|
+
Requires-Dist: rich<14.0.0,>=13.0.0
|
|
90
|
+
Requires-Dist: ruamel-yaml>=0.18.16
|
|
91
|
+
Requires-Dist: ruff>=0.14.2
|
|
92
|
+
Requires-Dist: typer>=0.20.0
|
|
93
|
+
Requires-Dist: typing-extensions>=4.15.0
|
|
94
|
+
Provides-Extra: dev
|
|
95
|
+
Requires-Dist: basedpyright>=1.32.1; extra == 'dev'
|
|
96
|
+
Requires-Dist: beartype>=0.22.4; extra == 'dev'
|
|
97
|
+
Requires-Dist: black>=25.9.0; extra == 'dev'
|
|
98
|
+
Requires-Dist: crosshair-tool>=0.0.97; extra == 'dev'
|
|
99
|
+
Requires-Dist: hypothesis>=6.142.4; extra == 'dev'
|
|
100
|
+
Requires-Dist: icontract>=2.7.1; extra == 'dev'
|
|
101
|
+
Requires-Dist: isort>=7.0.0; extra == 'dev'
|
|
102
|
+
Requires-Dist: pip-tools>=7.5.1; extra == 'dev'
|
|
103
|
+
Requires-Dist: pylint>=4.0.2; extra == 'dev'
|
|
104
|
+
Requires-Dist: pytest-asyncio>=1.2.0; extra == 'dev'
|
|
105
|
+
Requires-Dist: pytest-cov>=7.0.0; extra == 'dev'
|
|
106
|
+
Requires-Dist: pytest-mock>=3.15.1; extra == 'dev'
|
|
107
|
+
Requires-Dist: pytest-xdist>=3.8.0; extra == 'dev'
|
|
108
|
+
Requires-Dist: pytest>=8.4.2; extra == 'dev'
|
|
109
|
+
Requires-Dist: ruff>=0.14.2; extra == 'dev'
|
|
110
|
+
Requires-Dist: semgrep>=1.141.1; extra == 'dev'
|
|
111
|
+
Requires-Dist: tomlkit>=0.13.3; extra == 'dev'
|
|
112
|
+
Requires-Dist: types-pyyaml>=6.0.12.20250516; extra == 'dev'
|
|
113
|
+
Provides-Extra: scanning
|
|
114
|
+
Requires-Dist: semgrep>=1.141.1; extra == 'scanning'
|
|
115
|
+
Description-Content-Type: text/markdown
|
|
116
|
+
|
|
117
|
+
# SpecFact CLI
|
|
118
|
+
|
|
119
|
+
> **Stop "vibe coding", start shipping quality code with contracts**
|
|
120
|
+
|
|
121
|
+
[](LICENSE.md)
|
|
122
|
+
[](https://www.python.org/)
|
|
123
|
+
[](https://github.com/nold-ai/specfact-cli)
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## What is SpecFact CLI?
|
|
128
|
+
|
|
129
|
+
A command-line tool that helps you write better code by enforcing **contracts** - rules that catch bugs before they reach production.
|
|
130
|
+
|
|
131
|
+
Think of it as a **quality gate** for your development workflow that:
|
|
132
|
+
|
|
133
|
+
- ✅ Catches async bugs automatically
|
|
134
|
+
- ✅ Validates your code matches your specs
|
|
135
|
+
- ✅ Blocks bad code from merging
|
|
136
|
+
- ✅ Works offline, no cloud required
|
|
137
|
+
|
|
138
|
+
**Perfect for:** Teams who want to ship faster without breaking things.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Quick Start
|
|
143
|
+
|
|
144
|
+
### Install in 10 seconds
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# Zero-install (just run it)
|
|
148
|
+
uvx specfact --help
|
|
149
|
+
|
|
150
|
+
# Or install with pip
|
|
151
|
+
pip install specfact-cli
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Your first command (< 60 seconds)
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# Starting a new project?
|
|
158
|
+
specfact plan init --interactive
|
|
159
|
+
|
|
160
|
+
# Have existing code?
|
|
161
|
+
specfact import from-code --repo . --name my-project
|
|
162
|
+
|
|
163
|
+
# Using GitHub Spec-Kit?
|
|
164
|
+
specfact import from-spec-kit --repo ./my-project --dry-run
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
That's it! 🎉
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## See It In Action
|
|
172
|
+
|
|
173
|
+
We ran SpecFact CLI **on itself** to prove it works:
|
|
174
|
+
|
|
175
|
+
- ⚡ Analyzed 32 Python files → Discovered **32 features** and **81 stories** in **3 seconds**
|
|
176
|
+
- 🚫 Set enforcement to "balanced" → **Blocked 2 HIGH violations** (as configured)
|
|
177
|
+
- 📊 Compared manual vs auto-derived plans → Found **24 deviations** in **5 seconds**
|
|
178
|
+
|
|
179
|
+
**Total time**: < 10 seconds | **Total value**: Found real naming inconsistencies and undocumented features
|
|
180
|
+
|
|
181
|
+
👉 **[Read the complete example](docs/examples/dogfooding-specfact-cli.md)** with actual commands and outputs
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## What Can You Do?
|
|
186
|
+
|
|
187
|
+
### 1. 🔄 Import from GitHub Spec-Kit
|
|
188
|
+
|
|
189
|
+
Already using Spec-Kit? **Level up to automated enforcement** in one command:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
specfact import from-spec-kit --repo ./spec-kit-project --write
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Result**: Your Spec-Kit artifacts become production-ready contracts with automated quality gates.
|
|
196
|
+
|
|
197
|
+
### 2. 🔍 Analyze Your Existing Code
|
|
198
|
+
|
|
199
|
+
Turn brownfield code into a clean spec:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
specfact import from-code --repo . --name my-project
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Result**: Auto-generated plan showing what your code actually does
|
|
206
|
+
|
|
207
|
+
### 3. 📋 Plan New Features
|
|
208
|
+
|
|
209
|
+
Start with a spec, not with code:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
specfact plan init --interactive
|
|
213
|
+
specfact plan add-feature --key FEATURE-001 --title "User Login"
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**Result**: Clear acceptance criteria before writing any code
|
|
217
|
+
|
|
218
|
+
### 4. 🛡️ Enforce Quality
|
|
219
|
+
|
|
220
|
+
Set rules that actually block bad code:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
specfact enforce stage --preset balanced
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Modes:**
|
|
227
|
+
|
|
228
|
+
- `minimal` - Just observe, never block
|
|
229
|
+
- `balanced` - Block critical bugs, warn on others
|
|
230
|
+
- `strict` - Block everything suspicious
|
|
231
|
+
|
|
232
|
+
### 5. ✅ Validate Everything
|
|
233
|
+
|
|
234
|
+
One command to check it all:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
specfact repro
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Checks:** Contracts, types, async patterns, state machines
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Documentation
|
|
245
|
+
|
|
246
|
+
For complete documentation, see **[docs/README.md](docs/README.md)**.
|
|
247
|
+
|
|
248
|
+
**Quick Links:**
|
|
249
|
+
|
|
250
|
+
- 📖 **[Getting Started](docs/getting-started/README.md)** - Installation and first steps
|
|
251
|
+
- 🎯 **[The Journey: From Spec-Kit to SpecFact](docs/guides/speckit-journey.md)** - Level up from interactive authoring to automated enforcement
|
|
252
|
+
- 📋 **[Command Reference](docs/reference/commands.md)** - All commands with examples
|
|
253
|
+
- 🤖 **[IDE Integration](docs/guides/ide-integration.md)** - Set up slash commands in your IDE
|
|
254
|
+
- 💡 **[Use Cases](docs/guides/use-cases.md)** - Real-world scenarios
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
## Installation Options
|
|
259
|
+
|
|
260
|
+
### 1. uvx (Easiest)
|
|
261
|
+
|
|
262
|
+
No installation needed:
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
uvx specfact plan init
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### 2. pip
|
|
269
|
+
|
|
270
|
+
Install globally:
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
pip install specfact-cli
|
|
274
|
+
specfact --help
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### 3. Docker
|
|
278
|
+
|
|
279
|
+
Run in a container:
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
docker run ghcr.io/nold-ai/specfact-cli:latest --help
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Contributing
|
|
288
|
+
|
|
289
|
+
We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
git clone https://github.com/nold-ai/specfact-cli.git
|
|
293
|
+
cd specfact-cli
|
|
294
|
+
pip install -e ".[dev]"
|
|
295
|
+
hatch run contract-test-full
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## License
|
|
301
|
+
|
|
302
|
+
**Sustainable Use License** - Free for internal business use
|
|
303
|
+
|
|
304
|
+
### ✅ You Can
|
|
305
|
+
|
|
306
|
+
- Use it for your business (internal tools, automation)
|
|
307
|
+
- Modify it for your own needs
|
|
308
|
+
- Provide consulting services using SpecFact CLI
|
|
309
|
+
|
|
310
|
+
### ❌ You Cannot
|
|
311
|
+
|
|
312
|
+
- Sell it as a SaaS product
|
|
313
|
+
- White-label and resell
|
|
314
|
+
- Create competing products
|
|
315
|
+
|
|
316
|
+
For commercial licensing, contact [hello@noldai.com](mailto:hello@noldai.com)
|
|
317
|
+
|
|
318
|
+
**Full license**: [LICENSE.md](LICENSE.md) | **FAQ**: [USAGE-FAQ.md](USAGE-FAQ.md)
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Support
|
|
323
|
+
|
|
324
|
+
- 💬 **Questions?** [GitHub Discussions](https://github.com/nold-ai/specfact-cli/discussions)
|
|
325
|
+
- 🐛 **Found a bug?** [GitHub Issues](https://github.com/nold-ai/specfact-cli/issues)
|
|
326
|
+
- 📧 **Need help?** [hello@noldai.com](mailto:hello@noldai.com)
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
> **Built with ❤️ by [NOLD AI](https://noldai.com)**
|
|
331
|
+
|
|
332
|
+
Copyright © 2025 Nold AI (Owner: Dominikus Nold)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
specfact_cli/__init__.py,sha256=9wQNEw1pcLfCzBf1cKZsQQmT6uEnhL0xN-vp9u2OZS4,338
|
|
2
|
+
specfact_cli/cli.py,sha256=52Qr_YyTFCvaeo6tjowFrPIHB1FdZEVE9k3hW7c6Jv8,14624
|
|
3
|
+
specfact_cli/agents/__init__.py,sha256=Iu5QfKJhenQpTrUWizSy5MrSIU6MBMh3tVbuMmLSfw4,661
|
|
4
|
+
specfact_cli/agents/analyze_agent.py,sha256=Rywe5zWBO07efD0Ss5TlFYOhziQnarJqhPSZ3EBABTg,15617
|
|
5
|
+
specfact_cli/agents/base.py,sha256=fFS5R3_7U3hHvlTbXy1cren8Jx_p2ySEgjtY4tj5Jyc,3169
|
|
6
|
+
specfact_cli/agents/plan_agent.py,sha256=S1FdSAzLCTvZEVkASFKAONM6xskQc_HxNWJJQhqzfY8,6856
|
|
7
|
+
specfact_cli/agents/registry.py,sha256=kc7417QydGU9lhFEAKMSpoWwJsuYHFj1Q8cAYN4RItM,5161
|
|
8
|
+
specfact_cli/agents/sync_agent.py,sha256=AWp0k5AGaaKJvhpQ7rss3vCxG78hYRgskNU1LBfNABo,4351
|
|
9
|
+
specfact_cli/analyzers/__init__.py,sha256=qD11XL3t5jKPWasZZUdCxE4X7eQorG_7QutDGd2qr5E,266
|
|
10
|
+
specfact_cli/analyzers/code_analyzer.py,sha256=inKkLEoHFk-w6nQbKjhOHhkfc3QDwzC05DoRWHQxwbc,30723
|
|
11
|
+
specfact_cli/commands/__init__.py,sha256=Hm0ddN9c3UUvXEH1hCj7lYpZEY7NS-8vnKCC0XEngVc,109
|
|
12
|
+
specfact_cli/commands/enforce.py,sha256=A_tKZKaupr_hBdr8m4II-i9wfFnfuURUz3hhoRctOpo,2817
|
|
13
|
+
specfact_cli/commands/import_cmd.py,sha256=BMw6zhgu6OZ-V6qnfTjyBkEtUq0rcD0-lPfycQdIaPk,13867
|
|
14
|
+
specfact_cli/commands/init.py,sha256=OuRgZ9QFcB_mjMqXCeWuVlWYZo2dKNAcQ2smGwVnQUM,4565
|
|
15
|
+
specfact_cli/commands/plan.py,sha256=90xuVZmZ9TrG-icRxdd2eMZfgQEY8DFU3F-5SOs6jR0,41089
|
|
16
|
+
specfact_cli/commands/repro.py,sha256=U1v6gF-ks64lVboPYnbiTEaydXlQFpkuQc9f0cKeM2c,5807
|
|
17
|
+
specfact_cli/commands/sync.py,sha256=7IVabzsYZ06-_7AbvEbUc9BsawWggmpjQ8nP7OLAid0,17190
|
|
18
|
+
specfact_cli/common/__init__.py,sha256=OrOXNw5juhUiQ4XpAw_uw18xFX3ODq49JclQWqyWB7w,777
|
|
19
|
+
specfact_cli/common/logger_setup.py,sha256=rO0x43Gg4pIzdq6x1g4Dawz4CF-3Zl33o4zuSVN3I8Y,26825
|
|
20
|
+
specfact_cli/common/logging_utils.py,sha256=wSDCasch5b4F7B5hRYd3oeWYzmz738eTX-BRP7WD8ko,1549
|
|
21
|
+
specfact_cli/common/text_utils.py,sha256=g9uNKyNeZAI54oPraMJH3KJcAIICpq66dNt2xtYXLfQ,1968
|
|
22
|
+
specfact_cli/common/utils.py,sha256=dB-4_-nqo6sY2-HyeyARDcpoMODA5pVKdIONxbd6PxI,1622
|
|
23
|
+
specfact_cli/comparators/__init__.py,sha256=CIB1FT0OqGqIP-6WPcrpLANdaGb3bFZ6rPNEJdosaao,279
|
|
24
|
+
specfact_cli/comparators/plan_comparator.py,sha256=4Qtuxj6CVqyjegzv8WLvKfZmaQx_HY_C_ym73m70xhc,17496
|
|
25
|
+
specfact_cli/generators/__init__.py,sha256=bYNoCmyaQegcaNSwFT3DAT_e6epqNZHzglrSSICUTEo,460
|
|
26
|
+
specfact_cli/generators/plan_generator.py,sha256=gjbYEQY5UFc71tXwl56KJSq1p_CkgmArbagCIellokQ,3878
|
|
27
|
+
specfact_cli/generators/protocol_generator.py,sha256=yOSmogp-bUwJ45AhqfKzAbKiJ9VzQsBnXlS8FloTbYo,4343
|
|
28
|
+
specfact_cli/generators/report_generator.py,sha256=ziS2J7I14LDl8HgscoZc7d2I1DFd92zQ-Z71kzReTZs,8098
|
|
29
|
+
specfact_cli/generators/workflow_generator.py,sha256=LUaJzDW1-ND83K9dfE3yHxrH3_R1bwvUhL7f8wzycmw,4237
|
|
30
|
+
specfact_cli/importers/__init__.py,sha256=ZmKsoLYCZwIpQUgssnPc99S0tEKLQ8BSXZDoqPcqaAQ,255
|
|
31
|
+
specfact_cli/importers/speckit_converter.py,sha256=H4QVnOyAQ2hrgLv-a-jHy7KmzoNeH4S7mxxr_TsfR9k,32098
|
|
32
|
+
specfact_cli/importers/speckit_scanner.py,sha256=xSy8xmHtgvEKndCc5nNBRNfJwvnfDG3jOjBUFmjczGo,31205
|
|
33
|
+
specfact_cli/models/__init__.py,sha256=C3AITr0RWMBTCC8sEKFyG6hIE-8SCH3xA5PP4l_gXyA,891
|
|
34
|
+
specfact_cli/models/deviation.py,sha256=C3JRu1CZqv1UIeMWhT2Rpk5xM8MW4RUGsKcd0AsE34w,3826
|
|
35
|
+
specfact_cli/models/enforcement.py,sha256=MFsxoleu9n2U1I7ng6GCIxkyj0M0gJ1v3dFi94sljDo,5720
|
|
36
|
+
specfact_cli/models/plan.py,sha256=Fr_w49R6zM-E7rsEke1uMj3amwF_luJbm_Xk9MFi7V0,4413
|
|
37
|
+
specfact_cli/models/protocol.py,sha256=s9SpUIH9qf0W0Io_wWEYjERTdf1VOowq6rj20I3p9To,900
|
|
38
|
+
specfact_cli/modes/__init__.py,sha256=4SoF2nFBXQscZiQx7WtxN3d7J1W0yCSVGmkPZ8DZRNk,445
|
|
39
|
+
specfact_cli/modes/detector.py,sha256=qPs_KvlCXMQCnWP0vO6GGnmbgNFrrewYWlx5ffN9JJ4,3468
|
|
40
|
+
specfact_cli/modes/router.py,sha256=U9g4YhntRx7Wg6e59K1uMQt682YzzHdUeNHqEIfIUFU,5160
|
|
41
|
+
specfact_cli/sync/__init__.py,sha256=qd5KiaETOTzcHE9iUHkm11YfEUXTm4VeY1iwnnJEYzI,396
|
|
42
|
+
specfact_cli/sync/repository_sync.py,sha256=4jq0uUoWuHqFNd6g1OkVCUdTJuK9-WcsV8c8k2qFQkk,10007
|
|
43
|
+
specfact_cli/sync/speckit_sync.py,sha256=l_V7rYe7aLG6v3DPOJhPcc_1vx-jLqXAYsKZNLMbOzs,13612
|
|
44
|
+
specfact_cli/utils/__init__.py,sha256=7r71WkiTVVloVNhMi6SdBWkWJ5pytYir2-Hh_FH-M7s,1357
|
|
45
|
+
specfact_cli/utils/console.py,sha256=7ifgATHPGWEqzlvBkHIre9mbMjSaNX7KFPFs9_8W3J0,2254
|
|
46
|
+
specfact_cli/utils/feature_keys.py,sha256=Co2A6gFdhaYZhNOGYGKbHzLn6Rp5X-ywT5GuWqwHfxY,6651
|
|
47
|
+
specfact_cli/utils/git.py,sha256=qHmW50OaXccPCeCthMJZODHx5LibIJ1MuOOt95QS8Ao,7538
|
|
48
|
+
specfact_cli/utils/ide_setup.py,sha256=fjYiumkzpgy9ayc6OKhjgz4fbgg2p-qjyh7DDw9NQrM,12364
|
|
49
|
+
specfact_cli/utils/prompts.py,sha256=fbBrp8DhZFIGtX-puPbd05PeuyYwkMxh-dN_yMTVx1k,5761
|
|
50
|
+
specfact_cli/utils/structure.py,sha256=bbl-I2ozYYqRFuoGNMp-3gf6BIsquksF_Mlo11ky9Tw,18398
|
|
51
|
+
specfact_cli/utils/yaml_utils.py,sha256=xK2uvCVUssaHnB4BLYq9vJUarSuIIxANftlq8yrltkA,5719
|
|
52
|
+
specfact_cli/validators/__init__.py,sha256=L8AmArgcT0_vGUnFez40SWOtr0SN4qvGmzDZ5N8ZrW4,499
|
|
53
|
+
specfact_cli/validators/fsm.py,sha256=wwDAugwuBPaNRNB-g9-Y6Zwc2MwndpXdrPdgaRYVUx4,9995
|
|
54
|
+
specfact_cli/validators/repro_checker.py,sha256=YphkDju82um0JZRsGoO6gPVc0kKRzD3Py93K1YHjhuU,10713
|
|
55
|
+
specfact_cli/validators/schema.py,sha256=hLDcTE6lnNBbni1UBQdluvDLZNSxX7Ek7dhXvIvAXZc,6885
|
|
56
|
+
specfact_cli-0.4.0.dist-info/METADATA,sha256=CnibY3boIOHjR1v_UNsKELxt0hR2QyV5au54C3XF4Ws,12026
|
|
57
|
+
specfact_cli-0.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
58
|
+
specfact_cli-0.4.0.dist-info/entry_points.txt,sha256=NvpypgoclYhHooSFA3rOeoqoyo9hkM547yMbujJbjOk,55
|
|
59
|
+
specfact_cli-0.4.0.dist-info/licenses/LICENSE.md,sha256=MTjC0xPZjRB_MQt-_FD826DwppdV8uW4qFTm9t6BgnM,3669
|
|
60
|
+
specfact_cli-0.4.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Sustainable Use License
|
|
2
|
+
|
|
3
|
+
Version 1.0
|
|
4
|
+
|
|
5
|
+
## Acceptance
|
|
6
|
+
|
|
7
|
+
By using the software, you agree to all of the terms and conditions below.
|
|
8
|
+
|
|
9
|
+
## Copyright License
|
|
10
|
+
|
|
11
|
+
The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations below.
|
|
12
|
+
|
|
13
|
+
## Limitations
|
|
14
|
+
|
|
15
|
+
You may use or modify the software only for your own internal business purposes or for non-commercial or personal use. You may distribute the software or provide it to others only if you do so free of charge for non-commercial purposes. You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensor's trademarks is subject to applicable law.
|
|
16
|
+
|
|
17
|
+
## Patents
|
|
18
|
+
|
|
19
|
+
The licensor grants you a license, under any patent claims the licensor can license, or becomes able to license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case subject to the limitations and conditions in this license. This license does not cover any patent claims that you cause to be infringed by modifications or additions to the software. If you or your company make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
|
|
20
|
+
|
|
21
|
+
## Notices
|
|
22
|
+
|
|
23
|
+
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms. If you modify the software, you must include in any modified copies of the software a prominent notice stating that you have modified the software.
|
|
24
|
+
|
|
25
|
+
## No Other Rights
|
|
26
|
+
|
|
27
|
+
These terms do not imply any licenses other than those expressly granted in these terms.
|
|
28
|
+
|
|
29
|
+
## Termination
|
|
30
|
+
|
|
31
|
+
If you use the software in violation of these terms, such use is not licensed, and your license will automatically terminate. If the licensor provides you with a notice of your violation, and you cease all violation of this license no later than 30 days after you receive that notice, your license will be reinstated retroactively. However, if you violate these terms after such reinstatement, any additional violation of these terms will cause your license to terminate automatically and permanently.
|
|
32
|
+
|
|
33
|
+
## No Liability
|
|
34
|
+
|
|
35
|
+
As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.
|
|
36
|
+
|
|
37
|
+
## Definitions
|
|
38
|
+
|
|
39
|
+
The "licensor" is Nold AI (Owner: Dominikus Nold).
|
|
40
|
+
|
|
41
|
+
The "software" is the SpecFact CLI software the licensor makes available under these terms, including any portion of it.
|
|
42
|
+
|
|
43
|
+
"You" refers to the individual or entity agreeing to these terms.
|
|
44
|
+
|
|
45
|
+
"Your company" is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. Control means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
|
|
46
|
+
|
|
47
|
+
"Your license" is the license granted to you for the software under these terms.
|
|
48
|
+
|
|
49
|
+
"Use" means anything you do with the software requiring your license.
|
|
50
|
+
|
|
51
|
+
"Trademark" means trademarks, service marks, and similar rights.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
Copyright (c) 2025 Nold AI (Owner: Dominikus Nold)
|