elspais 0.11.0__py3-none-any.whl → 0.11.2__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.
- elspais/__init__.py +1 -1
- elspais/cli.py +75 -23
- elspais/commands/analyze.py +5 -6
- elspais/commands/changed.py +2 -6
- elspais/commands/config_cmd.py +4 -4
- elspais/commands/edit.py +32 -36
- elspais/commands/hash_cmd.py +24 -18
- elspais/commands/index.py +8 -7
- elspais/commands/init.py +4 -4
- elspais/commands/reformat_cmd.py +32 -43
- elspais/commands/rules_cmd.py +6 -2
- elspais/commands/trace.py +23 -19
- elspais/commands/validate.py +8 -10
- elspais/config/defaults.py +7 -1
- elspais/core/content_rules.py +0 -1
- elspais/core/git.py +4 -10
- elspais/core/parser.py +55 -56
- elspais/core/patterns.py +2 -6
- elspais/core/rules.py +10 -15
- elspais/mcp/__init__.py +2 -0
- elspais/mcp/context.py +1 -0
- elspais/mcp/serializers.py +1 -1
- elspais/mcp/server.py +54 -39
- elspais/reformat/__init__.py +13 -13
- elspais/reformat/detector.py +9 -16
- elspais/reformat/hierarchy.py +8 -7
- elspais/reformat/line_breaks.py +36 -38
- elspais/reformat/prompts.py +22 -12
- elspais/reformat/transformer.py +43 -41
- elspais/sponsors/__init__.py +0 -2
- elspais/testing/__init__.py +1 -1
- elspais/testing/result_parser.py +25 -21
- elspais/trace_view/__init__.py +4 -3
- elspais/trace_view/coverage.py +5 -5
- elspais/trace_view/generators/__init__.py +1 -1
- elspais/trace_view/generators/base.py +17 -12
- elspais/trace_view/generators/csv.py +2 -6
- elspais/trace_view/generators/markdown.py +3 -8
- elspais/trace_view/html/__init__.py +4 -2
- elspais/trace_view/html/generator.py +423 -289
- elspais/trace_view/models.py +25 -0
- elspais/trace_view/review/__init__.py +21 -18
- elspais/trace_view/review/branches.py +114 -121
- elspais/trace_view/review/models.py +232 -237
- elspais/trace_view/review/position.py +53 -71
- elspais/trace_view/review/server.py +264 -288
- elspais/trace_view/review/status.py +43 -58
- elspais/trace_view/review/storage.py +48 -72
- {elspais-0.11.0.dist-info → elspais-0.11.2.dist-info}/METADATA +12 -9
- {elspais-0.11.0.dist-info → elspais-0.11.2.dist-info}/RECORD +53 -53
- {elspais-0.11.0.dist-info → elspais-0.11.2.dist-info}/WHEEL +0 -0
- {elspais-0.11.0.dist-info → elspais-0.11.2.dist-info}/entry_points.txt +0 -0
- {elspais-0.11.0.dist-info → elspais-0.11.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -9,14 +9,11 @@ requirement parsing, implementation scanning, and output generation.
|
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
from typing import Dict, List, Optional
|
|
11
11
|
|
|
12
|
-
from elspais.config.loader import find_config_file, load_config, get_spec_directories
|
|
13
12
|
from elspais.config.defaults import DEFAULT_CONFIG
|
|
13
|
+
from elspais.config.loader import find_config_file, get_spec_directories, load_config
|
|
14
|
+
from elspais.core.git import get_git_changes
|
|
14
15
|
from elspais.core.parser import RequirementParser
|
|
15
16
|
from elspais.core.patterns import PatternConfig
|
|
16
|
-
from elspais.core.git import get_git_changes, GitChangeInfo
|
|
17
|
-
|
|
18
|
-
from elspais.trace_view.models import TraceViewRequirement, GitChangeInfo as TVGitChangeInfo
|
|
19
|
-
from elspais.trace_view.scanning import scan_implementation_files
|
|
20
17
|
from elspais.trace_view.coverage import (
|
|
21
18
|
calculate_coverage,
|
|
22
19
|
generate_coverage_report,
|
|
@@ -24,6 +21,9 @@ from elspais.trace_view.coverage import (
|
|
|
24
21
|
)
|
|
25
22
|
from elspais.trace_view.generators.csv import generate_csv, generate_planning_csv
|
|
26
23
|
from elspais.trace_view.generators.markdown import generate_markdown
|
|
24
|
+
from elspais.trace_view.models import GitChangeInfo as TVGitChangeInfo
|
|
25
|
+
from elspais.trace_view.models import TraceViewRequirement
|
|
26
|
+
from elspais.trace_view.scanning import scan_implementation_files
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
class TraceViewGenerator:
|
|
@@ -93,7 +93,7 @@ class TraceViewGenerator:
|
|
|
93
93
|
|
|
94
94
|
# Parse requirements
|
|
95
95
|
if not quiet:
|
|
96
|
-
print(
|
|
96
|
+
print("Scanning for requirements...")
|
|
97
97
|
self._parse_requirements(quiet)
|
|
98
98
|
|
|
99
99
|
if not self.requirements:
|
|
@@ -187,9 +187,7 @@ class TraceViewGenerator:
|
|
|
187
187
|
|
|
188
188
|
# Report branch changes vs main
|
|
189
189
|
if not quiet and git_changes.branch_changed_files:
|
|
190
|
-
spec_branch = [
|
|
191
|
-
f for f in git_changes.branch_changed_files if f.startswith("spec/")
|
|
192
|
-
]
|
|
190
|
+
spec_branch = [f for f in git_changes.branch_changed_files if f.startswith("spec/")]
|
|
193
191
|
if spec_branch:
|
|
194
192
|
print(f"Spec files changed vs main: {len(spec_branch)}")
|
|
195
193
|
|
|
@@ -298,7 +296,9 @@ class TraceViewGenerator:
|
|
|
298
296
|
cycle_count += 1
|
|
299
297
|
|
|
300
298
|
if not quiet and cycle_count > 0:
|
|
301
|
-
print(
|
|
299
|
+
print(
|
|
300
|
+
f" Warning: {cycle_count} requirements marked as cyclic (shown as orphaned items)"
|
|
301
|
+
)
|
|
302
302
|
|
|
303
303
|
def _calculate_base_path(self, output_file: Path):
|
|
304
304
|
"""Calculate relative path from output file location to repo root."""
|
|
@@ -320,8 +320,13 @@ class TraceViewGenerator:
|
|
|
320
320
|
|
|
321
321
|
def generate_planning_csv(self) -> str:
|
|
322
322
|
"""Generate planning CSV with actionable requirements."""
|
|
323
|
-
|
|
324
|
-
|
|
323
|
+
|
|
324
|
+
def get_status(req_id):
|
|
325
|
+
return get_implementation_status(self.requirements, req_id)
|
|
326
|
+
|
|
327
|
+
def calc_coverage(req_id):
|
|
328
|
+
return calculate_coverage(self.requirements, req_id)
|
|
329
|
+
|
|
325
330
|
return generate_planning_csv(self.requirements, get_status, calc_coverage)
|
|
326
331
|
|
|
327
332
|
def generate_coverage_report(self) -> str:
|
|
@@ -90,14 +90,10 @@ def generate_planning_csv(
|
|
|
90
90
|
writer = csv.writer(output)
|
|
91
91
|
|
|
92
92
|
# Header
|
|
93
|
-
writer.writerow(
|
|
94
|
-
["REQ ID", "Title", "Level", "Status", "Impl Status", "Coverage", "Code Refs"]
|
|
95
|
-
)
|
|
93
|
+
writer.writerow(["REQ ID", "Title", "Level", "Status", "Impl Status", "Coverage", "Code Refs"])
|
|
96
94
|
|
|
97
95
|
# Filter to actionable requirements (Active or Draft status)
|
|
98
|
-
actionable_reqs = [
|
|
99
|
-
req for req in requirements.values() if req.status in ["Active", "Draft"]
|
|
100
|
-
]
|
|
96
|
+
actionable_reqs = [req for req in requirements.values() if req.status in ["Active", "Draft"]]
|
|
101
97
|
|
|
102
98
|
# Sort by ID
|
|
103
99
|
actionable_reqs.sort(key=lambda r: r.id)
|
|
@@ -8,8 +8,8 @@ import sys
|
|
|
8
8
|
from datetime import datetime
|
|
9
9
|
from typing import Dict, List, Optional
|
|
10
10
|
|
|
11
|
-
from elspais.trace_view.models import TraceViewRequirement
|
|
12
11
|
from elspais.trace_view.coverage import count_by_level, find_orphaned_requirements
|
|
12
|
+
from elspais.trace_view.models import TraceViewRequirement
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def generate_legend_markdown() -> str:
|
|
@@ -83,9 +83,7 @@ def generate_markdown(
|
|
|
83
83
|
lines.append("\n## Orphaned Requirements\n")
|
|
84
84
|
lines.append("*(Requirements not linked from any parent)*\n")
|
|
85
85
|
for req in orphaned:
|
|
86
|
-
lines.append(
|
|
87
|
-
f"- **REQ-{req.id}**: {req.title} ({req.level}) - {req.display_filename}"
|
|
88
|
-
)
|
|
86
|
+
lines.append(f"- **REQ-{req.id}**: {req.title} ({req.level}) - {req.display_filename}")
|
|
89
87
|
|
|
90
88
|
return "\n".join(lines)
|
|
91
89
|
|
|
@@ -117,10 +115,7 @@ def format_req_tree_md(
|
|
|
117
115
|
cycle_path = ancestor_path + [req.id]
|
|
118
116
|
cycle_str = " -> ".join([f"REQ-{rid}" for rid in cycle_path])
|
|
119
117
|
print(f"Warning: CYCLE DETECTED: {cycle_str}", file=sys.stderr)
|
|
120
|
-
return (
|
|
121
|
-
" " * indent
|
|
122
|
-
+ f"- **CYCLE DETECTED**: REQ-{req.id} (path: {cycle_str})"
|
|
123
|
-
)
|
|
118
|
+
return " " * indent + f"- **CYCLE DETECTED**: REQ-{req.id} (path: {cycle_str})"
|
|
124
119
|
|
|
125
120
|
# Safety depth limit
|
|
126
121
|
MAX_DEPTH = 50
|
|
@@ -5,9 +5,11 @@ elspais.trace_view.html - Interactive HTML generation.
|
|
|
5
5
|
Requires: pip install elspais[trace-view]
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
|
|
8
9
|
def _check_jinja2():
|
|
9
10
|
try:
|
|
10
11
|
import jinja2 # noqa: F401
|
|
12
|
+
|
|
11
13
|
return True
|
|
12
14
|
except ImportError:
|
|
13
15
|
return False
|
|
@@ -17,6 +19,7 @@ JINJA2_AVAILABLE = _check_jinja2()
|
|
|
17
19
|
|
|
18
20
|
if JINJA2_AVAILABLE:
|
|
19
21
|
from elspais.trace_view.html.generator import HTMLGenerator
|
|
22
|
+
|
|
20
23
|
__all__ = ["HTMLGenerator", "JINJA2_AVAILABLE"]
|
|
21
24
|
else:
|
|
22
25
|
__all__ = ["JINJA2_AVAILABLE"]
|
|
@@ -26,6 +29,5 @@ else:
|
|
|
26
29
|
|
|
27
30
|
def __init__(self, *args, **kwargs):
|
|
28
31
|
raise ImportError(
|
|
29
|
-
"HTMLGenerator requires Jinja2. "
|
|
30
|
-
"Install with: pip install elspais[trace-view]"
|
|
32
|
+
"HTMLGenerator requires Jinja2. " "Install with: pip install elspais[trace-view]"
|
|
31
33
|
)
|