qodalis-cli-server 1.0.0b1__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 (42) hide show
  1. qodalis_cli/__init__.py +112 -0
  2. qodalis_cli/abstractions/__init__.py +25 -0
  3. qodalis_cli/abstractions/cli_command_author.py +7 -0
  4. qodalis_cli/abstractions/cli_command_parameter_descriptor.py +6 -0
  5. qodalis_cli/abstractions/cli_command_processor.py +6 -0
  6. qodalis_cli/abstractions/cli_process_command.py +3 -0
  7. qodalis_cli/controllers/__init__.py +11 -0
  8. qodalis_cli/controllers/cli_controller.py +111 -0
  9. qodalis_cli/controllers/cli_controller_v2.py +91 -0
  10. qodalis_cli/controllers/cli_version_controller.py +45 -0
  11. qodalis_cli/controllers/filesystem_controller.py +329 -0
  12. qodalis_cli/create_cli_server.py +157 -0
  13. qodalis_cli/extensions/__init__.py +3 -0
  14. qodalis_cli/extensions/cli_builder.py +51 -0
  15. qodalis_cli/filesystem/__init__.py +4 -0
  16. qodalis_cli/filesystem/filesystem_options.py +16 -0
  17. qodalis_cli/filesystem/filesystem_path_validator.py +42 -0
  18. qodalis_cli/models/__init__.py +13 -0
  19. qodalis_cli/models/cli_server_command_descriptor.py +30 -0
  20. qodalis_cli/models/cli_server_output.py +47 -0
  21. qodalis_cli/models/cli_server_response.py +12 -0
  22. qodalis_cli/processors/__init__.py +17 -0
  23. qodalis_cli/processors/cli_base64_command_processor.py +61 -0
  24. qodalis_cli/processors/cli_echo_command_processor.py +17 -0
  25. qodalis_cli/processors/cli_hash_command_processor.py +49 -0
  26. qodalis_cli/processors/cli_http_command_processor.py +143 -0
  27. qodalis_cli/processors/cli_status_command_processor.py +24 -0
  28. qodalis_cli/processors/cli_system_command_processor.py +34 -0
  29. qodalis_cli/processors/cli_uuid_command_processor.py +39 -0
  30. qodalis_cli/server.py +44 -0
  31. qodalis_cli/services/__init__.py +19 -0
  32. qodalis_cli/services/cli_command_executor_service.py +62 -0
  33. qodalis_cli/services/cli_command_registry.py +68 -0
  34. qodalis_cli/services/cli_event_socket_manager.py +46 -0
  35. qodalis_cli/services/cli_log_socket_manager.py +153 -0
  36. qodalis_cli/services/cli_response_builder.py +73 -0
  37. qodalis_cli/services/cli_shell_session_manager.py +201 -0
  38. qodalis_cli_server-1.0.0b1.dist-info/METADATA +689 -0
  39. qodalis_cli_server-1.0.0b1.dist-info/RECORD +42 -0
  40. qodalis_cli_server-1.0.0b1.dist-info/WHEEL +4 -0
  41. qodalis_cli_server-1.0.0b1.dist-info/entry_points.txt +2 -0
  42. qodalis_cli_server-1.0.0b1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,112 @@
