skilllite 0.1.0__tar.gz → 0.1.1__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 (46) hide show
  1. {skilllite-0.1.0/skilllite.egg-info → skilllite-0.1.1}/PKG-INFO +54 -1
  2. {skilllite-0.1.0 → skilllite-0.1.1}/README.md +53 -0
  3. {skilllite-0.1.0 → skilllite-0.1.1}/pyproject.toml +1 -1
  4. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/__init__.py +1 -1
  5. skilllite-0.1.1/skilllite/cli/__init__.py +19 -0
  6. skilllite-0.1.1/skilllite/cli/__main__.py +10 -0
  7. skilllite-0.1.1/skilllite/cli/binary.py +93 -0
  8. skilllite-0.1.1/skilllite/cli/integrations/__init__.py +8 -0
  9. skilllite-0.1.1/skilllite/cli/integrations/opencode.py +316 -0
  10. skilllite-0.1.1/skilllite/cli/main.py +142 -0
  11. skilllite-0.1.1/skilllite/cli/mcp.py +29 -0
  12. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/core/loops.py +5 -2
  13. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/mcp/server.py +296 -16
  14. {skilllite-0.1.0 → skilllite-0.1.1/skilllite.egg-info}/PKG-INFO +54 -1
  15. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite.egg-info/SOURCES.txt +7 -1
  16. skilllite-0.1.0/skilllite/cli.py +0 -217
  17. {skilllite-0.1.0 → skilllite-0.1.1}/LICENSE +0 -0
  18. {skilllite-0.1.0 → skilllite-0.1.1}/MANIFEST.in +0 -0
  19. {skilllite-0.1.0 → skilllite-0.1.1}/setup.cfg +0 -0
  20. {skilllite-0.1.0 → skilllite-0.1.1}/setup.py +0 -0
  21. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/analyzer.py +0 -0
  22. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/builtin_tools.py +0 -0
  23. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/core/__init__.py +0 -0
  24. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/core/executor.py +0 -0
  25. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/core/handler.py +0 -0
  26. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/core/manager.py +0 -0
  27. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/core/metadata.py +0 -0
  28. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/core/prompt_builder.py +0 -0
  29. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/core/registry.py +0 -0
  30. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/core/skill_info.py +0 -0
  31. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/core/tool_builder.py +0 -0
  32. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/core/tools.py +0 -0
  33. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/mcp/__init__.py +0 -0
  34. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/quick.py +0 -0
  35. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/sandbox/__init__.py +0 -0
  36. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/sandbox/base.py +0 -0
  37. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/sandbox/config.py +0 -0
  38. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/sandbox/skillbox/__init__.py +0 -0
  39. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/sandbox/skillbox/binary.py +0 -0
  40. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/sandbox/skillbox/executor.py +0 -0
  41. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/sandbox/utils.py +0 -0
  42. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite/validation.py +0 -0
  43. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite.egg-info/dependency_links.txt +0 -0
  44. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite.egg-info/entry_points.txt +0 -0
  45. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite.egg-info/requires.txt +0 -0
  46. {skilllite-0.1.0 → skilllite-0.1.1}/skilllite.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: skilllite
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: A lightweight Skills execution engine with LLM integration for LLM agents
5
5
  Author-email: SkillLite Team <skilllite@example.com>
6
6
  License: MIT
@@ -288,6 +288,59 @@ Enum for LLM provider formats:
288
288
  - `ToolFormat.CLAUDE`
289
289
  - `ToolFormat.OPENAI`
290
290
 
