skilllite 0.1.0__py3-none-any.whl → 0.1.2__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.
@@ -0,0 +1,359 @@
1
+ """
2
+ Unified Executor - Single source of truth for all skill execution.
3
+
4
+ This module provides the UnifiedExecutor class which handles all execution logic.
5
+ It uses ExecutionContext to get configuration at runtime, ensuring that any
6
+ changes to environment variables or context overrides are immediately reflected.
7
+
8
+ Key Design Principles:
9
+ 1. Never use instance variables for configuration
10
+ 2. Always read from ExecutionContext at execution time
11
+ 3. Single command building logic
12
+ 4. Single subprocess execution logic
13
+ """
14
+
15
+ import json
16
+ import os
17
+ import subprocess
18
+ from pathlib import Path
19
+ from typing import Any, Dict, List, Optional
20
+
21
+ from .base import ExecutionResult
22
+ from .context import ExecutionContext
23
+
24
+
25
+ class UnifiedExecutor:
26
+ """
27
+ Unified executor - all skill execution goes through this class.
28
+
29
+ This class is stateless regarding configuration. All configuration
30
+ comes from ExecutionContext passed to each method.
31
+ """
32
+
33
+ def __init__(self):
34
+ """Initialize the executor."""
35
+ from .skillbox import find_binary
36
+ self._binary_path = find_binary()
37
+ if not self._binary_path:
38
+ raise RuntimeError("skillbox binary not found")
39
+
40
+ @property
41
+ def binary_path(self) -> str:
42
+ """Path to the skillbox binary."""
43
+ return self._binary_path
44
+
45
+ @property
46
+ def is_available(self) -> bool:
47
+ """Check if skillbox is available."""
48
+ return self._binary_path is not None and os.path.exists(self._binary_path)
49
+
50
+ def execute(
51
+ self,
52
+ context: ExecutionContext,
53
+ skill_dir: Path,
54
+ input_data: Dict[str, Any],
55
+ entry_point: Optional[str] = None,
56
+ args: Optional[List[str]] = None,
57
+ ) -> ExecutionResult:
58
+ """
59
+ Execute a skill with the given context.
60
+
61
+ Args:
62
+ context: Execution context with all configuration
63
+ skill_dir: Path to the skill directory
64
+ input_data: Input data for the skill
65
+ entry_point: Optional specific script to execute
66
+ args: Optional command line arguments
67
+
68
+ Returns:
69
+ ExecutionResult with output or error
70
+ """
71
+ if entry_point:
72
+ return self.exec_script(
73
+ context=context,
74
+ skill_dir=skill_dir,
75
+ script_path=entry_point,
76
+ input_data=input_data,
77
+ args=args,
78
+ )
79
+
80
+ # Build command for skillbox run
81
+ cmd = self._build_run_command(context, skill_dir, input_data)
82
+ return self._run_subprocess(cmd, context, skill_dir)
83
+
84
+ def exec_script(
85
+ self,
86
+ context: ExecutionContext,
87
+ skill_dir: Path,
88
+ script_path: str,
89
+ input_data: Dict[str, Any],
90
+ args: Optional[List[str]] = None,
91
+ ) -> ExecutionResult:
92
+ """
93
+ Execute a specific script directly.
94
+
95
+ Args:
96
+ context: Execution context with all configuration
97
+ skill_dir: Path to the skill directory
98
+ script_path: Relative path to the script
99
+ input_data: Input data for the script
100
+ args: Optional command line arguments
101
+
102
+ Returns:
103
+ ExecutionResult with output or error
104
+ """
105
+ # Convert JSON input to CLI args if no explicit args provided
106
+ if args is None and input_data:
107
+ args = self._convert_json_to_cli_args(input_data)
108
+
109
+ # For Level 1/2 Python scripts, use direct execution for better performance
110
+ if script_path.endswith('.py') and context.sandbox_level != "3":
111
+ return self._exec_python_direct(context, skill_dir, script_path, args)
112
+
113
+ # Build command for skillbox exec
114
+ cmd = self._build_exec_command(context, skill_dir, script_path, input_data, args)
115
+ return self._run_subprocess(cmd, context, skill_dir)
116
+
117
+ def _build_run_command(
118
+ self,
119
+ context: ExecutionContext,
120
+ skill_dir: Path,
121
+ input_data: Dict[str, Any],
122
+ ) -> List[str]:
123
+ """Build command for skillbox run."""
124
+ # Convert to absolute path to avoid path issues
125
+ abs_skill_dir = Path(skill_dir).resolve()
126
+ cmd = [
127
+ self._binary_path,
128
+ "run",
129
+ str(abs_skill_dir),
130
+ json.dumps(input_data),
131
+ ]
132
+
133
+ # Add sandbox level from context (NOT from instance variable)
134
+ cmd.extend(["--sandbox-level", context.sandbox_level])
135
+
136
+ if context.allow_network:
137
+ cmd.append("--allow-network")
138
+
139
+ cmd.extend(["--timeout", str(context.timeout)])
140
+ cmd.extend(["--max-memory", str(context.max_memory_mb)])
141
+
142
+ return cmd
143
+
144
+ def _build_exec_command(
145
+ self,
146
+ context: ExecutionContext,
147
+ skill_dir: Path,
148
+ script_path: str,
149
+ input_data: Dict[str, Any],
150
+ args: Optional[List[str]] = None,
151
+ ) -> List[str]:
152
+ """Build command for skillbox exec."""
153
+ # Convert to absolute path to avoid path issues
154
+ abs_skill_dir = Path(skill_dir).resolve()
155
+ cmd = [
156
+ self._binary_path,
157
+ "exec",
158
+ str(abs_skill_dir),
159
+ script_path,
160
+ json.dumps(input_data),
161
+ ]
162
+
163
+ if args:
164
+ args_str = " ".join(args) if isinstance(args, list) else args
165
+ cmd.extend(["--args", args_str])
166
+
167
+ # Add sandbox level from context (NOT from instance variable)
168
+ cmd.extend(["--sandbox-level", context.sandbox_level])
169
+
170
+ if context.allow_network:
171
+ cmd.append("--allow-network")
172
+
173
+ cmd.extend(["--timeout", str(context.timeout)])
174
+ cmd.extend(["--max-memory", str(context.max_memory_mb)])
175
+
176
+ return cmd
177
+
178
+ def _run_subprocess(
179
+ self,
180
+ cmd: List[str],
181
+ context: ExecutionContext,
182
+ skill_dir: Path,
183
+ ) -> ExecutionResult:
184
+ """Run subprocess with the given command."""
185
+ env = self._build_env(context, skill_dir)
186
+
187
+ try:
188
+ if context.sandbox_level == "3" and not context.confirmed:
189
+ # Level 3 without confirmation: allow stderr for prompts
190
+ result = subprocess.run(
191
+ cmd,
192
+ stdin=None,
193
+ stdout=subprocess.PIPE,
194
+ stderr=None,
195
+ text=True,
196
+ timeout=context.timeout,
197
+ env=env,
198
+ )
199
+ return self._parse_output(result.stdout, "", result.returncode)
200
+ else:
201
+ # Level 1/2 or confirmed: capture all output
202
+ result = subprocess.run(
203
+ cmd,
204
+ capture_output=True,
205
+ text=True,
206
+ timeout=context.timeout,
207
+ env=env,
208
+ )
209
+ return self._parse_output(result.stdout, result.stderr, result.returncode)
210
+
211
+ except subprocess.TimeoutExpired:
212
+ return ExecutionResult(
213
+ success=False,
214
+ error=f"Execution timed out after {context.timeout} seconds",
215
+ exit_code=-1,
216
+ )
217
+ except FileNotFoundError:
218
+ return ExecutionResult(
219
+ success=False,
220
+ error=f"skillbox binary not found at: {self._binary_path}",
221
+ exit_code=-1,
222
+ )
223
+ except Exception as e:
224
+ return ExecutionResult(
225
+ success=False,
226
+ error=f"Execution failed: {str(e)}",
227
+ exit_code=-1,
228
+ )
229
+
230
+ def _build_env(
231
+ self,
232
+ context: ExecutionContext,
233
+ skill_dir: Path,
234
+ ) -> Dict[str, str]:
235
+ """Build environment variables for subprocess."""
236
+ env = os.environ.copy()
237
+
238
+ # Set sandbox level in environment (for consistency)
239
+ env["SKILLBOX_SANDBOX_LEVEL"] = context.sandbox_level
240
+ env["SKILLBOX_AUTO_APPROVE"] = "1" if context.auto_approve or context.confirmed else "1"
241
+
242
+ # Set skill-specific environment
243
+ env["SKILL_DIR"] = str(skill_dir)
244
+ env["SKILLBOX_TIMEOUT_SECS"] = str(context.timeout)
245
+ env["SKILLBOX_MAX_MEMORY_MB"] = str(context.max_memory_mb)
246
+
247
+ return env
248
+
249
+ def _exec_python_direct(
250
+ self,
251
+ context: ExecutionContext,
252
+ skill_dir: Path,
253
+ script_path: str,
254
+ args: Optional[List[str]] = None,
255
+ ) -> ExecutionResult:
256
+ """Execute Python script directly (for Level 1/2)."""
257
+ import sys
258
+
259
+ # Convert to absolute path to avoid path duplication issues
260
+ abs_skill_dir = Path(skill_dir).resolve()
261
+ full_script_path = abs_skill_dir / script_path
262
+
263
+ if not full_script_path.exists():
264
+ return ExecutionResult(
265
+ success=False,
266
+ error=f"Script not found: {full_script_path}",
267
+ exit_code=-1,
268
+ )
269
+
270
+ cmd = [sys.executable, str(full_script_path)]
271
+ if args:
272
+ cmd.extend(args)
273
+
274
+ env = self._build_env(context, abs_skill_dir)
275
+ env["PYTHONPATH"] = str(abs_skill_dir)
276
+
277
+ try:
278
+ # Don't set cwd to skill_dir - let scripts run from project root
279
+ # Scripts can use SKILL_DIR env var to find their own location
280
+ # This allows scripts like skill-creator to work with relative paths
281
+ # that are relative to the project root, not the skill directory
282
+ result = subprocess.run(
283
+ cmd,
284
+ capture_output=True,
285
+ text=True,
286
+ timeout=context.timeout,
287
+ env=env,
288
+ )
289
+ return self._parse_output(result.stdout, result.stderr, result.returncode)
290
+ except subprocess.TimeoutExpired:
291
+ return ExecutionResult(
292
+ success=False,
293
+ error=f"Execution timed out after {context.timeout} seconds",
294
+ exit_code=-1,
295
+ )
296
+ except Exception as e:
297
+ return ExecutionResult(
298
+ success=False,
299
+ error=f"Execution failed: {str(e)}",
300
+ exit_code=-1,
301
+ )
302
+
303
+ def _convert_json_to_cli_args(self, input_data: Dict[str, Any]) -> List[str]:
304
+ """Convert JSON input to CLI arguments.
305
+
306
+ Delegates to the shared utility function that properly handles
307
+ positional arguments like 'skill_name'.
308
+ """
309
+ from .utils import convert_json_to_cli_args
310
+ return convert_json_to_cli_args(input_data)
311
+
312
+ def _parse_output(
313
+ self,
314
+ stdout: str,
315
+ stderr: str,
316
+ returncode: int,
317
+ ) -> ExecutionResult:
318
+ """Parse subprocess output into ExecutionResult."""
319
+ combined = stdout + stderr
320
+
321
+ # Try to parse JSON output
322
+ try:
323
+ # Look for JSON in output
324
+ for line in combined.split('\n'):
325
+ line = line.strip()
326
+ if line.startswith('{') and line.endswith('}'):
327
+ data = json.loads(line)
328
+ if isinstance(data, dict):
329
+ return ExecutionResult(
330
+ success=returncode == 0,
331
+ output=data,
332
+ exit_code=returncode,
333
+ stdout=stdout,
334
+ stderr=stderr,
335
+ )
336
+ except json.JSONDecodeError:
337
+ pass
338
+
339
+ # Return as plain text
340
+ if returncode == 0:
341
+ return ExecutionResult(
342
+ success=True,
343
+ output={"result": stdout.strip()} if stdout.strip() else None,
344
+ exit_code=returncode,
345
+ stdout=stdout,
346
+ stderr=stderr,
347
+ )
348
+ else:
349
+ error_msg = stderr.strip() if stderr.strip() else stdout.strip()
350
+ return ExecutionResult(
351
+ success=False,
352
+ error=f"Skill execution failed with exit code {returncode}: {error_msg}",
353
+ exit_code=returncode,
354
+ stdout=stdout,
355
+ stderr=stderr,
356
+ )
357
+
358
+
359
+ __all__ = ["UnifiedExecutor"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: skilllite
3
- Version: 0.1.0
3
+ Version: 0.1.2
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
@@ -32,10 +32,16 @@ Provides-Extra: anthropic
32
32
  Requires-Dist: anthropic>=0.18.0; extra == "anthropic"
33
33
  Provides-Extra: mcp
34
34
  Requires-Dist: mcp>=1.0.0; extra == "mcp"
35
+ Provides-Extra: langchain
36
+ Requires-Dist: langchain-core>=0.1.0; extra == "langchain"
37
+ Provides-Extra: llamaindex
38
+ Requires-Dist: llama-index-core>=0.10.0; extra == "llamaindex"
35
39
  Provides-Extra: all
36
40
  Requires-Dist: openai>=1.0.0; extra == "all"
37
41
  Requires-Dist: anthropic>=0.18.0; extra == "all"
38
42
  Requires-Dist: mcp>=1.0.0; extra == "all"
43
+ Requires-Dist: langchain-core>=0.1.0; extra == "all"
44
+ Requires-Dist: llama-index-core>=0.10.0; extra == "all"
39
45
  Provides-Extra: dev
40
46
  Requires-Dist: pytest>=7.0; extra == "dev"
41
47
  Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
@@ -288,6 +294,150 @@ Enum for LLM provider formats:
288
294
  - `ToolFormat.CLAUDE`
289
295
  - `ToolFormat.OPENAI`
290
296
 
297
+ ## Framework Adapters
298
+
299
+ SkillLite provides adapters for popular AI frameworks with security confirmation support.
300
+
301
+ ### LangChain Integration
302
+
303
+ For LangChain/LangGraph integration, we recommend using the dedicated **[langchain-skilllite](https://pypi.org/project/langchain-skilllite/)** package:
304
+
305
+ ```bash
306
+ pip install langchain-skilllite
307
+ ```
308
+
309
+ ```python
310
+ from langchain_skilllite import SkillLiteToolkit
311
+ from langchain_openai import ChatOpenAI
312
+ from langgraph.prebuilt import create_react_agent
313
+
314
+ # Load all skills from a directory as LangChain tools
315
+ tools = SkillLiteToolkit.from_directory("./skills")
316
+
317
+ # Create a LangGraph agent
318
+ agent = create_react_agent(ChatOpenAI(model="gpt-4"), tools)
319
+
320
+ # Run the agent
321
+ result = agent.invoke({
322
+ "messages": [("user", "Convert 'hello world' to uppercase")]
323
+ })
324
+ ```
325
+
326
+ With security confirmation (sandbox_level=3):
327
+
328
+ ```python
329
+ def confirm_execution(report: str, scan_id: str) -> bool:
330
+ print(report)
331
+ return input("Continue? [y/N]: ").lower() == 'y'
332
+
333
+ tools = SkillLiteToolkit.from_directory(
334
+ "./skills",
335
+ sandbox_level=3, # 1=no sandbox, 2=sandbox only, 3=sandbox+scan
336
+ confirmation_callback=confirm_execution
337
+ )
338
+ ```
339
+
340
+ For more details, see the [langchain-skilllite documentation](../langchain-skilllite/README.md).
341
+
342
+ **Alternative**: You can also use the built-in adapter:
343
+
344
+ ```python
345
+ from skilllite import SkillManager
346
+ from skilllite.core.adapters.langchain import SkillLiteToolkit
347
+
348
+ manager = SkillManager(skills_dir="./skills")
349
+ tools = SkillLiteToolkit.from_manager(manager).get_tools()
350
+ ```
351
+
352
+ ### LlamaIndex Integration
353
+
354
+ ```python
355
+ from skilllite import SkillManager
356
+ from skilllite.core.adapters.llamaindex import SkillLiteToolSpec
357
+
358
+ manager = SkillManager(skills_dir="./skills")
359
+
360
+ # Basic usage
361
+ tool_spec = SkillLiteToolSpec.from_manager(manager)
362
+ tools = tool_spec.to_tool_list()
363
+
364
+ # With security confirmation
365
+ def confirm(report: str, scan_id: str) -> bool:
366
+ print(report)
367
+ return input("Continue? [y/N]: ").lower() == 'y'
368
+
369
+ tool_spec = SkillLiteToolSpec.from_manager(
370
+ manager,
371
+ sandbox_level=3,
372
+ confirmation_callback=confirm
373
+ )
374
+
375
+ # Use with LlamaIndex agent
376
+ from llama_index.core.agent import ReActAgent
377
+ agent = ReActAgent.from_tools(tools, llm=llm)
378
+ ```
379
+
380
+ ### Security Levels
381
+
382
+ | Level | Description |
383
+ |-------|-------------|
384
+ | 1 | No sandbox - direct execution |
385
+ | 2 | Sandbox isolation only |
386
+ | 3 | Sandbox + static security scan (requires confirmation for high-severity issues) |
387
+
388
+ ## OpenCode Integration
389
+
390
+ SkillLite can be integrated with [OpenCode](https://github.com/opencode-ai/opencode) as an MCP (Model Context Protocol) server, providing secure sandbox execution capabilities.
391
+
392
+ ### Quick Setup
393
+
394
+ ```bash
395
+ # Install with MCP support
396
+ pip install skilllite[mcp]
397
+
398
+ # One-command setup for OpenCode
399
+ skilllite init-opencode
400
+
401
+ # Start OpenCode
402
+ opencode
403
+ ```
404
+
405
+ The `init-opencode` command automatically:
406
+ - Detects the best way to start the MCP server (uvx, pipx, skilllite, or python)
407
+ - Creates `opencode.json` with optimal configuration
408
+ - Generates `.opencode/skills/skilllite/SKILL.md` with usage instructions
409
+ - Discovers your pre-defined skills
410
+
411
+ ### Available MCP Tools
412
+
413
+ | Tool | Description |
414
+ |------|-------------|
415
+ | `skilllite_list_skills` | List all available skills |
416
+ | `skilllite_get_skill_info` | Get skill details and input schema |
417
+ | `skilllite_run_skill` | Execute a pre-defined skill |
418
+ | `skilllite_scan_code` | Scan code for security issues |
419
+ | `skilllite_execute_code` | Execute code in secure sandbox |
420
+
421
+ ### Security Features
422
+
423
+ - **System-level Sandbox**: macOS Seatbelt / Linux Namespace isolation
424
+ - **Security Scanning**: Static analysis before execution
425
+ - **User Confirmation**: Dangerous code requires explicit approval
426
+ - **Scan ID Verification**: Prevents code modification between scan and execution
427
+
428
+ For detailed documentation, see [OpenCode Integration Tutorial](../tutorials/07_opencode_integration/README.md).
429
+
430
+ ## CLI Commands
431
+
432
+ ```bash
433
+ skilllite install # Install skillbox sandbox binary
434
+ skilllite uninstall # Remove skillbox binary
435
+ skilllite status # Show installation status
436
+ skilllite version # Show version information
437
+ skilllite mcp # Start MCP server
438
+ skilllite init-opencode # Initialize OpenCode integration
439
+ ```
440
+
291
441
  ## License
292
442
 
293
443
  MIT License
@@ -0,0 +1,45 @@
1
+ skilllite/__init__.py,sha256=D_6otb8PNLUqpxlsp_7WtLJlX7JDziOxGBc8iQhER9Q,3984
2
+ skilllite/analyzer.py,sha256=YG-ZJ6bO59pkP8LGECjcyCDPpH6wUYOm5QGx6et-ItA,14504
3
+ skilllite/builtin_tools.py,sha256=MGIlMlYTfj590PCY4ngbQteDIryfH7sDoKQyrDTH6L8,8067
4
+ skilllite/quick.py,sha256=_NWMBMywn0EK0dNeicbz37-M3UfnC7di3wjdBB0rPA4,16768
5
+ skilllite/validation.py,sha256=K3Hn6VKT7aybdKX8GXSRaxLbKmyVAnMYmP9cqh-D4s4,4308
6
+ skilllite/cli/__init__.py,sha256=PATRR5ZeAoB9H4gzVgw_5VAiP1GybZOuiAa1rOKFdW0,611
7
+ skilllite/cli/__main__.py,sha256=69kpU78u45_64qSgv1v6x3m3xxaWjHwb-QdjbpxXZCo,152
8
+ skilllite/cli/binary.py,sha256=Yp8um1G33r9SFuiAJcJ41XaMotHuNKo08bCet-0jd0g,2264
9
+ skilllite/cli/main.py,sha256=cyLb6l7dDuvmu7ZCJhUsU9MeTzQo0qKLrnC75EKf5Sw,3983
10
+ skilllite/cli/mcp.py,sha256=Kp-Z6aRZ7NB3T-y-b56jx6AnRyPOkfzfFQmBxYAB23Q,767
11
+ skilllite/cli/integrations/__init__.py,sha256=-NWqUaDEPCRpykfDOvl2zfpUfLIH3UxG1qUbmTvb92o,120
12
+ skilllite/cli/integrations/opencode.py,sha256=wT7rCqOkmX9GdhI994-0HhUtZEJ3PELPOC9PRscQDls,10521
13
+ skilllite/core/__init__.py,sha256=N6ZEqHBnmnhtZksqVDayCZ0oPEM_rACRsGhzNm191tU,2089
14
+ skilllite/core/executor.py,sha256=eNPcVKxKcLUjHJ7K2hstKtxobZiDIvPjk2IhbZv3nxo,6517
15
+ skilllite/core/handler.py,sha256=wVucut7ZfDxgCa3b6A99hxq-6OycRRQaMfGyBuxNMWk,16623
16
+ skilllite/core/loops.py,sha256=MVPMUOYgJT6VEvtAavB1PR-6kBh5kE7BlFE4ndBRgzE,39195
17
+ skilllite/core/manager.py,sha256=t87Qyql2YZQrUTiGAbI3q-8LF5Hiuy81HUvKCzwWtyQ,22451
18
+ skilllite/core/metadata.py,sha256=N-EOtPIRVM8sCAvvd75ogpqE3w2qIN-WKQ562mKHtPI,11607
19
+ skilllite/core/prompt_builder.py,sha256=rsubLzien9lKjOqM6iTn5nourPnz1-QQGzljiO0Z_3I,12844
20
+ skilllite/core/registry.py,sha256=AeljsV1uuYEJFGjpSwYxU6JGJ6EUuW8uNO3KirzHkuQ,6622
21
+ skilllite/core/security.py,sha256=Z91v4lltHDTJsk2tM1Ezu2TwjmZiWUqKlFKDABZEv2k,14185
22
+ skilllite/core/skill_info.py,sha256=4_jsArmn1e7jEUXDEkmDAzjSI_903sdpfNLHOp1t1-M,6079
23
+ skilllite/core/tool_builder.py,sha256=k28ze50h7AjBiEfgKR6Y4DUFIGZJ1sCYbHEk_VkYl7w,12866
24
+ skilllite/core/tools.py,sha256=3RiAnZ_7S7iE6ZHXTPNKmAYQFY8SBUEzcQJZA0tZmX8,8168
25
+ skilllite/core/adapters/__init__.py,sha256=cvPkwBxRCyoNi4GWkAYwsoNuJqR-BdziLm83EEkBhio,2698
26
+ skilllite/core/adapters/langchain.py,sha256=osacceLNv3mo5x8Oe9obzefGpH1hhxhbXqMavSKAo5Y,13169
27
+ skilllite/core/adapters/llamaindex.py,sha256=El-oQxzniMv9rPVdH6udmzrzz_hE50rd1goVWxzib68,9037
28
+ skilllite/mcp/__init__.py,sha256=xrpoWy9zs8IJkW6fkkR4XjQrITo5PWvFW9NkmK8E2Fg,1028
29
+ skilllite/mcp/server.py,sha256=VsdR36dF4YR3l5IUEsE7NfXd_zppy5J6egRVs_PhfSM,47934
30
+ skilllite/sandbox/__init__.py,sha256=6LPisVXB94SJ-C34nBAxd05NGEZR4PPxz2xaDpX4qEk,918
31
+ skilllite/sandbox/base.py,sha256=-Ul2QufoQ3myJNzBOEdv30A2HVSR9Oe4zEqpe9oJGqY,2628
32
+ skilllite/sandbox/config.py,sha256=eA3ceou6jF4S5kptv6cmIGKynQTaGDx3_vRrkJGQaAE,8207
33
+ skilllite/sandbox/context.py,sha256=3C8Z3RiXJCcFI-Sx4nT9Dkf0d38BPzRTCsAbj-NODWc,5982
34
+ skilllite/sandbox/execution_service.py,sha256=vQERxKzRk4rc50qmuPQfR9OY62bybm3KH_Q-kuzCl8s,8937
35
+ skilllite/sandbox/unified_executor.py,sha256=4gSwTd1-EwLWSZ1dyM3eXauhyTd32vCkS6sVr6m3qYM,12229
36
+ skilllite/sandbox/utils.py,sha256=o5AZVkhqIcZE9veUy7FTfN7uMHVWJJLYXs7gYIXsptg,2572
37
+ skilllite/sandbox/skillbox/__init__.py,sha256=SFnNlLnnAc_NEEkqOkDbxYNfXROL7n1S09K_HFI_BOE,866
38
+ skilllite/sandbox/skillbox/binary.py,sha256=TNKQamWucMw-J6L5BjAasNpYqhBcBpHwQPMqjUOkgp4,11838
39
+ skilllite/sandbox/skillbox/executor.py,sha256=xobVd5JmzJnwouVOO3arvN6IuC5VH28SXPqKHCXalHM,27175
40
+ skilllite-0.1.2.dist-info/licenses/LICENSE,sha256=ESBZ3GI5LkrbA2s5jZUQDqdcQ8oRlmk04aIYh34cOsw,1071
41
+ skilllite-0.1.2.dist-info/METADATA,sha256=A56Fqpe_U_BY5vls_YUSxnvqvYb4lunbyQRPaB1Gguc,12706
42
+ skilllite-0.1.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
43
+ skilllite-0.1.2.dist-info/entry_points.txt,sha256=H-meSKN3XzctxMvY6fa-YjAWyzs9t_0IjujOfumn4Wk,84
44
+ skilllite-0.1.2.dist-info/top_level.txt,sha256=aqo-9FEJuBbFT7WGE3aycTj27OxyQPCN6TuZtOcClAI,10
45
+ skilllite-0.1.2.dist-info/RECORD,,