moai-adk 0.25.4__py3-none-any.whl → 0.32.8__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.
Potentially problematic release.
This version of moai-adk might be problematic. Click here for more details.
- moai_adk/__init__.py +2 -5
- moai_adk/__main__.py +114 -82
- moai_adk/cli/__init__.py +6 -1
- moai_adk/cli/commands/__init__.py +1 -3
- moai_adk/cli/commands/analyze.py +5 -16
- moai_adk/cli/commands/doctor.py +6 -18
- moai_adk/cli/commands/init.py +56 -125
- moai_adk/cli/commands/language.py +14 -35
- moai_adk/cli/commands/status.py +9 -15
- moai_adk/cli/commands/update.py +1555 -190
- moai_adk/cli/prompts/init_prompts.py +112 -56
- moai_adk/cli/spec_status.py +263 -0
- moai_adk/cli/ui/__init__.py +44 -0
- moai_adk/cli/ui/progress.py +422 -0
- moai_adk/cli/ui/prompts.py +389 -0
- moai_adk/cli/ui/theme.py +129 -0
- moai_adk/cli/worktree/__init__.py +27 -0
- moai_adk/cli/worktree/__main__.py +31 -0
- moai_adk/cli/worktree/cli.py +672 -0
- moai_adk/cli/worktree/exceptions.py +89 -0
- moai_adk/cli/worktree/manager.py +490 -0
- moai_adk/cli/worktree/models.py +65 -0
- moai_adk/cli/worktree/registry.py +128 -0
- moai_adk/core/PHASE2_OPTIMIZATIONS.md +467 -0
- moai_adk/core/analysis/session_analyzer.py +17 -56
- moai_adk/core/claude_integration.py +26 -54
- moai_adk/core/command_helpers.py +10 -10
- moai_adk/core/comprehensive_monitoring_system.py +1183 -0
- moai_adk/core/config/auto_spec_config.py +5 -11
- moai_adk/core/config/migration.py +19 -9
- moai_adk/core/config/unified.py +436 -0
- moai_adk/core/context_manager.py +6 -12
- moai_adk/core/enterprise_features.py +1404 -0
- moai_adk/core/error_recovery_system.py +725 -112
- moai_adk/core/event_driven_hook_system.py +1371 -0
- moai_adk/core/git/__init__.py +8 -0
- moai_adk/core/git/branch_manager.py +3 -11
- moai_adk/core/git/checkpoint.py +1 -3
- moai_adk/core/git/conflict_detector.py +413 -0
- moai_adk/core/git/manager.py +91 -1
- moai_adk/core/hooks/post_tool_auto_spec_completion.py +56 -80
- moai_adk/core/input_validation_middleware.py +1006 -0
- moai_adk/core/integration/engine.py +6 -18
- moai_adk/core/integration/integration_tester.py +10 -9
- moai_adk/core/integration/utils.py +1 -1
- moai_adk/core/issue_creator.py +10 -28
- moai_adk/core/jit_context_loader.py +956 -0
- moai_adk/core/jit_enhanced_hook_manager.py +1987 -0
- moai_adk/core/language_config_resolver.py +485 -0
- moai_adk/core/language_validator.py +28 -41
- moai_adk/core/mcp/setup.py +15 -12
- moai_adk/core/merge/__init__.py +9 -0
- moai_adk/core/merge/analyzer.py +481 -0
- moai_adk/core/migration/alfred_to_moai_migrator.py +383 -0
- moai_adk/core/migration/backup_manager.py +78 -9
- moai_adk/core/migration/custom_element_scanner.py +358 -0
- moai_adk/core/migration/file_migrator.py +8 -17
- moai_adk/core/migration/interactive_checkbox_ui.py +488 -0
- moai_adk/core/migration/selective_restorer.py +470 -0
- moai_adk/core/migration/template_utils.py +74 -0
- moai_adk/core/migration/user_selection_ui.py +338 -0
- moai_adk/core/migration/version_detector.py +6 -10
- moai_adk/core/migration/version_migrator.py +3 -3
- moai_adk/core/performance/cache_system.py +8 -10
- moai_adk/core/phase_optimized_hook_scheduler.py +879 -0
- moai_adk/core/project/checker.py +2 -4
- moai_adk/core/project/detector.py +1 -3
- moai_adk/core/project/initializer.py +135 -23
- moai_adk/core/project/phase_executor.py +54 -81
- moai_adk/core/project/validator.py +6 -12
- moai_adk/core/quality/trust_checker.py +9 -27
- moai_adk/core/realtime_monitoring_dashboard.py +1724 -0
- moai_adk/core/robust_json_parser.py +611 -0
- moai_adk/core/rollback_manager.py +73 -148
- moai_adk/core/session_manager.py +10 -26
- moai_adk/core/skill_loading_system.py +579 -0
- moai_adk/core/spec/confidence_scoring.py +31 -100
- moai_adk/core/spec/ears_template_engine.py +351 -286
- moai_adk/core/spec/quality_validator.py +35 -69
- moai_adk/core/spec_status_manager.py +64 -74
- moai_adk/core/template/backup.py +45 -20
- moai_adk/core/template/config.py +112 -39
- moai_adk/core/template/merger.py +11 -19
- moai_adk/core/template/processor.py +253 -149
- moai_adk/core/template_engine.py +73 -40
- moai_adk/core/template_variable_synchronizer.py +417 -0
- moai_adk/core/unified_permission_manager.py +745 -0
- moai_adk/core/user_behavior_analytics.py +851 -0
- moai_adk/core/version_sync.py +429 -0
- moai_adk/foundation/__init__.py +56 -0
- moai_adk/foundation/backend.py +1027 -0
- moai_adk/foundation/database.py +1115 -0
- moai_adk/foundation/devops.py +1585 -0
- moai_adk/foundation/ears.py +431 -0
- moai_adk/foundation/frontend.py +870 -0
- moai_adk/foundation/git/commit_templates.py +4 -12
- moai_adk/foundation/git.py +376 -0
- moai_adk/foundation/langs.py +484 -0
- moai_adk/foundation/ml_ops.py +1162 -0
- moai_adk/foundation/testing.py +1524 -0
- moai_adk/foundation/trust/trust_principles.py +23 -72
- moai_adk/foundation/trust/validation_checklist.py +57 -162
- moai_adk/project/__init__.py +0 -0
- moai_adk/project/configuration.py +1084 -0
- moai_adk/project/documentation.py +566 -0
- moai_adk/project/schema.py +447 -0
- moai_adk/statusline/alfred_detector.py +1 -3
- moai_adk/statusline/config.py +13 -4
- moai_adk/statusline/enhanced_output_style_detector.py +23 -15
- moai_adk/statusline/main.py +51 -15
- moai_adk/statusline/renderer.py +104 -48
- moai_adk/statusline/update_checker.py +3 -9
- moai_adk/statusline/version_reader.py +140 -46
- moai_adk/templates/.claude/agents/moai/ai-nano-banana.md +549 -0
- moai_adk/templates/.claude/agents/moai/builder-agent.md +445 -0
- moai_adk/templates/.claude/agents/moai/builder-command.md +1132 -0
- moai_adk/templates/.claude/agents/moai/builder-skill.md +601 -0
- moai_adk/templates/.claude/agents/moai/expert-backend.md +831 -0
- moai_adk/templates/.claude/agents/moai/expert-database.md +774 -0
- moai_adk/templates/.claude/agents/moai/expert-debug.md +396 -0
- moai_adk/templates/.claude/agents/moai/expert-devops.md +711 -0
- moai_adk/templates/.claude/agents/moai/expert-frontend.md +666 -0
- moai_adk/templates/.claude/agents/moai/expert-security.md +474 -0
- moai_adk/templates/.claude/agents/moai/expert-uiux.md +1038 -0
- moai_adk/templates/.claude/agents/moai/manager-claude-code.md +429 -0
- moai_adk/templates/.claude/agents/moai/manager-docs.md +570 -0
- moai_adk/templates/.claude/agents/moai/manager-git.md +937 -0
- moai_adk/templates/.claude/agents/moai/manager-project.md +891 -0
- moai_adk/templates/.claude/agents/moai/manager-quality.md +598 -0
- moai_adk/templates/.claude/agents/moai/manager-spec.md +713 -0
- moai_adk/templates/.claude/agents/moai/manager-strategy.md +600 -0
- moai_adk/templates/.claude/agents/moai/manager-tdd.md +603 -0
- moai_adk/templates/.claude/agents/moai/mcp-context7.md +369 -0
- moai_adk/templates/.claude/agents/moai/mcp-figma.md +1567 -0
- moai_adk/templates/.claude/agents/moai/mcp-notion.md +749 -0
- moai_adk/templates/.claude/agents/moai/mcp-playwright.md +427 -0
- moai_adk/templates/.claude/agents/moai/mcp-sequential-thinking.md +994 -0
- moai_adk/templates/.claude/commands/moai/0-project.md +1143 -0
- moai_adk/templates/.claude/commands/moai/1-plan.md +1435 -0
- moai_adk/templates/.claude/commands/moai/2-run.md +883 -0
- moai_adk/templates/.claude/commands/moai/3-sync.md +993 -0
- moai_adk/templates/.claude/commands/moai/9-feedback.md +314 -0
- moai_adk/templates/.claude/hooks/__init__.py +8 -0
- moai_adk/templates/.claude/hooks/moai/__init__.py +8 -0
- moai_adk/templates/.claude/hooks/moai/lib/__init__.py +85 -0
- moai_adk/templates/.claude/hooks/moai/lib/checkpoint.py +244 -0
- moai_adk/templates/.claude/hooks/moai/lib/common.py +131 -0
- moai_adk/templates/.claude/hooks/moai/lib/config_manager.py +446 -0
- moai_adk/templates/.claude/hooks/moai/lib/config_validator.py +639 -0
- moai_adk/templates/.claude/hooks/moai/lib/example_config.json +104 -0
- moai_adk/templates/.claude/hooks/moai/lib/git_operations_manager.py +590 -0
- moai_adk/templates/.claude/hooks/moai/lib/language_validator.py +317 -0
- moai_adk/templates/.claude/hooks/moai/lib/models.py +102 -0
- moai_adk/templates/.claude/hooks/moai/lib/path_utils.py +28 -0
- moai_adk/templates/.claude/hooks/moai/lib/project.py +768 -0
- moai_adk/templates/.claude/hooks/moai/lib/test_hooks_improvements.py +443 -0
- moai_adk/templates/.claude/hooks/moai/lib/timeout.py +160 -0
- moai_adk/templates/.claude/hooks/moai/lib/unified_timeout_manager.py +530 -0
- moai_adk/templates/.claude/hooks/moai/session_end__auto_cleanup.py +862 -0
- moai_adk/templates/.claude/hooks/moai/session_start__show_project_info.py +921 -0
- moai_adk/templates/.claude/output-styles/moai/r2d2.md +380 -0
- moai_adk/templates/.claude/output-styles/moai/yoda.md +338 -0
- moai_adk/templates/.claude/settings.json +172 -0
- moai_adk/templates/.claude/skills/moai-docs-generation/SKILL.md +247 -0
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/README.md +44 -0
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/api-documentation.md +130 -0
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/code-documentation.md +152 -0
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/multi-format-output.md +178 -0
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/user-guides.md +147 -0
- moai_adk/templates/.claude/skills/moai-domain-backend/SKILL.md +319 -0
- moai_adk/templates/.claude/skills/moai-domain-database/SKILL.md +320 -0
- moai_adk/templates/.claude/skills/moai-domain-database/modules/README.md +53 -0
- moai_adk/templates/.claude/skills/moai-domain-database/modules/mongodb.md +231 -0
- moai_adk/templates/.claude/skills/moai-domain-database/modules/postgresql.md +169 -0
- moai_adk/templates/.claude/skills/moai-domain-database/modules/redis.md +262 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/SKILL.md +496 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/SKILL.md +453 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/examples.md +560 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/modules/accessibility-wcag.md +260 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/modules/component-architecture.md +228 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/modules/design-system-tokens.md +405 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/modules/icon-libraries.md +401 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/modules/theming-system.md +373 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/reference.md +243 -0
- moai_adk/templates/.claude/skills/moai-formats-data/SKILL.md +491 -0
- moai_adk/templates/.claude/skills/moai-formats-data/modules/README.md +98 -0
- moai_adk/templates/.claude/skills/moai-formats-data/modules/SKILL-MODULARIZATION-TEMPLATE.md +278 -0
- moai_adk/templates/.claude/skills/moai-formats-data/modules/caching-performance.md +459 -0
- moai_adk/templates/.claude/skills/moai-formats-data/modules/data-validation.md +485 -0
- moai_adk/templates/.claude/skills/moai-formats-data/modules/json-optimization.md +374 -0
- moai_adk/templates/.claude/skills/moai-formats-data/modules/toon-encoding.md +308 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/SKILL.md +201 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/best-practices-checklist.md +616 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-custom-slash-commands-official.md +729 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-hooks-official.md +560 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-iam-official.md +635 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-memory-official.md +543 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-settings-official.md +663 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-skills-official.md +113 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-sub-agents-official.md +238 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/complete-configuration-guide.md +175 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/skill-examples.md +1674 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/skill-formatting-guide.md +729 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/sub-agents/sub-agent-examples.md +1513 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/sub-agents/sub-agent-formatting-guide.md +1086 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/sub-agents/sub-agent-integration-patterns.md +1100 -0
- moai_adk/templates/.claude/skills/moai-foundation-context/SKILL.md +438 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/SKILL.md +515 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/README.md +296 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/agents-reference.md +346 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/commands-reference.md +432 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/delegation-patterns.md +757 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/execution-rules.md +687 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/modular-system.md +665 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/progressive-disclosure.md +649 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/spec-first-tdd.md +864 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/token-optimization.md +708 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/trust-5-framework.md +981 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/SKILL.md +362 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/examples.md +1232 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/modules/best-practices.md +261 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/modules/integration-patterns.md +194 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/modules/proactive-analysis.md +229 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/modules/trust5-validation.md +169 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/reference.md +1266 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/scripts/quality-gate.sh +668 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/templates/github-actions-quality.yml +481 -0
- moai_adk/templates/.claude/skills/moai-foundation-quality/templates/quality-config.yaml +519 -0
- moai_adk/templates/.claude/skills/moai-integration-mcp/SKILL.md +352 -0
- moai_adk/templates/.claude/skills/moai-integration-mcp/modules/README.md +52 -0
- moai_adk/templates/.claude/skills/moai-integration-mcp/modules/error-handling.md +334 -0
- moai_adk/templates/.claude/skills/moai-integration-mcp/modules/integration-patterns.md +310 -0
- moai_adk/templates/.claude/skills/moai-integration-mcp/modules/security-authentication.md +256 -0
- moai_adk/templates/.claude/skills/moai-integration-mcp/modules/server-architecture.md +253 -0
- moai_adk/templates/.claude/skills/moai-lang-unified/README.md +133 -0
- moai_adk/templates/.claude/skills/moai-lang-unified/SKILL.md +296 -0
- moai_adk/templates/.claude/skills/moai-lang-unified/examples.md +1269 -0
- moai_adk/templates/.claude/skills/moai-lang-unified/reference.md +331 -0
- moai_adk/templates/.claude/skills/moai-library-mermaid/SKILL.md +298 -0
- moai_adk/templates/.claude/skills/moai-library-mermaid/advanced-patterns.md +465 -0
- moai_adk/templates/.claude/skills/moai-library-mermaid/examples.md +270 -0
- moai_adk/templates/.claude/skills/moai-library-mermaid/optimization.md +440 -0
- moai_adk/templates/.claude/skills/moai-library-mermaid/reference.md +228 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/SKILL.md +316 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/advanced-patterns.md +336 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/advanced-deployment-patterns.md +182 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/advanced-patterns.md +17 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/configuration.md +57 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/content-architecture-optimization.md +162 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/deployment.md +52 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/framework-core-configuration.md +186 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/i18n-setup.md +55 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/mdx-components.md +52 -0
- moai_adk/templates/.claude/skills/moai-library-nextra/optimization.md +303 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/SKILL.md +370 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/examples.md +575 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/modules/advanced-patterns.md +394 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/modules/optimization.md +278 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/modules/shadcn-components.md +457 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/modules/shadcn-theming.md +373 -0
- moai_adk/templates/.claude/skills/moai-library-shadcn/reference.md +74 -0
- moai_adk/templates/.claude/skills/moai-platform-baas/README.md +186 -0
- moai_adk/templates/.claude/skills/moai-platform-baas/SKILL.md +290 -0
- moai_adk/templates/.claude/skills/moai-platform-baas/examples.md +1225 -0
- moai_adk/templates/.claude/skills/moai-platform-baas/reference.md +567 -0
- moai_adk/templates/.claude/skills/moai-platform-baas/scripts/provider-selector.py +323 -0
- moai_adk/templates/.claude/skills/moai-platform-baas/templates/stack-config.yaml +204 -0
- moai_adk/templates/.claude/skills/moai-workflow-jit-docs/SKILL.md +446 -0
- moai_adk/templates/.claude/skills/moai-workflow-jit-docs/advanced-patterns.md +379 -0
- moai_adk/templates/.claude/skills/moai-workflow-jit-docs/optimization.md +286 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/README.md +190 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/SKILL.md +387 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/__init__.py +520 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/complete_workflow_demo_fixed.py +574 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/complete_project_setup.py +317 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/complete_workflow_demo.py +663 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/config-migration-example.json +190 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/question-examples.json +135 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/quick_start.py +196 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/__init__.py +17 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/advanced-patterns.md +158 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/ask_user_integration.py +340 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/batch_questions.py +713 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/config_manager.py +538 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/documentation_manager.py +1336 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/language_initializer.py +730 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/migration_manager.py +608 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/template_optimizer.py +1005 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/schemas/config-schema.json +316 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/schemas/tab_schema.json +1362 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/config-template.json +71 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/doc-templates/product-template.md +44 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/doc-templates/structure-template.md +48 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/doc-templates/tech-template.md +71 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/question-templates/config-manager-setup.json +109 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/question-templates/language-initializer.json +228 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/question-templates/menu-project-config.json +130 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/question-templates/project-batch-questions.json +97 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/templates/question-templates/spec-workflow-setup.json +150 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/test_integration_simple.py +436 -0
- moai_adk/templates/.claude/skills/moai-workflow-templates/SKILL.md +374 -0
- moai_adk/templates/.claude/skills/moai-workflow-templates/modules/code-templates.md +124 -0
- moai_adk/templates/.claude/skills/moai-workflow-templates/modules/feedback-templates.md +100 -0
- moai_adk/templates/.claude/skills/moai-workflow-templates/modules/template-optimizer.md +138 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/LICENSE.txt +202 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/SKILL.md +453 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/advanced-patterns.md +576 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/examples/ai-powered-testing.py +294 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/examples/console_logging.py +35 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/examples/element_discovery.py +40 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/examples/static_html_automation.py +34 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/README.md +220 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/ai-debugging.md +845 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review.md +1416 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization.md +1234 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/smart-refactoring.md +1243 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd-context7.md +1260 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/optimization.md +505 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/reference/playwright-best-practices.md +57 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/scripts/with_server.py +218 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/templates/alfred-integration.md +376 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/workflows/enterprise-testing-workflow.py +571 -0
- moai_adk/templates/.claude/skills/moai-worktree/SKILL.md +410 -0
- moai_adk/templates/.claude/skills/moai-worktree/examples.md +606 -0
- moai_adk/templates/.claude/skills/moai-worktree/modules/integration-patterns.md +982 -0
- moai_adk/templates/.claude/skills/moai-worktree/modules/parallel-development.md +778 -0
- moai_adk/templates/.claude/skills/moai-worktree/modules/worktree-commands.md +646 -0
- moai_adk/templates/.claude/skills/moai-worktree/modules/worktree-management.md +782 -0
- moai_adk/templates/.claude/skills/moai-worktree/reference.md +357 -0
- moai_adk/templates/.git-hooks/pre-commit +103 -41
- moai_adk/templates/.git-hooks/pre-push +116 -21
- moai_adk/templates/.github/workflows/ci-universal.yml +513 -0
- moai_adk/templates/.github/workflows/security-secrets-check.yml +179 -0
- moai_adk/templates/.gitignore +184 -44
- moai_adk/templates/.mcp.json +7 -9
- moai_adk/templates/.moai/cache/personalization.json +10 -0
- moai_adk/templates/.moai/config/config.yaml +344 -0
- moai_adk/templates/.moai/config/presets/manual.yaml +28 -0
- moai_adk/templates/.moai/config/presets/personal.yaml +30 -0
- moai_adk/templates/.moai/config/presets/team.yaml +33 -0
- moai_adk/templates/.moai/config/questions/_schema.yaml +79 -0
- moai_adk/templates/.moai/config/questions/tab1-user.yaml +108 -0
- moai_adk/templates/.moai/config/questions/tab2-project.yaml +122 -0
- moai_adk/templates/.moai/config/questions/tab3-git.yaml +542 -0
- moai_adk/templates/.moai/config/questions/tab4-quality.yaml +167 -0
- moai_adk/templates/.moai/config/questions/tab5-system.yaml +152 -0
- moai_adk/templates/.moai/config/sections/git-strategy.yaml +40 -0
- moai_adk/templates/.moai/config/sections/language.yaml +11 -0
- moai_adk/templates/.moai/config/sections/project.yaml +13 -0
- moai_adk/templates/.moai/config/sections/quality.yaml +15 -0
- moai_adk/templates/.moai/config/sections/system.yaml +14 -0
- moai_adk/templates/.moai/config/sections/user.yaml +5 -0
- moai_adk/templates/.moai/config/statusline-config.yaml +86 -0
- moai_adk/templates/.moai/scripts/setup-glm.py +136 -0
- moai_adk/templates/CLAUDE.md +382 -501
- moai_adk/utils/__init__.py +24 -1
- moai_adk/utils/banner.py +7 -10
- moai_adk/utils/common.py +16 -30
- moai_adk/utils/link_validator.py +4 -12
- moai_adk/utils/safe_file_reader.py +2 -6
- moai_adk/utils/timeout.py +160 -0
- moai_adk/utils/toon_utils.py +256 -0
- moai_adk/version.py +22 -0
- moai_adk-0.32.8.dist-info/METADATA +2478 -0
- moai_adk-0.32.8.dist-info/RECORD +396 -0
- {moai_adk-0.25.4.dist-info → moai_adk-0.32.8.dist-info}/WHEEL +1 -1
- {moai_adk-0.25.4.dist-info → moai_adk-0.32.8.dist-info}/entry_points.txt +1 -0
- moai_adk/cli/commands/backup.py +0 -82
- moai_adk/cli/commands/improve_user_experience.py +0 -348
- moai_adk/cli/commands/migrate.py +0 -158
- moai_adk/cli/commands/validate_links.py +0 -118
- moai_adk/templates/.github/workflows/moai-gitflow.yml +0 -413
- moai_adk/templates/.github/workflows/moai-release-create.yml +0 -100
- moai_adk/templates/.github/workflows/moai-release-pipeline.yml +0 -188
- moai_adk/utils/user_experience.py +0 -531
- moai_adk-0.25.4.dist-info/METADATA +0 -2279
- moai_adk-0.25.4.dist-info/RECORD +0 -112
- {moai_adk-0.25.4.dist-info → moai_adk-0.32.8.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,851 @@
|
|
|
1
|
+
"""
|
|
2
|
+
User Behavior Analytics System
|
|
3
|
+
|
|
4
|
+
Analyzes user interactions, patterns, and preferences to provide insights
|
|
5
|
+
for system optimization and user experience improvement.
|
|
6
|
+
|
|
7
|
+
Key Features:
|
|
8
|
+
- User interaction tracking and pattern analysis
|
|
9
|
+
- Command usage frequency and preference analysis
|
|
10
|
+
- Session behavior analysis
|
|
11
|
+
- User preference learning and adaptation
|
|
12
|
+
- Collaboration pattern analysis
|
|
13
|
+
- Productivity metrics and insights
|
|
14
|
+
- User experience optimization recommendations
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
import logging
|
|
19
|
+
import statistics
|
|
20
|
+
import uuid
|
|
21
|
+
from collections import Counter, defaultdict, deque
|
|
22
|
+
from dataclasses import asdict, dataclass, field
|
|
23
|
+
from datetime import datetime, timedelta
|
|
24
|
+
from enum import Enum
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
from typing import Any, Dict, List, Optional, Set
|
|
27
|
+
|
|
28
|
+
# Set up logging
|
|
29
|
+
logger = logging.getLogger(__name__)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class UserActionType(Enum):
|
|
33
|
+
"""Types of user actions tracked"""
|
|
34
|
+
|
|
35
|
+
COMMAND_EXECUTION = "command_execution"
|
|
36
|
+
TOOL_USAGE = "tool_usage"
|
|
37
|
+
FILE_OPERATION = "file_operation"
|
|
38
|
+
ERROR_OCCURRED = "error_occurred"
|
|
39
|
+
HELP_REQUESTED = "help_requested"
|
|
40
|
+
SESSION_START = "session_start"
|
|
41
|
+
SESSION_END = "session_end"
|
|
42
|
+
TASK_COMPLETED = "task_completed"
|
|
43
|
+
PHASE_TRANSITION = "phase_transition"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class SessionState(Enum):
|
|
47
|
+
"""User session states"""
|
|
48
|
+
|
|
49
|
+
ACTIVE = "active"
|
|
50
|
+
IDLE = "idle"
|
|
51
|
+
FOCUSED = "focused"
|
|
52
|
+
STRUGGLING = "struggling"
|
|
53
|
+
PRODUCTIVE = "productive"
|
|
54
|
+
BREAK = "break"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass
|
|
58
|
+
class UserAction:
|
|
59
|
+
"""Single user action event"""
|
|
60
|
+
|
|
61
|
+
timestamp: datetime
|
|
62
|
+
action_type: UserActionType
|
|
63
|
+
user_id: str
|
|
64
|
+
session_id: str
|
|
65
|
+
action_data: Dict[str, Any]
|
|
66
|
+
context: Dict[str, Any] = field(default_factory=dict)
|
|
67
|
+
duration_ms: Optional[float] = None
|
|
68
|
+
success: bool = True
|
|
69
|
+
tags: Set[str] = field(default_factory=set)
|
|
70
|
+
|
|
71
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
72
|
+
"""Convert to dictionary for serialization"""
|
|
73
|
+
return {
|
|
74
|
+
"timestamp": self.timestamp.isoformat(),
|
|
75
|
+
"action_type": self.action_type.value,
|
|
76
|
+
"user_id": self.user_id,
|
|
77
|
+
"session_id": self.session_id,
|
|
78
|
+
"action_data": self.action_data,
|
|
79
|
+
"context": self.context,
|
|
80
|
+
"duration_ms": self.duration_ms,
|
|
81
|
+
"success": self.success,
|
|
82
|
+
"tags": list(self.tags),
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@dataclass
|
|
87
|
+
class UserSession:
|
|
88
|
+
"""User session information"""
|
|
89
|
+
|
|
90
|
+
session_id: str
|
|
91
|
+
user_id: str
|
|
92
|
+
start_time: datetime
|
|
93
|
+
end_time: Optional[datetime] = None
|
|
94
|
+
actions: List[UserAction] = field(default_factory=list)
|
|
95
|
+
state: SessionState = SessionState.ACTIVE
|
|
96
|
+
productivity_score: float = 0.0
|
|
97
|
+
total_commands: int = 0
|
|
98
|
+
total_errors: int = 0
|
|
99
|
+
total_duration_ms: float = 0.0
|
|
100
|
+
working_directory: str = ""
|
|
101
|
+
git_branch: str = ""
|
|
102
|
+
modified_files: Set[str] = field(default_factory=set)
|
|
103
|
+
tools_used: Set[str] = field(default_factory=set)
|
|
104
|
+
|
|
105
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
106
|
+
"""Convert to dictionary for serialization"""
|
|
107
|
+
return {
|
|
108
|
+
"session_id": self.session_id,
|
|
109
|
+
"user_id": self.user_id,
|
|
110
|
+
"start_time": self.start_time.isoformat(),
|
|
111
|
+
"end_time": self.end_time.isoformat() if self.end_time else None,
|
|
112
|
+
"state": self.state.value,
|
|
113
|
+
"productivity_score": self.productivity_score,
|
|
114
|
+
"total_commands": self.total_commands,
|
|
115
|
+
"total_errors": self.total_errors,
|
|
116
|
+
"total_duration_ms": self.total_duration_ms,
|
|
117
|
+
"working_directory": self.working_directory,
|
|
118
|
+
"git_branch": self.git_branch,
|
|
119
|
+
"modified_files": list(self.modified_files),
|
|
120
|
+
"tools_used": list(self.tools_used),
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@dataclass
|
|
125
|
+
class UserPreferences:
|
|
126
|
+
"""Learned user preferences and patterns"""
|
|
127
|
+
|
|
128
|
+
user_id: str
|
|
129
|
+
preferred_commands: Dict[str, int] = field(default_factory=dict)
|
|
130
|
+
preferred_tools: Dict[str, int] = field(default_factory=dict)
|
|
131
|
+
working_hours: Dict[str, int] = field(default_factory=dict)
|
|
132
|
+
peak_productivity_times: List[str] = field(default_factory=list)
|
|
133
|
+
common_workflows: List[List[str]] = field(default_factory=list)
|
|
134
|
+
error_patterns: List[str] = field(default_factory=list)
|
|
135
|
+
success_patterns: List[str] = field(default_factory=list)
|
|
136
|
+
collaboration_patterns: Dict[str, int] = field(default_factory=dict)
|
|
137
|
+
last_updated: datetime = field(default_factory=datetime.now)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class UserBehaviorAnalytics:
|
|
141
|
+
"""Main user behavior analytics system"""
|
|
142
|
+
|
|
143
|
+
def __init__(self, storage_path: Optional[Path] = None):
|
|
144
|
+
self.storage_path = storage_path or Path.cwd() / ".moai" / "analytics" / "user_behavior"
|
|
145
|
+
self.storage_path.mkdir(parents=True, exist_ok=True)
|
|
146
|
+
|
|
147
|
+
# Data storage
|
|
148
|
+
self.user_sessions: Dict[str, UserSession] = {}
|
|
149
|
+
self.active_sessions: Dict[str, UserSession] = {}
|
|
150
|
+
self.user_preferences: Dict[str, UserPreferences] = {}
|
|
151
|
+
self.action_history: deque = deque(maxlen=10000)
|
|
152
|
+
|
|
153
|
+
# Analysis caches
|
|
154
|
+
self._pattern_cache: Dict[str, Any] = {}
|
|
155
|
+
self._insight_cache: Dict[str, Any] = {}
|
|
156
|
+
self._last_cache_update = datetime.now()
|
|
157
|
+
|
|
158
|
+
# Load existing data
|
|
159
|
+
self._load_data()
|
|
160
|
+
|
|
161
|
+
def track_action(
|
|
162
|
+
self,
|
|
163
|
+
action_type: UserActionType,
|
|
164
|
+
user_id: str,
|
|
165
|
+
session_id: str,
|
|
166
|
+
action_data: Dict[str, Any],
|
|
167
|
+
context: Optional[Dict[str, Any]] = None,
|
|
168
|
+
duration_ms: Optional[float] = None,
|
|
169
|
+
success: bool = True,
|
|
170
|
+
) -> None:
|
|
171
|
+
"""Track a user action"""
|
|
172
|
+
action = UserAction(
|
|
173
|
+
timestamp=datetime.now(),
|
|
174
|
+
action_type=action_type,
|
|
175
|
+
user_id=user_id,
|
|
176
|
+
session_id=session_id,
|
|
177
|
+
action_data=action_data,
|
|
178
|
+
context=context or {},
|
|
179
|
+
duration_ms=duration_ms,
|
|
180
|
+
success=success,
|
|
181
|
+
tags=self._extract_action_tags(action_type, action_data),
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
# Store action
|
|
185
|
+
self.action_history.append(action)
|
|
186
|
+
|
|
187
|
+
# Update session if active
|
|
188
|
+
if session_id in self.active_sessions:
|
|
189
|
+
session = self.active_sessions[session_id]
|
|
190
|
+
session.actions.append(action)
|
|
191
|
+
|
|
192
|
+
# Update session metrics
|
|
193
|
+
if action_type == UserActionType.COMMAND_EXECUTION:
|
|
194
|
+
session.total_commands += 1
|
|
195
|
+
if not success:
|
|
196
|
+
session.total_errors += 1
|
|
197
|
+
|
|
198
|
+
# Track tools used
|
|
199
|
+
if "tool" in action_data:
|
|
200
|
+
session.tools_used.add(action_data["tool"])
|
|
201
|
+
|
|
202
|
+
# Track file modifications
|
|
203
|
+
if "files" in action_data:
|
|
204
|
+
session.modified_files.update(action_data["files"])
|
|
205
|
+
|
|
206
|
+
if duration_ms:
|
|
207
|
+
session.total_duration_ms += duration_ms
|
|
208
|
+
|
|
209
|
+
# Update session state
|
|
210
|
+
session.state = self._analyze_session_state(session)
|
|
211
|
+
|
|
212
|
+
# Update user preferences
|
|
213
|
+
self._update_user_preferences(user_id, action)
|
|
214
|
+
|
|
215
|
+
# Clear caches periodically
|
|
216
|
+
if (datetime.now() - self._last_cache_update).seconds > 300:
|
|
217
|
+
self._pattern_cache.clear()
|
|
218
|
+
self._insight_cache.clear()
|
|
219
|
+
self._last_cache_update = datetime.now()
|
|
220
|
+
|
|
221
|
+
def start_session(self, user_id: str, working_directory: str = "", git_branch: str = "") -> str:
|
|
222
|
+
"""Start tracking a new user session"""
|
|
223
|
+
session_id = str(uuid.uuid4())
|
|
224
|
+
|
|
225
|
+
session = UserSession(
|
|
226
|
+
session_id=session_id,
|
|
227
|
+
user_id=user_id,
|
|
228
|
+
start_time=datetime.now(),
|
|
229
|
+
working_directory=working_directory,
|
|
230
|
+
git_branch=git_branch,
|
|
231
|
+
state=SessionState.ACTIVE,
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
self.active_sessions[session_id] = session
|
|
235
|
+
self.user_sessions[session_id] = session
|
|
236
|
+
|
|
237
|
+
# Track session start action
|
|
238
|
+
self.track_action(
|
|
239
|
+
UserActionType.SESSION_START,
|
|
240
|
+
user_id,
|
|
241
|
+
session_id,
|
|
242
|
+
{"working_directory": working_directory, "git_branch": git_branch},
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
return session_id
|
|
246
|
+
|
|
247
|
+
def end_session(self, session_id: str) -> Optional[UserSession]:
|
|
248
|
+
"""End a user session"""
|
|
249
|
+
if session_id not in self.active_sessions:
|
|
250
|
+
return None
|
|
251
|
+
|
|
252
|
+
session = self.active_sessions[session_id]
|
|
253
|
+
session.end_time = datetime.now()
|
|
254
|
+
|
|
255
|
+
# Calculate final productivity score
|
|
256
|
+
session.productivity_score = self._calculate_productivity_score(session)
|
|
257
|
+
|
|
258
|
+
# Move from active to completed sessions
|
|
259
|
+
del self.active_sessions[session_id]
|
|
260
|
+
|
|
261
|
+
# Track session end action
|
|
262
|
+
self.track_action(
|
|
263
|
+
UserActionType.SESSION_END,
|
|
264
|
+
session.user_id,
|
|
265
|
+
session_id,
|
|
266
|
+
{
|
|
267
|
+
"duration_ms": session.total_duration_ms,
|
|
268
|
+
"commands": session.total_commands,
|
|
269
|
+
"errors": session.total_errors,
|
|
270
|
+
"productivity_score": session.productivity_score,
|
|
271
|
+
},
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
# Save data periodically
|
|
275
|
+
self._save_data()
|
|
276
|
+
|
|
277
|
+
return session
|
|
278
|
+
|
|
279
|
+
def get_user_patterns(self, user_id: str, days: int = 30) -> Dict[str, Any]:
|
|
280
|
+
"""Get user behavior patterns and insights"""
|
|
281
|
+
cache_key = f"patterns_{user_id}_{days}"
|
|
282
|
+
|
|
283
|
+
if cache_key in self._pattern_cache:
|
|
284
|
+
return self._pattern_cache[cache_key]
|
|
285
|
+
|
|
286
|
+
cutoff_date = datetime.now() - timedelta(days=days)
|
|
287
|
+
|
|
288
|
+
# Get user sessions in the time range
|
|
289
|
+
user_sessions = [
|
|
290
|
+
session
|
|
291
|
+
for session in self.user_sessions.values()
|
|
292
|
+
if session.user_id == user_id and session.start_time >= cutoff_date
|
|
293
|
+
]
|
|
294
|
+
|
|
295
|
+
# Analyze patterns
|
|
296
|
+
patterns = {
|
|
297
|
+
"session_count": len(user_sessions),
|
|
298
|
+
"avg_session_duration": 0.0,
|
|
299
|
+
"avg_productivity_score": 0.0,
|
|
300
|
+
"most_used_commands": {},
|
|
301
|
+
"most_used_tools": {},
|
|
302
|
+
"peak_productivity_hours": [],
|
|
303
|
+
"common_workflows": [],
|
|
304
|
+
"error_patterns": [],
|
|
305
|
+
"working_preferences": {},
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if user_sessions:
|
|
309
|
+
# Session metrics
|
|
310
|
+
durations = [s.total_duration_ms for s in user_sessions if s.total_duration_ms > 0]
|
|
311
|
+
productivity_scores = [s.productivity_score for s in user_sessions if s.productivity_score > 0]
|
|
312
|
+
|
|
313
|
+
if durations:
|
|
314
|
+
patterns["avg_session_duration"] = statistics.mean(durations)
|
|
315
|
+
if productivity_scores:
|
|
316
|
+
patterns["avg_productivity_score"] = statistics.mean(productivity_scores)
|
|
317
|
+
|
|
318
|
+
# Command usage
|
|
319
|
+
all_commands = []
|
|
320
|
+
all_tools = []
|
|
321
|
+
|
|
322
|
+
for session in user_sessions:
|
|
323
|
+
for action in session.actions:
|
|
324
|
+
if action.action_type == UserActionType.COMMAND_EXECUTION:
|
|
325
|
+
if "command" in action.action_data:
|
|
326
|
+
all_commands.append(action.action_data["command"])
|
|
327
|
+
if "tool" in action.action_data:
|
|
328
|
+
all_tools.append(action.action_data["tool"])
|
|
329
|
+
|
|
330
|
+
patterns["most_used_commands"] = dict(Counter(all_commands).most_common(10))
|
|
331
|
+
patterns["most_used_tools"] = dict(Counter(all_tools).most_common(10))
|
|
332
|
+
|
|
333
|
+
# Peak productivity hours
|
|
334
|
+
hour_productivity = defaultdict(list)
|
|
335
|
+
|
|
336
|
+
for session in user_sessions:
|
|
337
|
+
hour_productivity[session.start_time.hour].append(session.productivity_score)
|
|
338
|
+
|
|
339
|
+
avg_hourly_productivity = {
|
|
340
|
+
hour: statistics.mean(scores) if scores else 0 for hour, scores in hour_productivity.items()
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
# Top 3 most productive hours
|
|
344
|
+
top_hours = sorted(avg_hourly_productivity.items(), key=lambda x: x[1], reverse=True)[:3]
|
|
345
|
+
patterns["peak_productivity_hours"] = [f"{hour:02d}:00" for hour, _ in top_hours]
|
|
346
|
+
|
|
347
|
+
# Cache results
|
|
348
|
+
self._pattern_cache[cache_key] = patterns
|
|
349
|
+
|
|
350
|
+
return patterns
|
|
351
|
+
|
|
352
|
+
def get_user_insights(self, user_id: str, days: int = 7) -> Dict[str, Any]:
|
|
353
|
+
"""Get actionable insights and recommendations for a user"""
|
|
354
|
+
cache_key = f"insights_{user_id}_{days}"
|
|
355
|
+
|
|
356
|
+
if cache_key in self._insight_cache:
|
|
357
|
+
return self._insight_cache[cache_key]
|
|
358
|
+
|
|
359
|
+
patterns = self.get_user_patterns(user_id, days)
|
|
360
|
+
|
|
361
|
+
insights: Dict[str, Any] = {
|
|
362
|
+
"productivity_insights": [],
|
|
363
|
+
"efficiency_recommendations": [],
|
|
364
|
+
"collaboration_insights": [],
|
|
365
|
+
"learning_opportunities": [],
|
|
366
|
+
"tool_recommendations": [],
|
|
367
|
+
"workflow_optimizations": [],
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
# Productivity insights
|
|
371
|
+
if patterns["avg_productivity_score"] > 80:
|
|
372
|
+
insights["productivity_insights"].append(
|
|
373
|
+
"Excellent productivity score! User consistently performs at high level."
|
|
374
|
+
)
|
|
375
|
+
elif patterns["avg_productivity_score"] < 50:
|
|
376
|
+
insights["productivity_insights"].append(
|
|
377
|
+
"Productivity score could be improved. Consider workflow optimization."
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
# Session duration insights
|
|
381
|
+
if patterns["avg_session_duration"] > 1800000: # > 30 minutes
|
|
382
|
+
insights["productivity_insights"].append(
|
|
383
|
+
"Long session durations detected. Consider taking regular breaks for sustained productivity."
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
# Error pattern analysis
|
|
387
|
+
recent_actions = [
|
|
388
|
+
action
|
|
389
|
+
for action in self.action_history
|
|
390
|
+
if action.user_id == user_id and action.timestamp >= datetime.now() - timedelta(days=days)
|
|
391
|
+
]
|
|
392
|
+
|
|
393
|
+
error_actions = [
|
|
394
|
+
action
|
|
395
|
+
for action in recent_actions
|
|
396
|
+
if action.action_type == UserActionType.ERROR_OCCURRED or not action.success
|
|
397
|
+
]
|
|
398
|
+
|
|
399
|
+
if len(error_actions) > len(recent_actions) * 0.1: # > 10% error rate
|
|
400
|
+
insights["efficiency_recommendations"].append(
|
|
401
|
+
"High error rate detected. Consider additional training or tool familiarization."
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
# Tool usage insights
|
|
405
|
+
if patterns["most_used_tools"]:
|
|
406
|
+
top_tool = max(patterns["most_used_tools"].items(), key=lambda x: x[1])
|
|
407
|
+
insights["tool_recommendations"].append(f"Most frequently used tool: {top_tool[0]} ({top_tool[1]} uses)")
|
|
408
|
+
|
|
409
|
+
# Command pattern insights
|
|
410
|
+
if patterns["most_used_commands"]:
|
|
411
|
+
commands = list(patterns["most_used_commands"].keys())
|
|
412
|
+
if "/moai:" in " ".join(commands[:3]): # Top 3 commands
|
|
413
|
+
insights["workflow_optimizations"].append(
|
|
414
|
+
"Heavy MoAI command usage detected. Consider learning keyboard shortcuts for faster workflow."
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
# Peak productivity insights
|
|
418
|
+
if patterns["peak_productivity_hours"]:
|
|
419
|
+
peak_hours = ", ".join(patterns["peak_productivity_hours"])
|
|
420
|
+
insights["efficiency_recommendations"].append(
|
|
421
|
+
f"Peak productivity hours: {peak_hours}. Schedule important work during these times."
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
# Learning opportunities
|
|
425
|
+
if patterns["session_count"] < 5:
|
|
426
|
+
insights["learning_opportunities"].append(
|
|
427
|
+
"Consider more frequent sessions to build momentum and consistency."
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
# Cache results
|
|
431
|
+
self._insight_cache[cache_key] = insights
|
|
432
|
+
|
|
433
|
+
return insights
|
|
434
|
+
|
|
435
|
+
def get_team_analytics(self, days: int = 30) -> Dict[str, Any]:
|
|
436
|
+
"""Get team-wide analytics and collaboration patterns"""
|
|
437
|
+
cutoff_date = datetime.now() - timedelta(days=days)
|
|
438
|
+
|
|
439
|
+
# Get all sessions in time range
|
|
440
|
+
recent_sessions = [session for session in self.user_sessions.values() if session.start_time >= cutoff_date]
|
|
441
|
+
|
|
442
|
+
# Aggregate metrics
|
|
443
|
+
team_metrics = {
|
|
444
|
+
"total_sessions": len(recent_sessions),
|
|
445
|
+
"unique_users": len(set(s.user_id for s in recent_sessions)),
|
|
446
|
+
"avg_session_duration": 0.0,
|
|
447
|
+
"avg_productivity_score": 0.0,
|
|
448
|
+
"most_active_users": {},
|
|
449
|
+
"most_used_tools": {},
|
|
450
|
+
"collaboration_patterns": {},
|
|
451
|
+
"productivity_distribution": {},
|
|
452
|
+
"peak_hours": {},
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if recent_sessions:
|
|
456
|
+
# Calculate averages
|
|
457
|
+
durations = [s.total_duration_ms for s in recent_sessions if s.total_duration_ms > 0]
|
|
458
|
+
scores = [s.productivity_score for s in recent_sessions if s.productivity_score > 0]
|
|
459
|
+
|
|
460
|
+
if durations:
|
|
461
|
+
team_metrics["avg_session_duration"] = statistics.mean(durations)
|
|
462
|
+
if scores:
|
|
463
|
+
team_metrics["avg_productivity_score"] = statistics.mean(scores)
|
|
464
|
+
|
|
465
|
+
# Most active users
|
|
466
|
+
user_session_counts = Counter(s.user_id for s in recent_sessions)
|
|
467
|
+
team_metrics["most_active_users"] = dict(user_session_counts.most_common(10))
|
|
468
|
+
|
|
469
|
+
# Most used tools across team
|
|
470
|
+
all_tools: List[str] = []
|
|
471
|
+
for session in recent_sessions:
|
|
472
|
+
all_tools.extend(session.tools_used)
|
|
473
|
+
|
|
474
|
+
team_metrics["most_used_tools"] = dict(Counter(all_tools).most_common(10))
|
|
475
|
+
|
|
476
|
+
# Productivity distribution
|
|
477
|
+
productivity_ranges = {
|
|
478
|
+
"0-20": 0,
|
|
479
|
+
"21-40": 0,
|
|
480
|
+
"41-60": 0,
|
|
481
|
+
"61-80": 0,
|
|
482
|
+
"81-100": 0,
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
for score in scores:
|
|
486
|
+
if score <= 20:
|
|
487
|
+
productivity_ranges["0-20"] += 1
|
|
488
|
+
elif score <= 40:
|
|
489
|
+
productivity_ranges["21-40"] += 1
|
|
490
|
+
elif score <= 60:
|
|
491
|
+
productivity_ranges["41-60"] += 1
|
|
492
|
+
elif score <= 80:
|
|
493
|
+
productivity_ranges["61-80"] += 1
|
|
494
|
+
else:
|
|
495
|
+
productivity_ranges["81-100"] += 1
|
|
496
|
+
|
|
497
|
+
team_metrics["productivity_distribution"] = productivity_ranges
|
|
498
|
+
|
|
499
|
+
return team_metrics
|
|
500
|
+
|
|
501
|
+
def _extract_action_tags(self, action_type: UserActionType, action_data: Dict[str, Any]) -> Set[str]:
|
|
502
|
+
"""Extract relevant tags from action data"""
|
|
503
|
+
tags = {action_type.value}
|
|
504
|
+
|
|
505
|
+
# Extract tool tags
|
|
506
|
+
if "tool" in action_data:
|
|
507
|
+
tags.add(f"tool:{action_data['tool']}")
|
|
508
|
+
|
|
509
|
+
# Extract command tags
|
|
510
|
+
if "command" in action_data:
|
|
511
|
+
command = action_data["command"]
|
|
512
|
+
if "/moai:" in command:
|
|
513
|
+
tags.add("moai_command")
|
|
514
|
+
if "git" in command.lower():
|
|
515
|
+
tags.add("git_operation")
|
|
516
|
+
|
|
517
|
+
# Extract phase tags
|
|
518
|
+
if "phase" in action_data:
|
|
519
|
+
tags.add(f"phase:{action_data['phase']}")
|
|
520
|
+
|
|
521
|
+
# Extract success/failure tags
|
|
522
|
+
if "success" in action_data:
|
|
523
|
+
tags.add("success" if action_data["success"] else "failure")
|
|
524
|
+
|
|
525
|
+
return tags
|
|
526
|
+
|
|
527
|
+
def _update_user_preferences(self, user_id: str, action: UserAction) -> None:
|
|
528
|
+
"""Update learned user preferences based on actions"""
|
|
529
|
+
if user_id not in self.user_preferences:
|
|
530
|
+
self.user_preferences[user_id] = UserPreferences(user_id=user_id)
|
|
531
|
+
|
|
532
|
+
prefs = self.user_preferences[user_id]
|
|
533
|
+
|
|
534
|
+
# Update command preferences
|
|
535
|
+
if action.action_type == UserActionType.COMMAND_EXECUTION:
|
|
536
|
+
command = action.action_data.get("command", "")
|
|
537
|
+
if command:
|
|
538
|
+
prefs.preferred_commands[command] = prefs.preferred_commands.get(command, 0) + 1
|
|
539
|
+
|
|
540
|
+
# Update tool preferences
|
|
541
|
+
if "tool" in action.action_data:
|
|
542
|
+
tool = action.action_data["tool"]
|
|
543
|
+
prefs.preferred_tools[tool] = prefs.preferred_tools.get(tool, 0) + 1
|
|
544
|
+
|
|
545
|
+
# Update working hours
|
|
546
|
+
hour = action.timestamp.hour
|
|
547
|
+
prefs.working_hours[str(hour)] = prefs.working_hours.get(str(hour), 0) + 1
|
|
548
|
+
|
|
549
|
+
# Update patterns based on success/failure
|
|
550
|
+
if action.success:
|
|
551
|
+
pattern_key = f"{action.action_type.value}_{action.action_data}"
|
|
552
|
+
if pattern_key not in prefs.success_patterns:
|
|
553
|
+
prefs.success_patterns.append(pattern_key)
|
|
554
|
+
else:
|
|
555
|
+
pattern_key = f"{action.action_type.value}_{action.action_data}"
|
|
556
|
+
if pattern_key not in prefs.error_patterns:
|
|
557
|
+
prefs.error_patterns.append(pattern_key)
|
|
558
|
+
|
|
559
|
+
prefs.last_updated = datetime.now()
|
|
560
|
+
|
|
561
|
+
def _analyze_session_state(self, session: UserSession) -> SessionState:
|
|
562
|
+
"""Analyze and determine current session state"""
|
|
563
|
+
if not session.actions:
|
|
564
|
+
return SessionState.ACTIVE
|
|
565
|
+
|
|
566
|
+
recent_actions = [
|
|
567
|
+
action
|
|
568
|
+
for action in session.actions[-10:] # Last 10 actions
|
|
569
|
+
if (datetime.now() - action.timestamp).seconds < 300 # Last 5 minutes
|
|
570
|
+
]
|
|
571
|
+
|
|
572
|
+
if not recent_actions:
|
|
573
|
+
return SessionState.IDLE
|
|
574
|
+
|
|
575
|
+
# Calculate metrics
|
|
576
|
+
error_rate = sum(1 for action in recent_actions if not action.success) / len(recent_actions)
|
|
577
|
+
|
|
578
|
+
durations_with_ms = [a.duration_ms for a in recent_actions if a.duration_ms is not None]
|
|
579
|
+
avg_duration = statistics.mean(durations_with_ms) if durations_with_ms else 0
|
|
580
|
+
|
|
581
|
+
# Determine state
|
|
582
|
+
if error_rate > 0.5:
|
|
583
|
+
return SessionState.STRUGGLING
|
|
584
|
+
elif avg_duration > 10000 and error_rate < 0.1:
|
|
585
|
+
return SessionState.PRODUCTIVE
|
|
586
|
+
elif error_rate < 0.1 and len(recent_actions) > 5:
|
|
587
|
+
return SessionState.FOCUSED
|
|
588
|
+
else:
|
|
589
|
+
return SessionState.ACTIVE
|
|
590
|
+
|
|
591
|
+
def _calculate_productivity_score(self, session: UserSession) -> float:
|
|
592
|
+
"""Calculate productivity score for a session (0-100)"""
|
|
593
|
+
if not session.actions:
|
|
594
|
+
return 0.0
|
|
595
|
+
|
|
596
|
+
# Base score from success rate
|
|
597
|
+
successful_actions = sum(1 for action in session.actions if action.success)
|
|
598
|
+
success_rate = successful_actions / len(session.actions)
|
|
599
|
+
base_score = success_rate * 50
|
|
600
|
+
|
|
601
|
+
# Duration factor (optimal session duration)
|
|
602
|
+
duration_hours = session.total_duration_ms / (1000 * 60 * 60)
|
|
603
|
+
duration_factor = 0
|
|
604
|
+
|
|
605
|
+
if 0.5 <= duration_hours <= 4: # Optimal 30 min to 4 hours
|
|
606
|
+
duration_factor = 25
|
|
607
|
+
elif duration_hours > 0.25: # At least 15 minutes
|
|
608
|
+
duration_factor = 15
|
|
609
|
+
|
|
610
|
+
# Tool diversity factor
|
|
611
|
+
tool_diversity = min(len(session.tools_used) / 10, 1) * 15
|
|
612
|
+
|
|
613
|
+
# File modifications factor (if it's a coding session)
|
|
614
|
+
file_factor: float = 0.0
|
|
615
|
+
if session.modified_files:
|
|
616
|
+
file_factor = min(len(session.modified_files) / 5, 1) * 10
|
|
617
|
+
|
|
618
|
+
total_score = base_score + duration_factor + tool_diversity + file_factor
|
|
619
|
+
return min(total_score, 100.0)
|
|
620
|
+
|
|
621
|
+
def _load_data(self) -> None:
|
|
622
|
+
"""Load stored analytics data"""
|
|
623
|
+
try:
|
|
624
|
+
# Load user preferences
|
|
625
|
+
prefs_file = self.storage_path / "user_preferences.json"
|
|
626
|
+
if prefs_file.exists():
|
|
627
|
+
with open(prefs_file, "r") as f:
|
|
628
|
+
prefs_data = json.load(f)
|
|
629
|
+
|
|
630
|
+
for user_id, prefs_dict in prefs_data.items():
|
|
631
|
+
prefs = UserPreferences(user_id=user_id)
|
|
632
|
+
prefs.preferred_commands = prefs_dict.get("preferred_commands", {})
|
|
633
|
+
prefs.preferred_tools = prefs_dict.get("preferred_tools", {})
|
|
634
|
+
prefs.working_hours = prefs_dict.get("working_hours", {})
|
|
635
|
+
prefs.peak_productivity_times = prefs_dict.get("peak_productivity_times", [])
|
|
636
|
+
prefs.common_workflows = prefs_dict.get("common_workflows", [])
|
|
637
|
+
prefs.error_patterns = prefs_dict.get("error_patterns", [])
|
|
638
|
+
prefs.success_patterns = prefs_dict.get("success_patterns", [])
|
|
639
|
+
prefs.collaboration_patterns = prefs_dict.get("collaboration_patterns", {})
|
|
640
|
+
|
|
641
|
+
if prefs_dict.get("last_updated"):
|
|
642
|
+
prefs.last_updated = datetime.fromisoformat(prefs_dict["last_updated"])
|
|
643
|
+
|
|
644
|
+
self.user_preferences[user_id] = prefs
|
|
645
|
+
|
|
646
|
+
logger.info(f"Loaded preferences for {len(self.user_preferences)} users")
|
|
647
|
+
|
|
648
|
+
except Exception as e:
|
|
649
|
+
logger.error(f"Error loading analytics data: {e}")
|
|
650
|
+
|
|
651
|
+
def _save_data(self) -> None:
|
|
652
|
+
"""Save analytics data to storage"""
|
|
653
|
+
try:
|
|
654
|
+
# Save user preferences
|
|
655
|
+
prefs_data = {}
|
|
656
|
+
for user_id, prefs in self.user_preferences.items():
|
|
657
|
+
prefs_data[user_id] = {
|
|
658
|
+
"preferred_commands": prefs.preferred_commands,
|
|
659
|
+
"preferred_tools": prefs.preferred_tools,
|
|
660
|
+
"working_hours": prefs.working_hours,
|
|
661
|
+
"peak_productivity_times": prefs.peak_productivity_times,
|
|
662
|
+
"common_workflows": prefs.common_workflows,
|
|
663
|
+
"error_patterns": prefs.error_patterns,
|
|
664
|
+
"success_patterns": prefs.success_patterns,
|
|
665
|
+
"collaboration_patterns": prefs.collaboration_patterns,
|
|
666
|
+
"last_updated": prefs.last_updated.isoformat(),
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
prefs_file = self.storage_path / "user_preferences.json"
|
|
670
|
+
with open(prefs_file, "w") as f:
|
|
671
|
+
json.dump(prefs_data, f, indent=2)
|
|
672
|
+
|
|
673
|
+
logger.info(f"Saved preferences for {len(self.user_preferences)} users")
|
|
674
|
+
|
|
675
|
+
except Exception as e:
|
|
676
|
+
logger.error(f"Error saving analytics data: {e}")
|
|
677
|
+
|
|
678
|
+
def export_data(self, output_path: Path, user_id: Optional[str] = None) -> bool:
|
|
679
|
+
"""Export analytics data to file"""
|
|
680
|
+
try:
|
|
681
|
+
export_data = {
|
|
682
|
+
"export_timestamp": datetime.now().isoformat(),
|
|
683
|
+
"user_id": user_id or "all_users",
|
|
684
|
+
"data": {},
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
if user_id:
|
|
688
|
+
# Export single user data
|
|
689
|
+
patterns = self.get_user_patterns(user_id)
|
|
690
|
+
insights = self.get_user_insights(user_id)
|
|
691
|
+
prefs = self.user_preferences.get(user_id)
|
|
692
|
+
|
|
693
|
+
export_data["data"] = {
|
|
694
|
+
"patterns": patterns,
|
|
695
|
+
"insights": insights,
|
|
696
|
+
"preferences": asdict(prefs) if prefs else None,
|
|
697
|
+
}
|
|
698
|
+
else:
|
|
699
|
+
# Export team data
|
|
700
|
+
export_data["data"] = {
|
|
701
|
+
"team_analytics": self.get_team_analytics(),
|
|
702
|
+
"user_count": len(self.user_preferences),
|
|
703
|
+
"session_count": len(self.user_sessions),
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
with open(output_path, "w") as f:
|
|
707
|
+
json.dump(export_data, f, indent=2)
|
|
708
|
+
|
|
709
|
+
return True
|
|
710
|
+
|
|
711
|
+
except Exception as e:
|
|
712
|
+
logger.error(f"Error exporting data: {e}")
|
|
713
|
+
return False
|
|
714
|
+
|
|
715
|
+
def get_realtime_metrics(self, user_id: Optional[str] = None) -> Dict[str, Any]:
|
|
716
|
+
"""Get real-time analytics metrics"""
|
|
717
|
+
current_time = datetime.now()
|
|
718
|
+
|
|
719
|
+
metrics: Dict[str, Any] = {
|
|
720
|
+
"timestamp": current_time.isoformat(),
|
|
721
|
+
"active_sessions": len(self.active_sessions),
|
|
722
|
+
"total_sessions_today": 0,
|
|
723
|
+
"avg_session_duration": 0.0,
|
|
724
|
+
"current_productivity_scores": [],
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
today_start = current_time.replace(hour=0, minute=0, second=0, microsecond=0)
|
|
728
|
+
|
|
729
|
+
# Filter sessions and calculate metrics
|
|
730
|
+
today_sessions = [session for session in self.user_sessions.values() if session.start_time >= today_start]
|
|
731
|
+
|
|
732
|
+
metrics["total_sessions_today"] = len(today_sessions)
|
|
733
|
+
|
|
734
|
+
if today_sessions:
|
|
735
|
+
durations = [s.total_duration_ms for s in today_sessions if s.total_duration_ms > 0]
|
|
736
|
+
if durations:
|
|
737
|
+
metrics["avg_session_duration"] = statistics.mean(durations)
|
|
738
|
+
|
|
739
|
+
# Current productivity scores
|
|
740
|
+
productivity_scores: List[Dict[str, Any]] = []
|
|
741
|
+
for session in self.active_sessions.values():
|
|
742
|
+
if user_id is None or session.user_id == user_id:
|
|
743
|
+
current_score = self._calculate_productivity_score(session)
|
|
744
|
+
productivity_scores.append(
|
|
745
|
+
{
|
|
746
|
+
"user_id": session.user_id,
|
|
747
|
+
"session_id": session.session_id,
|
|
748
|
+
"score": current_score,
|
|
749
|
+
"state": session.state.value,
|
|
750
|
+
}
|
|
751
|
+
)
|
|
752
|
+
metrics["current_productivity_scores"] = productivity_scores
|
|
753
|
+
|
|
754
|
+
return metrics
|
|
755
|
+
|
|
756
|
+
|
|
757
|
+
# Global instance for easy access
|
|
758
|
+
_user_analytics: Optional[UserBehaviorAnalytics] = None
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
def get_user_analytics() -> UserBehaviorAnalytics:
|
|
762
|
+
"""Get or create global user behavior analytics instance"""
|
|
763
|
+
global _user_analytics
|
|
764
|
+
if _user_analytics is None:
|
|
765
|
+
_user_analytics = UserBehaviorAnalytics()
|
|
766
|
+
return _user_analytics
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
# Convenience functions
|
|
770
|
+
def track_user_action(
|
|
771
|
+
action_type: UserActionType,
|
|
772
|
+
user_id: str,
|
|
773
|
+
session_id: str,
|
|
774
|
+
action_data: Dict[str, Any],
|
|
775
|
+
context: Optional[Dict[str, Any]] = None,
|
|
776
|
+
duration_ms: Optional[float] = None,
|
|
777
|
+
success: bool = True,
|
|
778
|
+
) -> None:
|
|
779
|
+
"""Track a user action"""
|
|
780
|
+
analytics = get_user_analytics()
|
|
781
|
+
analytics.track_action(action_type, user_id, session_id, action_data, context, duration_ms, success)
|
|
782
|
+
|
|
783
|
+
|
|
784
|
+
def start_user_session(user_id: str, working_directory: str = "", git_branch: str = "") -> str:
|
|
785
|
+
"""Start tracking a user session"""
|
|
786
|
+
analytics = get_user_analytics()
|
|
787
|
+
return analytics.start_session(user_id, working_directory, git_branch)
|
|
788
|
+
|
|
789
|
+
|
|
790
|
+
def end_user_session(session_id: str) -> Optional[UserSession]:
|
|
791
|
+
"""End a user session"""
|
|
792
|
+
analytics = get_user_analytics()
|
|
793
|
+
return analytics.end_session(session_id)
|
|
794
|
+
|
|
795
|
+
|
|
796
|
+
def get_user_patterns(user_id: str, days: int = 30) -> Dict[str, Any]:
|
|
797
|
+
"""Get user behavior patterns"""
|
|
798
|
+
analytics = get_user_analytics()
|
|
799
|
+
return analytics.get_user_patterns(user_id, days)
|
|
800
|
+
|
|
801
|
+
|
|
802
|
+
def get_user_insights(user_id: str, days: int = 7) -> Dict[str, Any]:
|
|
803
|
+
"""Get user insights and recommendations"""
|
|
804
|
+
analytics = get_user_analytics()
|
|
805
|
+
return analytics.get_user_insights(user_id, days)
|
|
806
|
+
|
|
807
|
+
|
|
808
|
+
if __name__ == "__main__":
|
|
809
|
+
# Example usage
|
|
810
|
+
print("Testing User Behavior Analytics...")
|
|
811
|
+
|
|
812
|
+
analytics = UserBehaviorAnalytics()
|
|
813
|
+
|
|
814
|
+
# Simulate user session
|
|
815
|
+
user_id = "test_user"
|
|
816
|
+
session_id = analytics.start_session(user_id, "/Users/goos/MoAI/MoAI-ADK", "main")
|
|
817
|
+
|
|
818
|
+
# Track some actions
|
|
819
|
+
analytics.track_action(
|
|
820
|
+
UserActionType.COMMAND_EXECUTION,
|
|
821
|
+
user_id,
|
|
822
|
+
session_id,
|
|
823
|
+
{"command": "/moai:1-plan test feature", "tool": "spec_builder"},
|
|
824
|
+
duration_ms=1500,
|
|
825
|
+
success=True,
|
|
826
|
+
)
|
|
827
|
+
|
|
828
|
+
analytics.track_action(
|
|
829
|
+
UserActionType.TOOL_USAGE,
|
|
830
|
+
user_id,
|
|
831
|
+
session_id,
|
|
832
|
+
{"tool": "git", "operation": "commit"},
|
|
833
|
+
duration_ms=800,
|
|
834
|
+
success=True,
|
|
835
|
+
)
|
|
836
|
+
|
|
837
|
+
# End session
|
|
838
|
+
ended_session = analytics.end_session(session_id)
|
|
839
|
+
|
|
840
|
+
if ended_session:
|
|
841
|
+
print("Session completed:")
|
|
842
|
+
print(f" Duration: {ended_session.total_duration_ms / 1000:.1f} seconds")
|
|
843
|
+
print(f" Commands: {ended_session.total_commands}")
|
|
844
|
+
print(f" Productivity Score: {ended_session.productivity_score}")
|
|
845
|
+
print(f" Tools Used: {list(ended_session.tools_used)}")
|
|
846
|
+
|
|
847
|
+
# Get patterns
|
|
848
|
+
patterns = analytics.get_user_patterns(user_id, days=1)
|
|
849
|
+
print(f"User patterns: {patterns}")
|
|
850
|
+
|
|
851
|
+
print("User Behavior Analytics test completed!")
|