elspais 0.11.1__py3-none-any.whl → 0.43.5__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.
Files changed (148) hide show
  1. elspais/__init__.py +2 -11
  2. elspais/{sponsors/__init__.py → associates.py} +102 -58
  3. elspais/cli.py +395 -79
  4. elspais/commands/__init__.py +9 -3
  5. elspais/commands/analyze.py +121 -173
  6. elspais/commands/changed.py +15 -30
  7. elspais/commands/config_cmd.py +13 -16
  8. elspais/commands/edit.py +60 -44
  9. elspais/commands/example_cmd.py +319 -0
  10. elspais/commands/hash_cmd.py +167 -183
  11. elspais/commands/health.py +1177 -0
  12. elspais/commands/index.py +98 -114
  13. elspais/commands/init.py +103 -26
  14. elspais/commands/reformat_cmd.py +41 -444
  15. elspais/commands/rules_cmd.py +7 -3
  16. elspais/commands/trace.py +444 -321
  17. elspais/commands/validate.py +195 -415
  18. elspais/config/__init__.py +799 -5
  19. elspais/{core/content_rules.py → content_rules.py} +20 -3
  20. elspais/docs/cli/assertions.md +67 -0
  21. elspais/docs/cli/commands.md +304 -0
  22. elspais/docs/cli/config.md +262 -0
  23. elspais/docs/cli/format.md +66 -0
  24. elspais/docs/cli/git.md +45 -0
  25. elspais/docs/cli/health.md +190 -0
  26. elspais/docs/cli/hierarchy.md +60 -0
  27. elspais/docs/cli/ignore.md +72 -0
  28. elspais/docs/cli/mcp.md +245 -0
  29. elspais/docs/cli/quickstart.md +58 -0
  30. elspais/docs/cli/traceability.md +89 -0
  31. elspais/docs/cli/validation.md +96 -0
  32. elspais/graph/GraphNode.py +383 -0
  33. elspais/graph/__init__.py +40 -0
  34. elspais/graph/annotators.py +927 -0
  35. elspais/graph/builder.py +1886 -0
  36. elspais/graph/deserializer.py +248 -0
  37. elspais/graph/factory.py +284 -0
  38. elspais/graph/metrics.py +127 -0
  39. elspais/graph/mutations.py +161 -0
  40. elspais/graph/parsers/__init__.py +156 -0
  41. elspais/graph/parsers/code.py +213 -0
  42. elspais/graph/parsers/comments.py +112 -0
  43. elspais/graph/parsers/config_helpers.py +29 -0
  44. elspais/graph/parsers/heredocs.py +225 -0
  45. elspais/graph/parsers/journey.py +131 -0
  46. elspais/graph/parsers/remainder.py +79 -0
  47. elspais/graph/parsers/requirement.py +347 -0
  48. elspais/graph/parsers/results/__init__.py +6 -0
  49. elspais/graph/parsers/results/junit_xml.py +229 -0
  50. elspais/graph/parsers/results/pytest_json.py +313 -0
  51. elspais/graph/parsers/test.py +305 -0
  52. elspais/graph/relations.py +78 -0
  53. elspais/graph/serialize.py +216 -0
  54. elspais/html/__init__.py +8 -0
  55. elspais/html/generator.py +731 -0
  56. elspais/html/templates/trace_view.html.j2 +2151 -0
  57. elspais/mcp/__init__.py +47 -29
  58. elspais/mcp/__main__.py +5 -1
  59. elspais/mcp/file_mutations.py +138 -0
  60. elspais/mcp/server.py +2016 -247
  61. elspais/testing/__init__.py +4 -4
  62. elspais/testing/config.py +3 -0
  63. elspais/testing/mapper.py +1 -1
  64. elspais/testing/result_parser.py +25 -21
  65. elspais/testing/scanner.py +301 -12
  66. elspais/utilities/__init__.py +1 -0
  67. elspais/utilities/docs_loader.py +115 -0
  68. elspais/utilities/git.py +607 -0
  69. elspais/{core → utilities}/hasher.py +8 -22
  70. elspais/utilities/md_renderer.py +189 -0
  71. elspais/{core → utilities}/patterns.py +58 -57
  72. elspais/utilities/reference_config.py +626 -0
  73. elspais/validation/__init__.py +19 -0
  74. elspais/validation/format.py +264 -0
  75. {elspais-0.11.1.dist-info → elspais-0.43.5.dist-info}/METADATA +7 -4
  76. elspais-0.43.5.dist-info/RECORD +80 -0
  77. elspais/config/defaults.py +0 -173
  78. elspais/config/loader.py +0 -494
  79. elspais/core/__init__.py +0 -21
  80. elspais/core/git.py +0 -352
  81. elspais/core/models.py +0 -320
  82. elspais/core/parser.py +0 -640
  83. elspais/core/rules.py +0 -514
  84. elspais/mcp/context.py +0 -171
  85. elspais/mcp/serializers.py +0 -112
  86. elspais/reformat/__init__.py +0 -50
  87. elspais/reformat/detector.py +0 -119
  88. elspais/reformat/hierarchy.py +0 -246
  89. elspais/reformat/line_breaks.py +0 -220
  90. elspais/reformat/prompts.py +0 -123
  91. elspais/reformat/transformer.py +0 -264
  92. elspais/trace_view/__init__.py +0 -54
  93. elspais/trace_view/coverage.py +0 -183
  94. elspais/trace_view/generators/__init__.py +0 -12
  95. elspais/trace_view/generators/base.py +0 -329
  96. elspais/trace_view/generators/csv.py +0 -122
  97. elspais/trace_view/generators/markdown.py +0 -175
  98. elspais/trace_view/html/__init__.py +0 -31
  99. elspais/trace_view/html/generator.py +0 -1006
  100. elspais/trace_view/html/templates/base.html +0 -283
  101. elspais/trace_view/html/templates/components/code_viewer_modal.html +0 -14
  102. elspais/trace_view/html/templates/components/file_picker_modal.html +0 -20
  103. elspais/trace_view/html/templates/components/legend_modal.html +0 -69
  104. elspais/trace_view/html/templates/components/review_panel.html +0 -118
  105. elspais/trace_view/html/templates/partials/review/help/help-panel.json +0 -244
  106. elspais/trace_view/html/templates/partials/review/help/onboarding.json +0 -77
  107. elspais/trace_view/html/templates/partials/review/help/tooltips.json +0 -237
  108. elspais/trace_view/html/templates/partials/review/review-comments.js +0 -928
  109. elspais/trace_view/html/templates/partials/review/review-data.js +0 -961
  110. elspais/trace_view/html/templates/partials/review/review-help.js +0 -679
  111. elspais/trace_view/html/templates/partials/review/review-init.js +0 -177
  112. elspais/trace_view/html/templates/partials/review/review-line-numbers.js +0 -429
  113. elspais/trace_view/html/templates/partials/review/review-packages.js +0 -1029
  114. elspais/trace_view/html/templates/partials/review/review-position.js +0 -540
  115. elspais/trace_view/html/templates/partials/review/review-resize.js +0 -115
  116. elspais/trace_view/html/templates/partials/review/review-status.js +0 -659
  117. elspais/trace_view/html/templates/partials/review/review-sync.js +0 -992
  118. elspais/trace_view/html/templates/partials/review-styles.css +0 -2238
  119. elspais/trace_view/html/templates/partials/scripts.js +0 -1741
  120. elspais/trace_view/html/templates/partials/styles.css +0 -1756
  121. elspais/trace_view/models.py +0 -353
  122. elspais/trace_view/review/__init__.py +0 -60
  123. elspais/trace_view/review/branches.py +0 -1149
  124. elspais/trace_view/review/models.py +0 -1205
  125. elspais/trace_view/review/position.py +0 -609
  126. elspais/trace_view/review/server.py +0 -1056
  127. elspais/trace_view/review/status.py +0 -470
  128. elspais/trace_view/review/storage.py +0 -1367
  129. elspais/trace_view/scanning.py +0 -213
  130. elspais/trace_view/specs/README.md +0 -84
  131. elspais/trace_view/specs/tv-d00001-template-architecture.md +0 -36
  132. elspais/trace_view/specs/tv-d00002-css-extraction.md +0 -37
  133. elspais/trace_view/specs/tv-d00003-js-extraction.md +0 -43
  134. elspais/trace_view/specs/tv-d00004-build-embedding.md +0 -40
  135. elspais/trace_view/specs/tv-d00005-test-format.md +0 -78
  136. elspais/trace_view/specs/tv-d00010-review-data-models.md +0 -33
  137. elspais/trace_view/specs/tv-d00011-review-storage.md +0 -33
  138. elspais/trace_view/specs/tv-d00012-position-resolution.md +0 -33
  139. elspais/trace_view/specs/tv-d00013-git-branches.md +0 -31
  140. elspais/trace_view/specs/tv-d00014-review-api-server.md +0 -31
  141. elspais/trace_view/specs/tv-d00015-status-modifier.md +0 -27
  142. elspais/trace_view/specs/tv-d00016-js-integration.md +0 -33
  143. elspais/trace_view/specs/tv-p00001-html-generator.md +0 -33
  144. elspais/trace_view/specs/tv-p00002-review-system.md +0 -29
  145. elspais-0.11.1.dist-info/RECORD +0 -101
  146. {elspais-0.11.1.dist-info → elspais-0.43.5.dist-info}/WHEEL +0 -0
  147. {elspais-0.11.1.dist-info → elspais-0.43.5.dist-info}/entry_points.txt +0 -0
  148. {elspais-0.11.1.dist-info → elspais-0.43.5.dist-info}/licenses/LICENSE +0 -0
