specfact-cli 0.4.2__py3-none-any.whl → 0.6.8__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.
- specfact_cli/__init__.py +1 -1
- specfact_cli/agents/analyze_agent.py +2 -3
- specfact_cli/analyzers/__init__.py +2 -1
- specfact_cli/analyzers/ambiguity_scanner.py +601 -0
- specfact_cli/analyzers/code_analyzer.py +462 -30
- specfact_cli/analyzers/constitution_evidence_extractor.py +491 -0
- specfact_cli/analyzers/contract_extractor.py +419 -0
- specfact_cli/analyzers/control_flow_analyzer.py +281 -0
- specfact_cli/analyzers/requirement_extractor.py +337 -0
- specfact_cli/analyzers/test_pattern_extractor.py +330 -0
- specfact_cli/cli.py +151 -206
- specfact_cli/commands/constitution.py +281 -0
- specfact_cli/commands/enforce.py +42 -34
- specfact_cli/commands/import_cmd.py +481 -152
- specfact_cli/commands/init.py +224 -55
- specfact_cli/commands/plan.py +2133 -547
- specfact_cli/commands/repro.py +100 -78
- specfact_cli/commands/sync.py +701 -186
- specfact_cli/enrichers/constitution_enricher.py +765 -0
- specfact_cli/enrichers/plan_enricher.py +294 -0
- specfact_cli/importers/speckit_converter.py +364 -48
- specfact_cli/importers/speckit_scanner.py +65 -0
- specfact_cli/models/plan.py +42 -0
- specfact_cli/resources/mappings/node-async.yaml +49 -0
- specfact_cli/resources/mappings/python-async.yaml +47 -0
- specfact_cli/resources/mappings/speckit-default.yaml +82 -0
- specfact_cli/resources/prompts/specfact-enforce.md +185 -0
- specfact_cli/resources/prompts/specfact-import-from-code.md +626 -0
- specfact_cli/resources/prompts/specfact-plan-add-feature.md +188 -0
- specfact_cli/resources/prompts/specfact-plan-add-story.md +212 -0
- specfact_cli/resources/prompts/specfact-plan-compare.md +571 -0
- specfact_cli/resources/prompts/specfact-plan-init.md +531 -0
- specfact_cli/resources/prompts/specfact-plan-promote.md +352 -0
- specfact_cli/resources/prompts/specfact-plan-review.md +1276 -0
- specfact_cli/resources/prompts/specfact-plan-select.md +401 -0
- specfact_cli/resources/prompts/specfact-plan-update-feature.md +242 -0
- specfact_cli/resources/prompts/specfact-plan-update-idea.md +211 -0
- specfact_cli/resources/prompts/specfact-repro.md +268 -0
- specfact_cli/resources/prompts/specfact-sync.md +497 -0
- specfact_cli/resources/schemas/deviation.schema.json +61 -0
- specfact_cli/resources/schemas/plan.schema.json +204 -0
- specfact_cli/resources/schemas/protocol.schema.json +53 -0
- specfact_cli/resources/templates/github-action.yml.j2 +140 -0
- specfact_cli/resources/templates/plan.bundle.yaml.j2 +141 -0
- specfact_cli/resources/templates/pr-template.md.j2 +58 -0
- specfact_cli/resources/templates/protocol.yaml.j2 +24 -0
- specfact_cli/resources/templates/telemetry.yaml.example +35 -0
- specfact_cli/sync/__init__.py +10 -1
- specfact_cli/sync/watcher.py +268 -0
- specfact_cli/telemetry.py +440 -0
- specfact_cli/utils/acceptance_criteria.py +127 -0
- specfact_cli/utils/enrichment_parser.py +445 -0
- specfact_cli/utils/feature_keys.py +12 -3
- specfact_cli/utils/ide_setup.py +170 -0
- specfact_cli/utils/structure.py +179 -2
- specfact_cli/utils/yaml_utils.py +33 -0
- specfact_cli/validators/repro_checker.py +22 -1
- specfact_cli/validators/schema.py +15 -4
- specfact_cli-0.6.8.dist-info/METADATA +456 -0
- specfact_cli-0.6.8.dist-info/RECORD +99 -0
- {specfact_cli-0.4.2.dist-info → specfact_cli-0.6.8.dist-info}/entry_points.txt +1 -0
- specfact_cli-0.6.8.dist-info/licenses/LICENSE.md +202 -0
- specfact_cli-0.4.2.dist-info/METADATA +0 -370
- specfact_cli-0.4.2.dist-info/RECORD +0 -62
- specfact_cli-0.4.2.dist-info/licenses/LICENSE.md +0 -61
- {specfact_cli-0.4.2.dist-info → specfact_cli-0.6.8.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "Plan Bundle Schema",
|
|
4
|
+
"description": "Schema for SpecFact CLI plan bundle validation",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["version", "product"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"version": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"pattern": "^\\d+\\.\\d+$",
|
|
11
|
+
"description": "Plan bundle version"
|
|
12
|
+
},
|
|
13
|
+
"idea": {
|
|
14
|
+
"type": "object",
|
|
15
|
+
"required": ["title", "narrative"],
|
|
16
|
+
"properties": {
|
|
17
|
+
"title": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"minLength": 1
|
|
20
|
+
},
|
|
21
|
+
"narrative": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"minLength": 1
|
|
24
|
+
},
|
|
25
|
+
"target_users": {
|
|
26
|
+
"type": "array",
|
|
27
|
+
"items": {
|
|
28
|
+
"type": "string"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"value_hypothesis": {
|
|
32
|
+
"type": "string"
|
|
33
|
+
},
|
|
34
|
+
"constraints": {
|
|
35
|
+
"type": "array",
|
|
36
|
+
"items": {
|
|
37
|
+
"type": "string"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"metrics": {
|
|
41
|
+
"type": "object"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"business": {
|
|
46
|
+
"type": "object",
|
|
47
|
+
"properties": {
|
|
48
|
+
"segments": {
|
|
49
|
+
"type": "array",
|
|
50
|
+
"items": {
|
|
51
|
+
"type": "string"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"problems": {
|
|
55
|
+
"type": "array",
|
|
56
|
+
"items": {
|
|
57
|
+
"type": "string"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"solutions": {
|
|
61
|
+
"type": "array",
|
|
62
|
+
"items": {
|
|
63
|
+
"type": "string"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"differentiation": {
|
|
67
|
+
"type": "array",
|
|
68
|
+
"items": {
|
|
69
|
+
"type": "string"
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"risks": {
|
|
73
|
+
"type": "array",
|
|
74
|
+
"items": {
|
|
75
|
+
"type": "string"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"product": {
|
|
81
|
+
"type": "object",
|
|
82
|
+
"required": ["themes"],
|
|
83
|
+
"properties": {
|
|
84
|
+
"themes": {
|
|
85
|
+
"type": "array",
|
|
86
|
+
"items": {
|
|
87
|
+
"type": "string"
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"releases": {
|
|
91
|
+
"type": "array",
|
|
92
|
+
"items": {
|
|
93
|
+
"type": "object",
|
|
94
|
+
"required": ["name"],
|
|
95
|
+
"properties": {
|
|
96
|
+
"name": {
|
|
97
|
+
"type": "string"
|
|
98
|
+
},
|
|
99
|
+
"objectives": {
|
|
100
|
+
"type": "array",
|
|
101
|
+
"items": {
|
|
102
|
+
"type": "string"
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
"scope": {
|
|
106
|
+
"type": "array",
|
|
107
|
+
"items": {
|
|
108
|
+
"type": "string"
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"risks": {
|
|
112
|
+
"type": "array",
|
|
113
|
+
"items": {
|
|
114
|
+
"type": "string"
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"features": {
|
|
123
|
+
"type": "array",
|
|
124
|
+
"items": {
|
|
125
|
+
"type": "object",
|
|
126
|
+
"required": ["key", "title"],
|
|
127
|
+
"properties": {
|
|
128
|
+
"key": {
|
|
129
|
+
"type": "string",
|
|
130
|
+
"pattern": "^FEATURE-\\d+$"
|
|
131
|
+
},
|
|
132
|
+
"title": {
|
|
133
|
+
"type": "string",
|
|
134
|
+
"minLength": 1
|
|
135
|
+
},
|
|
136
|
+
"outcomes": {
|
|
137
|
+
"type": "array",
|
|
138
|
+
"items": {
|
|
139
|
+
"type": "string"
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
"acceptance": {
|
|
143
|
+
"type": "array",
|
|
144
|
+
"items": {
|
|
145
|
+
"type": "string"
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
"constraints": {
|
|
149
|
+
"type": "array",
|
|
150
|
+
"items": {
|
|
151
|
+
"type": "string"
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
"stories": {
|
|
155
|
+
"type": "array",
|
|
156
|
+
"items": {
|
|
157
|
+
"type": "object",
|
|
158
|
+
"required": ["key", "title"],
|
|
159
|
+
"properties": {
|
|
160
|
+
"key": {
|
|
161
|
+
"type": "string",
|
|
162
|
+
"pattern": "^STORY-\\d+$"
|
|
163
|
+
},
|
|
164
|
+
"title": {
|
|
165
|
+
"type": "string",
|
|
166
|
+
"minLength": 1
|
|
167
|
+
},
|
|
168
|
+
"acceptance": {
|
|
169
|
+
"type": "array",
|
|
170
|
+
"items": {
|
|
171
|
+
"type": "string"
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
"tags": {
|
|
175
|
+
"type": "array",
|
|
176
|
+
"items": {
|
|
177
|
+
"type": "string"
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
"confidence": {
|
|
181
|
+
"type": "number",
|
|
182
|
+
"minimum": 0.0,
|
|
183
|
+
"maximum": 1.0
|
|
184
|
+
},
|
|
185
|
+
"draft": {
|
|
186
|
+
"type": "boolean"
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
"confidence": {
|
|
192
|
+
"type": "number",
|
|
193
|
+
"minimum": 0.0,
|
|
194
|
+
"maximum": 1.0
|
|
195
|
+
},
|
|
196
|
+
"draft": {
|
|
197
|
+
"type": "boolean"
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "Protocol Schema",
|
|
4
|
+
"description": "Schema for SpecFact CLI FSM protocol validation",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["states", "start", "transitions"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"states": {
|
|
9
|
+
"type": "array",
|
|
10
|
+
"items": {
|
|
11
|
+
"type": "string"
|
|
12
|
+
},
|
|
13
|
+
"minItems": 1,
|
|
14
|
+
"uniqueItems": true,
|
|
15
|
+
"description": "List of state names"
|
|
16
|
+
},
|
|
17
|
+
"start": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "Initial state name"
|
|
20
|
+
},
|
|
21
|
+
"transitions": {
|
|
22
|
+
"type": "array",
|
|
23
|
+
"items": {
|
|
24
|
+
"type": "object",
|
|
25
|
+
"required": ["from_state", "on_event", "to_state"],
|
|
26
|
+
"properties": {
|
|
27
|
+
"from_state": {
|
|
28
|
+
"type": "string"
|
|
29
|
+
},
|
|
30
|
+
"on_event": {
|
|
31
|
+
"type": "string"
|
|
32
|
+
},
|
|
33
|
+
"to_state": {
|
|
34
|
+
"type": "string"
|
|
35
|
+
},
|
|
36
|
+
"guard": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"description": "Guard function name"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"description": "List of state transitions"
|
|
43
|
+
},
|
|
44
|
+
"guards": {
|
|
45
|
+
"type": "object",
|
|
46
|
+
"additionalProperties": {
|
|
47
|
+
"type": "string"
|
|
48
|
+
},
|
|
49
|
+
"description": "Guard definitions"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
|
|
2
|
+
# yamllint disable rule:line-length rule:truthy
|
|
3
|
+
name: SpecFact CLI Validation
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main, dev]
|
|
8
|
+
paths-ignore:
|
|
9
|
+
- "docs/**"
|
|
10
|
+
- "**.md"
|
|
11
|
+
- "**.mdc"
|
|
12
|
+
push:
|
|
13
|
+
branches: [main, dev]
|
|
14
|
+
paths-ignore:
|
|
15
|
+
- "docs/**"
|
|
16
|
+
- "**.md"
|
|
17
|
+
- "**.mdc"
|
|
18
|
+
workflow_dispatch:
|
|
19
|
+
inputs:
|
|
20
|
+
budget:
|
|
21
|
+
description: "Time budget in seconds"
|
|
22
|
+
required: false
|
|
23
|
+
default: "{{ budget }}"
|
|
24
|
+
type: string
|
|
25
|
+
mode:
|
|
26
|
+
description: "Enforcement mode (block, warn, log)"
|
|
27
|
+
required: false
|
|
28
|
+
default: "block"
|
|
29
|
+
type: choice
|
|
30
|
+
options:
|
|
31
|
+
- block
|
|
32
|
+
- warn
|
|
33
|
+
- log
|
|
34
|
+
|
|
35
|
+
jobs:
|
|
36
|
+
specfact-validation:
|
|
37
|
+
name: Contract Validation
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
permissions:
|
|
40
|
+
contents: read
|
|
41
|
+
pull-requests: write
|
|
42
|
+
checks: write
|
|
43
|
+
steps:
|
|
44
|
+
- name: Checkout
|
|
45
|
+
uses: actions/checkout@v4
|
|
46
|
+
|
|
47
|
+
- name: Set up Python
|
|
48
|
+
uses: actions/setup-python@v5
|
|
49
|
+
with:
|
|
50
|
+
python-version: "{{ python_version }}"
|
|
51
|
+
cache: "pip"
|
|
52
|
+
|
|
53
|
+
- name: Install dependencies
|
|
54
|
+
run: |
|
|
55
|
+
python -m pip install --upgrade pip
|
|
56
|
+
pip install hatch
|
|
57
|
+
|
|
58
|
+
- name: Install SpecFact CLI
|
|
59
|
+
run: |
|
|
60
|
+
echo "📦 Installing SpecFact CLI..."
|
|
61
|
+
pip install specfact-cli
|
|
62
|
+
|
|
63
|
+
- name: Set validation parameters
|
|
64
|
+
id: validation
|
|
65
|
+
run: |
|
|
66
|
+
BUDGET="${INPUT_BUDGET:-{{ budget }}}"
|
|
67
|
+
MODE="${INPUT_MODE:-block}"
|
|
68
|
+
echo "budget=$BUDGET" >> $GITHUB_OUTPUT
|
|
69
|
+
echo "mode=$MODE" >> $GITHUB_OUTPUT
|
|
70
|
+
echo "SPECFACT_BUDGET=$BUDGET" >> $GITHUB_ENV
|
|
71
|
+
echo "SPECFACT_MODE=$MODE" >> $GITHUB_ENV
|
|
72
|
+
|
|
73
|
+
- name: Run Contract Validation
|
|
74
|
+
id: repro
|
|
75
|
+
continue-on-error: true
|
|
76
|
+
run: |
|
|
77
|
+
specfact repro --verbose --budget {% raw %}${{ steps.validation.outputs.budget }}{% endraw %} || true
|
|
78
|
+
echo "exit_code=$?" >> $GITHUB_OUTPUT
|
|
79
|
+
|
|
80
|
+
- name: Find latest repro report
|
|
81
|
+
id: report
|
|
82
|
+
if: always()
|
|
83
|
+
run: |
|
|
84
|
+
REPORT_DIR=".specfact/reports/enforcement"
|
|
85
|
+
if [ -d "$REPORT_DIR" ]; then
|
|
86
|
+
LATEST_REPORT=$(find "$REPORT_DIR" -name "report-*.yaml" -type f -printf "%T@ %p\n" | sort -n | tail -1 | cut -d' ' -f2-)
|
|
87
|
+
if [ -n "$LATEST_REPORT" ]; then
|
|
88
|
+
echo "path=$LATEST_REPORT" >> $GITHUB_OUTPUT
|
|
89
|
+
echo "SPECFACT_REPORT_PATH=$LATEST_REPORT" >> $GITHUB_ENV
|
|
90
|
+
fi
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
- name: Create GitHub annotations
|
|
94
|
+
id: annotations
|
|
95
|
+
if: always() && {% raw %}steps.report.outputs.path != ''{% endraw %}
|
|
96
|
+
run: |
|
|
97
|
+
python -m specfact_cli.utils.github_annotations || true
|
|
98
|
+
|
|
99
|
+
- name: Generate PR comment
|
|
100
|
+
id: pr-comment
|
|
101
|
+
if: always() && {% raw %}github.event_name == 'pull_request' && steps.report.outputs.path != ''{% endraw %}
|
|
102
|
+
run: |
|
|
103
|
+
python -m specfact_cli.utils.github_annotations
|
|
104
|
+
if [ -f ".specfact/pr-comment.md" ]; then
|
|
105
|
+
echo "comment_path=.specfact/pr-comment.md" >> $GITHUB_OUTPUT
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
- name: Post PR comment
|
|
109
|
+
if: always() && {% raw %}github.event_name == 'pull_request' && steps.pr-comment.outputs.comment_path != ''{% endraw %}
|
|
110
|
+
uses: actions/github-script@v7
|
|
111
|
+
with:
|
|
112
|
+
script: |
|
|
113
|
+
const fs = require('fs');
|
|
114
|
+
const commentPath = '{% raw %}${{ steps.pr-comment.outputs.comment_path }}{% endraw %}';
|
|
115
|
+
if (fs.existsSync(commentPath)) {
|
|
116
|
+
const comment = fs.readFileSync(commentPath, 'utf8');
|
|
117
|
+
github.rest.issues.createComment({
|
|
118
|
+
issue_number: context.issue.number,
|
|
119
|
+
owner: context.repo.owner,
|
|
120
|
+
repo: context.repo.repo,
|
|
121
|
+
body: comment
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
- name: Upload validation report
|
|
126
|
+
if: always()
|
|
127
|
+
uses: actions/upload-artifact@v4
|
|
128
|
+
with:
|
|
129
|
+
name: specfact-report
|
|
130
|
+
path: |
|
|
131
|
+
.specfact/reports/enforcement/*.yaml
|
|
132
|
+
.specfact/pr-comment.md
|
|
133
|
+
if-no-files-found: ignore
|
|
134
|
+
|
|
135
|
+
- name: Fail workflow if validation failed
|
|
136
|
+
if: {% raw %}steps.repro.outputs.exit_code != '0' && steps.validation.outputs.mode == 'block'{% endraw %}
|
|
137
|
+
run: |
|
|
138
|
+
echo "❌ Validation failed. Exiting with error code."
|
|
139
|
+
exit 1
|
|
140
|
+
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
version: "1.0"
|
|
2
|
+
|
|
3
|
+
{% if idea %}
|
|
4
|
+
idea:
|
|
5
|
+
title: {{ idea.title }}
|
|
6
|
+
narrative: {{ idea.narrative }}
|
|
7
|
+
{% if idea.target_users %}
|
|
8
|
+
target_users:
|
|
9
|
+
{% for user in idea.target_users %}
|
|
10
|
+
- {{ user }}
|
|
11
|
+
{% endfor %}
|
|
12
|
+
{% endif %}
|
|
13
|
+
{% if idea.value_hypothesis %}
|
|
14
|
+
value_hypothesis: {{ idea.value_hypothesis }}
|
|
15
|
+
{% endif %}
|
|
16
|
+
{% if idea.constraints %}
|
|
17
|
+
constraints:
|
|
18
|
+
{% for constraint in idea.constraints %}
|
|
19
|
+
- {{ constraint }}
|
|
20
|
+
{% endfor %}
|
|
21
|
+
{% endif %}
|
|
22
|
+
{% if idea.metrics %}
|
|
23
|
+
metrics: {{ idea.metrics | tojson }}
|
|
24
|
+
{% endif %}
|
|
25
|
+
{% endif %}
|
|
26
|
+
|
|
27
|
+
{% if business %}
|
|
28
|
+
business:
|
|
29
|
+
{% if business.segments %}
|
|
30
|
+
segments:
|
|
31
|
+
{% for segment in business.segments %}
|
|
32
|
+
- {{ segment }}
|
|
33
|
+
{% endfor %}
|
|
34
|
+
{% endif %}
|
|
35
|
+
{% if business.problems %}
|
|
36
|
+
problems:
|
|
37
|
+
{% for problem in business.problems %}
|
|
38
|
+
- {{ problem }}
|
|
39
|
+
{% endfor %}
|
|
40
|
+
{% endif %}
|
|
41
|
+
{% if business.solutions %}
|
|
42
|
+
solutions:
|
|
43
|
+
{% for solution in business.solutions %}
|
|
44
|
+
- {{ solution }}
|
|
45
|
+
{% endfor %}
|
|
46
|
+
{% endif %}
|
|
47
|
+
{% if business.differentiation %}
|
|
48
|
+
differentiation:
|
|
49
|
+
{% for diff in business.differentiation %}
|
|
50
|
+
- {{ diff }}
|
|
51
|
+
{% endfor %}
|
|
52
|
+
{% endif %}
|
|
53
|
+
{% if business.risks %}
|
|
54
|
+
risks:
|
|
55
|
+
{% for risk in business.risks %}
|
|
56
|
+
- {{ risk }}
|
|
57
|
+
{% endfor %}
|
|
58
|
+
{% endif %}
|
|
59
|
+
{% endif %}
|
|
60
|
+
|
|
61
|
+
product:
|
|
62
|
+
{% if product.themes %}
|
|
63
|
+
themes:
|
|
64
|
+
{% for theme in product.themes %}
|
|
65
|
+
- {{ theme }}
|
|
66
|
+
{% endfor %}
|
|
67
|
+
{% endif %}
|
|
68
|
+
{% if product.releases %}
|
|
69
|
+
releases:
|
|
70
|
+
{% for release in product.releases %}
|
|
71
|
+
- name: {{ release.name }}
|
|
72
|
+
{% if release.objectives %}
|
|
73
|
+
objectives:
|
|
74
|
+
{% for objective in release.objectives %}
|
|
75
|
+
- {{ objective }}
|
|
76
|
+
{% endfor %}
|
|
77
|
+
{% endif %}
|
|
78
|
+
{% if release.scope %}
|
|
79
|
+
scope:
|
|
80
|
+
{% for item in release.scope %}
|
|
81
|
+
- {{ item }}
|
|
82
|
+
{% endfor %}
|
|
83
|
+
{% endif %}
|
|
84
|
+
{% if release.risks %}
|
|
85
|
+
risks:
|
|
86
|
+
{% for risk in release.risks %}
|
|
87
|
+
- {{ risk }}
|
|
88
|
+
{% endfor %}
|
|
89
|
+
{% endif %}
|
|
90
|
+
{% endfor %}
|
|
91
|
+
{% endif %}
|
|
92
|
+
|
|
93
|
+
{% if features %}
|
|
94
|
+
features:
|
|
95
|
+
{% for feature in features %}
|
|
96
|
+
- key: {{ feature.key }}
|
|
97
|
+
title: {{ feature.title }}
|
|
98
|
+
{% if feature.outcomes %}
|
|
99
|
+
outcomes:
|
|
100
|
+
{% for outcome in feature.outcomes %}
|
|
101
|
+
- {{ outcome }}
|
|
102
|
+
{% endfor %}
|
|
103
|
+
{% endif %}
|
|
104
|
+
{% if feature.acceptance %}
|
|
105
|
+
acceptance:
|
|
106
|
+
{% for criterion in feature.acceptance %}
|
|
107
|
+
- {{ criterion }}
|
|
108
|
+
{% endfor %}
|
|
109
|
+
{% endif %}
|
|
110
|
+
{% if feature.constraints %}
|
|
111
|
+
constraints:
|
|
112
|
+
{% for constraint in feature.constraints %}
|
|
113
|
+
- {{ constraint }}
|
|
114
|
+
{% endfor %}
|
|
115
|
+
{% endif %}
|
|
116
|
+
{% if feature.stories %}
|
|
117
|
+
stories:
|
|
118
|
+
{% for story in feature.stories %}
|
|
119
|
+
- key: {{ story.key }}
|
|
120
|
+
title: {{ story.title }}
|
|
121
|
+
{% if story.acceptance %}
|
|
122
|
+
acceptance:
|
|
123
|
+
{% for criterion in story.acceptance %}
|
|
124
|
+
- {{ criterion }}
|
|
125
|
+
{% endfor %}
|
|
126
|
+
{% endif %}
|
|
127
|
+
{% if story.tags %}
|
|
128
|
+
tags:
|
|
129
|
+
{% for tag in story.tags %}
|
|
130
|
+
- {{ tag }}
|
|
131
|
+
{% endfor %}
|
|
132
|
+
{% endif %}
|
|
133
|
+
confidence: {{ story.confidence }}
|
|
134
|
+
draft: {{ story.draft | lower }}
|
|
135
|
+
{% endfor %}
|
|
136
|
+
{% endif %}
|
|
137
|
+
confidence: {{ feature.confidence }}
|
|
138
|
+
draft: {{ feature.draft | lower }}
|
|
139
|
+
{% endfor %}
|
|
140
|
+
{% endif %}
|
|
141
|
+
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
## 🎯 Purpose
|
|
2
|
+
|
|
3
|
+
{{ purpose | default("Describe the purpose of this PR") }}
|
|
4
|
+
|
|
5
|
+
## 📋 Changes
|
|
6
|
+
|
|
7
|
+
{% if changes %}
|
|
8
|
+
{% for change in changes %}
|
|
9
|
+
- {{ change }}
|
|
10
|
+
{% endfor %}
|
|
11
|
+
{% else %}
|
|
12
|
+
- [ ] List your changes here
|
|
13
|
+
{% endif %}
|
|
14
|
+
|
|
15
|
+
## ✅ Validation
|
|
16
|
+
|
|
17
|
+
**SpecFact CLI Validation Results:**
|
|
18
|
+
|
|
19
|
+
{% if validation_passed %}
|
|
20
|
+
- ✅ All contracts validated successfully
|
|
21
|
+
- ✅ No plan deviations detected
|
|
22
|
+
- ✅ FSM protocol compliant
|
|
23
|
+
{% else %}
|
|
24
|
+
- ⚠️ Validation findings:
|
|
25
|
+
{% if high_count > 0 %}
|
|
26
|
+
- {{ high_count }} HIGH severity issue(s)
|
|
27
|
+
{% endif %}
|
|
28
|
+
{% if medium_count > 0 %}
|
|
29
|
+
- {{ medium_count }} MEDIUM severity issue(s)
|
|
30
|
+
{% endif %}
|
|
31
|
+
{% if low_count > 0 %}
|
|
32
|
+
- {{ low_count }} LOW severity issue(s)
|
|
33
|
+
{% endif %}
|
|
34
|
+
{% endif %}
|
|
35
|
+
|
|
36
|
+
## 📊 Coverage
|
|
37
|
+
|
|
38
|
+
{% if coverage %}
|
|
39
|
+
- **Line Coverage**: {{ coverage.line }}%
|
|
40
|
+
- **Branch Coverage**: {{ coverage.branch }}%
|
|
41
|
+
{% else %}
|
|
42
|
+
- [ ] Add coverage information
|
|
43
|
+
{% endif %}
|
|
44
|
+
|
|
45
|
+
## 🔗 Related
|
|
46
|
+
|
|
47
|
+
{% if related_issues %}
|
|
48
|
+
{% for issue in related_issues %}
|
|
49
|
+
- Closes #{{ issue }}
|
|
50
|
+
{% endfor %}
|
|
51
|
+
{% else %}
|
|
52
|
+
- [ ] Link related issues/PRs
|
|
53
|
+
{% endif %}
|
|
54
|
+
|
|
55
|
+
## 📝 Notes
|
|
56
|
+
|
|
57
|
+
{{ notes | default("Add any additional notes here") }}
|
|
58
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
states:
|
|
2
|
+
{% for state in states %}
|
|
3
|
+
- {{ state }}
|
|
4
|
+
{% endfor %}
|
|
5
|
+
|
|
6
|
+
start: {{ start }}
|
|
7
|
+
|
|
8
|
+
transitions:
|
|
9
|
+
{% for transition in transitions %}
|
|
10
|
+
- from_state: {{ transition.from_state }}
|
|
11
|
+
on_event: {{ transition.on_event }}
|
|
12
|
+
to_state: {{ transition.to_state }}
|
|
13
|
+
{% if transition.guard %}
|
|
14
|
+
guard: {{ transition.guard }}
|
|
15
|
+
{% endif %}
|
|
16
|
+
{% endfor %}
|
|
17
|
+
|
|
18
|
+
{% if guards %}
|
|
19
|
+
guards:
|
|
20
|
+
{% for guard_name, guard_expr in guards.items() %}
|
|
21
|
+
{{ guard_name }}: "{{ guard_expr }}"
|
|
22
|
+
{% endfor %}
|
|
23
|
+
{% endif %}
|
|
24
|
+
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# SpecFact CLI Telemetry Configuration
|
|
2
|
+
#
|
|
3
|
+
# This is an example configuration file for SpecFact CLI telemetry.
|
|
4
|
+
#
|
|
5
|
+
# To use this template:
|
|
6
|
+
# 1. Copy this file to ~/.specfact/telemetry.yaml
|
|
7
|
+
# 2. Customize the settings below
|
|
8
|
+
# 3. Replace YOUR_BASE64_ENCODED_CREDENTIALS_HERE with your actual credentials
|
|
9
|
+
#
|
|
10
|
+
# For more information, see: docs/reference/telemetry.md
|
|
11
|
+
|
|
12
|
+
# Enable telemetry (required)
|
|
13
|
+
enabled: true
|
|
14
|
+
|
|
15
|
+
# OTLP endpoint (HTTPS recommended for corporate environments)
|
|
16
|
+
# Example for Grafana Cloud EU:
|
|
17
|
+
# Get the exact endpoint from: Grafana Cloud Dashboard > Connections > OpenTelemetry > Send traces
|
|
18
|
+
endpoint: "https://otlp-gateway-prod-eu-west-2.grafana.net/otlp/v1/traces"
|
|
19
|
+
|
|
20
|
+
# Authentication headers
|
|
21
|
+
# For Grafana Cloud, get credentials from: Dashboard > Connections > OpenTelemetry > Send traces
|
|
22
|
+
# Format: "Basic <base64(instance-id:api-key)>"
|
|
23
|
+
# The token from Grafana Cloud setup wizard can be used directly
|
|
24
|
+
headers:
|
|
25
|
+
Authorization: "Basic YOUR_BASE64_ENCODED_CREDENTIALS_HERE"
|
|
26
|
+
|
|
27
|
+
# Optional: Advanced configuration
|
|
28
|
+
service_name: "specfact-cli" # Custom service name (default: "specfact-cli")
|
|
29
|
+
service_namespace: "cli" # Service namespace (default: "cli") - used by Grafana Cloud
|
|
30
|
+
deployment_environment: "production" # Deployment environment (default: "production") - used by Grafana Cloud
|
|
31
|
+
batch_size: 512 # Batch size (default: 512)
|
|
32
|
+
batch_timeout: 5 # Batch timeout in seconds (default: 5)
|
|
33
|
+
export_timeout: 10 # Export timeout in seconds (default: 10)
|
|
34
|
+
debug: false # Enable console output for debugging (default: false)
|
|
35
|
+
local_path: "~/.specfact/telemetry.log" # Local log file path (default: ~/.specfact/telemetry.log)
|
specfact_cli/sync/__init__.py
CHANGED
|
@@ -7,6 +7,15 @@ repository changes, and SpecFact plans.
|
|
|
7
7
|
|
|
8
8
|
from specfact_cli.sync.repository_sync import RepositorySync, RepositorySyncResult
|
|
9
9
|
from specfact_cli.sync.speckit_sync import SpecKitSync, SyncResult
|
|
10
|
+
from specfact_cli.sync.watcher import FileChange, SyncEventHandler, SyncWatcher
|
|
10
11
|
|
|
11
12
|
|
|
12
|
-
__all__ = [
|
|
13
|
+
__all__ = [
|
|
14
|
+
"FileChange",
|
|
15
|
+
"RepositorySync",
|
|
16
|
+
"RepositorySyncResult",
|
|
17
|
+
"SpecKitSync",
|
|
18
|
+
"SyncEventHandler",
|
|
19
|
+
"SyncResult",
|
|
20
|
+
"SyncWatcher",
|
|
21
|
+
]
|