dais-shell 0.2.0__tar.gz → 0.3.0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dais-shell
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: The shell tool for Dais.
5
5
  Author: BHznJNs
6
6
  Author-email: BHznJNs <441768875@qq.com>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "dais-shell"
3
- version = "0.2.0"
3
+ version = "0.3.0"
4
4
  description = "The shell tool for Dais."
5
5
  readme = "README.md"
6
6
  authors = [{ name = "BHznJNs", email = "441768875@qq.com" }]
@@ -5,7 +5,9 @@ from typing import TypeAlias
5
5
  from .env_builder import EnvBuilder
6
6
  from .iostream_reader import IOStreamReaderResult, IOStreamReaderStatus
7
7
  from .runtimes import BaseShellRuntime, BashRuntime, PowerShellRuntime
8
- from .types import CommandStep, ShellError, ShellRuntimeNotFoundError, ForbiddenShellTargetError
8
+ from .types.command_step import CommandStep
9
+ from .types.shell_script import ShellScript
10
+ from .types.exceptions import ShellError, ShellRuntimeNotFoundError, ForbiddenShellTargetError
9
11
  from .constants import DEFAULT_COMMAND_BLACKLIST
10
12
 
11
13
  ShellResult: TypeAlias = IOStreamReaderResult
@@ -30,19 +32,20 @@ class AgentShell:
30
32
  return BashRuntime(max_lines)
31
33
 
32
34
  def run_sync(self,
33
- step: CommandStep,
35
+ step: CommandStep | ShellScript,
34
36
  on_stdout=None,
35
37
  on_stderr=None
36
38
  ) -> ShellResult:
37
39
  return asyncio.run(self.run(step, on_stdout, on_stderr))
38
40
 
39
41
  async def run(self,
40
- step: CommandStep,
42
+ step: CommandStep | ShellScript,
41
43
  on_stdout=None,
42
44
  on_stderr=None
43
45
  ) -> ShellResult:
44
46
  step = replace(step)
45
- step.validate_forbidden(self._command_blacklist)
47
+ if isinstance(step, CommandStep):
48
+ step.validate_forbidden(self._command_blacklist)
46
49
  step.env = (self._env_builder
47
50
  .with_extra(step.env or {})
48
51
  .build())
@@ -51,6 +54,7 @@ class AgentShell:
51
54
  __all__ = [
52
55
  "AgentShell",
53
56
  "CommandStep",
57
+ "ShellScript",
54
58
  "ShellResult",
55
59
  "ShellResultStatus",
56
60
 
@@ -1,19 +1,20 @@
1
1
  from abc import ABC, abstractmethod
2
- from ..types import CommandStep
2
+ from ..types.command_step import CommandStep
3
+ from ..types.shell_script import ShellScript
3
4
  from ..iostream_reader import IOStreamReaderResult
4
5
 
5
6
 
6
7
  class BaseShellRuntime(ABC):
7
8
  @abstractmethod
8
9
  def run_sync(self,
9
- step: CommandStep,
10
+ step: CommandStep | ShellScript,
10
11
  on_stdout=None,
11
12
  on_stderr=None,
12
13
  ) -> IOStreamReaderResult: ...
13
14
 
14
15
  @abstractmethod
15
16
  async def run(self,
16
- step: CommandStep,
17
+ step: CommandStep | ShellScript,
17
18
  on_stdout=None,
18
19
  on_stderr=None
19
20
  ) -> IOStreamReaderResult: ...
@@ -5,7 +5,9 @@ from dataclasses import asdict, dataclass
5
5
 
6
6
  from dais_shell.utils.env_expander import EnvExpander
7
7
  from .BaseShellRuntime import BaseShellRuntime
8
- from ..types import CommandStep, ShellRuntimeNotFoundError
8
+ from ..types.command_step import CommandStep
9
+ from ..types.shell_script import ShellScript
10
+ from ..types.exceptions import ShellRuntimeNotFoundError
9
11
  from ..iostream_reader import IOStreamReader, IOStreamReaderResult
10
12
 
11
13
 
@@ -39,21 +41,24 @@ class BashRuntime(BaseShellRuntime):
39
41
  step.to_wrapper_script(),
40
42
  ]
41
43
 
42
- def _prepare_cmd(self, step: CommandStep) -> list[str]:
44
+ def _prepare_cmd(self, step: CommandStep | ShellScript) -> list[str]:
45
+ if isinstance(step, ShellScript):
46
+ return [self._shell, "-c", step.script]
47
+
43
48
  env_expander = EnvExpander(step.env or {})
44
49
  step.args = env_expander.expand(step.args)
45
50
  step = BashCommandStep.from_command_step(step)
46
51
  return self._make_bash_commands(step)
47
52
 
