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.
Files changed (74) hide show
  1. slcli/__init__.py +1 -0
  2. slcli/__main__.py +23 -0
  3. slcli/_version.py +4 -0
  4. slcli/asset_click.py +1289 -0
  5. slcli/cli_formatters.py +218 -0
  6. slcli/cli_utils.py +504 -0
  7. slcli/comment_click.py +602 -0
  8. slcli/completion_click.py +418 -0
  9. slcli/config.py +81 -0
  10. slcli/config_click.py +498 -0
  11. slcli/dff_click.py +979 -0
  12. slcli/dff_decorators.py +24 -0
  13. slcli/example_click.py +404 -0
  14. slcli/example_loader.py +274 -0
  15. slcli/example_provisioner.py +2777 -0
  16. slcli/examples/README.md +134 -0
  17. slcli/examples/_schema/schema-v1.0.json +169 -0
  18. slcli/examples/demo-complete-workflow/README.md +323 -0
  19. slcli/examples/demo-complete-workflow/config.yaml +638 -0
  20. slcli/examples/demo-test-plans/README.md +132 -0
  21. slcli/examples/demo-test-plans/config.yaml +154 -0
  22. slcli/examples/exercise-5-1-parametric-insights/README.md +101 -0
  23. slcli/examples/exercise-5-1-parametric-insights/config.yaml +1589 -0
  24. slcli/examples/exercise-7-1-test-plans/README.md +93 -0
  25. slcli/examples/exercise-7-1-test-plans/config.yaml +323 -0
  26. slcli/examples/spec-compliance-notebooks/README.md +140 -0
  27. slcli/examples/spec-compliance-notebooks/config.yaml +112 -0
  28. slcli/examples/spec-compliance-notebooks/notebooks/SpecAnalysis_ComplianceCalculation.ipynb +1553 -0
  29. slcli/examples/spec-compliance-notebooks/notebooks/SpecComplianceCalculation.ipynb +1577 -0
  30. slcli/examples/spec-compliance-notebooks/notebooks/SpecfileExtractionAndIngestion.ipynb +912 -0
  31. slcli/examples/spec-compliance-notebooks/spec_template.xlsx +0 -0
  32. slcli/feed_click.py +892 -0
  33. slcli/file_click.py +932 -0
  34. slcli/function_click.py +1400 -0
  35. slcli/function_templates.py +85 -0
  36. slcli/main.py +406 -0
  37. slcli/mcp_click.py +269 -0
  38. slcli/mcp_server.py +748 -0
  39. slcli/notebook_click.py +1770 -0
  40. slcli/platform.py +345 -0
  41. slcli/policy_click.py +679 -0
  42. slcli/policy_utils.py +411 -0
  43. slcli/profiles.py +411 -0
  44. slcli/response_handlers.py +359 -0
  45. slcli/routine_click.py +763 -0
  46. slcli/skill_click.py +253 -0
  47. slcli/skills/slcli/SKILL.md +713 -0
  48. slcli/skills/slcli/references/analysis-recipes.md +474 -0
  49. slcli/skills/slcli/references/filtering.md +236 -0
  50. slcli/skills/systemlink-webapp/SKILL.md +744 -0
  51. slcli/skills/systemlink-webapp/references/deployment.md +123 -0
  52. slcli/skills/systemlink-webapp/references/nimble-angular.md +380 -0
  53. slcli/skills/systemlink-webapp/references/systemlink-services.md +192 -0
  54. slcli/ssl_trust.py +93 -0
  55. slcli/system_click.py +2216 -0
  56. slcli/table_utils.py +124 -0
  57. slcli/tag_click.py +794 -0
  58. slcli/templates_click.py +599 -0
  59. slcli/testmonitor_click.py +1667 -0
  60. slcli/universal_handlers.py +305 -0
  61. slcli/user_click.py +1218 -0
  62. slcli/utils.py +832 -0
  63. slcli/web_editor.py +295 -0
  64. slcli/webapp_click.py +981 -0
  65. slcli/workflow_preview.py +287 -0
  66. slcli/workflows_click.py +988 -0
  67. slcli/workitem_click.py +2258 -0
  68. slcli/workspace_click.py +576 -0
  69. slcli/workspace_utils.py +206 -0
  70. systemlink_cli-1.3.1.dist-info/METADATA +20 -0
  71. systemlink_cli-1.3.1.dist-info/RECORD +74 -0
  72. systemlink_cli-1.3.1.dist-info/WHEEL +4 -0
  73. systemlink_cli-1.3.1.dist-info/entry_points.txt +7 -0
  74. 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)