elspais 0.11.0__tar.gz → 0.11.2__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.
- {elspais-0.11.0 → elspais-0.11.2}/CHANGELOG.md +24 -0
- {elspais-0.11.0 → elspais-0.11.2}/PKG-INFO +12 -9
- {elspais-0.11.0 → elspais-0.11.2}/README.md +11 -8
- {elspais-0.11.0 → elspais-0.11.2}/pyproject.toml +1 -1
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/__init__.py +1 -1
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/cli.py +75 -23
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/analyze.py +5 -6
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/changed.py +2 -6
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/config_cmd.py +4 -4
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/edit.py +32 -36
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/hash_cmd.py +24 -18
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/index.py +8 -7
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/init.py +4 -4
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/reformat_cmd.py +32 -43
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/rules_cmd.py +6 -2
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/trace.py +23 -19
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/validate.py +8 -10
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/config/defaults.py +7 -1
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/core/content_rules.py +0 -1
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/core/git.py +4 -10
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/core/parser.py +55 -56
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/core/patterns.py +2 -6
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/core/rules.py +10 -15
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/mcp/__init__.py +2 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/mcp/context.py +1 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/mcp/serializers.py +1 -1
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/mcp/server.py +54 -39
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/reformat/__init__.py +13 -13
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/reformat/detector.py +9 -16
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/reformat/hierarchy.py +8 -7
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/reformat/line_breaks.py +36 -38
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/reformat/prompts.py +22 -12
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/reformat/transformer.py +43 -41
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/sponsors/__init__.py +0 -2
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/testing/__init__.py +1 -1
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/testing/result_parser.py +25 -21
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/__init__.py +4 -3
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/coverage.py +5 -5
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/generators/base.py +17 -12
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/generators/csv.py +2 -6
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/generators/markdown.py +3 -8
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/__init__.py +4 -2
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/generator.py +423 -289
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/models.py +25 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/review/__init__.py +21 -18
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/review/branches.py +114 -121
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/review/models.py +232 -237
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/review/position.py +53 -71
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/review/server.py +264 -288
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/review/status.py +43 -58
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/review/storage.py +48 -72
- {elspais-0.11.0 → elspais-0.11.2}/.gitignore +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/LICENSE +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/docs/commands.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/docs/configuration.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/docs/multi-repo.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/docs/patterns.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/docs/roadmap/llm-reformatting-integration.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/docs/roadmap/new-format.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/docs/roadmap/plantuml-diagram-support.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/docs/roadmap/requirements-format-enhancements.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/docs/rules.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/docs/trace-view.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/__main__.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/__init__.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/config/__init__.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/config/loader.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/core/__init__.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/core/hasher.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/core/models.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/mcp/__main__.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/testing/config.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/testing/mapper.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/testing/scanner.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/generators/__init__.py +1 -1
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/base.html +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/components/code_viewer_modal.html +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/components/file_picker_modal.html +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/components/legend_modal.html +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/components/review_panel.html +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/help/help-panel.json +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/help/onboarding.json +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/help/tooltips.json +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/review-comments.js +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/review-data.js +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/review-help.js +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/review-init.js +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/review-line-numbers.js +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/review-packages.js +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/review-position.js +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/review-resize.js +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/review-status.js +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/review-sync.js +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review-styles.css +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/scripts.js +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/styles.css +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/scanning.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/README.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00001-template-architecture.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00002-css-extraction.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00003-js-extraction.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00004-build-embedding.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00005-test-format.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00010-review-data-models.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00011-review-storage.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00012-position-resolution.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00013-git-branches.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00014-review-api-server.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00015-status-modifier.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00016-js-integration.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-p00001-html-generator.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-p00002-review-system.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/conftest.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/assertions/.elspais.toml +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/assertions/spec/dev-impl.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/assertions/spec/prd-sample.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/associated-repo/.elspais.toml +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/associated-repo/spec/dev-sponsor.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/associated-repo/spec/prd-sponsor.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/fda-style/.elspais.toml +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/fda-style/spec/dev-impl.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/fda-style/spec/prd-core.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/hht-like/.elspais.toml +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/hht-like/database/schema.sql +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/hht-like/spec/INDEX.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/hht-like/spec/dev-impl.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/hht-like/spec/ops-deploy.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/hht-like/spec/prd-core.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/invalid/broken-links/.elspais.toml +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/invalid/broken-links/spec/broken.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/invalid/circular-deps/.elspais.toml +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/invalid/circular-deps/spec/circular.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/invalid/missing-hash/.elspais.toml +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/invalid/missing-hash/spec/missing.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/jira-style/.elspais.toml +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/jira-style/requirements/features.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/named-reqs/.elspais.toml +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/named-reqs/spec/features.md +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/mcp/__init__.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/mcp/test_context.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/mcp/test_serializers.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/test_config.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/test_content_rules.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/test_doc_sync.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/test_edit.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/test_git.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/test_hash_bugs.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/test_hasher.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/test_models.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/test_parser.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/test_parser_resilience.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/test_patterns.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/test_rules.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/test_sponsors.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/test_trace_view/__init__.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/test_trace_view/test_integration.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/test_validate_json.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/testing/__init__.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/testing/fixtures/junit_results.xml +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/testing/fixtures/pytest_results.json +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/testing/fixtures/sample_test.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/testing/test_config.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/testing/test_mapper.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/testing/test_result_parser.py +0 -0
- {elspais-0.11.0 → elspais-0.11.2}/tests/testing/test_scanner.py +0 -0
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
<!-- markdownlint-disable MD022 MD032 -->
|
|
4
|
+
<!-- Compact changelog format: no blank lines around headings/lists -->
|
|
5
|
+
|
|
3
6
|
All notable changes to elspais will be documented in this file.
|
|
4
7
|
|
|
5
8
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
@@ -7,6 +10,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
10
|
|
|
8
11
|
## [Unreleased]
|
|
9
12
|
|
|
13
|
+
## [0.11.2] - 2026-01-21
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- Fixed `elspais trace --view` crash caused by missing `is_cycle` and `cycle_path` properties in `TraceViewRequirement`
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Comprehensive git hooks (pre-commit, pre-push, commit-msg) with branch protection, linting, secret detection, and commit message format validation
|
|
22
|
+
- Commit message format validation requiring `[TICKET-NUMBER]` prefix (e.g., `[CUR-514]`)
|
|
23
|
+
- Markdownlint configuration (`.markdownlint.json`) disabling line length and duplicate heading rules
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- Applied ruff and black formatting fixes across the codebase
|
|
28
|
+
|
|
29
|
+
## [0.11.1] - 2026-01-15
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
- Improved CLI `--help` output with examples, subcommand hints, and clearer descriptions
|
|
33
|
+
|
|
10
34
|
## [0.11.0] - 2026-01-15
|
|
11
35
|
|
|
12
36
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: elspais
|
|
3
|
-
Version: 0.11.
|
|
3
|
+
Version: 0.11.2
|
|
4
4
|
Summary: Requirements validation and traceability tools - L-Space connects all libraries
|
|
5
5
|
Project-URL: Homepage, https://github.com/anspar/elspais
|
|
6
6
|
Project-URL: Documentation, https://github.com/anspar/elspais#readme
|
|
@@ -376,19 +376,19 @@ Options:
|
|
|
376
376
|
--help Show help
|
|
377
377
|
|
|
378
378
|
Commands:
|
|
379
|
-
validate Validate requirements format, links, hashes
|
|
379
|
+
validate Validate requirements format, links, and hashes
|
|
380
380
|
trace Generate traceability matrix
|
|
381
381
|
hash Manage requirement hashes (verify, update)
|
|
382
|
-
|
|
382
|
+
index Manage INDEX.md file (validate, regenerate)
|
|
383
|
+
analyze Analyze requirement hierarchy (hierarchy, orphans, coverage)
|
|
383
384
|
changed Detect git changes to spec files
|
|
384
|
-
|
|
385
|
-
edit Edit requirements in-place (status, implements, move)
|
|
386
|
-
config View and modify configuration
|
|
387
|
-
rules View and manage content rules
|
|
388
|
-
index Validate or regenerate INDEX.md
|
|
385
|
+
version Show version and check for updates
|
|
389
386
|
init Create .elspais.toml configuration
|
|
387
|
+
edit Edit requirements in-place (implements, status, move)
|
|
388
|
+
config View and modify configuration (show, get, set, ...)
|
|
389
|
+
rules View and manage content rules (list, show)
|
|
390
|
+
reformat-with-claude Reformat requirements using AI (Acceptance Criteria -> Assertions)
|
|
390
391
|
mcp MCP server commands (requires elspais[mcp])
|
|
391
|
-
version Show version and check for updates
|
|
392
392
|
```
|
|
393
393
|
|
|
394
394
|
See [docs/commands.md](docs/commands.md) for comprehensive command documentation.
|
|
@@ -401,6 +401,9 @@ git clone https://github.com/anspar/elspais.git
|
|
|
401
401
|
cd elspais
|
|
402
402
|
pip install -e ".[dev]"
|
|
403
403
|
|
|
404
|
+
# Enable git hooks (verifies docs stay in sync before push)
|
|
405
|
+
git config core.hooksPath .githooks
|
|
406
|
+
|
|
404
407
|
# Run tests
|
|
405
408
|
pytest
|
|
406
409
|
|
|
@@ -327,19 +327,19 @@ Options:
|
|
|
327
327
|
--help Show help
|
|
328
328
|
|
|
329
329
|
Commands:
|
|
330
|
-
validate Validate requirements format, links, hashes
|
|
330
|
+
validate Validate requirements format, links, and hashes
|
|
331
331
|
trace Generate traceability matrix
|
|
332
332
|
hash Manage requirement hashes (verify, update)
|
|
333
|
-
|
|
333
|
+
index Manage INDEX.md file (validate, regenerate)
|
|
334
|
+
analyze Analyze requirement hierarchy (hierarchy, orphans, coverage)
|
|
334
335
|
changed Detect git changes to spec files
|
|
335
|
-
|
|
336
|
-
edit Edit requirements in-place (status, implements, move)
|
|
337
|
-
config View and modify configuration
|
|
338
|
-
rules View and manage content rules
|
|
339
|
-
index Validate or regenerate INDEX.md
|
|
336
|
+
version Show version and check for updates
|
|
340
337
|
init Create .elspais.toml configuration
|
|
338
|
+
edit Edit requirements in-place (implements, status, move)
|
|
339
|
+
config View and modify configuration (show, get, set, ...)
|
|
340
|
+
rules View and manage content rules (list, show)
|
|
341
|
+
reformat-with-claude Reformat requirements using AI (Acceptance Criteria -> Assertions)
|
|
341
342
|
mcp MCP server commands (requires elspais[mcp])
|
|
342
|
-
version Show version and check for updates
|
|
343
343
|
```
|
|
344
344
|
|
|
345
345
|
See [docs/commands.md](docs/commands.md) for comprehensive command documentation.
|
|
@@ -352,6 +352,9 @@ git clone https://github.com/anspar/elspais.git
|
|
|
352
352
|
cd elspais
|
|
353
353
|
pip install -e ".[dev]"
|
|
354
354
|
|
|
355
|
+
# Enable git hooks (verifies docs stay in sync before push)
|
|
356
|
+
git config core.hooksPath .githooks
|
|
357
|
+
|
|
355
358
|
# Run tests
|
|
356
359
|
pytest
|
|
357
360
|
|
|
@@ -10,7 +10,7 @@ and supports multi-repository requirement management with configurable
|
|
|
10
10
|
ID patterns and validation rules.
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
|
-
from importlib.metadata import
|
|
13
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
14
14
|
|
|
15
15
|
try:
|
|
16
16
|
__version__ = version("elspais")
|
|
@@ -10,7 +10,19 @@ from pathlib import Path
|
|
|
10
10
|
from typing import List, Optional
|
|
11
11
|
|
|
12
12
|
from elspais import __version__
|
|
13
|
-
from elspais.commands import
|
|
13
|
+
from elspais.commands import (
|
|
14
|
+
analyze,
|
|
15
|
+
changed,
|
|
16
|
+
config_cmd,
|
|
17
|
+
edit,
|
|
18
|
+
hash_cmd,
|
|
19
|
+
index,
|
|
20
|
+
init,
|
|
21
|
+
reformat_cmd,
|
|
22
|
+
rules_cmd,
|
|
23
|
+
trace,
|
|
24
|
+
validate,
|
|
25
|
+
)
|
|
14
26
|
|
|
15
27
|
|
|
16
28
|
def create_parser() -> argparse.ArgumentParser:
|
|
@@ -22,9 +34,16 @@ def create_parser() -> argparse.ArgumentParser:
|
|
|
22
34
|
epilog="""
|
|
23
35
|
Examples:
|
|
24
36
|
elspais validate # Validate all requirements
|
|
37
|
+
elspais validate --fix # Auto-fix fixable issues
|
|
25
38
|
elspais trace --format html # Generate HTML traceability matrix
|
|
39
|
+
elspais trace --view # Interactive HTML view
|
|
26
40
|
elspais hash update # Update all requirement hashes
|
|
41
|
+
elspais changed # Show uncommitted spec changes
|
|
42
|
+
elspais analyze hierarchy # Show requirement hierarchy tree
|
|
43
|
+
elspais config show # View current configuration
|
|
27
44
|
elspais init # Create .elspais.toml configuration
|
|
45
|
+
|
|
46
|
+
For detailed command help: elspais <command> --help
|
|
28
47
|
""",
|
|
29
48
|
)
|
|
30
49
|
|
|
@@ -47,12 +66,14 @@ Examples:
|
|
|
47
66
|
metavar="PATH",
|
|
48
67
|
)
|
|
49
68
|
parser.add_argument(
|
|
50
|
-
"-v",
|
|
69
|
+
"-v",
|
|
70
|
+
"--verbose",
|
|
51
71
|
action="store_true",
|
|
52
72
|
help="Verbose output",
|
|
53
73
|
)
|
|
54
74
|
parser.add_argument(
|
|
55
|
-
"-q",
|
|
75
|
+
"-q",
|
|
76
|
+
"--quiet",
|
|
56
77
|
action="store_true",
|
|
57
78
|
help="Suppress non-error output",
|
|
58
79
|
)
|
|
@@ -64,6 +85,21 @@ Examples:
|
|
|
64
85
|
validate_parser = subparsers.add_parser(
|
|
65
86
|
"validate",
|
|
66
87
|
help="Validate requirements format, links, and hashes",
|
|
88
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
89
|
+
epilog="""
|
|
90
|
+
Examples:
|
|
91
|
+
elspais validate # Validate all requirements
|
|
92
|
+
elspais validate --fix # Auto-fix hashes and formatting
|
|
93
|
+
elspais validate --skip-rule hash.* # Skip all hash rules
|
|
94
|
+
elspais validate -j # Output JSON for tooling
|
|
95
|
+
elspais validate --mode core # Exclude associated repo specs
|
|
96
|
+
|
|
97
|
+
Common rules to skip:
|
|
98
|
+
hash.missing Hash footer is missing
|
|
99
|
+
hash.mismatch Hash doesn't match content
|
|
100
|
+
hierarchy.* All hierarchy rules
|
|
101
|
+
format.* All format rules
|
|
102
|
+
""",
|
|
67
103
|
)
|
|
68
104
|
validate_parser.add_argument(
|
|
69
105
|
"--fix",
|
|
@@ -79,11 +115,12 @@ Examples:
|
|
|
79
115
|
validate_parser.add_argument(
|
|
80
116
|
"--skip-rule",
|
|
81
117
|
action="append",
|
|
82
|
-
help="Skip
|
|
118
|
+
help="Skip validation rules (can be repeated, e.g., hash.*, format.*)",
|
|
83
119
|
metavar="RULE",
|
|
84
120
|
)
|
|
85
121
|
validate_parser.add_argument(
|
|
86
|
-
"-j",
|
|
122
|
+
"-j",
|
|
123
|
+
"--json",
|
|
87
124
|
action="store_true",
|
|
88
125
|
help="Output requirements as JSON (hht_diary compatible format)",
|
|
89
126
|
)
|
|
@@ -101,7 +138,7 @@ Examples:
|
|
|
101
138
|
"--mode",
|
|
102
139
|
choices=["core", "combined"],
|
|
103
140
|
default="combined",
|
|
104
|
-
help="
|
|
141
|
+
help="Scope: core (this repo only), combined (include sponsor repos)",
|
|
105
142
|
)
|
|
106
143
|
|
|
107
144
|
# trace command
|
|
@@ -113,7 +150,7 @@ Examples:
|
|
|
113
150
|
"--format",
|
|
114
151
|
choices=["markdown", "html", "csv", "both"],
|
|
115
152
|
default="both",
|
|
116
|
-
help="Output format (
|
|
153
|
+
help="Output format: markdown, html, csv, or both (markdown + csv)",
|
|
117
154
|
)
|
|
118
155
|
trace_parser.add_argument(
|
|
119
156
|
"--output",
|
|
@@ -130,17 +167,17 @@ Examples:
|
|
|
130
167
|
trace_parser.add_argument(
|
|
131
168
|
"--embed-content",
|
|
132
169
|
action="store_true",
|
|
133
|
-
help="Embed full requirement
|
|
170
|
+
help="Embed full requirement markdown in HTML for offline viewing",
|
|
134
171
|
)
|
|
135
172
|
trace_parser.add_argument(
|
|
136
173
|
"--edit-mode",
|
|
137
174
|
action="store_true",
|
|
138
|
-
help="
|
|
175
|
+
help="Enable in-browser editing of implements and status fields",
|
|
139
176
|
)
|
|
140
177
|
trace_parser.add_argument(
|
|
141
178
|
"--review-mode",
|
|
142
179
|
action="store_true",
|
|
143
|
-
help="
|
|
180
|
+
help="Enable collaborative review with comments and flags",
|
|
144
181
|
)
|
|
145
182
|
trace_parser.add_argument(
|
|
146
183
|
"--server",
|
|
@@ -168,7 +205,7 @@ Examples:
|
|
|
168
205
|
# hash command
|
|
169
206
|
hash_parser = subparsers.add_parser(
|
|
170
207
|
"hash",
|
|
171
|
-
help="Manage requirement hashes",
|
|
208
|
+
help="Manage requirement hashes (verify, update)",
|
|
172
209
|
)
|
|
173
210
|
hash_subparsers = hash_parser.add_subparsers(dest="hash_action")
|
|
174
211
|
|
|
@@ -195,7 +232,7 @@ Examples:
|
|
|
195
232
|
# index command
|
|
196
233
|
index_parser = subparsers.add_parser(
|
|
197
234
|
"index",
|
|
198
|
-
help="Manage INDEX.md file",
|
|
235
|
+
help="Manage INDEX.md file (validate, regenerate)",
|
|
199
236
|
)
|
|
200
237
|
index_subparsers = index_parser.add_subparsers(dest="index_action")
|
|
201
238
|
|
|
@@ -211,7 +248,7 @@ Examples:
|
|
|
211
248
|
# analyze command
|
|
212
249
|
analyze_parser = subparsers.add_parser(
|
|
213
250
|
"analyze",
|
|
214
|
-
help="Analyze requirement hierarchy",
|
|
251
|
+
help="Analyze requirement hierarchy (hierarchy, orphans, coverage)",
|
|
215
252
|
)
|
|
216
253
|
analyze_subparsers = analyze_parser.add_subparsers(dest="analyze_action")
|
|
217
254
|
|
|
@@ -221,7 +258,7 @@ Examples:
|
|
|
221
258
|
)
|
|
222
259
|
analyze_subparsers.add_parser(
|
|
223
260
|
"orphans",
|
|
224
|
-
help="Find
|
|
261
|
+
help="Find requirements with no parent (missing or invalid Implements)",
|
|
225
262
|
)
|
|
226
263
|
analyze_subparsers.add_parser(
|
|
227
264
|
"coverage",
|
|
@@ -240,12 +277,14 @@ Examples:
|
|
|
240
277
|
metavar="BRANCH",
|
|
241
278
|
)
|
|
242
279
|
changed_parser.add_argument(
|
|
243
|
-
"-j",
|
|
280
|
+
"-j",
|
|
281
|
+
"--json",
|
|
244
282
|
action="store_true",
|
|
245
283
|
help="Output as JSON",
|
|
246
284
|
)
|
|
247
285
|
changed_parser.add_argument(
|
|
248
|
-
"-a",
|
|
286
|
+
"-a",
|
|
287
|
+
"--all",
|
|
249
288
|
action="store_true",
|
|
250
289
|
help="Include all changed files (not just spec)",
|
|
251
290
|
)
|
|
@@ -258,7 +297,7 @@ Examples:
|
|
|
258
297
|
version_parser.add_argument(
|
|
259
298
|
"check",
|
|
260
299
|
nargs="?",
|
|
261
|
-
help="Check for updates",
|
|
300
|
+
help="Check for updates (not yet implemented)",
|
|
262
301
|
)
|
|
263
302
|
|
|
264
303
|
# init command
|
|
@@ -286,6 +325,17 @@ Examples:
|
|
|
286
325
|
edit_parser = subparsers.add_parser(
|
|
287
326
|
"edit",
|
|
288
327
|
help="Edit requirements in-place (implements, status, move)",
|
|
328
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
329
|
+
epilog="""
|
|
330
|
+
Examples:
|
|
331
|
+
elspais edit --req-id REQ-d00001 --status Draft
|
|
332
|
+
elspais edit --req-id REQ-d00001 --implements REQ-p00001,REQ-p00002
|
|
333
|
+
elspais edit --req-id REQ-d00001 --move-to roadmap/future.md
|
|
334
|
+
elspais edit --from-json edits.json
|
|
335
|
+
|
|
336
|
+
JSON batch format:
|
|
337
|
+
{"edits": [{"req_id": "...", "status": "...", "implements": [...]}]}
|
|
338
|
+
""",
|
|
289
339
|
)
|
|
290
340
|
edit_parser.add_argument(
|
|
291
341
|
"--req-id",
|
|
@@ -326,7 +376,7 @@ Examples:
|
|
|
326
376
|
# config command
|
|
327
377
|
config_parser = subparsers.add_parser(
|
|
328
378
|
"config",
|
|
329
|
-
help="View and modify configuration",
|
|
379
|
+
help="View and modify configuration (show, get, set, ...)",
|
|
330
380
|
)
|
|
331
381
|
config_subparsers = config_parser.add_subparsers(dest="config_action")
|
|
332
382
|
|
|
@@ -341,7 +391,8 @@ Examples:
|
|
|
341
391
|
metavar="SECTION",
|
|
342
392
|
)
|
|
343
393
|
config_show.add_argument(
|
|
344
|
-
"-j",
|
|
394
|
+
"-j",
|
|
395
|
+
"--json",
|
|
345
396
|
action="store_true",
|
|
346
397
|
help="Output as JSON",
|
|
347
398
|
)
|
|
@@ -356,7 +407,8 @@ Examples:
|
|
|
356
407
|
help="Configuration key (dot-notation, e.g., 'patterns.prefix')",
|
|
357
408
|
)
|
|
358
409
|
config_get.add_argument(
|
|
359
|
-
"-j",
|
|
410
|
+
"-j",
|
|
411
|
+
"--json",
|
|
360
412
|
action="store_true",
|
|
361
413
|
help="Output as JSON",
|
|
362
414
|
)
|
|
@@ -372,7 +424,7 @@ Examples:
|
|
|
372
424
|
)
|
|
373
425
|
config_set.add_argument(
|
|
374
426
|
"value",
|
|
375
|
-
help="Value to set (
|
|
427
|
+
help="Value to set (auto-detected: bool, number, JSON array/object, string)",
|
|
376
428
|
)
|
|
377
429
|
|
|
378
430
|
# config unset
|
|
@@ -422,7 +474,7 @@ Examples:
|
|
|
422
474
|
# rules command
|
|
423
475
|
rules_parser = subparsers.add_parser(
|
|
424
476
|
"rules",
|
|
425
|
-
help="View and manage content rules",
|
|
477
|
+
help="View and manage content rules (list, show)",
|
|
426
478
|
)
|
|
427
479
|
rules_subparsers = rules_parser.add_subparsers(dest="rules_action")
|
|
428
480
|
|
|
@@ -629,7 +681,7 @@ def mcp_command(args: argparse.Namespace) -> int:
|
|
|
629
681
|
if hasattr(args, "spec_dir") and args.spec_dir:
|
|
630
682
|
working_dir = args.spec_dir.parent
|
|
631
683
|
|
|
632
|
-
print(
|
|
684
|
+
print("Starting elspais MCP server...")
|
|
633
685
|
print(f"Working directory: {working_dir}")
|
|
634
686
|
print(f"Transport: {args.transport}")
|
|
635
687
|
|
|
@@ -41,16 +41,14 @@ def run_hierarchy(args: argparse.Namespace) -> int:
|
|
|
41
41
|
|
|
42
42
|
# Find root requirements (PRD with no implements)
|
|
43
43
|
roots = [
|
|
44
|
-
req
|
|
44
|
+
req
|
|
45
|
+
for req in requirements.values()
|
|
45
46
|
if req.level.upper() in ["PRD", "PRODUCT"] and not req.implements
|
|
46
47
|
]
|
|
47
48
|
|
|
48
49
|
if not roots:
|
|
49
50
|
# Fall back to all PRD requirements
|
|
50
|
-
roots = [
|
|
51
|
-
req for req in requirements.values()
|
|
52
|
-
if req.level.upper() in ["PRD", "PRODUCT"]
|
|
53
|
-
]
|
|
51
|
+
roots = [req for req in requirements.values() if req.level.upper() in ["PRD", "PRODUCT"]]
|
|
54
52
|
|
|
55
53
|
printed = set()
|
|
56
54
|
|
|
@@ -153,7 +151,8 @@ def run_coverage(args: argparse.Namespace) -> int:
|
|
|
153
151
|
|
|
154
152
|
# List unimplemented PRD
|
|
155
153
|
unimplemented = [
|
|
156
|
-
req
|
|
154
|
+
req
|
|
155
|
+
for req in requirements.values()
|
|
157
156
|
if req.level.upper() in ["PRD", "PRODUCT"] and req.id not in implemented_prd
|
|
158
157
|
]
|
|
159
158
|
|
|
@@ -11,13 +11,11 @@ import argparse
|
|
|
11
11
|
import json
|
|
12
12
|
import sys
|
|
13
13
|
from pathlib import Path
|
|
14
|
-
from typing import Dict,
|
|
14
|
+
from typing import Dict, Optional
|
|
15
15
|
|
|
16
16
|
from elspais.config.defaults import DEFAULT_CONFIG
|
|
17
17
|
from elspais.config.loader import find_config_file, load_config
|
|
18
18
|
from elspais.core.git import (
|
|
19
|
-
GitChangeInfo,
|
|
20
|
-
MovedRequirement,
|
|
21
19
|
detect_moved_requirements,
|
|
22
20
|
filter_spec_files,
|
|
23
21
|
get_current_req_locations,
|
|
@@ -76,9 +74,7 @@ def run(args: argparse.Namespace) -> int:
|
|
|
76
74
|
|
|
77
75
|
# Detect moved requirements
|
|
78
76
|
current_locations = get_current_req_locations(repo_root, spec_dir)
|
|
79
|
-
moved = detect_moved_requirements(
|
|
80
|
-
changes.committed_req_locations, current_locations
|
|
81
|
-
)
|
|
77
|
+
moved = detect_moved_requirements(changes.committed_req_locations, current_locations)
|
|
82
78
|
|
|
83
79
|
# Build result
|
|
84
80
|
result = {
|
|
@@ -8,15 +8,14 @@ import argparse
|
|
|
8
8
|
import json
|
|
9
9
|
import sys
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
from typing import Any, Dict, List, Optional, Tuple
|
|
11
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
12
12
|
|
|
13
|
+
from elspais.config.defaults import DEFAULT_CONFIG
|
|
13
14
|
from elspais.config.loader import (
|
|
14
15
|
find_config_file,
|
|
15
16
|
load_config,
|
|
16
|
-
merge_configs,
|
|
17
17
|
parse_toml,
|
|
18
18
|
)
|
|
19
|
-
from elspais.config.defaults import DEFAULT_CONFIG
|
|
20
19
|
|
|
21
20
|
|
|
22
21
|
def run(args: argparse.Namespace) -> int:
|
|
@@ -255,6 +254,7 @@ def cmd_path(args: argparse.Namespace) -> int:
|
|
|
255
254
|
|
|
256
255
|
# Helper functions
|
|
257
256
|
|
|
257
|
+
|
|
258
258
|
def _get_config_path(args: argparse.Namespace) -> Optional[Path]:
|
|
259
259
|
"""Get configuration file path from args or by discovery."""
|
|
260
260
|
if hasattr(args, "config") and args.config:
|
|
@@ -363,7 +363,7 @@ def _print_value(value: Any, prefix: str = "") -> None:
|
|
|
363
363
|
if prefix:
|
|
364
364
|
print(f"{prefix} = {'true' if value else 'false'}")
|
|
365
365
|
else:
|
|
366
|
-
print(
|
|
366
|
+
print("true" if value else "false")
|
|
367
367
|
elif isinstance(value, str):
|
|
368
368
|
if prefix:
|
|
369
369
|
print(f'{prefix} = "{value}"')
|