acra-cli 0.1.1__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 (169) hide show
  1. acra/__init__.py +7 -0
  2. acra/__main__.py +4 -0
  3. acra/agents/__init__.py +0 -0
  4. acra/agents/__pycache__/__init__.cpython-312.pyc +0 -0
  5. acra/agents/__pycache__/llm.cpython-312.pyc +0 -0
  6. acra/agents/__pycache__/llm_utils.cpython-312.pyc +0 -0
  7. acra/agents/coder/__init__.py +0 -0
  8. acra/agents/coder/__pycache__/__init__.cpython-312.pyc +0 -0
  9. acra/agents/coder/__pycache__/coder_agent.cpython-312.pyc +0 -0
  10. acra/agents/coder/__pycache__/coder_chain.cpython-312.pyc +0 -0
  11. acra/agents/coder/coder_agent.py +235 -0
  12. acra/agents/coder/coder_chain.py +204 -0
  13. acra/agents/critic/__init__.py +0 -0
  14. acra/agents/critic/__pycache__/__init__.cpython-312.pyc +0 -0
  15. acra/agents/critic/__pycache__/critic_agent.cpython-312.pyc +0 -0
  16. acra/agents/critic/__pycache__/critic_chain.cpython-312.pyc +0 -0
  17. acra/agents/critic/critic_agent.py +199 -0
  18. acra/agents/critic/critic_chain.py +268 -0
  19. acra/agents/executor/__init__.py +0 -0
  20. acra/agents/executor/__pycache__/__init__.cpython-312.pyc +0 -0
  21. acra/agents/executor/__pycache__/docker_runner.cpython-312.pyc +0 -0
  22. acra/agents/executor/__pycache__/executor_agent.cpython-312.pyc +0 -0
  23. acra/agents/executor/__pycache__/sandbox_runner.cpython-312.pyc +0 -0
  24. acra/agents/executor/docker_runner.py +114 -0
  25. acra/agents/executor/executor_agent.py +142 -0
  26. acra/agents/executor/sandbox_runner.py +144 -0
  27. acra/agents/human/__init__.py +0 -0
  28. acra/agents/human/__pycache__/__init__.cpython-312.pyc +0 -0
  29. acra/agents/human/__pycache__/human_node.cpython-312.pyc +0 -0
  30. acra/agents/human/human_node.py +37 -0
  31. acra/agents/llm.py +263 -0
  32. acra/agents/llm_utils.py +161 -0
  33. acra/agents/memory/__init__.py +0 -0
  34. acra/agents/memory/__pycache__/__init__.cpython-312.pyc +0 -0
  35. acra/agents/memory/__pycache__/memory_agent.cpython-312.pyc +0 -0
  36. acra/agents/memory/__pycache__/memory_manager.cpython-312.pyc +0 -0
  37. acra/agents/memory/__pycache__/retrieval.cpython-312.pyc +0 -0
  38. acra/agents/memory/memory_agent.py +239 -0
  39. acra/agents/memory/memory_manager.py +273 -0
  40. acra/agents/memory/retrieval.py +355 -0
  41. acra/agents/planner/__init__.py +0 -0
  42. acra/agents/planner/__pycache__/__init__.cpython-312.pyc +0 -0
  43. acra/agents/planner/__pycache__/planner_agent.cpython-312.pyc +0 -0
  44. acra/agents/planner/__pycache__/planner_chain.cpython-312.pyc +0 -0
  45. acra/agents/planner/planner_agent.py +97 -0
  46. acra/agents/planner/planner_chain.py +160 -0
  47. acra/agents/researcher/__init__.py +1 -0
  48. acra/agents/researcher/__pycache__/__init__.cpython-312.pyc +0 -0
  49. acra/agents/researcher/__pycache__/researcher_agent.cpython-312.pyc +0 -0
  50. acra/agents/researcher/__pycache__/researcher_chain.cpython-312.pyc +0 -0
  51. acra/agents/researcher/researcher_agent.py +231 -0
  52. acra/agents/researcher/researcher_chain.py +193 -0
  53. acra/brain/__init__.py +6 -0
  54. acra/brain/model_registry.py +19 -0
  55. acra/brain/provider_manager.py +21 -0
  56. acra/cli.py +52 -0
  57. acra/commands/__init__.py +29 -0
  58. acra/commands/ask.py +49 -0
  59. acra/commands/brain.py +58 -0
  60. acra/commands/config.py +25 -0
  61. acra/commands/context.py +30 -0
  62. acra/commands/graph.py +18 -0
  63. acra/commands/keys.py +40 -0
  64. acra/commands/logs.py +13 -0
  65. acra/commands/memory.py +27 -0
  66. acra/commands/plugin.py +18 -0
  67. acra/commands/research.py +65 -0
  68. acra/commands/serve.py +13 -0
  69. acra/commands/session.py +20 -0
  70. acra/commands/utils.py +12 -0
  71. acra/config/__init__.py +36 -0
  72. acra/config/__pycache__/__init__.cpython-312.pyc +0 -0
  73. acra/config/__pycache__/defaults.cpython-312.pyc +0 -0
  74. acra/config/__pycache__/profile_manager.cpython-312.pyc +0 -0
  75. acra/config/defaults.py +88 -0
  76. acra/config/profile_manager.py +87 -0
  77. acra/execution/__init__.py +1 -0
  78. acra/execution/logs/__init__.py +1 -0
  79. acra/execution/logs/error_logs/__init__.py +1 -0
  80. acra/execution/logs/execution_logs/__init__.py +1 -0
  81. acra/execution/sandbox/__init__.py +1 -0
  82. acra/execution/sandbox/docker_executor.py +209 -0
  83. acra/execution/sandbox/isolated_runner.py +148 -0
  84. acra/execution/sandbox/sandbox_manager.py +178 -0
  85. acra/graph/__init__.py +0 -0
  86. acra/graph/checkpoint.py +85 -0
  87. acra/graph/conditional_edges.py +103 -0
  88. acra/graph/edges.py +85 -0
  89. acra/graph/graph_visualizer.py +175 -0
  90. acra/graph/nodes.py +68 -0
  91. acra/graph/router.py +69 -0
  92. acra/graph/state.py +93 -0
  93. acra/graph/workflow.py +117 -0
  94. acra/memory/__init__.py +1 -0
  95. acra/memory/checkpoints/__init__.py +1 -0
  96. acra/memory/checkpoints/data/__init__.py +1 -0
  97. acra/memory/checkpoints/postgres_checkpoint.py +247 -0
  98. acra/memory/checkpoints/sqlite_checkpoint.py +309 -0
  99. acra/memory/chroma_db/__init__.py +1 -0
  100. acra/memory/conversation_memory/__init__.py +1 -0
  101. acra/memory/conversation_memory/long_term.py +229 -0
  102. acra/memory/conversation_memory/short_term.py +158 -0
  103. acra/memory/storage/__init__.py +1 -0
  104. acra/memory/vector_store/__init__.py +0 -0
  105. acra/memory/vector_store/chroma_store.py +260 -0
  106. acra/memory/vector_store/embeddings.py +43 -0
  107. acra/observability/__init__.py +1 -0
  108. acra/observability/langsmith_tracing.py +91 -0
  109. acra/observability/metrics.py +189 -0
  110. acra/observability/monitoring.py +162 -0
  111. acra/observability/token_tracking.py +131 -0
  112. acra/prompts/__init__.py +1 -0
  113. acra/schemas/__init__.py +0 -0
  114. acra/schemas/__pycache__/__init__.cpython-312.pyc +0 -0
  115. acra/schemas/__pycache__/coder_schema.cpython-312.pyc +0 -0
  116. acra/schemas/__pycache__/critic_schema.cpython-312.pyc +0 -0
  117. acra/schemas/__pycache__/execution_schema.cpython-312.pyc +0 -0
  118. acra/schemas/__pycache__/planner_schema.cpython-312.pyc +0 -0
  119. acra/schemas/__pycache__/researcher_schema.cpython-312.pyc +0 -0
  120. acra/schemas/__pycache__/shared_schema.cpython-312.pyc +0 -0
  121. acra/schemas/coder_schema.py +257 -0
  122. acra/schemas/critic_schema.py +177 -0
  123. acra/schemas/execution_schema.py +74 -0
  124. acra/schemas/planner_schema.py +129 -0
  125. acra/schemas/researcher_schema.py +220 -0
  126. acra/schemas/shared_schema.py +329 -0
  127. acra/tools/__init__.py +1 -0
  128. acra/tools/code_tools/__init__.py +1 -0
  129. acra/tools/code_tools/file_reader.py +156 -0
  130. acra/tools/code_tools/file_writer.py +108 -0
  131. acra/tools/code_tools/python_repl.py +72 -0
  132. acra/tools/code_tools/terminal_runner.py +98 -0
  133. acra/tools/github_tools/__init__.py +1 -0
  134. acra/tools/github_tools/commit_generator.py +91 -0
  135. acra/tools/github_tools/github_search.py +113 -0
  136. acra/tools/github_tools/repo_analyzer.py +138 -0
  137. acra/tools/integration_test_helper.py +370 -0
  138. acra/tools/validation_tools/__init__.py +1 -0
  139. acra/tools/validation_tools/dependency_checker.py +101 -0
  140. acra/tools/validation_tools/environment_config_validator.py +353 -0
  141. acra/tools/validation_tools/http_validator.py +336 -0
  142. acra/tools/validation_tools/response_validator.py +407 -0
  143. acra/tools/validation_tools/security_checker.py +93 -0
  144. acra/tools/validation_tools/syntax_checker.py +75 -0
  145. acra/tools/validation_tools/web_framework_validator.py +382 -0
  146. acra/tools/web_tools/__init__.py +1 -0
  147. acra/tools/web_tools/arxiv_search.py +110 -0
  148. acra/tools/web_tools/serpapi_search.py +106 -0
  149. acra/tools/web_tools/tavily_search.py +96 -0
  150. acra/ui/__init__.py +8 -0
  151. acra/ui/__pycache__/__init__.cpython-312.pyc +0 -0
  152. acra/ui/__pycache__/banner.cpython-312.pyc +0 -0
  153. acra/ui/__pycache__/components.cpython-312.pyc +0 -0
  154. acra/ui/__pycache__/shell.cpython-312.pyc +0 -0
  155. acra/ui/__pycache__/theme.cpython-312.pyc +0 -0
  156. acra/ui/banner.py +40 -0
  157. acra/ui/components.py +32 -0
  158. acra/ui/shell.py +91 -0
  159. acra/ui/theme.py +28 -0
  160. acra/utils/__init__.py +21 -0
  161. acra/utils/context_manager.py +20 -0
  162. acra/utils/keyring_manager.py +83 -0
  163. acra/utils/output_formatter.py +18 -0
  164. acra/utils/session_manager.py +59 -0
  165. acra_cli-0.1.1.dist-info/METADATA +616 -0
  166. acra_cli-0.1.1.dist-info/RECORD +169 -0
  167. acra_cli-0.1.1.dist-info/WHEEL +5 -0
  168. acra_cli-0.1.1.dist-info/licenses/LICENSE +661 -0
  169. acra_cli-0.1.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,87 @@
