strix-agent 0.1.9__tar.gz → 0.1.11__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.
Files changed (106) hide show
  1. {strix_agent-0.1.9 → strix_agent-0.1.11}/PKG-INFO +4 -15
  2. {strix_agent-0.1.9 → strix_agent-0.1.11}/README.md +0 -13
  3. {strix_agent-0.1.9 → strix_agent-0.1.11}/pyproject.toml +5 -2
  4. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/agents/StrixAgent/strix_agent.py +18 -6
  5. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/agents/StrixAgent/system_prompt.jinja +26 -7
  6. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/agents/base_agent.py +3 -0
  7. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/cli/app.py +3 -1
  8. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/cli/main.py +85 -1
  9. strix_agent-0.1.11/strix/cli/tool_components/terminal_renderer.py +131 -0
  10. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/llm/llm.py +3 -3
  11. strix_agent-0.1.11/strix/runtime/docker_runtime.py +315 -0
  12. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/runtime/runtime.py +3 -2
  13. strix_agent-0.1.11/strix/runtime/tool_server.py +205 -0
  14. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/agents_graph/agents_graph_actions.py +4 -4
  15. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/agents_graph/agents_graph_actions_schema.xml +17 -1
  16. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/argument_parser.py +2 -1
  17. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/executor.py +3 -0
  18. strix_agent-0.1.11/strix/tools/terminal/__init__.py +4 -0
  19. strix_agent-0.1.11/strix/tools/terminal/terminal_actions.py +35 -0
  20. strix_agent-0.1.11/strix/tools/terminal/terminal_actions_schema.xml +143 -0
  21. strix_agent-0.1.11/strix/tools/terminal/terminal_manager.py +151 -0
  22. strix_agent-0.1.11/strix/tools/terminal/terminal_session.py +447 -0
  23. strix_agent-0.1.9/strix/cli/tool_components/terminal_renderer.py +0 -99
  24. strix_agent-0.1.9/strix/runtime/docker_runtime.py +0 -271
  25. strix_agent-0.1.9/strix/runtime/tool_server.py +0 -97
  26. strix_agent-0.1.9/strix/tools/terminal/__init__.py +0 -4
  27. strix_agent-0.1.9/strix/tools/terminal/terminal_actions.py +0 -53
  28. strix_agent-0.1.9/strix/tools/terminal/terminal_actions_schema.xml +0 -118
  29. strix_agent-0.1.9/strix/tools/terminal/terminal_instance.py +0 -231
  30. strix_agent-0.1.9/strix/tools/terminal/terminal_manager.py +0 -191
  31. {strix_agent-0.1.9 → strix_agent-0.1.11}/LICENSE +0 -0
  32. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/__init__.py +0 -0
  33. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/agents/StrixAgent/__init__.py +0 -0
  34. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/agents/__init__.py +0 -0
  35. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/agents/state.py +0 -0
  36. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/cli/__init__.py +0 -0
  37. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/cli/assets/cli.tcss +0 -0
  38. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/cli/tool_components/__init__.py +0 -0
  39. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/cli/tool_components/agents_graph_renderer.py +0 -0
  40. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/cli/tool_components/base_renderer.py +0 -0
  41. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/cli/tool_components/browser_renderer.py +0 -0
  42. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/cli/tool_components/file_edit_renderer.py +0 -0
  43. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/cli/tool_components/finish_renderer.py +0 -0
  44. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/cli/tool_components/notes_renderer.py +0 -0
  45. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/cli/tool_components/proxy_renderer.py +0 -0
  46. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/cli/tool_components/python_renderer.py +0 -0
  47. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/cli/tool_components/registry.py +0 -0
  48. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/cli/tool_components/reporting_renderer.py +0 -0
  49. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/cli/tool_components/scan_info_renderer.py +0 -0
  50. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/cli/tool_components/thinking_renderer.py +0 -0
  51. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/cli/tool_components/user_message_renderer.py +0 -0
  52. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/cli/tool_components/web_search_renderer.py +0 -0
  53. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/cli/tracer.py +0 -0
  54. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/llm/__init__.py +0 -0
  55. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/llm/config.py +0 -0
  56. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/llm/memory_compressor.py +0 -0
  57. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/llm/request_queue.py +0 -0
  58. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/llm/utils.py +0 -0
  59. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/prompts/__init__.py +0 -0
  60. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/prompts/coordination/root_agent.jinja +0 -0
  61. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/prompts/vulnerabilities/authentication_jwt.jinja +0 -0
  62. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/prompts/vulnerabilities/business_logic.jinja +0 -0
  63. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/prompts/vulnerabilities/csrf.jinja +0 -0
  64. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/prompts/vulnerabilities/idor.jinja +0 -0
  65. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/prompts/vulnerabilities/race_conditions.jinja +0 -0
  66. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/prompts/vulnerabilities/rce.jinja +0 -0
  67. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/prompts/vulnerabilities/sql_injection.jinja +0 -0
  68. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/prompts/vulnerabilities/ssrf.jinja +0 -0
  69. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/prompts/vulnerabilities/xss.jinja +0 -0
  70. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/prompts/vulnerabilities/xxe.jinja +0 -0
  71. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/runtime/__init__.py +0 -0
  72. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/__init__.py +0 -0
  73. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/agents_graph/__init__.py +0 -0
  74. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/browser/__init__.py +0 -0
  75. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/browser/browser_actions.py +0 -0
  76. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/browser/browser_actions_schema.xml +0 -0
  77. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/browser/browser_instance.py +0 -0
  78. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/browser/tab_manager.py +0 -0
  79. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/file_edit/__init__.py +0 -0
  80. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/file_edit/file_edit_actions.py +0 -0
  81. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/file_edit/file_edit_actions_schema.xml +0 -0
  82. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/finish/__init__.py +0 -0
  83. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/finish/finish_actions.py +0 -0
  84. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/finish/finish_actions_schema.xml +0 -0
  85. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/notes/__init__.py +0 -0
  86. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/notes/notes_actions.py +0 -0
  87. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/notes/notes_actions_schema.xml +0 -0
  88. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/proxy/__init__.py +0 -0
  89. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/proxy/proxy_actions.py +0 -0
  90. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/proxy/proxy_actions_schema.xml +0 -0
  91. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/proxy/proxy_manager.py +0 -0
  92. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/python/__init__.py +0 -0
  93. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/python/python_actions.py +0 -0
  94. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/python/python_actions_schema.xml +0 -0
  95. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/python/python_instance.py +0 -0
  96. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/python/python_manager.py +0 -0
  97. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/registry.py +0 -0
  98. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/reporting/__init__.py +0 -0
  99. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/reporting/reporting_actions.py +0 -0
  100. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/reporting/reporting_actions_schema.xml +0 -0
  101. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/thinking/__init__.py +0 -0
  102. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/thinking/thinking_actions.py +0 -0
  103. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/thinking/thinking_actions_schema.xml +0 -0
  104. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/web_search/__init__.py +0 -0
  105. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/web_search/web_search_actions.py +0 -0
  106. {strix_agent-0.1.9 → strix_agent-0.1.11}/strix/tools/web_search/web_search_actions_schema.xml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: strix-agent
