PraisonAI 3.0.0__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 (393) hide show
  1. praisonai/__init__.py +54 -0
  2. praisonai/__main__.py +15 -0
  3. praisonai/acp/__init__.py +54 -0
  4. praisonai/acp/config.py +159 -0
  5. praisonai/acp/server.py +587 -0
  6. praisonai/acp/session.py +219 -0
  7. praisonai/adapters/__init__.py +50 -0
  8. praisonai/adapters/readers.py +395 -0
  9. praisonai/adapters/rerankers.py +315 -0
  10. praisonai/adapters/retrievers.py +394 -0
  11. praisonai/adapters/vector_stores.py +409 -0
  12. praisonai/agent_scheduler.py +337 -0
  13. praisonai/agents_generator.py +903 -0
  14. praisonai/api/call.py +292 -0
  15. praisonai/auto.py +1197 -0
  16. praisonai/capabilities/__init__.py +275 -0
  17. praisonai/capabilities/a2a.py +140 -0
  18. praisonai/capabilities/assistants.py +283 -0
  19. praisonai/capabilities/audio.py +320 -0
  20. praisonai/capabilities/batches.py +469 -0
  21. praisonai/capabilities/completions.py +336 -0
  22. praisonai/capabilities/container_files.py +155 -0
  23. praisonai/capabilities/containers.py +93 -0
  24. praisonai/capabilities/embeddings.py +158 -0
  25. praisonai/capabilities/files.py +467 -0
  26. praisonai/capabilities/fine_tuning.py +293 -0
  27. praisonai/capabilities/guardrails.py +182 -0
  28. praisonai/capabilities/images.py +330 -0
  29. praisonai/capabilities/mcp.py +190 -0
  30. praisonai/capabilities/messages.py +270 -0
  31. praisonai/capabilities/moderations.py +154 -0
  32. praisonai/capabilities/ocr.py +217 -0
  33. praisonai/capabilities/passthrough.py +204 -0
  34. praisonai/capabilities/rag.py +207 -0
  35. praisonai/capabilities/realtime.py +160 -0
  36. praisonai/capabilities/rerank.py +165 -0
  37. praisonai/capabilities/responses.py +266 -0
  38. praisonai/capabilities/search.py +109 -0
  39. praisonai/capabilities/skills.py +133 -0
  40. praisonai/capabilities/vector_store_files.py +334 -0
  41. praisonai/capabilities/vector_stores.py +304 -0
  42. praisonai/capabilities/videos.py +141 -0
  43. praisonai/chainlit_ui.py +304 -0
  44. praisonai/chat/__init__.py +106 -0
  45. praisonai/chat/app.py +125 -0
  46. praisonai/cli/__init__.py +26 -0
  47. praisonai/cli/app.py +213 -0
  48. praisonai/cli/commands/__init__.py +75 -0
  49. praisonai/cli/commands/acp.py +70 -0
  50. praisonai/cli/commands/completion.py +333 -0
  51. praisonai/cli/commands/config.py +166 -0
  52. praisonai/cli/commands/debug.py +142 -0
  53. praisonai/cli/commands/diag.py +55 -0
  54. praisonai/cli/commands/doctor.py +166 -0
  55. praisonai/cli/commands/environment.py +179 -0
  56. praisonai/cli/commands/lsp.py +112 -0
  57. praisonai/cli/commands/mcp.py +210 -0
  58. praisonai/cli/commands/profile.py +457 -0
  59. praisonai/cli/commands/run.py +228 -0
  60. praisonai/cli/commands/schedule.py +150 -0
  61. praisonai/cli/commands/serve.py +97 -0
  62. praisonai/cli/commands/session.py +212 -0
  63. praisonai/cli/commands/traces.py +145 -0
  64. praisonai/cli/commands/version.py +101 -0
  65. praisonai/cli/configuration/__init__.py +18 -0
  66. praisonai/cli/configuration/loader.py +353 -0
  67. praisonai/cli/configuration/paths.py +114 -0
  68. praisonai/cli/configuration/schema.py +164 -0
  69. praisonai/cli/features/__init__.py +268 -0
  70. praisonai/cli/features/acp.py +236 -0
  71. praisonai/cli/features/action_orchestrator.py +546 -0
  72. praisonai/cli/features/agent_scheduler.py +773 -0
  73. praisonai/cli/features/agent_tools.py +474 -0
  74. praisonai/cli/features/agents.py +375 -0
  75. praisonai/cli/features/at_mentions.py +471 -0
  76. praisonai/cli/features/auto_memory.py +182 -0
  77. praisonai/cli/features/autonomy_mode.py +490 -0
  78. praisonai/cli/features/background.py +356 -0
  79. praisonai/cli/features/base.py +168 -0
  80. praisonai/cli/features/capabilities.py +1326 -0
  81. praisonai/cli/features/checkpoints.py +338 -0
  82. praisonai/cli/features/code_intelligence.py +652 -0
  83. praisonai/cli/features/compaction.py +294 -0
  84. praisonai/cli/features/compare.py +534 -0
  85. praisonai/cli/features/cost_tracker.py +514 -0
  86. praisonai/cli/features/debug.py +810 -0
  87. praisonai/cli/features/deploy.py +517 -0
  88. praisonai/cli/features/diag.py +289 -0
  89. praisonai/cli/features/doctor/__init__.py +63 -0
  90. praisonai/cli/features/doctor/checks/__init__.py +24 -0
  91. praisonai/cli/features/doctor/checks/acp_checks.py +240 -0
  92. praisonai/cli/features/doctor/checks/config_checks.py +366 -0
  93. praisonai/cli/features/doctor/checks/db_checks.py +366 -0
  94. praisonai/cli/features/doctor/checks/env_checks.py +543 -0
  95. praisonai/cli/features/doctor/checks/lsp_checks.py +199 -0
  96. praisonai/cli/features/doctor/checks/mcp_checks.py +349 -0
  97. praisonai/cli/features/doctor/checks/memory_checks.py +268 -0
  98. praisonai/cli/features/doctor/checks/network_checks.py +251 -0
  99. praisonai/cli/features/doctor/checks/obs_checks.py +328 -0
  100. praisonai/cli/features/doctor/checks/performance_checks.py +235 -0
  101. praisonai/cli/features/doctor/checks/permissions_checks.py +259 -0
  102. praisonai/cli/features/doctor/checks/selftest_checks.py +322 -0
  103. praisonai/cli/features/doctor/checks/serve_checks.py +426 -0
  104. praisonai/cli/features/doctor/checks/skills_checks.py +231 -0
  105. praisonai/cli/features/doctor/checks/tools_checks.py +371 -0
  106. praisonai/cli/features/doctor/engine.py +266 -0
  107. praisonai/cli/features/doctor/formatters.py +310 -0
  108. praisonai/cli/features/doctor/handler.py +397 -0
  109. praisonai/cli/features/doctor/models.py +264 -0
  110. praisonai/cli/features/doctor/registry.py +239 -0
  111. praisonai/cli/features/endpoints.py +1019 -0
  112. praisonai/cli/features/eval.py +560 -0
  113. praisonai/cli/features/external_agents.py +231 -0
  114. praisonai/cli/features/fast_context.py +410 -0
  115. praisonai/cli/features/flow_display.py +566 -0
  116. praisonai/cli/features/git_integration.py +651 -0
  117. praisonai/cli/features/guardrail.py +171 -0
  118. praisonai/cli/features/handoff.py +185 -0
  119. praisonai/cli/features/hooks.py +583 -0
  120. praisonai/cli/features/image.py +384 -0
  121. praisonai/cli/features/interactive_runtime.py +585 -0
  122. praisonai/cli/features/interactive_tools.py +380 -0
  123. praisonai/cli/features/interactive_tui.py +603 -0
  124. praisonai/cli/features/jobs.py +632 -0
  125. praisonai/cli/features/knowledge.py +531 -0
  126. praisonai/cli/features/lite.py +244 -0
  127. praisonai/cli/features/lsp_cli.py +225 -0
  128. praisonai/cli/features/mcp.py +169 -0
  129. praisonai/cli/features/message_queue.py +587 -0
  130. praisonai/cli/features/metrics.py +211 -0
  131. praisonai/cli/features/n8n.py +673 -0
  132. praisonai/cli/features/observability.py +293 -0
  133. praisonai/cli/features/ollama.py +361 -0
  134. praisonai/cli/features/output_style.py +273 -0
  135. praisonai/cli/features/package.py +631 -0
  136. praisonai/cli/features/performance.py +308 -0
  137. praisonai/cli/features/persistence.py +636 -0
  138. praisonai/cli/features/profile.py +226 -0
  139. praisonai/cli/features/profiler/__init__.py +81 -0
  140. praisonai/cli/features/profiler/core.py +558 -0
  141. praisonai/cli/features/profiler/optimizations.py +652 -0
  142. praisonai/cli/features/profiler/suite.py +386 -0
  143. praisonai/cli/features/profiling.py +350 -0
  144. praisonai/cli/features/queue/__init__.py +73 -0
  145. praisonai/cli/features/queue/manager.py +395 -0
  146. praisonai/cli/features/queue/models.py +286 -0
  147. praisonai/cli/features/queue/persistence.py +564 -0
  148. praisonai/cli/features/queue/scheduler.py +484 -0
  149. praisonai/cli/features/queue/worker.py +372 -0
  150. praisonai/cli/features/recipe.py +1723 -0
  151. praisonai/cli/features/recipes.py +449 -0
  152. praisonai/cli/features/registry.py +229 -0
  153. praisonai/cli/features/repo_map.py +860 -0
  154. praisonai/cli/features/router.py +466 -0
  155. praisonai/cli/features/sandbox_executor.py +515 -0
  156. praisonai/cli/features/serve.py +829 -0
  157. praisonai/cli/features/session.py +222 -0
  158. praisonai/cli/features/skills.py +856 -0
  159. praisonai/cli/features/slash_commands.py +650 -0
  160. praisonai/cli/features/telemetry.py +179 -0
  161. praisonai/cli/features/templates.py +1384 -0
  162. praisonai/cli/features/thinking.py +305 -0
  163. praisonai/cli/features/todo.py +334 -0
  164. praisonai/cli/features/tools.py +680 -0
  165. praisonai/cli/features/tui/__init__.py +83 -0
  166. praisonai/cli/features/tui/app.py +580 -0
  167. praisonai/cli/features/tui/cli.py +566 -0
  168. praisonai/cli/features/tui/debug.py +511 -0
  169. praisonai/cli/features/tui/events.py +99 -0
  170. praisonai/cli/features/tui/mock_provider.py +328 -0
  171. praisonai/cli/features/tui/orchestrator.py +652 -0
  172. praisonai/cli/features/tui/screens/__init__.py +50 -0
  173. praisonai/cli/features/tui/screens/main.py +245 -0
  174. praisonai/cli/features/tui/screens/queue.py +174 -0
  175. praisonai/cli/features/tui/screens/session.py +124 -0
  176. praisonai/cli/features/tui/screens/settings.py +148 -0
  177. praisonai/cli/features/tui/widgets/__init__.py +56 -0
  178. praisonai/cli/features/tui/widgets/chat.py +261 -0
  179. praisonai/cli/features/tui/widgets/composer.py +224 -0
  180. praisonai/cli/features/tui/widgets/queue_panel.py +200 -0
  181. praisonai/cli/features/tui/widgets/status.py +167 -0
  182. praisonai/cli/features/tui/widgets/tool_panel.py +248 -0
  183. praisonai/cli/features/workflow.py +720 -0
  184. praisonai/cli/legacy.py +236 -0
  185. praisonai/cli/main.py +5559 -0
  186. praisonai/cli/schedule_cli.py +54 -0
  187. praisonai/cli/state/__init__.py +31 -0
  188. praisonai/cli/state/identifiers.py +161 -0
  189. praisonai/cli/state/sessions.py +313 -0
  190. praisonai/code/__init__.py +93 -0
  191. praisonai/code/agent_tools.py +344 -0
  192. praisonai/code/diff/__init__.py +21 -0
  193. praisonai/code/diff/diff_strategy.py +432 -0
  194. praisonai/code/tools/__init__.py +27 -0
  195. praisonai/code/tools/apply_diff.py +221 -0
  196. praisonai/code/tools/execute_command.py +275 -0
  197. praisonai/code/tools/list_files.py +274 -0
  198. praisonai/code/tools/read_file.py +206 -0
  199. praisonai/code/tools/search_replace.py +248 -0
  200. praisonai/code/tools/write_file.py +217 -0
  201. praisonai/code/utils/__init__.py +46 -0
  202. praisonai/code/utils/file_utils.py +307 -0
  203. praisonai/code/utils/ignore_utils.py +308 -0
  204. praisonai/code/utils/text_utils.py +276 -0
  205. praisonai/db/__init__.py +64 -0
  206. praisonai/db/adapter.py +531 -0
  207. praisonai/deploy/__init__.py +62 -0
  208. praisonai/deploy/api.py +231 -0
  209. praisonai/deploy/docker.py +454 -0
  210. praisonai/deploy/doctor.py +367 -0
  211. praisonai/deploy/main.py +327 -0
  212. praisonai/deploy/models.py +179 -0
  213. praisonai/deploy/providers/__init__.py +33 -0
  214. praisonai/deploy/providers/aws.py +331 -0
  215. praisonai/deploy/providers/azure.py +358 -0
  216. praisonai/deploy/providers/base.py +101 -0
  217. praisonai/deploy/providers/gcp.py +314 -0
  218. praisonai/deploy/schema.py +208 -0
  219. praisonai/deploy.py +185 -0
  220. praisonai/endpoints/__init__.py +53 -0
  221. praisonai/endpoints/a2u_server.py +410 -0
  222. praisonai/endpoints/discovery.py +165 -0
  223. praisonai/endpoints/providers/__init__.py +28 -0
  224. praisonai/endpoints/providers/a2a.py +253 -0
  225. praisonai/endpoints/providers/a2u.py +208 -0
  226. praisonai/endpoints/providers/agents_api.py +171 -0
  227. praisonai/endpoints/providers/base.py +231 -0
  228. praisonai/endpoints/providers/mcp.py +263 -0
  229. praisonai/endpoints/providers/recipe.py +206 -0
  230. praisonai/endpoints/providers/tools_mcp.py +150 -0
  231. praisonai/endpoints/registry.py +131 -0
  232. praisonai/endpoints/server.py +161 -0
  233. praisonai/inbuilt_tools/__init__.py +24 -0
  234. praisonai/inbuilt_tools/autogen_tools.py +117 -0
  235. praisonai/inc/__init__.py +2 -0
  236. praisonai/inc/config.py +96 -0
  237. praisonai/inc/models.py +155 -0
  238. praisonai/integrations/__init__.py +56 -0
  239. praisonai/integrations/base.py +303 -0
  240. praisonai/integrations/claude_code.py +270 -0
  241. praisonai/integrations/codex_cli.py +255 -0
  242. praisonai/integrations/cursor_cli.py +195 -0
  243. praisonai/integrations/gemini_cli.py +222 -0
  244. praisonai/jobs/__init__.py +67 -0
  245. praisonai/jobs/executor.py +425 -0
  246. praisonai/jobs/models.py +230 -0
  247. praisonai/jobs/router.py +314 -0
  248. praisonai/jobs/server.py +186 -0
  249. praisonai/jobs/store.py +203 -0
  250. praisonai/llm/__init__.py +66 -0
  251. praisonai/llm/registry.py +382 -0
  252. praisonai/mcp_server/__init__.py +152 -0
  253. praisonai/mcp_server/adapters/__init__.py +74 -0
  254. praisonai/mcp_server/adapters/agents.py +128 -0
  255. praisonai/mcp_server/adapters/capabilities.py +168 -0
  256. praisonai/mcp_server/adapters/cli_tools.py +568 -0
  257. praisonai/mcp_server/adapters/extended_capabilities.py +462 -0
  258. praisonai/mcp_server/adapters/knowledge.py +93 -0
  259. praisonai/mcp_server/adapters/memory.py +104 -0
  260. praisonai/mcp_server/adapters/prompts.py +306 -0
  261. praisonai/mcp_server/adapters/resources.py +124 -0
  262. praisonai/mcp_server/adapters/tools_bridge.py +280 -0
  263. praisonai/mcp_server/auth/__init__.py +48 -0
  264. praisonai/mcp_server/auth/api_key.py +291 -0
  265. praisonai/mcp_server/auth/oauth.py +460 -0
  266. praisonai/mcp_server/auth/oidc.py +289 -0
  267. praisonai/mcp_server/auth/scopes.py +260 -0
  268. praisonai/mcp_server/cli.py +852 -0
  269. praisonai/mcp_server/elicitation.py +445 -0
  270. praisonai/mcp_server/icons.py +302 -0
  271. praisonai/mcp_server/recipe_adapter.py +573 -0
  272. praisonai/mcp_server/recipe_cli.py +824 -0
  273. praisonai/mcp_server/registry.py +703 -0
  274. praisonai/mcp_server/sampling.py +422 -0
  275. praisonai/mcp_server/server.py +490 -0
  276. praisonai/mcp_server/tasks.py +443 -0
  277. praisonai/mcp_server/transports/__init__.py +18 -0
  278. praisonai/mcp_server/transports/http_stream.py +376 -0
  279. praisonai/mcp_server/transports/stdio.py +132 -0
  280. praisonai/persistence/__init__.py +84 -0
  281. praisonai/persistence/config.py +238 -0
  282. praisonai/persistence/conversation/__init__.py +25 -0
  283. praisonai/persistence/conversation/async_mysql.py +427 -0
  284. praisonai/persistence/conversation/async_postgres.py +410 -0
  285. praisonai/persistence/conversation/async_sqlite.py +371 -0
  286. praisonai/persistence/conversation/base.py +151 -0
  287. praisonai/persistence/conversation/json_store.py +250 -0
  288. praisonai/persistence/conversation/mysql.py +387 -0
  289. praisonai/persistence/conversation/postgres.py +401 -0
  290. praisonai/persistence/conversation/singlestore.py +240 -0
  291. praisonai/persistence/conversation/sqlite.py +341 -0
  292. praisonai/persistence/conversation/supabase.py +203 -0
  293. praisonai/persistence/conversation/surrealdb.py +287 -0
  294. praisonai/persistence/factory.py +301 -0
  295. praisonai/persistence/hooks/__init__.py +18 -0
  296. praisonai/persistence/hooks/agent_hooks.py +297 -0
  297. praisonai/persistence/knowledge/__init__.py +26 -0
  298. praisonai/persistence/knowledge/base.py +144 -0
  299. praisonai/persistence/knowledge/cassandra.py +232 -0
  300. praisonai/persistence/knowledge/chroma.py +295 -0
  301. praisonai/persistence/knowledge/clickhouse.py +242 -0
  302. praisonai/persistence/knowledge/cosmosdb_vector.py +438 -0
  303. praisonai/persistence/knowledge/couchbase.py +286 -0
  304. praisonai/persistence/knowledge/lancedb.py +216 -0
  305. praisonai/persistence/knowledge/langchain_adapter.py +291 -0
  306. praisonai/persistence/knowledge/lightrag_adapter.py +212 -0
  307. praisonai/persistence/knowledge/llamaindex_adapter.py +256 -0
  308. praisonai/persistence/knowledge/milvus.py +277 -0
  309. praisonai/persistence/knowledge/mongodb_vector.py +306 -0
  310. praisonai/persistence/knowledge/pgvector.py +335 -0
  311. praisonai/persistence/knowledge/pinecone.py +253 -0
  312. praisonai/persistence/knowledge/qdrant.py +301 -0
  313. praisonai/persistence/knowledge/redis_vector.py +291 -0
  314. praisonai/persistence/knowledge/singlestore_vector.py +299 -0
  315. praisonai/persistence/knowledge/surrealdb_vector.py +309 -0
  316. praisonai/persistence/knowledge/upstash_vector.py +266 -0
  317. praisonai/persistence/knowledge/weaviate.py +223 -0
  318. praisonai/persistence/migrations/__init__.py +10 -0
  319. praisonai/persistence/migrations/manager.py +251 -0
  320. praisonai/persistence/orchestrator.py +406 -0
  321. praisonai/persistence/state/__init__.py +21 -0
  322. praisonai/persistence/state/async_mongodb.py +200 -0
  323. praisonai/persistence/state/base.py +107 -0
  324. praisonai/persistence/state/dynamodb.py +226 -0
  325. praisonai/persistence/state/firestore.py +175 -0
  326. praisonai/persistence/state/gcs.py +155 -0
  327. praisonai/persistence/state/memory.py +245 -0
  328. praisonai/persistence/state/mongodb.py +158 -0
  329. praisonai/persistence/state/redis.py +190 -0
  330. praisonai/persistence/state/upstash.py +144 -0
  331. praisonai/persistence/tests/__init__.py +3 -0
  332. praisonai/persistence/tests/test_all_backends.py +633 -0
  333. praisonai/profiler.py +1214 -0
  334. praisonai/recipe/__init__.py +134 -0
  335. praisonai/recipe/bridge.py +278 -0
  336. praisonai/recipe/core.py +893 -0
  337. praisonai/recipe/exceptions.py +54 -0
  338. praisonai/recipe/history.py +402 -0
  339. praisonai/recipe/models.py +266 -0
  340. praisonai/recipe/operations.py +440 -0
  341. praisonai/recipe/policy.py +422 -0
  342. praisonai/recipe/registry.py +849 -0
  343. praisonai/recipe/runtime.py +214 -0
  344. praisonai/recipe/security.py +711 -0
  345. praisonai/recipe/serve.py +859 -0
  346. praisonai/recipe/server.py +613 -0
  347. praisonai/scheduler/__init__.py +45 -0
  348. praisonai/scheduler/agent_scheduler.py +552 -0
  349. praisonai/scheduler/base.py +124 -0
  350. praisonai/scheduler/daemon_manager.py +225 -0
  351. praisonai/scheduler/state_manager.py +155 -0
  352. praisonai/scheduler/yaml_loader.py +193 -0
  353. praisonai/scheduler.py +194 -0
  354. praisonai/setup/__init__.py +1 -0
  355. praisonai/setup/build.py +21 -0
  356. praisonai/setup/post_install.py +23 -0
  357. praisonai/setup/setup_conda_env.py +25 -0
  358. praisonai/setup.py +16 -0
  359. praisonai/templates/__init__.py +116 -0
  360. praisonai/templates/cache.py +364 -0
  361. praisonai/templates/dependency_checker.py +358 -0
  362. praisonai/templates/discovery.py +391 -0
  363. praisonai/templates/loader.py +564 -0
  364. praisonai/templates/registry.py +511 -0
  365. praisonai/templates/resolver.py +206 -0
  366. praisonai/templates/security.py +327 -0
  367. praisonai/templates/tool_override.py +498 -0
  368. praisonai/templates/tools_doctor.py +256 -0
  369. praisonai/test.py +105 -0
  370. praisonai/train.py +562 -0
  371. praisonai/train_vision.py +306 -0
  372. praisonai/ui/agents.py +824 -0
  373. praisonai/ui/callbacks.py +57 -0
  374. praisonai/ui/chainlit_compat.py +246 -0
  375. praisonai/ui/chat.py +532 -0
  376. praisonai/ui/code.py +717 -0
  377. praisonai/ui/colab.py +474 -0
  378. praisonai/ui/colab_chainlit.py +81 -0
  379. praisonai/ui/components/aicoder.py +284 -0
  380. praisonai/ui/context.py +283 -0
  381. praisonai/ui/database_config.py +56 -0
  382. praisonai/ui/db.py +294 -0
  383. praisonai/ui/realtime.py +488 -0
  384. praisonai/ui/realtimeclient/__init__.py +756 -0
  385. praisonai/ui/realtimeclient/tools.py +242 -0
  386. praisonai/ui/sql_alchemy.py +710 -0
  387. praisonai/upload_vision.py +140 -0
  388. praisonai/version.py +1 -0
  389. praisonai-3.0.0.dist-info/METADATA +3493 -0
  390. praisonai-3.0.0.dist-info/RECORD +393 -0
  391. praisonai-3.0.0.dist-info/WHEEL +5 -0
  392. praisonai-3.0.0.dist-info/entry_points.txt +4 -0
  393. praisonai-3.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,275 @@
