luaskills-sdk 0.2.3__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.
luaskills/__init__.py ADDED
@@ -0,0 +1,58 @@
1
+ """
2
+ Python SDK for integrating LuaSkills through the public JSON FFI surface.
3
+ 通过公共 JSON FFI 表面集成 LuaSkills 的 Python SDK。
4
+ """
5
+
6
+ from .client import (
7
+ LuaSkillsClient,
8
+ SkillConfigClient,
9
+ SkillManagementClient,
10
+ SystemSkillManagementClient,
11
+ create_engine_options,
12
+ default_host_options,
13
+ default_pool_config,
14
+ default_space_controller_options,
15
+ )
16
+ from .ffi import JsonProviderCallback, LuaSkillsError, LuaSkillsJsonFfi, resolve_library_path
17
+ from .roots import RuntimeRoots
18
+ from .runtime_assets import (
19
+ RuntimeDatabasePreset,
20
+ build_runtime_install_manifest,
21
+ host_options_from_runtime_manifest,
22
+ install_runtime_assets,
23
+ load_runtime_install_manifest,
24
+ resolve_luaskills_library_path_from_runtime,
25
+ resolve_runtime_platform_target,
26
+ runtime_manifest_path,
27
+ write_runtime_install_manifest,
28
+ )
29
+ from .types import Authority, LuaInvocationContext, RuntimeSkillRoot, SkillInstallSourceType
30
+
31
+ __all__ = [
32
+ "Authority",
33
+ "JsonProviderCallback",
34
+ "LuaInvocationContext",
35
+ "LuaSkillsClient",
36
+ "LuaSkillsError",
37
+ "LuaSkillsJsonFfi",
38
+ "RuntimeRoots",
39
+ "RuntimeSkillRoot",
40
+ "RuntimeDatabasePreset",
41
+ "SkillConfigClient",
42
+ "SkillInstallSourceType",
43
+ "SkillManagementClient",
44
+ "SystemSkillManagementClient",
45
+ "create_engine_options",
46
+ "default_host_options",
47
+ "default_pool_config",
48
+ "default_space_controller_options",
49
+ "build_runtime_install_manifest",
50
+ "host_options_from_runtime_manifest",
51
+ "install_runtime_assets",
52
+ "load_runtime_install_manifest",
53
+ "resolve_luaskills_library_path_from_runtime",
54
+ "resolve_runtime_platform_target",
55
+ "resolve_library_path",
56
+ "runtime_manifest_path",
57
+ "write_runtime_install_manifest",
58
+ ]
luaskills/cli.py ADDED
@@ -0,0 +1,347 @@
1
+ """
2
+ Command-line interface for the Python LuaSkills SDK.
3
+ Python LuaSkills SDK 的命令行接口。
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import argparse
9
+ import json
10
+ import sys
11
+ from pathlib import Path
12
+ from typing import Any
13
+
14
+ from .client import LuaSkillsClient
15
+ from .roots import RuntimeRoots
16
+ from .runtime_assets import RuntimeDatabasePreset, build_runtime_install_manifest, install_runtime_assets
17
+ from .types import Authority, RuntimeSkillRoot
18
+
19
+
20
+ def main(argv: list[str] | None = None) -> None:
21
+ """
22
+ Dispatch one CLI command and print JSON output.
23
+ 分发单个 CLI 命令并输出 JSON。
24
+ """
25
+
26
+ parser = build_parser()
27
+ args = parser.parse_args(normalize_global_args(argv if argv is not None else sys.argv[1:]))
28
+ runtime_root = Path(args.runtime_root).expanduser().resolve()
29
+ if args.command == "version":
30
+ print_json(LuaSkillsClient.version(library_path=args.lib, runtime_root=runtime_root))
31
+ return
32
+ if args.command == "describe":
33
+ print_json(LuaSkillsClient.describe(library_path=args.lib, runtime_root=runtime_root))
34
+ return
35
+
36
+ if args.command == "install-runtime":
37
+ install_options = runtime_install_options(args, runtime_root)
38
+ print_json(build_runtime_install_manifest(**install_options) if args.dry_run else install_runtime_assets(**install_options))
39
+ return
40
+
41
+ skill_roots = build_roots(args, runtime_root)
42
+ RuntimeRoots.ensure_layout(runtime_root, skill_roots)
43
+ with LuaSkillsClient(library_path=args.lib, runtime_root=runtime_root, ensure_runtime_layout=False) as client:
44
+ if args.command != "load":
45
+ client.load_from_roots(skill_roots)
46
+ dispatch_engine_command(client, skill_roots, args)
47
+
48
+
49
+ def build_parser() -> argparse.ArgumentParser:
50
+ """
51
+ Build the top-level command-line parser.
52
+ 构造顶层命令行解析器。
53
+ """
54
+
55
+ parser = argparse.ArgumentParser(prog="luaskills")
56
+ parser.add_argument("--lib", help="LuaSkills dynamic library path")
57
+ parser.add_argument("--runtime-root", default=str(Path.cwd() / "luaskills-runtime"))
58
+ parser.add_argument("--authority", default=Authority.DELEGATED_TOOL.value, choices=[Authority.SYSTEM.value, Authority.DELEGATED_TOOL.value])
59
+ parser.add_argument("--root-only", action="store_true")
60
+ parser.add_argument("--no-project", action="store_true")
61
+ parser.add_argument("--no-user", action="store_true")
62
+ parser.add_argument("--root-skills")
63
+ parser.add_argument("--project-skills")
64
+ parser.add_argument("--user-skills")
65
+ subparsers = parser.add_subparsers(dest="command", required=True)
66
+
67
+ for command in ["version", "describe", "load", "reload", "list", "help-list"]:
68
+ subparsers.add_parser(command)
69
+
70
+ install_runtime_parser = subparsers.add_parser("install-runtime")
71
+ install_runtime_parser.add_argument("--database", default=RuntimeDatabasePreset.NONE.value, choices=[preset.value for preset in RuntimeDatabasePreset])
72
+ install_runtime_parser.add_argument("--dry-run", action="store_true")
73
+ install_runtime_parser.add_argument("--skip-lua-runtime", action="store_true")
74
+ install_runtime_parser.add_argument("--skip-luaskills-ffi", action="store_true")
75
+ install_runtime_parser.add_argument("--luaskills-version", default=None)
76
+ install_runtime_parser.add_argument("--lua-runtime-version", default=None)
77
+ install_runtime_parser.add_argument("--vldb-controller-version", default=None)
78
+ install_runtime_parser.add_argument("--vldb-sqlite-version", default=None)
79
+ install_runtime_parser.add_argument("--vldb-lancedb-version", default=None)
80
+ install_runtime_parser.add_argument("--luaskills-repo", default="LuaSkills/luaskills")
81
+ install_runtime_parser.add_argument("--lua-runtime-repo", default=None)
82
+ install_runtime_parser.add_argument("--vldb-controller-repo", default="OpenVulcan/vldb-controller")
83
+ install_runtime_parser.add_argument("--vldb-sqlite-repo", default="OpenVulcan/vldb-sqlite")
84
+ install_runtime_parser.add_argument("--vldb-lancedb-repo", default="OpenVulcan/vldb-lancedb")
85
+
86
+ one_value_commands = ["help-detail", "is-skill", "skill-name", "enable", "disable", "system-enable", "system-disable"]
87
+ for command in one_value_commands:
88
+ subparser = subparsers.add_parser(command)
89
+ subparser.add_argument("first")
90
+ subparser.add_argument("second", nargs="?")
91
+
92
+ completion_parser = subparsers.add_parser("prompt-completions")
93
+ completion_parser.add_argument("prompt_name")
94
+ completion_parser.add_argument("argument_name")
95
+
96
+ call_parser = subparsers.add_parser("call")
97
+ call_parser.add_argument("tool_name")
98
+ call_parser.add_argument("args_json", nargs="?", default="{}")
99
+
100
+ run_lua_parser = subparsers.add_parser("run-lua")
101
+ run_lua_parser.add_argument("code")
102
+ run_lua_parser.add_argument("args_json", nargs="?", default="{}")
103
+
104
+ config_parser = subparsers.add_parser("config")
105
+ config_parser.add_argument("action", choices=["list", "get", "set", "delete"])
106
+ config_parser.add_argument("values", nargs="*")
107
+
108
+ for command in ["install", "update", "system-install", "system-update"]:
109
+ subparser = subparsers.add_parser(command)
110
+ subparser.add_argument("source")
111
+ subparser.add_argument("--skill-id")
112
+ subparser.add_argument("--source-type", default="github")
113
+ subparser.add_argument("--target-root")
114
+
115
+ for command in ["uninstall", "system-uninstall"]:
116
+ subparser = subparsers.add_parser(command)
117
+ subparser.add_argument("skill_id")
118
+ subparser.add_argument("--target-root")
119
+ subparser.add_argument("--remove-sqlite", action="store_true")
120
+ subparser.add_argument("--remove-lancedb", action="store_true")
121
+
122
+ return parser
123
+
124
+
125
+ def normalize_global_args(raw_args: list[str]) -> list[str]:
126
+ """
127
+ Move recognized global options before the subcommand so users may place them anywhere.
128
+ 将已识别的全局选项移动到子命令之前,使用户可把它们放在任意位置。
129
+ """
130
+
131
+ value_options = {
132
+ "--lib",
133
+ "--runtime-root",
134
+ "--authority",
135
+ "--root-skills",
136
+ "--project-skills",
137
+ "--user-skills",
138
+ }
139
+ boolean_options = {"--root-only", "--no-project", "--no-user"}
140
+ global_args: list[str] = []
141
+ command_args: list[str] = []
142
+ index = 0
143
+ while index < len(raw_args):
144
+ value = raw_args[index]
145
+ name = value.split("=", 1)[0]
146
+ if name in boolean_options:
147
+ global_args.append(value)
148
+ elif name in value_options:
149
+ global_args.append(value)
150
+ if "=" not in value:
151
+ if index + 1 >= len(raw_args):
152
+ raise ValueError(f"{value} requires a value")
153
+ global_args.append(raw_args[index + 1])
154
+ index += 1
155
+ else:
156
+ command_args.append(value)
157
+ index += 1
158
+ return global_args + command_args
159
+
160
+
161
+ def dispatch_engine_command(client: LuaSkillsClient, skill_roots: list[RuntimeSkillRoot], args: argparse.Namespace) -> None:
162
+ """
163
+ Dispatch one command that requires an engine handle.
164
+ 分发一个需要引擎句柄的命令。
165
+ """
166
+
167
+ authority = args.authority
168
+ if args.command == "load":
169
+ print_json(client.load_from_roots(skill_roots))
170
+ elif args.command == "reload":
171
+ print_json(client.reload_from_roots(skill_roots))
172
+ elif args.command == "list":
173
+ print_json(client.list_entries(authority))
174
+ elif args.command == "help-list":
175
+ print_json(client.list_skill_help(authority))
176
+ elif args.command == "help-detail":
177
+ print_json(client.render_skill_help_detail(args.first, args.second or "main", authority=authority))
178
+ elif args.command == "is-skill":
179
+ print_json({"value": client.is_skill(args.first, authority)})
180
+ elif args.command == "skill-name":
181
+ print_json({"skill_id": client.skill_name_for_tool(args.first, authority)})
182
+ elif args.command == "prompt-completions":
183
+ print_json(client.prompt_argument_completions(args.prompt_name, args.argument_name, authority))
184
+ elif args.command == "call":
185
+ print_json(client.call_skill(args.tool_name, json.loads(args.args_json)))
186
+ elif args.command == "run-lua":
187
+ print_json(client.run_lua(args.code, json.loads(args.args_json)))
188
+ elif args.command == "config":
189
+ dispatch_config_command(client, args)
190
+ elif args.command == "enable":
191
+ print_json(client.skills.enable(skill_roots, args.first))
192
+ elif args.command == "disable":
193
+ print_json(client.skills.disable(skill_roots, args.first, args.second))
194
+ elif args.command == "install":
195
+ print_json(client.skills.install(skill_roots, install_request(args), target_root=target_root(args, skill_roots)))
196
+ elif args.command == "update":
197
+ print_json(client.skills.update(skill_roots, install_request(args), target_root=target_root(args, skill_roots)))
198
+ elif args.command == "uninstall":
199
+ print_json(client.skills.uninstall(skill_roots, args.skill_id, options=uninstall_options(args), target_root=target_root(args, skill_roots)))
200
+ elif args.command == "system-enable":
201
+ print_json(client.system(authority).enable(skill_roots, args.first))
202
+ elif args.command == "system-disable":
203
+ print_json(client.system(authority).disable(skill_roots, args.first, args.second))
204
+ elif args.command == "system-install":
205
+ print_json(client.system(authority).install(skill_roots, install_request(args), target_root=target_root(args, skill_roots)))
206
+ elif args.command == "system-update":
207
+ print_json(client.system(authority).update(skill_roots, install_request(args), target_root=target_root(args, skill_roots)))
208
+ elif args.command == "system-uninstall":
209
+ print_json(client.system(authority).uninstall(skill_roots, args.skill_id, options=uninstall_options(args), target_root=target_root(args, skill_roots)))
210
+ else:
211
+ raise ValueError(f"unknown command: {args.command}")
212
+
213
+
214
+ def runtime_install_options(args: argparse.Namespace, runtime_root: Path) -> dict[str, Any]:
215
+ """
216
+ Build runtime asset installation options from CLI arguments.
217
+ 从 CLI 参数构造运行时资产安装选项。
218
+ """
219
+
220
+ options: dict[str, Any] = {
221
+ "runtime_root": runtime_root,
222
+ "database": args.database,
223
+ "include_lua_runtime": not args.skip_lua_runtime,
224
+ "include_luaskills_ffi": not args.skip_luaskills_ffi,
225
+ "luaskills_repo": args.luaskills_repo,
226
+ "lua_runtime_repo": args.lua_runtime_repo,
227
+ "vldb_controller_repo": args.vldb_controller_repo,
228
+ "vldb_sqlite_repo": args.vldb_sqlite_repo,
229
+ "vldb_lancedb_repo": args.vldb_lancedb_repo,
230
+ }
231
+ if args.luaskills_version:
232
+ options["luaskills_version"] = args.luaskills_version
233
+ if args.lua_runtime_version:
234
+ options["lua_runtime_version"] = args.lua_runtime_version
235
+ if args.vldb_controller_version:
236
+ options["vldb_controller_version"] = args.vldb_controller_version
237
+ if args.vldb_sqlite_version:
238
+ options["vldb_sqlite_version"] = args.vldb_sqlite_version
239
+ if args.vldb_lancedb_version:
240
+ options["vldb_lancedb_version"] = args.vldb_lancedb_version
241
+ return options
242
+
243
+
244
+ def dispatch_config_command(client: LuaSkillsClient, args: argparse.Namespace) -> None:
245
+ """
246
+ Dispatch one skill-config subcommand.
247
+ 分发单个 skill-config 子命令。
248
+ """
249
+
250
+ values = args.values
251
+ if args.action == "list":
252
+ require_config_value_count(args.action, values)
253
+ print_json(client.config.list(values[0] if values else None))
254
+ elif args.action == "get":
255
+ require_config_value_count(args.action, values)
256
+ print_json(client.config.get(values[0], values[1]))
257
+ elif args.action == "set":
258
+ require_config_value_count(args.action, values)
259
+ print_json(client.config.set(values[0], values[1], values[2]))
260
+ elif args.action == "delete":
261
+ require_config_value_count(args.action, values)
262
+ print_json(client.config.delete(values[0], values[1]))
263
+
264
+
265
+ def require_config_value_count(action: str, values: list[str]) -> None:
266
+ """
267
+ Validate the positional value count for one skill-config CLI action.
268
+ 校验单个 skill-config CLI 动作的位置参数数量。
269
+ """
270
+
271
+ expected_ranges = {
272
+ "list": (0, 1, "config list [skill-id]"),
273
+ "get": (2, 2, "config get <skill-id> <key>"),
274
+ "set": (3, 3, "config set <skill-id> <key> <value>"),
275
+ "delete": (2, 2, "config delete <skill-id> <key>"),
276
+ }
277
+ minimum, maximum, usage = expected_ranges[action]
278
+ if minimum <= len(values) <= maximum:
279
+ return
280
+ raise ValueError(usage)
281
+
282
+
283
+ def build_roots(args: argparse.Namespace, runtime_root: Path) -> list[RuntimeSkillRoot]:
284
+ """
285
+ Build the formal root chain from CLI flags.
286
+ 从 CLI 标志构造正式 root 链。
287
+ """
288
+
289
+ roots = RuntimeRoots.standard(
290
+ runtime_root,
291
+ include_project=not args.no_project and not args.root_only,
292
+ include_user=not args.no_user and not args.root_only,
293
+ )
294
+ replacements = {
295
+ "ROOT": args.root_skills,
296
+ "PROJECT": args.project_skills,
297
+ "USER": args.user_skills,
298
+ }
299
+ return [RuntimeSkillRoot(root.name, str(Path(replacements.get(root.name) or root.skills_dir).expanduser().resolve()).replace("\\", "/")) for root in roots]
300
+
301
+
302
+ def target_root(args: argparse.Namespace, skill_roots: list[RuntimeSkillRoot]) -> RuntimeSkillRoot | None:
303
+ """
304
+ Resolve the optional target root requested by lifecycle flags.
305
+ 解析生命周期标志请求的可选目标 root。
306
+ """
307
+
308
+ label = getattr(args, "target_root", None)
309
+ return RuntimeRoots.find_by_label(skill_roots, label) if label else None
310
+
311
+
312
+ def install_request(args: argparse.Namespace) -> dict[str, Any]:
313
+ """
314
+ Build one install or update request from CLI arguments.
315
+ 从 CLI 参数构造单个安装或更新请求。
316
+ """
317
+
318
+ return {
319
+ "skill_id": args.skill_id,
320
+ "source": args.source,
321
+ "source_type": args.source_type,
322
+ }
323
+
324
+
325
+ def uninstall_options(args: argparse.Namespace) -> dict[str, bool]:
326
+ """
327
+ Build uninstall cleanup options from CLI flags.
328
+ 从 CLI 标志构造卸载清理选项。
329
+ """
330
+
331
+ return {
332
+ "remove_sqlite": args.remove_sqlite,
333
+ "remove_lancedb": args.remove_lancedb,
334
+ }
335
+
336
+
337
+ def print_json(value: Any) -> None:
338
+ """
339
+ Print one value as pretty JSON.
340
+ 将单个值以美化 JSON 输出。
341
+ """
342
+
343
+ print(json.dumps(value, ensure_ascii=False, indent=2))
344
+
345
+
346
+ if __name__ == "__main__":
347
+ main()