dais-shell 0.2.0__tar.gz → 0.3.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dais-shell
3
- Version: 0.2.0
3
+ Version: 0.3.1
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.1"
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:
@@ -1,16 +1,62 @@
1
1
  import asyncio
2
2
  import base64
3
- import json
4
3
  import shutil
5
4
  import re
6
5
  import xml.etree.ElementTree as ET
7
6
  import subprocess
8
- from dataclasses import asdict, dataclass
7
+ from dataclasses import asdict, dataclass, fields
9
8
 
10
9
  from dais_shell.utils.env_expander import EnvExpander
11
10
  from .BaseShellRuntime import BaseShellRuntime
12
11
  from ..iostream_reader import IOStreamReader, IOStreamReaderResult
13
- from ..types import CommandStep, ShellRuntimeNotFoundError
12
+ from ..types.command_step import CommandStep
13
+ from ..types.shell_script import ShellScript
14
+ from ..types.exceptions import ShellRuntimeNotFoundError
15
+
16
+
17
+ POWERSHELL_PREFERENCES = """
18
+ $ErrorActionPreference = "Stop"
19
+ $WarningPreference = "SilentlyContinue"
20
+ $VerbosePreference = "SilentlyContinue"
21
+ $DebugPreference = "SilentlyContinue"
22
+ $InformationPreference = "SilentlyContinue"
23
+ $ProgressPreference = "SilentlyContinue"
24
+
25
+ $PSNativeCommandArgumentPassing = "Standard"
26
+ """.strip()
27
+
28
+ @dataclass
29
+ class PowerShellScript(ShellScript):
30
+ @classmethod
31
+ def from_shell_script(cls, script: ShellScript):
32
+ data = asdict(script)
33
+ return cls(**{
34
+ field.name: data[field.name]
35
+ for field in fields(ShellScript)
36
+ })
37
+
38
+ def to_wrapper_script(self):
39
+ return f"""
40
+ {POWERSHELL_PREFERENCES}
41
+
42
+ chcp 65001 | Out-Null
43
+ $OutputEncoding = [System.Text.Encoding]::UTF8
44
+ [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
45
+ [Console]::InputEncoding = [System.Text.Encoding]::UTF8
46
+
47
+ $LASTEXITCODE = $null
48
+
49
+ & {{
50
+ {self.script}
51
+
52
+ $daisSuccess = $?
53
+ $daisExitCode = $LASTEXITCODE
54
+
55
+ if ($daisSuccess) {{ exit 0 }}
56
+ if ($daisExitCode -ne $null) {{ exit $daisExitCode }}
57
+ exit 1
58
+ }}
59
+ """.strip()
14
60
 
15
61
 
16
62
  @dataclass
@@ -24,8 +70,7 @@ class PowerShellCommandStep(CommandStep):
24
70
  return "'" + s.replace("'", "''") + "'"
25
71
 
26
72
  script = f"""
27
- $ErrorActionPreference = "Stop"
28
- $PSNativeCommandArgumentPassing = "Standard"
73
+ {POWERSHELL_PREFERENCES}
29
74
 
30
75
  chcp 65001 | Out-Null
31
76
  $OutputEncoding = [System.Text.Encoding]::UTF8
@@ -102,7 +147,13 @@ class PowerShellRuntime(BaseShellRuntime):
102
147
  "-EncodedCommand", encoded
103
148
  ]
104
149
 
105
- def _prepare_cmd(self, step: CommandStep) -> list[str]:
150
+ def _prepare_cmd(self, step: CommandStep | ShellScript) -> list[str]:
151
+ if isinstance(step, ShellScript):
152
+ script = PowerShellScript.from_shell_script(step)
153
+ return self._make_powershell_commands(
154
+ self._encode(script.to_wrapper_script())
155
+ )
156
+
106
157
  env_expander = EnvExpander(step.env or {})
107
158
  step.args = env_expander.expand(step.args)
108
159
  step = PowerShellCommandStep.from_command_step(step)
@@ -112,7 +163,7 @@ class PowerShellRuntime(BaseShellRuntime):
112
163
 
113
164
  def run_sync(
114
165
  self,
115
- step: CommandStep,
166
+ step: CommandStep | ShellScript,
116
167
  on_stdout=None,
117
168
  on_stderr=None,
118
169
  ) -> IOStreamReaderResult:
@@ -120,7 +171,7 @@ class PowerShellRuntime(BaseShellRuntime):
120
171
 
121
172
  async def run(
122
173
  self,
123
- step: CommandStep,
174
+ step: CommandStep | ShellScript,
124
175
  on_stdout=None,
125
176
  on_stderr=None
126
177
  ) -> 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