moai-adk 0.15.0__py3-none-any.whl → 0.25.4__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 +1 -2
- moai_adk/__main__.py +85 -2
- moai_adk/cli/__init__.py +0 -1
- moai_adk/cli/commands/__init__.py +0 -1
- moai_adk/cli/commands/analyze.py +127 -0
- moai_adk/cli/commands/backup.py +5 -3
- moai_adk/cli/commands/doctor.py +35 -11
- moai_adk/cli/commands/improve_user_experience.py +348 -0
- moai_adk/cli/commands/init.py +150 -23
- moai_adk/cli/commands/language.py +269 -0
- moai_adk/cli/commands/migrate.py +158 -0
- moai_adk/cli/commands/status.py +13 -12
- moai_adk/cli/commands/update.py +364 -60
- moai_adk/cli/commands/validate_links.py +118 -0
- moai_adk/cli/main.py +3 -2
- moai_adk/cli/prompts/init_prompts.py +79 -82
- moai_adk/core/__init__.py +0 -1
- moai_adk/core/analysis/__init__.py +9 -0
- moai_adk/core/analysis/session_analyzer.py +439 -0
- moai_adk/core/claude_integration.py +421 -0
- moai_adk/core/command_helpers.py +270 -0
- moai_adk/core/config/__init__.py +6 -0
- moai_adk/core/config/auto_spec_config.py +346 -0
- moai_adk/core/config/migration.py +133 -12
- moai_adk/core/context_manager.py +279 -0
- moai_adk/core/diagnostics/slash_commands.py +0 -1
- moai_adk/core/error_recovery_system.py +1289 -0
- moai_adk/core/git/__init__.py +0 -1
- moai_adk/core/git/branch.py +0 -1
- moai_adk/core/git/branch_manager.py +4 -4
- moai_adk/core/git/checkpoint.py +1 -5
- moai_adk/core/git/commit.py +0 -1
- moai_adk/core/git/event_detector.py +3 -5
- moai_adk/core/git/manager.py +0 -1
- moai_adk/core/hooks/post_tool_auto_spec_completion.py +925 -0
- moai_adk/core/integration/__init__.py +22 -0
- moai_adk/core/integration/engine.py +169 -0
- moai_adk/core/integration/integration_tester.py +225 -0
- moai_adk/core/integration/models.py +88 -0
- moai_adk/core/integration/utils.py +211 -0
- moai_adk/core/issue_creator.py +28 -18
- moai_adk/core/language_config.py +202 -0
- moai_adk/core/language_validator.py +556 -0
- moai_adk/core/mcp/setup.py +113 -0
- moai_adk/core/migration/__init__.py +18 -0
- moai_adk/core/migration/backup_manager.py +208 -0
- moai_adk/core/migration/file_migrator.py +218 -0
- moai_adk/core/migration/version_detector.py +143 -0
- moai_adk/core/migration/version_migrator.py +228 -0
- moai_adk/core/performance/__init__.py +6 -0
- moai_adk/core/performance/cache_system.py +318 -0
- moai_adk/core/performance/parallel_processor.py +116 -0
- moai_adk/core/project/__init__.py +0 -1
- moai_adk/core/project/backup_utils.py +2 -7
- moai_adk/core/project/checker.py +3 -3
- moai_adk/core/project/detector.py +20 -40
- moai_adk/core/project/initializer.py +42 -17
- moai_adk/core/project/phase_executor.py +415 -58
- moai_adk/core/project/validator.py +6 -25
- moai_adk/core/quality/__init__.py +1 -1
- moai_adk/core/quality/trust_checker.py +64 -110
- moai_adk/core/quality/validators/__init__.py +1 -1
- moai_adk/core/quality/validators/base_validator.py +1 -1
- moai_adk/core/rollback_manager.py +993 -0
- moai_adk/core/session_manager.py +667 -0
- moai_adk/core/spec/confidence_scoring.py +749 -0
- moai_adk/core/spec/ears_template_engine.py +1182 -0
- moai_adk/core/spec/quality_validator.py +721 -0
- moai_adk/core/spec_status_manager.py +488 -0
- moai_adk/core/template/__init__.py +0 -1
- moai_adk/core/template/backup.py +41 -1
- moai_adk/core/template/config.py +11 -12
- moai_adk/core/template/languages.py +0 -1
- moai_adk/core/template/merger.py +79 -22
- moai_adk/core/template/processor.py +614 -40
- moai_adk/core/template_engine.py +36 -27
- moai_adk/foundation/git/commit_templates.py +565 -0
- moai_adk/foundation/trust/trust_principles.py +725 -0
- moai_adk/foundation/trust/validation_checklist.py +1678 -0
- moai_adk/statusline/__init__.py +38 -0
- moai_adk/statusline/alfred_detector.py +107 -0
- moai_adk/statusline/config.py +364 -0
- moai_adk/statusline/enhanced_output_style_detector.py +364 -0
- moai_adk/statusline/git_collector.py +190 -0
- moai_adk/statusline/main.py +228 -0
- moai_adk/statusline/metrics_tracker.py +78 -0
- moai_adk/statusline/renderer.py +327 -0
- moai_adk/statusline/update_checker.py +135 -0
- moai_adk/statusline/version_reader.py +647 -0
- moai_adk/templates/.git-hooks/pre-commit +66 -0
- moai_adk/templates/.git-hooks/pre-push +116 -4
- moai_adk/templates/.github/workflows/moai-gitflow.yml +1 -7
- moai_adk/templates/.github/workflows/spec-issue-sync.yml +0 -1
- moai_adk/templates/.gitignore +44 -0
- moai_adk/templates/.mcp.json +22 -0
- moai_adk/templates/CLAUDE.md +450 -1071
- moai_adk/utils/__init__.py +0 -1
- moai_adk/utils/banner.py +0 -1
- moai_adk/utils/common.py +308 -0
- moai_adk/utils/link_validator.py +249 -0
- moai_adk/utils/logger.py +4 -9
- moai_adk/utils/safe_file_reader.py +210 -0
- moai_adk/utils/user_experience.py +531 -0
- moai_adk-0.25.4.dist-info/METADATA +2279 -0
- moai_adk-0.25.4.dist-info/RECORD +112 -0
- moai_adk/core/tags/__init__.py +0 -86
- moai_adk/core/tags/ci_validator.py +0 -463
- moai_adk/core/tags/cli.py +0 -283
- moai_adk/core/tags/generator.py +0 -109
- moai_adk/core/tags/inserter.py +0 -99
- moai_adk/core/tags/mapper.py +0 -126
- moai_adk/core/tags/parser.py +0 -76
- moai_adk/core/tags/pre_commit_validator.py +0 -393
- moai_adk/core/tags/reporter.py +0 -956
- moai_adk/core/tags/tags.py +0 -149
- moai_adk/core/tags/validator.py +0 -897
- moai_adk/templates/.claude/agents/alfred/backend-expert.md +0 -319
- moai_adk/templates/.claude/agents/alfred/cc-manager.md +0 -316
- moai_adk/templates/.claude/agents/alfred/debug-helper.md +0 -208
- moai_adk/templates/.claude/agents/alfred/devops-expert.md +0 -464
- moai_adk/templates/.claude/agents/alfred/doc-syncer.md +0 -214
- moai_adk/templates/.claude/agents/alfred/frontend-expert.md +0 -357
- moai_adk/templates/.claude/agents/alfred/git-manager.md +0 -406
- moai_adk/templates/.claude/agents/alfred/implementation-planner.md +0 -423
- moai_adk/templates/.claude/agents/alfred/project-manager.md +0 -312
- moai_adk/templates/.claude/agents/alfred/quality-gate.md +0 -343
- moai_adk/templates/.claude/agents/alfred/skill-factory.md +0 -865
- moai_adk/templates/.claude/agents/alfred/spec-builder.md +0 -392
- moai_adk/templates/.claude/agents/alfred/tag-agent.md +0 -361
- moai_adk/templates/.claude/agents/alfred/tdd-implementer.md +0 -428
- moai_adk/templates/.claude/agents/alfred/trust-checker.md +0 -375
- moai_adk/templates/.claude/agents/alfred/ui-ux-expert.md +0 -571
- moai_adk/templates/.claude/commands/alfred/0-project.md +0 -1525
- moai_adk/templates/.claude/commands/alfred/1-plan.md +0 -802
- moai_adk/templates/.claude/commands/alfred/2-run.md +0 -709
- moai_adk/templates/.claude/commands/alfred/3-sync.md +0 -1009
- moai_adk/templates/.claude/commands/alfred/9-feedback.md +0 -149
- moai_adk/templates/.claude/hooks/alfred/core/project.py +0 -748
- moai_adk/templates/.claude/hooks/alfred/core/timeout.py +0 -136
- moai_adk/templates/.claude/hooks/alfred/core/ttl_cache.py +0 -108
- moai_adk/templates/.claude/hooks/alfred/core/version_cache.py +0 -198
- moai_adk/templates/.claude/hooks/alfred/handlers/__init__.py +0 -29
- moai_adk/templates/.claude/hooks/alfred/post_tool__log_changes.py +0 -94
- moai_adk/templates/.claude/hooks/alfred/pre_tool__auto_checkpoint.py +0 -100
- moai_adk/templates/.claude/hooks/alfred/session_end__cleanup.py +0 -94
- moai_adk/templates/.claude/hooks/alfred/session_start__show_project_info.py +0 -94
- moai_adk/templates/.claude/hooks/alfred/shared/core/__init__.py +0 -170
- moai_adk/templates/.claude/hooks/alfred/shared/core/checkpoint.py +0 -271
- moai_adk/templates/.claude/hooks/alfred/shared/core/context.py +0 -67
- moai_adk/templates/.claude/hooks/alfred/shared/core/project.py +0 -749
- moai_adk/templates/.claude/hooks/alfred/shared/core/tags.py +0 -230
- moai_adk/templates/.claude/hooks/alfred/shared/core/version_cache.py +0 -198
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/__init__.py +0 -21
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/notification.py +0 -154
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/session.py +0 -174
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/tool.py +0 -87
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/user.py +0 -61
- moai_adk/templates/.claude/hooks/alfred/user_prompt__jit_load_docs.py +0 -112
- moai_adk/templates/.claude/hooks/alfred/utils/__init__.py +0 -1
- moai_adk/templates/.claude/hooks/alfred/utils/timeout.py +0 -161
- moai_adk/templates/.claude/settings.json +0 -144
- moai_adk/templates/.claude/skills/moai-alfred-agent-guide/SKILL.md +0 -70
- moai_adk/templates/.claude/skills/moai-alfred-agent-guide/examples.md +0 -62
- moai_adk/templates/.claude/skills/moai-alfred-agent-guide/reference.md +0 -242
- moai_adk/templates/.claude/skills/moai-alfred-config-schema/SKILL.md +0 -56
- moai_adk/templates/.claude/skills/moai-alfred-config-schema/examples.md +0 -28
- moai_adk/templates/.claude/skills/moai-alfred-config-schema/reference.md +0 -444
- moai_adk/templates/.claude/skills/moai-alfred-context-budget/SKILL.md +0 -62
- moai_adk/templates/.claude/skills/moai-alfred-context-budget/examples.md +0 -28
- moai_adk/templates/.claude/skills/moai-alfred-context-budget/reference.md +0 -405
- moai_adk/templates/.claude/skills/moai-alfred-dev-guide/SKILL.md +0 -51
- moai_adk/templates/.claude/skills/moai-alfred-dev-guide/examples.md +0 -355
- moai_adk/templates/.claude/skills/moai-alfred-dev-guide/reference.md +0 -239
- moai_adk/templates/.claude/skills/moai-alfred-ears-authoring/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-alfred-ears-authoring/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-alfred-ears-authoring/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/SKILL.md +0 -323
- moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/examples.md +0 -286
- moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/reference.md +0 -126
- moai_adk/templates/.claude/skills/moai-alfred-git-workflow/SKILL.md +0 -122
- moai_adk/templates/.claude/skills/moai-alfred-git-workflow/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-alfred-git-workflow/reference.md +0 -29
- moai_adk/templates/.claude/skills/moai-alfred-gitflow-policy/SKILL.md +0 -74
- moai_adk/templates/.claude/skills/moai-alfred-gitflow-policy/examples.md +0 -4
- moai_adk/templates/.claude/skills/moai-alfred-gitflow-policy/reference.md +0 -269
- moai_adk/templates/.claude/skills/moai-alfred-interactive-questions/SKILL.md +0 -237
- moai_adk/templates/.claude/skills/moai-alfred-interactive-questions/examples.md +0 -615
- moai_adk/templates/.claude/skills/moai-alfred-interactive-questions/reference.md +0 -653
- moai_adk/templates/.claude/skills/moai-alfred-issue-labels/SKILL.md +0 -19
- moai_adk/templates/.claude/skills/moai-alfred-issue-labels/examples.md +0 -4
- moai_adk/templates/.claude/skills/moai-alfred-issue-labels/reference.md +0 -150
- moai_adk/templates/.claude/skills/moai-alfred-language-detection/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-alfred-language-detection/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-alfred-language-detection/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-alfred-persona-roles/SKILL.md +0 -198
- moai_adk/templates/.claude/skills/moai-alfred-persona-roles/examples.md +0 -431
- moai_adk/templates/.claude/skills/moai-alfred-persona-roles/reference.md +0 -141
- moai_adk/templates/.claude/skills/moai-alfred-practices/SKILL.md +0 -89
- moai_adk/templates/.claude/skills/moai-alfred-practices/examples.md +0 -122
- moai_adk/templates/.claude/skills/moai-alfred-practices/reference.md +0 -369
- moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/SKILL.md +0 -508
- moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/examples.md +0 -481
- moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/reference.md +0 -100
- moai_adk/templates/.claude/skills/moai-alfred-reporting/SKILL.md +0 -273
- moai_adk/templates/.claude/skills/moai-alfred-rules/SKILL.md +0 -77
- moai_adk/templates/.claude/skills/moai-alfred-rules/examples.md +0 -265
- moai_adk/templates/.claude/skills/moai-alfred-rules/reference.md +0 -539
- moai_adk/templates/.claude/skills/moai-alfred-session-state/SKILL.md +0 -19
- moai_adk/templates/.claude/skills/moai-alfred-session-state/examples.md +0 -4
- moai_adk/templates/.claude/skills/moai-alfred-session-state/reference.md +0 -84
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/README.md +0 -137
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/SKILL.md +0 -219
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/examples/validate-spec.sh +0 -161
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/examples.md +0 -541
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/reference.md +0 -622
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-extended/SKILL.md +0 -115
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-extended/examples.md +0 -4
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-extended/reference.md +0 -348
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-validation/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-validation/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-validation/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-alfred-tag-scanning/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-alfred-tag-scanning/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-alfred-tag-scanning/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/SKILL.md +0 -19
- moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/examples.md +0 -4
- moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/reference.md +0 -211
- moai_adk/templates/.claude/skills/moai-alfred-trust-validation/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-alfred-trust-validation/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-alfred-trust-validation/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-alfred-workflow/SKILL.md +0 -288
- moai_adk/templates/.claude/skills/moai-cc-agents/SKILL.md +0 -269
- moai_adk/templates/.claude/skills/moai-cc-agents/templates/agent-template.md +0 -32
- moai_adk/templates/.claude/skills/moai-cc-claude-md/SKILL.md +0 -298
- moai_adk/templates/.claude/skills/moai-cc-claude-md/templates/CLAUDE-template.md +0 -26
- moai_adk/templates/.claude/skills/moai-cc-commands/SKILL.md +0 -307
- moai_adk/templates/.claude/skills/moai-cc-commands/templates/command-template.md +0 -21
- moai_adk/templates/.claude/skills/moai-cc-hooks/SKILL.md +0 -252
- moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/pre-bash-check.sh +0 -19
- moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/preserve-permissions.sh +0 -19
- moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/validate-bash-command.py +0 -24
- moai_adk/templates/.claude/skills/moai-cc-mcp-plugins/SKILL.md +0 -199
- moai_adk/templates/.claude/skills/moai-cc-mcp-plugins/templates/settings-mcp-template.json +0 -39
- moai_adk/templates/.claude/skills/moai-cc-memory/SKILL.md +0 -316
- moai_adk/templates/.claude/skills/moai-cc-memory/templates/session-summary-template.md +0 -18
- moai_adk/templates/.claude/skills/moai-cc-settings/SKILL.md +0 -263
- moai_adk/templates/.claude/skills/moai-cc-settings/templates/settings-complete-template.json +0 -30
- moai_adk/templates/.claude/skills/moai-cc-skill-descriptions/SKILL.md +0 -19
- moai_adk/templates/.claude/skills/moai-cc-skill-descriptions/examples.md +0 -4
- moai_adk/templates/.claude/skills/moai-cc-skill-descriptions/reference.md +0 -218
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/CHECKLIST.md +0 -482
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/EXAMPLES.md +0 -278
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/INTERACTIVE-DISCOVERY.md +0 -524
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/METADATA.md +0 -477
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/PARALLEL-ANALYSIS-REPORT.md +0 -429
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/PYTHON-VERSION-MATRIX.md +0 -391
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL-FACTORY-WORKFLOW.md +0 -431
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL-UPDATE-ADVISOR.md +0 -577
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL.md +0 -271
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/STEP-BY-STEP-GUIDE.md +0 -466
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/STRUCTURE.md +0 -583
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/WEB-RESEARCH.md +0 -526
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/reference.md +0 -465
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/scripts/generate-structure.sh +0 -328
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/scripts/validate-skill.sh +0 -312
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/SKILL_TEMPLATE.md +0 -245
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/examples-template.md +0 -285
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/reference-template.md +0 -278
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/scripts-template.sh +0 -303
- moai_adk/templates/.claude/skills/moai-cc-skills/SKILL.md +0 -291
- moai_adk/templates/.claude/skills/moai-cc-skills/templates/SKILL-template.md +0 -15
- moai_adk/templates/.claude/skills/moai-design-systems/SKILL.md +0 -802
- moai_adk/templates/.claude/skills/moai-design-systems/examples.md +0 -1238
- moai_adk/templates/.claude/skills/moai-design-systems/reference.md +0 -673
- moai_adk/templates/.claude/skills/moai-domain-backend/SKILL.md +0 -290
- moai_adk/templates/.claude/skills/moai-domain-backend/examples.md +0 -1633
- moai_adk/templates/.claude/skills/moai-domain-backend/reference.md +0 -660
- moai_adk/templates/.claude/skills/moai-domain-cli-tool/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-domain-cli-tool/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-domain-cli-tool/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-domain-data-science/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-domain-data-science/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-domain-data-science/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-domain-database/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-domain-database/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-domain-database/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-domain-devops/SKILL.md +0 -124
- moai_adk/templates/.claude/skills/moai-domain-devops/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-domain-devops/reference.md +0 -31
- moai_adk/templates/.claude/skills/moai-domain-frontend/SKILL.md +0 -128
- moai_adk/templates/.claude/skills/moai-domain-frontend/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-domain-frontend/reference.md +0 -31
- moai_adk/templates/.claude/skills/moai-domain-ml/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-domain-ml/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-domain-ml/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-domain-mobile-app/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-domain-mobile-app/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-domain-mobile-app/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-domain-security/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-domain-security/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-domain-security/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-domain-web-api/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-domain-web-api/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-domain-web-api/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-essentials-debug/SKILL.md +0 -303
- moai_adk/templates/.claude/skills/moai-essentials-debug/examples.md +0 -1064
- moai_adk/templates/.claude/skills/moai-essentials-debug/reference.md +0 -1047
- moai_adk/templates/.claude/skills/moai-essentials-perf/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-essentials-perf/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-essentials-perf/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-essentials-refactor/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-essentials-refactor/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-essentials-refactor/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-essentials-review/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-essentials-review/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-essentials-review/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-foundation-ears/SKILL.md +0 -116
- moai_adk/templates/.claude/skills/moai-foundation-ears/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-foundation-ears/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-foundation-git/SKILL.md +0 -122
- moai_adk/templates/.claude/skills/moai-foundation-git/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-foundation-git/reference.md +0 -29
- moai_adk/templates/.claude/skills/moai-foundation-langs/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-foundation-langs/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-foundation-langs/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-foundation-specs/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-foundation-specs/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-foundation-specs/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-foundation-tags/SKILL.md +0 -113
- moai_adk/templates/.claude/skills/moai-foundation-tags/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-foundation-tags/reference.md +0 -28
- moai_adk/templates/.claude/skills/moai-foundation-trust/SKILL.md +0 -307
- moai_adk/templates/.claude/skills/moai-foundation-trust/examples.md +0 -0
- moai_adk/templates/.claude/skills/moai-foundation-trust/reference.md +0 -1099
- moai_adk/templates/.claude/skills/moai-lang-c/SKILL.md +0 -124
- moai_adk/templates/.claude/skills/moai-lang-c/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-c/reference.md +0 -31
- moai_adk/templates/.claude/skills/moai-lang-cpp/SKILL.md +0 -124
- moai_adk/templates/.claude/skills/moai-lang-cpp/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-cpp/reference.md +0 -31
- moai_adk/templates/.claude/skills/moai-lang-csharp/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-lang-csharp/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-csharp/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-lang-dart/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-lang-dart/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-dart/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-lang-go/SKILL.md +0 -127
- moai_adk/templates/.claude/skills/moai-lang-go/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-go/reference.md +0 -31
- moai_adk/templates/.claude/skills/moai-lang-java/SKILL.md +0 -126
- moai_adk/templates/.claude/skills/moai-lang-java/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-java/reference.md +0 -31
- moai_adk/templates/.claude/skills/moai-lang-javascript/SKILL.md +0 -125
- moai_adk/templates/.claude/skills/moai-lang-javascript/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-javascript/reference.md +0 -32
- moai_adk/templates/.claude/skills/moai-lang-kotlin/SKILL.md +0 -124
- moai_adk/templates/.claude/skills/moai-lang-kotlin/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-kotlin/reference.md +0 -31
- moai_adk/templates/.claude/skills/moai-lang-php/SKILL.md +0 -126
- moai_adk/templates/.claude/skills/moai-lang-php/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-php/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-lang-python/SKILL.md +0 -433
- moai_adk/templates/.claude/skills/moai-lang-python/examples.md +0 -624
- moai_adk/templates/.claude/skills/moai-lang-python/reference.md +0 -316
- moai_adk/templates/.claude/skills/moai-lang-r/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-lang-r/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-r/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-lang-ruby/SKILL.md +0 -124
- moai_adk/templates/.claude/skills/moai-lang-ruby/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-ruby/reference.md +0 -31
- moai_adk/templates/.claude/skills/moai-lang-rust/SKILL.md +0 -127
- moai_adk/templates/.claude/skills/moai-lang-rust/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-rust/reference.md +0 -31
- moai_adk/templates/.claude/skills/moai-lang-scala/SKILL.md +0 -125
- moai_adk/templates/.claude/skills/moai-lang-scala/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-scala/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-lang-shell/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-lang-shell/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-shell/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-lang-sql/SKILL.md +0 -124
- moai_adk/templates/.claude/skills/moai-lang-sql/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-sql/reference.md +0 -31
- moai_adk/templates/.claude/skills/moai-lang-swift/SKILL.md +0 -123
- moai_adk/templates/.claude/skills/moai-lang-swift/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-swift/reference.md +0 -30
- moai_adk/templates/.claude/skills/moai-lang-typescript/SKILL.md +0 -133
- moai_adk/templates/.claude/skills/moai-lang-typescript/examples.md +0 -29
- moai_adk/templates/.claude/skills/moai-lang-typescript/reference.md +0 -34
- moai_adk/templates/.claude/skills/moai-project-documentation.md +0 -622
- moai_adk/templates/.github/workflows/c-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/cpp-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/csharp-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/dart-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/go-tag-validation.yml +0 -130
- moai_adk/templates/.github/workflows/java-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/javascript-tag-validation.yml +0 -135
- moai_adk/templates/.github/workflows/kotlin-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/php-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/python-tag-validation.yml +0 -118
- moai_adk/templates/.github/workflows/release.yml +0 -118
- moai_adk/templates/.github/workflows/ruby-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/rust-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/shell-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/swift-tag-validation.yml +0 -11
- moai_adk/templates/.github/workflows/tag-report.yml +0 -269
- moai_adk/templates/.github/workflows/tag-validation.yml +0 -186
- moai_adk/templates/.github/workflows/typescript-tag-validation.yml +0 -154
- moai_adk/templates/.moai/config.json +0 -115
- moai_adk/templates/workflows/go-tag-validation.yml +0 -30
- moai_adk/templates/workflows/javascript-tag-validation.yml +0 -41
- moai_adk/templates/workflows/python-tag-validation.yml +0 -42
- moai_adk/templates/workflows/typescript-tag-validation.yml +0 -31
- moai_adk-0.15.0.dist-info/METADATA +0 -3079
- moai_adk-0.15.0.dist-info/RECORD +0 -365
- {moai_adk-0.15.0.dist-info → moai_adk-0.25.4.dist-info}/WHEEL +0 -0
- {moai_adk-0.15.0.dist-info → moai_adk-0.25.4.dist-info}/entry_points.txt +0 -0
- {moai_adk-0.15.0.dist-info → moai_adk-0.25.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,22 +1,93 @@
|
|
|
1
|
-
#
|
|
2
|
-
"""Template copy and backup processor
|
|
1
|
+
# # REMOVED_ORPHAN_CODE:TEMPLATE-001 | SPEC: SPEC-INIT-003/spec.md | Chain: TEMPLATE-001
|
|
2
|
+
"""Enhanced Template copy and backup processor with improved version handling and validation.
|
|
3
|
+
|
|
4
|
+
SPEC-INIT-003 v0.3.0: preserve user content
|
|
5
|
+
Enhanced with:
|
|
6
|
+
- Comprehensive version field management
|
|
7
|
+
- Template substitution validation
|
|
8
|
+
- Performance optimization
|
|
9
|
+
- Error handling improvements
|
|
10
|
+
- Configuration-driven behavior
|
|
11
|
+
"""
|
|
3
12
|
|
|
4
13
|
from __future__ import annotations
|
|
5
14
|
|
|
15
|
+
import logging
|
|
6
16
|
import re
|
|
7
17
|
import shutil
|
|
18
|
+
from dataclasses import dataclass
|
|
8
19
|
from pathlib import Path
|
|
20
|
+
from typing import Any, Dict, List, Optional
|
|
9
21
|
|
|
10
22
|
from rich.console import Console
|
|
11
23
|
|
|
12
24
|
from moai_adk.core.template.backup import TemplateBackup
|
|
13
25
|
from moai_adk.core.template.merger import TemplateMerger
|
|
26
|
+
from moai_adk.statusline.version_reader import VersionConfig, VersionReader
|
|
14
27
|
|
|
15
28
|
console = Console()
|
|
16
29
|
|
|
17
30
|
|
|
31
|
+
@dataclass
|
|
32
|
+
class TemplateProcessorConfig:
|
|
33
|
+
"""Configuration for TemplateProcessor behavior."""
|
|
34
|
+
|
|
35
|
+
# Version handling configuration
|
|
36
|
+
version_cache_ttl_seconds: int = 120
|
|
37
|
+
version_fallback: str = "unknown"
|
|
38
|
+
version_format_regex: str = r"^v?(\d+\.\d+\.\d+(-[a-zA-Z0-9]+)?)$"
|
|
39
|
+
enable_version_validation: bool = True
|
|
40
|
+
preserve_user_version: bool = True
|
|
41
|
+
|
|
42
|
+
# Template substitution configuration
|
|
43
|
+
validate_template_variables: bool = True
|
|
44
|
+
max_variable_length: int = 50
|
|
45
|
+
allowed_variable_pattern: str = r"^[A-Z_]+$"
|
|
46
|
+
enable_substitution_warnings: bool = True
|
|
47
|
+
|
|
48
|
+
# Performance configuration
|
|
49
|
+
enable_caching: bool = True
|
|
50
|
+
cache_size: int = 100
|
|
51
|
+
async_operations: bool = False
|
|
52
|
+
|
|
53
|
+
# Error handling configuration
|
|
54
|
+
graceful_degradation: bool = True
|
|
55
|
+
verbose_logging: bool = False
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def from_dict(cls, config_dict: Dict[str, Any]) -> "TemplateProcessorConfig":
|
|
59
|
+
"""Create config from dictionary."""
|
|
60
|
+
config_dict = config_dict or {}
|
|
61
|
+
return cls(
|
|
62
|
+
version_cache_ttl_seconds=config_dict.get("version_cache_ttl_seconds", 120),
|
|
63
|
+
version_fallback=config_dict.get("version_fallback", "unknown"),
|
|
64
|
+
version_format_regex=config_dict.get(
|
|
65
|
+
"version_format_regex", r"^v?(\d+\.\d+\.\d+(-[a-zA-Z0-9]+)?)$"
|
|
66
|
+
),
|
|
67
|
+
enable_version_validation=config_dict.get(
|
|
68
|
+
"enable_version_validation", True
|
|
69
|
+
),
|
|
70
|
+
preserve_user_version=config_dict.get("preserve_user_version", True),
|
|
71
|
+
validate_template_variables=config_dict.get(
|
|
72
|
+
"validate_template_variables", True
|
|
73
|
+
),
|
|
74
|
+
max_variable_length=config_dict.get("max_variable_length", 50),
|
|
75
|
+
allowed_variable_pattern=config_dict.get(
|
|
76
|
+
"allowed_variable_pattern", r"^[A-Z_]+$"
|
|
77
|
+
),
|
|
78
|
+
enable_substitution_warnings=config_dict.get(
|
|
79
|
+
"enable_substitution_warnings", True
|
|
80
|
+
),
|
|
81
|
+
enable_caching=config_dict.get("enable_caching", True),
|
|
82
|
+
cache_size=config_dict.get("cache_size", 100),
|
|
83
|
+
async_operations=config_dict.get("async_operations", False),
|
|
84
|
+
graceful_degradation=config_dict.get("graceful_degradation", True),
|
|
85
|
+
verbose_logging=config_dict.get("verbose_logging", False),
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
18
89
|
class TemplateProcessor:
|
|
19
|
-
"""Orchestrate template copying and backups."""
|
|
90
|
+
"""Orchestrate template copying and backups with enhanced version handling and validation."""
|
|
20
91
|
|
|
21
92
|
# User data protection paths (never touch) - SPEC-INIT-003 v0.3.0
|
|
22
93
|
PROTECTED_PATHS = [
|
|
@@ -30,17 +101,363 @@ class TemplateProcessor:
|
|
|
30
101
|
# Paths excluded from backups
|
|
31
102
|
BACKUP_EXCLUDE = PROTECTED_PATHS
|
|
32
103
|
|
|
33
|
-
|
|
34
|
-
|
|
104
|
+
# Common template variables with validation hints
|
|
105
|
+
COMMON_TEMPLATE_VARIABLES = {
|
|
106
|
+
"PROJECT_DIR": "Cross-platform project path (run /alfred:0-project to set)",
|
|
107
|
+
"HOOK_PROJECT_DIR": "Cross-platform hook path (deprecated, use PROJECT_DIR instead)",
|
|
108
|
+
"PROJECT_NAME": "Project name (run /alfred:0-project to set)",
|
|
109
|
+
"AUTHOR": "Project author (run /alfred:0-project to set)",
|
|
110
|
+
"CONVERSATION_LANGUAGE": "Interface language (run /alfred:0-project to set)",
|
|
111
|
+
"MOAI_VERSION": "MoAI-ADK version (should be set automatically)",
|
|
112
|
+
"MOAI_VERSION_SHORT": "Short MoAI-ADK version (without 'v' prefix)",
|
|
113
|
+
"MOAI_VERSION_DISPLAY": "Display version with proper formatting",
|
|
114
|
+
"MOAI_VERSION_TRIMMED": "Trimmed version for UI displays",
|
|
115
|
+
"MOAI_VERSION_SEMVER": "Semantic version format (major.minor.patch)",
|
|
116
|
+
"MOAI_VERSION_VALID": "Version validation status",
|
|
117
|
+
"MOAI_VERSION_SOURCE": "Version source information",
|
|
118
|
+
"MOAI_VERSION_CACHE_AGE": "Cache age for debugging",
|
|
119
|
+
"CREATION_TIMESTAMP": "Project creation timestamp",
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
def __init__(
|
|
123
|
+
self, target_path: Path, config: Optional[TemplateProcessorConfig] = None
|
|
124
|
+
) -> None:
|
|
125
|
+
"""Initialize the processor with enhanced configuration.
|
|
35
126
|
|
|
36
127
|
Args:
|
|
37
128
|
target_path: Project path.
|
|
129
|
+
config: Optional configuration for processor behavior.
|
|
38
130
|
"""
|
|
39
131
|
self.target_path = target_path.resolve()
|
|
40
132
|
self.template_root = self._get_template_root()
|
|
41
133
|
self.backup = TemplateBackup(self.target_path)
|
|
42
134
|
self.merger = TemplateMerger(self.target_path)
|
|
43
135
|
self.context: dict[str, str] = {} # Template variable substitution context
|
|
136
|
+
self._version_reader: VersionReader | None = None
|
|
137
|
+
self.config = config or TemplateProcessorConfig()
|
|
138
|
+
self._substitution_cache: Dict[str, str] = {} # Cache for substitution results
|
|
139
|
+
self._variable_validation_cache: Dict[str, bool] = (
|
|
140
|
+
{}
|
|
141
|
+
) # Cache for variable validation
|
|
142
|
+
self.logger = logging.getLogger(__name__)
|
|
143
|
+
|
|
144
|
+
if self.config.verbose_logging:
|
|
145
|
+
self.logger.info(
|
|
146
|
+
f"TemplateProcessor initialized with config: {self.config}"
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
def set_context(self, context: dict[str, str]) -> None:
|
|
150
|
+
"""Set variable substitution context with enhanced validation.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
context: Dictionary of template variables.
|
|
154
|
+
"""
|
|
155
|
+
self.context = context
|
|
156
|
+
self._substitution_cache.clear() # Clear cache when context changes
|
|
157
|
+
self._variable_validation_cache.clear()
|
|
158
|
+
|
|
159
|
+
if self.config.verbose_logging:
|
|
160
|
+
self.logger.debug(f"Context set with {len(context)} variables")
|
|
161
|
+
|
|
162
|
+
# Validate template variables if enabled
|
|
163
|
+
if self.config.validate_template_variables:
|
|
164
|
+
self._validate_template_variables(context)
|
|
165
|
+
|
|
166
|
+
# Add deprecation mapping for HOOK_PROJECT_DIR
|
|
167
|
+
if "PROJECT_DIR" in self.context and "HOOK_PROJECT_DIR" not in self.context:
|
|
168
|
+
self.context["HOOK_PROJECT_DIR"] = self.context["PROJECT_DIR"]
|
|
169
|
+
|
|
170
|
+
def _get_version_reader(self) -> VersionReader:
|
|
171
|
+
"""
|
|
172
|
+
Get or create version reader instance with enhanced configuration.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
VersionReader instance
|
|
176
|
+
"""
|
|
177
|
+
if self._version_reader is None:
|
|
178
|
+
version_config = VersionConfig(
|
|
179
|
+
cache_ttl_seconds=self.config.version_cache_ttl_seconds,
|
|
180
|
+
fallback_version=self.config.version_fallback,
|
|
181
|
+
version_format_regex=self.config.version_format_regex,
|
|
182
|
+
debug_mode=self.config.verbose_logging,
|
|
183
|
+
)
|
|
184
|
+
self._version_reader = VersionReader(version_config)
|
|
185
|
+
|
|
186
|
+
if self.config.verbose_logging:
|
|
187
|
+
self.logger.info("VersionReader created with enhanced configuration")
|
|
188
|
+
return self._version_reader
|
|
189
|
+
|
|
190
|
+
def _validate_template_variables(self, context: Dict[str, str]) -> None:
|
|
191
|
+
"""
|
|
192
|
+
Validate template variables with comprehensive checking.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
context: Dictionary of template variables to validate
|
|
196
|
+
"""
|
|
197
|
+
import re
|
|
198
|
+
|
|
199
|
+
if not self.config.validate_template_variables:
|
|
200
|
+
return
|
|
201
|
+
|
|
202
|
+
validation_errors: List[str] = []
|
|
203
|
+
warning_messages: List[str] = []
|
|
204
|
+
|
|
205
|
+
# Check variable names against pattern
|
|
206
|
+
variable_pattern = re.compile(self.config.allowed_variable_pattern)
|
|
207
|
+
|
|
208
|
+
for var_name, var_value in context.items():
|
|
209
|
+
# Check variable name format
|
|
210
|
+
if not variable_pattern.match(var_name):
|
|
211
|
+
validation_errors.append(f"Invalid variable name format: '{var_name}'")
|
|
212
|
+
continue
|
|
213
|
+
|
|
214
|
+
# Check variable length
|
|
215
|
+
if len(var_name) > self.config.max_variable_length:
|
|
216
|
+
warning_messages.append(
|
|
217
|
+
f"Variable name '{var_name}' exceeds maximum length"
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
# Check variable value length
|
|
221
|
+
if len(var_value) > self.config.max_variable_length * 2:
|
|
222
|
+
warning_messages.append(
|
|
223
|
+
f"Variable value '{var_value[:20]}...' is very long"
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
# Check for potentially dangerous values
|
|
227
|
+
if "{{" in var_value or "}}" in var_value:
|
|
228
|
+
warning_messages.append(
|
|
229
|
+
f"Variable '{var_name}' contains placeholder patterns"
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
# Check for common variables that should be present
|
|
233
|
+
missing_common_vars = []
|
|
234
|
+
for common_var in self.COMMON_TEMPLATE_VARIABLES:
|
|
235
|
+
if common_var not in context:
|
|
236
|
+
missing_common_vars.append(common_var)
|
|
237
|
+
|
|
238
|
+
if missing_common_vars and self.config.enable_substitution_warnings:
|
|
239
|
+
warning_messages.append(
|
|
240
|
+
f"Common variables missing: {', '.join(missing_common_vars[:3])}"
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
# Report validation results
|
|
244
|
+
if validation_errors and not self.config.graceful_degradation:
|
|
245
|
+
raise ValueError(
|
|
246
|
+
f"Template variable validation failed: {validation_errors}"
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
if validation_errors and self.config.graceful_degradation:
|
|
250
|
+
self.logger.warning(
|
|
251
|
+
f"Template variable validation warnings: {validation_errors}"
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
if warning_messages and self.config.enable_substitution_warnings:
|
|
255
|
+
self.logger.warning(f"Template variable warnings: {warning_messages}")
|
|
256
|
+
|
|
257
|
+
if self.config.verbose_logging:
|
|
258
|
+
self.logger.debug(
|
|
259
|
+
f"Template variables validated: {len(context)} variables checked"
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
def get_enhanced_version_context(self) -> dict[str, str]:
|
|
263
|
+
"""
|
|
264
|
+
Get enhanced version context with proper error handling and caching.
|
|
265
|
+
|
|
266
|
+
Returns comprehensive version information including multiple format options
|
|
267
|
+
and debugging information.
|
|
268
|
+
|
|
269
|
+
Returns:
|
|
270
|
+
Dictionary containing enhanced version-related template variables
|
|
271
|
+
"""
|
|
272
|
+
version_context = {}
|
|
273
|
+
logger = logging.getLogger(__name__)
|
|
274
|
+
|
|
275
|
+
try:
|
|
276
|
+
version_reader = self._get_version_reader()
|
|
277
|
+
moai_version = version_reader.get_version()
|
|
278
|
+
|
|
279
|
+
# Basic version information
|
|
280
|
+
version_context["MOAI_VERSION"] = moai_version
|
|
281
|
+
version_context["MOAI_VERSION_SHORT"] = self._format_short_version(
|
|
282
|
+
moai_version
|
|
283
|
+
)
|
|
284
|
+
version_context["MOAI_VERSION_DISPLAY"] = self._format_display_version(
|
|
285
|
+
moai_version
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
# Enhanced formatting options
|
|
289
|
+
version_context["MOAI_VERSION_TRIMMED"] = self._format_trimmed_version(
|
|
290
|
+
moai_version, max_length=10
|
|
291
|
+
)
|
|
292
|
+
version_context["MOAI_VERSION_SEMVER"] = self._format_semver_version(
|
|
293
|
+
moai_version
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
# Validation and source information
|
|
297
|
+
version_context["MOAI_VERSION_VALID"] = (
|
|
298
|
+
"true" if moai_version != "unknown" else "false"
|
|
299
|
+
)
|
|
300
|
+
version_context["MOAI_VERSION_SOURCE"] = self._get_version_source(
|
|
301
|
+
version_reader
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
# Performance metrics
|
|
305
|
+
cache_age = version_reader.get_cache_age_seconds()
|
|
306
|
+
if cache_age is not None:
|
|
307
|
+
version_context["MOAI_VERSION_CACHE_AGE"] = f"{cache_age:.2f}s"
|
|
308
|
+
else:
|
|
309
|
+
version_context["MOAI_VERSION_CACHE_AGE"] = "uncached"
|
|
310
|
+
|
|
311
|
+
# Additional metadata
|
|
312
|
+
if self.config.enable_version_validation:
|
|
313
|
+
is_valid = self._is_valid_version_format(moai_version)
|
|
314
|
+
version_context["MOAI_VERSION_FORMAT_VALID"] = (
|
|
315
|
+
"true" if is_valid else "false"
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
if self.config.verbose_logging:
|
|
319
|
+
logger.debug(f"Enhanced version context generated: {version_context}")
|
|
320
|
+
|
|
321
|
+
except Exception as e:
|
|
322
|
+
logger.warning(f"Failed to read version for template context: {e}")
|
|
323
|
+
# Use fallback version with comprehensive formatting
|
|
324
|
+
fallback_version = self.config.version_fallback
|
|
325
|
+
version_context["MOAI_VERSION"] = fallback_version
|
|
326
|
+
version_context["MOAI_VERSION_SHORT"] = self._format_short_version(
|
|
327
|
+
fallback_version
|
|
328
|
+
)
|
|
329
|
+
version_context["MOAI_VERSION_DISPLAY"] = self._format_display_version(
|
|
330
|
+
fallback_version
|
|
331
|
+
)
|
|
332
|
+
version_context["MOAI_VERSION_TRIMMED"] = self._format_trimmed_version(
|
|
333
|
+
fallback_version, max_length=10
|
|
334
|
+
)
|
|
335
|
+
version_context["MOAI_VERSION_SEMVER"] = self._format_semver_version(
|
|
336
|
+
fallback_version
|
|
337
|
+
)
|
|
338
|
+
version_context["MOAI_VERSION_VALID"] = (
|
|
339
|
+
"false" if fallback_version == "unknown" else "true"
|
|
340
|
+
)
|
|
341
|
+
version_context["MOAI_VERSION_SOURCE"] = "fallback_config"
|
|
342
|
+
version_context["MOAI_VERSION_CACHE_AGE"] = "unavailable"
|
|
343
|
+
version_context["MOAI_VERSION_FORMAT_VALID"] = "false"
|
|
344
|
+
|
|
345
|
+
return version_context
|
|
346
|
+
|
|
347
|
+
def _is_valid_version_format(self, version: str) -> bool:
|
|
348
|
+
"""
|
|
349
|
+
Validate version format using configured regex pattern.
|
|
350
|
+
|
|
351
|
+
Args:
|
|
352
|
+
version: Version string to validate
|
|
353
|
+
|
|
354
|
+
Returns:
|
|
355
|
+
True if version format is valid
|
|
356
|
+
"""
|
|
357
|
+
import re
|
|
358
|
+
|
|
359
|
+
try:
|
|
360
|
+
pattern = re.compile(self.config.version_format_regex)
|
|
361
|
+
return bool(pattern.match(version))
|
|
362
|
+
except re.error:
|
|
363
|
+
# Fallback to default pattern if custom one is invalid
|
|
364
|
+
default_pattern = re.compile(r"^v?(\d+\.\d+\.\d+(-[a-zA-Z0-9]+)?)$")
|
|
365
|
+
return bool(default_pattern.match(version))
|
|
366
|
+
|
|
367
|
+
def _format_short_version(self, version: str) -> str:
|
|
368
|
+
"""
|
|
369
|
+
Format short version by removing 'v' prefix if present.
|
|
370
|
+
|
|
371
|
+
Args:
|
|
372
|
+
version: Version string
|
|
373
|
+
|
|
374
|
+
Returns:
|
|
375
|
+
Short version string
|
|
376
|
+
"""
|
|
377
|
+
return version[1:] if version.startswith("v") else version
|
|
378
|
+
|
|
379
|
+
def _format_display_version(self, version: str) -> str:
|
|
380
|
+
"""
|
|
381
|
+
Format display version with proper formatting.
|
|
382
|
+
|
|
383
|
+
Args:
|
|
384
|
+
version: Version string
|
|
385
|
+
|
|
386
|
+
Returns:
|
|
387
|
+
Display version string
|
|
388
|
+
"""
|
|
389
|
+
if version == "unknown":
|
|
390
|
+
return "MoAI-ADK unknown version"
|
|
391
|
+
elif version.startswith("v"):
|
|
392
|
+
return f"MoAI-ADK {version}"
|
|
393
|
+
else:
|
|
394
|
+
return f"MoAI-ADK v{version}"
|
|
395
|
+
|
|
396
|
+
def _format_trimmed_version(self, version: str, max_length: int = 10) -> str:
|
|
397
|
+
"""
|
|
398
|
+
Format version with maximum length, suitable for UI displays.
|
|
399
|
+
|
|
400
|
+
Args:
|
|
401
|
+
version: Version string
|
|
402
|
+
max_length: Maximum allowed length for the version string
|
|
403
|
+
|
|
404
|
+
Returns:
|
|
405
|
+
Trimmed version string
|
|
406
|
+
"""
|
|
407
|
+
if version == "unknown":
|
|
408
|
+
return "unknown"
|
|
409
|
+
|
|
410
|
+
# Remove 'v' prefix for trimming
|
|
411
|
+
clean_version = version[1:] if version.startswith("v") else version
|
|
412
|
+
|
|
413
|
+
# Trim if necessary
|
|
414
|
+
if len(clean_version) > max_length:
|
|
415
|
+
return clean_version[:max_length]
|
|
416
|
+
return clean_version
|
|
417
|
+
|
|
418
|
+
def _format_semver_version(self, version: str) -> str:
|
|
419
|
+
"""
|
|
420
|
+
Format version as semantic version with major.minor.patch structure.
|
|
421
|
+
|
|
422
|
+
Args:
|
|
423
|
+
version: Version string
|
|
424
|
+
|
|
425
|
+
Returns:
|
|
426
|
+
Semantic version string
|
|
427
|
+
"""
|
|
428
|
+
if version == "unknown":
|
|
429
|
+
return "0.0.0"
|
|
430
|
+
|
|
431
|
+
# Remove 'v' prefix and extract semantic version
|
|
432
|
+
clean_version = version[1:] if version.startswith("v") else version
|
|
433
|
+
|
|
434
|
+
# Extract core semantic version (remove pre-release and build metadata)
|
|
435
|
+
import re
|
|
436
|
+
|
|
437
|
+
semver_match = re.match(r"^(\d+\.\d+\.\d+)", clean_version)
|
|
438
|
+
if semver_match:
|
|
439
|
+
return semver_match.group(1)
|
|
440
|
+
return "0.0.0"
|
|
441
|
+
|
|
442
|
+
def _get_version_source(self, version_reader: VersionReader) -> str:
|
|
443
|
+
"""
|
|
444
|
+
Determine the source of the version information.
|
|
445
|
+
|
|
446
|
+
Args:
|
|
447
|
+
version_reader: VersionReader instance
|
|
448
|
+
|
|
449
|
+
Returns:
|
|
450
|
+
String indicating version source
|
|
451
|
+
"""
|
|
452
|
+
config = version_reader.get_config()
|
|
453
|
+
cache_age = version_reader.get_cache_age_seconds()
|
|
454
|
+
|
|
455
|
+
if cache_age is not None and cache_age < config.cache_ttl_seconds:
|
|
456
|
+
return "config_cached"
|
|
457
|
+
elif cache_age is not None:
|
|
458
|
+
return "config_stale"
|
|
459
|
+
else:
|
|
460
|
+
return config.fallback_source.value
|
|
44
461
|
|
|
45
462
|
def _get_template_root(self) -> Path:
|
|
46
463
|
"""Return the template root path."""
|
|
@@ -58,28 +475,142 @@ class TemplateProcessor:
|
|
|
58
475
|
self.context = context
|
|
59
476
|
|
|
60
477
|
def _substitute_variables(self, content: str) -> tuple[str, list[str]]:
|
|
61
|
-
"""
|
|
478
|
+
"""
|
|
479
|
+
Substitute template variables in content with enhanced validation and caching.
|
|
480
|
+
|
|
481
|
+
Args:
|
|
482
|
+
content: Content to substitute variables in
|
|
62
483
|
|
|
63
484
|
Returns:
|
|
64
485
|
Tuple of (substituted_content, warnings_list)
|
|
65
486
|
"""
|
|
66
487
|
warnings = []
|
|
67
|
-
|
|
68
|
-
|
|
488
|
+
logger = logging.getLogger(__name__)
|
|
489
|
+
|
|
490
|
+
# Check cache first if enabled
|
|
491
|
+
cache_key = hash((frozenset(self.context.items()), content[:1000]))
|
|
492
|
+
if self.config.enable_caching and cache_key in self._substitution_cache:
|
|
493
|
+
cached_result = self._substitution_cache[cache_key]
|
|
494
|
+
if self.config.verbose_logging:
|
|
495
|
+
logger.debug("Using cached substitution result")
|
|
496
|
+
return cached_result
|
|
497
|
+
|
|
498
|
+
# Enhanced variable substitution with validation
|
|
499
|
+
substitution_count = 0
|
|
69
500
|
for key, value in self.context.items():
|
|
70
501
|
placeholder = f"{{{{{key}}}}}" # {{KEY}}
|
|
71
502
|
if placeholder in content:
|
|
503
|
+
if self.config.validate_template_variables:
|
|
504
|
+
# Validate variable before substitution
|
|
505
|
+
if not self._is_valid_template_variable(key, value):
|
|
506
|
+
warnings.append(
|
|
507
|
+
f"Invalid variable {key} - skipped substitution"
|
|
508
|
+
)
|
|
509
|
+
continue
|
|
510
|
+
|
|
72
511
|
safe_value = self._sanitize_value(value)
|
|
73
512
|
content = content.replace(placeholder, safe_value)
|
|
513
|
+
substitution_count += 1
|
|
74
514
|
|
|
75
|
-
|
|
76
|
-
|
|
515
|
+
if self.config.verbose_logging:
|
|
516
|
+
logger.debug(f"Substituted {key}: {safe_value[:50]}...")
|
|
517
|
+
|
|
518
|
+
# Detect unsubstituted variables with enhanced error messages
|
|
519
|
+
remaining = re.findall(r"\{\{([A-Z_]+)\}\}", content)
|
|
77
520
|
if remaining:
|
|
78
521
|
unique_remaining = sorted(set(remaining))
|
|
79
|
-
|
|
522
|
+
|
|
523
|
+
# Build detailed warning message with enhanced suggestions
|
|
524
|
+
warning_parts = []
|
|
525
|
+
for var in unique_remaining:
|
|
526
|
+
if var in self.COMMON_TEMPLATE_VARIABLES:
|
|
527
|
+
suggestion = self.COMMON_TEMPLATE_VARIABLES[var]
|
|
528
|
+
warning_parts.append(f"{{{{{var}}}}} → {suggestion}")
|
|
529
|
+
else:
|
|
530
|
+
warning_parts.append(
|
|
531
|
+
f"{{{{{var}}}}} → Unknown variable (check template)"
|
|
532
|
+
)
|
|
533
|
+
|
|
534
|
+
warnings.append("Template variables not substituted:")
|
|
535
|
+
warnings.extend(f" • {part}" for part in warning_parts)
|
|
536
|
+
|
|
537
|
+
if self.config.enable_substitution_warnings:
|
|
538
|
+
warnings.append(
|
|
539
|
+
"💡 Run 'uv run moai-adk update' to fix template variables"
|
|
540
|
+
)
|
|
541
|
+
|
|
542
|
+
# Add performance information if verbose logging is enabled
|
|
543
|
+
if self.config.verbose_logging:
|
|
544
|
+
warnings.append(f" 📊 Substituted {substitution_count} variables")
|
|
545
|
+
|
|
546
|
+
# Cache the result if enabled
|
|
547
|
+
if self.config.enable_caching:
|
|
548
|
+
result = (content, warnings)
|
|
549
|
+
self._substitution_cache[cache_key] = result
|
|
550
|
+
|
|
551
|
+
# Manage cache size
|
|
552
|
+
if len(self._substitution_cache) > self.config.cache_size:
|
|
553
|
+
# Remove oldest entry (simple FIFO)
|
|
554
|
+
oldest_key = next(iter(self._substitution_cache))
|
|
555
|
+
del self._substitution_cache[oldest_key]
|
|
556
|
+
if self.config.verbose_logging:
|
|
557
|
+
logger.debug("Cache size limit reached, removed oldest entry")
|
|
80
558
|
|
|
81
559
|
return content, warnings
|
|
82
560
|
|
|
561
|
+
def _is_valid_template_variable(self, key: str, value: str) -> bool:
|
|
562
|
+
"""
|
|
563
|
+
Validate a template variable before substitution.
|
|
564
|
+
|
|
565
|
+
Args:
|
|
566
|
+
key: Variable name
|
|
567
|
+
value: Variable value
|
|
568
|
+
|
|
569
|
+
Returns:
|
|
570
|
+
True if variable is valid
|
|
571
|
+
"""
|
|
572
|
+
import re
|
|
573
|
+
|
|
574
|
+
# Check variable name format
|
|
575
|
+
if not re.match(self.config.allowed_variable_pattern, key):
|
|
576
|
+
return False
|
|
577
|
+
|
|
578
|
+
# Check variable length
|
|
579
|
+
if len(key) > self.config.max_variable_length:
|
|
580
|
+
return False
|
|
581
|
+
|
|
582
|
+
# Check value length
|
|
583
|
+
if len(value) > self.config.max_variable_length * 2:
|
|
584
|
+
return False
|
|
585
|
+
|
|
586
|
+
# Note: {{ }} patterns are handled by sanitization, not validation
|
|
587
|
+
|
|
588
|
+
# Check for empty values
|
|
589
|
+
if not value.strip():
|
|
590
|
+
return False
|
|
591
|
+
|
|
592
|
+
return True
|
|
593
|
+
|
|
594
|
+
def clear_substitution_cache(self) -> None:
|
|
595
|
+
"""Clear the substitution cache."""
|
|
596
|
+
self._substitution_cache.clear()
|
|
597
|
+
if self.config.verbose_logging:
|
|
598
|
+
self.logger.debug("Substitution cache cleared")
|
|
599
|
+
|
|
600
|
+
def get_cache_stats(self) -> Dict[str, Any]:
|
|
601
|
+
"""
|
|
602
|
+
Get cache statistics.
|
|
603
|
+
|
|
604
|
+
Returns:
|
|
605
|
+
Dictionary containing cache statistics
|
|
606
|
+
"""
|
|
607
|
+
return {
|
|
608
|
+
"cache_size": len(self._substitution_cache),
|
|
609
|
+
"max_cache_size": self.config.cache_size,
|
|
610
|
+
"cache_enabled": self.config.enable_caching,
|
|
611
|
+
"cache_hit_ratio": 0.0, # Would need to track hits to implement this
|
|
612
|
+
}
|
|
613
|
+
|
|
83
614
|
def _sanitize_value(self, value: str) -> str:
|
|
84
615
|
"""Sanitize value to prevent recursive substitution and control characters.
|
|
85
616
|
|
|
@@ -90,9 +621,9 @@ class TemplateProcessor:
|
|
|
90
621
|
Sanitized value.
|
|
91
622
|
"""
|
|
92
623
|
# Remove control characters (keep printable and whitespace)
|
|
93
|
-
value =
|
|
624
|
+
value = "".join(c for c in value if c.isprintable() or c in "\n\r\t")
|
|
94
625
|
# Prevent recursive substitution by removing placeholder patterns
|
|
95
|
-
value = value.replace(
|
|
626
|
+
value = value.replace("{{", "").replace("}}", "")
|
|
96
627
|
return value
|
|
97
628
|
|
|
98
629
|
def _is_text_file(self, file_path: Path) -> bool:
|
|
@@ -105,8 +636,18 @@ class TemplateProcessor:
|
|
|
105
636
|
True if file is text-based.
|
|
106
637
|
"""
|
|
107
638
|
text_extensions = {
|
|
108
|
-
|
|
109
|
-
|
|
639
|
+
".md",
|
|
640
|
+
".json",
|
|
641
|
+
".txt",
|
|
642
|
+
".py",
|
|
643
|
+
".ts",
|
|
644
|
+
".js",
|
|
645
|
+
".yaml",
|
|
646
|
+
".yml",
|
|
647
|
+
".toml",
|
|
648
|
+
".xml",
|
|
649
|
+
".sh",
|
|
650
|
+
".bash",
|
|
110
651
|
}
|
|
111
652
|
return file_path.suffix.lower() in text_extensions
|
|
112
653
|
|
|
@@ -130,7 +671,7 @@ class TemplateProcessor:
|
|
|
130
671
|
import yaml
|
|
131
672
|
|
|
132
673
|
# Pattern to match YAML frontmatter
|
|
133
|
-
frontmatter_pattern = r
|
|
674
|
+
frontmatter_pattern = r"^---\n(.*?)\n---"
|
|
134
675
|
match = re.match(frontmatter_pattern, content, re.DOTALL)
|
|
135
676
|
|
|
136
677
|
if not match:
|
|
@@ -141,18 +682,18 @@ class TemplateProcessor:
|
|
|
141
682
|
yaml_data = yaml.safe_load(yaml_content)
|
|
142
683
|
|
|
143
684
|
# Check if description is a dict (multilingual)
|
|
144
|
-
if isinstance(yaml_data.get(
|
|
685
|
+
if isinstance(yaml_data.get("description"), dict):
|
|
145
686
|
# Select language (fallback to English)
|
|
146
|
-
descriptions = yaml_data[
|
|
147
|
-
selected_desc = descriptions.get(language, descriptions.get(
|
|
687
|
+
descriptions = yaml_data["description"]
|
|
688
|
+
selected_desc = descriptions.get(language, descriptions.get("en", ""))
|
|
148
689
|
|
|
149
690
|
# Replace description with selected language
|
|
150
|
-
yaml_data[
|
|
691
|
+
yaml_data["description"] = selected_desc
|
|
151
692
|
|
|
152
693
|
# Reconstruct frontmatter
|
|
153
694
|
new_yaml = yaml.dump(yaml_data, allow_unicode=True, sort_keys=False)
|
|
154
695
|
# Preserve the rest of the content
|
|
155
|
-
rest_content = content[match.end():]
|
|
696
|
+
rest_content = content[match.end() :]
|
|
156
697
|
return f"---\n{new_yaml}---{rest_content}"
|
|
157
698
|
|
|
158
699
|
except Exception:
|
|
@@ -176,17 +717,17 @@ class TemplateProcessor:
|
|
|
176
717
|
# Text files: read, substitute, write
|
|
177
718
|
if self._is_text_file(src) and self.context:
|
|
178
719
|
try:
|
|
179
|
-
content = src.read_text(encoding=
|
|
720
|
+
content = src.read_text(encoding="utf-8")
|
|
180
721
|
content, file_warnings = self._substitute_variables(content)
|
|
181
722
|
|
|
182
723
|
# Apply description localization for command/output-style files
|
|
183
|
-
if src.suffix ==
|
|
184
|
-
|
|
724
|
+
if src.suffix == ".md" and (
|
|
725
|
+
"commands/alfred" in str(src) or "output-styles/alfred" in str(src)
|
|
185
726
|
):
|
|
186
|
-
lang = self.context.get(
|
|
727
|
+
lang = self.context.get("CONVERSATION_LANGUAGE", "en")
|
|
187
728
|
content = self._localize_yaml_description(content, lang)
|
|
188
729
|
|
|
189
|
-
dst.write_text(content, encoding=
|
|
730
|
+
dst.write_text(content, encoding="utf-8")
|
|
190
731
|
warnings.extend(file_warnings)
|
|
191
732
|
except UnicodeDecodeError:
|
|
192
733
|
# Binary file fallback
|
|
@@ -290,9 +831,6 @@ class TemplateProcessor:
|
|
|
290
831
|
def _copy_claude(self, silent: bool = False) -> None:
|
|
291
832
|
""".claude/ directory copy with variable substitution (selective with alfred folder overwrite).
|
|
292
833
|
|
|
293
|
-
@CODE:INIT-004:ALFRED-001 | Copy all 4 Alfred command files from templates
|
|
294
|
-
@REQ:COMMAND-GENERATION-001 | SPEC-INIT-004: Automatic generation of Alfred command files
|
|
295
|
-
@SPEC:TEMPLATE-PROCESSING-001 | Template processor integration for Alfred command files
|
|
296
834
|
|
|
297
835
|
Strategy:
|
|
298
836
|
- Alfred folders (commands/agents/hooks/output-styles/alfred) → copy wholesale (delete & overwrite)
|
|
@@ -311,8 +849,6 @@ class TemplateProcessor:
|
|
|
311
849
|
# Create .claude directory if not exists
|
|
312
850
|
dst.mkdir(parents=True, exist_ok=True)
|
|
313
851
|
|
|
314
|
-
# @CODE:INIT-004:ALFRED-002 | Alfred command files must always be overwritten
|
|
315
|
-
# @CODE:INIT-004:ALFRED-COPY | Copy all 4 Alfred command files from templates
|
|
316
852
|
# Alfred folders to copy wholesale (overwrite)
|
|
317
853
|
alfred_folders = [
|
|
318
854
|
"hooks/alfred",
|
|
@@ -344,15 +880,28 @@ class TemplateProcessor:
|
|
|
344
880
|
dst_item = dst / rel_path
|
|
345
881
|
|
|
346
882
|
# Skip Alfred parent folders (already handled above)
|
|
347
|
-
if item.is_dir() and item.name in [
|
|
883
|
+
if item.is_dir() and item.name in [
|
|
884
|
+
"hooks",
|
|
885
|
+
"commands",
|
|
886
|
+
"output-styles",
|
|
887
|
+
"agents",
|
|
888
|
+
]:
|
|
348
889
|
continue
|
|
349
890
|
|
|
350
891
|
if item.is_file():
|
|
351
892
|
# Smart merge for settings.json
|
|
352
893
|
if item.name == "settings.json":
|
|
353
894
|
self._merge_settings_json(item, dst_item)
|
|
895
|
+
# Apply variable substitution to merged settings.json (for cross-platform Hook paths)
|
|
896
|
+
if self.context:
|
|
897
|
+
content = dst_item.read_text(encoding="utf-8")
|
|
898
|
+
content, file_warnings = self._substitute_variables(content)
|
|
899
|
+
dst_item.write_text(content, encoding="utf-8")
|
|
900
|
+
all_warnings.extend(file_warnings)
|
|
354
901
|
if not silent:
|
|
355
|
-
console.print(
|
|
902
|
+
console.print(
|
|
903
|
+
" 🔄 settings.json merged (Hook paths configured for your OS)"
|
|
904
|
+
)
|
|
356
905
|
else:
|
|
357
906
|
# FORCE OVERWRITE: Always copy other files (no skip)
|
|
358
907
|
warnings = self._copy_file_with_substitution(item, dst_item)
|
|
@@ -380,10 +929,11 @@ class TemplateProcessor:
|
|
|
380
929
|
console.print("⚠️ .moai/ template not found")
|
|
381
930
|
return
|
|
382
931
|
|
|
383
|
-
# Paths excluded from template copying (specs/, reports/)
|
|
932
|
+
# Paths excluded from template copying (specs/, reports/, .moai/config/config.json)
|
|
384
933
|
template_protected_paths = [
|
|
385
934
|
"specs",
|
|
386
935
|
"reports",
|
|
936
|
+
".moai/config/config.json",
|
|
387
937
|
]
|
|
388
938
|
|
|
389
939
|
all_warnings = []
|
|
@@ -417,7 +967,7 @@ class TemplateProcessor:
|
|
|
417
967
|
console.print(" ✅ .moai/ copy complete (variables substituted)")
|
|
418
968
|
|
|
419
969
|
def _copy_github(self, silent: bool = False) -> None:
|
|
420
|
-
""".github/ directory copy with
|
|
970
|
+
""".github/ directory copy with smart merge (preserves user workflows)."""
|
|
421
971
|
src = self.template_root / ".github"
|
|
422
972
|
dst = self.target_path / ".github"
|
|
423
973
|
|
|
@@ -426,13 +976,17 @@ class TemplateProcessor:
|
|
|
426
976
|
console.print("⚠️ .github/ template not found")
|
|
427
977
|
return
|
|
428
978
|
|
|
979
|
+
# Smart merge: preserve existing user workflows
|
|
429
980
|
if dst.exists():
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
981
|
+
self._merge_github_workflows(src, dst)
|
|
982
|
+
else:
|
|
983
|
+
# First time: just copy
|
|
984
|
+
self._copy_dir_with_substitution(src, dst)
|
|
433
985
|
|
|
434
986
|
if not silent:
|
|
435
|
-
console.print(
|
|
987
|
+
console.print(
|
|
988
|
+
" 🔄 .github/ merged (user workflows preserved, variables substituted)"
|
|
989
|
+
)
|
|
436
990
|
|
|
437
991
|
def _copy_claude_md(self, silent: bool = False) -> None:
|
|
438
992
|
"""Copy CLAUDE.md with smart merge (preserves \"## Project Information\" section)."""
|
|
@@ -447,8 +1001,19 @@ class TemplateProcessor:
|
|
|
447
1001
|
# Smart merge: preserve existing "## Project Information" section
|
|
448
1002
|
if dst.exists():
|
|
449
1003
|
self._merge_claude_md(src, dst)
|
|
1004
|
+
# Substitute variables in the merged content
|
|
1005
|
+
if self.context:
|
|
1006
|
+
content = dst.read_text(encoding="utf-8")
|
|
1007
|
+
content, warnings = self._substitute_variables(content)
|
|
1008
|
+
dst.write_text(content, encoding="utf-8")
|
|
1009
|
+
if warnings and not silent:
|
|
1010
|
+
console.print("[yellow]⚠️ Template warnings:[/yellow]")
|
|
1011
|
+
for warning in set(warnings):
|
|
1012
|
+
console.print(f" {warning}")
|
|
450
1013
|
if not silent:
|
|
451
|
-
console.print(
|
|
1014
|
+
console.print(
|
|
1015
|
+
" 🔄 CLAUDE.md merged (project information preserved, variables substituted)"
|
|
1016
|
+
)
|
|
452
1017
|
else:
|
|
453
1018
|
# First time: just copy
|
|
454
1019
|
self._copy_file_with_substitution(src, dst)
|
|
@@ -464,6 +1029,15 @@ class TemplateProcessor:
|
|
|
464
1029
|
"""
|
|
465
1030
|
self.merger.merge_claude_md(src, dst)
|
|
466
1031
|
|
|
1032
|
+
def _merge_github_workflows(self, src: Path, dst: Path) -> None:
|
|
1033
|
+
"""Delegate the smart merge for .github/workflows/.
|
|
1034
|
+
|
|
1035
|
+
Args:
|
|
1036
|
+
src: Template .github directory.
|
|
1037
|
+
dst: Project .github directory.
|
|
1038
|
+
"""
|
|
1039
|
+
self.merger.merge_github_workflows(src, dst)
|
|
1040
|
+
|
|
467
1041
|
def _merge_settings_json(self, src: Path, dst: Path) -> None:
|
|
468
1042
|
"""Delegate the smart merge for settings.json.
|
|
469
1043
|
|