elspais/cli.py CHANGED
@@ -10,7 +10,21 @@ 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
+ example_cmd,
19
+ hash_cmd,
20
+ health,
21
+ index,
22
+ init,
23
+ reformat_cmd,
24
+ rules_cmd,
25
+ trace,
26
+ validate,
27
+ )
14
28
 
15
29
 
16
30
  def create_parser() -> argparse.ArgumentParser:
@@ -28,8 +42,17 @@ Examples:
28
42
  elspais hash update # Update all requirement hashes
29
43
  elspais changed # Show uncommitted spec changes
30
44
  elspais analyze hierarchy # Show requirement hierarchy tree
31
- elspais config show # View current configuration
32
- elspais init # Create .elspais.toml configuration
45
+
46
+ Configuration:
47
+ elspais init # Create .elspais.toml in current directory
48
+ elspais config path # Show config file location
49
+ elspais config show # View all settings
50
+ elspais config --help # Configuration guide with examples
51
+
52
+ Documentation:
53
+ elspais example # Quick requirement format reference
54
+ elspais example --full # Full specification document
55
+ elspais completion # Shell tab-completion setup
33
56
 
34
57
  For detailed command help: elspais <command> --help
35
58
  """,
@@ -54,12 +77,14 @@ For detailed command help: elspais <command> --help
54
77
  metavar="PATH",
55
78
  )
56
79
  parser.add_argument(
57
- "-v", "--verbose",
80
+ "-v",
81
+ "--verbose",
58
82
  action="store_true",
59
83
  help="Verbose output",
60
84
  )
61
85
  parser.add_argument(
62
- "-q", "--quiet",
86
+ "-q",
87
+ "--quiet",
63
88
  action="store_true",
64
89
  help="Suppress non-error output",
65
90
  )
@@ -90,13 +115,12 @@ Common rules to skip:
90
115
  validate_parser.add_argument(
91
116
  "--fix",
92
117
  action="store_true",
93
- help="Auto-fix fixable issues",
118
+ help="Auto-fix issues that can be corrected programmatically (hashes, status)",
94
119
  )
95
120
  validate_parser.add_argument(
96
- "--core-repo",
97
- type=Path,
98
- help="Path to core repository (for associated repo validation)",
99
- metavar="PATH",
121
+ "--dry-run",
122
+ action="store_true",
123
+ help="Show what would be fixed without making changes (use with --fix)",
100
124
  )
101
125
  validate_parser.add_argument(
102
126
  "--skip-rule",
@@ -105,25 +129,64 @@ Common rules to skip:
105
129
  metavar="RULE",
106
130
  )
107
131
  validate_parser.add_argument(
108
- "-j", "--json",
132
+ "-j",
133
+ "--json",
109
134
  action="store_true",
110
135
  help="Output requirements as JSON (hht_diary compatible format)",
111
136
  )
112
- validate_parser.add_argument(
113
- "--tests",
137
+ # NOTE: --tests, --no-tests, --mode removed (dead code - never implemented)
138
+
139
+ # health command
140
+ health_parser = subparsers.add_parser(
141
+ "health",
142
+ help="Check repository and configuration health",
143
+ formatter_class=argparse.RawDescriptionHelpFormatter,
144
+ epilog="""
145
+ Examples:
146
+ elspais health # Run all health checks
147
+ elspais health --config # Check config only
148
+ elspais health --spec # Check spec files only
149
+ elspais health --code # Check code references only
150
+ elspais health --tests # Check test mappings only
151
+ elspais health -j # Output JSON for tooling
152
+ elspais health -v # Verbose output with details
153
+
154
+ Checks performed:
155
+ CONFIG: TOML syntax, required fields, pattern tokens, hierarchy rules, paths
156
+ SPEC: File parsing, duplicate IDs, reference resolution, orphans
157
+ CODE: Code→REQ reference validation, coverage statistics
158
+ TESTS: Test→REQ mappings, result status, coverage statistics
159
+ """,
160
+ )
161
+ health_parser.add_argument(
162
+ "--config",
163
+ dest="config_only",
114
164
  action="store_true",
115
- help="Force test scanning even if disabled in config",
165
+ help="Run configuration checks only",
116
166
  )
117
- validate_parser.add_argument(
118
- "--no-tests",
167
+ health_parser.add_argument(
168
+ "--spec",
169
+ dest="spec_only",
119
170
  action="store_true",
120
- help="Skip test scanning",
171
+ help="Run spec file checks only",
121
172
  )
122
- validate_parser.add_argument(
123
- "--mode",
124
- choices=["core", "combined"],
125
- default="combined",
126
- help="Scope: core (this repo only), combined (include sponsor repos)",
173
+ health_parser.add_argument(
174
+ "--code",
175
+ dest="code_only",
176
+ action="store_true",
177
+ help="Run code reference checks only",
178
+ )
179
+ health_parser.add_argument(
180
+ "--tests",
181
+ dest="tests_only",
182
+ action="store_true",
183
+ help="Run test mapping checks only",
184
+ )
185
+ health_parser.add_argument(
186
+ "-j",
187
+ "--json",
188
+ action="store_true",
189
+ help="Output as JSON",
127
190
  )
128
191
 
129
192
  # trace command
@@ -169,23 +232,19 @@ Common rules to skip:
169
232
  action="store_true",
170
233
  help="Start review server (requires trace-review extra)",
171
234
  )
235
+ # NOTE: --port, --mode, --sponsor, --graph removed (dead code - never implemented)
236
+ # Graph-based trace options
172
237
  trace_parser.add_argument(
173
- "--port",
174
- type=int,
175
- default=8080,
176
- help="Port for review server (default: 8080)",
177
- )
178
- trace_parser.add_argument(
179
- "--mode",
180
- choices=["core", "sponsor", "combined"],
181
- default="core",
182
- help="Report mode: core, sponsor, or combined (default: core)",
238
+ "--graph-json",
239
+ action="store_true",
240
+ help="Output graph structure as JSON",
183
241
  )
184
242
  trace_parser.add_argument(
185
- "--sponsor",
186
- help="Sponsor name for sponsor-specific reports",
187
- metavar="NAME",
243
+ "--report",
244
+ choices=["minimal", "standard", "full"],
245
+ help="Report preset to use (default: standard)",
188
246
  )
247
+ # NOTE: --depth removed (dead code - never implemented)
189
248
 
190
249
  # hash command
191
250
  hash_parser = subparsers.add_parser(
@@ -262,12 +321,14 @@ Common rules to skip:
262
321
  metavar="BRANCH",
263
322
  )
264
323
  changed_parser.add_argument(
265
- "-j", "--json",
324
+ "-j",
325
+ "--json",
266
326
  action="store_true",
267
327
  help="Output as JSON",
268
328
  )
269
329
  changed_parser.add_argument(
270
- "-a", "--all",
330
+ "-a",
331
+ "--all",
271
332
  action="store_true",
272
333
  help="Include all changed files (not just spec)",
273
334
  )
@@ -303,6 +364,38 @@ Common rules to skip:
303
364
  action="store_true",
304
365
  help="Overwrite existing configuration",
305
366
  )
367
+ init_parser.add_argument(
368
+ "--template",
369
+ action="store_true",
370
+ help="Create an example requirement file in spec/",
371
+ )
372
+
373
+ # example command
374
+ example_parser = subparsers.add_parser(
375
+ "example",
376
+ help="Display requirement format examples and templates",
377
+ formatter_class=argparse.RawDescriptionHelpFormatter,
378
+ epilog="""
379
+ Subcommands:
380
+ elspais example Quick reference (default)
381
+ elspais example requirement Full requirement template with all sections
382
+ elspais example journey User journey template
383
+ elspais example assertion Assertion rules and examples
384
+ elspais example ids Show ID patterns from current config
385
+ elspais example --full Display spec/requirements-spec.md (if exists)
386
+ """,
387
+ )
388
+ example_parser.add_argument(
389
+ "example_type",
390
+ nargs="?",
391
+ choices=["requirement", "journey", "assertion", "ids"],
392
+ help="Example type to display",
393
+ )
394
+ example_parser.add_argument(
395
+ "--full",
396
+ action="store_true",
397
+ help="Display the full requirements specification file",
398
+ )
306
399
 
307
400
  # edit command
308
401
  edit_parser = subparsers.add_parser(
@@ -317,7 +410,7 @@ Examples:
317
410
  elspais edit --from-json edits.json
318
411
 
319
412
  JSON batch format:
320
- {"edits": [{"req_id": "...", "status": "...", "implements": [...]}]}
413
+ [{"req_id": "...", "status": "...", "implements": [...]}]
321
414
  """,
