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,1005 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MoAI Menu Project - Template Optimizer Module
|
|
3
|
+
|
|
4
|
+
Advanced template analysis, optimization, and performance management system.
|
|
5
|
+
Integrates patterns from moai-project-template-optimizer skill with
|
|
6
|
+
intelligent analysis and automated optimization capabilities.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import re
|
|
11
|
+
import shutil
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any, Dict, List, Tuple
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TemplateOptimizer:
|
|
18
|
+
"""Advanced template optimization and performance analysis system."""
|
|
19
|
+
|
|
20
|
+
def __init__(self, project_root: str, config: Dict[str, Any]):
|
|
21
|
+
self.project_root = Path(project_root)
|
|
22
|
+
self.config = config
|
|
23
|
+
self.templates_dir = self.project_root / ".claude/skills/moai-menu-project/templates"
|
|
24
|
+
self.backups_dir = self.project_root / ".moai-backups"
|
|
25
|
+
self.optimization_cache = {}
|
|
26
|
+
self._ensure_directories()
|
|
27
|
+
|
|
28
|
+
def _ensure_directories(self):
|
|
29
|
+
"""Ensure all necessary directories exist."""
|
|
30
|
+
self.templates_dir.mkdir(parents=True, exist_ok=True)
|
|
31
|
+
self.backups_dir.mkdir(parents=True, exist_ok=True)
|
|
32
|
+
(self.templates_dir / "optimized").mkdir(exist_ok=True)
|
|
33
|
+
(self.templates_dir / "benchmarks").mkdir(exist_ok=True)
|
|
34
|
+
|
|
35
|
+
def analyze_project_templates(self) -> Dict[str, Any]:
|
|
36
|
+
"""
|
|
37
|
+
Perform comprehensive analysis of project templates.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
Analysis results with performance metrics and optimization recommendations
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
analysis_result = {
|
|
44
|
+
"timestamp": datetime.now().isoformat(),
|
|
45
|
+
"project_root": str(self.project_root),
|
|
46
|
+
"template_files": [],
|
|
47
|
+
"performance_metrics": {},
|
|
48
|
+
"optimization_opportunities": [],
|
|
49
|
+
"backup_recommendations": [],
|
|
50
|
+
"complexity_analysis": {},
|
|
51
|
+
"resource_usage": {},
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# Discover template files
|
|
55
|
+
template_files = self._discover_template_files()
|
|
56
|
+
analysis_result["template_files"] = template_files
|
|
57
|
+
|
|
58
|
+
# Analyze each template file
|
|
59
|
+
for template_file in template_files:
|
|
60
|
+
file_analysis = self._analyze_template_file(template_file)
|
|
61
|
+
analysis_result["performance_metrics"][template_file["path"]] = file_analysis
|
|
62
|
+
|
|
63
|
+
# Identify optimization opportunities
|
|
64
|
+
analysis_result["optimization_opportunities"] = self._identify_optimization_opportunities(
|
|
65
|
+
analysis_result["performance_metrics"]
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Analyze overall project complexity
|
|
69
|
+
analysis_result["complexity_analysis"] = self._analyze_project_complexity(template_files)
|
|
70
|
+
|
|
71
|
+
# Calculate resource usage patterns
|
|
72
|
+
analysis_result["resource_usage"] = self._calculate_resource_usage(template_files)
|
|
73
|
+
|
|
74
|
+
# Generate backup recommendations
|
|
75
|
+
analysis_result["backup_recommendations"] = self._generate_backup_recommendations(analysis_result)
|
|
76
|
+
|
|
77
|
+
return analysis_result
|
|
78
|
+
|
|
79
|
+
def _discover_template_files(self) -> List[Dict[str, Any]]:
|
|
80
|
+
"""Discover all template files in the project."""
|
|
81
|
+
|
|
82
|
+
template_files = []
|
|
83
|
+
|
|
84
|
+
# Common template file patterns
|
|
85
|
+
template_patterns = [
|
|
86
|
+
"**/*.template",
|
|
87
|
+
"**/*.tmpl",
|
|
88
|
+
"**/*.mustache",
|
|
89
|
+
"**/*.hbs",
|
|
90
|
+
"**/*.handlebars",
|
|
91
|
+
"**/*.jinja",
|
|
92
|
+
"**/*.jinja2",
|
|
93
|
+
"**/*.erb",
|
|
94
|
+
"**/*.liquid",
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
# Search for template files
|
|
98
|
+
for pattern in template_patterns:
|
|
99
|
+
for file_path in self.project_root.glob(pattern):
|
|
100
|
+
if file_path.is_file():
|
|
101
|
+
relative_path = file_path.relative_to(self.project_root)
|
|
102
|
+
|
|
103
|
+
# Calculate file metrics
|
|
104
|
+
file_stats = file_path.stat()
|
|
105
|
+
|
|
106
|
+
template_files.append(
|
|
107
|
+
{
|
|
108
|
+
"path": str(relative_path),
|
|
109
|
+
"absolute_path": str(file_path),
|
|
110
|
+
"size_bytes": file_stats.st_size,
|
|
111
|
+
"modified_time": datetime.fromtimestamp(file_stats.st_mtime).isoformat(),
|
|
112
|
+
"type": self._determine_template_type(file_path),
|
|
113
|
+
"language": self._determine_template_language(file_path),
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Also check common template directories
|
|
118
|
+
template_dirs = [
|
|
119
|
+
"templates",
|
|
120
|
+
"template",
|
|
121
|
+
"views",
|
|
122
|
+
"layouts",
|
|
123
|
+
"_layouts",
|
|
124
|
+
"_includes",
|
|
125
|
+
"_templates",
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
for template_dir in template_dirs:
|
|
129
|
+
dir_path = self.project_root / template_dir
|
|
130
|
+
if dir_path.exists() and dir_path.is_dir():
|
|
131
|
+
for file_path in dir_path.rglob("*"):
|
|
132
|
+
if file_path.is_file() and file_path.suffix in [
|
|
133
|
+
".md",
|
|
134
|
+
".html",
|
|
135
|
+
".txt",
|
|
136
|
+
".yml",
|
|
137
|
+
".yaml",
|
|
138
|
+
".json",
|
|
139
|
+
]:
|
|
140
|
+
# Check if file contains template markers
|
|
141
|
+
content = file_path.read_text(encoding="utf-8", errors="ignore")
|
|
142
|
+
if self._contains_template_markers(content):
|
|
143
|
+
relative_path = file_path.relative_to(self.project_root)
|
|
144
|
+
file_stats = file_path.stat()
|
|
145
|
+
|
|
146
|
+
template_files.append(
|
|
147
|
+
{
|
|
148
|
+
"path": str(relative_path),
|
|
149
|
+
"absolute_path": str(file_path),
|
|
150
|
+
"size_bytes": file_stats.st_size,
|
|
151
|
+
"modified_time": datetime.fromtimestamp(file_stats.st_mtime).isoformat(),
|
|
152
|
+
"type": "content_template",
|
|
153
|
+
"language": "text",
|
|
154
|
+
}
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
return sorted(template_files, key=lambda x: x["path"])
|
|
158
|
+
|
|
159
|
+
def _determine_template_type(self, file_path: Path) -> str:
|
|
160
|
+
"""Determine template type based on file extension and content."""
|
|
161
|
+
|
|
162
|
+
extension_map = {
|
|
163
|
+
".mustache": "mustache",
|
|
164
|
+
".hbs": "handlebars",
|
|
165
|
+
".handlebars": "handlebars",
|
|
166
|
+
".jinja": "jinja",
|
|
167
|
+
".jinja2": "jinja2",
|
|
168
|
+
".erb": "erb",
|
|
169
|
+
".liquid": "liquid",
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return extension_map.get(file_path.suffix.lower(), "unknown")
|
|
173
|
+
|
|
174
|
+
def _determine_template_language(self, file_path: Path) -> str:
|
|
175
|
+
"""Determine the primary language used in template."""
|
|
176
|
+
|
|
177
|
+
try:
|
|
178
|
+
content = file_path.read_text(encoding="utf-8", errors="ignore")
|
|
179
|
+
|
|
180
|
+
# Look for language-specific markers
|
|
181
|
+
if any(marker in content for marker in ["{{", "{%", "{#"]):
|
|
182
|
+
return "jinja"
|
|
183
|
+
elif any(marker in content for marker in ["{{", "{{#", "{{/"]):
|
|
184
|
+
return "handlebars"
|
|
185
|
+
elif any(marker in content for marker in ["<%", "<%=", "<%-"]):
|
|
186
|
+
return "erb"
|
|
187
|
+
elif any(marker in content for marker in ["{{ ", "{% ", "{{-"]):
|
|
188
|
+
return "liquid"
|
|
189
|
+
else:
|
|
190
|
+
return "text"
|
|
191
|
+
|
|
192
|
+
except (UnicodeDecodeError, OSError):
|
|
193
|
+
return "binary"
|
|
194
|
+
|
|
195
|
+
def _contains_template_markers(self, content: str) -> bool:
|
|
196
|
+
"""Check if content contains template markers."""
|
|
197
|
+
|
|
198
|
+
template_markers = [
|
|
199
|
+
"{{",
|
|
200
|
+
"}}", # Generic template markers
|
|
201
|
+
"{%",
|
|
202
|
+
"%}", # Jinja-like
|
|
203
|
+
"{{#",
|
|
204
|
+
"{{/", # Handlebars-like
|
|
205
|
+
"<%",
|
|
206
|
+
"%>", # ERB-like
|
|
207
|
+
"{{-",
|
|
208
|
+
"-}}", # Liquid-like
|
|
209
|
+
"{#",
|
|
210
|
+
"#}", # Comment markers
|
|
211
|
+
"[[",
|
|
212
|
+
"]]", # Angular-like
|
|
213
|
+
"${",
|
|
214
|
+
"}", # Variable interpolation
|
|
215
|
+
]
|
|
216
|
+
|
|
217
|
+
return any(marker in content for marker in template_markers)
|
|
218
|
+
|
|
219
|
+
def _analyze_template_file(self, template_file: Dict[str, Any]) -> Dict[str, Any]:
|
|
220
|
+
"""Analyze individual template file for performance and complexity."""
|
|
221
|
+
|
|
222
|
+
file_path = Path(template_file["absolute_path"])
|
|
223
|
+
|
|
224
|
+
analysis = {
|
|
225
|
+
"file_path": template_file["path"],
|
|
226
|
+
"size_metrics": self._analyze_file_size(file_path),
|
|
227
|
+
"complexity_metrics": self._analyze_template_complexity(file_path),
|
|
228
|
+
"performance_metrics": self._estimate_template_performance(file_path),
|
|
229
|
+
"optimization_potential": 0,
|
|
230
|
+
"recommendations": [],
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
# Calculate overall optimization potential
|
|
234
|
+
analysis["optimization_potential"] = self._calculate_optimization_potential(analysis)
|
|
235
|
+
|
|
236
|
+
# Generate specific recommendations
|
|
237
|
+
analysis["recommendations"] = self._generate_file_recommendations(analysis)
|
|
238
|
+
|
|
239
|
+
return analysis
|
|
240
|
+
|
|
241
|
+
def _analyze_file_size(self, file_path: Path) -> Dict[str, Any]:
|
|
242
|
+
"""Analyze file size and content metrics."""
|
|
243
|
+
|
|
244
|
+
try:
|
|
245
|
+
content = file_path.read_text(encoding="utf-8")
|
|
246
|
+
|
|
247
|
+
lines = content.splitlines()
|
|
248
|
+
|
|
249
|
+
return {
|
|
250
|
+
"total_size_bytes": len(content.encode("utf-8")),
|
|
251
|
+
"character_count": len(content),
|
|
252
|
+
"line_count": len(lines),
|
|
253
|
+
"blank_lines": sum(1 for line in lines if not line.strip()),
|
|
254
|
+
"average_line_length": (sum(len(line) for line in lines) / len(lines) if lines else 0),
|
|
255
|
+
"max_line_length": max(len(line) for line in lines) if lines else 0,
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
except (UnicodeDecodeError, OSError):
|
|
259
|
+
return {
|
|
260
|
+
"total_size_bytes": file_path.stat().st_size,
|
|
261
|
+
"character_count": 0,
|
|
262
|
+
"line_count": 0,
|
|
263
|
+
"blank_lines": 0,
|
|
264
|
+
"average_line_length": 0,
|
|
265
|
+
"max_line_length": 0,
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
def _analyze_template_complexity(self, file_path: Path) -> Dict[str, Any]:
|
|
269
|
+
"""Analyze template complexity metrics."""
|
|
270
|
+
|
|
271
|
+
try:
|
|
272
|
+
content = file_path.read_text(encoding="utf-8", errors="ignore")
|
|
273
|
+
|
|
274
|
+
complexity = {
|
|
275
|
+
"variable_count": 0,
|
|
276
|
+
"loop_count": 0,
|
|
277
|
+
"conditional_count": 0,
|
|
278
|
+
"include_count": 0,
|
|
279
|
+
"nested_level_max": 0,
|
|
280
|
+
"template_depth": 0,
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
# Count different template constructs
|
|
284
|
+
complexity["variable_count"] = len(re.findall(r"\{\{[^}]+\}\}", content))
|
|
285
|
+
complexity["loop_count"] = len(re.findall(r"\{%\s*for\s+.+\s+in\s+.+%\}", content))
|
|
286
|
+
complexity["conditional_count"] = len(re.findall(r"\{%\s*if\s+.+%\}", content))
|
|
287
|
+
complexity["include_count"] = len(re.findall(r"\{%\s*(include|extend|import)\s+.+%\}", content))
|
|
288
|
+
|
|
289
|
+
# Calculate nesting level
|
|
290
|
+
current_level = 0
|
|
291
|
+
max_level = 0
|
|
292
|
+
|
|
293
|
+
for char in content:
|
|
294
|
+
if char == "{":
|
|
295
|
+
if content[content.index(char) : content.index(char) + 2] in [
|
|
296
|
+
"{{",
|
|
297
|
+
"{%",
|
|
298
|
+
]:
|
|
299
|
+
current_level += 1
|
|
300
|
+
max_level = max(max_level, current_level)
|
|
301
|
+
elif char == "}":
|
|
302
|
+
if current_level > 0:
|
|
303
|
+
current_level -= 1
|
|
304
|
+
|
|
305
|
+
complexity["nested_level_max"] = max_level
|
|
306
|
+
complexity["template_depth"] = self._calculate_template_depth(content)
|
|
307
|
+
|
|
308
|
+
except (UnicodeDecodeError, OSError):
|
|
309
|
+
complexity = {
|
|
310
|
+
"variable_count": 0,
|
|
311
|
+
"loop_count": 0,
|
|
312
|
+
"conditional_count": 0,
|
|
313
|
+
"include_count": 0,
|
|
314
|
+
"nested_level_max": 0,
|
|
315
|
+
"template_depth": 0,
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return complexity
|
|
319
|
+
|
|
320
|
+
def _calculate_template_depth(self, content: str) -> int:
|
|
321
|
+
"""Calculate template inheritance depth."""
|
|
322
|
+
|
|
323
|
+
# Look for extends, include, import statements
|
|
324
|
+
depth_patterns = [
|
|
325
|
+
r'\{%\s*extends\s+["\']([^"\']+)["\']\s*%\}',
|
|
326
|
+
r'\{%\s*include\s+["\']([^"\']+)["\']\s*%\}',
|
|
327
|
+
r'\{%\s*import\s+["\']([^"\']+)["\']\s*%\}',
|
|
328
|
+
]
|
|
329
|
+
|
|
330
|
+
depth = 0
|
|
331
|
+
for pattern in depth_patterns:
|
|
332
|
+
matches = re.findall(pattern, content)
|
|
333
|
+
depth += len(matches)
|
|
334
|
+
|
|
335
|
+
return min(depth, 10) # Cap at reasonable maximum
|
|
336
|
+
|
|
337
|
+
def _estimate_template_performance(self, file_path: Path) -> Dict[str, Any]:
|
|
338
|
+
"""Estimate template rendering performance."""
|
|
339
|
+
|
|
340
|
+
size_analysis = self._analyze_file_size(file_path)
|
|
341
|
+
complexity_analysis = self._analyze_template_complexity(file_path)
|
|
342
|
+
|
|
343
|
+
performance = {
|
|
344
|
+
"estimated_render_time_ms": 0,
|
|
345
|
+
"memory_usage_estimate_kb": 0,
|
|
346
|
+
"cpu_intensity": "low",
|
|
347
|
+
"cache_friendly": True,
|
|
348
|
+
"render_complexity_score": 0,
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
# Basic performance estimation based on size and complexity
|
|
352
|
+
base_time = 1.0 # Base render time in ms
|
|
353
|
+
|
|
354
|
+
# Add time for complexity
|
|
355
|
+
complexity_time = (
|
|
356
|
+
complexity_analysis["variable_count"] * 0.1
|
|
357
|
+
+ complexity_analysis["loop_count"] * 2.0
|
|
358
|
+
+ complexity_analysis["conditional_count"] * 0.5
|
|
359
|
+
+ complexity_analysis["include_count"] * 1.0
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
# Add time for file size
|
|
363
|
+
size_time = size_analysis["total_size_bytes"] / 10000 # 10KB per ms
|
|
364
|
+
|
|
365
|
+
performance["estimated_render_time_ms"] = base_time + complexity_time + size_time
|
|
366
|
+
|
|
367
|
+
# Estimate memory usage
|
|
368
|
+
performance["memory_usage_estimate_kb"] = size_analysis["total_size_bytes"] / 1024
|
|
369
|
+
|
|
370
|
+
# Determine CPU intensity
|
|
371
|
+
if performance["estimated_render_time_ms"] > 100:
|
|
372
|
+
performance["cpu_intensity"] = "high"
|
|
373
|
+
elif performance["estimated_render_time_ms"] > 50:
|
|
374
|
+
performance["cpu_intensity"] = "medium"
|
|
375
|
+
else:
|
|
376
|
+
performance["cpu_intensity"] = "low"
|
|
377
|
+
|
|
378
|
+
# Check cache friendliness
|
|
379
|
+
performance["cache_friendly"] = (
|
|
380
|
+
complexity_analysis["variable_count"] < 50
|
|
381
|
+
and complexity_analysis["loop_count"] < 10
|
|
382
|
+
and performance["estimated_render_time_ms"] < 100
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
# Calculate render complexity score
|
|
386
|
+
performance["render_complexity_score"] = (
|
|
387
|
+
complexity_analysis["variable_count"] * 1
|
|
388
|
+
+ complexity_analysis["loop_count"] * 3
|
|
389
|
+
+ complexity_analysis["conditional_count"] * 2
|
|
390
|
+
+ complexity_analysis["nested_level_max"] * 4
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
return performance
|
|
394
|
+
|
|
395
|
+
def _calculate_optimization_potential(self, file_analysis: Dict[str, Any]) -> float:
|
|
396
|
+
"""Calculate optimization potential score (0-100)."""
|
|
397
|
+
|
|
398
|
+
potential = 0.0
|
|
399
|
+
|
|
400
|
+
# Size-based potential
|
|
401
|
+
size_metrics = file_analysis["size_metrics"]
|
|
402
|
+
if size_metrics["total_size_bytes"] > 50000: # 50KB
|
|
403
|
+
potential += 20
|
|
404
|
+
elif size_metrics["total_size_bytes"] > 20000: # 20KB
|
|
405
|
+
potential += 10
|
|
406
|
+
|
|
407
|
+
# Complexity-based potential
|
|
408
|
+
complexity_metrics = file_analysis["complexity_metrics"]
|
|
409
|
+
if complexity_metrics["nested_level_max"] > 5:
|
|
410
|
+
potential += 15
|
|
411
|
+
elif complexity_metrics["nested_level_max"] > 3:
|
|
412
|
+
potential += 8
|
|
413
|
+
|
|
414
|
+
if complexity_metrics["variable_count"] > 100:
|
|
415
|
+
potential += 10
|
|
416
|
+
elif complexity_metrics["variable_count"] > 50:
|
|
417
|
+
potential += 5
|
|
418
|
+
|
|
419
|
+
# Performance-based potential
|
|
420
|
+
performance_metrics = file_analysis["performance_metrics"]
|
|
421
|
+
if performance_metrics["estimated_render_time_ms"] > 100:
|
|
422
|
+
potential += 20
|
|
423
|
+
elif performance_metrics["estimated_render_time_ms"] > 50:
|
|
424
|
+
potential += 10
|
|
425
|
+
|
|
426
|
+
if not performance_metrics["cache_friendly"]:
|
|
427
|
+
potential += 15
|
|
428
|
+
|
|
429
|
+
return min(potential, 100) # Cap at 100
|
|
430
|
+
|
|
431
|
+
def _generate_file_recommendations(self, file_analysis: Dict[str, Any]) -> List[str]:
|
|
432
|
+
"""Generate optimization recommendations for a file."""
|
|
433
|
+
|
|
434
|
+
recommendations = []
|
|
435
|
+
|
|
436
|
+
size_metrics = file_analysis["size_metrics"]
|
|
437
|
+
complexity_metrics = file_analysis["complexity_metrics"]
|
|
438
|
+
performance_metrics = file_analysis["performance_metrics"]
|
|
439
|
+
|
|
440
|
+
# Size recommendations
|
|
441
|
+
if size_metrics["total_size_bytes"] > 50000:
|
|
442
|
+
recommendations.append("Consider splitting large template into smaller components")
|
|
443
|
+
|
|
444
|
+
if size_metrics["max_line_length"] > 200:
|
|
445
|
+
recommendations.append("Break long lines for better readability")
|
|
446
|
+
|
|
447
|
+
# Complexity recommendations
|
|
448
|
+
if complexity_metrics["nested_level_max"] > 5:
|
|
449
|
+
recommendations.append("Reduce nesting level by extracting sub-templates")
|
|
450
|
+
|
|
451
|
+
if complexity_metrics["variable_count"] > 100:
|
|
452
|
+
recommendations.append("Consider consolidating related variables")
|
|
453
|
+
|
|
454
|
+
if complexity_metrics["loop_count"] > 10:
|
|
455
|
+
recommendations.append("Optimize loops and consider pagination for large datasets")
|
|
456
|
+
|
|
457
|
+
# Performance recommendations
|
|
458
|
+
if performance_metrics["estimated_render_time_ms"] > 100:
|
|
459
|
+
recommendations.append("Implement template caching for better performance")
|
|
460
|
+
|
|
461
|
+
if not performance_metrics["cache_friendly"]:
|
|
462
|
+
recommendations.append("Restructure template for better cache efficiency")
|
|
463
|
+
|
|
464
|
+
if performance_metrics["cpu_intensity"] == "high":
|
|
465
|
+
recommendations.append("Consider moving complex logic to template filters or functions")
|
|
466
|
+
|
|
467
|
+
return recommendations
|
|
468
|
+
|
|
469
|
+
def _identify_optimization_opportunities(self, performance_metrics: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
470
|
+
"""Identify global optimization opportunities across all templates."""
|
|
471
|
+
|
|
472
|
+
opportunities = []
|
|
473
|
+
|
|
474
|
+
# Analyze patterns across all files
|
|
475
|
+
total_files = len(performance_metrics)
|
|
476
|
+
if total_files == 0:
|
|
477
|
+
return opportunities
|
|
478
|
+
|
|
479
|
+
# Calculate aggregate metrics
|
|
480
|
+
total_size = sum(metrics["size_metrics"]["total_size_bytes"] for metrics in performance_metrics.values())
|
|
481
|
+
avg_render_time = (
|
|
482
|
+
sum(metrics["performance_metrics"]["estimated_render_time_ms"] for metrics in performance_metrics.values())
|
|
483
|
+
/ total_files
|
|
484
|
+
)
|
|
485
|
+
high_complexity_files = sum(
|
|
486
|
+
1 for metrics in performance_metrics.values() if metrics["complexity_metrics"]["nested_level_max"] > 3
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
# Size optimization opportunities
|
|
490
|
+
if total_size > 100000: # 100KB total
|
|
491
|
+
opportunities.append(
|
|
492
|
+
{
|
|
493
|
+
"type": "size_optimization",
|
|
494
|
+
"priority": "high",
|
|
495
|
+
"description": f"Large total template size ({total_size / 1024:.1f}KB)",
|
|
496
|
+
"recommendation": "Consider consolidating shared templates and removing unused content",
|
|
497
|
+
"estimated_impact": "15-25% reduction in load time",
|
|
498
|
+
}
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
# Performance optimization opportunities
|
|
502
|
+
if avg_render_time > 50:
|
|
503
|
+
opportunities.append(
|
|
504
|
+
{
|
|
505
|
+
"type": "performance_optimization",
|
|
506
|
+
"priority": "medium",
|
|
507
|
+
"description": f"Average render time is high ({avg_render_time:.1f}ms)",
|
|
508
|
+
"recommendation": "Implement template caching and optimize complex templates",
|
|
509
|
+
"estimated_impact": "20-40% improvement in render time",
|
|
510
|
+
}
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
# Complexity optimization opportunities
|
|
514
|
+
if high_complexity_files > total_files * 0.3: # More than 30% files are complex
|
|
515
|
+
opportunities.append(
|
|
516
|
+
{
|
|
517
|
+
"type": "complexity_optimization",
|
|
518
|
+
"priority": "medium",
|
|
519
|
+
"description": f"High complexity in {high_complexity_files} of {total_files} templates",
|
|
520
|
+
"recommendation": "Extract complex logic into template filters and reduce nesting",
|
|
521
|
+
"estimated_impact": "Improved maintainability and 10-20% performance gain",
|
|
522
|
+
}
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
# Template reuse opportunities
|
|
526
|
+
template_types = {}
|
|
527
|
+
for metrics in performance_metrics.values():
|
|
528
|
+
file_path = Path(metrics["file_path"])
|
|
529
|
+
template_type = file_path.suffix
|
|
530
|
+
template_types[template_type] = template_types.get(template_type, 0) + 1
|
|
531
|
+
|
|
532
|
+
common_types = [t for t, count in template_types.items() if count > 3]
|
|
533
|
+
if common_types:
|
|
534
|
+
opportunities.append(
|
|
535
|
+
{
|
|
536
|
+
"type": "template_reuse",
|
|
537
|
+
"priority": "low",
|
|
538
|
+
"description": f"Multiple templates of type: {', '.join(common_types)}",
|
|
539
|
+
"recommendation": "Create base templates and use template inheritance",
|
|
540
|
+
"estimated_impact": "Reduced duplication and easier maintenance",
|
|
541
|
+
}
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
return sorted(
|
|
545
|
+
opportunities,
|
|
546
|
+
key=lambda x: {"high": 3, "medium": 2, "low": 1}.get(x["priority"], 0),
|
|
547
|
+
reverse=True,
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
def _analyze_project_complexity(self, template_files: List[Dict[str, Any]]) -> Dict[str, Any]:
|
|
551
|
+
"""Analyze overall project template complexity."""
|
|
552
|
+
|
|
553
|
+
complexity_analysis = {
|
|
554
|
+
"total_files": len(template_files),
|
|
555
|
+
"total_size_bytes": sum(f["size_bytes"] for f in template_files),
|
|
556
|
+
"file_types": {},
|
|
557
|
+
"template_languages": {},
|
|
558
|
+
"average_file_size": 0,
|
|
559
|
+
"complexity_distribution": {"low": 0, "medium": 0, "high": 0},
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
if template_files:
|
|
563
|
+
complexity_analysis["average_file_size"] = complexity_analysis["total_size_bytes"] / len(template_files)
|
|
564
|
+
|
|
565
|
+
# Analyze file types
|
|
566
|
+
for template_file in template_files:
|
|
567
|
+
file_type = template_file["type"]
|
|
568
|
+
complexity_analysis["file_types"][file_type] = complexity_analysis["file_types"].get(file_type, 0) + 1
|
|
569
|
+
|
|
570
|
+
lang = template_file["language"]
|
|
571
|
+
complexity_analysis["template_languages"][lang] = complexity_analysis["template_languages"].get(lang, 0) + 1
|
|
572
|
+
|
|
573
|
+
return complexity_analysis
|
|
574
|
+
|
|
575
|
+
def _calculate_resource_usage(self, template_files: List[Dict[str, Any]]) -> Dict[str, Any]:
|
|
576
|
+
"""Calculate resource usage patterns and predictions."""
|
|
577
|
+
|
|
578
|
+
resource_usage = {
|
|
579
|
+
"disk_usage": {
|
|
580
|
+
"total_bytes": sum(f["size_bytes"] for f in template_files),
|
|
581
|
+
"average_file_size": 0,
|
|
582
|
+
"largest_file": None,
|
|
583
|
+
},
|
|
584
|
+
"memory_estimates": {"peak_usage_kb": 0, "average_usage_kb": 0},
|
|
585
|
+
"performance_predictions": {
|
|
586
|
+
"concurrent_render_support": 0,
|
|
587
|
+
"recommended_cache_size_mb": 0,
|
|
588
|
+
},
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
if template_files:
|
|
592
|
+
resource_usage["disk_usage"]["average_file_size"] = resource_usage["disk_usage"]["total_bytes"] / len(
|
|
593
|
+
template_files
|
|
594
|
+
)
|
|
595
|
+
resource_usage["disk_usage"]["largest_file"] = max(template_files, key=lambda f: f["size_bytes"])["path"]
|
|
596
|
+
|
|
597
|
+
# Estimate memory usage (rough approximation: 3x file size for processing)
|
|
598
|
+
total_size_kb = resource_usage["disk_usage"]["total_bytes"] / 1024
|
|
599
|
+
resource_usage["memory_estimates"]["average_usage_kb"] = total_size_kb * 3
|
|
600
|
+
resource_usage["memory_estimates"]["peak_usage_kb"] = total_size_kb * 5
|
|
601
|
+
|
|
602
|
+
# Performance predictions
|
|
603
|
+
avg_file_size_kb = resource_usage["disk_usage"]["average_file_size"] / 1024
|
|
604
|
+
resource_usage["performance_predictions"]["concurrent_render_support"] = int(
|
|
605
|
+
1000 / (avg_file_size_kb + 10)
|
|
606
|
+
) # Rough estimate
|
|
607
|
+
resource_usage["performance_predictions"]["recommended_cache_size_mb"] = max(1, int(total_size_kb / 1024))
|
|
608
|
+
|
|
609
|
+
return resource_usage
|
|
610
|
+
|
|
611
|
+
def _generate_backup_recommendations(self, analysis_result: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
612
|
+
"""Generate backup recommendations based on analysis."""
|
|
613
|
+
|
|
614
|
+
recommendations = []
|
|
615
|
+
|
|
616
|
+
template_count = len(analysis_result["template_files"])
|
|
617
|
+
total_size = analysis_result["complexity_analysis"]["total_size_bytes"]
|
|
618
|
+
optimization_opportunities = analysis_result["optimization_opportunities"]
|
|
619
|
+
|
|
620
|
+
# Create backup if optimization opportunities exist
|
|
621
|
+
if optimization_opportunities:
|
|
622
|
+
high_priority_ops = [op for op in optimization_opportunities if op["priority"] == "high"]
|
|
623
|
+
|
|
624
|
+
if high_priority_ops:
|
|
625
|
+
recommendations.append(
|
|
626
|
+
{
|
|
627
|
+
"type": "pre_optimization_backup",
|
|
628
|
+
"priority": "high",
|
|
629
|
+
"description": "Create backup before applying optimizations",
|
|
630
|
+
"reason": "High-impact optimizations detected",
|
|
631
|
+
"backup_size_estimate": total_size,
|
|
632
|
+
"recommended_backup_name": f"backup-{datetime.now().strftime('%Y-%m-%d')}-pre-optimization",
|
|
633
|
+
}
|
|
634
|
+
)
|
|
635
|
+
|
|
636
|
+
# Regular backup recommendations
|
|
637
|
+
if template_count > 10:
|
|
638
|
+
recommendations.append(
|
|
639
|
+
{
|
|
640
|
+
"type": "regular_backup",
|
|
641
|
+
"priority": "medium",
|
|
642
|
+
"description": "Regular backup recommended for large template collections",
|
|
643
|
+
"reason": f"{template_count} template files detected",
|
|
644
|
+
"backup_frequency": "weekly",
|
|
645
|
+
}
|
|
646
|
+
)
|
|
647
|
+
|
|
648
|
+
# Version control recommendations
|
|
649
|
+
if not (self.project_root / ".git").exists():
|
|
650
|
+
recommendations.append(
|
|
651
|
+
{
|
|
652
|
+
"type": "version_control",
|
|
653
|
+
"priority": "low",
|
|
654
|
+
"description": "Consider using Git for template version control",
|
|
655
|
+
"reason": "No version control system detected",
|
|
656
|
+
"suggested_action": "Initialize Git repository",
|
|
657
|
+
}
|
|
658
|
+
)
|
|
659
|
+
|
|
660
|
+
return recommendations
|
|
661
|
+
|
|
662
|
+
def create_optimized_templates(self, optimization_options: Dict[str, Any] = None) -> Dict[str, Any]:
|
|
663
|
+
"""
|
|
664
|
+
Create optimized versions of templates.
|
|
665
|
+
|
|
666
|
+
Args:
|
|
667
|
+
optimization_options: Options for optimization process
|
|
668
|
+
|
|
669
|
+
Returns:
|
|
670
|
+
Optimization results and created files
|
|
671
|
+
"""
|
|
672
|
+
|
|
673
|
+
if optimization_options is None:
|
|
674
|
+
optimization_options = {
|
|
675
|
+
"backup_first": True,
|
|
676
|
+
"apply_size_optimizations": True,
|
|
677
|
+
"apply_performance_optimizations": True,
|
|
678
|
+
"apply_complexity_optimizations": True,
|
|
679
|
+
"preserve_functionality": True,
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
optimization_result = {
|
|
683
|
+
"timestamp": datetime.now().isoformat(),
|
|
684
|
+
"options_used": optimization_options,
|
|
685
|
+
"backup_created": False,
|
|
686
|
+
"optimized_files": [],
|
|
687
|
+
"optimizations_applied": [],
|
|
688
|
+
"size_reduction": 0,
|
|
689
|
+
"performance_improvement": 0,
|
|
690
|
+
"errors": [],
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
# Create backup if requested
|
|
694
|
+
if optimization_options.get("backup_first", True):
|
|
695
|
+
backup_result = self._create_template_backup("pre-optimization")
|
|
696
|
+
optimization_result["backup_created"] = backup_result["success"]
|
|
697
|
+
optimization_result["backup_info"] = backup_result
|
|
698
|
+
|
|
699
|
+
# Analyze current templates
|
|
700
|
+
analysis = self.analyze_project_templates()
|
|
701
|
+
|
|
702
|
+
# Apply optimizations
|
|
703
|
+
for template_file in analysis["template_files"]:
|
|
704
|
+
file_optimization = self._optimize_template_file(template_file, optimization_options)
|
|
705
|
+
|
|
706
|
+
if file_optimization["success"]:
|
|
707
|
+
optimization_result["optimized_files"].append(file_optimization)
|
|
708
|
+
optimization_result["optimizations_applied"].extend(file_optimization["applied_optimizations"])
|
|
709
|
+
else:
|
|
710
|
+
optimization_result["errors"].append(
|
|
711
|
+
{
|
|
712
|
+
"file": template_file["path"],
|
|
713
|
+
"error": file_optimization.get("error", "Unknown error"),
|
|
714
|
+
}
|
|
715
|
+
)
|
|
716
|
+
|
|
717
|
+
# Calculate overall improvements
|
|
718
|
+
if optimization_result["optimized_files"]:
|
|
719
|
+
original_total_size = sum(f["size_bytes"] for f in analysis["template_files"])
|
|
720
|
+
optimized_total_size = sum(f["optimized_size_bytes"] for f in optimization_result["optimized_files"])
|
|
721
|
+
|
|
722
|
+
if original_total_size > 0:
|
|
723
|
+
optimization_result["size_reduction"] = (
|
|
724
|
+
(original_total_size - optimized_total_size) / original_total_size * 100
|
|
725
|
+
)
|
|
726
|
+
|
|
727
|
+
return optimization_result
|
|
728
|
+
|
|
729
|
+
def _create_template_backup(self, backup_name: str = None) -> Dict[str, Any]:
|
|
730
|
+
"""Create backup of all template files."""
|
|
731
|
+
|
|
732
|
+
if backup_name is None:
|
|
733
|
+
backup_name = f"backup-{datetime.now().strftime('%Y-%m-%d-%H-%M-%S')}"
|
|
734
|
+
|
|
735
|
+
backup_path = self.backups_dir / backup_name
|
|
736
|
+
backup_path.mkdir(parents=True, exist_ok=True)
|
|
737
|
+
|
|
738
|
+
backup_result = {
|
|
739
|
+
"backup_name": backup_name,
|
|
740
|
+
"backup_path": str(backup_path),
|
|
741
|
+
"success": False,
|
|
742
|
+
"files_backed_up": 0,
|
|
743
|
+
"total_size_bytes": 0,
|
|
744
|
+
"created_at": datetime.now().isoformat(),
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
try:
|
|
748
|
+
# Discover and backup template files
|
|
749
|
+
template_files = self._discover_template_files()
|
|
750
|
+
|
|
751
|
+
for template_file in template_files:
|
|
752
|
+
source_path = Path(template_file["absolute_path"])
|
|
753
|
+
relative_path = Path(template_file["path"])
|
|
754
|
+
backup_file_path = backup_path / relative_path
|
|
755
|
+
|
|
756
|
+
# Ensure backup directory exists
|
|
757
|
+
backup_file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
758
|
+
|
|
759
|
+
# Copy file
|
|
760
|
+
shutil.copy2(source_path, backup_file_path)
|
|
761
|
+
backup_result["files_backed_up"] += 1
|
|
762
|
+
backup_result["total_size_bytes"] += template_file["size_bytes"]
|
|
763
|
+
|
|
764
|
+
# Create backup metadata
|
|
765
|
+
metadata = {
|
|
766
|
+
"backup_name": backup_name,
|
|
767
|
+
"created_at": backup_result["created_at"],
|
|
768
|
+
"files_backed_up": backup_result["files_backed_up"],
|
|
769
|
+
"total_size_bytes": backup_result["total_size_bytes"],
|
|
770
|
+
"project_root": str(self.project_root),
|
|
771
|
+
"template_files": template_files,
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
metadata_path = backup_path / "backup-metadata.json"
|
|
775
|
+
metadata_path.write_text(json.dumps(metadata, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
776
|
+
|
|
777
|
+
backup_result["success"] = True
|
|
778
|
+
|
|
779
|
+
except Exception as e:
|
|
780
|
+
backup_result["error"] = str(e)
|
|
781
|
+
|
|
782
|
+
return backup_result
|
|
783
|
+
|
|
784
|
+
def _optimize_template_file(self, template_file: Dict[str, Any], options: Dict[str, Any]) -> Dict[str, Any]:
|
|
785
|
+
"""Optimize individual template file."""
|
|
786
|
+
|
|
787
|
+
file_path = Path(template_file["absolute_path"])
|
|
788
|
+
optimization_result = {
|
|
789
|
+
"file_path": template_file["path"],
|
|
790
|
+
"success": False,
|
|
791
|
+
"original_size_bytes": template_file["size_bytes"],
|
|
792
|
+
"optimized_size_bytes": 0,
|
|
793
|
+
"applied_optimizations": [],
|
|
794
|
+
"error": None,
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
try:
|
|
798
|
+
# Read original content
|
|
799
|
+
original_content = file_path.read_text(encoding="utf-8")
|
|
800
|
+
optimized_content = original_content
|
|
801
|
+
applied_optimizations = []
|
|
802
|
+
|
|
803
|
+
# Apply size optimizations
|
|
804
|
+
if options.get("apply_size_optimizations", True):
|
|
805
|
+
size_optimized, size_opts = self._apply_size_optimizations(optimized_content)
|
|
806
|
+
if size_optimized != optimized_content:
|
|
807
|
+
optimized_content = size_optimized
|
|
808
|
+
applied_optimizations.extend(size_opts)
|
|
809
|
+
|
|
810
|
+
# Apply performance optimizations
|
|
811
|
+
if options.get("apply_performance_optimizations", True):
|
|
812
|
+
perf_optimized, perf_opts = self._apply_performance_optimizations(optimized_content)
|
|
813
|
+
if perf_optimized != optimized_content:
|
|
814
|
+
optimized_content = perf_optimized
|
|
815
|
+
applied_optimizations.extend(perf_opts)
|
|
816
|
+
|
|
817
|
+
# Apply complexity optimizations
|
|
818
|
+
if options.get("apply_complexity_optimizations", True):
|
|
819
|
+
complexity_optimized, complexity_opts = self._apply_complexity_optimizations(optimized_content)
|
|
820
|
+
if complexity_optimized != optimized_content:
|
|
821
|
+
optimized_content = complexity_optimized
|
|
822
|
+
applied_optimizations.extend(complexity_opts)
|
|
823
|
+
|
|
824
|
+
# Write optimized version
|
|
825
|
+
if optimized_content != original_content:
|
|
826
|
+
# Create optimized version
|
|
827
|
+
optimized_dir = self.templates_dir / "optimized"
|
|
828
|
+
relative_path = file_path.relative_to(self.project_root)
|
|
829
|
+
optimized_file_path = optimized_dir / relative_path
|
|
830
|
+
|
|
831
|
+
optimized_file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
832
|
+
optimized_file_path.write_text(optimized_content, encoding="utf-8")
|
|
833
|
+
|
|
834
|
+
optimization_result.update(
|
|
835
|
+
{
|
|
836
|
+
"success": True,
|
|
837
|
+
"optimized_size_bytes": len(optimized_content.encode("utf-8")),
|
|
838
|
+
"applied_optimizations": applied_optimizations,
|
|
839
|
+
"optimized_file_path": str(optimized_file_path),
|
|
840
|
+
}
|
|
841
|
+
)
|
|
842
|
+
else:
|
|
843
|
+
optimization_result["success"] = True
|
|
844
|
+
optimization_result["message"] = "No optimizations needed"
|
|
845
|
+
|
|
846
|
+
except Exception as e:
|
|
847
|
+
optimization_result["error"] = str(e)
|
|
848
|
+
|
|
849
|
+
return optimization_result
|
|
850
|
+
|
|
851
|
+
def _apply_size_optimizations(self, content: str) -> Tuple[str, List[str]]:
|
|
852
|
+
"""Apply size reduction optimizations."""
|
|
853
|
+
|
|
854
|
+
optimized_content = content
|
|
855
|
+
applied_optimizations = []
|
|
856
|
+
|
|
857
|
+
# Remove excessive whitespace
|
|
858
|
+
original_lines = content.splitlines()
|
|
859
|
+
optimized_lines = []
|
|
860
|
+
|
|
861
|
+
for line in original_lines:
|
|
862
|
+
# Remove leading/trailing whitespace but preserve template indentation
|
|
863
|
+
stripped_line = line.rstrip()
|
|
864
|
+
if stripped_line or line.strip() == "":
|
|
865
|
+
optimized_lines.append(stripped_line)
|
|
866
|
+
|
|
867
|
+
optimized_content = "\n".join(optimized_lines)
|
|
868
|
+
|
|
869
|
+
if len(optimized_content) < len(content) * 0.95: # At least 5% reduction
|
|
870
|
+
applied_optimizations.append("whitespace_optimization")
|
|
871
|
+
|
|
872
|
+
# Remove redundant template markers
|
|
873
|
+
# (This would be more sophisticated in practice)
|
|
874
|
+
optimized_content = re.sub(r"\{\{\s+\{\{", "{{", optimized_content)
|
|
875
|
+
optimized_content = re.sub(r"\}\}\s+\}\}", "}}", optimized_content)
|
|
876
|
+
|
|
877
|
+
if optimized_content != content:
|
|
878
|
+
applied_optimizations.append("template_marker_optimization")
|
|
879
|
+
|
|
880
|
+
return optimized_content, applied_optimizations
|
|
881
|
+
|
|
882
|
+
def _apply_performance_optimizations(self, content: str) -> Tuple[str, List[str]]:
|
|
883
|
+
"""Apply performance optimizations."""
|
|
884
|
+
|
|
885
|
+
optimized_content = content
|
|
886
|
+
applied_optimizations = []
|
|
887
|
+
|
|
888
|
+
# Optimize loop structures
|
|
889
|
+
# This is a simplified example - real optimization would be more sophisticated
|
|
890
|
+
original_content = optimized_content
|
|
891
|
+
|
|
892
|
+
# Replace complex inline conditions with template filters
|
|
893
|
+
optimized_content = re.sub(
|
|
894
|
+
r"\{\{\s*if\s+(.+?)\s*%\}\s*\{\{\s*(.+?)\s*\}\}\s*\{\%\s*else\s*%\}\s*\{\{\s*(.+?)\s*\}\}\s*\{\%\s*endif\s*%\}",
|
|
895
|
+
r'{{ \1 | default("\3") if \2 else "\3" }}',
|
|
896
|
+
optimized_content,
|
|
897
|
+
)
|
|
898
|
+
|
|
899
|
+
if optimized_content != original_content:
|
|
900
|
+
applied_optimizations.append("conditional_optimization")
|
|
901
|
+
|
|
902
|
+
# Cache expensive operations
|
|
903
|
+
optimized_content = re.sub(r"\{\{\s*(.+?)\|length\s*\}\}", r"{{ \1 | length }}", optimized_content)
|
|
904
|
+
|
|
905
|
+
return optimized_content, applied_optimizations
|
|
906
|
+
|
|
907
|
+
def _apply_complexity_optimizations(self, content: str) -> Tuple[str, List[str]]:
|
|
908
|
+
"""Apply complexity reduction optimizations."""
|
|
909
|
+
|
|
910
|
+
optimized_content = content
|
|
911
|
+
applied_optimizations = []
|
|
912
|
+
|
|
913
|
+
# Extract complex nested structures into separate templates
|
|
914
|
+
# This is a simplified detection - real implementation would be more advanced
|
|
915
|
+
|
|
916
|
+
# Find deeply nested structures (simplified example)
|
|
917
|
+
nesting_level = 0
|
|
918
|
+
max_nesting = 0
|
|
919
|
+
lines = content.splitlines()
|
|
920
|
+
|
|
921
|
+
for line in lines:
|
|
922
|
+
open_blocks = line.count("{%") + line.count("{{")
|
|
923
|
+
close_blocks = line.count("%}") + line.count("}}")
|
|
924
|
+
nesting_level += open_blocks - close_blocks
|
|
925
|
+
max_nesting = max(max_nesting, nesting_level)
|
|
926
|
+
|
|
927
|
+
if max_nesting > 5:
|
|
928
|
+
applied_optimizations.append("complexity_reduction_needed")
|
|
929
|
+
# In practice, this would extract nested content to separate templates
|
|
930
|
+
|
|
931
|
+
return optimized_content, applied_optimizations
|
|
932
|
+
|
|
933
|
+
def benchmark_template_performance(self, template_paths: List[str] = None) -> Dict[str, Any]:
|
|
934
|
+
"""
|
|
935
|
+
Benchmark template rendering performance.
|
|
936
|
+
|
|
937
|
+
Args:
|
|
938
|
+
template_paths: Specific templates to benchmark (all if None)
|
|
939
|
+
|
|
940
|
+
Returns:
|
|
941
|
+
Performance benchmark results
|
|
942
|
+
"""
|
|
943
|
+
|
|
944
|
+
benchmark_result = {
|
|
945
|
+
"timestamp": datetime.now().isoformat(),
|
|
946
|
+
"benchmark_files": template_paths or [],
|
|
947
|
+
"performance_metrics": {},
|
|
948
|
+
"summary": {
|
|
949
|
+
"total_files_tested": 0,
|
|
950
|
+
"average_render_time_ms": 0,
|
|
951
|
+
"fastest_file": None,
|
|
952
|
+
"slowest_file": None,
|
|
953
|
+
},
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
# Get files to benchmark
|
|
957
|
+
if template_paths is None:
|
|
958
|
+
template_files = self._discover_template_files()
|
|
959
|
+
template_paths = [f["path"] for f in template_files]
|
|
960
|
+
|
|
961
|
+
benchmark_result["benchmark_files"] = template_paths
|
|
962
|
+
render_times = []
|
|
963
|
+
|
|
964
|
+
for template_path in template_paths:
|
|
965
|
+
file_path = self.project_root / template_path
|
|
966
|
+
if file_path.exists():
|
|
967
|
+
performance_metrics = self._estimate_template_performance(file_path)
|
|
968
|
+
|
|
969
|
+
benchmark_result["performance_metrics"][template_path] = {
|
|
970
|
+
"estimated_render_time_ms": performance_metrics["estimated_render_time_ms"],
|
|
971
|
+
"memory_usage_kb": performance_metrics["memory_usage_estimate_kb"],
|
|
972
|
+
"cpu_intensity": performance_metrics["cpu_intensity"],
|
|
973
|
+
"cache_friendly": performance_metrics["cache_friendly"],
|
|
974
|
+
"complexity_score": performance_metrics["render_complexity_score"],
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
render_times.append(performance_metrics["estimated_render_time_ms"])
|
|
978
|
+
|
|
979
|
+
# Calculate summary
|
|
980
|
+
if render_times:
|
|
981
|
+
benchmark_result["summary"]["total_files_tested"] = len(render_times)
|
|
982
|
+
benchmark_result["summary"]["average_render_time_ms"] = sum(render_times) / len(render_times)
|
|
983
|
+
|
|
984
|
+
# Find fastest and slowest files
|
|
985
|
+
min_time_idx = render_times.index(min(render_times))
|
|
986
|
+
max_time_idx = render_times.index(max(render_times))
|
|
987
|
+
|
|
988
|
+
benchmark_result["summary"]["fastest_file"] = {
|
|
989
|
+
"path": template_paths[min_time_idx],
|
|
990
|
+
"render_time_ms": min(render_times),
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
benchmark_result["summary"]["slowest_file"] = {
|
|
994
|
+
"path": template_paths[max_time_idx],
|
|
995
|
+
"render_time_ms": max(render_times),
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
# Save benchmark results
|
|
999
|
+
benchmark_dir = self.templates_dir / "benchmarks"
|
|
1000
|
+
benchmark_dir.mkdir(exist_ok=True)
|
|
1001
|
+
|
|
1002
|
+
benchmark_file = benchmark_dir / f"benchmark-{datetime.now().strftime('%Y%m%d-%H%M%S')}.json"
|
|
1003
|
+
benchmark_file.write_text(json.dumps(benchmark_result, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
1004
|
+
|
|
1005
|
+
return benchmark_result
|