291
+ ## OpenCode Integration
292
+
293
+ SkillLite can be integrated with [OpenCode](https://github.com/opencode-ai/opencode) as an MCP (Model Context Protocol) server, providing secure sandbox execution capabilities.
294
+
295
+ ### Quick Setup
296
+
297
+ ```bash
298
+ # Install with MCP support
299
+ pip install skilllite[mcp]
300
+
301
+ # One-command setup for OpenCode
302
+ skilllite init-opencode
303
+
304
+ # Start OpenCode
305
+ opencode
306
+ ```
307
+
308
+ The `init-opencode` command automatically:
309
+ - Detects the best way to start the MCP server (uvx, pipx, skilllite, or python)
310
+ - Creates `opencode.json` with optimal configuration
311
+ - Generates `.opencode/skills/skilllite/SKILL.md` with usage instructions
312
+ - Discovers your pre-defined skills
313
+
314
+ ### Available MCP Tools
315
+
316
+ | Tool | Description |
317
+ |------|-------------|
318
+ | `skilllite_list_skills` | List all available skills |
319
+ | `skilllite_get_skill_info` | Get skill details and input schema |
320
+ | `skilllite_run_skill` | Execute a pre-defined skill |
321
+ | `skilllite_scan_code` | Scan code for security issues |
322
+ | `skilllite_execute_code` | Execute code in secure sandbox |
323
+
324
+ ### Security Features
325
+
326
+ - **System-level Sandbox**: macOS Seatbelt / Linux Namespace isolation
327
+ - **Security Scanning**: Static analysis before execution
328
+ - **User Confirmation**: Dangerous code requires explicit approval
329
+ - **Scan ID Verification**: Prevents code modification between scan and execution
330
+
331
+ For detailed documentation, see [OpenCode Integration Tutorial](../tutorials/07_opencode_integration/README.md).
332
+
333
+ ## CLI Commands
334
+
335
+ ```bash
336
+ skilllite install # Install skillbox sandbox binary
337
+ skilllite uninstall # Remove skillbox binary
338
+ skilllite status # Show installation status
339
+ skilllite version # Show version information
340
+ skilllite mcp # Start MCP server
341
+ skilllite init-opencode # Initialize OpenCode integration
342
+ ```
343
+
291
344
  ## License
292
345
 
293
346
  MIT License
@@ -242,6 +242,59 @@ Enum for LLM provider formats:
242
242
  - `ToolFormat.CLAUDE`
243
243
  - `ToolFormat.OPENAI`
244
244
 
245
+ ## OpenCode Integration
246
+
247
+ SkillLite can be integrated with [OpenCode](https://github.com/opencode-ai/opencode) as an MCP (Model Context Protocol) server, providing secure sandbox execution capabilities.
248
+
249
+ ### Quick Setup
250
+
251
+ ```bash
252
+ # Install with MCP support
253
+ pip install skilllite[mcp]
254
+
255
+ # One-command setup for OpenCode
256
+ skilllite init-opencode
257
+
258
+ # Start OpenCode
259
+ opencode
260
+ ```
261
+
262
+ The `init-opencode` command automatically:
263
+ - Detects the best way to start the MCP server (uvx, pipx, skilllite, or python)
264
+ - Creates `opencode.json` with optimal configuration
265
+ - Generates `.opencode/skills/skilllite/SKILL.md` with usage instructions
266
+ - Discovers your pre-defined skills
267
+
268
+ ### Available MCP Tools
269
+
270
+ | Tool | Description |
271
+ |------|-------------|
272
+ | `skilllite_list_skills` | List all available skills |
273
+ | `skilllite_get_skill_info` | Get skill details and input schema |
274
+ | `skilllite_run_skill` | Execute a pre-defined skill |
275
+ | `skilllite_scan_code` | Scan code for security issues |
276
+ | `skilllite_execute_code` | Execute code in secure sandbox |
277
+
278
+ ### Security Features
279
+
280
+ - **System-level Sandbox**: macOS Seatbelt / Linux Namespace isolation
281
+ - **Security Scanning**: Static analysis before execution
282
+ - **User Confirmation**: Dangerous code requires explicit approval
283
+ - **Scan ID Verification**: Prevents code modification between scan and execution
284
+
285
+ For detailed documentation, see [OpenCode Integration Tutorial](../tutorials/07_opencode_integration/README.md).
286
+
287
+ ## CLI Commands
288
+
289
+ ```bash
290
+ skilllite install # Install skillbox sandbox binary
291
+ skilllite uninstall # Remove skillbox binary
292
+ skilllite status # Show installation status
293
+ skilllite version # Show version information
294
+ skilllite mcp # Start MCP server
295
+ skilllite init-opencode # Initialize OpenCode integration
296
+ ```
297
+
245
298
  ## License
246
299
 
247
300
  MIT License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "skilllite"
7
- version = "0.1.0"
7
+ version = "0.1.1"
8
8
  description = "A lightweight Skills execution engine with LLM integration for LLM agents"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -113,7 +113,7 @@ try:
113
113
  except ImportError:
114
114
  MCP_AVAILABLE = False
115
115
 
116
- __version__ = "0.1.0"
116
+ __version__ = "0.1.1"
117
117
  __all__ = [
118
118
  # Core
119
119
  "SkillManager",
@@ -0,0 +1,19 @@
1
+ """
2
+ Command-line interface for skilllite.
3
+
4
+ Provides commands for managing the skillbox binary, similar to
5
+ how Playwright provides `playwright install` for browser management.
6
+
7
+ Usage:
8
+ skilllite install # Download and install the sandbox binary
9
+ skilllite uninstall # Remove the installed binary
10
+ skilllite status # Show installation status
11
+ skilllite version # Show version information
12
+ skilllite mcp # Start MCP server
13
+ skilllite init-opencode # Initialize OpenCode integration
14
+ """
15
+
16
+ from .main import main, create_parser
17
+
18
+ __all__ = ["main", "create_parser"]
19
+
@@ -0,0 +1,10 @@
1
+ """
2
+ Allow running the CLI as a module: python -m skilllite.cli
3
+ """
4
+
5
+ import sys
6
+ from .main import main
7
+
8
+ if __name__ == "__main__":
9
+ sys.exit(main())
10
+
@@ -0,0 +1,93 @@
1
+ """
2
+ Binary management commands for skilllite CLI.
3
+
4
+ Commands: install, uninstall, status, version
5
+ """
6
+
7
+ import argparse
8
+ import sys
9
+
10
+ from .. import __version__
11
+ from ..sandbox.skillbox import (
12
+ BINARY_VERSION,
13
+ get_platform,
14
+ install,
15
+ is_installed,
16
+ get_installed_version,
17
+ uninstall,
18
+ )
19
+
20
+
21
+ def print_status() -> None:
22
+ """Print installation status."""
23
+ from ..sandbox.skillbox import find_binary, get_binary_path
24
+
25
+ print("SkillLite Installation Status")
26
+ print("=" * 40)
27
+
28
+ if is_installed():
29
+ version = get_installed_version()
30
+ print(f"✓ skillbox is installed (v{version})")
31
+ print(f" Location: {get_binary_path()}")
32
+ else:
33
+ binary = find_binary()
34
+ if binary:
35
+ print(f"✓ skillbox found at: {binary}")
36
+ else:
37
+ print("✗ skillbox is not installed")
38
+ print(" Install with: skilllite install")
39
+
40
+
41
+ def cmd_install(args: argparse.Namespace) -> int:
42
+ """Install the skillbox binary."""
43
+ try:
44
+ install(
45
+ version=args.version,
46
+ force=args.force,
47
+ show_progress=not args.quiet
48
+ )
49
+ return 0
50
+ except Exception as e:
51
+ print(f"Error: {e}", file=sys.stderr)
52
+ return 1
53
+
54
+
55
+ def cmd_uninstall(args: argparse.Namespace) -> int:
56
+ """Uninstall the skillbox binary."""
57
+ try:
58
+ uninstall()
59
+ return 0
60
+ except Exception as e:
61
+ print(f"Error: {e}", file=sys.stderr)
62
+ return 1
63
+
64
+
65
+ def cmd_status(args: argparse.Namespace) -> int:
66
+ """Show installation status."""
67
+ try:
68
+ print_status()
69
+ return 0
70
+ except Exception as e:
71
+ print(f"Error: {e}", file=sys.stderr)
72
+ return 1
73
+
74
+
75
+ def cmd_version(args: argparse.Namespace) -> int:
76
+ """Show version information."""
77
+ print(f"skilllite Python SDK: v{__version__}")
78
+ print(f"skillbox binary (bundled): v{BINARY_VERSION}")
79
+
80
+ installed_version = get_installed_version()
81
+ if installed_version:
82
+ print(f"skillbox binary (installed): v{installed_version}")
83
+ else:
84
+ print("skillbox binary (installed): not installed")
85
+
86
+ try:
87
+ plat = get_platform()
88
+ print(f"Platform: {plat}")
89
+ except RuntimeError as e:
90
+ print(f"Platform: {e}")
91
+
92
+ return 0
93
+
@@ -0,0 +1,8 @@
1
+ """
2
+ CLI integrations for external tools.
3
+ """
4
+
5
+ from .opencode import cmd_init_opencode
6
+
7
+ __all__ = ["cmd_init_opencode"]
8
+
@@ -0,0 +1,316 @@
1
+ """
2
+ OpenCode integration for skilllite CLI.
3
+
4
+ Provides the init-opencode command to set up SkillLite integration with OpenCode.
5
+ """
6
+
7
+ import argparse
8
+ import json
9
+ import os
10
+ import sys
11
+ from pathlib import Path
12
+ from typing import List, Dict, Any
13
+
14
+ from ...sandbox.skillbox import (
15
+ install,
16
+ is_installed,
17
+ get_installed_version,
18
+ )
19
+
20
+
21
+ def _get_available_skills(skills_dir: str) -> List[Dict[str, Any]]:
22
+ """Get list of available skills from the skills directory."""
23
+ skills = []
24
+ skills_path = Path(skills_dir)
25
+
26
+ if not skills_path.exists():
27
+ return skills
28
+
29
+ for skill_dir in skills_path.iterdir():
30
+ if not skill_dir.is_dir():
31
+ continue
32
+
33
+ skill_md = skill_dir / "SKILL.md"
34
+ if not skill_md.exists():
35
+ continue
36
+
37
+ # Parse basic skill info from SKILL.md
38
+ try:
39
+ content = skill_md.read_text()
40
+ name = skill_dir.name
41
+ description = ""
42
+
43
+ # Extract description from YAML frontmatter
44
+ if content.startswith("---"):
45
+ parts = content.split("---", 2)
46
+ if len(parts) >= 3:
47
+ import re
48
+ desc_match = re.search(r'description:\s*["\']?([^"\'\n]+)', parts[1])
49
+ if desc_match:
50
+ description = desc_match.group(1).strip()
51
+
52
+ skills.append({
53
+ "name": name,
54
+ "description": description or f"Execute {name} skill"
55
+ })
56
+ except Exception:
57
+ continue
58
+
59
+ return skills
60
+
61
+
62
+ def _generate_skill_md_content(skills: List[Dict[str, Any]]) -> str:
63
+ """Generate the SKILL.md content for OpenCode integration."""
64
+ skills_list = ""
65
+ if skills:
66
+ for skill in skills:
67
+ skills_list += f"- **{skill['name']}**: {skill['description']}\n"
68
+ else:
69
+ skills_list = "- (No pre-defined skills found. Use skilllite_execute_code for code execution.)\n"
70
+
71
+ return f'''---
72
+ name: skilllite
73
+ description: 在安全沙箱中执行代码或预定义技能。当需要运行不信任的代码、网络请求、数据处理时使用。
74
+ ---
75
+
76
+ ## 概述
77
+
78
+ SkillLite 提供了一个安全的沙箱执行环境。代码在系统级沙箱(macOS Seatbelt / Linux Namespace)中隔离运行,防止恶意代码影响主机系统。
79
+
80
+ ## 何时使用 SkillLite 而不是 bash
81
+
82
+ | 场景 | 用 bash | 用 SkillLite |
83
+ |-----|---------|-------------|
84
+ | git 操作 | ✅ | |
85
+ | 读取项目文件 | ✅ | |
86
+ | 执行用户提供的代码 | | ✅ |
87
+ | 网络请求/API 调用 | | ✅ |
88
+ | 数据分析处理 | | ✅ |
89
+ | 运行不信任的脚本 | | ✅ |
90
+ | 执行可能危险的命令 | | ✅ |
91
+
92
+ ## 可用工具
93
+
94
+ ### 1. skilllite_execute_code
95
+ 在沙箱中执行任意代码(Python/JavaScript/Bash)。
96
+
97
+ **参数:**
98
+ - `language`: "python" | "javascript" | "bash"
99
+ - `code`: 要执行的代码
100
+ - `confirmed`: 是否确认执行(高危代码需要)
101
+ - `scan_id`: 扫描 ID(确认执行时需要)
102
+
103
+ **安全确认流程:**
104
+ 当检测到危险代码时,会返回安全报告和 `scan_id`。向用户展示安全问题后,如果用户同意执行,需要再次调用时设置 `confirmed=true` 和返回的 `scan_id`。
105
+
106
+ ### 2. skilllite_run_skill
107
+ 执行预定义技能。
108
+
109
+ **参数:**
110
+ - `skill_name`: 技能名称
111
+ - `input`: 技能的输入参数(JSON 对象)
112
+
113
+ ### 3. skilllite_list_skills
114
+ 查看所有可用的预定义技能。无需参数。
115
+
116
+ ### 4. skilllite_get_skill_info
117
+ 获取指定技能的详细信息,包括输入参数模式。
118
+
119
+ **参数:**
120
+ - `skill_name`: 技能名称
121
+
122
+ ### 5. skilllite_scan_code
123
+ 仅扫描代码安全性,不执行。用于预检查代码是否安全。
124
+
125
+ **参数:**
126
+ - `language`: "python" | "javascript" | "bash"
127
+ - `code`: 要扫描的代码
128
+
129
+ ## 预定义技能
130
+
131
+ {skills_list}
132
+
133
+ ## 使用示例
134
+
135
+ ### 执行 Python 代码
136
+ ```
137
+ skilllite_execute_code(language="python", code="print(sum(range(1, 101)))")
138
+ ```
139
+
140
+ ### 处理危险代码
141
+ 1. 调用 `skilllite_execute_code` 执行代码
142
+ 2. 如果返回 `requires_confirmation=true`,向用户展示安全问题
143
+ 3. 用户确认后,再次调用时带上 `confirmed=true` 和 `scan_id`
144
+
145
+ ### 使用预定义技能
146
+ ```
147
+ skilllite_list_skills() # 查看可用技能
148
+ skilllite_get_skill_info(skill_name="calculator") # 查看技能参数
149
+ skilllite_run_skill(skill_name="calculator", input={{"operation": "add", "a": 5, "b": 3}})
150
+ ```
151
+ '''
152
+
153
+
154
+ def _detect_best_command() -> tuple[List[str], str]:
155
+ """
156
+ Detect the best command to start the MCP server.
157
+
158
+ Returns:
159
+ Tuple of (command_list, description)
160
+
161
+ Priority:
162
+ 1. uvx (if available) - most portable, auto-manages environment
163
+ 2. pipx (if available) - similar to uvx
164
+ 3. python3 -m skilllite.mcp.server - if skilllite is in PATH's python
165
+ 4. Full python path - fallback
166
+ """
167
+ import shutil
168
+ import subprocess
169
+
170
+ # Check if uvx is available
171
+ if shutil.which("uvx"):
172
+ return (["uvx", "skilllite", "mcp"], "uvx (auto-managed)")
173
+
174
+ # Check if pipx is available and skilllite is installed via pipx
175
+ if shutil.which("pipx"):
176
+ # Check if skilllite is installed in pipx
177
+ try:
178
+ result = subprocess.run(
179
+ ["pipx", "list", "--short"],
180
+ capture_output=True,
181
+ text=True,
182
+ timeout=5
183
+ )
184
+ if "skilllite" in result.stdout:
185
+ return (["pipx", "run", "skilllite", "mcp"], "pipx (installed)")
186
+ except Exception:
187
+ pass
188
+
189
+ # Check if skilllite command is directly available in PATH
190
+ if shutil.which("skilllite"):
191
+ return (["skilllite", "mcp"], "skilllite (in PATH)")
192
+
193
+ # Check if python3 has skilllite installed
194
+ python3_path = shutil.which("python3")
195
+ if python3_path:
196
+ try:
197
+ result = subprocess.run(
198
+ [python3_path, "-c", "import skilllite; print('ok')"],
199
+ capture_output=True,
200
+ text=True,
201
+ timeout=5
202
+ )
203
+ if result.returncode == 0 and "ok" in result.stdout:
204
+ return (["python3", "-m", "skilllite.mcp.server"], "python3 (skilllite installed)")
205
+ except Exception:
206
+ pass
207
+
208
+ # Fallback: use current Python's full path
209
+ return ([sys.executable, "-m", "skilllite.mcp.server"], "full path (fallback)")
210
+
211
+
212
+ def _generate_opencode_config(command: List[str], skills_dir: str) -> Dict[str, Any]:
213
+ """Generate OpenCode configuration."""
214
+ return {
215
+ "$schema": "https://opencode.ai/config.json",
216
+ "mcp": {
217
+ "skilllite": {
218
+ "type": "local",
219
+ "command": command,
220
+ "environment": {
221
+ "SKILLBOX_SANDBOX_LEVEL": "3",
222
+ "SKILLLITE_SKILLS_DIR": skills_dir
223
+ },
224
+ "enabled": True
225
+ }
226
+ }
227
+ }
228
+
229
+
230
+ def cmd_init_opencode(args: argparse.Namespace) -> int:
231
+ """Initialize OpenCode integration."""
232
+ try:
233
+ project_dir = Path(args.project_dir or os.getcwd())
234
+ skills_dir = args.skills_dir or "./.skills"
235
+
236
+ print("🚀 Initializing SkillLite integration for OpenCode...")
237
+ print(f" Project directory: {project_dir}")
238
+ print()
239
+
240
+ # 1. Check if skillbox is installed
241
+ if not is_installed():
242
+ print("⚠ skillbox not installed. Installing...")
243
+ install(show_progress=True)
244
+ else:
245
+ version = get_installed_version()
246
+ print(f"✓ skillbox installed (v{version})")
247
+
248
+ # 2. Detect best command to start MCP server
249
+ command, command_desc = _detect_best_command()
250
+ print(f"✓ MCP command: {command_desc}")
251
+ print(f" → {' '.join(command)}")
252
+
253
+ # 3. Create opencode.json
254
+ opencode_config_path = project_dir / "opencode.json"
255
+ config = _generate_opencode_config(command, skills_dir)
256
+
257
+ if opencode_config_path.exists() and not args.force:
258
+ # Merge with existing config
259
+ try:
260
+ existing = json.loads(opencode_config_path.read_text())
261
+ if "mcp" not in existing:
262
+ existing["mcp"] = {}
263
+ existing["mcp"]["skilllite"] = config["mcp"]["skilllite"]
264
+ if "$schema" not in existing:
265
+ existing["$schema"] = config["$schema"]
266
+ config = existing
267
+ print("✓ Updated existing opencode.json")
268
+ except Exception:
269
+ print("⚠ Could not parse existing opencode.json, overwriting")
270
+ else:
271
+ print("✓ Created opencode.json")
272
+
273
+ opencode_config_path.write_text(json.dumps(config, indent=2, ensure_ascii=False))
274
+
275
+ # 4. Get available skills
276
+ # Handle relative path properly - remove leading "./" but keep the rest
277
+ skills_dir_clean = skills_dir[2:] if skills_dir.startswith("./") else skills_dir
278
+ full_skills_dir = project_dir / skills_dir_clean
279
+ skills = _get_available_skills(str(full_skills_dir))
280
+ print(f"✓ Found {len(skills)} skills in {skills_dir}")
281
+
282
+ # 5. Create .opencode/skills/skilllite/SKILL.md
283
+ skill_dir = project_dir / ".opencode" / "skills" / "skilllite"
284
+ skill_dir.mkdir(parents=True, exist_ok=True)
285
+
286
+ skill_md_path = skill_dir / "SKILL.md"
287
+ skill_md_content = _generate_skill_md_content(skills)
288
+ skill_md_path.write_text(skill_md_content, encoding="utf-8")
289
+ print("✓ Created .opencode/skills/skilllite/SKILL.md")
290
+
291
+ # 6. Summary
292
+ print()
293
+ print("=" * 50)
294
+ print("🎉 SkillLite integration initialized successfully!")
295
+ print()
296
+ print("Created files:")
297
+ print(f" • {opencode_config_path.relative_to(project_dir)}")
298
+ print(f" • {skill_md_path.relative_to(project_dir)}")
299
+ print()
300
+ print("Available MCP tools in OpenCode:")
301
+ print(" • skilllite_execute_code - Execute code in sandbox")
302
+ print(" • skilllite_run_skill - Run pre-defined skills")
303
+ print(" • skilllite_list_skills - List available skills")
304
+ print(" • skilllite_get_skill_info - Get skill details")
305
+ print(" • skilllite_scan_code - Scan code for security issues")
306
+ print()
307
+ print("Start OpenCode with: opencode")
308
+ print("=" * 50)
309
+
310
+ return 0
311
+ except Exception as e:
312
+ import traceback
313
+ print(f"Error: {e}", file=sys.stderr)
314
+ traceback.print_exc()
315
+ return 1
316
+