1
+ """Profile management for acra."""
2
+
3
+ import json
4
+ import os
5
+ from getpass import getpass
6
+ from pathlib import Path
7
+ from typing import Any, Dict, Optional
8
+
9
+ CONFIG_DIR = Path.home() / ".acra"
10
+ CONFIG_FILE = CONFIG_DIR / "config.json"
11
+ DEFAULT_PROFILE_NAME = "default"
12
+
13
+
14
+ def _ensure_config_dir() -> None:
15
+ CONFIG_DIR.mkdir(parents=True, exist_ok=True)
16
+
17
+
18
+ def _safe_load_config() -> Dict[str, Any]:
19
+ _ensure_config_dir()
20
+ if not CONFIG_FILE.exists():
21
+ return {"profiles": {DEFAULT_PROFILE_NAME: {}}, "active": DEFAULT_PROFILE_NAME}
22
+ try:
23
+ with open(CONFIG_FILE, "r", encoding="utf-8") as f:
24
+ return json.load(f)
25
+ except Exception:
26
+ return {"profiles": {DEFAULT_PROFILE_NAME: {}}, "active": DEFAULT_PROFILE_NAME}
27
+
28
+
29
+ def _save_config(data: Dict[str, Any]) -> None:
30
+ _ensure_config_dir()
31
+ with open(CONFIG_FILE, "w", encoding="utf-8") as f:
32
+ json.dump(data, f, indent=2)
33
+
34
+
35
+ class ProfileManager:
36
+ """Manage named acra configuration profiles."""
37
+
38
+ def __init__(self) -> None:
39
+ self._data = _safe_load_config()
40
+
41
+ def list_profiles(self) -> Dict[str, Any]:
42
+ return self._data.get("profiles", {})
43
+
44
+ def load_profile(self, profile_name: Optional[str] = None) -> Dict[str, Any]:
45
+ if profile_name is None:
46
+ profile_name = self._data.get("active", DEFAULT_PROFILE_NAME)
47
+ profiles = self._data.get("profiles", {})
48
+ return profiles.get(profile_name, profiles.get(DEFAULT_PROFILE_NAME, {}))
49
+
50
+ def save_profile(self, profile_name: str, profile_data: Dict[str, Any]) -> None:
51
+ profiles = self._data.setdefault("profiles", {})
52
+ profiles[profile_name] = profile_data
53
+ self._data["active"] = profile_name
54
+ _save_config(self._data)
55
+
56
+ def set_active(self, profile_name: str) -> None:
57
+ profiles = self._data.setdefault("profiles", {})
58
+ if profile_name in profiles:
59
+ self._data["active"] = profile_name
60
+ _save_config(self._data)
61
+ else:
62
+ raise ValueError(f"Profile not found: {profile_name}")
63
+
64
+ def run_wizard(self, profile_name: Optional[str] = None) -> str:
65
+ profile_name = profile_name or DEFAULT_PROFILE_NAME
66
+ print("Welcome to acra setup wizard")
67
+ provider = input("Choose provider (gemini/openai/groq/ollama/huggingface_cloud/huggingface_local): ").strip() or "gemini"
68
+ model = input("Model name: ").strip() or "gemini-2.5-flash"
69
+ api_key = getpass("Provider API key (hidden): ")
70
+ theme = input("Theme (dark-orange/dark-blue/dark-green): ").strip() or "dark-orange"
71
+ workspace = input("Workspace path (default=current directory): ").strip() or os.getcwd()
72
+ research_keys = {}
73
+ print("Configure research keys. Press enter to skip a source.")
74
+ for source in ["web", "github", "docs", "arxiv"]:
75
+ prompt = f"Research {source} API key (if required): "
76
+ value = getpass(prompt) if source != "arxiv" else input(prompt).strip()
77
+ research_keys[source] = value or None
78
+
79
+ profile = {
80
+ "provider": provider,
81
+ "model": model,
82
+ "theme": theme,
83
+ "workspace": workspace,
84
+ "research_keys": research_keys,
85
+ }
86
+ self.save_profile(profile_name, profile)
87
+ return profile_name
@@ -0,0 +1 @@
1
+ # Package acra/execution
@@ -0,0 +1 @@
1
+ # Package acra/execution/logs
@@ -0,0 +1 @@
1
+ # Package acra/execution/logs/error_logs
@@ -0,0 +1 @@
1
+ # Package acra/execution/logs/execution_logs
@@ -0,0 +1 @@
1
+ # Package acra/execution/sandbox
@@ -0,0 +1,209 @@
1
+ import subprocess
2
+ import shlex
3
+ import os
4
+ from pathlib import Path
5
+ from typing import Dict, List, Optional, Union
6
+
7
+
8
+ # docker executer
9
+
10
+ class DockerExecutor:
11
+ """
12
+ Docker-based isolated code execution.
13
+
14
+ Responsibilities:
15
+ - execute code safely
16
+ - isolate runtime environment
17
+ - prevent host contamination
18
+ - support autonomous execution
19
+ """
20
+
21
+
22
+ # run python file
23
+
24
+ @staticmethod
25
+ def run_python_file(
26
+ file_path: str,
27
+ working_directory: str,
28
+ timeout: int = 60
29
+ ) -> Dict:
30
+ """
31
+ Execute Python file inside Docker.
32
+ """
33
+
34
+ try:
35
+
36
+ command = [
37
+
38
+ "docker",
39
+ "run",
40
+
41
+ "--rm",
42
+ "--network",
43
+ "none",
44
+ "--user",
45
+ f"{os.getuid()}:{os.getgid()}",
46
+ "--memory",
47
+ "256m",
48
+ "--cpus",
49
+ "1",
50
+ "--pids-limit",
51
+ "128",
52
+ "--cap-drop",
53
+ "ALL",
54
+ "--security-opt",
55
+ "no-new-privileges",
56
+
57
+ "-v",
58
+ f"{Path(working_directory).resolve()}:/app:rw",
59
+
60
+ "-w",
61
+ "/app",
62
+
63
+ "python:3.11-slim",
64
+
65
+ "python",
66
+ file_path
67
+ ]
68
+
69
+ result = subprocess.run(
70
+
71
+ command,
72
+
73
+ capture_output=True,
74
+
75
+ text=True,
76
+
77
+ timeout=timeout
78
+ )
79
+
80
+ success = (
81
+ result.returncode == 0
82
+ )
83
+
84
+ return {
85
+
86
+ "success": success,
87
+
88
+ "stdout": result.stdout,
89
+
90
+ "stderr": result.stderr,
91
+
92
+ "return_code": (
93
+ result.returncode
94
+ )
95
+ }
96
+
97
+ except subprocess.TimeoutExpired:
98
+
99
+ return {
100
+
101
+ "success": False,
102
+
103
+ "stdout": "",
104
+
105
+ "stderr": (
106
+ "Execution timed out."
107
+ )
108
+ }
109
+
110
+ except Exception as e:
111
+
112
+ return {
113
+
114
+ "success": False,
115
+
116
+ "stdout": "",
117
+
118
+ "stderr": str(e)
119
+ }
120
+
121
+
122
+ # run shell command
123
+
124
+ @staticmethod
125
+ def run_command(
126
+ command: Union[str, List[str]],
127
+ working_directory: str,
128
+ timeout: int = 60
129
+ ) -> Dict:
130
+ """
131
+ Execute shell command in Docker.
132
+ """
133
+
134
+ try:
135
+ command_args = shlex.split(command) if isinstance(command, str) else command
136
+
137
+ docker_command = [
138
+
139
+ "docker",
140
+ "run",
141
+
142
+ "--rm",
143
+ "--network",
144
+ "none",
145
+ "--user",
146
+ f"{os.getuid()}:{os.getgid()}",
147
+ "--memory",
148
+ "256m",
149
+ "--cpus",
150
+ "1",
151
+ "--pids-limit",
152
+ "128",
153
+ "--cap-drop",
154
+ "ALL",
155
+ "--security-opt",
156
+ "no-new-privileges",
157
+
158
+ "-v",
159
+ f"{Path(working_directory).resolve()}:/app:rw",
160
+
161
+ "-w",
162
+ "/app",
163
+
164
+ "python:3.11-slim",
165
+
166
+ *command_args
167
+ ]
168
+
169
+ result = subprocess.run(
170
+
171
+ docker_command,
172
+
173
+ capture_output=True,
174
+
175
+ text=True,
176
+
177
+ timeout=timeout
178
+ )
179
+
180
+ return {
181
+
182
+ "success": (
183
+ result.returncode == 0
184
+ ),
185
+
186
+ "stdout": result.stdout,
187
+
188
+ "stderr": result.stderr,
189
+
190
+ "return_code": (
191
+ result.returncode
192
+ )
193
+ }
194
+
195
+ except Exception as e:
196
+
197
+ return {
198
+
199
+ "success": False,
200
+
201
+ "stdout": "",
202
+
203
+ "stderr": str(e)
204
+ }
205
+
206
+
207
+ # global executer
208
+
209
+ docker_executor = DockerExecutor()
@@ -0,0 +1,148 @@
1
+ import subprocess
2
+ from typing import Dict, Optional
3
+
4
+
5
+ # isolated runner
6
+
7
+ class IsolatedRunner:
8
+ """
9
+ Lightweight isolated execution runner.
10
+
11
+ Responsibilities:
12
+ - local isolated execution
13
+ - rapid debugging workflows
14
+ - development-time execution
15
+ """
16
+
17
+ def __init__(
18
+ self,
19
+ timeout: int = 30
20
+ ):
21
+
22
+ self.timeout = timeout
23
+
24
+
25
+ # run python script
26
+
27
+ def run_python_script(
28
+ self,
29
+ script_path: str,
30
+ cwd: Optional[str] = None
31
+ ) -> Dict:
32
+ """
33
+ Execute local Python script.
34
+ """
35
+
36
+ try:
37
+
38
+ result = subprocess.run(
39
+
40
+ ["python", script_path],
41
+
42
+ capture_output=True,
43
+
44
+ text=True,
45
+
46
+ cwd=cwd,
47
+
48
+ timeout=self.timeout
49
+ )
50
+
51
+ return {
52
+
53
+ "success": (
54
+ result.returncode == 0
55
+ ),
56
+
57
+ "stdout": result.stdout,
58
+
59
+ "stderr": result.stderr,
60
+
61
+ "return_code": (
62
+ result.returncode
63
+ )
64
+ }
65
+
66
+ except subprocess.TimeoutExpired:
67
+
68
+ return {
69
+
70
+ "success": False,
71
+
72
+ "stdout": "",
73
+
74
+ "stderr": (
75
+ "Execution timed out."
76
+ )
77
+ }
78
+
79
+ except Exception as e:
80
+
81
+ return {
82
+
83
+ "success": False,
84
+
85
+ "stdout": "",
86
+
87
+ "stderr": str(e)
88
+ }
89
+
90
+
91
+ # run terminal command
92
+
93
+ def run_command(
94
+ self,
95
+ command: str,
96
+ cwd: Optional[str] = None
97
+ ) -> Dict:
98
+ """
99
+ Execute shell command locally.
100
+ """
101
+
102
+ try:
103
+
104
+ result = subprocess.run(
105
+
106
+ command,
107
+
108
+ shell=True,
109
+
110
+ capture_output=True,
111
+
112
+ text=True,
113
+
114
+ cwd=cwd,
115
+
116
+ timeout=self.timeout
117
+ )
118
+
119
+ return {
120
+
121
+ "success": (
122
+ result.returncode == 0
123
+ ),
124
+
125
+ "stdout": result.stdout,
126
+
127
+ "stderr": result.stderr,
128
+
129
+ "return_code": (
130
+ result.returncode
131
+ )
132
+ }
133
+
134
+ except Exception as e:
135
+
136
+ return {
137
+
138
+ "success": False,
139
+
140
+ "stdout": "",
141
+
142
+ "stderr": str(e)
143
+ }
144
+
145
+
146
+ # global runner
147
+
148
+ isolated_runner = IsolatedRunner()
@@ -0,0 +1,178 @@
1
+ import os
2
+ import uuid
3
+ from pathlib import Path
4
+ from typing import Dict
5
+
6
+
7
+ # sandbox config
8
+
9
+ SANDBOX_ROOT = "execution/generated_projects"
10
+
11
+ os.makedirs(SANDBOX_ROOT, exist_ok=True)
12
+
13
+
14
+ # sandbox manager
15
+
16
+ class SandboxManager:
17
+ """
18
+ Sandbox environment manager.
19
+
20
+ Responsibilities:
21
+ - create isolated workspaces
22
+ - manage execution directories
23
+ - cleanup temporary projects
24
+ - support autonomous execution
25
+ """
26
+
27
+ def __init__(self):
28
+
29
+ self.sandbox_root = SANDBOX_ROOT
30
+
31
+
32
+ # create sandbox
33
+
34
+ def create_sandbox(
35
+ self,
36
+ prefix: str = "workflow"
37
+ ) -> Dict:
38
+ """
39
+ Create isolated execution workspace.
40
+ """
41
+
42
+ try:
43
+
44
+ sandbox_id = (
45
+ f"{prefix}_{uuid.uuid4().hex[:8]}"
46
+ )
47
+
48
+ sandbox_path = os.path.join(
49
+ self.sandbox_root,
50
+ sandbox_id
51
+ )
52
+
53
+ Path(sandbox_path).mkdir(
54
+ parents=True,
55
+ exist_ok=True
56
+ )
57
+
58
+ return {
59
+
60
+ "success": True,
61
+
62
+ "sandbox_id": sandbox_id,
63
+
64
+ "sandbox_path": sandbox_path
65
+ }
66
+
67
+ except Exception as e:
68
+
69
+ return {
70
+
71
+ "success": False,
72
+
73
+ "error": str(e)
74
+ }
75
+
76
+
77
+ # delete sandbox
78
+
79
+ def delete_sandbox(
80
+ self,
81
+ sandbox_path: str
82
+ ) -> Dict:
83
+ """
84
+ Remove sandbox workspace.
85
+ """
86
+
87
+ try:
88
+
89
+ if os.path.exists(
90
+ sandbox_path
91
+ ):
92
+
93
+ for root, dirs, files in os.walk(
94
+ sandbox_path,
95
+ topdown=False
96
+ ):
97
+
98
+ for file in files:
99
+
100
+ os.remove(
101
+ os.path.join(
102
+ root,
103
+ file
104
+ )
105
+ )
106
+
107
+ for directory in dirs:
108
+
109
+ os.rmdir(
110
+ os.path.join(
111
+ root,
112
+ directory
113
+ )
114
+ )
115
+
116
+ os.rmdir(sandbox_path)
117
+
118
+ return {
119
+
120
+ "success": True,
121
+
122
+ "sandbox_path": sandbox_path
123
+ }
124
+
125
+ except Exception as e:
126
+
127
+ return {
128
+
129
+ "success": False,
130
+
131
+ "error": str(e)
132
+ }
133
+
134
+
135
+ # list sandboxes
136
+
137
+ def list_sandboxes(self) -> Dict:
138
+ """
139
+ Retrieve active sandboxes.
140
+ """
141
+
142
+ try:
143
+
144
+ sandboxes = []
145
+
146
+ for item in os.listdir(
147
+ self.sandbox_root
148
+ ):
149
+
150
+ full_path = os.path.join(
151
+ self.sandbox_root,
152
+ item
153
+ )
154
+
155
+ if os.path.isdir(full_path):
156
+
157
+ sandboxes.append(full_path)
158
+
159
+ return {
160
+
161
+ "success": True,
162
+
163
+ "sandboxes": sandboxes
164
+ }
165
+
166
+ except Exception as e:
167
+
168
+ return {
169
+
170
+ "success": False,
171
+
172
+ "error": str(e)
173
+ }
174
+
175
+
176
+ # global sandbox manager
177
+
178
+ sandbox_manager = SandboxManager()
acra/graph/__init__.py ADDED
File without changes