elspais 0.9.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- elspais/__init__.py +36 -0
- elspais/__main__.py +8 -0
- elspais/cli.py +525 -0
- elspais/commands/__init__.py +12 -0
- elspais/commands/analyze.py +218 -0
- elspais/commands/config_cmd.py +501 -0
- elspais/commands/edit.py +522 -0
- elspais/commands/hash_cmd.py +174 -0
- elspais/commands/index.py +166 -0
- elspais/commands/init.py +177 -0
- elspais/commands/rules_cmd.py +120 -0
- elspais/commands/trace.py +208 -0
- elspais/commands/validate.py +388 -0
- elspais/config/__init__.py +13 -0
- elspais/config/defaults.py +173 -0
- elspais/config/loader.py +494 -0
- elspais/core/__init__.py +21 -0
- elspais/core/content_rules.py +170 -0
- elspais/core/hasher.py +143 -0
- elspais/core/models.py +318 -0
- elspais/core/parser.py +596 -0
- elspais/core/patterns.py +390 -0
- elspais/core/rules.py +514 -0
- elspais/mcp/__init__.py +42 -0
- elspais/mcp/__main__.py +6 -0
- elspais/mcp/context.py +171 -0
- elspais/mcp/serializers.py +112 -0
- elspais/mcp/server.py +339 -0
- elspais/testing/__init__.py +27 -0
- elspais/testing/config.py +48 -0
- elspais/testing/mapper.py +163 -0
- elspais/testing/result_parser.py +289 -0
- elspais/testing/scanner.py +206 -0
- elspais-0.9.1.dist-info/METADATA +393 -0
- elspais-0.9.1.dist-info/RECORD +38 -0
- elspais-0.9.1.dist-info/WHEEL +4 -0
- elspais-0.9.1.dist-info/entry_points.txt +2 -0
- elspais-0.9.1.dist-info/licenses/LICENSE +21 -0
elspais/__init__.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
elspais - Requirements validation and traceability tools
|
|
3
|
+
|
|
4
|
+
L-Space is the ultimate library, connecting all libraries everywhere
|
|
5
|
+
through the sheer weight of accumulated knowledge.
|
|
6
|
+
— Terry Pratchett
|
|
7
|
+
|
|
8
|
+
elspais validates requirement formats, generates traceability matrices,
|
|
9
|
+
and supports multi-repository requirement management with configurable
|
|
10
|
+
ID patterns and validation rules.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
__version__ = version("elspais")
|
|
17
|
+
except PackageNotFoundError:
|
|
18
|
+
__version__ = "0.0.0+unknown" # Not installed
|
|
19
|
+
__author__ = "Anspar"
|
|
20
|
+
__license__ = "MIT"
|
|
21
|
+
|
|
22
|
+
from elspais.core.models import Assertion, ContentRule, ParsedRequirement, Requirement
|
|
23
|
+
from elspais.core.patterns import PatternValidator
|
|
24
|
+
from elspais.core.rules import RuleEngine, RuleViolation, Severity
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"__version__",
|
|
28
|
+
"Assertion",
|
|
29
|
+
"ContentRule",
|
|
30
|
+
"Requirement",
|
|
31
|
+
"ParsedRequirement",
|
|
32
|
+
"PatternValidator",
|
|
33
|
+
"RuleEngine",
|
|
34
|
+
"RuleViolation",
|
|
35
|
+
"Severity",
|
|
36
|
+
]
|
elspais/__main__.py
ADDED
elspais/cli.py
ADDED
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
"""
|
|
2
|
+
elspais.cli - Command-line interface.
|
|
3
|
+
|
|
4
|
+
Main entry point for the elspais CLI tool.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import List, Optional
|
|
11
|
+
|
|
12
|
+
from elspais import __version__
|
|
13
|
+
from elspais.commands import analyze, config_cmd, edit, hash_cmd, index, init, rules_cmd, trace, validate
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def create_parser() -> argparse.ArgumentParser:
|
|
17
|
+
"""Create the argument parser."""
|
|
18
|
+
parser = argparse.ArgumentParser(
|
|
19
|
+
prog="elspais",
|
|
20
|
+
description="Requirements validation and traceability tools (L-Space)",
|
|
21
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
22
|
+
epilog="""
|
|
23
|
+
Examples:
|
|
24
|
+
elspais validate # Validate all requirements
|
|
25
|
+
elspais trace --format html # Generate HTML traceability matrix
|
|
26
|
+
elspais hash update # Update all requirement hashes
|
|
27
|
+
elspais init # Create .elspais.toml configuration
|
|
28
|
+
""",
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Global options
|
|
32
|
+
parser.add_argument(
|
|
33
|
+
"--version",
|
|
34
|
+
action="version",
|
|
35
|
+
version=f"elspais {__version__}",
|
|
36
|
+
)
|
|
37
|
+
parser.add_argument(
|
|
38
|
+
"--config",
|
|
39
|
+
type=Path,
|
|
40
|
+
help="Path to configuration file",
|
|
41
|
+
metavar="PATH",
|
|
42
|
+
)
|
|
43
|
+
parser.add_argument(
|
|
44
|
+
"--spec-dir",
|
|
45
|
+
type=Path,
|
|
46
|
+
help="Override spec directory",
|
|
47
|
+
metavar="PATH",
|
|
48
|
+
)
|
|
49
|
+
parser.add_argument(
|
|
50
|
+
"-v", "--verbose",
|
|
51
|
+
action="store_true",
|
|
52
|
+
help="Verbose output",
|
|
53
|
+
)
|
|
54
|
+
parser.add_argument(
|
|
55
|
+
"-q", "--quiet",
|
|
56
|
+
action="store_true",
|
|
57
|
+
help="Suppress non-error output",
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# Subcommands
|
|
61
|
+
subparsers = parser.add_subparsers(dest="command", help="Available commands")
|
|
62
|
+
|
|
63
|
+
# validate command
|
|
64
|
+
validate_parser = subparsers.add_parser(
|
|
65
|
+
"validate",
|
|
66
|
+
help="Validate requirements format, links, and hashes",
|
|
67
|
+
)
|
|
68
|
+
validate_parser.add_argument(
|
|
69
|
+
"--fix",
|
|
70
|
+
action="store_true",
|
|
71
|
+
help="Auto-fix fixable issues",
|
|
72
|
+
)
|
|
73
|
+
validate_parser.add_argument(
|
|
74
|
+
"--core-repo",
|
|
75
|
+
type=Path,
|
|
76
|
+
help="Path to core repository (for associated repo validation)",
|
|
77
|
+
metavar="PATH",
|
|
78
|
+
)
|
|
79
|
+
validate_parser.add_argument(
|
|
80
|
+
"--skip-rule",
|
|
81
|
+
action="append",
|
|
82
|
+
help="Skip specific validation rules",
|
|
83
|
+
metavar="RULE",
|
|
84
|
+
)
|
|
85
|
+
validate_parser.add_argument(
|
|
86
|
+
"-j", "--json",
|
|
87
|
+
action="store_true",
|
|
88
|
+
help="Output requirements as JSON (hht_diary compatible format)",
|
|
89
|
+
)
|
|
90
|
+
validate_parser.add_argument(
|
|
91
|
+
"--tests",
|
|
92
|
+
action="store_true",
|
|
93
|
+
help="Force test scanning even if disabled in config",
|
|
94
|
+
)
|
|
95
|
+
validate_parser.add_argument(
|
|
96
|
+
"--no-tests",
|
|
97
|
+
action="store_true",
|
|
98
|
+
help="Skip test scanning",
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# trace command
|
|
102
|
+
trace_parser = subparsers.add_parser(
|
|
103
|
+
"trace",
|
|
104
|
+
help="Generate traceability matrix",
|
|
105
|
+
)
|
|
106
|
+
trace_parser.add_argument(
|
|
107
|
+
"--format",
|
|
108
|
+
choices=["markdown", "html", "csv", "both"],
|
|
109
|
+
default="both",
|
|
110
|
+
help="Output format (default: both)",
|
|
111
|
+
)
|
|
112
|
+
trace_parser.add_argument(
|
|
113
|
+
"--output",
|
|
114
|
+
type=Path,
|
|
115
|
+
help="Output file path",
|
|
116
|
+
metavar="PATH",
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# hash command
|
|
120
|
+
hash_parser = subparsers.add_parser(
|
|
121
|
+
"hash",
|
|
122
|
+
help="Manage requirement hashes",
|
|
123
|
+
)
|
|
124
|
+
hash_subparsers = hash_parser.add_subparsers(dest="hash_action")
|
|
125
|
+
|
|
126
|
+
hash_subparsers.add_parser(
|
|
127
|
+
"verify",
|
|
128
|
+
help="Verify hashes without changes",
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
hash_update = hash_subparsers.add_parser(
|
|
132
|
+
"update",
|
|
133
|
+
help="Update hashes",
|
|
134
|
+
)
|
|
135
|
+
hash_update.add_argument(
|
|
136
|
+
"req_id",
|
|
137
|
+
nargs="?",
|
|
138
|
+
help="Specific requirement ID to update",
|
|
139
|
+
)
|
|
140
|
+
hash_update.add_argument(
|
|
141
|
+
"--dry-run",
|
|
142
|
+
action="store_true",
|
|
143
|
+
help="Show changes without applying",
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# index command
|
|
147
|
+
index_parser = subparsers.add_parser(
|
|
148
|
+
"index",
|
|
149
|
+
help="Manage INDEX.md file",
|
|
150
|
+
)
|
|
151
|
+
index_subparsers = index_parser.add_subparsers(dest="index_action")
|
|
152
|
+
|
|
153
|
+
index_subparsers.add_parser(
|
|
154
|
+
"validate",
|
|
155
|
+
help="Validate INDEX.md accuracy",
|
|
156
|
+
)
|
|
157
|
+
index_subparsers.add_parser(
|
|
158
|
+
"regenerate",
|
|
159
|
+
help="Regenerate INDEX.md from scratch",
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
# analyze command
|
|
163
|
+
analyze_parser = subparsers.add_parser(
|
|
164
|
+
"analyze",
|
|
165
|
+
help="Analyze requirement hierarchy",
|
|
166
|
+
)
|
|
167
|
+
analyze_subparsers = analyze_parser.add_subparsers(dest="analyze_action")
|
|
168
|
+
|
|
169
|
+
analyze_subparsers.add_parser(
|
|
170
|
+
"hierarchy",
|
|
171
|
+
help="Show requirement hierarchy tree",
|
|
172
|
+
)
|
|
173
|
+
analyze_subparsers.add_parser(
|
|
174
|
+
"orphans",
|
|
175
|
+
help="Find orphaned requirements",
|
|
176
|
+
)
|
|
177
|
+
analyze_subparsers.add_parser(
|
|
178
|
+
"coverage",
|
|
179
|
+
help="Implementation coverage report",
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# version command
|
|
183
|
+
version_parser = subparsers.add_parser(
|
|
184
|
+
"version",
|
|
185
|
+
help="Show version and check for updates",
|
|
186
|
+
)
|
|
187
|
+
version_parser.add_argument(
|
|
188
|
+
"check",
|
|
189
|
+
nargs="?",
|
|
190
|
+
help="Check for updates",
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
# init command
|
|
194
|
+
init_parser = subparsers.add_parser(
|
|
195
|
+
"init",
|
|
196
|
+
help="Create .elspais.toml configuration",
|
|
197
|
+
)
|
|
198
|
+
init_parser.add_argument(
|
|
199
|
+
"--type",
|
|
200
|
+
choices=["core", "associated"],
|
|
201
|
+
help="Repository type",
|
|
202
|
+
)
|
|
203
|
+
init_parser.add_argument(
|
|
204
|
+
"--associated-prefix",
|
|
205
|
+
help="Associated repo prefix (e.g., CAL)",
|
|
206
|
+
metavar="PREFIX",
|
|
207
|
+
)
|
|
208
|
+
init_parser.add_argument(
|
|
209
|
+
"--force",
|
|
210
|
+
action="store_true",
|
|
211
|
+
help="Overwrite existing configuration",
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
# edit command
|
|
215
|
+
edit_parser = subparsers.add_parser(
|
|
216
|
+
"edit",
|
|
217
|
+
help="Edit requirements in-place (implements, status, move)",
|
|
218
|
+
)
|
|
219
|
+
edit_parser.add_argument(
|
|
220
|
+
"--req-id",
|
|
221
|
+
help="Requirement ID to edit",
|
|
222
|
+
metavar="ID",
|
|
223
|
+
)
|
|
224
|
+
edit_parser.add_argument(
|
|
225
|
+
"--implements",
|
|
226
|
+
help="New Implements value (comma-separated, empty string to clear)",
|
|
227
|
+
metavar="REFS",
|
|
228
|
+
)
|
|
229
|
+
edit_parser.add_argument(
|
|
230
|
+
"--status",
|
|
231
|
+
help="New Status value",
|
|
232
|
+
metavar="STATUS",
|
|
233
|
+
)
|
|
234
|
+
edit_parser.add_argument(
|
|
235
|
+
"--move-to",
|
|
236
|
+
help="Move requirement to file (relative to spec dir)",
|
|
237
|
+
metavar="FILE",
|
|
238
|
+
)
|
|
239
|
+
edit_parser.add_argument(
|
|
240
|
+
"--from-json",
|
|
241
|
+
help="Batch edit from JSON file (- for stdin)",
|
|
242
|
+
metavar="FILE",
|
|
243
|
+
)
|
|
244
|
+
edit_parser.add_argument(
|
|
245
|
+
"--dry-run",
|
|
246
|
+
action="store_true",
|
|
247
|
+
help="Show changes without applying",
|
|
248
|
+
)
|
|
249
|
+
edit_parser.add_argument(
|
|
250
|
+
"--validate-refs",
|
|
251
|
+
action="store_true",
|
|
252
|
+
help="Validate that implements references exist",
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
# config command
|
|
256
|
+
config_parser = subparsers.add_parser(
|
|
257
|
+
"config",
|
|
258
|
+
help="View and modify configuration",
|
|
259
|
+
)
|
|
260
|
+
config_subparsers = config_parser.add_subparsers(dest="config_action")
|
|
261
|
+
|
|
262
|
+
# config show
|
|
263
|
+
config_show = config_subparsers.add_parser(
|
|
264
|
+
"show",
|
|
265
|
+
help="Show current configuration",
|
|
266
|
+
)
|
|
267
|
+
config_show.add_argument(
|
|
268
|
+
"--section",
|
|
269
|
+
help="Show only a specific section (e.g., 'patterns', 'rules.format')",
|
|
270
|
+
metavar="SECTION",
|
|
271
|
+
)
|
|
272
|
+
config_show.add_argument(
|
|
273
|
+
"-j", "--json",
|
|
274
|
+
action="store_true",
|
|
275
|
+
help="Output as JSON",
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
# config get
|
|
279
|
+
config_get = config_subparsers.add_parser(
|
|
280
|
+
"get",
|
|
281
|
+
help="Get a configuration value",
|
|
282
|
+
)
|
|
283
|
+
config_get.add_argument(
|
|
284
|
+
"key",
|
|
285
|
+
help="Configuration key (dot-notation, e.g., 'patterns.prefix')",
|
|
286
|
+
)
|
|
287
|
+
config_get.add_argument(
|
|
288
|
+
"-j", "--json",
|
|
289
|
+
action="store_true",
|
|
290
|
+
help="Output as JSON",
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
# config set
|
|
294
|
+
config_set = config_subparsers.add_parser(
|
|
295
|
+
"set",
|
|
296
|
+
help="Set a configuration value",
|
|
297
|
+
)
|
|
298
|
+
config_set.add_argument(
|
|
299
|
+
"key",
|
|
300
|
+
help="Configuration key (dot-notation, e.g., 'patterns.prefix')",
|
|
301
|
+
)
|
|
302
|
+
config_set.add_argument(
|
|
303
|
+
"value",
|
|
304
|
+
help="Value to set (type auto-detected: true/false, numbers, JSON arrays/objects, or string)",
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
# config unset
|
|
308
|
+
config_unset = config_subparsers.add_parser(
|
|
309
|
+
"unset",
|
|
310
|
+
help="Remove a configuration key",
|
|
311
|
+
)
|
|
312
|
+
config_unset.add_argument(
|
|
313
|
+
"key",
|
|
314
|
+
help="Configuration key to remove",
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
# config add
|
|
318
|
+
config_add = config_subparsers.add_parser(
|
|
319
|
+
"add",
|
|
320
|
+
help="Add a value to an array configuration",
|
|
321
|
+
)
|
|
322
|
+
config_add.add_argument(
|
|
323
|
+
"key",
|
|
324
|
+
help="Configuration key for array (e.g., 'directories.code')",
|
|
325
|
+
)
|
|
326
|
+
config_add.add_argument(
|
|
327
|
+
"value",
|
|
328
|
+
help="Value to add to the array",
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
# config remove
|
|
332
|
+
config_remove = config_subparsers.add_parser(
|
|
333
|
+
"remove",
|
|
334
|
+
help="Remove a value from an array configuration",
|
|
335
|
+
)
|
|
336
|
+
config_remove.add_argument(
|
|
337
|
+
"key",
|
|
338
|
+
help="Configuration key for array (e.g., 'directories.code')",
|
|
339
|
+
)
|
|
340
|
+
config_remove.add_argument(
|
|
341
|
+
"value",
|
|
342
|
+
help="Value to remove from the array",
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
# config path
|
|
346
|
+
config_subparsers.add_parser(
|
|
347
|
+
"path",
|
|
348
|
+
help="Show path to configuration file",
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
# rules command
|
|
352
|
+
rules_parser = subparsers.add_parser(
|
|
353
|
+
"rules",
|
|
354
|
+
help="View and manage content rules",
|
|
355
|
+
)
|
|
356
|
+
rules_subparsers = rules_parser.add_subparsers(dest="rules_action")
|
|
357
|
+
|
|
358
|
+
# rules list
|
|
359
|
+
rules_subparsers.add_parser(
|
|
360
|
+
"list",
|
|
361
|
+
help="List configured content rules",
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
# rules show
|
|
365
|
+
rules_show = rules_subparsers.add_parser(
|
|
366
|
+
"show",
|
|
367
|
+
help="Show content of a content rule file",
|
|
368
|
+
)
|
|
369
|
+
rules_show.add_argument(
|
|
370
|
+
"file",
|
|
371
|
+
help="Content rule file name (e.g., 'AI-AGENT.md')",
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
# mcp command
|
|
375
|
+
mcp_parser = subparsers.add_parser(
|
|
376
|
+
"mcp",
|
|
377
|
+
help="MCP server commands (requires elspais[mcp])",
|
|
378
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
379
|
+
epilog="""
|
|
380
|
+
Claude Code Configuration:
|
|
381
|
+
Add to ~/.claude/claude_desktop_config.json:
|
|
382
|
+
|
|
383
|
+
{
|
|
384
|
+
"mcpServers": {
|
|
385
|
+
"elspais": {
|
|
386
|
+
"command": "elspais",
|
|
387
|
+
"args": ["mcp", "serve"],
|
|
388
|
+
"cwd": "/path/to/your/project"
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
Set "cwd" to the directory containing your .elspais.toml config.
|
|
394
|
+
|
|
395
|
+
Resources:
|
|
396
|
+
requirements://all List all requirements
|
|
397
|
+
requirements://{id} Get requirement details
|
|
398
|
+
requirements://level/{level} Filter by PRD/OPS/DEV
|
|
399
|
+
content-rules://list List content rules
|
|
400
|
+
content-rules://{file} Get content rule content
|
|
401
|
+
config://current Current configuration
|
|
402
|
+
|
|
403
|
+
Tools:
|
|
404
|
+
validate Run validation rules
|
|
405
|
+
parse_requirement Parse requirement text
|
|
406
|
+
search Search requirements by pattern
|
|
407
|
+
get_requirement Get requirement details
|
|
408
|
+
analyze Analyze hierarchy/orphans/coverage
|
|
409
|
+
""",
|
|
410
|
+
)
|
|
411
|
+
mcp_subparsers = mcp_parser.add_subparsers(dest="mcp_action")
|
|
412
|
+
|
|
413
|
+
# mcp serve
|
|
414
|
+
mcp_serve = mcp_subparsers.add_parser(
|
|
415
|
+
"serve",
|
|
416
|
+
help="Start MCP server",
|
|
417
|
+
)
|
|
418
|
+
mcp_serve.add_argument(
|
|
419
|
+
"--transport",
|
|
420
|
+
choices=["stdio", "sse", "streamable-http"],
|
|
421
|
+
default="stdio",
|
|
422
|
+
help="Transport type (default: stdio)",
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
return parser
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def main(argv: Optional[List[str]] = None) -> int:
|
|
429
|
+
"""
|
|
430
|
+
Main entry point for the CLI.
|
|
431
|
+
|
|
432
|
+
Args:
|
|
433
|
+
argv: Command line arguments (defaults to sys.argv[1:])
|
|
434
|
+
|
|
435
|
+
Returns:
|
|
436
|
+
Exit code (0 for success, non-zero for failure)
|
|
437
|
+
"""
|
|
438
|
+
parser = create_parser()
|
|
439
|
+
args = parser.parse_args(argv)
|
|
440
|
+
|
|
441
|
+
# Handle no command
|
|
442
|
+
if not args.command:
|
|
443
|
+
parser.print_help()
|
|
444
|
+
return 0
|
|
445
|
+
|
|
446
|
+
try:
|
|
447
|
+
# Dispatch to command handlers
|
|
448
|
+
if args.command == "validate":
|
|
449
|
+
return validate.run(args)
|
|
450
|
+
elif args.command == "trace":
|
|
451
|
+
return trace.run(args)
|
|
452
|
+
elif args.command == "hash":
|
|
453
|
+
return hash_cmd.run(args)
|
|
454
|
+
elif args.command == "index":
|
|
455
|
+
return index.run(args)
|
|
456
|
+
elif args.command == "analyze":
|
|
457
|
+
return analyze.run(args)
|
|
458
|
+
elif args.command == "version":
|
|
459
|
+
return version_command(args)
|
|
460
|
+
elif args.command == "init":
|
|
461
|
+
return init.run(args)
|
|
462
|
+
elif args.command == "edit":
|
|
463
|
+
return edit.run(args)
|
|
464
|
+
elif args.command == "config":
|
|
465
|
+
return config_cmd.run(args)
|
|
466
|
+
elif args.command == "rules":
|
|
467
|
+
return rules_cmd.run(args)
|
|
468
|
+
elif args.command == "mcp":
|
|
469
|
+
return mcp_command(args)
|
|
470
|
+
else:
|
|
471
|
+
parser.print_help()
|
|
472
|
+
return 1
|
|
473
|
+
|
|
474
|
+
except KeyboardInterrupt:
|
|
475
|
+
print("\nOperation cancelled.", file=sys.stderr)
|
|
476
|
+
return 130
|
|
477
|
+
except Exception as e:
|
|
478
|
+
if args.verbose:
|
|
479
|
+
raise
|
|
480
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
481
|
+
return 1
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
def version_command(args: argparse.Namespace) -> int:
|
|
485
|
+
"""Handle version command."""
|
|
486
|
+
print(f"elspais {__version__}")
|
|
487
|
+
|
|
488
|
+
if args.check:
|
|
489
|
+
print("Checking for updates...")
|
|
490
|
+
# TODO: Implement update check
|
|
491
|
+
print("Update check not yet implemented.")
|
|
492
|
+
|
|
493
|
+
return 0
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
def mcp_command(args: argparse.Namespace) -> int:
|
|
497
|
+
"""Handle MCP server commands."""
|
|
498
|
+
try:
|
|
499
|
+
from elspais.mcp.server import run_server
|
|
500
|
+
except ImportError:
|
|
501
|
+
print("Error: MCP dependencies not installed.", file=sys.stderr)
|
|
502
|
+
print("Install with: pip install elspais[mcp]", file=sys.stderr)
|
|
503
|
+
return 1
|
|
504
|
+
|
|
505
|
+
if args.mcp_action == "serve":
|
|
506
|
+
working_dir = Path.cwd()
|
|
507
|
+
if hasattr(args, "spec_dir") and args.spec_dir:
|
|
508
|
+
working_dir = args.spec_dir.parent
|
|
509
|
+
|
|
510
|
+
print(f"Starting elspais MCP server...")
|
|
511
|
+
print(f"Working directory: {working_dir}")
|
|
512
|
+
print(f"Transport: {args.transport}")
|
|
513
|
+
|
|
514
|
+
try:
|
|
515
|
+
run_server(working_dir=working_dir, transport=args.transport)
|
|
516
|
+
except KeyboardInterrupt:
|
|
517
|
+
print("\nServer stopped.")
|
|
518
|
+
return 0
|
|
519
|
+
else:
|
|
520
|
+
print("Usage: elspais mcp serve")
|
|
521
|
+
return 1
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
if __name__ == "__main__":
|
|
525
|
+
sys.exit(main())
|