systemlink-cli 1.3.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.
- slcli/__init__.py +1 -0
- slcli/__main__.py +23 -0
- slcli/_version.py +4 -0
- slcli/asset_click.py +1289 -0
- slcli/cli_formatters.py +218 -0
- slcli/cli_utils.py +504 -0
- slcli/comment_click.py +602 -0
- slcli/completion_click.py +418 -0
- slcli/config.py +81 -0
- slcli/config_click.py +498 -0
- slcli/dff_click.py +979 -0
- slcli/dff_decorators.py +24 -0
- slcli/example_click.py +404 -0
- slcli/example_loader.py +274 -0
- slcli/example_provisioner.py +2777 -0
- slcli/examples/README.md +134 -0
- slcli/examples/_schema/schema-v1.0.json +169 -0
- slcli/examples/demo-complete-workflow/README.md +323 -0
- slcli/examples/demo-complete-workflow/config.yaml +638 -0
- slcli/examples/demo-test-plans/README.md +132 -0
- slcli/examples/demo-test-plans/config.yaml +154 -0
- slcli/examples/exercise-5-1-parametric-insights/README.md +101 -0
- slcli/examples/exercise-5-1-parametric-insights/config.yaml +1589 -0
- slcli/examples/exercise-7-1-test-plans/README.md +93 -0
- slcli/examples/exercise-7-1-test-plans/config.yaml +323 -0
- slcli/examples/spec-compliance-notebooks/README.md +140 -0
- slcli/examples/spec-compliance-notebooks/config.yaml +112 -0
- slcli/examples/spec-compliance-notebooks/notebooks/SpecAnalysis_ComplianceCalculation.ipynb +1553 -0
- slcli/examples/spec-compliance-notebooks/notebooks/SpecComplianceCalculation.ipynb +1577 -0
- slcli/examples/spec-compliance-notebooks/notebooks/SpecfileExtractionAndIngestion.ipynb +912 -0
- slcli/examples/spec-compliance-notebooks/spec_template.xlsx +0 -0
- slcli/feed_click.py +892 -0
- slcli/file_click.py +932 -0
- slcli/function_click.py +1400 -0
- slcli/function_templates.py +85 -0
- slcli/main.py +406 -0
- slcli/mcp_click.py +269 -0
- slcli/mcp_server.py +748 -0
- slcli/notebook_click.py +1770 -0
- slcli/platform.py +345 -0
- slcli/policy_click.py +679 -0
- slcli/policy_utils.py +411 -0
- slcli/profiles.py +411 -0
- slcli/response_handlers.py +359 -0
- slcli/routine_click.py +763 -0
- slcli/skill_click.py +253 -0
- slcli/skills/slcli/SKILL.md +713 -0
- slcli/skills/slcli/references/analysis-recipes.md +474 -0
- slcli/skills/slcli/references/filtering.md +236 -0
- slcli/skills/systemlink-webapp/SKILL.md +744 -0
- slcli/skills/systemlink-webapp/references/deployment.md +123 -0
- slcli/skills/systemlink-webapp/references/nimble-angular.md +380 -0
- slcli/skills/systemlink-webapp/references/systemlink-services.md +192 -0
- slcli/ssl_trust.py +93 -0
- slcli/system_click.py +2216 -0
- slcli/table_utils.py +124 -0
- slcli/tag_click.py +794 -0
- slcli/templates_click.py +599 -0
- slcli/testmonitor_click.py +1667 -0
- slcli/universal_handlers.py +305 -0
- slcli/user_click.py +1218 -0
- slcli/utils.py +832 -0
- slcli/web_editor.py +295 -0
- slcli/webapp_click.py +981 -0
- slcli/workflow_preview.py +287 -0
- slcli/workflows_click.py +988 -0
- slcli/workitem_click.py +2258 -0
- slcli/workspace_click.py +576 -0
- slcli/workspace_utils.py +206 -0
- systemlink_cli-1.3.1.dist-info/METADATA +20 -0
- systemlink_cli-1.3.1.dist-info/RECORD +74 -0
- systemlink_cli-1.3.1.dist-info/WHEEL +4 -0
- systemlink_cli-1.3.1.dist-info/entry_points.txt +7 -0
- systemlink_cli-1.3.1.dist-info/licenses/LICENSE +21 -0
slcli/mcp_click.py
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
"""CLI commands for the slcli MCP server.
|
|
2
|
+
|
|
3
|
+
Provides 'slcli mcp serve' and 'slcli mcp install' subcommands.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import platform
|
|
8
|
+
import shutil
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any, Dict, List, Optional
|
|
12
|
+
|
|
13
|
+
import click
|
|
14
|
+
|
|
15
|
+
from .utils import ExitCodes
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _slcli_exe() -> str:
|
|
19
|
+
"""Return the absolute path to the slcli executable, or 'slcli' as a fallback."""
|
|
20
|
+
exe = shutil.which("slcli")
|
|
21
|
+
return exe if exe else "slcli"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _vscode_server_entry(slcli_exe: str) -> Dict[str, Any]:
|
|
25
|
+
"""Return the VS Code MCP server JSON object for slcli."""
|
|
26
|
+
return {
|
|
27
|
+
"type": "stdio",
|
|
28
|
+
"command": slcli_exe,
|
|
29
|
+
"args": ["mcp", "serve"],
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _claude_server_entry(slcli_exe: str) -> Dict[str, Any]:
|
|
34
|
+
"""Return the Claude Desktop / Cursor MCP server JSON object for slcli."""
|
|
35
|
+
return {
|
|
36
|
+
"command": slcli_exe,
|
|
37
|
+
"args": ["mcp", "serve"],
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _find_claude_config_file() -> Path:
|
|
42
|
+
"""Return the platform-specific path to Claude Desktop's config file."""
|
|
43
|
+
system = platform.system()
|
|
44
|
+
if system == "Darwin":
|
|
45
|
+
base = Path.home() / "Library" / "Application Support" / "Claude"
|
|
46
|
+
elif system == "Windows":
|
|
47
|
+
base = Path(str(Path.home() / "AppData" / "Roaming" / "Claude"))
|
|
48
|
+
else:
|
|
49
|
+
# Linux / other
|
|
50
|
+
base = Path.home() / ".config" / "claude"
|
|
51
|
+
return base / "claude_desktop_config.json"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _merge_and_write_json(
|
|
55
|
+
config_file: Path,
|
|
56
|
+
top_key: str,
|
|
57
|
+
server_name: str,
|
|
58
|
+
server_entry: Dict[str, Any],
|
|
59
|
+
) -> None:
|
|
60
|
+
"""Read (or create) a JSON config file, upsert the server entry, and write it back.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
config_file: Path to the JSON config file.
|
|
64
|
+
top_key: Top-level JSON key that holds the server map (e.g. 'servers' or 'mcpServers').
|
|
65
|
+
server_name: Name to use as the key inside the server map.
|
|
66
|
+
server_entry: Server entry dict to write.
|
|
67
|
+
"""
|
|
68
|
+
if config_file.exists():
|
|
69
|
+
existing: Dict[str, Any] = json.loads(config_file.read_text(encoding="utf-8"))
|
|
70
|
+
else:
|
|
71
|
+
config_file.parent.mkdir(parents=True, exist_ok=True)
|
|
72
|
+
existing = {}
|
|
73
|
+
|
|
74
|
+
existing.setdefault(top_key, {})
|
|
75
|
+
existing[top_key][server_name] = server_entry
|
|
76
|
+
config_file.write_text(json.dumps(existing, indent=2) + "\n", encoding="utf-8")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _install_vscode(slcli_exe: str) -> None:
|
|
80
|
+
"""Write / update .vscode/mcp.json in the current directory."""
|
|
81
|
+
config_file = Path(".vscode") / "mcp.json"
|
|
82
|
+
_merge_and_write_json(
|
|
83
|
+
config_file,
|
|
84
|
+
top_key="servers",
|
|
85
|
+
server_name="slcli",
|
|
86
|
+
server_entry=_vscode_server_entry(slcli_exe),
|
|
87
|
+
)
|
|
88
|
+
click.echo(f"✓ VS Code MCP config written to {config_file}")
|
|
89
|
+
click.echo(" Restart VS Code (or reload the window) to activate the server.")
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _install_claude(slcli_exe: str) -> None:
|
|
93
|
+
"""Merge slcli into Claude Desktop's config file."""
|
|
94
|
+
config_file = _find_claude_config_file()
|
|
95
|
+
_merge_and_write_json(
|
|
96
|
+
config_file,
|
|
97
|
+
top_key="mcpServers",
|
|
98
|
+
server_name="slcli",
|
|
99
|
+
server_entry=_claude_server_entry(slcli_exe),
|
|
100
|
+
)
|
|
101
|
+
click.echo(f"✓ Claude Desktop MCP config updated: {config_file}")
|
|
102
|
+
click.echo(" Restart Claude Desktop to activate the server.")
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _install_cursor(slcli_exe: str) -> None:
|
|
106
|
+
"""Write / update .cursor/mcp.json in the current directory."""
|
|
107
|
+
config_file = Path(".cursor") / "mcp.json"
|
|
108
|
+
_merge_and_write_json(
|
|
109
|
+
config_file,
|
|
110
|
+
top_key="mcpServers",
|
|
111
|
+
server_name="slcli",
|
|
112
|
+
server_entry=_claude_server_entry(slcli_exe),
|
|
113
|
+
)
|
|
114
|
+
click.echo(f"✓ Cursor MCP config written to {config_file}")
|
|
115
|
+
click.echo(" Reload Cursor to activate the server.")
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _install_codex(slcli_exe: str) -> None:
|
|
119
|
+
"""Write / update .codex/mcp.json in the current directory."""
|
|
120
|
+
config_file = Path(".codex") / "mcp.json"
|
|
121
|
+
_merge_and_write_json(
|
|
122
|
+
config_file,
|
|
123
|
+
top_key="mcpServers",
|
|
124
|
+
server_name="slcli",
|
|
125
|
+
server_entry=_claude_server_entry(slcli_exe),
|
|
126
|
+
)
|
|
127
|
+
click.echo(f"✓ Codex MCP config written to {config_file}")
|
|
128
|
+
click.echo(" Reload Codex to activate the server.")
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
_INSTALLERS: Dict[str, Any] = {
|
|
132
|
+
"vscode": _install_vscode,
|
|
133
|
+
"claude": _install_claude,
|
|
134
|
+
"cursor": _install_cursor,
|
|
135
|
+
"codex": _install_codex,
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
_TARGET_CHOICES: List[str] = ["vscode", "claude", "cursor", "codex", "all"]
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def register_mcp_commands(cli: Any) -> None:
|
|
142
|
+
"""Register the 'mcp' command group and its subcommands."""
|
|
143
|
+
|
|
144
|
+
@cli.group()
|
|
145
|
+
def mcp() -> None:
|
|
146
|
+
"""MCP (Model Context Protocol) server integration for AI assistants."""
|
|
147
|
+
|
|
148
|
+
@mcp.command(name="serve")
|
|
149
|
+
@click.option(
|
|
150
|
+
"--transport",
|
|
151
|
+
"-T",
|
|
152
|
+
type=click.Choice(["stdio", "sse"]),
|
|
153
|
+
default="stdio",
|
|
154
|
+
show_default=True,
|
|
155
|
+
help="Transport layer: 'stdio' for AI client integration, 'sse' for HTTP/SSE.",
|
|
156
|
+
)
|
|
157
|
+
@click.option(
|
|
158
|
+
"--port",
|
|
159
|
+
"-p",
|
|
160
|
+
default=8000,
|
|
161
|
+
show_default=True,
|
|
162
|
+
help="Port to bind to (SSE transport only).",
|
|
163
|
+
)
|
|
164
|
+
@click.option(
|
|
165
|
+
"--host",
|
|
166
|
+
default="127.0.0.1",
|
|
167
|
+
show_default=True,
|
|
168
|
+
help="Host to bind to (SSE transport only).",
|
|
169
|
+
)
|
|
170
|
+
def serve(transport: str, port: int, host: str) -> None:
|
|
171
|
+
"""Start the MCP server.
|
|
172
|
+
|
|
173
|
+
Defaults to stdio transport for direct AI client integration (VS Code
|
|
174
|
+
Copilot, Claude Desktop, Cursor). Switch to SSE transport to serve
|
|
175
|
+
over HTTP — useful for the MCP Inspector, browser-based tooling, or
|
|
176
|
+
any client that prefers a persistent HTTP connection.
|
|
177
|
+
|
|
178
|
+
\b
|
|
179
|
+
Stdio (default — configure once with 'slcli mcp install'):
|
|
180
|
+
slcli mcp serve
|
|
181
|
+
|
|
182
|
+
\b
|
|
183
|
+
SSE (HTTP server on http://127.0.0.1:8000/sse):
|
|
184
|
+
slcli mcp serve --transport sse
|
|
185
|
+
slcli mcp serve --transport sse --host 0.0.0.0 --port 9000
|
|
186
|
+
|
|
187
|
+
\b
|
|
188
|
+
Test with the MCP Inspector (SSE):
|
|
189
|
+
slcli mcp serve --transport sse
|
|
190
|
+
npx @modelcontextprotocol/inspector
|
|
191
|
+
# connect to http://127.0.0.1:8000/sse (transport: SSE)
|
|
192
|
+
"""
|
|
193
|
+
try:
|
|
194
|
+
from .mcp_server import main as run_mcp_server
|
|
195
|
+
from .mcp_server import server as mcp_server
|
|
196
|
+
except ImportError:
|
|
197
|
+
click.echo(
|
|
198
|
+
"✗ The 'mcp' package is not installed.\n"
|
|
199
|
+
" Install it with: pip install 'mcp>=1.0'\n"
|
|
200
|
+
" Or in a Poetry project: poetry add mcp",
|
|
201
|
+
err=True,
|
|
202
|
+
)
|
|
203
|
+
sys.exit(ExitCodes.GENERAL_ERROR)
|
|
204
|
+
|
|
205
|
+
if transport == "stdio":
|
|
206
|
+
run_mcp_server()
|
|
207
|
+
else:
|
|
208
|
+
mcp_server.settings.host = host
|
|
209
|
+
mcp_server.settings.port = port
|
|
210
|
+
|
|
211
|
+
click.echo(f"✓ slcli MCP server starting in SSE mode on http://{host}:{port}/sse")
|
|
212
|
+
click.echo(" Open the Inspector: npx @modelcontextprotocol/inspector")
|
|
213
|
+
click.echo(f" Then connect to: http://{host}:{port}/sse (transport: SSE)")
|
|
214
|
+
click.echo(" Press Ctrl+C to stop.\n")
|
|
215
|
+
|
|
216
|
+
try:
|
|
217
|
+
mcp_server.run(transport="sse")
|
|
218
|
+
except KeyboardInterrupt:
|
|
219
|
+
click.echo("\nslcli MCP server stopped")
|
|
220
|
+
sys.exit(0)
|
|
221
|
+
|
|
222
|
+
@mcp.command(name="install")
|
|
223
|
+
@click.option(
|
|
224
|
+
"--target",
|
|
225
|
+
"-t",
|
|
226
|
+
type=click.Choice(_TARGET_CHOICES),
|
|
227
|
+
default="vscode",
|
|
228
|
+
show_default=True,
|
|
229
|
+
help=(
|
|
230
|
+
"AI client to configure: vscode (.vscode/mcp.json), "
|
|
231
|
+
"claude (Claude Desktop global config), "
|
|
232
|
+
"cursor (.cursor/mcp.json), "
|
|
233
|
+
"codex (.codex/mcp.json), "
|
|
234
|
+
"or all."
|
|
235
|
+
),
|
|
236
|
+
)
|
|
237
|
+
@click.option(
|
|
238
|
+
"--exe",
|
|
239
|
+
"slcli_exe",
|
|
240
|
+
default=None,
|
|
241
|
+
help=(
|
|
242
|
+
"Path to the slcli executable to use in the config "
|
|
243
|
+
"(auto-detected from PATH if not specified)"
|
|
244
|
+
),
|
|
245
|
+
)
|
|
246
|
+
def install(target: str, slcli_exe: Optional[str]) -> None:
|
|
247
|
+
"""Write MCP server configuration for an AI client.
|
|
248
|
+
|
|
249
|
+
Automatically creates or updates the client's config file so it can
|
|
250
|
+
discover and launch the slcli MCP server.
|
|
251
|
+
|
|
252
|
+
\b
|
|
253
|
+
Examples:
|
|
254
|
+
slcli mcp install # VS Code (default)
|
|
255
|
+
slcli mcp install --target claude # Claude Desktop
|
|
256
|
+
slcli mcp install --target cursor # Cursor
|
|
257
|
+
slcli mcp install --target codex # OpenAI Codex CLI
|
|
258
|
+
slcli mcp install --target all # all four
|
|
259
|
+
"""
|
|
260
|
+
exe = slcli_exe or _slcli_exe()
|
|
261
|
+
|
|
262
|
+
targets_to_run: List[str] = list(_INSTALLERS.keys()) if target == "all" else [target]
|
|
263
|
+
|
|
264
|
+
for t in targets_to_run:
|
|
265
|
+
installer = _INSTALLERS[t]
|
|
266
|
+
try:
|
|
267
|
+
installer(exe)
|
|
268
|
+
except Exception as exc: # noqa: BLE001
|
|
269
|
+
click.echo(f"✗ Failed to configure {t}: {exc}", err=True)
|