1
+ """
2
+ Execute Command Tool for PraisonAI Code.
3
+
4
+ Provides functionality to execute shell commands safely.
5
+ """
6
+
7
+ import os
8
+ import subprocess
9
+ import shlex
10
+ from typing import Optional, Dict, Any
11
+
12
+
13
+ # Commands that are generally safe to auto-run
14
+ SAFE_COMMANDS = {
15
+ 'ls', 'dir', 'pwd', 'echo', 'cat', 'head', 'tail', 'wc',
16
+ 'grep', 'find', 'which', 'whereis', 'type', 'file',
17
+ 'date', 'whoami', 'hostname', 'uname',
18
+ 'python', 'python3', 'node', 'npm', 'npx', 'pip', 'pip3',
19
+ 'git', 'cargo', 'go', 'ruby', 'java', 'javac',
20
+ }
21
+
22
+ # Commands that should never be auto-run
23
+ DANGEROUS_COMMANDS = {
24
+ 'rm', 'rmdir', 'del', 'format', 'mkfs',
25
+ 'dd', 'shred', 'chmod', 'chown', 'chgrp',
26
+ 'kill', 'killall', 'pkill',
27
+ 'shutdown', 'reboot', 'halt', 'poweroff',
28
+ 'sudo', 'su', 'doas',
29
+ 'curl', 'wget', 'ssh', 'scp', 'rsync',
30
+ 'mv', 'cp', # Can be destructive
31
+ }
32
+
33
+
34
+ def execute_command(
35
+ command: str,
36
+ cwd: Optional[str] = None,
37
+ workspace: Optional[str] = None,
38
+ timeout: int = 120,
39
+ capture_output: bool = True,
40
+ shell: bool = True,
41
+ env: Optional[Dict[str, str]] = None,
42
+ ) -> Dict[str, Any]:
43
+ """
44
+ Execute a shell command and return the result.
45
+
46
+ This tool executes shell commands with safety checks and output capture.
47
+
48
+ Args:
49
+ command: The command to execute
50
+ cwd: Working directory for the command
51
+ workspace: Workspace root (for security validation)
52
+ timeout: Command timeout in seconds
53
+ capture_output: Whether to capture stdout/stderr
54
+ shell: Whether to run through shell
55
+ env: Additional environment variables
56
+
57
+ Returns:
58
+ Dictionary with:
59
+ - success: bool
60
+ - exit_code: int
61
+ - stdout: str
62
+ - stderr: str
63
+ - command: str
64
+ - error: str (if success is False)
65
+
66
+ Example:
67
+ >>> result = execute_command("python --version")
68
+ >>> print(result['stdout'])
69
+ """
70
+ if not command or not command.strip():
71
+ return {
72
+ 'success': False,
73
+ 'error': "Empty command",
74
+ 'command': command,
75
+ 'exit_code': -1,
76
+ 'stdout': '',
77
+ 'stderr': '',
78
+ }
79
+
80
+ # Resolve working directory
81
+ if cwd:
82
+ if workspace and not os.path.isabs(cwd):
83
+ work_dir = os.path.abspath(os.path.join(workspace, cwd))
84
+ else:
85
+ work_dir = os.path.abspath(cwd)
86
+ elif workspace:
87
+ work_dir = workspace
88
+ else:
89
+ work_dir = os.getcwd()
90
+
91
+ # Validate working directory exists
92
+ if not os.path.isdir(work_dir):
93
+ return {
94
+ 'success': False,
95
+ 'error': f"Working directory not found: {cwd}",
96
+ 'command': command,
97
+ 'exit_code': -1,
98
+ 'stdout': '',
99
+ 'stderr': '',
100
+ }
101
+
102
+ # Prepare environment
103
+ cmd_env = os.environ.copy()
104
+ if env:
105
+ cmd_env.update(env)
106
+
107
+ # Set PAGER to cat to avoid interactive pagers
108
+ cmd_env['PAGER'] = 'cat'
109
+
110
+ try:
111
+ # Execute command
112
+ if shell:
113
+ result = subprocess.run(
114
+ command,
115
+ shell=True,
116
+ cwd=work_dir,
117
+ capture_output=capture_output,
118
+ timeout=timeout,
119
+ env=cmd_env,
120
+ text=True,
121
+ )
122
+ else:
123
+ # Parse command for non-shell execution
124
+ args = shlex.split(command)
125
+ result = subprocess.run(
126
+ args,
127
+ cwd=work_dir,
128
+ capture_output=capture_output,
129
+ timeout=timeout,
130
+ env=cmd_env,
131
+ text=True,
132
+ )
133
+
134
+ return {
135
+ 'success': result.returncode == 0,
136
+ 'exit_code': result.returncode,
137
+ 'stdout': result.stdout if capture_output else '',
138
+ 'stderr': result.stderr if capture_output else '',
139
+ 'command': command,
140
+ 'cwd': work_dir,
141
+ }
142
+
143
+ except subprocess.TimeoutExpired:
144
+ return {
145
+ 'success': False,
146
+ 'error': f"Command timed out after {timeout} seconds",
147
+ 'command': command,
148
+ 'exit_code': -1,
149
+ 'stdout': '',
150
+ 'stderr': '',
151
+ }
152
+ except FileNotFoundError as e:
153
+ return {
154
+ 'success': False,
155
+ 'error': f"Command not found: {str(e)}",
156
+ 'command': command,
157
+ 'exit_code': -1,
158
+ 'stdout': '',
159
+ 'stderr': '',
160
+ }
161
+ except PermissionError:
162
+ return {
163
+ 'success': False,
164
+ 'error': "Permission denied",
165
+ 'command': command,
166
+ 'exit_code': -1,
167
+ 'stdout': '',
168
+ 'stderr': '',
169
+ }
170
+ except Exception as e:
171
+ return {
172
+ 'success': False,
173
+ 'error': f"Error executing command: {str(e)}",
174
+ 'command': command,
175
+ 'exit_code': -1,
176
+ 'stdout': '',
177
+ 'stderr': '',
178
+ }
179
+
180
+
181
+ def is_safe_command(command: str) -> bool:
182
+ """
183
+ Check if a command is considered safe to auto-run.
184
+
185
+ Args:
186
+ command: The command to check
187
+
188
+ Returns:
189
+ True if the command is considered safe
190
+ """
191
+ if not command:
192
+ return False
193
+
194
+ # Get the base command (first word)
195
+ parts = shlex.split(command)
196
+ if not parts:
197
+ return False
198
+
199
+ base_cmd = os.path.basename(parts[0]).lower()
200
+
201
+ # Check against dangerous commands
202
+ if base_cmd in DANGEROUS_COMMANDS:
203
+ return False
204
+
205
+ # Check against safe commands
206
+ if base_cmd in SAFE_COMMANDS:
207
+ return True
208
+
209
+ # Default to unsafe
210
+ return False
211
+
212
+
213
+ def get_command_info(command: str) -> Dict[str, Any]:
214
+ """
215
+ Get information about a command without executing it.
216
+
217
+ Args:
218
+ command: The command to analyze
219
+
220
+ Returns:
221
+ Dictionary with command analysis
222
+ """
223
+ if not command:
224
+ return {
225
+ 'valid': False,
226
+ 'error': "Empty command",
227
+ }
228
+
229
+ try:
230
+ parts = shlex.split(command)
231
+ base_cmd = parts[0] if parts else ''
232
+
233
+ return {
234
+ 'valid': True,
235
+ 'base_command': base_cmd,
236
+ 'arguments': parts[1:] if len(parts) > 1 else [],
237
+ 'is_safe': is_safe_command(command),
238
+ 'is_dangerous': os.path.basename(base_cmd).lower() in DANGEROUS_COMMANDS,
239
+ }
240
+ except ValueError as e:
241
+ return {
242
+ 'valid': False,
243
+ 'error': f"Invalid command syntax: {str(e)}",
244
+ }
245
+
246
+
247
+ def run_python(
248
+ code: str,
249
+ cwd: Optional[str] = None,
250
+ timeout: int = 60,
251
+ ) -> Dict[str, Any]:
252
+ """
253
+ Execute Python code and return the result.
254
+
255
+ Args:
256
+ code: Python code to execute
257
+ cwd: Working directory
258
+ timeout: Execution timeout
259
+
260
+ Returns:
261
+ Dictionary with execution result
262
+ """
263
+ # Create a temporary command to run the code
264
+ import sys
265
+ python_cmd = sys.executable
266
+
267
+ # Escape the code for command line
268
+ escaped_code = code.replace('\\', '\\\\').replace('"', '\\"')
269
+ command = f'{python_cmd} -c "{escaped_code}"'
270
+
271
+ return execute_command(
272
+ command=command,
273
+ cwd=cwd,
274
+ timeout=timeout,
275
+ )
@@ -0,0 +1,274 @@
1
+ """
2
+ List Files Tool for PraisonAI Code.
3
+
4
+ Provides functionality to list directory contents with filtering options.
5
+ """
6
+
7
+ import os
8
+ from typing import Optional, List, Dict, Any
9
+
10
+ from ..utils.ignore_utils import (
11
+ should_ignore_path,
12
+ load_gitignore_patterns,
13
+ )
14
+
15
+
16
+ def list_files(
17
+ path: str,
18
+ recursive: bool = False,
19
+ workspace: Optional[str] = None,
20
+ max_files: int = 200,
21
+ include_hidden: bool = False,
22
+ extensions: Optional[List[str]] = None,
23
+ respect_gitignore: bool = True,
24
+ ) -> Dict[str, Any]:
25
+ """
26
+ List files and directories in a given path.
27
+
28
+ This tool lists the contents of a directory, optionally recursively,
29
+ with support for filtering and gitignore patterns.
30
+
31
+ Args:
32
+ path: Path to the directory (absolute or relative to workspace)
33
+ recursive: Whether to list recursively
34
+ workspace: Workspace root directory (for relative paths)
35
+ max_files: Maximum number of files to return
36
+ include_hidden: Whether to include hidden files (starting with .)
37
+ extensions: List of file extensions to include (e.g., ['py', 'js'])
38
+ respect_gitignore: Whether to respect .gitignore patterns
39
+
40
+ Returns:
41
+ Dictionary with:
42
+ - success: bool
43
+ - files: List of file entries with path, type, size
44
+ - directories: List of directory entries
45
+ - total_count: int (total items found)
46
+ - truncated: bool (True if max_files was reached)
47
+ - error: str (if success is False)
48
+
49
+ Example:
50
+ >>> result = list_files("src", recursive=True, extensions=['py'])
51
+ >>> for f in result['files']:
52
+ ... print(f['path'])
53
+ """
54
+ # Resolve path
55
+ if workspace and not os.path.isabs(path):
56
+ abs_path = os.path.abspath(os.path.join(workspace, path))
57
+ else:
58
+ abs_path = os.path.abspath(path)
59
+
60
+ # Check if directory exists
61
+ if not os.path.isdir(abs_path):
62
+ return {
63
+ 'success': False,
64
+ 'error': f"Directory not found: {path}",
65
+ 'files': [],
66
+ 'directories': [],
67
+ 'total_count': 0,
68
+ }
69
+
70
+ # Load gitignore patterns
71
+ ignore_patterns = []
72
+ if respect_gitignore:
73
+ # Load from workspace root if available
74
+ if workspace:
75
+ ignore_patterns = load_gitignore_patterns(workspace)
76
+ # Also load from the target directory
77
+ ignore_patterns.extend(load_gitignore_patterns(abs_path))
78
+
79
+ files = []
80
+ directories = []
81
+ total_count = 0
82
+ truncated = False
83
+
84
+ try:
85
+ if recursive:
86
+ # Walk directory tree
87
+ for root, dirs, filenames in os.walk(abs_path):
88
+ # Filter hidden directories
89
+ if not include_hidden:
90
+ dirs[:] = [d for d in dirs if not d.startswith('.')]
91
+
92
+ # Filter ignored directories
93
+ if respect_gitignore:
94
+ base_dir = workspace or abs_path
95
+ dirs[:] = [
96
+ d for d in dirs
97
+ if not should_ignore_path(
98
+ os.path.join(root, d),
99
+ ignore_patterns,
100
+ base_dir,
101
+ is_directory=True
102
+ )
103
+ ]
104
+
105
+ # Process files
106
+ for filename in filenames:
107
+ if total_count >= max_files:
108
+ truncated = True
109
+ break
110
+
111
+ # Skip hidden files
112
+ if not include_hidden and filename.startswith('.'):
113
+ continue
114
+
115
+ file_path = os.path.join(root, filename)
116
+ rel_path = os.path.relpath(file_path, abs_path)
117
+
118
+ # Check gitignore
119
+ if respect_gitignore:
120
+ base_dir = workspace or abs_path
121
+ if should_ignore_path(file_path, ignore_patterns, base_dir):
122
+ continue
123
+
124
+ # Filter by extension
125
+ if extensions:
126
+ ext = os.path.splitext(filename)[1].lstrip('.')
127
+ if ext.lower() not in [e.lower() for e in extensions]:
128
+ continue
129
+
130
+ # Get file info
131
+ try:
132
+ stat = os.stat(file_path)
133
+ files.append({
134
+ 'path': rel_path,
135
+ 'name': filename,
136
+ 'size': stat.st_size,
137
+ 'modified': stat.st_mtime,
138
+ })
139
+ total_count += 1
140
+ except OSError:
141
+ continue
142
+
143
+ if truncated:
144
+ break
145
+
146
+ # Add directories
147
+ for dirname in dirs:
148
+ if total_count >= max_files:
149
+ truncated = True
150
+ break
151
+
152
+ dir_path = os.path.join(root, dirname)
153
+ rel_path = os.path.relpath(dir_path, abs_path)
154
+
155
+ directories.append({
156
+ 'path': rel_path,
157
+ 'name': dirname,
158
+ })
159
+ total_count += 1
160
+ else:
161
+ # List only top level
162
+ for entry in os.listdir(abs_path):
163
+ if total_count >= max_files:
164
+ truncated = True
165
+ break
166
+
167
+ # Skip hidden files
168
+ if not include_hidden and entry.startswith('.'):
169
+ continue
170
+
171
+ entry_path = os.path.join(abs_path, entry)
172
+
173
+ # Check gitignore
174
+ if respect_gitignore:
175
+ base_dir = workspace or abs_path
176
+ is_dir = os.path.isdir(entry_path)
177
+ if should_ignore_path(entry_path, ignore_patterns, base_dir, is_dir):
178
+ continue
179
+
180
+ if os.path.isfile(entry_path):
181
+ # Filter by extension
182
+ if extensions:
183
+ ext = os.path.splitext(entry)[1].lstrip('.')
184
+ if ext.lower() not in [e.lower() for e in extensions]:
185
+ continue
186
+
187
+ try:
188
+ stat = os.stat(entry_path)
189
+ files.append({
190
+ 'path': entry,
191
+ 'name': entry,
192
+ 'size': stat.st_size,
193
+ 'modified': stat.st_mtime,
194
+ })
195
+ total_count += 1
196
+ except OSError:
197
+ continue
198
+
199
+ elif os.path.isdir(entry_path):
200
+ directories.append({
201
+ 'path': entry,
202
+ 'name': entry,
203
+ })
204
+ total_count += 1
205
+
206
+ # Sort results
207
+ files.sort(key=lambda x: x['path'])
208
+ directories.sort(key=lambda x: x['path'])
209
+
210
+ return {
211
+ 'success': True,
212
+ 'files': files,
213
+ 'directories': directories,
214
+ 'total_count': total_count,
215
+ 'truncated': truncated,
216
+ 'path': path,
217
+ }
218
+
219
+ except PermissionError:
220
+ return {
221
+ 'success': False,
222
+ 'error': f"Permission denied: {path}",
223
+ 'files': [],
224
+ 'directories': [],
225
+ 'total_count': 0,
226
+ }
227
+ except Exception as e:
228
+ return {
229
+ 'success': False,
230
+ 'error': f"Error listing {path}: {str(e)}",
231
+ 'files': [],
232
+ 'directories': [],
233
+ 'total_count': 0,
234
+ }
235
+
236
+
237
+ def format_file_list(result: Dict[str, Any], show_size: bool = True) -> str:
238
+ """
239
+ Format a list_files result as a readable string.
240
+
241
+ Args:
242
+ result: Result from list_files()
243
+ show_size: Whether to show file sizes
244
+
245
+ Returns:
246
+ Formatted string representation
247
+ """
248
+ if not result['success']:
249
+ return f"Error: {result.get('error', 'Unknown error')}"
250
+
251
+ lines = []
252
+
253
+ # Add directories first
254
+ for d in result['directories']:
255
+ lines.append(f"📁 {d['path']}/")
256
+
257
+ # Add files
258
+ for f in result['files']:
259
+ if show_size:
260
+ size = f.get('size', 0)
261
+ if size < 1024:
262
+ size_str = f"{size}B"
263
+ elif size < 1024 * 1024:
264
+ size_str = f"{size / 1024:.1f}KB"
265
+ else:
266
+ size_str = f"{size / (1024 * 1024):.1f}MB"
267
+ lines.append(f"📄 {f['path']} ({size_str})")
268
+ else:
269
+ lines.append(f"📄 {f['path']}")
270
+
271
+ if result.get('truncated'):
272
+ lines.append(f"\n... (truncated, showing {result['total_count']} of more items)")
273
+
274
+ return '\n'.join(lines)