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,301 @@
1
+ """Command Loader
2
+
3
+ Loads commands from directory structures.
4
+
5
+ Architectural patterns inspired by everything-claude-code by Affaan Mustafa.
6
+ See: https://github.com/affaan-m/everything-claude-code (MIT License)
7
+ See: ACKNOWLEDGMENTS.md for full attribution.
8
+
9
+ Copyright 2025 Smart AI Memory, LLC
10
+ Licensed under Fair Source 0.9
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import logging
16
+ from collections.abc import Iterator
17
+ from pathlib import Path
18
+
19
+ from attune_llm.commands.models import CommandConfig
20
+ from attune_llm.commands.parser import CommandParser
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+ # Default commands directory relative to project root
25
+ DEFAULT_COMMANDS_DIR = ".claude/commands"
26
+
27
+ # Files to skip when scanning
28
+ SKIP_FILES = frozenset(
29
+ {
30
+ "README.md",
31
+ "readme.md",
32
+ "CHANGELOG.md",
33
+ "changelog.md",
34
+ "INDEX.md",
35
+ "index.md",
36
+ }
37
+ )
38
+
39
+
40
+ class CommandLoader:
41
+ """Loader for discovering and loading command markdown files.
42
+
43
+ Scans directories for .md files with command definitions and loads
44
+ them into CommandConfig instances.
45
+
46
+ Example:
47
+ loader = CommandLoader()
48
+
49
+ # Load a single command
50
+ config = loader.load(".claude/commands/commit.md")
51
+
52
+ # Load all commands from a directory
53
+ commands = loader.load_directory(".claude/commands/")
54
+
55
+ # Discover and iterate commands lazily
56
+ for config in loader.discover(".claude/commands/"):
57
+ print(config.name)
58
+ """
59
+
60
+ def __init__(self, parser: CommandParser | None = None):
61
+ """Initialize the loader.
62
+
63
+ Args:
64
+ parser: Optional custom parser instance
65
+
66
+ """
67
+ self.parser = parser or CommandParser()
68
+
69
+ def load(self, file_path: str | Path) -> CommandConfig:
70
+ """Load a single command file.
71
+
72
+ Args:
73
+ file_path: Path to the command markdown file
74
+
75
+ Returns:
76
+ CommandConfig instance
77
+
78
+ """
79
+ return self.parser.parse_file(file_path)
80
+
81
+ def load_directory(
82
+ self,
83
+ directory: str | Path,
84
+ recursive: bool = False,
85
+ ) -> dict[str, CommandConfig]:
86
+ """Load all commands from a directory.
87
+
88
+ Args:
89
+ directory: Directory to scan for .md files
90
+ recursive: If True, scan subdirectories
91
+
92
+ Returns:
93
+ Dictionary mapping command names to configs
94
+
95
+ """
96
+ commands: dict[str, CommandConfig] = {}
97
+
98
+ for config in self.discover(directory, recursive=recursive):
99
+ if config.name in commands:
100
+ logger.warning(
101
+ "Duplicate command name '%s' - keeping first occurrence",
102
+ config.name,
103
+ )
104
+ continue
105
+ commands[config.name] = config
106
+
107
+ logger.info("Loaded %d command(s) from %s", len(commands), directory)
108
+ return commands
109
+
110
+ def discover(
111
+ self,
112
+ directory: str | Path,
113
+ recursive: bool = False,
114
+ ) -> Iterator[CommandConfig]:
115
+ """Discover and yield commands from a directory.
116
+
117
+ Args:
118
+ directory: Directory to scan
119
+ recursive: If True, scan subdirectories
120
+
121
+ Yields:
122
+ CommandConfig instances
123
+
124
+ """
125
+ directory = Path(directory)
126
+
127
+ if not directory.exists():
128
+ logger.warning("Commands directory not found: %s", directory)
129
+ return
130
+
131
+ if not directory.is_dir():
132
+ raise ValueError(f"Not a directory: {directory}")
133
+
134
+ # Get pattern for globbing
135
+ pattern = "**/*.md" if recursive else "*.md"
136
+
137
+ for file_path in sorted(directory.glob(pattern)):
138
+ if not file_path.is_file():
139
+ continue
140
+
141
+ # Skip non-command files
142
+ if file_path.name in SKIP_FILES:
143
+ continue
144
+ if file_path.name.startswith("_"):
145
+ continue
146
+ if file_path.name.startswith("."):
147
+ continue
148
+
149
+ try:
150
+ config = self.parser.parse_file(file_path)
151
+ yield config
152
+ except ValueError as e:
153
+ logger.warning("Skipping invalid command file %s: %s", file_path, e)
154
+ except FileNotFoundError as e:
155
+ logger.warning("Command file not found %s: %s", file_path, e)
156
+ except OSError as e:
157
+ logger.error("Error loading command file %s: %s", file_path, e)
158
+
159
+ def validate_directory(
160
+ self,
161
+ directory: str | Path,
162
+ recursive: bool = False,
163
+ ) -> dict[str, list[str]]:
164
+ """Validate all command files in a directory.
165
+
166
+ Args:
167
+ directory: Directory to validate
168
+ recursive: If True, scan subdirectories
169
+
170
+ Returns:
171
+ Dictionary mapping file paths to lists of errors
172
+
173
+ """
174
+ directory = Path(directory)
175
+ results: dict[str, list[str]] = {}
176
+
177
+ if not directory.exists():
178
+ return {str(directory): ["Directory not found"]}
179
+
180
+ pattern = "**/*.md" if recursive else "*.md"
181
+
182
+ for file_path in sorted(directory.glob(pattern)):
183
+ if not file_path.is_file():
184
+ continue
185
+ if file_path.name in SKIP_FILES:
186
+ continue
187
+ if file_path.name.startswith("_"):
188
+ continue
189
+
190
+ errors = self.parser.validate_file(file_path)
191
+ if errors:
192
+ results[str(file_path)] = errors
193
+
194
+ return results
195
+
196
+ def get_command_names(
197
+ self,
198
+ directory: str | Path,
199
+ recursive: bool = False,
200
+ ) -> list[str]:
201
+ """Get list of command names in a directory without fully loading.
202
+
203
+ Args:
204
+ directory: Directory to scan
205
+ recursive: If True, scan subdirectories
206
+
207
+ Returns:
208
+ List of command names
209
+
210
+ """
211
+ names: list[str] = []
212
+ for config in self.discover(directory, recursive=recursive):
213
+ names.append(config.name)
214
+ return names
215
+
216
+ def find_command_file(
217
+ self,
218
+ name: str,
219
+ directory: str | Path,
220
+ ) -> Path | None:
221
+ """Find a command file by name.
222
+
223
+ Args:
224
+ name: Command name to find
225
+ directory: Directory to search
226
+
227
+ Returns:
228
+ Path to command file or None
229
+
230
+ """
231
+ directory = Path(directory)
232
+
233
+ # Try exact match first
234
+ exact_path = directory / f"{name}.md"
235
+ if exact_path.exists():
236
+ return exact_path
237
+
238
+ # Search through files
239
+ for file_path in directory.glob("*.md"):
240
+ if file_path.stem == name:
241
+ return file_path
242
+
243
+ return None
244
+
245
+
246
+ def load_commands_from_paths(
247
+ paths: list[str | Path],
248
+ parser: CommandParser | None = None,
249
+ ) -> dict[str, CommandConfig]:
250
+ """Load commands from multiple paths (files or directories).
251
+
252
+ Args:
253
+ paths: List of file or directory paths
254
+ parser: Optional custom parser
255
+
256
+ Returns:
257
+ Dictionary mapping command names to configs
258
+
259
+ """
260
+ loader = CommandLoader(parser=parser)
261
+ commands: dict[str, CommandConfig] = {}
262
+
263
+ for path in paths:
264
+ path = Path(path)
265
+
266
+ if path.is_file():
267
+ config = loader.load(path)
268
+ commands[config.name] = config
269
+ elif path.is_dir():
270
+ dir_commands = loader.load_directory(path)
271
+ commands.update(dir_commands)
272
+ else:
273
+ logger.warning("Path not found: %s", path)
274
+
275
+ return commands
276
+
277
+
278
+ def get_default_commands_directory() -> Path:
279
+ """Get the default commands directory.
280
+
281
+ Searches for .claude/commands/ starting from current directory
282
+ and walking up to find project root.
283
+
284
+ Returns:
285
+ Path to commands directory
286
+
287
+ """
288
+ current = Path.cwd()
289
+
290
+ # Walk up looking for .claude/commands/
291
+ for parent in [current, *current.parents]:
292
+ commands_dir = parent / DEFAULT_COMMANDS_DIR
293
+ if commands_dir.exists():
294
+ return commands_dir
295
+
296
+ # Also check for .claude directory as project root indicator
297
+ if (parent / ".claude").exists():
298
+ return commands_dir
299
+
300
+ # Fall back to current directory
301
+ return current / DEFAULT_COMMANDS_DIR
@@ -0,0 +1,231 @@
1
+ """Command Configuration Models
2
+
3
+ Data models for command definitions loaded from markdown files.
4
+
5
+ Architectural patterns inspired by everything-claude-code by Affaan Mustafa.
6
+ See: https://github.com/affaan-m/everything-claude-code (MIT License)
7
+ See: ACKNOWLEDGMENTS.md for full attribution.
8
+
9
+ Copyright 2025 Smart AI Memory, LLC
10
+ Licensed under Fair Source 0.9
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from dataclasses import dataclass, field
16
+ from datetime import datetime
17
+ from enum import Enum
18
+ from pathlib import Path
19
+ from typing import Any
20
+
21
+
22
+ class CommandCategory(str, Enum):
23
+ """Categories for commands."""
24
+
25
+ WORKFLOW = "workflow" # Multi-step workflows
26
+ GIT = "git" # Git operations
27
+ TEST = "test" # Testing related
28
+ DOCS = "docs" # Documentation
29
+ SECURITY = "security" # Security analysis
30
+ PERFORMANCE = "performance" # Performance tools
31
+ LEARNING = "learning" # Pattern learning
32
+ CONTEXT = "context" # Context management
33
+ UTILITY = "utility" # General utilities
34
+
35
+
36
+ @dataclass
37
+ class CommandMetadata:
38
+ """Metadata for a command extracted from YAML frontmatter.
39
+
40
+ Example frontmatter:
41
+ ---
42
+ name: compact
43
+ description: Strategic context compaction
44
+ category: context
45
+ aliases: [comp, save-state]
46
+ hooks:
47
+ pre: PreCompact
48
+ post: PostCompact
49
+ requires_user_id: true
50
+ ---
51
+ """
52
+
53
+ name: str
54
+ description: str = ""
55
+ category: CommandCategory = CommandCategory.UTILITY
56
+ aliases: list[str] = field(default_factory=list)
57
+ hooks: dict[str, str] = field(default_factory=dict)
58
+ requires_user_id: bool = False
59
+ requires_context: bool = False
60
+ tags: list[str] = field(default_factory=list)
61
+ author: str = ""
62
+ version: str = "1.0"
63
+
64
+ def to_dict(self) -> dict[str, Any]:
65
+ """Convert to dictionary."""
66
+ return {
67
+ "name": self.name,
68
+ "description": self.description,
69
+ "category": self.category.value,
70
+ "aliases": self.aliases,
71
+ "hooks": self.hooks,
72
+ "requires_user_id": self.requires_user_id,
73
+ "requires_context": self.requires_context,
74
+ "tags": self.tags,
75
+ "author": self.author,
76
+ "version": self.version,
77
+ }
78
+
79
+ @classmethod
80
+ def from_dict(cls, data: dict[str, Any]) -> CommandMetadata:
81
+ """Create from dictionary."""
82
+ category_str = data.get("category", "utility")
83
+ try:
84
+ category = CommandCategory(category_str)
85
+ except ValueError:
86
+ category = CommandCategory.UTILITY
87
+
88
+ return cls(
89
+ name=data.get("name", ""),
90
+ description=data.get("description", ""),
91
+ category=category,
92
+ aliases=data.get("aliases", []),
93
+ hooks=data.get("hooks", {}),
94
+ requires_user_id=data.get("requires_user_id", False),
95
+ requires_context=data.get("requires_context", False),
96
+ tags=data.get("tags", []),
97
+ author=data.get("author", ""),
98
+ version=data.get("version", "1.0"),
99
+ )
100
+
101
+
102
+ @dataclass
103
+ class CommandConfig:
104
+ """Complete configuration for a command.
105
+
106
+ Combines metadata from YAML frontmatter with the markdown body
107
+ that contains the command instructions.
108
+ """
109
+
110
+ name: str
111
+ description: str
112
+ body: str # Markdown content with instructions
113
+ metadata: CommandMetadata
114
+ source_file: Path | None = None
115
+ loaded_at: datetime = field(default_factory=datetime.now)
116
+
117
+ @property
118
+ def aliases(self) -> list[str]:
119
+ """Get command aliases."""
120
+ return self.metadata.aliases
121
+
122
+ @property
123
+ def category(self) -> CommandCategory:
124
+ """Get command category."""
125
+ return self.metadata.category
126
+
127
+ @property
128
+ def hooks(self) -> dict[str, str]:
129
+ """Get hook configuration."""
130
+ return self.metadata.hooks
131
+
132
+ def get_all_names(self) -> list[str]:
133
+ """Get command name and all aliases."""
134
+ return [self.name] + self.aliases
135
+
136
+ def to_dict(self) -> dict[str, Any]:
137
+ """Convert to dictionary."""
138
+ return {
139
+ "name": self.name,
140
+ "description": self.description,
141
+ "body": self.body,
142
+ "metadata": self.metadata.to_dict(),
143
+ "source_file": str(self.source_file) if self.source_file else None,
144
+ "loaded_at": self.loaded_at.isoformat(),
145
+ }
146
+
147
+ @classmethod
148
+ def from_dict(cls, data: dict[str, Any]) -> CommandConfig:
149
+ """Create from dictionary."""
150
+ return cls(
151
+ name=data["name"],
152
+ description=data.get("description", ""),
153
+ body=data.get("body", ""),
154
+ metadata=CommandMetadata.from_dict(data.get("metadata", {})),
155
+ source_file=Path(data["source_file"]) if data.get("source_file") else None,
156
+ loaded_at=datetime.fromisoformat(data["loaded_at"])
157
+ if "loaded_at" in data
158
+ else datetime.now(),
159
+ )
160
+
161
+ def format_for_display(self) -> str:
162
+ """Format command for display in help."""
163
+ aliases_str = ""
164
+ if self.aliases:
165
+ aliases_str = f" (aliases: {', '.join(self.aliases)})"
166
+
167
+ return f"/{self.name}{aliases_str} - {self.description}"
168
+
169
+ def format_full_help(self) -> str:
170
+ """Format full help including body."""
171
+ lines = [
172
+ f"# /{self.name}",
173
+ "",
174
+ self.description,
175
+ "",
176
+ ]
177
+
178
+ if self.aliases:
179
+ lines.extend(
180
+ [
181
+ "## Aliases",
182
+ ", ".join(f"/{a}" for a in self.aliases),
183
+ "",
184
+ ]
185
+ )
186
+
187
+ if self.metadata.tags:
188
+ lines.extend(
189
+ [
190
+ "## Tags",
191
+ ", ".join(self.metadata.tags),
192
+ "",
193
+ ]
194
+ )
195
+
196
+ lines.extend(
197
+ [
198
+ "## Instructions",
199
+ "",
200
+ self.body,
201
+ ]
202
+ )
203
+
204
+ return "\n".join(lines)
205
+
206
+
207
+ @dataclass
208
+ class CommandResult:
209
+ """Result from executing a command."""
210
+
211
+ command_name: str
212
+ success: bool
213
+ output: str = ""
214
+ error: str | None = None
215
+ duration_ms: float = 0.0
216
+ hooks_fired: list[str] = field(default_factory=list)
217
+ context_saved: bool = False
218
+ patterns_applied: list[str] = field(default_factory=list)
219
+
220
+ def to_dict(self) -> dict[str, Any]:
221
+ """Convert to dictionary."""
222
+ return {
223
+ "command_name": self.command_name,
224
+ "success": self.success,
225
+ "output": self.output,
226
+ "error": self.error,
227
+ "duration_ms": self.duration_ms,
228
+ "hooks_fired": self.hooks_fired,
229
+ "context_saved": self.context_saved,
230
+ "patterns_applied": self.patterns_applied,
231
+ }