48
53
  def run_sync(self,
49
- step: CommandStep,
54
+ step: CommandStep | ShellScript,
50
55
  on_stdout=None,
51
56
  on_stderr=None,
52
57
  ) -> IOStreamReaderResult:
53
58
  return asyncio.run(self.run(step, on_stdout, on_stderr))
54
59
 
55
60
  async def run(self,
56
- step: CommandStep,
61
+ step: CommandStep | ShellScript,
57
62
  on_stdout=None,
58
63
  on_stderr=None
59
64
  ) -> IOStreamReaderResult:
@@ -5,12 +5,49 @@ import shutil
5
5
  import re
6
6
  import xml.etree.ElementTree as ET
7
7
  import subprocess
8
- from dataclasses import asdict, dataclass
8
+ from dataclasses import asdict, dataclass, fields
9
9
 
10
10
  from dais_shell.utils.env_expander import EnvExpander
11
11
  from .BaseShellRuntime import BaseShellRuntime
12
12
  from ..iostream_reader import IOStreamReader, IOStreamReaderResult
13
- from ..types import CommandStep, ShellRuntimeNotFoundError
13
+ from ..types.command_step import CommandStep
14
+ from ..types.shell_script import ShellScript
15
+ from ..types.exceptions import ShellRuntimeNotFoundError
16
+
17
+
18
+ @dataclass
19
+ class PowerShellScript(ShellScript):
20
+ @classmethod
21
+ def from_shell_script(cls, script: ShellScript):
22
+ data = asdict(script)
23
+ return cls(**{
24
+ field.name: data[field.name]
25
+ for field in fields(ShellScript)
26
+ })
27
+
28
+ def to_wrapper_script(self):
29
+ return f"""
30
+ $ErrorActionPreference = "Stop"
31
+ $PSNativeCommandArgumentPassing = "Standard"
32
+
33
+ chcp 65001 | Out-Null
34
+ $OutputEncoding = [System.Text.Encoding]::UTF8
35
+ [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
36
+ [Console]::InputEncoding = [System.Text.Encoding]::UTF8
37
+
38
+ $LASTEXITCODE = $null
39
+
40
+ & {{
41
+ {self.script}
42
+
43
+ $daisSuccess = $?
44
+ $daisExitCode = $LASTEXITCODE
45
+
46
+ if ($daisSuccess) {{ exit 0 }}
47
+ if ($daisExitCode -ne $null) {{ exit $daisExitCode }}
48
+ exit 1
49
+ }}
50
+ """.strip()
14
51
 
15
52
 
16
53
  @dataclass
@@ -102,7 +139,13 @@ class PowerShellRuntime(BaseShellRuntime):
102
139
  "-EncodedCommand", encoded
103
140
  ]
104
141
 
105
- def _prepare_cmd(self, step: CommandStep) -> list[str]:
142
+ def _prepare_cmd(self, step: CommandStep | ShellScript) -> list[str]:
143
+ if isinstance(step, ShellScript):
144
+ script = PowerShellScript.from_shell_script(step)
145
+ return self._make_powershell_commands(
146
+ self._encode(script.to_wrapper_script())
147
+ )
148
+
106
149
  env_expander = EnvExpander(step.env or {})
107
150
  step.args = env_expander.expand(step.args)
108
151
  step = PowerShellCommandStep.from_command_step(step)
@@ -112,7 +155,7 @@ class PowerShellRuntime(BaseShellRuntime):
112
155
 
113
156
  def run_sync(
114
157
  self,
115
- step: CommandStep,
158
+ step: CommandStep | ShellScript,
116
159
  on_stdout=None,
117
160
  on_stderr=None,
118
161
  ) -> IOStreamReaderResult:
@@ -120,7 +163,7 @@ class PowerShellRuntime(BaseShellRuntime):
120
163
 
121
164
  async def run(
122
165
  self,
123
- step: CommandStep,
166
+ step: CommandStep | ShellScript,
124
167
  on_stdout=None,
125
168
  on_stderr=None
126
169
  ) -> IOStreamReaderResult:
@@ -1,2 +1,3 @@
1
1
  from .command_step import *
2
+ from .shell_script import *
2
3
  from .exceptions import *
@@ -22,6 +22,7 @@ class CommandStep:
22
22
  if name in filter:
23
23
  raise ForbiddenShellTargetError(name)
24
24
 
25
+
25
26
  __all__ = [
26
27
  "CommandStep",
27
28
  ]
@@ -0,0 +1,17 @@
1
+ from dataclasses import dataclass
2
+ from pathlib import Path
3
+
4
+
5
+ @dataclass
6
+ class ShellScript:
7
+ """Trusted shell source executed directly without command blacklist validation."""
8
+
9
+ script: str
10
+ cwd: str | Path
11
+ env: dict[str, str] | None = None
12
+ timeout: int | None = None
13
+
14
+
15
+ __all__ = [
16
+ "ShellScript",
17
+ ]
File without changes