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
attune/cli_unified.py ADDED
@@ -0,0 +1,814 @@
1
+ """Unified CLI for Empathy Framework
2
+
3
+ DEPRECATED: This module is deprecated as of v5.0.0.
4
+ Use the minimal CLI instead: `empathy` (attune.cli_minimal)
5
+
6
+ The minimal CLI provides:
7
+ - `empathy workflow list|info|run` - Workflow management
8
+ - `empathy telemetry show|savings|export` - Usage tracking
9
+ - `empathy provider show|set` - Provider configuration
10
+ - `empathy validate` - Configuration validation
11
+
12
+ For interactive features, use Claude Code slash commands:
13
+ - /dev, /testing, /docs, /release, /help
14
+
15
+ Migration guide: https://smartaimemory.com/framework-docs/migration/cli/
16
+
17
+ ---
18
+
19
+ A simplified, intelligent CLI using Socratic questioning.
20
+
21
+ Usage:
22
+ empathy do "review code in src/" # Intelligent - asks questions if needed
23
+ empathy r . # Quick: review
24
+ empathy s . # Quick: security
25
+ empathy t . # Quick: test
26
+ empathy scan . # Quick scan (no API)
27
+ empathy ship # Pre-commit check
28
+
29
+ Copyright 2025 Smart-AI-Memory
30
+ Licensed under Fair Source License 0.9
31
+ """
32
+
33
+ import warnings
34
+
35
+ warnings.warn(
36
+ "empathy-unified CLI is deprecated. Use 'empathy' (cli_minimal) instead. "
37
+ "See: https://smartaimemory.com/framework-docs/reference/cli-reference/",
38
+ DeprecationWarning,
39
+ stacklevel=2,
40
+ )
41
+
42
+ import json
43
+ import subprocess
44
+ import sys
45
+ from importlib.metadata import version as get_version
46
+ from pathlib import Path
47
+
48
+ import typer
49
+ from rich.console import Console
50
+ from rich.panel import Panel
51
+
52
+ # =============================================================================
53
+ # CONSTANTS
54
+ # =============================================================================
55
+
56
+ CHEATSHEET_CONTENT = """\
57
+ [bold]Main Command[/bold]
58
+ empathy do "..." Intelligent task execution (asks questions if needed)
59
+
60
+ [bold]Quick Actions (short aliases)[/bold]
61
+ empathy r [path] Review code
62
+ empathy s [path] Security audit
63
+ empathy t [path] Generate tests
64
+ empathy d [path] Generate docs
65
+
66
+ [bold]Utilities[/bold]
67
+ empathy scan [path] Quick scan (no API needed)
68
+ empathy ship Pre-commit validation
69
+ empathy health Project health check
70
+
71
+ [bold]Reports[/bold]
72
+ empathy report costs API cost tracking
73
+ empathy report health Project health summary
74
+ empathy report patterns Learned patterns
75
+
76
+ [bold]Memory[/bold]
77
+ empathy memory Memory system status
78
+ empathy memory start Start Redis"""
79
+
80
+ TIER_CONFIG_PATH = Path(".empathy") / "tier_config.json"
81
+
82
+
83
+ # =============================================================================
84
+ # HELPER FUNCTIONS
85
+ # =============================================================================
86
+
87
+
88
+ def _load_tier_config() -> dict:
89
+ """Load tier configuration from .attune/tier_config.json."""
90
+ if TIER_CONFIG_PATH.exists():
91
+ try:
92
+ return json.loads(TIER_CONFIG_PATH.read_text())
93
+ except json.JSONDecodeError:
94
+ return {}
95
+ return {}
96
+
97
+
98
+ def _save_tier_config(config: dict) -> None:
99
+ """Save tier configuration to .attune/tier_config.json."""
100
+ TIER_CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
101
+ TIER_CONFIG_PATH.write_text(json.dumps(config, indent=2))
102
+
103
+
104
+ def _auto_sync_patterns() -> None:
105
+ """Automatically sync patterns to Claude Code after workflow completion."""
106
+ try:
107
+ result = subprocess.run(
108
+ ["empathy-sync-claude", "--source", "patterns"],
109
+ capture_output=True,
110
+ text=True,
111
+ timeout=30,
112
+ check=False,
113
+ )
114
+ if result.returncode == 0:
115
+ console.print("\n[dim]✓ Patterns synced to Claude Code[/dim]")
116
+ except (subprocess.TimeoutExpired, FileNotFoundError, Exception):
117
+ pass # Silent fail
118
+
119
+
120
+ def _run_workflow(name: str, path: Path, json_output: bool = False):
121
+ """Helper to run a workflow via the legacy CLI."""
122
+ workflow_input = f'{{"path": "{path}"}}'
123
+
124
+ cmd = [
125
+ sys.executable,
126
+ "-m",
127
+ "attune.cli",
128
+ "workflow",
129
+ "run",
130
+ name,
131
+ "--input",
132
+ workflow_input,
133
+ ]
134
+ if json_output:
135
+ cmd.append("--json")
136
+
137
+ result = subprocess.run(cmd, check=False)
138
+
139
+ if result.returncode == 0 and not json_output:
140
+ _auto_sync_patterns()
141
+
142
+
143
+ # =============================================================================
144
+ # APP SETUP
145
+ # =============================================================================
146
+
147
+ app = typer.Typer(
148
+ name="empathy",
149
+ help="Empathy Framework - Intelligent AI-Developer Collaboration",
150
+ no_args_is_help=True,
151
+ rich_markup_mode="rich",
152
+ )
153
+
154
+ console = Console()
155
+
156
+
157
+ def get_empathy_version() -> str:
158
+ """Get the installed version of empathy-framework."""
159
+ try:
160
+ return get_version("empathy-framework")
161
+ except Exception:
162
+ return "dev"
163
+
164
+
165
+ def version_callback(value: bool):
166
+ """Show version and exit."""
167
+ if value:
168
+ console.print(f"[bold blue]Empathy Framework[/bold blue] v{get_empathy_version()}")
169
+ raise typer.Exit()
170
+
171
+
172
+ @app.callback()
173
+ def callback(
174
+ version: bool = typer.Option(
175
+ None,
176
+ "--version",
177
+ "-v",
178
+ callback=version_callback,
179
+ is_eager=True,
180
+ help="Show version and exit",
181
+ ),
182
+ ):
183
+ """Empathy Framework - Intelligent AI-Developer Collaboration
184
+
185
+ [bold]Quick Start:[/bold]
186
+ empathy do "review the code" Ask AI to do something
187
+ empathy r . Quick code review
188
+ empathy scan . Quick security scan
189
+
190
+ [bold]Shortcuts:[/bold]
191
+ r = review, s = security, t = test, d = docs
192
+ """
193
+
194
+
195
+ # =============================================================================
196
+ # MAIN COMMAND: do
197
+ # =============================================================================
198
+
199
+
200
+ @app.command("do")
201
+ def do_command(
202
+ goal: str = typer.Argument(..., help="What you want to accomplish"),
203
+ path: Path = typer.Option(Path("."), "--path", "-p", help="Path to analyze"),
204
+ interactive: bool = typer.Option(
205
+ True, "--interactive/--no-interactive", "-i", help="Ask clarifying questions"
206
+ ),
207
+ ):
208
+ """Intelligent task execution using Socratic questioning.
209
+
210
+ The AI will understand your goal and ask clarifying questions if needed.
211
+ Uses domain templates for common tasks like code review, security, testing.
212
+
213
+ Examples:
214
+ empathy do "review the authentication code"
215
+ empathy do "find security vulnerabilities" --path ./src
216
+ empathy do "generate tests for the API" --no-interactive
217
+ """
218
+ console.print(f"\n[bold]Goal:[/bold] {goal}")
219
+ console.print(f"[dim]Path: {path}[/dim]\n")
220
+
221
+ # Use Socratic system for intelligent task execution
222
+ try:
223
+ from attune.socratic import SocraticWorkflowBuilder
224
+ from attune.socratic.cli import console as socratic_console
225
+ from attune.socratic.cli import render_form_interactive
226
+ from attune.socratic.storage import get_default_storage
227
+
228
+ builder = SocraticWorkflowBuilder()
229
+ storage = get_default_storage()
230
+
231
+ # Start session with the goal
232
+ session = builder.start_session()
233
+ session = builder.set_goal(session, f"{goal} (path: {path})")
234
+ storage.save_session(session)
235
+
236
+ # Show domain detection
237
+ if session.goal_analysis:
238
+ console.print(f"[cyan]Detected domain:[/cyan] {session.goal_analysis.domain}")
239
+ console.print(f"[cyan]Confidence:[/cyan] {session.goal_analysis.confidence:.0%}")
240
+
241
+ if session.goal_analysis.ambiguities and interactive:
242
+ console.print("\n[yellow]Clarifications needed:[/yellow]")
243
+ for amb in session.goal_analysis.ambiguities:
244
+ console.print(f" • {amb}")
245
+
246
+ # Interactive questioning if needed
247
+ if interactive:
248
+ while not builder.is_ready_to_generate(session):
249
+ form = builder.get_next_questions(session)
250
+ if not form:
251
+ break
252
+
253
+ answers = render_form_interactive(form, socratic_console)
254
+ session = builder.submit_answers(session, answers)
255
+ storage.save_session(session)
256
+
257
+ # Generate and execute workflow
258
+ if builder.is_ready_to_generate(session):
259
+ console.print("\n[bold]Generating workflow...[/bold]")
260
+ workflow = builder.generate_workflow(session)
261
+ storage.save_session(session)
262
+
263
+ console.print(
264
+ f"\n[green]✓ Generated workflow with {len(workflow.agents)} agents[/green]"
265
+ )
266
+ console.print(workflow.describe())
267
+
268
+ # Execute the workflow
269
+ if session.blueprint:
270
+ storage.save_blueprint(session.blueprint)
271
+ console.print(f"\n[dim]Blueprint saved: {session.blueprint.id[:8]}...[/dim]")
272
+
273
+ _auto_sync_patterns()
274
+
275
+ except ImportError as e:
276
+ console.print(f"[yellow]Socratic system not fully available: {e}[/yellow]")
277
+ console.print("[dim]Falling back to keyword matching...[/dim]\n")
278
+
279
+ # Fallback: keyword-based workflow selection
280
+ goal_lower = goal.lower()
281
+ if any(w in goal_lower for w in ["review", "check", "analyze"]):
282
+ _run_workflow("code-review", path)
283
+ elif any(w in goal_lower for w in ["security", "vulnerab", "owasp"]):
284
+ _run_workflow("security-audit", path)
285
+ elif any(w in goal_lower for w in ["test", "coverage"]):
286
+ _run_workflow("test-gen", path)
287
+ elif any(w in goal_lower for w in ["doc", "document"]):
288
+ _run_workflow("doc-gen", path)
289
+ else:
290
+ _run_workflow("code-review", path)
291
+
292
+
293
+ # =============================================================================
294
+ # SHORT ALIASES
295
+ # =============================================================================
296
+
297
+
298
+ @app.command("r")
299
+ def review_short(
300
+ path: Path = typer.Argument(Path("."), help="Path to review"),
301
+ json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
302
+ ):
303
+ """[bold]Review[/bold] - Quick code review.
304
+
305
+ Alias for: empathy do "review code"
306
+ """
307
+ _run_workflow("code-review", path, json_output)
308
+
309
+
310
+ @app.command("s")
311
+ def security_short(
312
+ path: Path = typer.Argument(Path("."), help="Path to scan"),
313
+ json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
314
+ ):
315
+ """[bold]Security[/bold] - Quick security audit.
316
+
317
+ Alias for: empathy do "security audit"
318
+ """
319
+ _run_workflow("security-audit", path, json_output)
320
+
321
+
322
+ @app.command("t")
323
+ def test_short(
324
+ path: Path = typer.Argument(Path("."), help="Path to analyze"),
325
+ json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
326
+ ):
327
+ """[bold]Test[/bold] - Generate tests.
328
+
329
+ Alias for: empathy do "generate tests"
330
+ """
331
+ _run_workflow("test-gen", path, json_output)
332
+
333
+
334
+ @app.command("d")
335
+ def docs_short(
336
+ path: Path = typer.Argument(Path("."), help="Path to document"),
337
+ json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
338
+ ):
339
+ """[bold]Docs[/bold] - Generate documentation.
340
+
341
+ Alias for: empathy do "generate docs"
342
+ """
343
+ _run_workflow("doc-gen", path, json_output)
344
+
345
+
346
+ # =============================================================================
347
+ # UTILITY COMMANDS
348
+ # =============================================================================
349
+
350
+
351
+ @app.command("scan")
352
+ def scan_command(
353
+ scan_type: str = typer.Argument("all", help="Scan type: security, performance, or all"),
354
+ path: Path = typer.Argument(Path("."), help="Path to scan"),
355
+ ):
356
+ """Quick security/performance scan (no API needed).
357
+
358
+ Examples:
359
+ empathy scan all .
360
+ empathy scan security ./src
361
+ """
362
+ if scan_type not in ("security", "performance", "all"):
363
+ console.print(f"[red]Invalid scan type: {scan_type}[/red]")
364
+ console.print("Valid types: security, performance, all")
365
+ raise typer.Exit(code=1)
366
+
367
+ console.print(f"[bold blue]Scanning {path} ({scan_type})...[/bold blue]\n")
368
+
369
+ if scan_type in ("all", "security"):
370
+ # Run ruff for linting
371
+ console.print("[bold]Running ruff (linting)...[/bold]")
372
+ subprocess.run(["ruff", "check", str(path)], check=False)
373
+
374
+ # Run bandit for security
375
+ console.print("\n[bold]Running bandit (security)...[/bold]")
376
+ result = subprocess.run(["bandit", "-r", str(path), "-q"], check=False, capture_output=True)
377
+ if result.returncode == 0:
378
+ console.print("[green]No security issues found[/green]")
379
+ elif result.stdout:
380
+ console.print(result.stdout.decode())
381
+
382
+ if scan_type in ("all", "performance"):
383
+ console.print("\n[bold]Checking for performance patterns...[/bold]")
384
+ # Basic performance check - look for common issues
385
+ subprocess.run(["ruff", "check", str(path), "--select", "PERF"], check=False)
386
+
387
+ console.print("\n[bold green]Scan complete![/bold green]")
388
+
389
+
390
+ @app.command("ship")
391
+ def ship_command(
392
+ skip_sync: bool = typer.Option(False, "--skip-sync", help="Skip pattern sync"),
393
+ ):
394
+ """Pre-commit validation (lint, format, tests, security).
395
+
396
+ Run this before committing to ensure code quality.
397
+ """
398
+ args = [sys.executable, "-m", "attune.cli", "ship"]
399
+ if skip_sync:
400
+ args.append("--skip-sync")
401
+ subprocess.run(args, check=False)
402
+
403
+
404
+ @app.command("health")
405
+ def health_command(
406
+ deep: bool = typer.Option(False, "--deep", help="Comprehensive check"),
407
+ fix: bool = typer.Option(False, "--fix", help="Auto-fix issues"),
408
+ ):
409
+ """Quick project health check.
410
+
411
+ Shows lint issues, test status, and overall health score.
412
+ """
413
+ args = [sys.executable, "-m", "attune.cli", "health"]
414
+ if deep:
415
+ args.append("--deep")
416
+ if fix:
417
+ args.append("--fix")
418
+ subprocess.run(args, check=False)
419
+
420
+
421
+ # =============================================================================
422
+ # REPORT SUBCOMMAND GROUP
423
+ # =============================================================================
424
+
425
+ report_app = typer.Typer(help="View reports and dashboards")
426
+ app.add_typer(report_app, name="report")
427
+
428
+
429
+ @report_app.command("costs")
430
+ def report_costs():
431
+ """View API cost tracking."""
432
+ subprocess.run([sys.executable, "-m", "attune.cli", "costs"], check=False)
433
+
434
+
435
+ @report_app.command("health")
436
+ def report_health():
437
+ """View project health summary."""
438
+ subprocess.run([sys.executable, "-m", "attune.cli", "status"], check=False)
439
+
440
+
441
+ @report_app.command("patterns")
442
+ def report_patterns():
443
+ """View learned patterns."""
444
+ subprocess.run(
445
+ [sys.executable, "-m", "attune.memory.control_panel", "patterns"],
446
+ check=False,
447
+ )
448
+
449
+
450
+ @report_app.command("telemetry")
451
+ def report_telemetry(
452
+ limit: int = typer.Option(20, "--limit", "-l", help="Number of entries"),
453
+ ):
454
+ """View LLM usage telemetry."""
455
+ subprocess.run(
456
+ [sys.executable, "-m", "attune.cli", "telemetry", "show", "--limit", str(limit)],
457
+ check=False,
458
+ )
459
+
460
+
461
+ # =============================================================================
462
+ # MEMORY SUBCOMMAND GROUP
463
+ # =============================================================================
464
+
465
+ memory_app = typer.Typer(help="Memory system control panel")
466
+ app.add_typer(memory_app, name="memory")
467
+
468
+
469
+ @memory_app.callback(invoke_without_command=True)
470
+ def memory_default(ctx: typer.Context):
471
+ """Memory system control panel."""
472
+ if ctx.invoked_subcommand is None:
473
+ subprocess.run(
474
+ [sys.executable, "-m", "attune.memory.control_panel", "status"],
475
+ check=False,
476
+ )
477
+
478
+
479
+ @memory_app.command("status")
480
+ def memory_status():
481
+ """Check memory system status."""
482
+ subprocess.run(
483
+ [sys.executable, "-m", "attune.memory.control_panel", "status"],
484
+ check=False,
485
+ )
486
+
487
+
488
+ @memory_app.command("start")
489
+ def memory_start():
490
+ """Start Redis server for short-term memory."""
491
+ subprocess.run(
492
+ [sys.executable, "-m", "attune.memory.control_panel", "start"],
493
+ check=False,
494
+ )
495
+
496
+
497
+ @memory_app.command("stop")
498
+ def memory_stop():
499
+ """Stop Redis server."""
500
+ subprocess.run(
501
+ [sys.executable, "-m", "attune.memory.control_panel", "stop"],
502
+ check=False,
503
+ )
504
+
505
+
506
+ @memory_app.command("patterns")
507
+ def memory_patterns():
508
+ """List stored patterns."""
509
+ subprocess.run(
510
+ [sys.executable, "-m", "attune.memory.control_panel", "patterns"],
511
+ check=False,
512
+ )
513
+
514
+
515
+ # =============================================================================
516
+ # UTILITIES SUBCOMMAND GROUP
517
+ # =============================================================================
518
+
519
+ utilities_app = typer.Typer(help="Utility tools - init, cheatsheet, dashboard, sync")
520
+ app.add_typer(utilities_app, name="utilities")
521
+ app.add_typer(utilities_app, name="utility", hidden=True) # Alias for common typo
522
+
523
+
524
+ @utilities_app.command("cheatsheet")
525
+ def utilities_cheatsheet():
526
+ """Show quick reference for all commands."""
527
+ console.print(
528
+ Panel.fit(
529
+ CHEATSHEET_CONTENT,
530
+ title="[bold blue]Empathy Framework Cheatsheet[/bold blue]",
531
+ ),
532
+ )
533
+
534
+
535
+ @utilities_app.command("init")
536
+ def utilities_init():
537
+ """Create a new configuration file."""
538
+ subprocess.run([sys.executable, "-m", "attune.cli", "init"], check=False)
539
+
540
+
541
+ @utilities_app.command("dashboard")
542
+ def utilities_dashboard():
543
+ """Launch visual dashboard."""
544
+ subprocess.run([sys.executable, "-m", "attune.cli", "dashboard"], check=False)
545
+
546
+
547
+ @utilities_app.command("sync-claude")
548
+ def utilities_sync_claude(
549
+ source: str = typer.Option("patterns", "--source", "-s", help="Source to sync"),
550
+ ):
551
+ """Sync patterns to Claude Code memory."""
552
+ subprocess.run(["empathy-sync-claude", "--source", source], check=False)
553
+
554
+
555
+ @utilities_app.command("costs")
556
+ def utilities_costs():
557
+ """View API cost tracking."""
558
+ subprocess.run([sys.executable, "-m", "attune.cli", "costs"], check=False)
559
+
560
+
561
+ @utilities_app.command("status")
562
+ def utilities_status():
563
+ """What needs attention now."""
564
+ subprocess.run([sys.executable, "-m", "attune.cli", "status"], check=False)
565
+
566
+
567
+ @utilities_app.command("scan")
568
+ def utilities_scan(
569
+ path: Path = typer.Argument(Path("."), help="Path to scan"),
570
+ scan_type: str = typer.Option(
571
+ "all", "--type", "-t", help="Scan type: security, performance, or all"
572
+ ),
573
+ ):
574
+ """Scan codebase for issues.
575
+
576
+ Examples:
577
+ empathy utility scan .
578
+ empathy utility scan ./src --type security
579
+ """
580
+ # Delegate to main scan command
581
+ scan_command(scan_type, path)
582
+
583
+
584
+ # =============================================================================
585
+ # CHEATSHEET (top-level alias for convenience)
586
+ # =============================================================================
587
+
588
+
589
+ @app.command("cheatsheet")
590
+ def cheatsheet():
591
+ """Show quick reference for all commands."""
592
+ console.print(
593
+ Panel.fit(
594
+ CHEATSHEET_CONTENT,
595
+ title="[bold blue]Empathy Framework Cheatsheet[/bold blue]",
596
+ ),
597
+ )
598
+
599
+
600
+ # =============================================================================
601
+ # ADDITIONAL COMMAND APPS (exported for cli/__init__.py)
602
+ # These provide structure for commands that will be migrated from legacy CLI
603
+ # =============================================================================
604
+
605
+ # Workflow commands - run multi-model AI workflows
606
+ workflow_app = typer.Typer(help="Run multi-model AI workflows")
607
+
608
+
609
+ @workflow_app.command("list")
610
+ def workflow_list():
611
+ """List available workflows."""
612
+ subprocess.run(
613
+ [sys.executable, "-m", "attune.cli", "workflow", "list"],
614
+ check=False,
615
+ )
616
+
617
+
618
+ @workflow_app.command("run")
619
+ def workflow_run(
620
+ name: str = typer.Argument(..., help="Workflow name"),
621
+ input_json: str = typer.Option("{}", "--input", "-i", help="Input JSON"),
622
+ json_output: bool = typer.Option(False, "--json", "-j", help="JSON output"),
623
+ ):
624
+ """Run a workflow by name."""
625
+ args = [sys.executable, "-m", "attune.cli", "workflow", "run", name, "--input", input_json]
626
+ if json_output:
627
+ args.append("--json")
628
+ subprocess.run(args, check=False)
629
+
630
+
631
+ @workflow_app.command("describe")
632
+ def workflow_describe(name: str = typer.Argument(..., help="Workflow name")):
633
+ """Describe a workflow."""
634
+ subprocess.run(
635
+ [sys.executable, "-m", "attune.cli", "workflow", "describe", name],
636
+ check=False,
637
+ )
638
+
639
+
640
+ # Orchestrate commands - advanced orchestration features
641
+ orchestrate_app = typer.Typer(help="Advanced workflow orchestration")
642
+
643
+
644
+ @orchestrate_app.command("run")
645
+ def orchestrate_run(
646
+ task: str = typer.Argument(..., help="Task description"),
647
+ path: Path = typer.Option(Path("."), "--path", "-p", help="Path to analyze"),
648
+ ):
649
+ """Run orchestrated task."""
650
+ task_json = json.dumps({"task": task, "path": str(path)})
651
+ subprocess.run(
652
+ [sys.executable, "-m", "attune.cli", "orchestrate", "--input", task_json],
653
+ check=False,
654
+ )
655
+
656
+
657
+ # Telemetry commands - LLM usage tracking
658
+ telemetry_app = typer.Typer(help="LLM usage telemetry and cost tracking")
659
+
660
+
661
+ @telemetry_app.command("show")
662
+ def telemetry_show(
663
+ limit: int = typer.Option(20, "--limit", "-l", help="Number of entries"),
664
+ ):
665
+ """Show telemetry data."""
666
+ subprocess.run(
667
+ [sys.executable, "-m", "attune.cli", "telemetry", "show", "--limit", str(limit)],
668
+ check=False,
669
+ )
670
+
671
+
672
+ @telemetry_app.command("export")
673
+ def telemetry_export(
674
+ output: Path = typer.Argument(..., help="Output file path"),
675
+ format_type: str = typer.Option("json", "--format", "-f", help="Output format: json, csv"),
676
+ ):
677
+ """Export telemetry data."""
678
+ subprocess.run(
679
+ [
680
+ sys.executable,
681
+ "-m",
682
+ "attune.cli",
683
+ "telemetry",
684
+ "export",
685
+ str(output),
686
+ "--format",
687
+ format_type,
688
+ ],
689
+ check=False,
690
+ )
691
+
692
+
693
+ @telemetry_app.command("reset")
694
+ def telemetry_reset():
695
+ """Reset telemetry data."""
696
+ subprocess.run(
697
+ [sys.executable, "-m", "attune.cli", "telemetry", "reset"],
698
+ check=False,
699
+ )
700
+
701
+
702
+ # Service commands - background services
703
+ service_app = typer.Typer(help="Background services management")
704
+
705
+
706
+ @service_app.command("status")
707
+ def service_status():
708
+ """Check service status."""
709
+ # Check Redis status via memory control panel
710
+ subprocess.run(
711
+ [sys.executable, "-m", "attune.memory.control_panel", "status"],
712
+ check=False,
713
+ )
714
+
715
+
716
+ @service_app.command("start")
717
+ def service_start(service_name: str = typer.Argument("all", help="Service to start")):
718
+ """Start background services."""
719
+ if service_name in ("all", "redis"):
720
+ subprocess.run(
721
+ [sys.executable, "-m", "attune.memory.control_panel", "start"],
722
+ check=False,
723
+ )
724
+
725
+
726
+ @service_app.command("stop")
727
+ def service_stop(service_name: str = typer.Argument("all", help="Service to stop")):
728
+ """Stop background services."""
729
+ if service_name in ("all", "redis"):
730
+ subprocess.run(
731
+ [sys.executable, "-m", "attune.memory.control_panel", "stop"],
732
+ check=False,
733
+ )
734
+
735
+
736
+ # Progressive commands - progressive test generation
737
+ progressive_app = typer.Typer(help="Progressive test generation")
738
+
739
+
740
+ @progressive_app.command("list")
741
+ def progressive_list():
742
+ """List progressive test results."""
743
+ subprocess.run(
744
+ [sys.executable, "-m", "attune.cli", "progressive", "list"],
745
+ check=False,
746
+ )
747
+
748
+
749
+ @progressive_app.command("report")
750
+ def progressive_report(session_id: str = typer.Argument(..., help="Session ID")):
751
+ """Show progressive test report."""
752
+ subprocess.run(
753
+ [sys.executable, "-m", "attune.cli", "progressive", "report", session_id],
754
+ check=False,
755
+ )
756
+
757
+
758
+ @progressive_app.command("analytics")
759
+ def progressive_analytics():
760
+ """Show progressive test analytics."""
761
+ subprocess.run(
762
+ [sys.executable, "-m", "attune.cli", "progressive", "analytics"],
763
+ check=False,
764
+ )
765
+
766
+
767
+ # Tier commands - model tier management
768
+ tier_app = typer.Typer(help="Model tier configuration")
769
+
770
+
771
+ @tier_app.command("recommend")
772
+ def tier_recommend(
773
+ task: str = typer.Argument("code-review", help="Task type"),
774
+ ):
775
+ """Get tier recommendation for a task."""
776
+ subprocess.run(
777
+ [sys.executable, "-m", "attune.cli", "tier", "recommend", task],
778
+ check=False,
779
+ )
780
+
781
+
782
+ @tier_app.command("stats")
783
+ def tier_stats():
784
+ """Show tier usage statistics."""
785
+ subprocess.run(
786
+ [sys.executable, "-m", "attune.cli", "tier", "stats"],
787
+ check=False,
788
+ )
789
+
790
+
791
+ @tier_app.command("set")
792
+ def tier_set(
793
+ task: str = typer.Argument(..., help="Task type"),
794
+ tier_name: str = typer.Argument(..., help="Tier name: cheap, balanced, premium"),
795
+ ):
796
+ """Set tier for a task type."""
797
+ config = _load_tier_config()
798
+ config[task] = tier_name
799
+ _save_tier_config(config)
800
+ console.print(f"[green]Set {task} to use {tier_name} tier[/green]")
801
+
802
+
803
+ # =============================================================================
804
+ # ENTRY POINT
805
+ # =============================================================================
806
+
807
+
808
+ def main():
809
+ """Entry point for the unified CLI."""
810
+ app()
811
+
812
+
813
+ if __name__ == "__main__":
814
+ main()