3
- Version: 0.1.9
3
+ Version: 0.1.11
4
4
  Summary: Open-source AI Hackers for your apps
5
5
  License: Apache-2.0
6
6
  Keywords: cybersecurity,security,vulnerability,scanner,pentest,agent,ai,cli
@@ -22,8 +22,10 @@ Requires-Dist: docker (>=7.1.0,<8.0.0)
22
22
  Requires-Dist: fastapi
23
23
  Requires-Dist: gql[requests] (>=3.5.3,<4.0.0)
24
24
  Requires-Dist: ipython (>=9.3.0,<10.0.0)
25
- Requires-Dist: litellm[proxy] (>=1.75.7,<2.0.0)
25
+ Requires-Dist: libtmux (>=0.46.2,<0.47.0)
26
+ Requires-Dist: litellm[proxy] (>=1.75.8,<1.76.0)
26
27
  Requires-Dist: numpydoc (>=1.8.0,<2.0.0)
28
+ Requires-Dist: openai (>=1.99.5,<1.100.0)
27
29
  Requires-Dist: openhands-aci (>=0.3.0,<0.4.0)
28
30
  Requires-Dist: playwright (>=1.48.0,<2.0.0)
29
31
  Requires-Dist: pydantic[email] (>=2.11.3,<3.0.0)
