attune-ai 2.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 (457) hide show
  1. attune/__init__.py +358 -0
  2. attune/adaptive/__init__.py +13 -0
  3. attune/adaptive/task_complexity.py +127 -0
  4. attune/agent_monitoring.py +414 -0
  5. attune/cache/__init__.py +117 -0
  6. attune/cache/base.py +166 -0
  7. attune/cache/dependency_manager.py +256 -0
  8. attune/cache/hash_only.py +251 -0
  9. attune/cache/hybrid.py +457 -0
  10. attune/cache/storage.py +285 -0
  11. attune/cache_monitor.py +356 -0
  12. attune/cache_stats.py +298 -0
  13. attune/cli/__init__.py +152 -0
  14. attune/cli/__main__.py +12 -0
  15. attune/cli/commands/__init__.py +1 -0
  16. attune/cli/commands/batch.py +264 -0
  17. attune/cli/commands/cache.py +248 -0
  18. attune/cli/commands/help.py +331 -0
  19. attune/cli/commands/info.py +140 -0
  20. attune/cli/commands/inspect.py +436 -0
  21. attune/cli/commands/inspection.py +57 -0
  22. attune/cli/commands/memory.py +48 -0
  23. attune/cli/commands/metrics.py +92 -0
  24. attune/cli/commands/orchestrate.py +184 -0
  25. attune/cli/commands/patterns.py +207 -0
  26. attune/cli/commands/profiling.py +202 -0
  27. attune/cli/commands/provider.py +98 -0
  28. attune/cli/commands/routing.py +285 -0
  29. attune/cli/commands/setup.py +96 -0
  30. attune/cli/commands/status.py +235 -0
  31. attune/cli/commands/sync.py +166 -0
  32. attune/cli/commands/tier.py +121 -0
  33. attune/cli/commands/utilities.py +114 -0
  34. attune/cli/commands/workflow.py +579 -0
  35. attune/cli/core.py +32 -0
  36. attune/cli/parsers/__init__.py +68 -0
  37. attune/cli/parsers/batch.py +118 -0
  38. attune/cli/parsers/cache.py +65 -0
  39. attune/cli/parsers/help.py +41 -0
  40. attune/cli/parsers/info.py +26 -0
  41. attune/cli/parsers/inspect.py +66 -0
  42. attune/cli/parsers/metrics.py +42 -0
  43. attune/cli/parsers/orchestrate.py +61 -0
  44. attune/cli/parsers/patterns.py +54 -0
  45. attune/cli/parsers/provider.py +40 -0
  46. attune/cli/parsers/routing.py +110 -0
  47. attune/cli/parsers/setup.py +42 -0
  48. attune/cli/parsers/status.py +47 -0
  49. attune/cli/parsers/sync.py +31 -0
  50. attune/cli/parsers/tier.py +33 -0
  51. attune/cli/parsers/workflow.py +77 -0
  52. attune/cli/utils/__init__.py +1 -0
  53. attune/cli/utils/data.py +242 -0
  54. attune/cli/utils/helpers.py +68 -0
  55. attune/cli_legacy.py +3957 -0
  56. attune/cli_minimal.py +1159 -0
  57. attune/cli_router.py +437 -0
  58. attune/cli_unified.py +814 -0
  59. attune/config/__init__.py +66 -0
  60. attune/config/xml_config.py +286 -0
  61. attune/config.py +545 -0
  62. attune/coordination.py +870 -0
  63. attune/core.py +1511 -0
  64. attune/core_modules/__init__.py +15 -0
  65. attune/cost_tracker.py +626 -0
  66. attune/dashboard/__init__.py +41 -0
  67. attune/dashboard/app.py +512 -0
  68. attune/dashboard/simple_server.py +435 -0
  69. attune/dashboard/standalone_server.py +547 -0
  70. attune/discovery.py +306 -0
  71. attune/emergence.py +306 -0
  72. attune/exceptions.py +123 -0
  73. attune/feedback_loops.py +373 -0
  74. attune/hot_reload/README.md +473 -0
  75. attune/hot_reload/__init__.py +62 -0
  76. attune/hot_reload/config.py +83 -0
  77. attune/hot_reload/integration.py +229 -0
  78. attune/hot_reload/reloader.py +298 -0
  79. attune/hot_reload/watcher.py +183 -0
  80. attune/hot_reload/websocket.py +177 -0
  81. attune/levels.py +577 -0
  82. attune/leverage_points.py +441 -0
  83. attune/logging_config.py +261 -0
  84. attune/mcp/__init__.py +10 -0
  85. attune/mcp/server.py +506 -0
  86. attune/memory/__init__.py +237 -0
  87. attune/memory/claude_memory.py +469 -0
  88. attune/memory/config.py +224 -0
  89. attune/memory/control_panel.py +1290 -0
  90. attune/memory/control_panel_support.py +145 -0
  91. attune/memory/cross_session.py +845 -0
  92. attune/memory/edges.py +179 -0
  93. attune/memory/encryption.py +159 -0
  94. attune/memory/file_session.py +770 -0
  95. attune/memory/graph.py +570 -0
  96. attune/memory/long_term.py +913 -0
  97. attune/memory/long_term_types.py +99 -0
  98. attune/memory/mixins/__init__.py +25 -0
  99. attune/memory/mixins/backend_init_mixin.py +249 -0
  100. attune/memory/mixins/capabilities_mixin.py +208 -0
  101. attune/memory/mixins/handoff_mixin.py +208 -0
  102. attune/memory/mixins/lifecycle_mixin.py +49 -0
  103. attune/memory/mixins/long_term_mixin.py +352 -0
  104. attune/memory/mixins/promotion_mixin.py +109 -0
  105. attune/memory/mixins/short_term_mixin.py +182 -0
  106. attune/memory/nodes.py +179 -0
  107. attune/memory/redis_bootstrap.py +540 -0
  108. attune/memory/security/__init__.py +31 -0
  109. attune/memory/security/audit_logger.py +932 -0
  110. attune/memory/security/pii_scrubber.py +640 -0
  111. attune/memory/security/secrets_detector.py +678 -0
  112. attune/memory/short_term.py +2192 -0
  113. attune/memory/simple_storage.py +302 -0
  114. attune/memory/storage/__init__.py +15 -0
  115. attune/memory/storage_backend.py +167 -0
  116. attune/memory/summary_index.py +583 -0
  117. attune/memory/types.py +446 -0
  118. attune/memory/unified.py +182 -0
  119. attune/meta_workflows/__init__.py +74 -0
  120. attune/meta_workflows/agent_creator.py +248 -0
  121. attune/meta_workflows/builtin_templates.py +567 -0
  122. attune/meta_workflows/cli_commands/__init__.py +56 -0
  123. attune/meta_workflows/cli_commands/agent_commands.py +321 -0
  124. attune/meta_workflows/cli_commands/analytics_commands.py +442 -0
  125. attune/meta_workflows/cli_commands/config_commands.py +232 -0
  126. attune/meta_workflows/cli_commands/memory_commands.py +182 -0
  127. attune/meta_workflows/cli_commands/template_commands.py +354 -0
  128. attune/meta_workflows/cli_commands/workflow_commands.py +382 -0
  129. attune/meta_workflows/cli_meta_workflows.py +59 -0
  130. attune/meta_workflows/form_engine.py +292 -0
  131. attune/meta_workflows/intent_detector.py +409 -0
  132. attune/meta_workflows/models.py +569 -0
  133. attune/meta_workflows/pattern_learner.py +738 -0
  134. attune/meta_workflows/plan_generator.py +384 -0
  135. attune/meta_workflows/session_context.py +397 -0
  136. attune/meta_workflows/template_registry.py +229 -0
  137. attune/meta_workflows/workflow.py +984 -0
  138. attune/metrics/__init__.py +12 -0
  139. attune/metrics/collector.py +31 -0
  140. attune/metrics/prompt_metrics.py +194 -0
  141. attune/models/__init__.py +172 -0
  142. attune/models/__main__.py +13 -0
  143. attune/models/adaptive_routing.py +437 -0
  144. attune/models/auth_cli.py +444 -0
  145. attune/models/auth_strategy.py +450 -0
  146. attune/models/cli.py +655 -0
  147. attune/models/empathy_executor.py +354 -0
  148. attune/models/executor.py +257 -0
  149. attune/models/fallback.py +762 -0
  150. attune/models/provider_config.py +282 -0
  151. attune/models/registry.py +472 -0
  152. attune/models/tasks.py +359 -0
  153. attune/models/telemetry/__init__.py +71 -0
  154. attune/models/telemetry/analytics.py +594 -0
  155. attune/models/telemetry/backend.py +196 -0
  156. attune/models/telemetry/data_models.py +431 -0
  157. attune/models/telemetry/storage.py +489 -0
  158. attune/models/token_estimator.py +420 -0
  159. attune/models/validation.py +280 -0
  160. attune/monitoring/__init__.py +52 -0
  161. attune/monitoring/alerts.py +946 -0
  162. attune/monitoring/alerts_cli.py +448 -0
  163. attune/monitoring/multi_backend.py +271 -0
  164. attune/monitoring/otel_backend.py +362 -0
  165. attune/optimization/__init__.py +19 -0
  166. attune/optimization/context_optimizer.py +272 -0
  167. attune/orchestration/__init__.py +67 -0
  168. attune/orchestration/agent_templates.py +707 -0
  169. attune/orchestration/config_store.py +499 -0
  170. attune/orchestration/execution_strategies.py +2111 -0
  171. attune/orchestration/meta_orchestrator.py +1168 -0
  172. attune/orchestration/pattern_learner.py +696 -0
  173. attune/orchestration/real_tools.py +931 -0
  174. attune/pattern_cache.py +187 -0
  175. attune/pattern_library.py +542 -0
  176. attune/patterns/debugging/all_patterns.json +81 -0
  177. attune/patterns/debugging/workflow_20260107_1770825e.json +77 -0
  178. attune/patterns/refactoring_memory.json +89 -0
  179. attune/persistence.py +564 -0
  180. attune/platform_utils.py +265 -0
  181. attune/plugins/__init__.py +28 -0
  182. attune/plugins/base.py +361 -0
  183. attune/plugins/registry.py +268 -0
  184. attune/project_index/__init__.py +32 -0
  185. attune/project_index/cli.py +335 -0
  186. attune/project_index/index.py +667 -0
  187. attune/project_index/models.py +504 -0
  188. attune/project_index/reports.py +474 -0
  189. attune/project_index/scanner.py +777 -0
  190. attune/project_index/scanner_parallel.py +291 -0
  191. attune/prompts/__init__.py +61 -0
  192. attune/prompts/config.py +77 -0
  193. attune/prompts/context.py +177 -0
  194. attune/prompts/parser.py +285 -0
  195. attune/prompts/registry.py +313 -0
  196. attune/prompts/templates.py +208 -0
  197. attune/redis_config.py +302 -0
  198. attune/redis_memory.py +799 -0
  199. attune/resilience/__init__.py +56 -0
  200. attune/resilience/circuit_breaker.py +256 -0
  201. attune/resilience/fallback.py +179 -0
  202. attune/resilience/health.py +300 -0
  203. attune/resilience/retry.py +209 -0
  204. attune/resilience/timeout.py +135 -0
  205. attune/routing/__init__.py +43 -0
  206. attune/routing/chain_executor.py +433 -0
  207. attune/routing/classifier.py +217 -0
  208. attune/routing/smart_router.py +234 -0
  209. attune/routing/workflow_registry.py +343 -0
  210. attune/scaffolding/README.md +589 -0
  211. attune/scaffolding/__init__.py +35 -0
  212. attune/scaffolding/__main__.py +14 -0
  213. attune/scaffolding/cli.py +240 -0
  214. attune/scaffolding/templates/base_wizard.py.jinja2 +121 -0
  215. attune/scaffolding/templates/coach_wizard.py.jinja2 +321 -0
  216. attune/scaffolding/templates/domain_wizard.py.jinja2 +408 -0
  217. attune/scaffolding/templates/linear_flow_wizard.py.jinja2 +203 -0
  218. attune/socratic/__init__.py +256 -0
  219. attune/socratic/ab_testing.py +958 -0
  220. attune/socratic/blueprint.py +533 -0
  221. attune/socratic/cli.py +703 -0
  222. attune/socratic/collaboration.py +1114 -0
  223. attune/socratic/domain_templates.py +924 -0
  224. attune/socratic/embeddings.py +738 -0
  225. attune/socratic/engine.py +794 -0
  226. attune/socratic/explainer.py +682 -0
  227. attune/socratic/feedback.py +772 -0
  228. attune/socratic/forms.py +629 -0
  229. attune/socratic/generator.py +732 -0
  230. attune/socratic/llm_analyzer.py +637 -0
  231. attune/socratic/mcp_server.py +702 -0
  232. attune/socratic/session.py +312 -0
  233. attune/socratic/storage.py +667 -0
  234. attune/socratic/success.py +730 -0
  235. attune/socratic/visual_editor.py +860 -0
  236. attune/socratic/web_ui.py +958 -0
  237. attune/telemetry/__init__.py +39 -0
  238. attune/telemetry/agent_coordination.py +475 -0
  239. attune/telemetry/agent_tracking.py +367 -0
  240. attune/telemetry/approval_gates.py +545 -0
  241. attune/telemetry/cli.py +1231 -0
  242. attune/telemetry/commands/__init__.py +14 -0
  243. attune/telemetry/commands/dashboard_commands.py +696 -0
  244. attune/telemetry/event_streaming.py +409 -0
  245. attune/telemetry/feedback_loop.py +567 -0
  246. attune/telemetry/usage_tracker.py +591 -0
  247. attune/templates.py +754 -0
  248. attune/test_generator/__init__.py +38 -0
  249. attune/test_generator/__main__.py +14 -0
  250. attune/test_generator/cli.py +234 -0
  251. attune/test_generator/generator.py +355 -0
  252. attune/test_generator/risk_analyzer.py +216 -0
  253. attune/test_generator/templates/unit_test.py.jinja2 +272 -0
  254. attune/tier_recommender.py +384 -0
  255. attune/tools.py +183 -0
  256. attune/trust/__init__.py +28 -0
  257. attune/trust/circuit_breaker.py +579 -0
  258. attune/trust_building.py +527 -0
  259. attune/validation/__init__.py +19 -0
  260. attune/validation/xml_validator.py +281 -0
  261. attune/vscode_bridge.py +173 -0
  262. attune/workflow_commands.py +780 -0
  263. attune/workflow_patterns/__init__.py +33 -0
  264. attune/workflow_patterns/behavior.py +249 -0
  265. attune/workflow_patterns/core.py +76 -0
  266. attune/workflow_patterns/output.py +99 -0
  267. attune/workflow_patterns/registry.py +255 -0
  268. attune/workflow_patterns/structural.py +288 -0
  269. attune/workflows/__init__.py +539 -0
  270. attune/workflows/autonomous_test_gen.py +1268 -0
  271. attune/workflows/base.py +2667 -0
  272. attune/workflows/batch_processing.py +342 -0
  273. attune/workflows/bug_predict.py +1084 -0
  274. attune/workflows/builder.py +273 -0
  275. attune/workflows/caching.py +253 -0
  276. attune/workflows/code_review.py +1048 -0
  277. attune/workflows/code_review_adapters.py +312 -0
  278. attune/workflows/code_review_pipeline.py +722 -0
  279. attune/workflows/config.py +645 -0
  280. attune/workflows/dependency_check.py +644 -0
  281. attune/workflows/document_gen/__init__.py +25 -0
  282. attune/workflows/document_gen/config.py +30 -0
  283. attune/workflows/document_gen/report_formatter.py +162 -0
  284. attune/workflows/document_gen/workflow.py +1426 -0
  285. attune/workflows/document_manager.py +216 -0
  286. attune/workflows/document_manager_README.md +134 -0
  287. attune/workflows/documentation_orchestrator.py +1205 -0
  288. attune/workflows/history.py +510 -0
  289. attune/workflows/keyboard_shortcuts/__init__.py +39 -0
  290. attune/workflows/keyboard_shortcuts/generators.py +391 -0
  291. attune/workflows/keyboard_shortcuts/parsers.py +416 -0
  292. attune/workflows/keyboard_shortcuts/prompts.py +295 -0
  293. attune/workflows/keyboard_shortcuts/schema.py +193 -0
  294. attune/workflows/keyboard_shortcuts/workflow.py +509 -0
  295. attune/workflows/llm_base.py +363 -0
  296. attune/workflows/manage_docs.py +87 -0
  297. attune/workflows/manage_docs_README.md +134 -0
  298. attune/workflows/manage_documentation.py +821 -0
  299. attune/workflows/new_sample_workflow1.py +149 -0
  300. attune/workflows/new_sample_workflow1_README.md +150 -0
  301. attune/workflows/orchestrated_health_check.py +849 -0
  302. attune/workflows/orchestrated_release_prep.py +600 -0
  303. attune/workflows/output.py +413 -0
  304. attune/workflows/perf_audit.py +863 -0
  305. attune/workflows/pr_review.py +762 -0
  306. attune/workflows/progress.py +785 -0
  307. attune/workflows/progress_server.py +322 -0
  308. attune/workflows/progressive/README 2.md +454 -0
  309. attune/workflows/progressive/README.md +454 -0
  310. attune/workflows/progressive/__init__.py +82 -0
  311. attune/workflows/progressive/cli.py +219 -0
  312. attune/workflows/progressive/core.py +488 -0
  313. attune/workflows/progressive/orchestrator.py +723 -0
  314. attune/workflows/progressive/reports.py +520 -0
  315. attune/workflows/progressive/telemetry.py +274 -0
  316. attune/workflows/progressive/test_gen.py +495 -0
  317. attune/workflows/progressive/workflow.py +589 -0
  318. attune/workflows/refactor_plan.py +694 -0
  319. attune/workflows/release_prep.py +895 -0
  320. attune/workflows/release_prep_crew.py +969 -0
  321. attune/workflows/research_synthesis.py +404 -0
  322. attune/workflows/routing.py +168 -0
  323. attune/workflows/secure_release.py +593 -0
  324. attune/workflows/security_adapters.py +297 -0
  325. attune/workflows/security_audit.py +1329 -0
  326. attune/workflows/security_audit_phase3.py +355 -0
  327. attune/workflows/seo_optimization.py +633 -0
  328. attune/workflows/step_config.py +234 -0
  329. attune/workflows/telemetry_mixin.py +269 -0
  330. attune/workflows/test5.py +125 -0
  331. attune/workflows/test5_README.md +158 -0
  332. attune/workflows/test_coverage_boost_crew.py +849 -0
  333. attune/workflows/test_gen/__init__.py +52 -0
  334. attune/workflows/test_gen/ast_analyzer.py +249 -0
  335. attune/workflows/test_gen/config.py +88 -0
  336. attune/workflows/test_gen/data_models.py +38 -0
  337. attune/workflows/test_gen/report_formatter.py +289 -0
  338. attune/workflows/test_gen/test_templates.py +381 -0
  339. attune/workflows/test_gen/workflow.py +655 -0
  340. attune/workflows/test_gen.py +54 -0
  341. attune/workflows/test_gen_behavioral.py +477 -0
  342. attune/workflows/test_gen_parallel.py +341 -0
  343. attune/workflows/test_lifecycle.py +526 -0
  344. attune/workflows/test_maintenance.py +627 -0
  345. attune/workflows/test_maintenance_cli.py +590 -0
  346. attune/workflows/test_maintenance_crew.py +840 -0
  347. attune/workflows/test_runner.py +622 -0
  348. attune/workflows/tier_tracking.py +531 -0
  349. attune/workflows/xml_enhanced_crew.py +285 -0
  350. attune_ai-2.0.0.dist-info/METADATA +1026 -0
  351. attune_ai-2.0.0.dist-info/RECORD +457 -0
  352. attune_ai-2.0.0.dist-info/WHEEL +5 -0
  353. attune_ai-2.0.0.dist-info/entry_points.txt +26 -0
  354. attune_ai-2.0.0.dist-info/licenses/LICENSE +201 -0
  355. attune_ai-2.0.0.dist-info/licenses/LICENSE_CHANGE_ANNOUNCEMENT.md +101 -0
  356. attune_ai-2.0.0.dist-info/top_level.txt +5 -0
  357. attune_healthcare/__init__.py +13 -0
  358. attune_healthcare/monitors/__init__.py +9 -0
  359. attune_healthcare/monitors/clinical_protocol_monitor.py +315 -0
  360. attune_healthcare/monitors/monitoring/__init__.py +44 -0
  361. attune_healthcare/monitors/monitoring/protocol_checker.py +300 -0
  362. attune_healthcare/monitors/monitoring/protocol_loader.py +214 -0
  363. attune_healthcare/monitors/monitoring/sensor_parsers.py +306 -0
  364. attune_healthcare/monitors/monitoring/trajectory_analyzer.py +389 -0
  365. attune_llm/README.md +553 -0
  366. attune_llm/__init__.py +28 -0
  367. attune_llm/agent_factory/__init__.py +53 -0
  368. attune_llm/agent_factory/adapters/__init__.py +85 -0
  369. attune_llm/agent_factory/adapters/autogen_adapter.py +312 -0
  370. attune_llm/agent_factory/adapters/crewai_adapter.py +483 -0
  371. attune_llm/agent_factory/adapters/haystack_adapter.py +298 -0
  372. attune_llm/agent_factory/adapters/langchain_adapter.py +362 -0
  373. attune_llm/agent_factory/adapters/langgraph_adapter.py +333 -0
  374. attune_llm/agent_factory/adapters/native.py +228 -0
  375. attune_llm/agent_factory/adapters/wizard_adapter.py +423 -0
  376. attune_llm/agent_factory/base.py +305 -0
  377. attune_llm/agent_factory/crews/__init__.py +67 -0
  378. attune_llm/agent_factory/crews/code_review.py +1113 -0
  379. attune_llm/agent_factory/crews/health_check.py +1262 -0
  380. attune_llm/agent_factory/crews/refactoring.py +1128 -0
  381. attune_llm/agent_factory/crews/security_audit.py +1018 -0
  382. attune_llm/agent_factory/decorators.py +287 -0
  383. attune_llm/agent_factory/factory.py +558 -0
  384. attune_llm/agent_factory/framework.py +193 -0
  385. attune_llm/agent_factory/memory_integration.py +328 -0
  386. attune_llm/agent_factory/resilient.py +320 -0
  387. attune_llm/agents_md/__init__.py +22 -0
  388. attune_llm/agents_md/loader.py +218 -0
  389. attune_llm/agents_md/parser.py +271 -0
  390. attune_llm/agents_md/registry.py +307 -0
  391. attune_llm/claude_memory.py +466 -0
  392. attune_llm/cli/__init__.py +8 -0
  393. attune_llm/cli/sync_claude.py +487 -0
  394. attune_llm/code_health.py +1313 -0
  395. attune_llm/commands/__init__.py +51 -0
  396. attune_llm/commands/context.py +375 -0
  397. attune_llm/commands/loader.py +301 -0
  398. attune_llm/commands/models.py +231 -0
  399. attune_llm/commands/parser.py +371 -0
  400. attune_llm/commands/registry.py +429 -0
  401. attune_llm/config/__init__.py +29 -0
  402. attune_llm/config/unified.py +291 -0
  403. attune_llm/context/__init__.py +22 -0
  404. attune_llm/context/compaction.py +455 -0
  405. attune_llm/context/manager.py +434 -0
  406. attune_llm/contextual_patterns.py +361 -0
  407. attune_llm/core.py +907 -0
  408. attune_llm/git_pattern_extractor.py +435 -0
  409. attune_llm/hooks/__init__.py +24 -0
  410. attune_llm/hooks/config.py +306 -0
  411. attune_llm/hooks/executor.py +289 -0
  412. attune_llm/hooks/registry.py +302 -0
  413. attune_llm/hooks/scripts/__init__.py +39 -0
  414. attune_llm/hooks/scripts/evaluate_session.py +201 -0
  415. attune_llm/hooks/scripts/first_time_init.py +285 -0
  416. attune_llm/hooks/scripts/pre_compact.py +207 -0
  417. attune_llm/hooks/scripts/session_end.py +183 -0
  418. attune_llm/hooks/scripts/session_start.py +163 -0
  419. attune_llm/hooks/scripts/suggest_compact.py +225 -0
  420. attune_llm/learning/__init__.py +30 -0
  421. attune_llm/learning/evaluator.py +438 -0
  422. attune_llm/learning/extractor.py +514 -0
  423. attune_llm/learning/storage.py +560 -0
  424. attune_llm/levels.py +227 -0
  425. attune_llm/pattern_confidence.py +414 -0
  426. attune_llm/pattern_resolver.py +272 -0
  427. attune_llm/pattern_summary.py +350 -0
  428. attune_llm/providers.py +967 -0
  429. attune_llm/routing/__init__.py +32 -0
  430. attune_llm/routing/model_router.py +362 -0
  431. attune_llm/security/IMPLEMENTATION_SUMMARY.md +413 -0
  432. attune_llm/security/PHASE2_COMPLETE.md +384 -0
  433. attune_llm/security/PHASE2_SECRETS_DETECTOR_COMPLETE.md +271 -0
  434. attune_llm/security/QUICK_REFERENCE.md +316 -0
  435. attune_llm/security/README.md +262 -0
  436. attune_llm/security/__init__.py +62 -0
  437. attune_llm/security/audit_logger.py +929 -0
  438. attune_llm/security/audit_logger_example.py +152 -0
  439. attune_llm/security/pii_scrubber.py +640 -0
  440. attune_llm/security/secrets_detector.py +678 -0
  441. attune_llm/security/secrets_detector_example.py +304 -0
  442. attune_llm/security/secure_memdocs.py +1192 -0
  443. attune_llm/security/secure_memdocs_example.py +278 -0
  444. attune_llm/session_status.py +745 -0
  445. attune_llm/state.py +246 -0
  446. attune_llm/utils/__init__.py +5 -0
  447. attune_llm/utils/tokens.py +349 -0
  448. attune_software/SOFTWARE_PLUGIN_README.md +57 -0
  449. attune_software/__init__.py +13 -0
  450. attune_software/cli/__init__.py +120 -0
  451. attune_software/cli/inspect.py +362 -0
  452. attune_software/cli.py +574 -0
  453. attune_software/plugin.py +188 -0
  454. workflow_scaffolding/__init__.py +11 -0
  455. workflow_scaffolding/__main__.py +12 -0
  456. workflow_scaffolding/cli.py +206 -0
  457. workflow_scaffolding/generator.py +265 -0