322
415
  )
323
416
  edit_parser.add_argument(
@@ -360,6 +453,39 @@ JSON batch format:
360
453
  config_parser = subparsers.add_parser(
361
454
  "config",
362
455
  help="View and modify configuration (show, get, set, ...)",
456
+ formatter_class=argparse.RawDescriptionHelpFormatter,
457
+ epilog="""
458
+ Configuration File:
459
+ elspais looks for .elspais.toml in the current directory or parent directories.
460
+ Create one with: elspais init
461
+
462
+ Location: elspais config path
463
+ View all: elspais config show
464
+
465
+ Quick Start (.elspais.toml):
466
+ [project]
467
+ name = "my-project"
468
+ spec_dir = "spec" # Where requirement files live
469
+
470
+ [patterns]
471
+ prefix = "REQ" # Requirement ID prefix
472
+ separator = "-" # ID separator (REQ-p00001)
473
+
474
+ [rules]
475
+ strict_mode = false # Strict implements semantics
476
+
477
+ [rules.hierarchy]
478
+ allowed = ["dev -> ops, prd", "ops -> prd"]
479
+
480
+ Common Commands:
481
+ elspais config show # View current config
482
+ elspais config get patterns.prefix
483
+ elspais config set project.name "MyApp"
484
+ elspais config path # Show config file location
485
+
486
+ Full Documentation:
487
+ See docs/configuration.md for all options.
488
+ """,
363
489
  )
364
490
  config_subparsers = config_parser.add_subparsers(dest="config_action")
365
491
 
@@ -374,7 +500,8 @@ JSON batch format:
374
500
  metavar="SECTION",
375
501
  )
