praisonai-code 0.0.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 (309) hide show
  1. praisonai_code/__init__.py +17 -0
  2. praisonai_code/cli/__init__.py +12 -0
  3. praisonai_code/cli/_forward_shim.py +10 -0
  4. praisonai_code/cli/_paths.py +88 -0
  5. praisonai_code/cli/_warnings.py +58 -0
  6. praisonai_code/cli/app.py +757 -0
  7. praisonai_code/cli/approval_backend.py +272 -0
  8. praisonai_code/cli/branding.py +94 -0
  9. praisonai_code/cli/commands/__init__.py +114 -0
  10. praisonai_code/cli/commands/acp.py +80 -0
  11. praisonai_code/cli/commands/agent.py +116 -0
  12. praisonai_code/cli/commands/agents.py +80 -0
  13. praisonai_code/cli/commands/app.py +139 -0
  14. praisonai_code/cli/commands/attach.py +95 -0
  15. praisonai_code/cli/commands/audit.py +102 -0
  16. praisonai_code/cli/commands/auth.py +508 -0
  17. praisonai_code/cli/commands/batch.py +848 -0
  18. praisonai_code/cli/commands/benchmark.py +286 -0
  19. praisonai_code/cli/commands/browser.py +299 -0
  20. praisonai_code/cli/commands/call.py +45 -0
  21. praisonai_code/cli/commands/chat.py +332 -0
  22. praisonai_code/cli/commands/checkpoint.py +170 -0
  23. praisonai_code/cli/commands/code.py +276 -0
  24. praisonai_code/cli/commands/command.py +114 -0
  25. praisonai_code/cli/commands/commit.py +47 -0
  26. praisonai_code/cli/commands/completion.py +333 -0
  27. praisonai_code/cli/commands/config.py +681 -0
  28. praisonai_code/cli/commands/context.py +414 -0
  29. praisonai_code/cli/commands/daemon.py +203 -0
  30. praisonai_code/cli/commands/debug.py +142 -0
  31. praisonai_code/cli/commands/deploy.py +71 -0
  32. praisonai_code/cli/commands/diag.py +55 -0
  33. praisonai_code/cli/commands/docs.py +1575 -0
  34. praisonai_code/cli/commands/doctor.py +332 -0
  35. praisonai_code/cli/commands/endpoints.py +51 -0
  36. praisonai_code/cli/commands/environment.py +179 -0
  37. praisonai_code/cli/commands/eval.py +131 -0
  38. praisonai_code/cli/commands/examples.py +953 -0
  39. praisonai_code/cli/commands/flow.py +436 -0
  40. praisonai_code/cli/commands/github.py +752 -0
  41. praisonai_code/cli/commands/hooks.py +74 -0
  42. praisonai_code/cli/commands/init.py +174 -0
  43. praisonai_code/cli/commands/knowledge.py +440 -0
  44. praisonai_code/cli/commands/langextract.py +120 -0
  45. praisonai_code/cli/commands/langfuse.py +984 -0
  46. praisonai_code/cli/commands/loop.py +211 -0
  47. praisonai_code/cli/commands/lsp.py +112 -0
  48. praisonai_code/cli/commands/managed.py +659 -0
  49. praisonai_code/cli/commands/mcp.py +763 -0
  50. praisonai_code/cli/commands/memory.py +298 -0
  51. praisonai_code/cli/commands/models.py +264 -0
  52. praisonai_code/cli/commands/n8n.py +326 -0
  53. praisonai_code/cli/commands/obs.py +19 -0
  54. praisonai_code/cli/commands/package.py +76 -0
  55. praisonai_code/cli/commands/paths.py +106 -0
  56. praisonai_code/cli/commands/permissions.py +272 -0
  57. praisonai_code/cli/commands/plugins.py +609 -0
  58. praisonai_code/cli/commands/port.py +530 -0
  59. praisonai_code/cli/commands/profile.py +466 -0
  60. praisonai_code/cli/commands/publish.py +193 -0
  61. praisonai_code/cli/commands/rag.py +913 -0
  62. praisonai_code/cli/commands/realtime.py +52 -0
  63. praisonai_code/cli/commands/recipe.py +684 -0
  64. praisonai_code/cli/commands/registry.py +59 -0
  65. praisonai_code/cli/commands/replay.py +830 -0
  66. praisonai_code/cli/commands/research.py +49 -0
  67. praisonai_code/cli/commands/retrieval.py +377 -0
  68. praisonai_code/cli/commands/rules.py +71 -0
  69. praisonai_code/cli/commands/run.py +1573 -0
  70. praisonai_code/cli/commands/sandbox.py +371 -0
  71. praisonai_code/cli/commands/schedule.py +529 -0
  72. praisonai_code/cli/commands/serve.py +690 -0
  73. praisonai_code/cli/commands/session.py +450 -0
  74. praisonai_code/cli/commands/setup.py +174 -0
  75. praisonai_code/cli/commands/skills.py +545 -0
  76. praisonai_code/cli/commands/standardise.py +711 -0
  77. praisonai_code/cli/commands/templates.py +54 -0
  78. praisonai_code/cli/commands/test.py +558 -0
  79. praisonai_code/cli/commands/todo.py +74 -0
  80. praisonai_code/cli/commands/tools.py +205 -0
  81. praisonai_code/cli/commands/traces.py +145 -0
  82. praisonai_code/cli/commands/tracker.py +852 -0
  83. praisonai_code/cli/commands/train.py +613 -0
  84. praisonai_code/cli/commands/ui.py +172 -0
  85. praisonai_code/cli/commands/up.py +354 -0
  86. praisonai_code/cli/commands/validate.py +291 -0
  87. praisonai_code/cli/commands/version.py +101 -0
  88. praisonai_code/cli/commands/workflow.py +97 -0
  89. praisonai_code/cli/config_loader.py +437 -0
  90. praisonai_code/cli/configuration/__init__.py +27 -0
  91. praisonai_code/cli/configuration/config.schema.json +57 -0
  92. praisonai_code/cli/configuration/credentials.py +446 -0
  93. praisonai_code/cli/configuration/loader.py +364 -0
  94. praisonai_code/cli/configuration/model_resolver.py +161 -0
  95. praisonai_code/cli/configuration/oauth.py +389 -0
  96. praisonai_code/cli/configuration/paths.py +224 -0
  97. praisonai_code/cli/configuration/resolver.py +687 -0
  98. praisonai_code/cli/configuration/schema.py +317 -0
  99. praisonai_code/cli/execution/__init__.py +99 -0
  100. praisonai_code/cli/execution/core.py +208 -0
  101. praisonai_code/cli/execution/profiler.py +898 -0
  102. praisonai_code/cli/execution/request.py +85 -0
  103. praisonai_code/cli/execution/result.py +74 -0
  104. praisonai_code/cli/fallback_schema.py +416 -0
  105. praisonai_code/cli/features/__init__.py +278 -0
  106. praisonai_code/cli/features/_endpoint_registry.py +64 -0
  107. praisonai_code/cli/features/_search_registry.py +43 -0
  108. praisonai_code/cli/features/acp.py +236 -0
  109. praisonai_code/cli/features/action_orchestrator.py +576 -0
  110. praisonai_code/cli/features/agent_scheduler.py +773 -0
  111. praisonai_code/cli/features/agent_tools.py +603 -0
  112. praisonai_code/cli/features/agents.py +397 -0
  113. praisonai_code/cli/features/at_mentions.py +471 -0
  114. praisonai_code/cli/features/audit_cli.py +270 -0
  115. praisonai_code/cli/features/auto_memory.py +182 -0
  116. praisonai_code/cli/features/auto_mode.py +552 -0
  117. praisonai_code/cli/features/autonomy_mode.py +546 -0
  118. praisonai_code/cli/features/background.py +356 -0
  119. praisonai_code/cli/features/base.py +168 -0
  120. praisonai_code/cli/features/benchmark.py +1462 -0
  121. praisonai_code/cli/features/capabilities.py +1326 -0
  122. praisonai_code/cli/features/checkpoints.py +345 -0
  123. praisonai_code/cli/features/cli_profiler.py +335 -0
  124. praisonai_code/cli/features/code_intelligence.py +666 -0
  125. praisonai_code/cli/features/compaction.py +294 -0
  126. praisonai_code/cli/features/compare.py +534 -0
  127. praisonai_code/cli/features/config_hierarchy.py +366 -0
  128. praisonai_code/cli/features/context_manager.py +597 -0
  129. praisonai_code/cli/features/cost_tracker.py +514 -0
  130. praisonai_code/cli/features/csv_test_runner.py +736 -0
  131. praisonai_code/cli/features/custom_definitions.py +790 -0
  132. praisonai_code/cli/features/debug.py +810 -0
  133. praisonai_code/cli/features/deploy.py +605 -0
  134. praisonai_code/cli/features/diag.py +289 -0
  135. praisonai_code/cli/features/display_jsonl.py +173 -0
  136. praisonai_code/cli/features/doctor/__init__.py +63 -0
  137. praisonai_code/cli/features/doctor/checks/__init__.py +29 -0
  138. praisonai_code/cli/features/doctor/checks/acp_checks.py +220 -0
  139. praisonai_code/cli/features/doctor/checks/bot_checks.py +340 -0
  140. praisonai_code/cli/features/doctor/checks/config_checks.py +373 -0
  141. praisonai_code/cli/features/doctor/checks/db_checks.py +366 -0
  142. praisonai_code/cli/features/doctor/checks/env_checks.py +637 -0
  143. praisonai_code/cli/features/doctor/checks/gateway_checks.py +387 -0
  144. praisonai_code/cli/features/doctor/checks/lsp_checks.py +231 -0
  145. praisonai_code/cli/features/doctor/checks/mcp_checks.py +367 -0
  146. praisonai_code/cli/features/doctor/checks/memory_checks.py +268 -0
  147. praisonai_code/cli/features/doctor/checks/network_checks.py +251 -0
  148. praisonai_code/cli/features/doctor/checks/obs_checks.py +328 -0
  149. praisonai_code/cli/features/doctor/checks/packaging_checks.py +422 -0
  150. praisonai_code/cli/features/doctor/checks/performance_checks.py +235 -0
  151. praisonai_code/cli/features/doctor/checks/permissions_checks.py +259 -0
  152. praisonai_code/cli/features/doctor/checks/runtime_checks.py +650 -0
  153. praisonai_code/cli/features/doctor/checks/runtime_migration_checks.py +220 -0
  154. praisonai_code/cli/features/doctor/checks/selftest_checks.py +322 -0
  155. praisonai_code/cli/features/doctor/checks/serve_checks.py +426 -0
  156. praisonai_code/cli/features/doctor/checks/skills_checks.py +327 -0
  157. praisonai_code/cli/features/doctor/checks/tools_checks.py +371 -0
  158. praisonai_code/cli/features/doctor/engine.py +266 -0
  159. praisonai_code/cli/features/doctor/formatters.py +377 -0
  160. praisonai_code/cli/features/doctor/handler.py +564 -0
  161. praisonai_code/cli/features/doctor/models.py +276 -0
  162. praisonai_code/cli/features/doctor/registry.py +239 -0
  163. praisonai_code/cli/features/endpoints.py +1016 -0
  164. praisonai_code/cli/features/eval.py +559 -0
  165. praisonai_code/cli/features/examples.py +707 -0
  166. praisonai_code/cli/features/external_agents.py +231 -0
  167. praisonai_code/cli/features/fast_context.py +410 -0
  168. praisonai_code/cli/features/file_history.py +320 -0
  169. praisonai_code/cli/features/flow_display.py +566 -0
  170. praisonai_code/cli/features/git_attribution.py +159 -0
  171. praisonai_code/cli/features/git_integration.py +651 -0
  172. praisonai_code/cli/features/guardrail.py +171 -0
  173. praisonai_code/cli/features/handoff.py +252 -0
  174. praisonai_code/cli/features/hooks.py +583 -0
  175. praisonai_code/cli/features/hybrid_workflow.py +391 -0
  176. praisonai_code/cli/features/image.py +384 -0
  177. praisonai_code/cli/features/interactive_core_headless.py +450 -0
  178. praisonai_code/cli/features/interactive_runtime.py +600 -0
  179. praisonai_code/cli/features/interactive_test_harness.py +537 -0
  180. praisonai_code/cli/features/interactive_tools.py +428 -0
  181. praisonai_code/cli/features/interactive_tui.py +603 -0
  182. praisonai_code/cli/features/job_workflow.py +906 -0
  183. praisonai_code/cli/features/jobs.py +632 -0
  184. praisonai_code/cli/features/knowledge.py +531 -0
  185. praisonai_code/cli/features/knowledge_cli.py +438 -0
  186. praisonai_code/cli/features/lite.py +244 -0
  187. praisonai_code/cli/features/logs.py +200 -0
  188. praisonai_code/cli/features/lsp_cli.py +225 -0
  189. praisonai_code/cli/features/lsp_diagnostics.py +185 -0
  190. praisonai_code/cli/features/mcp.py +344 -0
  191. praisonai_code/cli/features/message_queue.py +587 -0
  192. praisonai_code/cli/features/metrics.py +210 -0
  193. praisonai_code/cli/features/migrate.py +1329 -0
  194. praisonai_code/cli/features/migration_flow.py +463 -0
  195. praisonai_code/cli/features/migration_spec.py +276 -0
  196. praisonai_code/cli/features/n8n.py +703 -0
  197. praisonai_code/cli/features/observability.py +293 -0
  198. praisonai_code/cli/features/ollama.py +361 -0
  199. praisonai_code/cli/features/output_modes.py +155 -0
  200. praisonai_code/cli/features/output_style.py +273 -0
  201. praisonai_code/cli/features/package.py +631 -0
  202. praisonai_code/cli/features/performance.py +308 -0
  203. praisonai_code/cli/features/persistence.py +636 -0
  204. praisonai_code/cli/features/profiler/__init__.py +81 -0
  205. praisonai_code/cli/features/profiler/core.py +558 -0
  206. praisonai_code/cli/features/profiler/optimizations.py +652 -0
  207. praisonai_code/cli/features/profiler/suite.py +386 -0
  208. praisonai_code/cli/features/queue/__init__.py +73 -0
  209. praisonai_code/cli/features/queue/manager.py +435 -0
  210. praisonai_code/cli/features/queue/models.py +289 -0
  211. praisonai_code/cli/features/queue/persistence.py +564 -0
  212. praisonai_code/cli/features/queue/scheduler.py +529 -0
  213. praisonai_code/cli/features/queue/worker.py +400 -0
  214. praisonai_code/cli/features/recipe.py +2187 -0
  215. praisonai_code/cli/features/recipe_creator.py +996 -0
  216. praisonai_code/cli/features/recipe_optimizer.py +1364 -0
  217. praisonai_code/cli/features/recipe_prompts.py +226 -0
  218. praisonai_code/cli/features/registry.py +229 -0
  219. praisonai_code/cli/features/repo_map.py +860 -0
  220. praisonai_code/cli/features/router.py +466 -0
  221. praisonai_code/cli/features/safe_shell.py +427 -0
  222. praisonai_code/cli/features/sandbox_cli.py +283 -0
  223. praisonai_code/cli/features/sandbox_executor.py +536 -0
  224. praisonai_code/cli/features/sdk_knowledge.py +500 -0
  225. praisonai_code/cli/features/session.py +222 -0
  226. praisonai_code/cli/features/session_checkpoints.py +208 -0
  227. praisonai_code/cli/features/setup/__init__.py +9 -0
  228. praisonai_code/cli/features/setup/handler.py +355 -0
  229. praisonai_code/cli/features/setup/templates.py +62 -0
  230. praisonai_code/cli/features/skills.py +940 -0
  231. praisonai_code/cli/features/slash_commands.py +692 -0
  232. praisonai_code/cli/features/telemetry.py +179 -0
  233. praisonai_code/cli/features/templates.py +1390 -0
  234. praisonai_code/cli/features/thinking.py +343 -0
  235. praisonai_code/cli/features/todo.py +334 -0
  236. praisonai_code/cli/features/tools.py +680 -0
  237. praisonai_code/cli/features/tui/__init__.py +83 -0
  238. praisonai_code/cli/features/tui/app.py +871 -0
  239. praisonai_code/cli/features/tui/cli.py +580 -0
  240. praisonai_code/cli/features/tui/config.py +150 -0
  241. praisonai_code/cli/features/tui/debug.py +526 -0
  242. praisonai_code/cli/features/tui/events.py +99 -0
  243. praisonai_code/cli/features/tui/mock_provider.py +328 -0
  244. praisonai_code/cli/features/tui/orchestrator.py +652 -0
  245. praisonai_code/cli/features/tui/screens/__init__.py +50 -0
  246. praisonai_code/cli/features/tui/screens/help.py +157 -0
  247. praisonai_code/cli/features/tui/screens/main.py +568 -0
  248. praisonai_code/cli/features/tui/screens/queue.py +174 -0
  249. praisonai_code/cli/features/tui/screens/session.py +124 -0
  250. praisonai_code/cli/features/tui/screens/settings.py +148 -0
  251. praisonai_code/cli/features/tui/session_store.py +198 -0
  252. praisonai_code/cli/features/tui/widgets/__init__.py +56 -0
  253. praisonai_code/cli/features/tui/widgets/chat.py +263 -0
  254. praisonai_code/cli/features/tui/widgets/command_popup.py +258 -0
  255. praisonai_code/cli/features/tui/widgets/composer.py +292 -0
  256. praisonai_code/cli/features/tui/widgets/file_popup.py +207 -0
  257. praisonai_code/cli/features/tui/widgets/queue_panel.py +223 -0
  258. praisonai_code/cli/features/tui/widgets/status.py +181 -0
  259. praisonai_code/cli/features/tui/widgets/tool_panel.py +307 -0
  260. praisonai_code/cli/features/wizard.py +289 -0
  261. praisonai_code/cli/features/workflow.py +802 -0
  262. praisonai_code/cli/features/yaml_utils.py +321 -0
  263. praisonai_code/cli/interactive/__init__.py +48 -0
  264. praisonai_code/cli/interactive/async_tui.py +1218 -0
  265. praisonai_code/cli/interactive/config.py +139 -0
  266. praisonai_code/cli/interactive/core.py +618 -0
  267. praisonai_code/cli/interactive/events.py +131 -0
  268. praisonai_code/cli/interactive/frontends/__init__.py +31 -0
  269. praisonai_code/cli/interactive/frontends/rich_frontend.py +462 -0
  270. praisonai_code/cli/interactive/frontends/textual_frontend.py +157 -0
  271. praisonai_code/cli/interactive/praison_io.py +502 -0
  272. praisonai_code/cli/interactive/repl.py +297 -0
  273. praisonai_code/cli/interactive/split_tui.py +456 -0
  274. praisonai_code/cli/interactive/tui_app.py +457 -0
  275. praisonai_code/cli/langfuse_client.py +360 -0
  276. praisonai_code/cli/main.py +7421 -0
  277. praisonai_code/cli/output/__init__.py +25 -0
  278. praisonai_code/cli/output/console.py +456 -0
  279. praisonai_code/cli/output/event_bridge.py +191 -0
  280. praisonai_code/cli/schedule_cli.py +54 -0
  281. praisonai_code/cli/schema_provider.py +23 -0
  282. praisonai_code/cli/session/__init__.py +16 -0
  283. praisonai_code/cli/session/resume.py +148 -0
  284. praisonai_code/cli/session/unified.py +548 -0
  285. praisonai_code/cli/state/__init__.py +31 -0
  286. praisonai_code/cli/state/identifiers.py +161 -0
  287. praisonai_code/cli/state/project_sessions.py +383 -0
  288. praisonai_code/cli/state/sessions.py +390 -0
  289. praisonai_code/cli/ui/__init__.py +160 -0
  290. praisonai_code/cli/ui/config.py +46 -0
  291. praisonai_code/cli/ui/events.py +61 -0
  292. praisonai_code/cli/ui/mg_backend.py +342 -0
  293. praisonai_code/cli/ui/plain.py +133 -0
  294. praisonai_code/cli/ui/rich_backend.py +162 -0
  295. praisonai_code/cli/unified_schema.py +655 -0
  296. praisonai_code/cli/utils/env_utils.py +126 -0
  297. praisonai_code/cli/utils/project.py +131 -0
  298. praisonai_code/cli_backends/__init__.py +73 -0
  299. praisonai_code/cli_backends/claude.py +373 -0
  300. praisonai_code/cli_backends/registry.py +113 -0
  301. praisonai_code/runtime/__init__.py +36 -0
  302. praisonai_code/runtime/__main__.py +81 -0
  303. praisonai_code/runtime/client.py +131 -0
  304. praisonai_code/runtime/descriptor.py +209 -0
  305. praisonai_code/runtime/server.py +356 -0
  306. praisonai_code-0.0.1.dist-info/METADATA +80 -0
  307. praisonai_code-0.0.1.dist-info/RECORD +309 -0
  308. praisonai_code-0.0.1.dist-info/WHEEL +5 -0
  309. praisonai_code-0.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,270 @@