1
+ """Qodalis CLI Server - A Python CLI server framework for the Qodalis CLI ecosystem."""
2
+
3
+ from .abstractions import (
4
+ ICliCommandAuthor,
5
+ CliCommandAuthor,
6
+ DEFAULT_LIBRARY_AUTHOR,
7
+ CliProcessCommand,
8
+ ICliCommandParameterDescriptor,
9
+ CliCommandParameterDescriptor,
10
+ ICliCommandProcessor,
11
+ CliCommandProcessor,
12
+ ICliModule,
13
+ CliModule,
14
+ )
15
+ from .models import (
16
+ CliServerOutput,
17
+ CliServerResponse,
18
+ CliServerCommandDescriptor,
19
+ CliServerCommandParameterDescriptorDto,
20
+ )
21
+ from .services import (
22
+ ICliCommandRegistry,
23
+ CliCommandRegistry,
24
+ ICliResponseBuilder,
25
+ CliResponseBuilder,
26
+ ICliCommandExecutorService,
27
+ CliCommandExecutorService,
28
+ CliEventSocketManager,
29
+ CliShellSessionManager,
30
+ )
31
+ from .controllers import create_cli_router, create_cli_router_v2, create_cli_version_router, create_filesystem_router
32
+ from .extensions import CliBuilder
33
+ from .filesystem import FileSystemOptions, FileSystemPathValidator
34
+
35
+ # Re-export filesystem plugin types for convenience
36
+ from qodalis_cli_filesystem import (
37
+ FileEntry,
38
+ FileStat,
39
+ FileStorageExistsError,
40
+ FileStorageIsADirectoryError,
41
+ FileStorageNotADirectoryError,
42
+ FileStorageNotFoundError,
43
+ FileStoragePermissionError,
44
+ IFileStorageProvider,
45
+ )
46
+ from qodalis_cli_filesystem.providers import (
47
+ InMemoryFileStorageProvider,
48
+ OsFileStorageProvider,
49
+ OsProviderOptions,
50
+ )
51
+ from .processors import (
52
+ CliEchoCommandProcessor,
53
+ CliStatusCommandProcessor,
54
+ CliSystemCommandProcessor,
55
+ CliHttpCommandProcessor,
56
+ CliHashCommandProcessor,
57
+ CliBase64CommandProcessor,
58
+ CliUuidCommandProcessor,
59
+ )
60
+ from .create_cli_server import create_cli_server, CliServerOptions
61
+
62
+ __all__ = [
63
+ "ICliCommandAuthor",
64
+ "CliCommandAuthor",
65
+ "DEFAULT_LIBRARY_AUTHOR",
66
+ "CliProcessCommand",
67
+ "ICliCommandParameterDescriptor",
68
+ "CliCommandParameterDescriptor",
69
+ "ICliCommandProcessor",
70
+ "CliCommandProcessor",
71
+ "ICliModule",
72
+ "CliModule",
73
+ "CliServerOutput",
74
+ "CliServerResponse",
75
+ "CliServerCommandDescriptor",
76
+ "CliServerCommandParameterDescriptorDto",
77
+ "ICliCommandRegistry",
78
+ "CliCommandRegistry",
79
+ "ICliResponseBuilder",
80
+ "CliResponseBuilder",
81
+ "ICliCommandExecutorService",
82
+ "CliCommandExecutorService",
83
+ "CliEventSocketManager",
84
+ "CliShellSessionManager",
85
+ "create_cli_router",
86
+ "create_cli_router_v2",
87
+ "create_cli_version_router",
88
+ "create_filesystem_router",
89
+ "CliBuilder",
90
+ "FileSystemOptions",
91
+ "FileSystemPathValidator",
92
+ "CliEchoCommandProcessor",
93
+ "CliStatusCommandProcessor",
94
+ "CliSystemCommandProcessor",
95
+ "CliHttpCommandProcessor",
96
+ "CliHashCommandProcessor",
97
+ "CliBase64CommandProcessor",
98
+ "CliUuidCommandProcessor",
99
+ "create_cli_server",
100
+ "CliServerOptions",
101
+ "FileEntry",
102
+ "FileStat",
103
+ "FileStorageExistsError",
104
+ "FileStorageIsADirectoryError",
105
+ "FileStorageNotADirectoryError",
106
+ "FileStorageNotFoundError",
107
+ "FileStoragePermissionError",
108
+ "IFileStorageProvider",
109
+ "InMemoryFileStorageProvider",
110
+ "OsFileStorageProvider",
111
+ "OsProviderOptions",
112
+ ]
@@ -0,0 +1,25 @@
1
+ from qodalis_cli_server_abstractions import (
2
+ ICliCommandAuthor,
3
+ CliCommandAuthor,
4
+ DEFAULT_LIBRARY_AUTHOR,
5
+ CliProcessCommand,
6
+ ICliCommandParameterDescriptor,
7
+ CliCommandParameterDescriptor,
8
+ ICliCommandProcessor,
9
+ CliCommandProcessor,
10
+ ICliModule,
11
+ CliModule,
12
+ )
13
+
14
+ __all__ = [
15
+ "ICliCommandAuthor",
16
+ "CliCommandAuthor",
17
+ "DEFAULT_LIBRARY_AUTHOR",
18
+ "CliProcessCommand",
19
+ "ICliCommandParameterDescriptor",
20
+ "CliCommandParameterDescriptor",
21
+ "ICliCommandProcessor",
22
+ "CliCommandProcessor",
23
+ "ICliModule",
24
+ "CliModule",
25
+ ]
@@ -0,0 +1,7 @@
1
+ from qodalis_cli_server_abstractions.cli_command_author import (
2
+ ICliCommandAuthor,
3
+ CliCommandAuthor,
4
+ DEFAULT_LIBRARY_AUTHOR,
5
+ )
6
+
7
+ __all__ = ["ICliCommandAuthor", "CliCommandAuthor", "DEFAULT_LIBRARY_AUTHOR"]
@@ -0,0 +1,6 @@
1
+ from qodalis_cli_server_abstractions.cli_command_parameter_descriptor import (
2
+ ICliCommandParameterDescriptor,
3
+ CliCommandParameterDescriptor,
4
+ )
5
+
6
+ __all__ = ["ICliCommandParameterDescriptor", "CliCommandParameterDescriptor"]
@@ -0,0 +1,6 @@
1
+ from qodalis_cli_server_abstractions.cli_command_processor import (
2
+ ICliCommandProcessor,
3
+ CliCommandProcessor,
4
+ )
5
+
6
+ __all__ = ["ICliCommandProcessor", "CliCommandProcessor"]
@@ -0,0 +1,3 @@
1
+ from qodalis_cli_server_abstractions.cli_process_command import CliProcessCommand
2
+
3
+ __all__ = ["CliProcessCommand"]
@@ -0,0 +1,11 @@
1
+ from .cli_controller import create_cli_router
2
+ from .cli_controller_v2 import create_cli_router_v2
3
+ from .cli_version_controller import create_cli_version_router
4
+ from .filesystem_controller import create_filesystem_router
5
+
6
+ __all__ = [
7
+ "create_cli_router",
8
+ "create_cli_router_v2",
9
+ "create_cli_version_router",
10
+ "create_filesystem_router",
11
+ ]
@@ -0,0 +1,111 @@
1
+ from __future__ import annotations
2
+
3
+ import platform
4
+ from typing import Any
5
+
6
+ from fastapi import APIRouter
7
+ from fastapi.responses import JSONResponse
8
+ from pydantic import BaseModel, Field
9
+
10
+ from ..abstractions import ICliCommandProcessor
11
+ from ..abstractions.cli_process_command import CliProcessCommand
12
+ from ..models import CliServerCommandDescriptor, CliServerCommandParameterDescriptorDto, CliServerResponse
13
+ from ..services.cli_command_executor_service import ICliCommandExecutorService
14
+ from ..services.cli_command_registry import ICliCommandRegistry
15
+
16
+ SERVER_VERSION = "1.0.0"
17
+
18
+
19
+ class ExecuteRequest(BaseModel):
20
+ command: str = ""
21
+ raw_command: str = Field(alias="rawCommand", default="")
22
+ value: str | None = None
23
+ args: dict[str, Any] = Field(default_factory=dict)
24
+ chain_commands: list[str] = Field(alias="chainCommands", default_factory=list)
25
+ data: Any = None
26
+
27
+ model_config = {"populate_by_name": True}
28
+
29
+
30
+ def _map_to_descriptor(processor: ICliCommandProcessor) -> dict[str, Any]:
31
+ params = None
32
+ if processor.parameters:
33
+ params = [
34
+ CliServerCommandParameterDescriptorDto(
35
+ name=p.name,
36
+ description=p.description,
37
+ required=p.required,
38
+ type=p.type,
39
+ aliases=p.aliases,
40
+ defaultValue=p.default_value,
41
+ ).model_dump(by_alias=True, exclude_none=True)
42
+ for p in processor.parameters
43
+ ]
44
+
45
+ subs = None
46
+ if processor.processors:
47
+ subs = [_map_to_descriptor(p) for p in processor.processors]
48
+
49
+ desc = CliServerCommandDescriptor(
50
+ command=processor.command,
51
+ description=processor.description,
52
+ version=processor.version,
53
+ parameters=params if params else None,
54
+ processors=subs if subs else None,
55
+ allowUnlistedCommands=processor.allow_unlisted_commands,
56
+ valueRequired=processor.value_required,
57
+ author={"name": processor.author.name, "email": processor.author.email},
58
+ )
59
+ return desc.model_dump(by_alias=True, exclude_none=True)
60
+
61
+
62
+ def create_cli_router(
63
+ registry: ICliCommandRegistry,
64
+ executor: ICliCommandExecutorService,
65
+ ) -> APIRouter:
66
+ router = APIRouter()
67
+
68
+ @router.get("/version")
69
+ async def get_version() -> dict[str, str]:
70
+ return {"version": SERVER_VERSION}
71
+
72
+ @router.get("/capabilities")
73
+ async def get_capabilities() -> dict[str, Any]:
74
+ detected_os = (
75
+ "darwin" if platform.system() == "Darwin"
76
+ else "win32" if platform.system() == "Windows"
77
+ else "linux"
78
+ )
79
+
80
+ shell = "powershell" if platform.system() == "Windows" else "bash"
81
+ shell_path = (
82
+ "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
83
+ if platform.system() == "Windows"
84
+ else "/bin/bash"
85
+ )
86
+
87
+ return {
88
+ "shell": True,
89
+ "os": detected_os,
90
+ "shellPath": shell_path,
91
+ "version": SERVER_VERSION,
92
+ }
93
+
94
+ @router.get("/commands")
95
+ async def get_commands() -> list[dict[str, Any]]:
96
+ return [_map_to_descriptor(p) for p in registry.processors]
97
+
98
+ @router.post("/execute")
99
+ async def execute_command(request: ExecuteRequest) -> JSONResponse:
100
+ cmd = CliProcessCommand(
101
+ command=request.command,
102
+ raw_command=request.raw_command,
103
+ value=request.value,
104
+ args=request.args,
105
+ chain_commands=request.chain_commands,
106
+ data=request.data,
107
+ )
108
+ result = await executor.execute_async(cmd)
109
+ return JSONResponse(result.model_dump(by_alias=True, exclude_none=True))
110
+
111
+ return router
@@ -0,0 +1,91 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from fastapi import APIRouter
6
+ from fastapi.responses import JSONResponse
7
+ from pydantic import BaseModel, Field
8
+
9
+ from ..abstractions import ICliCommandProcessor
10
+ from ..abstractions.cli_process_command import CliProcessCommand
11
+ from ..models import CliServerCommandDescriptor, CliServerCommandParameterDescriptorDto, CliServerResponse
12
+ from ..services.cli_command_executor_service import ICliCommandExecutorService
13
+ from ..services.cli_command_registry import ICliCommandRegistry
14
+
15
+
16
+ class ExecuteRequestV2(BaseModel):
17
+ command: str = ""
18
+ raw_command: str = Field(alias="rawCommand", default="")
19
+ value: str | None = None
20
+ args: dict[str, Any] = Field(default_factory=dict)
21
+ chain_commands: list[str] = Field(alias="chainCommands", default_factory=list)
22
+ data: Any = None
23
+
24
+ model_config = {"populate_by_name": True}
25
+
26
+
27
+ def _map_to_descriptor_v2(processor: ICliCommandProcessor) -> dict[str, Any]:
28
+ params = None
29
+ if processor.parameters:
30
+ params = [
31
+ CliServerCommandParameterDescriptorDto(
32
+ name=p.name,
33
+ description=p.description,
34
+ required=p.required,
35
+ type=p.type,
36
+ aliases=p.aliases,
37
+ defaultValue=p.default_value,
38
+ ).model_dump(by_alias=True, exclude_none=True)
39
+ for p in processor.parameters
40
+ ]
41
+
42
+ subs = None
43
+ if processor.processors:
44
+ subs = [_map_to_descriptor_v2(p) for p in processor.processors]
45
+
46
+ desc = CliServerCommandDescriptor(
47
+ command=processor.command,
48
+ description=processor.description,
49
+ version=processor.version,
50
+ apiVersion=processor.api_version,
51
+ parameters=params if params else None,
52
+ processors=subs if subs else None,
53
+ allowUnlistedCommands=processor.allow_unlisted_commands,
54
+ valueRequired=processor.value_required,
55
+ author={"name": processor.author.name, "email": processor.author.email},
56
+ )
57
+ return desc.model_dump(by_alias=True, exclude_none=True)
58
+
59
+
60
+ def create_cli_router_v2(
61
+ registry: ICliCommandRegistry,
62
+ executor: ICliCommandExecutorService,
63
+ ) -> APIRouter:
64
+ router = APIRouter()
65
+
66
+ @router.get("/version")
67
+ async def get_version_v2() -> dict[str, Any]:
68
+ return {"apiVersion": 2, "serverVersion": "2.0.0"}
69
+
70
+ @router.get("/commands")
71
+ async def get_commands_v2() -> list[dict[str, Any]]:
72
+ return [
73
+ _map_to_descriptor_v2(p)
74
+ for p in registry.processors
75
+ if p.api_version >= 2
76
+ ]
77
+
78
+ @router.post("/execute")
79
+ async def execute_command_v2(request: ExecuteRequestV2) -> JSONResponse:
80
+ cmd = CliProcessCommand(
81
+ command=request.command,
82
+ raw_command=request.raw_command,
83
+ value=request.value,
84
+ args=request.args,
85
+ chain_commands=request.chain_commands,
86
+ data=request.data,
87
+ )
88
+ result = await executor.execute_async(cmd)
89
+ return JSONResponse(result.model_dump(by_alias=True, exclude_none=True))
90
+
91
+ return router
@@ -0,0 +1,45 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import platform
5
+ from typing import Any
6
+
7
+ from fastapi import APIRouter
8
+
9
+ SERVER_VERSION = "1.0.0"
10
+
11
+
12
+ def create_cli_version_router() -> APIRouter:
13
+ router = APIRouter()
14
+
15
+ @router.get("/versions")
16
+ async def get_versions() -> dict[str, Any]:
17
+ return {
18
+ "supportedVersions": [1, 2],
19
+ "preferredVersion": 2,
20
+ "serverVersion": SERVER_VERSION,
21
+ }
22
+
23
+ @router.get("/capabilities")
24
+ async def get_capabilities() -> dict[str, Any]:
25
+ detected_os = (
26
+ "darwin" if platform.system() == "Darwin"
27
+ else "win32" if platform.system() == "Windows"
28
+ else "linux"
29
+ )
30
+
31
+ shell = "powershell" if platform.system() == "Windows" else "bash"
32
+ shell_path = (
33
+ "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
34
+ if platform.system() == "Windows"
35
+ else "/bin/bash"
36
+ )
37
+
38
+ return {
39
+ "shell": True,
40
+ "os": detected_os,
41
+ "shellPath": shell_path,
42
+ "version": SERVER_VERSION,
43
+ }
44
+
45
+ return router