@@ -45,9 +47,6 @@ Description-Content-Type: text/markdown
45
47
  [![Apache 2.0](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
46
48
  [![Vercel AI Accelerator 2025](https://img.shields.io/badge/Vercel%20AI-Accelerator%202025-000000?style=flat&logo=vercel)](https://vercel.com/ai-accelerator)
47
49
  [![Status: Alpha](https://img.shields.io/badge/status-alpha-orange.svg)](https://github.com/usestrix/strix)
48
- [![Discord](https://dcbadge.limes.pink/api/server/yduEyduBsp?style=flat)](https://discord.gg/yduEyduBsp)
49
-
50
- **⚡ Use it to hack your apps before the bad guys do ⚡**
51
50
 
52
51
  </div>
53
52
 
@@ -172,15 +171,5 @@ Our managed platform provides:
172
171
 
173
172
  Have questions? Found a bug? Want to contribute? **[Join our Discord!](https://discord.gg/yduEyduBsp)**
174
173
 
175
- ---
176
-
177
- <div align="center">
178
-
179
- ### About • Links
180
-
181
- **[OmniSecure Inc.](https://omnisecure.ai)** • Applied AI Research Lab
182
-
183
- [Discord Community](https://discord.gg/yduEyduBsp) • [Enterprise Solutions](https://form.typeform.com/to/ljtvl6X0) • [Report Issues](https://github.com/usestrix/strix/issues)
184
-
185
174
  </div>
186
175
 
@@ -7,9 +7,6 @@
7
7
  [![Apache 2.0](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
8
8
  [![Vercel AI Accelerator 2025](https://img.shields.io/badge/Vercel%20AI-Accelerator%202025-000000?style=flat&logo=vercel)](https://vercel.com/ai-accelerator)
9
9
  [![Status: Alpha](https://img.shields.io/badge/status-alpha-orange.svg)](https://github.com/usestrix/strix)
10
- [![Discord](https://dcbadge.limes.pink/api/server/yduEyduBsp?style=flat)](https://discord.gg/yduEyduBsp)
11
-
12
- **⚡ Use it to hack your apps before the bad guys do ⚡**
13
10
 
14
11
  </div>
15
12
 
@@ -134,14 +131,4 @@ Our managed platform provides:
134
131
 
135
132
  Have questions? Found a bug? Want to contribute? **[Join our Discord!](https://discord.gg/yduEyduBsp)**
136
133
 
137
- ---
138
-
139
- <div align="center">
140
-
141
- ### About • Links
142
-
143
- **[OmniSecure Inc.](https://omnisecure.ai)** • Applied AI Research Lab
144
-
145
- [Discord Community](https://discord.gg/yduEyduBsp) • [Enterprise Solutions](https://form.typeform.com/to/ljtvl6X0) • [Report Issues](https://github.com/usestrix/strix/issues)
146
-
147
134
  </div>
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "strix-agent"
3
- version = "0.1.9"
3
+ version = "0.1.11"
4
4
  description = "Open-source AI Hackers for your apps"
5
5
  authors = ["Strix <hi@usestrix.com>"]
6
6
  readme = "README.md"
@@ -45,7 +45,8 @@ strix = "strix.cli.main:main"
45
45
  python = "^3.12"
46
46
  fastapi = "*"
47
47
  uvicorn = "*"
48
- litellm = {version = "^1.75.7", extras = ["proxy"]}
48
+ litellm = { version = "~1.75.8", extras = ["proxy"] }
49
+ openai = ">=1.99.5,<1.100.0"
49
50
  tenacity = "^9.0.0"
50
51
  numpydoc = "^1.8.0"
51
52
  pydantic = {extras = ["email"], version = "^2.11.3"}
@@ -59,6 +60,7 @@ textual = "^4.0.0"
59
60
  xmltodict = "^0.13.0"
60
61
  pyte = "^0.8.1"
61
62
  requests = "^2.32.0"
63
+ libtmux = "^0.46.2"
62
64
 
63
65
  [tool.poetry.group.dev.dependencies]
64
66
  # Type checking and static analysis
@@ -126,6 +128,7 @@ module = [
126
128
  "gql.*",
127
129
  "textual.*",
128
130
  "pyte.*",
131
+ "libtmux.*",
129
132
  ]
130
133
  ignore_missing_imports = true
131
134
 
@@ -26,9 +26,21 @@ class StrixAgent(BaseAgent):
26
26
  task_parts = []
27
27
 
28
28
  if scan_type == "repository":
29
- task_parts.append(
30
- f"Perform a security assessment of the Git repository: {target['target_repo']}"
31
- )
29
+ repo_url = target["target_repo"]
30
+ cloned_path = target.get("cloned_repo_path")
31
+
32
+ if cloned_path:
33
+ workspace_path = "/workspace"
34
+ task_parts.append(
35
+ f"Perform a security assessment of the Git repository: {repo_url}. "
36
+ f"The repository has been cloned from '{repo_url}' to '{cloned_path}' "
37
+ f"(host path) and then copied to '{workspace_path}' in your environment."
38
+ f"Analyze the codebase at: {workspace_path}"
39
+ )
40
+ else:
41
+ task_parts.append(
42
+ f"Perform a security assessment of the Git repository: {repo_url}"
43
+ )
32
44
 
33
45
  elif scan_type == "web_application":
34
46
  task_parts.append(
@@ -37,12 +49,12 @@ class StrixAgent(BaseAgent):
37
49
 
38
50
  elif scan_type == "local_code":
39
51
  original_path = target.get("target_path", "unknown")
40
- shared_workspace_path = "/shared_workspace"
52
+ workspace_path = "/workspace"
41
53
  task_parts.append(
42
54
  f"Perform a security assessment of the local codebase. "
43
55
  f"The code from '{original_path}' (user host path) has been copied to "
44
- f"'{shared_workspace_path}' in your environment. "
45
- f"Analyze the codebase at: {shared_workspace_path}"
56
+ f"'{workspace_path}' in your environment. "
57
+ f"Analyze the codebase at: {workspace_path}"
46
58
  )
47
59
 
48
60
  else:
@@ -145,11 +145,10 @@ Remember: A single high-impact vulnerability is worth more than dozens of low-se
145
145
 
146
146
  <multi_agent_system>
147
147
  AGENT ISOLATION & SANDBOXING:
148
- - Each subagent runs in a completely isolated sandbox environment
149
- - Each agent has its own: browser sessions, terminal sessions, proxy (history and scope rules), /workspace directory, environment variables, running processes
150
- - Agents cannot share network ports or interfere with each other's processes
151
- - Only shared resource is /shared_workspace for collaboration and file exchange
152
- - Use /shared_workspace to pass files, reports, and coordination data between agents
148
+ - All agents run in the same shared Docker container for efficiency
149
+ - Each agent has its own: browser sessions, terminal sessions
150
+ - All agents share the same /workspace directory and proxy history
151
+ - Agents can see each other's files and proxy traffic for better collaboration
153
152
 
154
153
  SIMPLE WORKFLOW RULES:
155
154
 
@@ -206,6 +205,27 @@ CRITICAL RULES:
206
205
  - **ONE AGENT = ONE TASK** - Don't let agents do multiple unrelated jobs
207
206
  - **SPAWN REACTIVELY** - Create new agents based on what you discover
208
207
  - **ONLY REPORTING AGENTS** can use create_vulnerability_report tool
208
+ - **AGENT SPECIALIZATION MANDATORY** - Each agent must be highly specialized with maximum 3 prompt modules
209
+ - **NO GENERIC AGENTS** - Avoid creating broad, multi-purpose agents that dilute focus
210
+
211
+ AGENT SPECIALIZATION EXAMPLES:
212
+
213
+ GOOD SPECIALIZATION:
214
+ - "SQLi Validation Agent" with prompt_modules: sql_injection
215
+ - "XSS Discovery Agent" with prompt_modules: xss
216
+ - "Auth Testing Agent" with prompt_modules: authentication_jwt, business_logic
217
+ - "SSRF + XXE Agent" with prompt_modules: ssrf, xxe, rce (related attack vectors)
218
+
219
+ BAD SPECIALIZATION:
220
+ - "General Web Testing Agent" with prompt_modules: sql_injection, xss, csrf, ssrf, authentication_jwt (too broad)
221
+ - "Everything Agent" with prompt_modules: all available modules (completely unfocused)
222
+ - Any agent with more than 3 prompt modules (violates constraints)
223
+
224
+ FOCUS PRINCIPLES:
225
+ - Each agent should have deep expertise in 1-3 related vulnerability types
226
+ - Agents with single modules have the deepest specialization
227
+ - Related vulnerabilities (like SSRF+XXE or Auth+Business Logic) can be combined
228
+ - Never create "kitchen sink" agents that try to do everything
209
229
 
210
230
  REALISTIC TESTING OUTCOMES:
211
231
  - **No Findings**: Agent completes testing but finds no vulnerabilities
@@ -291,8 +311,7 @@ PROGRAMMING:
291
311
  - You can install any additional tools/packages needed based on the task/context using package managers (apt, pip, npm, go install, etc.)
292
312
 
293
313
  Directories:
294
- - /workspace - Your private agent directory
295
- - /shared_workspace - Shared between agents
314
+ - /workspace - where you should work.
296
315
  - /home/pentester/tools - Additional tool scripts
297
316
  - /home/pentester/tools/wordlists - Currently empty, but you should download wordlists here when you need.
298
317
 
@@ -239,6 +239,9 @@ class BaseAgent(metaclass=AgentMeta):
239
239
  self.state.sandbox_token = sandbox_info["auth_token"]
240
240
  self.state.sandbox_info = sandbox_info
241
241
 
242
+ if "agent_id" in sandbox_info:
243
+ self.state.sandbox_info["agent_id"] = sandbox_info["agent_id"]
244
+
242
245
  if not self.state.task:
243
246
  self.state.task = task
244
247
 
@@ -248,6 +248,8 @@ class StrixCLIApp(App): # type: ignore[misc]
248
248
 
249
249
  if args.target_type == "local_code" and "target_path" in args.target_dict:
250
250
  config["local_source_path"] = args.target_dict["target_path"]
251
+ elif args.target_type == "repository" and "cloned_repo_path" in args.target_dict:
252
+ config["local_source_path"] = args.target_dict["cloned_repo_path"]
251
253
 
252
254
  return config
253
255
 
@@ -876,7 +878,7 @@ class StrixCLIApp(App): # type: ignore[misc]
876
878
  result = tool_data.get("result")
877
879
 
878
880
  tool_colors = {
879
- "terminal_action": "#22c55e",
881
+ "terminal_execute": "#22c55e",
880
882
  "browser_action": "#06b6d4",
881
883
  "python_action": "#3b82f6",
882
884
  "agents_graph_action": "#fbbf24",
@@ -9,7 +9,9 @@ import logging
9
9
  import os
10
10
  import secrets
11
11
  import shutil
12
+ import subprocess
12
13
  import sys
14
+ import tempfile
13
15
  from pathlib import Path
14
16
  from typing import Any
15
17
  from urllib.parse import urlparse
@@ -204,6 +206,81 @@ def generate_run_name() -> str:
204
206
  return f"{adj}-{noun}-{number}"
205
207
 
206
208
 
209
+ def clone_repository(repo_url: str, run_name: str) -> str:
210
+ console = Console()
211
+
212
+ git_executable = shutil.which("git")
213
+ if git_executable is None:
214
+ raise FileNotFoundError("Git executable not found in PATH")
215
+
216
+ temp_dir = Path(tempfile.gettempdir()) / "strix_repos" / run_name
217
+ temp_dir.mkdir(parents=True, exist_ok=True)
218
+
219
+ repo_name = Path(repo_url).stem if repo_url.endswith(".git") else Path(repo_url).name
220
+
221
+ clone_path = temp_dir / repo_name
222
+
223
+ if clone_path.exists():
224
+ shutil.rmtree(clone_path)
225
+
226
+ try:
227
+ with console.status(f"[bold cyan]Cloning repository {repo_name}...", spinner="dots"):
228
+ subprocess.run( # noqa: S603
229
+ [
230
+ git_executable,
231
+ "clone",
232
+ repo_url,
233
+ str(clone_path),
234
+ ],
235
+ capture_output=True,
236
+ text=True,
237
+ check=True,
238
+ )
239
+
240
+ return str(clone_path.absolute())
241
+
242
+ except subprocess.CalledProcessError as e:
243
+ error_text = Text()
244
+ error_text.append("❌ ", style="bold red")
245
+ error_text.append("REPOSITORY CLONE FAILED", style="bold red")
246
+ error_text.append("\n\n", style="white")
247
+ error_text.append(f"Could not clone repository: {repo_url}\n", style="white")
248
+ error_text.append(
249
+ f"Error: {e.stderr if hasattr(e, 'stderr') and e.stderr else str(e)}", style="dim red"
250
+ )
251
+
252
+ panel = Panel(
253
+ error_text,
254
+ title="[bold red]🛡️ STRIX CLONE ERROR",
255
+ title_align="center",
256
+ border_style="red",
257
+ padding=(1, 2),
258
+ )
259
+ console.print("\n")
260
+ console.print(panel)
261
+ console.print()
262
+ sys.exit(1)
263
+ except FileNotFoundError:
264
+ error_text = Text()
265
+ error_text.append("❌ ", style="bold red")
266
+ error_text.append("GIT NOT FOUND", style="bold red")
267
+ error_text.append("\n\n", style="white")
268
+ error_text.append("Git is not installed or not available in PATH.\n", style="white")
269
+ error_text.append("Please install Git to clone repositories.\n", style="white")
270
+
271
+ panel = Panel(
272
+ error_text,
273
+ title="[bold red]🛡️ STRIX CLONE ERROR",
274
+ title_align="center",
275
+ border_style="red",
276
+ padding=(1, 2),
277
+ )
278
+ console.print("\n")
279
+ console.print(panel)
280
+ console.print()
281
+ sys.exit(1)
282
+
283
+
207
284
  def infer_target_type(target: str) -> tuple[str, dict[str, str]]:
208
285
  if not target or not isinstance(target, str):
209
286
  raise ValueError("Target must be a non-empty string")
@@ -544,16 +621,23 @@ def main() -> None:
544
621
  if sys.platform == "win32":
545
622
  asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
546
623
 
624
+ args = parse_arguments()
625
+
547
626
  check_docker_installed()
548
627
  pull_docker_image()
549
628
 
550
629
  validate_environment()
551
630
  asyncio.run(warm_up_llm())
552
631
 
553
- args = parse_arguments()
554
632
  if not args.run_name:
555
633
  args.run_name = generate_run_name()
556
634
 
635
+ if args.target_type == "repository":
636
+ repo_url = args.target_dict["target_repo"]
637
+ cloned_path = clone_repository(repo_url, args.run_name)
638
+
639
+ args.target_dict["cloned_repo_path"] = cloned_path
640
+
557
641
  asyncio.run(run_strix_cli(args))
558
642
 
559
643
  results_path = Path("agent_runs") / args.run_name
@@ -0,0 +1,131 @@
1
+ from typing import Any, ClassVar
2
+
3
+ from textual.widgets import Static
4
+
5
+ from .base_renderer import BaseToolRenderer
6
+ from .registry import register_tool_renderer
7
+
8
+
9
+ @register_tool_renderer
10
+ class TerminalRenderer(BaseToolRenderer):
11
+ tool_name: ClassVar[str] = "terminal_execute"
12
+ css_classes: ClassVar[list[str]] = ["tool-call", "terminal-tool"]
13
+
14
+ @classmethod
15
+ def render(cls, tool_data: dict[str, Any]) -> Static:
16
+ args = tool_data.get("args", {})
17
+ status = tool_data.get("status", "unknown")
18
+ result = tool_data.get("result", {})
19
+
20
+ command = args.get("command", "")
21
+ is_input = args.get("is_input", False)
22
+ terminal_id = args.get("terminal_id", "default")
23
+ timeout = args.get("timeout")
24
+
25
+ content = cls._build_sleek_content(command, is_input, terminal_id, timeout, result)
26
+
27
+ css_classes = cls.get_css_classes(status)
28
+ return Static(content, classes=css_classes)
29
+
30
+ @classmethod
31
+ def _build_sleek_content(
32
+ cls,
33
+ command: str,
34
+ is_input: bool,
35
+ terminal_id: str, # noqa: ARG003
36
+ timeout: float | None, # noqa: ARG003
37
+ result: dict[str, Any], # noqa: ARG003
38
+ ) -> str:
39
+ terminal_icon = ">_"
40
+
41
+ if not command.strip():
42
+ return f"{terminal_icon} [dim]getting logs...[/]"
43
+
44
+ control_sequences = {
45
+ "C-c",
46
+ "C-d",
47
+ "C-z",
48
+ "C-a",
49
+ "C-e",
50
+ "C-k",
51
+ "C-l",
52
+ "C-u",
53
+ "C-w",
54
+ "C-r",
55
+ "C-s",
56
+ "C-t",
57
+ "C-y",
58
+ "^c",
59
+ "^d",
60
+ "^z",
61
+ "^a",
62
+ "^e",
63
+ "^k",
64
+ "^l",
65
+ "^u",
66
+ "^w",
67
+ "^r",
68
+ "^s",
69
+ "^t",
70
+ "^y",
71
+ }
72
+ special_keys = {
73
+ "Enter",
74
+ "Escape",
75
+ "Space",
76
+ "Tab",
77
+ "BTab",
78
+ "BSpace",
79
+ "DC",
80
+ "IC",
81
+ "Up",
82
+ "Down",
83
+ "Left",
84
+ "Right",
85
+ "Home",
86
+ "End",
87
+ "PageUp",
88
+ "PageDown",
89
+ "PgUp",
90
+ "PgDn",
91
+ "PPage",
92
+ "NPage",
93
+ "F1",
94
+ "F2",
95
+ "F3",
96
+ "F4",
97
+ "F5",
98
+ "F6",
99
+ "F7",
100
+ "F8",
101
+ "F9",
102
+ "F10",
103
+ "F11",
104
+ "F12",
105
+ }
106
+
107
+ is_special = (
108
+ command in control_sequences
109
+ or command in special_keys
110
+ or command.startswith(("M-", "S-", "C-S-", "C-M-", "S-M-"))
111
+ )
112
+
113
+ if is_special:
114
+ return f"{terminal_icon} [#ef4444]{command}[/]"
115
+
116
+ if is_input:
117
+ formatted_command = cls._format_command_display(command)
118
+ return f"{terminal_icon} [#3b82f6]>>>[/] [#22c55e]{formatted_command}[/]"
119
+
120
+ formatted_command = cls._format_command_display(command)
121
+ return f"{terminal_icon} [#22c55e]$ {formatted_command}[/]"
122
+
123
+ @classmethod
124
+ def _format_command_display(cls, command: str) -> str:
125
+ if not command:
126
+ return ""
127
+
128
+ if len(command) > 200:
129
+ command = command[:197] + "..."
130
+
131
+ return cls.escape_markup(command)
@@ -313,7 +313,7 @@ class LLM:
313
313
  completion_args["stop"] = ["</function>"]
314
314
 
315
315
  if self._should_include_reasoning_effort():
316
- completion_args["reasoning_effort"] = "medium"
316
+ completion_args["reasoning_effort"] = "high"
317
317
 
318
318
  queue = get_global_queue()
319
319
  response = await queue.make_request(completion_args)
@@ -348,7 +348,7 @@ class LLM:
348
348
 
349
349
  try:
350
350
  cost = completion_cost(response) or 0.0
351
- except (ValueError, TypeError, RuntimeError) as e:
351
+ except Exception as e: # noqa: BLE001
352
352
  logger.warning(f"Failed to calculate cost: {e}")
353
353
  cost = 0.0
354
354
 
@@ -370,5 +370,5 @@ class LLM:
370
370
  logger.info(f"Cache creation: {cache_creation_tokens} tokens written to cache")
371
371
 
372
372
  logger.info(f"Usage stats: {self.usage_stats}")
373
- except (AttributeError, TypeError, ValueError) as e:
373
+ except Exception as e: # noqa: BLE001
374
374
  logger.warning(f"Failed to update usage stats: {e}")