1
+ """
2
+ Security Audit CLI for PraisonAI.
3
+
4
+ Provides security scanning and audit capabilities.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ import logging
11
+ from typing import Dict, Any, List
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ class SecurityAudit:
17
+ """Security audit scanner for PraisonAI projects."""
18
+
19
+ def __init__(self):
20
+ self.findings: List[Dict[str, Any]] = []
21
+
22
+ def scan(self, path: str = ".") -> Dict[str, Any]:
23
+ """Scan a project for security issues.
24
+
25
+ Args:
26
+ path: Path to scan
27
+
28
+ Returns:
29
+ Audit results
30
+ """
31
+ self.findings = []
32
+
33
+ self._check_env_files(path)
34
+ self._check_api_keys_in_code(path)
35
+ self._check_yaml_configs(path)
36
+ self._check_dependencies(path)
37
+ self._check_permissions(path)
38
+
39
+ critical = sum(1 for f in self.findings if f["severity"] == "critical")
40
+ high = sum(1 for f in self.findings if f["severity"] == "high")
41
+ medium = sum(1 for f in self.findings if f["severity"] == "medium")
42
+ low = sum(1 for f in self.findings if f["severity"] == "low")
43
+
44
+ return {
45
+ "path": path,
46
+ "findings": self.findings,
47
+ "summary": {
48
+ "total": len(self.findings),
49
+ "critical": critical,
50
+ "high": high,
51
+ "medium": medium,
52
+ "low": low,
53
+ },
54
+ "passed": critical == 0 and high == 0,
55
+ }
56
+
57
+ def _check_env_files(self, path: str) -> None:
58
+ """Check for exposed .env files."""
59
+ env_files = []
60
+ for root, dirs, files in os.walk(path):
61
+ dirs[:] = [d for d in dirs if not d.startswith(".git")]
62
+ for f in files:
63
+ if f == ".env" or f.endswith(".env"):
64
+ env_files.append(os.path.join(root, f))
65
+
66
+ for env_file in env_files:
67
+ gitignore_path = os.path.join(os.path.dirname(env_file), ".gitignore")
68
+ if os.path.exists(gitignore_path):
69
+ with open(gitignore_path, "r") as f:
70
+ gitignore = f.read()
71
+ if ".env" not in gitignore:
72
+ self.findings.append({
73
+ "type": "exposed_env",
74
+ "severity": "critical",
75
+ "file": env_file,
76
+ "message": ".env file not in .gitignore - secrets may be exposed",
77
+ "fix": "Add '.env' to .gitignore",
78
+ })
79
+ else:
80
+ self.findings.append({
81
+ "type": "missing_gitignore",
82
+ "severity": "high",
83
+ "file": env_file,
84
+ "message": "No .gitignore found - .env file may be committed",
85
+ "fix": "Create .gitignore with '.env' entry",
86
+ })
87
+
88
+ def _check_api_keys_in_code(self, path: str) -> None:
89
+ """Check for hardcoded API keys in code."""
90
+ import re
91
+
92
+ patterns = [
93
+ (r'sk-[a-zA-Z0-9]{48}', "OpenAI API key"),
94
+ (r'sk-ant-[a-zA-Z0-9-]{95}', "Anthropic API key"),
95
+ (r'AIza[a-zA-Z0-9_-]{35}', "Google API key"),
96
+ (r'xoxb-[0-9]+-[0-9]+-[a-zA-Z0-9]+', "Slack bot token"),
97
+ (r'xapp-[0-9]+-[a-zA-Z0-9]+', "Slack app token"),
98
+ ]
99
+
100
+ for root, dirs, files in os.walk(path):
101
+ dirs[:] = [d for d in dirs if not d.startswith(".") and d != "__pycache__"]
102
+ for f in files:
103
+ if f.endswith((".py", ".yaml", ".yml", ".json", ".js", ".ts")):
104
+ file_path = os.path.join(root, f)
105
+ try:
106
+ with open(file_path, "r", encoding="utf-8", errors="ignore") as fp:
107
+ content = fp.read()
108
+
109
+ for pattern, key_type in patterns:
110
+ if re.search(pattern, content):
111
+ self.findings.append({
112
+ "type": "hardcoded_key",
113
+ "severity": "critical",
114
+ "file": file_path,
115
+ "message": f"Possible {key_type} found in code",
116
+ "fix": "Move API key to environment variable",
117
+ })
118
+ except Exception:
119
+ pass
120
+
121
+ def _check_yaml_configs(self, path: str) -> None:
122
+ """Check YAML configurations for security issues."""
123
+ for root, dirs, files in os.walk(path):
124
+ dirs[:] = [d for d in dirs if not d.startswith(".")]
125
+ for f in files:
126
+ if f.endswith((".yaml", ".yml")):
127
+ file_path = os.path.join(root, f)
128
+ try:
129
+ import yaml
130
+ with open(file_path, "r") as fp:
131
+ config = yaml.safe_load(fp)
132
+
133
+ if config and isinstance(config, dict):
134
+ if "api_key" in str(config).lower():
135
+ self.findings.append({
136
+ "type": "key_in_config",
137
+ "severity": "high",
138
+ "file": file_path,
139
+ "message": "API key reference found in YAML config",
140
+ "fix": "Use environment variables instead",
141
+ })
142
+ except Exception:
143
+ pass
144
+
145
+ def _check_dependencies(self, path: str) -> None:
146
+ """Check for known vulnerable dependencies."""
147
+ requirements_files = ["requirements.txt", "pyproject.toml"]
148
+
149
+ for req_file in requirements_files:
150
+ req_path = os.path.join(path, req_file)
151
+ if os.path.exists(req_path):
152
+ self.findings.append({
153
+ "type": "dependency_check",
154
+ "severity": "low",
155
+ "file": req_path,
156
+ "message": "Run 'pip-audit' to check for vulnerable dependencies",
157
+ "fix": "pip install pip-audit && pip-audit",
158
+ })
159
+ break
160
+
161
+ def _check_permissions(self, path: str) -> None:
162
+ """Check file permissions."""
163
+ sensitive_files = [".env", "credentials.json", "service-account.json"]
164
+
165
+ for root, dirs, files in os.walk(path):
166
+ dirs[:] = [d for d in dirs if not d.startswith(".git")]
167
+ for f in files:
168
+ if f in sensitive_files:
169
+ file_path = os.path.join(root, f)
170
+ try:
171
+ mode = os.stat(file_path).st_mode
172
+ if mode & 0o077:
173
+ self.findings.append({
174
+ "type": "file_permissions",
175
+ "severity": "medium",
176
+ "file": file_path,
177
+ "message": "Sensitive file has overly permissive permissions",
178
+ "fix": f"chmod 600 {file_path}",
179
+ })
180
+ except Exception:
181
+ pass
182
+
183
+
184
+ def handle_audit_command(args) -> None:
185
+ """Handle audit CLI command."""
186
+ try:
187
+ from rich.console import Console
188
+ from rich.table import Table
189
+ from rich.panel import Panel
190
+ except ImportError:
191
+ print("Error: Rich library required for audit display")
192
+ return
193
+
194
+ console = Console()
195
+ audit = SecurityAudit()
196
+
197
+ path = getattr(args, "path", ".")
198
+ results = audit.scan(path)
199
+
200
+ console.print(Panel.fit(
201
+ f"[bold]Security Audit Results[/bold]\n"
202
+ f"Path: {results['path']}",
203
+ title="PraisonAI Security Audit",
204
+ ))
205
+ console.print()
206
+
207
+ summary = results["summary"]
208
+ if summary["total"] == 0:
209
+ console.print("[green]✓ No security issues found![/green]")
210
+ else:
211
+ table = Table(title="Summary")
212
+ table.add_column("Severity", style="bold")
213
+ table.add_column("Count", justify="right")
214
+
215
+ if summary["critical"] > 0:
216
+ table.add_row("[red]Critical[/red]", str(summary["critical"]))
217
+ if summary["high"] > 0:
218
+ table.add_row("[orange1]High[/orange1]", str(summary["high"]))
219
+ if summary["medium"] > 0:
220
+ table.add_row("[yellow]Medium[/yellow]", str(summary["medium"]))
221
+ if summary["low"] > 0:
222
+ table.add_row("[blue]Low[/blue]", str(summary["low"]))
223
+
224
+ console.print(table)
225
+ console.print()
226
+
227
+ findings_table = Table(title="Findings")
228
+ findings_table.add_column("Severity")
229
+ findings_table.add_column("Type")
230
+ findings_table.add_column("File")
231
+ findings_table.add_column("Message")
232
+
233
+ severity_colors = {
234
+ "critical": "red",
235
+ "high": "orange1",
236
+ "medium": "yellow",
237
+ "low": "blue",
238
+ }
239
+
240
+ for finding in results["findings"]:
241
+ color = severity_colors.get(finding["severity"], "white")
242
+ findings_table.add_row(
243
+ f"[{color}]{finding['severity'].upper()}[/{color}]",
244
+ finding["type"],
245
+ finding["file"],
246
+ finding["message"],
247
+ )
248
+
249
+ console.print(findings_table)
250
+ console.print()
251
+
252
+ if not results["passed"]:
253
+ console.print("[red]✗ Audit failed - critical/high issues found[/red]")
254
+ else:
255
+ console.print("[yellow]âš  Audit passed with warnings[/yellow]")
256
+
257
+
258
+ def add_audit_parser(subparsers) -> None:
259
+ """Add audit subparser to CLI."""
260
+ audit_parser = subparsers.add_parser(
261
+ "audit",
262
+ help="Run security audit on project",
263
+ )
264
+ audit_parser.add_argument(
265
+ "path",
266
+ nargs="?",
267
+ default=".",
268
+ help="Path to audit (default: current directory)",
269
+ )
270
+ audit_parser.set_defaults(func=handle_audit_command)
@@ -0,0 +1,182 @@
1
+ """
2
+ Auto Memory Handler for CLI.
3
+
4
+ Provides automatic memory extraction and storage.
5
+ Usage: praisonai "Learn about user preferences" --auto-memory
6
+ """
7
+
8
+ from typing import Any, Dict, Tuple
9
+ from .base import FlagHandler
10
+
11
+
12
+ class AutoMemoryHandler(FlagHandler):
13
+ """
14
+ Handler for --auto-memory flag.
15
+
16
+ Automatically extracts and stores important information from conversations.
17
+
18
+ Example:
19
+ praisonai "Learn about user preferences" --auto-memory
20
+ praisonai "Remember this context" --auto-memory --user-id myuser
21
+ """
22
+
23
+ @property
24
+ def feature_name(self) -> str:
25
+ return "auto_memory"
26
+
27
+ @property
28
+ def flag_name(self) -> str:
29
+ return "auto-memory"
30
+
31
+ @property
32
+ def flag_help(self) -> str:
33
+ return "Enable automatic memory extraction and storage"
34
+
35
+ def check_dependencies(self) -> Tuple[bool, str]:
36
+ """Check if AutoMemory is available."""
37
+ try:
38
+ import importlib.util
39
+ if importlib.util.find_spec("praisonaiagents") is not None:
40
+ return True, ""
41
+ return False, "praisonaiagents not installed"
42
+ except ImportError:
43
+ return False, "praisonaiagents not installed. Install with: pip install praisonaiagents"
44
+
45
+ def _get_auto_memory(self, user_id: str = None):
46
+ """Get AutoMemory instance lazily."""
47
+ try:
48
+ from praisonaiagents.memory import AutoMemory, FileMemory
49
+ # AutoMemory requires a FileMemory instance
50
+ memory = FileMemory(user_id=user_id or "default")
51
+ return AutoMemory(memory=memory)
52
+ except ImportError:
53
+ self.print_status(
54
+ "AutoMemory requires praisonaiagents. Install with: pip install praisonaiagents",
55
+ "error"
56
+ )
57
+ return None
58
+
59
+ def apply_to_agent_config(self, config: Dict[str, Any], flag_value: Any) -> Dict[str, Any]:
60
+ """
61
+ Apply auto memory configuration.
62
+
63
+ Args:
64
+ config: Agent configuration dictionary
65
+ flag_value: Boolean or dict with user_id
66
+
67
+ Returns:
68
+ Modified configuration
69
+ """
70
+ if flag_value:
71
+ config['auto_memory'] = True
72
+ if isinstance(flag_value, dict):
73
+ config['auto_memory_user_id'] = flag_value.get('user_id', 'default')
74
+ return config
75
+
76
+ def extract_memories(self, text: str, user_id: str = None, user_message: str = None) -> list:
77
+ """
78
+ Extract and store memories from text.
79
+
80
+ Args:
81
+ text: Assistant response text to extract memories from
82
+ user_id: User ID for memory isolation
83
+ user_message: Original user message (for context)
84
+
85
+ Returns:
86
+ List of extracted memories
87
+ """
88
+ auto_memory = self._get_auto_memory(user_id)
89
+ if not auto_memory:
90
+ return []
91
+
92
+ try:
93
+ # Use process_interaction which extracts AND stores memories
94
+ memories = auto_memory.process_interaction(
95
+ user_message=user_message or text,
96
+ assistant_response=text if user_message else None,
97
+ store=True # Store the memories
98
+ )
99
+ if memories:
100
+ self.print_status(f"🧠 Extracted and stored {len(memories)} memories", "success")
101
+ return memories
102
+ except Exception as e:
103
+ self.log(f"Memory extraction failed: {e}", "error")
104
+
105
+ return []
106
+
107
+ def store_memory(self, content: str, user_id: str = None, importance: float = 0.5) -> bool:
108
+ """
109
+ Store a memory.
110
+
111
+ Args:
112
+ content: Memory content
113
+ user_id: User ID for memory isolation
114
+ importance: Importance score (0-1)
115
+
116
+ Returns:
117
+ True if successful
118
+ """
119
+ auto_memory = self._get_auto_memory(user_id)
120
+ if not auto_memory:
121
+ return False
122
+
123
+ try:
124
+ if hasattr(auto_memory, 'store'):
125
+ auto_memory.store(content, importance=importance)
126
+ elif hasattr(auto_memory, 'add'):
127
+ auto_memory.add(content, importance=importance)
128
+
129
+ self.print_status("✅ Memory stored", "success")
130
+ return True
131
+ except Exception as e:
132
+ self.log(f"Memory storage failed: {e}", "error")
133
+ return False
134
+
135
+ def post_process_result(self, result: Any, flag_value: Any, user_message: str = None) -> Any:
136
+ """
137
+ Post-process result to extract and store memories.
138
+
139
+ Args:
140
+ result: Agent output
141
+ flag_value: Boolean or dict with configuration
142
+ user_message: Original user message for context
143
+
144
+ Returns:
145
+ Original result (memories are stored)
146
+ """
147
+ if not flag_value:
148
+ return result
149
+
150
+ user_id = None
151
+ if isinstance(flag_value, dict):
152
+ user_id = flag_value.get('user_id')
153
+ user_message = flag_value.get('user_message', user_message)
154
+
155
+ # Extract and store memories from result
156
+ text = str(result)
157
+ memories = self.extract_memories(text, user_id, user_message=user_message)
158
+
159
+ if memories:
160
+ self.print_status("\n🧠 Auto-extracted Memories:", "info")
161
+ for mem in memories:
162
+ mem_type = mem.get('type', 'unknown')
163
+ content = mem.get('content', str(mem))[:50]
164
+ self.print_status(f" • {mem_type}: {content}...", "info")
165
+
166
+ return result
167
+
168
+ def execute(self, text: str = None, user_id: str = None, **kwargs) -> Dict[str, Any]:
169
+ """
170
+ Execute auto memory extraction.
171
+
172
+ Args:
173
+ text: Text to process
174
+ user_id: User ID for memory isolation
175
+
176
+ Returns:
177
+ Dictionary of extracted memories
178
+ """
179
+ if not text:
180
+ return {}
181
+
182
+ return self.extract_memories(text, user_id)