376
502
  config_show.add_argument(
377
- "-j", "--json",
503
+ "-j",
504
+ "--json",
378
505
  action="store_true",
379
506
  help="Output as JSON",
380
507
  )
@@ -389,7 +516,8 @@ JSON batch format:
389
516
  help="Configuration key (dot-notation, e.g., 'patterns.prefix')",
390
517
  )
391
518
  config_get.add_argument(
392
- "-j", "--json",
519
+ "-j",
520
+ "--json",
393
521
  action="store_true",
394
522
  help="Output as JSON",
395
523
  )
@@ -405,7 +533,7 @@ JSON batch format:
405
533
  )
406
534
  config_set.add_argument(
407
535
  "value",
408
- help="Value to set (type auto-detected: true/false, numbers, JSON arrays/objects, or string)",
536
+ help="Value to set (auto-detected: bool, number, JSON array/object, string)",
409
537
  )
410
538
 
411
539
  # config unset
@@ -475,51 +603,105 @@ JSON batch format:
475
603
  help="Content rule file name (e.g., 'AI-AGENT.md')",
476
604
  )
477
605
 
478
- # reformat-with-claude command
479
- reformat_parser = subparsers.add_parser(
606
+ # reformat-with-claude command (NOT YET IMPLEMENTED - placeholder for future feature)
607
+ subparsers.add_parser(
480
608
  "reformat-with-claude",
481
- help="Reformat requirements using AI (Acceptance Criteria -> Assertions)",
609
+ help="[NOT IMPLEMENTED] Reformat requirements using AI (Acceptance Criteria -> Assertions)",
482
610
  )
483
- reformat_parser.add_argument(
484
- "--start-req",
485
- help="Starting requirement ID (default: all PRD requirements)",
486
- metavar="ID",
487
- )
488
- reformat_parser.add_argument(
489
- "--depth",
490
- type=int,
491
- help="Maximum traversal depth (default: unlimited)",
492
- )
493
- reformat_parser.add_argument(
494
- "--dry-run",
495
- action="store_true",
496
- help="Preview changes without applying",
497
- )
498
- reformat_parser.add_argument(
499
- "--backup",
500
- action="store_true",
501
- help="Create .bak files before editing",
611
+ # NOTE: All arguments removed - command not yet implemented
612
+ # See src/elspais/commands/reformat_cmd.py for planned features
613
+
614
+ # docs command - comprehensive user documentation
615
+ docs_parser = subparsers.add_parser(
616
+ "docs",
617
+ help="Read the user guide (topics: quickstart, format, hierarchy, ...)",
618
+ formatter_class=argparse.RawDescriptionHelpFormatter,
619
+ epilog="""
620
+ Available Topics:
621
+ quickstart Getting started with elspais (default)
622
+ format Requirement file format and structure
623
+ hierarchy PRD → OPS → DEV levels and implements
624
+ assertions Writing testable assertions with SHALL
625
+ traceability Linking requirements to code and tests
626
+ validation Running validation and fixing issues
627
+ git Change detection and git integration
628
+ config Configuration file reference
629
+ mcp MCP server for AI integration
630
+ all Show complete documentation
631
+
632
+ Examples:
633
+ elspais docs # Quick start guide
634
+ elspais docs format # Requirement format reference
635
+ elspais docs all # Complete documentation
636
+ elspais docs all --no-pager # Disable pager
637
+ """,
502
638
  )
503
- reformat_parser.add_argument(
504
- "--force",
639
+ docs_parser.add_argument(
640
+ "topic",
641
+ nargs="?",
642
+ default="quickstart",
643
+ choices=[
644
+ "quickstart",
645
+ "format",
646
+ "hierarchy",
647
+ "assertions",
648
+ "traceability",
649
+ "validation",
650
+ "git",
651
+ "config",
652
+ "commands",
653
+ "health",
654
+ "mcp",
655
+ "all",
656
+ ],
657
+ help="Documentation topic (default: quickstart)",
658
+ )
659
+ docs_parser.add_argument(
660
+ "--plain",
505
661
  action="store_true",
506
- help="Reformat even if already in new format",
662
+ help="Plain text output (no ANSI colors)",
507
663
  )
508
- reformat_parser.add_argument(
509
- "--fix-line-breaks",
664
+ docs_parser.add_argument(
665
+ "--no-pager",
510
666
  action="store_true",
511
- help="Normalize line breaks (remove extra blank lines)",
667
+ help="Disable paging (print directly to stdout)",
512
668
  )
513
- reformat_parser.add_argument(
514
- "--line-breaks-only",
515
- action="store_true",
516
- help="Only fix line breaks, skip AI-based reformatting",
669
+
670
+ # completion command - shell tab-completion setup
671
+ completion_parser = subparsers.add_parser(
672
+ "completion",
673
+ help="Generate shell tab-completion scripts",
674
+ formatter_class=argparse.RawDescriptionHelpFormatter,
675
+ epilog="""
676
+ Shell Completion Setup:
677
+
678
+ First, install the completion extra:
679
+ pip install elspais[completion]
680
+
681
+ Bash (add to ~/.bashrc):
682
+ eval "$(register-python-argcomplete elspais)"
683
+
684
+ Zsh (add to ~/.zshrc):
685
+ autoload -U bashcompinit
686
+ bashcompinit
687
+ eval "$(register-python-argcomplete elspais)"
688
+
689
+ Fish (add to ~/.config/fish/config.fish):
690
+ register-python-argcomplete --shell fish elspais | source
691
+
692
+ Tcsh (add to ~/.tcshrc):
693
+ eval `register-python-argcomplete --shell tcsh elspais`
694
+
695
+ Global activation (for all argcomplete-enabled tools):
696
+ activate-global-python-argcomplete
697
+
698
+ After adding the appropriate line, restart your shell or source the config file.
699
+ """,
517
700
  )
518
- reformat_parser.add_argument(
519
- "--mode",
520
- choices=["combined", "core-only", "local-only"],
521
- default="combined",
522
- help="Which repos to include in hierarchy (default: combined)",
701
+ completion_parser.add_argument(
702
+ "--shell",
703
+ choices=["bash", "zsh", "fish", "tcsh"],
704
+ help="Generate script for specific shell",
523
705
  )
524
706
 
525
707
  # mcp command
@@ -587,6 +769,17 @@ def main(argv: Optional[List[str]] = None) -> int:
587
769
  Exit code (0 for success, non-zero for failure)
588
770
  """
589
771
  parser = create_parser()
772
+
773
+ # Enable shell tab-completion if argcomplete is installed
774
+ # Install with: pip install elspais[completion]
775
+ # Then activate: eval "$(register-python-argcomplete elspais)"
776
+ try:
777
+ import argcomplete
778
+
779
+ argcomplete.autocomplete(parser)
780
+ except ImportError:
781
+ pass
782
+
590
783
  args = parser.parse_args(argv)
591
784
 
592
785
  # Handle no command
@@ -594,10 +787,28 @@ def main(argv: Optional[List[str]] = None) -> int:
594
787
  parser.print_help()
595
788
  return 0
596
789
 
790
+ # Auto-detect git repository root and change to it
791
+ # This ensures elspais works the same from any subdirectory
792
+ import os
793
+
794
+ from elspais.config import find_git_root
795
+
796
+ original_cwd = Path.cwd()
797
+ git_root = find_git_root(original_cwd)
798
+
799
+ if git_root and git_root != original_cwd:
800
+ os.chdir(git_root)
801
+ if args.verbose:
802
+ print(f"Working from repository root: {git_root}", file=sys.stderr)
803
+ elif not git_root and args.verbose:
804
+ print("Warning: Not in a git repository", file=sys.stderr)
805
+
597
806
  try:
598
807
  # Dispatch to command handlers
599
808
  if args.command == "validate":
600
809
  return validate.run(args)
810
+ elif args.command == "health":
811
+ return health.run(args)
601
812
  elif args.command == "trace":
602
813
  return trace.run(args)
603
814
  elif args.command == "hash":
@@ -612,6 +823,8 @@ def main(argv: Optional[List[str]] = None) -> int:
612
823
  return version_command(args)
613
824
  elif args.command == "init":
614
825
  return init.run(args)
826
+ elif args.command == "example":
827
+ return example_cmd.run(args)
615
828
  elif args.command == "edit":
616
829
  return edit.run(args)
617
830
  elif args.command == "config":
@@ -620,6 +833,10 @@ def main(argv: Optional[List[str]] = None) -> int:
620
833
  return rules_cmd.run(args)
621
834
  elif args.command == "reformat-with-claude":
622
835
  return reformat_cmd.run(args)
836
+ elif args.command == "docs":
837
+ return docs_command(args)
838
+ elif args.command == "completion":
839
+ return completion_command(args)
623
840
  elif args.command == "mcp":
624
841
  return mcp_command(args)
625
842
  else:
@@ -636,6 +853,105 @@ def main(argv: Optional[List[str]] = None) -> int:
636
853
  return 1
637
854
 
638
855
 
856
+ def docs_command(args: argparse.Namespace) -> int:
857
+ """Handle docs command - display user documentation from markdown files."""
858
+ import pydoc
859
+
860
+ from elspais.utilities.docs_loader import load_all_topics, load_topic
861
+ from elspais.utilities.md_renderer import render_markdown
862
+
863
+ topic = args.topic
864
+ use_pager = not args.no_pager and sys.stdout.isatty()
865
+ use_color = not args.plain and sys.stdout.isatty()
866
+
867
+ # Load content from markdown files
868
+ if topic == "all":
869
+ content = load_all_topics()
870
+ else:
871
+ content = load_topic(topic)
872
+
873
+ if content is None:
874
+ print(f"Error: Documentation not found for topic '{topic}'", file=sys.stderr)
875
+ print("Documentation files may not be installed correctly.", file=sys.stderr)
876
+ return 1
877
+
878
+ # Render markdown to ANSI and display
879
+ output = render_markdown(content, use_color=use_color)
880
+
881
+ if use_pager:
882
+ pydoc.pager(output)
883
+ else:
884
+ print(output)
885
+
886
+ return 0
887
+
888
+
889
+ def completion_command(args: argparse.Namespace) -> int:
890
+ """Handle completion command - generate shell completion scripts."""
891
+ import importlib.util
892
+
893
+ if importlib.util.find_spec("argcomplete") is None:
894
+ print("Error: argcomplete not installed.", file=sys.stderr)
895
+ print("Install with: pip install elspais[completion]", file=sys.stderr)
896
+ return 1
897
+
898
+ shell = args.shell
899
+
900
+ if shell:
901
+ # Generate script for specific shell
902
+ import subprocess
903
+
904
+ shell_flag = f"--shell={shell}" if shell in ("fish", "tcsh") else ""
905
+ cmd = ["register-python-argcomplete"]
906
+ if shell_flag:
907
+ cmd.append(shell_flag)
908
+ cmd.append("elspais")
909
+
910
+ try:
911
+ result = subprocess.run(cmd, capture_output=True, text=True)
912
+ if result.returncode == 0:
913
+ print(result.stdout)
914
+ else:
915
+ print(f"Error generating completion script: {result.stderr}", file=sys.stderr)
916
+ return 1
917
+ except FileNotFoundError:
918
+ print("Error: register-python-argcomplete not found.", file=sys.stderr)
919
+ print("Make sure argcomplete is properly installed.", file=sys.stderr)
920
+ return 1
921
+ else:
922
+ # Show setup instructions
923
+ print(
924
+ """
925
+ Shell Completion Setup for elspais
926
+ ===================================
927
+
928
+ Bash (add to ~/.bashrc):
929
+ eval "$(register-python-argcomplete elspais)"
930
+
931
+ Zsh (add to ~/.zshrc):
932
+ autoload -U bashcompinit
933
+ bashcompinit
934
+ eval "$(register-python-argcomplete elspais)"
935
+
936
+ Fish (add to ~/.config/fish/config.fish):
937
+ register-python-argcomplete --shell fish elspais | source
938
+
939
+ Tcsh (add to ~/.tcshrc):
940
+ eval `register-python-argcomplete --shell tcsh elspais`
941
+
942
+ Generate script for a specific shell:
943
+ elspais completion --shell bash
944
+ elspais completion --shell zsh
945
+ elspais completion --shell fish
946
+ elspais completion --shell tcsh
947
+
948
+ After adding the line, restart your shell or source the config file.
949
+ """
950
+ )
951
+
952
+ return 0
953
+
954
+
639
955
  def version_command(args: argparse.Namespace) -> int:
640
956
  """Handle version command."""
641
957
  print(f"elspais {__version__}")
@@ -662,7 +978,7 @@ def mcp_command(args: argparse.Namespace) -> int:
662
978
  if hasattr(args, "spec_dir") and args.spec_dir:
663
979
  working_dir = args.spec_dir.parent
664
980
 
665
- print(f"Starting elspais MCP server...")
981
+ print("Starting elspais MCP server...")
666
982
  print(f"Working directory: {working_dir}")
667
983
  print(f"Transport: {args.transport}")
668
984
 
@@ -3,10 +3,16 @@ elspais.commands - CLI command implementations
3
3
  """
4
4
 
5
5
  __all__ = [
6
- "validate",
7
- "trace",
6
+ "analyze",
7
+ "changed",
8
+ "config_cmd",
9
+ "edit",
10
+ "example_cmd",
8
11
  "hash_cmd",
9
12
  "index",
10
- "analyze",
11
13
  "init",
14
+ "reformat_cmd",
15
+ "rules_cmd",
16
+ "trace",
17
+ "validate",
12
18
  ]