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,864 @@
|
|
|
1
|
+
# SPEC-First TDD - Specification-Driven Development
|
|
2
|
+
|
|
3
|
+
Purpose: Specification-driven test-driven development workflow ensuring clear requirements before implementation through EARS format and RED-GREEN-REFACTOR cycles.
|
|
4
|
+
|
|
5
|
+
Version: 1.0.0
|
|
6
|
+
Last Updated: 2025-11-25
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Quick Reference (30 seconds)
|
|
11
|
+
|
|
12
|
+
SPEC-First TDD is MoAI-ADK's development methodology combining:
|
|
13
|
+
|
|
14
|
+
1. SPEC Generation - EARS format requirements (/moai:1-plan)
|
|
15
|
+
2. Test-Driven Development - RED-GREEN-REFACTOR (/moai:2-run)
|
|
16
|
+
3. Documentation Sync - Auto-generated docs (/moai:3-sync)
|
|
17
|
+
|
|
18
|
+
Three-Phase Workflow:
|
|
19
|
+
```
|
|
20
|
+
Phase 1: SPEC → spec-builder → .moai/specs/SPEC-XXX/spec.md
|
|
21
|
+
Phase 2: TDD → tdd-implementer → Code + Tests (≥85% coverage)
|
|
22
|
+
Phase 3: Docs → docs-manager → API docs + diagrams
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Token Budget: SPEC 30K | TDD 180K | Docs 40K | Total 250K
|
|
26
|
+
|
|
27
|
+
Key Practice: Execute `/clear` after Phase 1 to save 45-50K tokens.
|
|
28
|
+
|
|
29
|
+
EARS Patterns:
|
|
30
|
+
- Ubiquitous: System SHALL always...
|
|
31
|
+
- Event-driven: WHEN <event>, system SHALL...
|
|
32
|
+
- State-driven: WHILE <state>, system SHALL...
|
|
33
|
+
- Unwanted: System SHALL NOT...
|
|
34
|
+
- Optional: WHERE possible, system SHOULD...
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Implementation Guide (5 minutes)
|
|
39
|
+
|
|
40
|
+
### Phase 1: SPEC Generation
|
|
41
|
+
|
|
42
|
+
Purpose: Define clear, testable requirements in EARS format before coding.
|
|
43
|
+
|
|
44
|
+
Workflow:
|
|
45
|
+
```bash
|
|
46
|
+
# 1. Generate SPEC
|
|
47
|
+
/moai:1-plan "Implement user authentication with JWT tokens"
|
|
48
|
+
|
|
49
|
+
# 2. spec-builder creates:
|
|
50
|
+
.moai/specs/SPEC-001/
|
|
51
|
+
spec.md # EARS format requirements
|
|
52
|
+
acceptance.md # Acceptance criteria
|
|
53
|
+
complexity.yaml # Complexity analysis
|
|
54
|
+
|
|
55
|
+
# 3. Execute /clear (mandatory)
|
|
56
|
+
/clear # Saves 45-50K tokens, prepares clean context
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
EARS Format Structure:
|
|
60
|
+
|
|
61
|
+
```markdown
|
|
62
|
+
---
|
|
63
|
+
spec_id: SPEC-001
|
|
64
|
+
title: User Authentication System
|
|
65
|
+
version: 1.0.0
|
|
66
|
+
complexity: Medium
|
|
67
|
+
estimated_effort: 8-12 hours
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Requirements
|
|
71
|
+
|
|
72
|
+
### SPEC-001-REQ-01: User Registration (Ubiquitous)
|
|
73
|
+
Pattern: Ubiquitous
|
|
74
|
+
Statement: The system SHALL register users with email and password validation.
|
|
75
|
+
|
|
76
|
+
Acceptance Criteria:
|
|
77
|
+
- Email format validated (RFC 5322)
|
|
78
|
+
- Password strength: ≥8 chars, mixed case, numbers, symbols
|
|
79
|
+
- Duplicate email rejected with clear error
|
|
80
|
+
- Success returns user ID and confirmation email sent
|
|
81
|
+
|
|
82
|
+
Test Coverage Target: ≥90%
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
### SPEC-001-REQ-02: JWT Token Generation (Event-driven)
|
|
87
|
+
Pattern: Event-driven
|
|
88
|
+
Statement: WHEN a user successfully authenticates, the system SHALL generate a JWT token with 1-hour expiry.
|
|
89
|
+
|
|
90
|
+
Acceptance Criteria:
|
|
91
|
+
- Token includes user ID, email, role claims
|
|
92
|
+
- Token signed with RS256 algorithm
|
|
93
|
+
- Expiry set to 1 hour from generation
|
|
94
|
+
- Refresh token generated with 7-day expiry
|
|
95
|
+
|
|
96
|
+
Test Coverage Target: ≥95%
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
### SPEC-001-REQ-03: Token Validation (State-driven)
|
|
101
|
+
Pattern: State-driven
|
|
102
|
+
Statement: WHILE a request includes Authorization header, the system SHALL validate JWT token before processing.
|
|
103
|
+
|
|
104
|
+
Acceptance Criteria:
|
|
105
|
+
- Expired tokens rejected with 401 Unauthorized
|
|
106
|
+
- Invalid signature rejected with 401 Unauthorized
|
|
107
|
+
- Valid token extracts user claims successfully
|
|
108
|
+
- Token blacklist checked (revoked tokens)
|
|
109
|
+
|
|
110
|
+
Test Coverage Target: ≥95%
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
### SPEC-001-REQ-04: Weak Password Prevention (Unwanted)
|
|
115
|
+
Pattern: Unwanted
|
|
116
|
+
Statement: The system SHALL NOT allow passwords from common password lists (top 10K).
|
|
117
|
+
|
|
118
|
+
Acceptance Criteria:
|
|
119
|
+
- Common passwords rejected (e.g., "password123")
|
|
120
|
+
- Sequential patterns rejected (e.g., "abc123")
|
|
121
|
+
- User-specific patterns rejected (e.g., email prefix)
|
|
122
|
+
- Clear error message with improvement suggestions
|
|
123
|
+
|
|
124
|
+
Test Coverage Target: ≥85%
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
### SPEC-001-REQ-05: OAuth2 Integration (Optional)
|
|
129
|
+
Pattern: Optional
|
|
130
|
+
Statement: WHERE user chooses, the system SHOULD support OAuth2 authentication via Google and GitHub.
|
|
131
|
+
|
|
132
|
+
Acceptance Criteria:
|
|
133
|
+
- OAuth2 providers configurable
|
|
134
|
+
- User can link multiple providers to one account
|
|
135
|
+
- Provider-specific profile data merged
|
|
136
|
+
- Graceful fallback if provider unavailable
|
|
137
|
+
|
|
138
|
+
Test Coverage Target: ≥80%
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Complexity Analysis:
|
|
142
|
+
|
|
143
|
+
```yaml
|
|
144
|
+
# .moai/specs/SPEC-001/complexity.yaml
|
|
145
|
+
complexity_metrics:
|
|
146
|
+
total_requirements: 5
|
|
147
|
+
critical_requirements: 3
|
|
148
|
+
|
|
149
|
+
complexity_breakdown:
|
|
150
|
+
SPEC-001-REQ-01: Medium # Standard CRUD + validation
|
|
151
|
+
SPEC-001-REQ-02: Medium # JWT library integration
|
|
152
|
+
SPEC-001-REQ-03: High # Security validation logic
|
|
153
|
+
SPEC-001-REQ-04: Low # Lookup validation
|
|
154
|
+
SPEC-001-REQ-05: High # External API integration
|
|
155
|
+
|
|
156
|
+
estimated_effort:
|
|
157
|
+
development: 8 hours
|
|
158
|
+
testing: 4 hours
|
|
159
|
+
total: 12 hours
|
|
160
|
+
|
|
161
|
+
risk_factors:
|
|
162
|
+
- Security-critical functionality
|
|
163
|
+
- External OAuth2 provider dependencies
|
|
164
|
+
- Token expiry edge cases
|
|
165
|
+
|
|
166
|
+
dependencies:
|
|
167
|
+
- PyJWT library
|
|
168
|
+
- bcrypt library
|
|
169
|
+
- OAuth2 client libraries
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
### Phase 2: Test-Driven Development
|
|
175
|
+
|
|
176
|
+
Purpose: Implement requirements through RED-GREEN-REFACTOR cycles with ≥85% coverage.
|
|
177
|
+
|
|
178
|
+
RED-GREEN-REFACTOR Cycle:
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
# ====================================
|
|
182
|
+
# RED PHASE: Write failing test first
|
|
183
|
+
# ====================================
|
|
184
|
+
|
|
185
|
+
import pytest
|
|
186
|
+
from src.auth.registration import register_user
|
|
187
|
+
from src.models.user import User
|
|
188
|
+
from src.exceptions import ValidationError
|
|
189
|
+
|
|
190
|
+
def test_register_user_with_valid_data():
|
|
191
|
+
"""SPEC-001-REQ-01: User registration with valid data."""
|
|
192
|
+
# Arrange
|
|
193
|
+
email = "user@example.com"
|
|
194
|
+
password = "SecureP@ssw0rd"
|
|
195
|
+
|
|
196
|
+
# Act
|
|
197
|
+
result = register_user(email=email, password=password)
|
|
198
|
+
|
|
199
|
+
# Assert
|
|
200
|
+
assert result.success is True
|
|
201
|
+
assert result.user.email == email
|
|
202
|
+
assert result.user.id is not None
|
|
203
|
+
assert result.confirmation_sent is True
|
|
204
|
+
|
|
205
|
+
# Run test → FAILS (functions don't exist yet)
|
|
206
|
+
|
|
207
|
+
# ====================================
|
|
208
|
+
# GREEN PHASE: Minimal implementation
|
|
209
|
+
# ====================================
|
|
210
|
+
|
|
211
|
+
# src/auth/registration.py
|
|
212
|
+
from dataclasses import dataclass
|
|
213
|
+
from src.models.user import User
|
|
214
|
+
import bcrypt
|
|
215
|
+
import re
|
|
216
|
+
|
|
217
|
+
@dataclass
|
|
218
|
+
class RegistrationResult:
|
|
219
|
+
success: bool
|
|
220
|
+
user: User
|
|
221
|
+
confirmation_sent: bool
|
|
222
|
+
|
|
223
|
+
def register_user(email: str, password: str) -> RegistrationResult:
|
|
224
|
+
"""Register new user with email and password."""
|
|
225
|
+
# Minimal code to pass test
|
|
226
|
+
user = User(id=1, email=email, password_hash=password)
|
|
227
|
+
return RegistrationResult(
|
|
228
|
+
success=True,
|
|
229
|
+
user=user,
|
|
230
|
+
confirmation_sent=True
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
# Run test → PASSES (test now passes)
|
|
234
|
+
|
|
235
|
+
# ====================================
|
|
236
|
+
# REFACTOR PHASE: Improve quality
|
|
237
|
+
# ====================================
|
|
238
|
+
|
|
239
|
+
# src/auth/registration.py (refactored)
|
|
240
|
+
from dataclasses import dataclass
|
|
241
|
+
from typing import Optional
|
|
242
|
+
from src.models.user import User
|
|
243
|
+
from src.database import db_session
|
|
244
|
+
from src.email import send_confirmation_email
|
|
245
|
+
from src.exceptions import ValidationError
|
|
246
|
+
import bcrypt
|
|
247
|
+
import re
|
|
248
|
+
|
|
249
|
+
EMAIL_REGEX = re.compile(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$')
|
|
250
|
+
PASSWORD_MIN_LENGTH = 8
|
|
251
|
+
|
|
252
|
+
@dataclass
|
|
253
|
+
class RegistrationResult:
|
|
254
|
+
"""Result of user registration attempt."""
|
|
255
|
+
success: bool
|
|
256
|
+
user: Optional[User]
|
|
257
|
+
confirmation_sent: bool
|
|
258
|
+
error: Optional[str] = None
|
|
259
|
+
|
|
260
|
+
def register_user(email: str, password: str) -> RegistrationResult:
|
|
261
|
+
"""Register new user with email and password.
|
|
262
|
+
|
|
263
|
+
Implements SPEC-001-REQ-01: User Registration (Ubiquitous)
|
|
264
|
+
|
|
265
|
+
Args:
|
|
266
|
+
email: User email address (must be valid format)
|
|
267
|
+
password: User password (≥8 chars, mixed case, numbers, symbols)
|
|
268
|
+
|
|
269
|
+
Returns:
|
|
270
|
+
RegistrationResult with user data or error
|
|
271
|
+
|
|
272
|
+
Raises:
|
|
273
|
+
ValidationError: If email or password invalid
|
|
274
|
+
|
|
275
|
+
Example:
|
|
276
|
+
>>> result = register_user("user@example.com", "SecureP@ssw0rd")
|
|
277
|
+
>>> result.success
|
|
278
|
+
True
|
|
279
|
+
>>> result.user.email
|
|
280
|
+
'user@example.com'
|
|
281
|
+
"""
|
|
282
|
+
# Validate email format (RFC 5322 compliant)
|
|
283
|
+
if not EMAIL_REGEX.match(email):
|
|
284
|
+
raise ValidationError("Invalid email format")
|
|
285
|
+
|
|
286
|
+
# Check for duplicate email
|
|
287
|
+
existing_user = User.query.filter_by(email=email).first()
|
|
288
|
+
if existing_user:
|
|
289
|
+
raise ValidationError("Email already registered")
|
|
290
|
+
|
|
291
|
+
# Validate password strength
|
|
292
|
+
if not _is_password_strong(password):
|
|
293
|
+
raise ValidationError(
|
|
294
|
+
"Password must be ≥8 characters with mixed case, numbers, and symbols"
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
# Hash password securely
|
|
298
|
+
password_hash = bcrypt.hashpw(
|
|
299
|
+
password.encode('utf-8'),
|
|
300
|
+
bcrypt.gensalt(rounds=12)
|
|
301
|
+
).decode('utf-8')
|
|
302
|
+
|
|
303
|
+
# Create user
|
|
304
|
+
user = User(email=email, password_hash=password_hash)
|
|
305
|
+
db_session.add(user)
|
|
306
|
+
db_session.commit()
|
|
307
|
+
|
|
308
|
+
# Send confirmation email
|
|
309
|
+
confirmation_sent = send_confirmation_email(user.email, user.id)
|
|
310
|
+
|
|
311
|
+
return RegistrationResult(
|
|
312
|
+
success=True,
|
|
313
|
+
user=user,
|
|
314
|
+
confirmation_sent=confirmation_sent
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
def _is_password_strong(password: str) -> bool:
|
|
318
|
+
"""Validate password strength.
|
|
319
|
+
|
|
320
|
+
Requirements:
|
|
321
|
+
- At least 8 characters
|
|
322
|
+
- Contains uppercase letter
|
|
323
|
+
- Contains lowercase letter
|
|
324
|
+
- Contains digit
|
|
325
|
+
- Contains special symbol
|
|
326
|
+
"""
|
|
327
|
+
if len(password) < PASSWORD_MIN_LENGTH:
|
|
328
|
+
return False
|
|
329
|
+
|
|
330
|
+
has_upper = any(c.isupper() for c in password)
|
|
331
|
+
has_lower = any(c.islower() for c in password)
|
|
332
|
+
has_digit = any(c.isdigit() for c in password)
|
|
333
|
+
has_symbol = any(not c.isalnum() for c in password)
|
|
334
|
+
|
|
335
|
+
return all([has_upper, has_lower, has_digit, has_symbol])
|
|
336
|
+
|
|
337
|
+
# Run test → PASSES (with improved implementation)
|
|
338
|
+
# Coverage: 95% (meets ≥90% target)
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
Comprehensive Test Suite:
|
|
342
|
+
|
|
343
|
+
```python
|
|
344
|
+
# tests/auth/test_registration.py
|
|
345
|
+
import pytest
|
|
346
|
+
from src.auth.registration import register_user
|
|
347
|
+
from src.exceptions import ValidationError
|
|
348
|
+
|
|
349
|
+
class TestUserRegistration:
|
|
350
|
+
"""Test suite for SPEC-001-REQ-01: User Registration."""
|
|
351
|
+
|
|
352
|
+
def test_register_user_success(self):
|
|
353
|
+
"""Test successful registration with valid data."""
|
|
354
|
+
result = register_user("user@example.com", "SecureP@ssw0rd")
|
|
355
|
+
assert result.success is True
|
|
356
|
+
assert result.user.email == "user@example.com"
|
|
357
|
+
assert result.confirmation_sent is True
|
|
358
|
+
|
|
359
|
+
def test_register_user_invalid_email(self):
|
|
360
|
+
"""Test registration fails with invalid email format."""
|
|
361
|
+
with pytest.raises(ValidationError, match="Invalid email format"):
|
|
362
|
+
register_user("invalid-email", "SecureP@ssw0rd")
|
|
363
|
+
|
|
364
|
+
def test_register_user_duplicate_email(self):
|
|
365
|
+
"""Test registration fails with duplicate email."""
|
|
366
|
+
register_user("user@example.com", "SecureP@ssw0rd")
|
|
367
|
+
|
|
368
|
+
with pytest.raises(ValidationError, match="Email already registered"):
|
|
369
|
+
register_user("user@example.com", "AnotherP@ssw0rd")
|
|
370
|
+
|
|
371
|
+
def test_register_user_weak_password(self):
|
|
372
|
+
"""Test registration fails with weak password."""
|
|
373
|
+
weak_passwords = [
|
|
374
|
+
"short", # Too short
|
|
375
|
+
"alllowercase1", # No uppercase
|
|
376
|
+
"ALLUPPERCASE1", # No lowercase
|
|
377
|
+
"NoNumbersHere!", # No digits
|
|
378
|
+
"NoSymbols123" # No symbols
|
|
379
|
+
]
|
|
380
|
+
|
|
381
|
+
for weak_pwd in weak_passwords:
|
|
382
|
+
with pytest.raises(ValidationError, match="Password must be"):
|
|
383
|
+
register_user("user@example.com", weak_pwd)
|
|
384
|
+
|
|
385
|
+
def test_register_user_password_hashing(self):
|
|
386
|
+
"""Test password is properly hashed (not stored plain text)."""
|
|
387
|
+
result = register_user("user@example.com", "SecureP@ssw0rd")
|
|
388
|
+
|
|
389
|
+
# Password hash should not equal plain text
|
|
390
|
+
assert result.user.password_hash != "SecureP@ssw0rd"
|
|
391
|
+
|
|
392
|
+
# Hash should be bcrypt format (starts with $2b$)
|
|
393
|
+
assert result.user.password_hash.startswith("$2b$")
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
Coverage Report:
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
# Run tests with coverage
|
|
400
|
+
pytest tests/auth/test_registration.py --cov=src/auth/registration --cov-report=html
|
|
401
|
+
|
|
402
|
+
# Output:
|
|
403
|
+
---------- coverage: platform darwin, python 3.13.0 -----------
|
|
404
|
+
Name Stmts Miss Cover Missing
|
|
405
|
+
-------------------------------------------------------
|
|
406
|
+
src/auth/registration.py 42 2 95% 87, 92
|
|
407
|
+
-------------------------------------------------------
|
|
408
|
+
TOTAL 42 2 95%
|
|
409
|
+
|
|
410
|
+
# Coverage meets ≥90% target
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
### Phase 3: Documentation Synchronization
|
|
416
|
+
|
|
417
|
+
Purpose: Auto-generate comprehensive documentation from implementation.
|
|
418
|
+
|
|
419
|
+
Workflow:
|
|
420
|
+
```bash
|
|
421
|
+
# 1. Generate documentation
|
|
422
|
+
/moai:3-sync SPEC-001
|
|
423
|
+
|
|
424
|
+
# 2. docs-manager creates:
|
|
425
|
+
.moai/specs/SPEC-001/
|
|
426
|
+
docs/
|
|
427
|
+
api.md # API reference
|
|
428
|
+
architecture.md # Architecture diagram
|
|
429
|
+
testing.md # Test report
|
|
430
|
+
report.md # Implementation summary
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
Auto-Generated API Documentation:
|
|
434
|
+
|
|
435
|
+
```markdown
|
|
436
|
+
# API Documentation - User Authentication
|
|
437
|
+
|
|
438
|
+
## Endpoints
|
|
439
|
+
|
|
440
|
+
### POST /api/auth/register
|
|
441
|
+
Register new user account.
|
|
442
|
+
|
|
443
|
+
Request:
|
|
444
|
+
```json
|
|
445
|
+
{
|
|
446
|
+
"email": "user@example.com",
|
|
447
|
+
"password": "SecureP@ssw0rd"
|
|
448
|
+
}
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
Response (201 Created):
|
|
452
|
+
```json
|
|
453
|
+
{
|
|
454
|
+
"success": true,
|
|
455
|
+
"user": {
|
|
456
|
+
"id": 123,
|
|
457
|
+
"email": "user@example.com",
|
|
458
|
+
"created_at": "2025-11-25T10:30:00Z"
|
|
459
|
+
},
|
|
460
|
+
"message": "Confirmation email sent"
|
|
461
|
+
}
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
Errors:
|
|
465
|
+
- `400 Bad Request`: Invalid email or weak password
|
|
466
|
+
- `409 Conflict`: Email already registered
|
|
467
|
+
|
|
468
|
+
Coverage: 95% (meets ≥90% target)
|
|
469
|
+
|
|
470
|
+
Implementation: `SPEC-001-REQ-01`
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
## Advanced Implementation (10+ minutes)
|
|
476
|
+
|
|
477
|
+
### EARS Pattern Advanced Usage
|
|
478
|
+
|
|
479
|
+
Complex Event-Driven Requirements:
|
|
480
|
+
|
|
481
|
+
```markdown
|
|
482
|
+
### SPEC-002-REQ-03: Multi-Factor Authentication (Event-driven + State-driven)
|
|
483
|
+
Pattern: Event-driven + State-driven
|
|
484
|
+
Statement:
|
|
485
|
+
- WHEN a user attempts login with MFA enabled (Event)
|
|
486
|
+
- WHILE the MFA verification is pending (State)
|
|
487
|
+
- The system SHALL send TOTP code and require verification within 5 minutes
|
|
488
|
+
|
|
489
|
+
Acceptance Criteria:
|
|
490
|
+
1. Event trigger: Login attempt detected
|
|
491
|
+
2. State check: User has MFA enabled
|
|
492
|
+
3. Action: Generate TOTP code (6 digits, 30s validity)
|
|
493
|
+
4. Notification: Send code via SMS or email
|
|
494
|
+
5. Verification: User submits code within 5 minutes
|
|
495
|
+
6. Expiry: Code expires after 5 minutes
|
|
496
|
+
7. Rate limiting: Max 3 failed attempts, then 15-minute lockout
|
|
497
|
+
|
|
498
|
+
Test Scenarios:
|
|
499
|
+
- Happy path: User submits valid code within time
|
|
500
|
+
- Expired code: User submits code after 5 minutes
|
|
501
|
+
- Invalid code: User submits incorrect code
|
|
502
|
+
- Rate limit: User exceeds 3 failed attempts
|
|
503
|
+
- Disabled MFA: User without MFA enabled
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
Implementation:
|
|
507
|
+
|
|
508
|
+
```python
|
|
509
|
+
# RED PHASE: Complex test scenario
|
|
510
|
+
def test_mfa_verification_with_valid_code():
|
|
511
|
+
"""SPEC-002-REQ-03: MFA verification happy path."""
|
|
512
|
+
# Arrange
|
|
513
|
+
user = create_user_with_mfa_enabled()
|
|
514
|
+
login_attempt = initiate_login(user.email, user.password)
|
|
515
|
+
|
|
516
|
+
# System generates TOTP code
|
|
517
|
+
totp_code = get_pending_totp_code(user.id)
|
|
518
|
+
|
|
519
|
+
# Act
|
|
520
|
+
result = verify_mfa(
|
|
521
|
+
user.id,
|
|
522
|
+
code=totp_code,
|
|
523
|
+
timestamp=datetime.now()
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
# Assert
|
|
527
|
+
assert result.success is True
|
|
528
|
+
assert result.token is not None # JWT issued
|
|
529
|
+
assert result.mfa_verified is True
|
|
530
|
+
|
|
531
|
+
def test_mfa_verification_with_expired_code():
|
|
532
|
+
"""SPEC-002-REQ-03: MFA code expiry."""
|
|
533
|
+
user = create_user_with_mfa_enabled()
|
|
534
|
+
login_attempt = initiate_login(user.email, user.password)
|
|
535
|
+
totp_code = get_pending_totp_code(user.id)
|
|
536
|
+
|
|
537
|
+
# Act - submit code after 6 minutes (expired)
|
|
538
|
+
result = verify_mfa(
|
|
539
|
+
user.id,
|
|
540
|
+
code=totp_code,
|
|
541
|
+
timestamp=datetime.now() + timedelta(minutes=6)
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
# Assert
|
|
545
|
+
assert result.success is False
|
|
546
|
+
assert result.error == "Code expired"
|
|
547
|
+
|
|
548
|
+
def test_mfa_rate_limiting():
|
|
549
|
+
"""SPEC-002-REQ-03: Rate limiting after failed attempts."""
|
|
550
|
+
user = create_user_with_mfa_enabled()
|
|
551
|
+
login_attempt = initiate_login(user.email, user.password)
|
|
552
|
+
|
|
553
|
+
# 3 failed attempts
|
|
554
|
+
for _ in range(3):
|
|
555
|
+
verify_mfa(user.id, code="000000") # Invalid code
|
|
556
|
+
|
|
557
|
+
# Act - 4th attempt should be blocked
|
|
558
|
+
result = verify_mfa(user.id, code="123456")
|
|
559
|
+
|
|
560
|
+
# Assert
|
|
561
|
+
assert result.success is False
|
|
562
|
+
assert result.error == "Too many failed attempts. Try again in 15 minutes."
|
|
563
|
+
|
|
564
|
+
# GREEN + REFACTOR PHASE
|
|
565
|
+
from datetime import datetime, timedelta
|
|
566
|
+
from typing import Optional
|
|
567
|
+
import pyotp
|
|
568
|
+
|
|
569
|
+
@dataclass
|
|
570
|
+
class MFAVerificationResult:
|
|
571
|
+
success: bool
|
|
572
|
+
token: Optional[str]
|
|
573
|
+
mfa_verified: bool
|
|
574
|
+
error: Optional[str] = None
|
|
575
|
+
|
|
576
|
+
class MFAManager:
|
|
577
|
+
"""Manage multi-factor authentication."""
|
|
578
|
+
|
|
579
|
+
TOTP_VALIDITY_SECONDS = 300 # 5 minutes
|
|
580
|
+
MAX_FAILED_ATTEMPTS = 3
|
|
581
|
+
LOCKOUT_MINUTES = 15
|
|
582
|
+
|
|
583
|
+
def verify_mfa(
|
|
584
|
+
self,
|
|
585
|
+
user_id: int,
|
|
586
|
+
code: str,
|
|
587
|
+
timestamp: datetime = None
|
|
588
|
+
) -> MFAVerificationResult:
|
|
589
|
+
"""Verify MFA code.
|
|
590
|
+
|
|
591
|
+
Implements SPEC-002-REQ-03: Multi-Factor Authentication
|
|
592
|
+
|
|
593
|
+
Args:
|
|
594
|
+
user_id: User ID attempting verification
|
|
595
|
+
code: 6-digit TOTP code
|
|
596
|
+
timestamp: Verification timestamp (default: now)
|
|
597
|
+
|
|
598
|
+
Returns:
|
|
599
|
+
MFAVerificationResult with verification status
|
|
600
|
+
"""
|
|
601
|
+
timestamp = timestamp or datetime.now()
|
|
602
|
+
|
|
603
|
+
# Get user and pending verification
|
|
604
|
+
user = User.query.get(user_id)
|
|
605
|
+
pending_mfa = PendingMFA.query.filter_by(
|
|
606
|
+
user_id=user_id,
|
|
607
|
+
verified=False
|
|
608
|
+
).first()
|
|
609
|
+
|
|
610
|
+
if not pending_mfa:
|
|
611
|
+
return MFAVerificationResult(
|
|
612
|
+
success=False,
|
|
613
|
+
token=None,
|
|
614
|
+
mfa_verified=False,
|
|
615
|
+
error="No pending MFA verification"
|
|
616
|
+
)
|
|
617
|
+
|
|
618
|
+
# Check rate limiting
|
|
619
|
+
if self._is_rate_limited(user_id):
|
|
620
|
+
return MFAVerificationResult(
|
|
621
|
+
success=False,
|
|
622
|
+
token=None,
|
|
623
|
+
mfa_verified=False,
|
|
624
|
+
error=f"Too many failed attempts. Try again in {self.LOCKOUT_MINUTES} minutes."
|
|
625
|
+
)
|
|
626
|
+
|
|
627
|
+
# Check expiry (5 minutes from generation)
|
|
628
|
+
if timestamp - pending_mfa.created_at > timedelta(seconds=self.TOTP_VALIDITY_SECONDS):
|
|
629
|
+
return MFAVerificationResult(
|
|
630
|
+
success=False,
|
|
631
|
+
token=None,
|
|
632
|
+
mfa_verified=False,
|
|
633
|
+
error="Code expired"
|
|
634
|
+
)
|
|
635
|
+
|
|
636
|
+
# Verify TOTP code
|
|
637
|
+
totp = pyotp.TOTP(user.mfa_secret)
|
|
638
|
+
if not totp.verify(code, valid_window=1):
|
|
639
|
+
self._record_failed_attempt(user_id)
|
|
640
|
+
return MFAVerificationResult(
|
|
641
|
+
success=False,
|
|
642
|
+
token=None,
|
|
643
|
+
mfa_verified=False,
|
|
644
|
+
error="Invalid code"
|
|
645
|
+
)
|
|
646
|
+
|
|
647
|
+
# Success - mark verified and generate JWT
|
|
648
|
+
pending_mfa.verified = True
|
|
649
|
+
pending_mfa.verified_at = timestamp
|
|
650
|
+
db_session.commit()
|
|
651
|
+
|
|
652
|
+
jwt_token = self._generate_jwt_token(user)
|
|
653
|
+
|
|
654
|
+
return MFAVerificationResult(
|
|
655
|
+
success=True,
|
|
656
|
+
token=jwt_token,
|
|
657
|
+
mfa_verified=True
|
|
658
|
+
)
|
|
659
|
+
|
|
660
|
+
def _is_rate_limited(self, user_id: int) -> bool:
|
|
661
|
+
"""Check if user is rate limited."""
|
|
662
|
+
recent_failures = FailedMFAAttempt.query.filter(
|
|
663
|
+
FailedMFAAttempt.user_id == user_id,
|
|
664
|
+
FailedMFAAttempt.timestamp > datetime.now() - timedelta(minutes=self.LOCKOUT_MINUTES)
|
|
665
|
+
).count()
|
|
666
|
+
|
|
667
|
+
return recent_failures >= self.MAX_FAILED_ATTEMPTS
|
|
668
|
+
|
|
669
|
+
def _record_failed_attempt(self, user_id: int):
|
|
670
|
+
"""Record failed MFA attempt for rate limiting."""
|
|
671
|
+
attempt = FailedMFAAttempt(
|
|
672
|
+
user_id=user_id,
|
|
673
|
+
timestamp=datetime.now()
|
|
674
|
+
)
|
|
675
|
+
db_session.add(attempt)
|
|
676
|
+
db_session.commit()
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
### SPEC-TDD Integration Patterns
|
|
680
|
+
|
|
681
|
+
Pattern 1: Iterative SPEC Refinement:
|
|
682
|
+
|
|
683
|
+
```python
|
|
684
|
+
# Initial SPEC (v1.0.0)
|
|
685
|
+
SPEC-003-REQ-01: File upload with size limit (10MB)
|
|
686
|
+
|
|
687
|
+
# Implementation reveals edge case
|
|
688
|
+
# → User uploads 9.9MB file successfully
|
|
689
|
+
# → But total storage exceeds user quota
|
|
690
|
+
|
|
691
|
+
# Refined SPEC (v1.1.0)
|
|
692
|
+
SPEC-003-REQ-01: File upload with size and quota validation
|
|
693
|
+
- Single file limit: 10MB
|
|
694
|
+
- User quota limit: 100MB total
|
|
695
|
+
- Validation: Check both limits before accepting upload
|
|
696
|
+
|
|
697
|
+
# Updated tests
|
|
698
|
+
def test_file_upload_exceeds_quota():
|
|
699
|
+
"""SPEC-003-REQ-01 v1.1.0: Quota validation."""
|
|
700
|
+
user = create_user(quota_limit_mb=100)
|
|
701
|
+
upload_files(user, total_size_mb=95) # Existing files
|
|
702
|
+
|
|
703
|
+
# Attempt upload within file limit but exceeds quota
|
|
704
|
+
result = upload_file(user, file_size_mb=8)
|
|
705
|
+
|
|
706
|
+
assert result.success is False
|
|
707
|
+
assert result.error == "Upload would exceed storage quota"
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
Pattern 2: SPEC-Driven Test Generation:
|
|
711
|
+
|
|
712
|
+
```python
|
|
713
|
+
# Automated test generation from SPEC
|
|
714
|
+
|
|
715
|
+
class SPECTestGenerator:
|
|
716
|
+
"""Generate tests automatically from SPEC requirements."""
|
|
717
|
+
|
|
718
|
+
def generate_tests_for_requirement(self, requirement: dict) -> str:
|
|
719
|
+
"""Generate test code from SPEC requirement."""
|
|
720
|
+
|
|
721
|
+
spec_id = requirement['id']
|
|
722
|
+
pattern = requirement['pattern']
|
|
723
|
+
acceptance_criteria = requirement['acceptance_criteria']
|
|
724
|
+
|
|
725
|
+
if pattern == 'Event-driven':
|
|
726
|
+
return self._generate_event_driven_tests(spec_id, acceptance_criteria)
|
|
727
|
+
elif pattern == 'State-driven':
|
|
728
|
+
return self._generate_state_driven_tests(spec_id, acceptance_criteria)
|
|
729
|
+
elif pattern == 'Unwanted':
|
|
730
|
+
return self._generate_unwanted_tests(spec_id, acceptance_criteria)
|
|
731
|
+
else:
|
|
732
|
+
return self._generate_standard_tests(spec_id, acceptance_criteria)
|
|
733
|
+
|
|
734
|
+
def _generate_event_driven_tests(self, spec_id: str, criteria: list) -> str:
|
|
735
|
+
"""Generate tests for event-driven requirements."""
|
|
736
|
+
|
|
737
|
+
test_template = f'''
|
|
738
|
+
def test_{spec_id.lower().replace('-', '_')}_event_triggered():
|
|
739
|
+
"""{spec_id}: Event-driven requirement test."""
|
|
740
|
+
# Arrange
|
|
741
|
+
{{setup_code}}
|
|
742
|
+
|
|
743
|
+
# Act - Trigger event
|
|
744
|
+
{{trigger_event}}
|
|
745
|
+
|
|
746
|
+
# Assert - Verify system response
|
|
747
|
+
{{assertions}}
|
|
748
|
+
|
|
749
|
+
def test_{spec_id.lower().replace('-', '_')}_no_event():
|
|
750
|
+
"""{spec_id}: No action when event not triggered."""
|
|
751
|
+
# Arrange
|
|
752
|
+
{{setup_code}}
|
|
753
|
+
|
|
754
|
+
# Act - No event triggered
|
|
755
|
+
{{no_event_code}}
|
|
756
|
+
|
|
757
|
+
# Assert - System remains unchanged
|
|
758
|
+
{{no_change_assertions}}
|
|
759
|
+
'''
|
|
760
|
+
return test_template
|
|
761
|
+
|
|
762
|
+
# Usage
|
|
763
|
+
generator = SPECTestGenerator()
|
|
764
|
+
requirement = {
|
|
765
|
+
'id': 'SPEC-001-REQ-02',
|
|
766
|
+
'pattern': 'Event-driven',
|
|
767
|
+
'acceptance_criteria': [...]
|
|
768
|
+
}
|
|
769
|
+
test_code = generator.generate_tests_for_requirement(requirement)
|
|
770
|
+
```
|
|
771
|
+
|
|
772
|
+
### Continuous SPEC-TDD Workflow
|
|
773
|
+
|
|
774
|
+
Automated Pipeline:
|
|
775
|
+
|
|
776
|
+
```yaml
|
|
777
|
+
# .github/workflows/spec-tdd-pipeline.yml
|
|
778
|
+
name: SPEC-First TDD Pipeline
|
|
779
|
+
|
|
780
|
+
on:
|
|
781
|
+
push:
|
|
782
|
+
paths:
|
|
783
|
+
- '.moai/specs/'
|
|
784
|
+
- 'src/'
|
|
785
|
+
- 'tests/'
|
|
786
|
+
|
|
787
|
+
jobs:
|
|
788
|
+
spec-validation:
|
|
789
|
+
name: "Phase 1: SPEC Validation"
|
|
790
|
+
runs-on: ubuntu-latest
|
|
791
|
+
steps:
|
|
792
|
+
- uses: actions/checkout@v4
|
|
793
|
+
|
|
794
|
+
- name: Validate SPEC format
|
|
795
|
+
run: python .moai/scripts/validate_spec.py
|
|
796
|
+
|
|
797
|
+
- name: Check requirement traceability
|
|
798
|
+
run: python .moai/scripts/check_traceability.py
|
|
799
|
+
|
|
800
|
+
- name: Generate test scaffolding
|
|
801
|
+
run: python .moai/scripts/generate_test_scaffolding.py
|
|
802
|
+
|
|
803
|
+
tdd-implementation:
|
|
804
|
+
name: "Phase 2: TDD Implementation"
|
|
805
|
+
needs: spec-validation
|
|
806
|
+
runs-on: ubuntu-latest
|
|
807
|
+
steps:
|
|
808
|
+
- uses: actions/checkout@v4
|
|
809
|
+
|
|
810
|
+
- name: Run RED phase tests
|
|
811
|
+
run: |
|
|
812
|
+
pytest tests/ -v --tb=short || true # Allow failures
|
|
813
|
+
echo "RED phase: Expected failures "
|
|
814
|
+
|
|
815
|
+
- name: Verify tests exist for all requirements
|
|
816
|
+
run: python .moai/scripts/verify_test_coverage_mapping.py
|
|
817
|
+
|
|
818
|
+
quality-gates:
|
|
819
|
+
name: "Phase 3: Quality Gates"
|
|
820
|
+
needs: tdd-implementation
|
|
821
|
+
runs-on: ubuntu-latest
|
|
822
|
+
steps:
|
|
823
|
+
- uses: actions/checkout@v4
|
|
824
|
+
|
|
825
|
+
- name: Run tests with coverage
|
|
826
|
+
run: pytest --cov=src --cov-fail-under=85
|
|
827
|
+
|
|
828
|
+
- name: Validate TRUST 5
|
|
829
|
+
run: python .moai/scripts/validate_trust5.py
|
|
830
|
+
|
|
831
|
+
- name: Generate documentation
|
|
832
|
+
run: python .moai/scripts/generate_docs.py
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
---
|
|
836
|
+
|
|
837
|
+
## Works Well With
|
|
838
|
+
|
|
839
|
+
Agents:
|
|
840
|
+
- spec-builder - EARS format SPEC generation
|
|
841
|
+
- tdd-implementer - RED-GREEN-REFACTOR execution
|
|
842
|
+
- quality-gate - TRUST 5 validation
|
|
843
|
+
- docs-manager - Documentation generation
|
|
844
|
+
|
|
845
|
+
Skills:
|
|
846
|
+
- moai-foundation-ears - EARS format patterns
|
|
847
|
+
- moai-foundation-trust - Quality framework
|
|
848
|
+
- moai-essentials-testing-integration - Test frameworks
|
|
849
|
+
|
|
850
|
+
Commands:
|
|
851
|
+
- /moai:1-plan - SPEC generation (Phase 1)
|
|
852
|
+
- /moai:2-run - TDD implementation (Phase 2)
|
|
853
|
+
- /moai:3-sync - Documentation sync (Phase 3)
|
|
854
|
+
- /clear - Token optimization between phases
|
|
855
|
+
|
|
856
|
+
Memory:
|
|
857
|
+
- Skill("moai-foundation-core") modules/execution-rules.md - SPEC decision criteria
|
|
858
|
+
- @.moai/specs/ - SPEC storage location
|
|
859
|
+
|
|
860
|
+
---
|
|
861
|
+
|
|
862
|
+
Version: 1.0.0
|
|
863
|
+
Last Updated: 2025-11-25
|
|
864
|
+
Status: Production Ready
|