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.
Files changed (165) hide show
  1. {elspais-0.11.0 → elspais-0.11.2}/CHANGELOG.md +24 -0
  2. {elspais-0.11.0 → elspais-0.11.2}/PKG-INFO +12 -9
  3. {elspais-0.11.0 → elspais-0.11.2}/README.md +11 -8
  4. {elspais-0.11.0 → elspais-0.11.2}/pyproject.toml +1 -1
  5. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/__init__.py +1 -1
  6. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/cli.py +75 -23
  7. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/analyze.py +5 -6
  8. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/changed.py +2 -6
  9. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/config_cmd.py +4 -4
  10. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/edit.py +32 -36
  11. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/hash_cmd.py +24 -18
  12. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/index.py +8 -7
  13. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/init.py +4 -4
  14. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/reformat_cmd.py +32 -43
  15. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/rules_cmd.py +6 -2
  16. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/trace.py +23 -19
  17. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/validate.py +8 -10
  18. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/config/defaults.py +7 -1
  19. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/core/content_rules.py +0 -1
  20. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/core/git.py +4 -10
  21. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/core/parser.py +55 -56
  22. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/core/patterns.py +2 -6
  23. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/core/rules.py +10 -15
  24. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/mcp/__init__.py +2 -0
  25. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/mcp/context.py +1 -0
  26. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/mcp/serializers.py +1 -1
  27. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/mcp/server.py +54 -39
  28. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/reformat/__init__.py +13 -13
  29. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/reformat/detector.py +9 -16
  30. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/reformat/hierarchy.py +8 -7
  31. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/reformat/line_breaks.py +36 -38
  32. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/reformat/prompts.py +22 -12
  33. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/reformat/transformer.py +43 -41
  34. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/sponsors/__init__.py +0 -2
  35. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/testing/__init__.py +1 -1
  36. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/testing/result_parser.py +25 -21
  37. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/__init__.py +4 -3
  38. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/coverage.py +5 -5
  39. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/generators/base.py +17 -12
  40. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/generators/csv.py +2 -6
  41. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/generators/markdown.py +3 -8
  42. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/__init__.py +4 -2
  43. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/generator.py +423 -289
  44. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/models.py +25 -0
  45. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/review/__init__.py +21 -18
  46. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/review/branches.py +114 -121
  47. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/review/models.py +232 -237
  48. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/review/position.py +53 -71
  49. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/review/server.py +264 -288
  50. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/review/status.py +43 -58
  51. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/review/storage.py +48 -72
  52. {elspais-0.11.0 → elspais-0.11.2}/.gitignore +0 -0
  53. {elspais-0.11.0 → elspais-0.11.2}/LICENSE +0 -0
  54. {elspais-0.11.0 → elspais-0.11.2}/docs/commands.md +0 -0
  55. {elspais-0.11.0 → elspais-0.11.2}/docs/configuration.md +0 -0
  56. {elspais-0.11.0 → elspais-0.11.2}/docs/multi-repo.md +0 -0
  57. {elspais-0.11.0 → elspais-0.11.2}/docs/patterns.md +0 -0
  58. {elspais-0.11.0 → elspais-0.11.2}/docs/roadmap/llm-reformatting-integration.md +0 -0
  59. {elspais-0.11.0 → elspais-0.11.2}/docs/roadmap/new-format.md +0 -0
  60. {elspais-0.11.0 → elspais-0.11.2}/docs/roadmap/plantuml-diagram-support.md +0 -0
  61. {elspais-0.11.0 → elspais-0.11.2}/docs/roadmap/requirements-format-enhancements.md +0 -0
  62. {elspais-0.11.0 → elspais-0.11.2}/docs/rules.md +0 -0
  63. {elspais-0.11.0 → elspais-0.11.2}/docs/trace-view.md +0 -0
  64. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/__main__.py +0 -0
  65. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/commands/__init__.py +0 -0
  66. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/config/__init__.py +0 -0
  67. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/config/loader.py +0 -0
  68. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/core/__init__.py +0 -0
  69. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/core/hasher.py +0 -0
  70. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/core/models.py +0 -0
  71. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/mcp/__main__.py +0 -0
  72. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/testing/config.py +0 -0
  73. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/testing/mapper.py +0 -0
  74. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/testing/scanner.py +0 -0
  75. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/generators/__init__.py +1 -1
  76. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/base.html +0 -0
  77. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/components/code_viewer_modal.html +0 -0
  78. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/components/file_picker_modal.html +0 -0
  79. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/components/legend_modal.html +0 -0
  80. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/components/review_panel.html +0 -0
  81. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/help/help-panel.json +0 -0
  82. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/help/onboarding.json +0 -0
  83. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/help/tooltips.json +0 -0
  84. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/review-comments.js +0 -0
  85. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/review-data.js +0 -0
  86. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/review-help.js +0 -0
  87. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/review-init.js +0 -0
  88. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/review-line-numbers.js +0 -0
  89. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/review-packages.js +0 -0
  90. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/review-position.js +0 -0
  91. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/review-resize.js +0 -0
  92. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/review-status.js +0 -0
  93. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review/review-sync.js +0 -0
  94. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/review-styles.css +0 -0
  95. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/scripts.js +0 -0
  96. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/html/templates/partials/styles.css +0 -0
  97. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/scanning.py +0 -0
  98. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/README.md +0 -0
  99. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00001-template-architecture.md +0 -0
  100. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00002-css-extraction.md +0 -0
  101. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00003-js-extraction.md +0 -0
  102. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00004-build-embedding.md +0 -0
  103. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00005-test-format.md +0 -0
  104. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00010-review-data-models.md +0 -0
  105. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00011-review-storage.md +0 -0
  106. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00012-position-resolution.md +0 -0
  107. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00013-git-branches.md +0 -0
  108. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00014-review-api-server.md +0 -0
  109. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00015-status-modifier.md +0 -0
  110. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-d00016-js-integration.md +0 -0
  111. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-p00001-html-generator.md +0 -0
  112. {elspais-0.11.0 → elspais-0.11.2}/src/elspais/trace_view/specs/tv-p00002-review-system.md +0 -0
  113. {elspais-0.11.0 → elspais-0.11.2}/tests/conftest.py +0 -0
  114. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/assertions/.elspais.toml +0 -0
  115. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/assertions/spec/dev-impl.md +0 -0
  116. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/assertions/spec/prd-sample.md +0 -0
  117. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/associated-repo/.elspais.toml +0 -0
  118. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/associated-repo/spec/dev-sponsor.md +0 -0
  119. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/associated-repo/spec/prd-sponsor.md +0 -0
  120. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/fda-style/.elspais.toml +0 -0
  121. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/fda-style/spec/dev-impl.md +0 -0
  122. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/fda-style/spec/prd-core.md +0 -0
  123. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/hht-like/.elspais.toml +0 -0
  124. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/hht-like/database/schema.sql +0 -0
  125. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/hht-like/spec/INDEX.md +0 -0
  126. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/hht-like/spec/dev-impl.md +0 -0
  127. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/hht-like/spec/ops-deploy.md +0 -0
  128. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/hht-like/spec/prd-core.md +0 -0
  129. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/invalid/broken-links/.elspais.toml +0 -0
  130. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/invalid/broken-links/spec/broken.md +0 -0
  131. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/invalid/circular-deps/.elspais.toml +0 -0
  132. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/invalid/circular-deps/spec/circular.md +0 -0
  133. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/invalid/missing-hash/.elspais.toml +0 -0
  134. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/invalid/missing-hash/spec/missing.md +0 -0
  135. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/jira-style/.elspais.toml +0 -0
  136. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/jira-style/requirements/features.md +0 -0
  137. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/named-reqs/.elspais.toml +0 -0
  138. {elspais-0.11.0 → elspais-0.11.2}/tests/fixtures/named-reqs/spec/features.md +0 -0
  139. {elspais-0.11.0 → elspais-0.11.2}/tests/mcp/__init__.py +0 -0
  140. {elspais-0.11.0 → elspais-0.11.2}/tests/mcp/test_context.py +0 -0
  141. {elspais-0.11.0 → elspais-0.11.2}/tests/mcp/test_serializers.py +0 -0
  142. {elspais-0.11.0 → elspais-0.11.2}/tests/test_config.py +0 -0
  143. {elspais-0.11.0 → elspais-0.11.2}/tests/test_content_rules.py +0 -0
  144. {elspais-0.11.0 → elspais-0.11.2}/tests/test_doc_sync.py +0 -0
  145. {elspais-0.11.0 → elspais-0.11.2}/tests/test_edit.py +0 -0
  146. {elspais-0.11.0 → elspais-0.11.2}/tests/test_git.py +0 -0
  147. {elspais-0.11.0 → elspais-0.11.2}/tests/test_hash_bugs.py +0 -0
  148. {elspais-0.11.0 → elspais-0.11.2}/tests/test_hasher.py +0 -0
  149. {elspais-0.11.0 → elspais-0.11.2}/tests/test_models.py +0 -0
  150. {elspais-0.11.0 → elspais-0.11.2}/tests/test_parser.py +0 -0
  151. {elspais-0.11.0 → elspais-0.11.2}/tests/test_parser_resilience.py +0 -0
  152. {elspais-0.11.0 → elspais-0.11.2}/tests/test_patterns.py +0 -0
  153. {elspais-0.11.0 → elspais-0.11.2}/tests/test_rules.py +0 -0
  154. {elspais-0.11.0 → elspais-0.11.2}/tests/test_sponsors.py +0 -0
  155. {elspais-0.11.0 → elspais-0.11.2}/tests/test_trace_view/__init__.py +0 -0
  156. {elspais-0.11.0 → elspais-0.11.2}/tests/test_trace_view/test_integration.py +0 -0
  157. {elspais-0.11.0 → elspais-0.11.2}/tests/test_validate_json.py +0 -0
  158. {elspais-0.11.0 → elspais-0.11.2}/tests/testing/__init__.py +0 -0
  159. {elspais-0.11.0 → elspais-0.11.2}/tests/testing/fixtures/junit_results.xml +0 -0
  160. {elspais-0.11.0 → elspais-0.11.2}/tests/testing/fixtures/pytest_results.json +0 -0
  161. {elspais-0.11.0 → elspais-0.11.2}/tests/testing/fixtures/sample_test.py +0 -0
  162. {elspais-0.11.0 → elspais-0.11.2}/tests/testing/test_config.py +0 -0
  163. {elspais-0.11.0 → elspais-0.11.2}/tests/testing/test_mapper.py +0 -0
  164. {elspais-0.11.0 → elspais-0.11.2}/tests/testing/test_result_parser.py +0 -0
  165. {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.0
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
- reformat-with-claude Transform requirements using AI (Acceptance Criteria → Assertions)
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
- analyze Analyze requirement hierarchy
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
- reformat-with-claude Transform requirements using AI (Acceptance Criteria → Assertions)
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
- analyze Analyze requirement hierarchy
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
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "elspais"
7
- version = "0.11.0"
7
+ version = "0.11.2"
8
8
  description = "Requirements validation and traceability tools - L-Space connects all libraries"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -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 version, PackageNotFoundError
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 analyze, changed, config_cmd, edit, hash_cmd, index, init, rules_cmd, trace, validate, reformat_cmd
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", "--verbose",
69
+ "-v",
70
+ "--verbose",
51
71
  action="store_true",
52
72
  help="Verbose output",
53
73
  )
54
74
  parser.add_argument(
55
- "-q", "--quiet",
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 specific validation rules",
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", "--json",
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="core: skip sponsor repos, combined: include all (default: combined)",
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 (default: both)",
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 content in HTML output",
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="Include edit mode UI in HTML output",
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="Include review mode UI in HTML output",
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 orphaned requirements",
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", "--json",
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", "--all",
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", "--json",
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", "--json",
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 (type auto-detected: true/false, numbers, JSON arrays/objects, or string)",
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(f"Starting elspais MCP server...")
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 for req in requirements.values()
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 for req in requirements.values()
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, List, Optional
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, Union
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('true' if value else 'false')
366
+ print("true" if value else "false")
367
367
  elif isinstance(value, str):
368
368
  if prefix:
369
369
  print(f'{prefix} = "{value}"')