@@ -0,0 +1,593 @@
1
+ """Secure Release Pipeline
2
+
3
+ A comprehensive security pipeline that composes multiple security workflows
4
+ for maximum coverage before release approval.
5
+
6
+ Orchestrates:
7
+ 1. SecurityAuditCrew (optional, parallel) - 5-agent multi-agent security crew
8
+ 2. SecurityAuditWorkflow - OWASP-focused vulnerability scanning
9
+ 3. CodeReviewWorkflow - Security-aware code review (optional)
10
+ 4. ReleasePreparationWorkflow - Pre-release quality gate
11
+
12
+ Copyright 2025 Smart-AI-Memory
13
+ Licensed under Fair Source License 0.9
14
+ """
15
+
16
+ import asyncio
17
+ import logging
18
+ from dataclasses import dataclass, field
19
+ from datetime import datetime
20
+ from typing import Any
21
+
22
+ from .base import WorkflowResult
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ @dataclass
28
+ class SecureReleaseResult:
29
+ """Result from SecureReleasePipeline execution."""
30
+
31
+ success: bool
32
+ go_no_go: str # "GO", "NO_GO", "CONDITIONAL"
33
+
34
+ # Individual workflow results
35
+ crew_report: dict | None = None
36
+ security_audit: WorkflowResult | None = None
37
+ code_review: WorkflowResult | None = None
38
+ release_prep: WorkflowResult | None = None
39
+
40
+ # Unified metrics
41
+ combined_risk_score: float = 0.0
42
+ total_findings: int = 0
43
+ critical_count: int = 0
44
+ high_count: int = 0
45
+
46
+ # Cost tracking
47
+ total_cost: float = 0.0
48
+ total_duration_ms: int = 0
49
+
50
+ # Recommendations
51
+ blockers: list[str] = field(default_factory=list)
52
+ warnings: list[str] = field(default_factory=list)
53
+ recommendations: list[str] = field(default_factory=list)
54
+
55
+ # Metadata
56
+ mode: str = "full"
57
+ crew_enabled: bool = False
58
+
59
+ def to_dict(self) -> dict:
60
+ """Convert result to dictionary."""
61
+ return {
62
+ "success": self.success,
63
+ "go_no_go": self.go_no_go,
64
+ "combined_risk_score": self.combined_risk_score,
65
+ "total_findings": self.total_findings,
66
+ "critical_count": self.critical_count,
67
+ "high_count": self.high_count,
68
+ "total_cost": self.total_cost,
69
+ "total_duration_ms": self.total_duration_ms,
70
+ "blockers": self.blockers,
71
+ "warnings": self.warnings,
72
+ "recommendations": self.recommendations,
73
+ "mode": self.mode,
74
+ "crew_enabled": self.crew_enabled,
75
+ }
76
+
77
+ @property
78
+ def formatted_report(self) -> str:
79
+ """Generate human-readable report."""
80
+ return format_secure_release_report(self)
81
+
82
+
83
+ class SecureReleasePipeline:
84
+ """Comprehensive security pipeline for release preparation.
85
+
86
+ This pipeline composes multiple security workflows to provide
87
+ maximum coverage before release approval.
88
+
89
+ Execution modes:
90
+ - "full": Run all workflows (SecurityAuditCrew + all workflows) [DEFAULT]
91
+ - "standard": Skip crew, run all workflows (fallback when crew unavailable)
92
+
93
+ Note: For quick release checks without full security audit, use the
94
+ ReleasePreparationWorkflow directly instead.
95
+
96
+ Usage:
97
+ pipeline = SecureReleasePipeline(mode="full")
98
+ result = await pipeline.execute(
99
+ path="./src",
100
+ diff="...",
101
+ files_changed=[...]
102
+ )
103
+
104
+ if result.go_no_go == "GO":
105
+ print("Ready for release!")
106
+ else:
107
+ for blocker in result.blockers:
108
+ print(f"BLOCKER: {blocker}")
109
+ """
110
+
111
+ name = "secure-release"
112
+ description = "Comprehensive security pipeline composing multiple workflows"
113
+
114
+ def __init__(
115
+ self,
116
+ mode: str = "full", # "full" or "standard"
117
+ use_crew: bool | None = None, # Override mode's crew setting
118
+ parallel_crew: bool = True, # Run crew in parallel with first workflow
119
+ crew_config: dict | None = None,
120
+ **kwargs: Any,
121
+ ):
122
+ """Initialize secure release pipeline.
123
+
124
+ Args:
125
+ mode: Execution mode - "full" (with crew, DEFAULT) or "standard" (skip crew)
126
+ use_crew: Override crew setting (None uses mode default: full=True, standard=False)
127
+ parallel_crew: Run SecurityAuditCrew in parallel with first workflow
128
+ crew_config: Configuration for SecurityAuditCrew
129
+ **kwargs: Additional arguments passed to child workflows
130
+
131
+ """
132
+ # Validate mode
133
+ if mode not in ("full", "standard"):
134
+ raise ValueError(f"Invalid mode '{mode}'. Must be 'full' or 'standard'.")
135
+
136
+ self.mode = mode
137
+ self.use_crew = use_crew if use_crew is not None else (mode == "full")
138
+ self.parallel_crew = parallel_crew
139
+ self.crew_config = crew_config or {}
140
+ self.kwargs = kwargs
141
+
142
+ async def execute(
143
+ self,
144
+ path: str = ".",
145
+ diff: str = "",
146
+ files_changed: list[str] | None = None,
147
+ since: str = "1 week ago",
148
+ **kwargs: Any,
149
+ ) -> SecureReleaseResult:
150
+ """Execute the secure release pipeline.
151
+
152
+ Args:
153
+ path: Path to codebase to analyze
154
+ diff: Git diff for code review (optional)
155
+ files_changed: List of changed files (optional)
156
+ since: Period for changelog generation
157
+ **kwargs: Additional arguments
158
+
159
+ Returns:
160
+ SecureReleaseResult with combined analysis
161
+
162
+ """
163
+ try:
164
+ from .security_adapters import (
165
+ _check_crew_available,
166
+ _get_crew_audit,
167
+ crew_report_to_workflow_format,
168
+ )
169
+
170
+ adapters_available = True
171
+ except ImportError:
172
+ adapters_available = False
173
+ _check_crew_available = lambda: False
174
+ _get_crew_audit = None
175
+ crew_report_to_workflow_format = None
176
+
177
+ started_at = datetime.now()
178
+
179
+ crew_report = None
180
+ security_result = None
181
+ code_review_result = None
182
+ release_result = None
183
+
184
+ total_cost = 0.0
185
+ blockers: list[str] = []
186
+ warnings: list[str] = []
187
+ recommendations: list[str] = []
188
+
189
+ try:
190
+ # Step 1: SecurityAuditCrew (parallel or first)
191
+ crew_task = None
192
+ crew_enabled = self.use_crew and adapters_available and _check_crew_available()
193
+
194
+ if crew_enabled:
195
+ if self.parallel_crew:
196
+ # Start crew in parallel
197
+ crew_task = asyncio.create_task(_get_crew_audit(path, self.crew_config))
198
+ else:
199
+ # Run crew first, then proceed
200
+ crew_report_obj = await _get_crew_audit(path, self.crew_config)
201
+ if crew_report_obj:
202
+ crew_report = crew_report_to_workflow_format(crew_report_obj)
203
+
204
+ # Step 2: SecurityAuditWorkflow
205
+ from .security_audit import SecurityAuditWorkflow
206
+
207
+ security_workflow = SecurityAuditWorkflow(**self.kwargs)
208
+ security_result = await security_workflow.execute(path=path)
209
+ total_cost += security_result.cost_report.total_cost
210
+
211
+ # Collect crew results if running in parallel
212
+ if crew_task:
213
+ try:
214
+ crew_report_obj = await asyncio.wait_for(crew_task, timeout=300.0)
215
+ if crew_report_obj:
216
+ crew_report = crew_report_to_workflow_format(crew_report_obj)
217
+ except asyncio.TimeoutError:
218
+ logger.warning("SecurityAuditCrew timed out")
219
+ warnings.append("SecurityAuditCrew timed out - results not included")
220
+
221
+ # Step 3: CodeReviewWorkflow (if diff provided)
222
+ if diff:
223
+ from .code_review import CodeReviewWorkflow
224
+
225
+ code_workflow = CodeReviewWorkflow(**self.kwargs)
226
+
227
+ # Pass crew findings as external audit if available
228
+ code_input: dict = {
229
+ "diff": diff,
230
+ "files_changed": files_changed or [],
231
+ }
232
+ if crew_report:
233
+ code_input["external_audit_results"] = crew_report
234
+
235
+ code_review_result = await code_workflow.execute(**code_input)
236
+ total_cost += code_review_result.cost_report.total_cost
237
+
238
+ # Step 4: ReleasePreparationWorkflow
239
+ from .release_prep import ReleasePreparationWorkflow
240
+
241
+ release_workflow = ReleasePreparationWorkflow(**self.kwargs)
242
+ release_result = await release_workflow.execute(path=path, since=since)
243
+ total_cost += release_result.cost_report.total_cost
244
+
245
+ # Aggregate results
246
+ combined_risk_score = self._calculate_combined_risk(
247
+ crew_report,
248
+ security_result,
249
+ code_review_result,
250
+ release_result,
251
+ )
252
+
253
+ findings = self._aggregate_findings(crew_report, security_result, code_review_result)
254
+
255
+ # Determine go/no-go
256
+ go_no_go = self._determine_go_no_go(combined_risk_score, findings, release_result)
257
+
258
+ blockers, warnings, recommendations = self._generate_recommendations(
259
+ crew_report,
260
+ security_result,
261
+ code_review_result,
262
+ release_result,
263
+ )
264
+
265
+ except Exception as e:
266
+ logger.error(f"Secure release pipeline failed: {e}")
267
+ blockers.append(f"Pipeline failed: {e!s}")
268
+ go_no_go = "NO_GO"
269
+ combined_risk_score = 100.0
270
+ findings = {"critical": 0, "high": 0, "total": 0}
271
+
272
+ completed_at = datetime.now()
273
+ duration_ms = int((completed_at - started_at).total_seconds() * 1000)
274
+
275
+ return SecureReleaseResult(
276
+ success=go_no_go != "NO_GO",
277
+ go_no_go=go_no_go,
278
+ crew_report=crew_report,
279
+ security_audit=security_result,
280
+ code_review=code_review_result,
281
+ release_prep=release_result,
282
+ combined_risk_score=combined_risk_score,
283
+ total_findings=findings.get("total", 0),
284
+ critical_count=findings.get("critical", 0),
285
+ high_count=findings.get("high", 0),
286
+ total_cost=total_cost,
287
+ total_duration_ms=duration_ms,
288
+ blockers=blockers,
289
+ warnings=warnings,
290
+ recommendations=recommendations,
291
+ mode=self.mode,
292
+ crew_enabled=crew_report is not None,
293
+ )
294
+
295
+ def _calculate_combined_risk(
296
+ self,
297
+ crew_report: dict | None,
298
+ security_result: WorkflowResult | None,
299
+ code_review_result: WorkflowResult | None,
300
+ release_result: WorkflowResult | None,
301
+ ) -> float:
302
+ """Calculate combined risk score from all sources."""
303
+ scores = []
304
+ weights = []
305
+
306
+ if crew_report:
307
+ scores.append(crew_report.get("risk_score", 0))
308
+ weights.append(1.5) # Crew gets higher weight
309
+
310
+ if security_result and security_result.final_output:
311
+ assessment = security_result.final_output.get("assessment", {})
312
+ scores.append(assessment.get("risk_score", 0))
313
+ weights.append(1.0)
314
+
315
+ if code_review_result and code_review_result.final_output:
316
+ security_score = code_review_result.final_output.get("security_score", 90)
317
+ # Convert to risk (100 - security_score)
318
+ scores.append(100 - security_score)
319
+ weights.append(0.8)
320
+
321
+ if not scores:
322
+ return 0.0
323
+
324
+ weighted_sum = sum(s * w for s, w in zip(scores, weights, strict=False))
325
+ return float(min(100.0, weighted_sum / sum(weights)))
326
+
327
+ def _aggregate_findings(
328
+ self,
329
+ crew_report: dict | None,
330
+ security_result: WorkflowResult | None,
331
+ code_review_result: WorkflowResult | None,
332
+ ) -> dict:
333
+ """Aggregate findings from all sources."""
334
+ critical = 0
335
+ high = 0
336
+ total = 0
337
+
338
+ if crew_report:
339
+ assessment = crew_report.get("assessment", {})
340
+ critical += len(assessment.get("critical_findings", []))
341
+ high += len(assessment.get("high_findings", []))
342
+ total += crew_report.get("finding_count", 0)
343
+
344
+ if security_result and security_result.final_output:
345
+ assessment = security_result.final_output.get("assessment", {})
346
+ severity = assessment.get("severity_breakdown", {})
347
+ critical = max(critical, severity.get("critical", 0))
348
+ high = max(high, severity.get("high", 0))
349
+ total = max(
350
+ total,
351
+ sum(severity.values()) if severity else 0,
352
+ )
353
+
354
+ if code_review_result and code_review_result.final_output:
355
+ if code_review_result.final_output.get("has_critical_issues"):
356
+ critical = max(critical, 1)
357
+
358
+ return {"critical": critical, "high": high, "total": total}
359
+
360
+ def _determine_go_no_go(
361
+ self,
362
+ risk_score: float,
363
+ findings: dict,
364
+ release_result: WorkflowResult | None,
365
+ ) -> str:
366
+ """Determine go/no-go decision."""
367
+ # Critical findings = immediate NO_GO
368
+ if findings.get("critical", 0) > 0:
369
+ return "NO_GO"
370
+
371
+ # Very high risk = NO_GO
372
+ if risk_score >= 75:
373
+ return "NO_GO"
374
+
375
+ # High findings or elevated risk = CONDITIONAL
376
+ if findings.get("high", 0) > 3 or risk_score >= 50:
377
+ return "CONDITIONAL"
378
+
379
+ # Release workflow not approved = CONDITIONAL
380
+ if release_result and release_result.final_output:
381
+ if not release_result.final_output.get("approved", True):
382
+ return "CONDITIONAL"
383
+
384
+ return "GO"
385
+
386
+ def _generate_recommendations(
387
+ self,
388
+ crew_report: dict | None,
389
+ security_result: WorkflowResult | None,
390
+ code_review_result: WorkflowResult | None,
391
+ release_result: WorkflowResult | None,
392
+ ) -> tuple[list[str], list[str], list[str]]:
393
+ """Generate blockers, warnings, and recommendations."""
394
+ blockers = []
395
+ warnings = []
396
+ recommendations = []
397
+
398
+ # Crew findings
399
+ if crew_report:
400
+ critical = crew_report.get("assessment", {}).get("critical_findings", [])
401
+ for f in critical:
402
+ blockers.append(f"Critical: {f.get('title', 'Unknown issue')}")
403
+
404
+ high = crew_report.get("assessment", {}).get("high_findings", [])
405
+ for f in high[:3]: # Top 3
406
+ warnings.append(f"High: {f.get('title', 'Unknown issue')}")
407
+
408
+ # Security audit findings
409
+ if security_result and security_result.final_output:
410
+ assessment = security_result.final_output.get("assessment", {})
411
+ if assessment.get("risk_level") == "critical":
412
+ blockers.append("Security audit identified critical risk level")
413
+ elif assessment.get("risk_level") == "high":
414
+ warnings.append("Security audit identified high risk level")
415
+
416
+ # Code review verdict
417
+ if code_review_result and code_review_result.final_output:
418
+ verdict = code_review_result.final_output.get("verdict", "")
419
+ if verdict == "reject":
420
+ blockers.append("Code review: Changes rejected")
421
+ elif verdict == "request_changes":
422
+ warnings.append("Code review: Changes requested")
423
+
424
+ # Release prep blockers
425
+ if release_result and release_result.final_output:
426
+ for b in release_result.final_output.get("blockers", []):
427
+ blockers.append(f"Release: {b}")
428
+ for w in release_result.final_output.get("warnings", []):
429
+ warnings.append(f"Release: {w}")
430
+
431
+ # General recommendations
432
+ if not blockers and not warnings:
433
+ recommendations.append("All checks passed - ready for release")
434
+ elif blockers:
435
+ recommendations.append("Address all blockers before release")
436
+ recommendations.append("Consider running security audit on fixes")
437
+ elif warnings:
438
+ recommendations.append("Review warnings before release")
439
+ recommendations.append("Document accepted risks if proceeding")
440
+
441
+ return blockers, warnings, recommendations
442
+
443
+ @classmethod
444
+ def for_pr_review(cls, files_changed: int = 0) -> "SecureReleasePipeline":
445
+ """Create pipeline optimized for PR review."""
446
+ return cls(
447
+ mode="standard" if files_changed < 10 else "full",
448
+ parallel_crew=True,
449
+ )
450
+
451
+ @classmethod
452
+ def for_release(cls) -> "SecureReleasePipeline":
453
+ """Create pipeline for release preparation."""
454
+ return cls(
455
+ mode="full",
456
+ crew_config={"scan_depth": "thorough"},
457
+ )
458
+
459
+
460
+ def format_secure_release_report(result: SecureReleaseResult) -> str:
461
+ """Format secure release result as a human-readable report.
462
+
463
+ Args:
464
+ result: The SecureReleaseResult object
465
+
466
+ Returns:
467
+ Formatted report string
468
+
469
+ """
470
+ lines = []
471
+
472
+ # Header with go/no-go decision
473
+ go_no_go = result.go_no_go
474
+
475
+ if go_no_go == "GO":
476
+ status_icon = "✅"
477
+ status_text = "READY FOR RELEASE"
478
+ elif go_no_go == "CONDITIONAL":
479
+ status_icon = "⚠️"
480
+ status_text = "CONDITIONAL APPROVAL"
481
+ else:
482
+ status_icon = "❌"
483
+ status_text = "RELEASE BLOCKED"
484
+
485
+ lines.append("=" * 60)
486
+ lines.append("SECURE RELEASE REPORT")
487
+ lines.append("=" * 60)
488
+ lines.append("")
489
+ lines.append(f"Decision: {status_icon} {go_no_go} - {status_text}")
490
+ lines.append(f"Risk Score: {result.combined_risk_score:.1f}/100")
491
+ lines.append(f"Pipeline Mode: {result.mode.upper()}")
492
+ lines.append(f"Crew Enabled: {'Yes' if result.crew_enabled else 'No'}")
493
+ lines.append("")
494
+
495
+ # Findings summary
496
+ lines.append("-" * 60)
497
+ lines.append("FINDINGS SUMMARY")
498
+ lines.append("-" * 60)
499
+ lines.append(f"Total Findings: {result.total_findings}")
500
+ lines.append(f" 🔴 Critical: {result.critical_count}")
501
+ lines.append(f" 🟠 High: {result.high_count}")
502
+ lines.append("")
503
+
504
+ # Blockers
505
+ if result.blockers:
506
+ lines.append("-" * 60)
507
+ lines.append("🚫 BLOCKERS (Must Fix Before Release)")
508
+ lines.append("-" * 60)
509
+ for blocker in result.blockers:
510
+ lines.append(f" • {blocker}")
511
+ lines.append("")
512
+
513
+ # Warnings
514
+ if result.warnings:
515
+ lines.append("-" * 60)
516
+ lines.append("⚠️ WARNINGS")
517
+ lines.append("-" * 60)
518
+ for warning in result.warnings:
519
+ lines.append(f" • {warning}")
520
+ lines.append("")
521
+
522
+ # Recommendations
523
+ if result.recommendations:
524
+ lines.append("-" * 60)
525
+ lines.append("💡 RECOMMENDATIONS")
526
+ lines.append("-" * 60)
527
+ for rec in result.recommendations:
528
+ lines.append(f" • {rec}")
529
+ lines.append("")
530
+
531
+ # Individual workflow summaries
532
+ lines.append("-" * 60)
533
+ lines.append("WORKFLOW RESULTS")
534
+ lines.append("-" * 60)
535
+
536
+ # Crew results
537
+ if result.crew_report:
538
+ crew_risk = result.crew_report.get("risk_score", 0)
539
+ crew_findings = result.crew_report.get("finding_count", 0)
540
+ crew_icon = "✅" if crew_risk < 50 else "⚠️" if crew_risk < 75 else "❌"
541
+ lines.append(
542
+ f" {crew_icon} SecurityAuditCrew: {crew_findings} findings, risk {crew_risk}/100",
543
+ )
544
+ elif result.crew_enabled:
545
+ lines.append(" ⏭️ SecurityAuditCrew: Skipped or failed")
546
+
547
+ # Security audit
548
+ if result.security_audit:
549
+ sec_output = result.security_audit.final_output or {}
550
+ assessment = sec_output.get("assessment", {})
551
+ sec_risk = assessment.get("risk_score", 0)
552
+ sec_level = assessment.get("risk_level", "unknown")
553
+ sec_icon = "✅" if sec_risk < 50 else "⚠️" if sec_risk < 75 else "❌"
554
+ lines.append(f" {sec_icon} SecurityAudit: {sec_level} risk ({sec_risk}/100)")
555
+
556
+ # Code review
557
+ if result.code_review:
558
+ cr_output = result.code_review.final_output or {}
559
+ verdict = cr_output.get("verdict", "unknown")
560
+ cr_icon = "✅" if verdict == "approve" else "⚠️" if verdict == "request_changes" else "❌"
561
+ lines.append(f" {cr_icon} CodeReview: {verdict}")
562
+
563
+ # Release prep
564
+ if result.release_prep:
565
+ rp_output = result.release_prep.final_output or {}
566
+ approved = rp_output.get("approved", False)
567
+ confidence = rp_output.get("confidence", "unknown")
568
+ rp_icon = "✅" if approved else "❌"
569
+ lines.append(
570
+ f" {rp_icon} ReleasePrep: {'Approved' if approved else 'Not Approved'} ({confidence} confidence)",
571
+ )
572
+
573
+ lines.append("")
574
+
575
+ # Cost and duration
576
+ lines.append("-" * 60)
577
+ lines.append("EXECUTION DETAILS")
578
+ lines.append("-" * 60)
579
+ lines.append(f"Total Cost: ${result.total_cost:.4f}")
580
+ lines.append(f"Duration: {result.total_duration_ms:.0f}ms")
581
+ lines.append("")
582
+
583
+ # Footer
584
+ lines.append("=" * 60)
585
+ if go_no_go == "GO":
586
+ lines.append("All security checks passed. Proceed with release.")
587
+ elif go_no_go == "CONDITIONAL":
588
+ lines.append("Review warnings before proceeding with release.")
589
+ else:
590
+ lines.append("Address all blockers before release can proceed.")
591
+ lines.append("=" * 60)
592
+
593
+ return "\n".join(lines)