moai-adk 0.25.4__py3-none-any.whl โ†’ 0.41.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of moai-adk might be problematic. Click here for more details.

Files changed (672) hide show
  1. moai_adk/__init__.py +2 -5
  2. moai_adk/__main__.py +114 -82
  3. moai_adk/cli/__init__.py +6 -1
  4. moai_adk/cli/commands/__init__.py +1 -3
  5. moai_adk/cli/commands/analyze.py +5 -16
  6. moai_adk/cli/commands/doctor.py +6 -18
  7. moai_adk/cli/commands/init.py +60 -126
  8. moai_adk/cli/commands/language.py +14 -35
  9. moai_adk/cli/commands/status.py +9 -15
  10. moai_adk/cli/commands/update.py +1560 -190
  11. moai_adk/cli/prompts/init_prompts.py +112 -56
  12. moai_adk/cli/spec_status.py +263 -0
  13. moai_adk/cli/ui/__init__.py +44 -0
  14. moai_adk/cli/ui/progress.py +422 -0
  15. moai_adk/cli/ui/prompts.py +389 -0
  16. moai_adk/cli/ui/theme.py +129 -0
  17. moai_adk/cli/worktree/__init__.py +27 -0
  18. moai_adk/cli/worktree/__main__.py +31 -0
  19. moai_adk/cli/worktree/cli.py +683 -0
  20. moai_adk/cli/worktree/exceptions.py +89 -0
  21. moai_adk/cli/worktree/manager.py +493 -0
  22. moai_adk/cli/worktree/models.py +65 -0
  23. moai_adk/cli/worktree/registry.py +422 -0
  24. moai_adk/core/PHASE2_OPTIMIZATIONS.md +467 -0
  25. moai_adk/core/analysis/session_analyzer.py +17 -56
  26. moai_adk/core/claude_integration.py +26 -54
  27. moai_adk/core/command_helpers.py +10 -10
  28. moai_adk/core/comprehensive_monitoring_system.py +1183 -0
  29. moai_adk/core/config/migration.py +19 -9
  30. moai_adk/core/config/unified.py +610 -0
  31. moai_adk/core/context_manager.py +6 -12
  32. moai_adk/core/enterprise_features.py +1404 -0
  33. moai_adk/core/error_recovery_system.py +747 -116
  34. moai_adk/core/event_driven_hook_system.py +1371 -0
  35. moai_adk/core/git/__init__.py +8 -0
  36. moai_adk/core/git/branch_manager.py +3 -11
  37. moai_adk/core/git/checkpoint.py +1 -3
  38. moai_adk/core/git/conflict_detector.py +422 -0
  39. moai_adk/core/git/event_detector.py +16 -5
  40. moai_adk/core/git/manager.py +91 -1
  41. moai_adk/core/input_validation_middleware.py +1006 -0
  42. moai_adk/core/integration/engine.py +6 -18
  43. moai_adk/core/integration/integration_tester.py +10 -9
  44. moai_adk/core/integration/utils.py +1 -1
  45. moai_adk/core/issue_creator.py +10 -28
  46. moai_adk/core/jit_context_loader.py +956 -0
  47. moai_adk/core/jit_enhanced_hook_manager.py +1987 -0
  48. moai_adk/core/language_config_resolver.py +578 -0
  49. moai_adk/core/language_validator.py +28 -41
  50. moai_adk/core/mcp/setup.py +15 -12
  51. moai_adk/core/merge/__init__.py +9 -0
  52. moai_adk/core/merge/analyzer.py +666 -0
  53. moai_adk/core/migration/alfred_to_moai_migrator.py +389 -0
  54. moai_adk/core/migration/backup_manager.py +131 -12
  55. moai_adk/core/migration/custom_element_scanner.py +358 -0
  56. moai_adk/core/migration/file_migrator.py +181 -18
  57. moai_adk/core/migration/interactive_checkbox_ui.py +499 -0
  58. moai_adk/core/migration/selective_restorer.py +470 -0
  59. moai_adk/core/migration/template_utils.py +74 -0
  60. moai_adk/core/migration/user_selection_ui.py +338 -0
  61. moai_adk/core/migration/version_detector.py +127 -27
  62. moai_adk/core/migration/version_migrator.py +47 -12
  63. moai_adk/core/performance/cache_system.py +8 -10
  64. moai_adk/core/phase_optimized_hook_scheduler.py +879 -0
  65. moai_adk/core/project/backup_utils.py +9 -1
  66. moai_adk/core/project/checker.py +2 -4
  67. moai_adk/core/project/detector.py +1 -3
  68. moai_adk/core/project/initializer.py +142 -93
  69. moai_adk/core/project/phase_executor.py +130 -111
  70. moai_adk/core/project/validator.py +6 -12
  71. moai_adk/core/quality/trust_checker.py +39 -37
  72. moai_adk/core/realtime_monitoring_dashboard.py +1724 -0
  73. moai_adk/core/robust_json_parser.py +611 -0
  74. moai_adk/core/rollback_manager.py +116 -164
  75. moai_adk/core/session_manager.py +10 -26
  76. moai_adk/core/skill_loading_system.py +579 -0
  77. moai_adk/core/spec_status_manager.py +64 -74
  78. moai_adk/core/template/backup.py +48 -22
  79. moai_adk/core/template/config.py +142 -45
  80. moai_adk/core/template/merger.py +45 -27
  81. moai_adk/core/template/processor.py +391 -152
  82. moai_adk/core/template_engine.py +83 -41
  83. moai_adk/core/template_variable_synchronizer.py +431 -0
  84. moai_adk/core/unified_permission_manager.py +745 -0
  85. moai_adk/core/user_behavior_analytics.py +851 -0
  86. moai_adk/core/version_sync.py +477 -0
  87. moai_adk/foundation/__init__.py +56 -0
  88. moai_adk/foundation/backend.py +1027 -0
  89. moai_adk/foundation/database.py +1115 -0
  90. moai_adk/foundation/devops.py +1585 -0
  91. moai_adk/foundation/ears.py +431 -0
  92. moai_adk/foundation/frontend.py +870 -0
  93. moai_adk/foundation/git/commit_templates.py +4 -12
  94. moai_adk/foundation/git.py +376 -0
  95. moai_adk/foundation/langs.py +484 -0
  96. moai_adk/foundation/ml_ops.py +1162 -0
  97. moai_adk/foundation/testing.py +1524 -0
  98. moai_adk/foundation/trust/trust_principles.py +23 -72
  99. moai_adk/foundation/trust/validation_checklist.py +57 -162
  100. moai_adk/project/__init__.py +0 -0
  101. moai_adk/project/configuration.py +1084 -0
  102. moai_adk/project/documentation.py +566 -0
  103. moai_adk/project/schema.py +447 -0
  104. moai_adk/statusline/alfred_detector.py +1 -3
  105. moai_adk/statusline/config.py +18 -6
  106. moai_adk/statusline/enhanced_output_style_detector.py +23 -15
  107. moai_adk/statusline/main.py +109 -15
  108. moai_adk/statusline/renderer.py +85 -69
  109. moai_adk/statusline/update_checker.py +3 -9
  110. moai_adk/statusline/version_reader.py +140 -46
  111. moai_adk/templates/.claude/agents/moai/ai-nano-banana.md +716 -0
  112. moai_adk/templates/.claude/agents/moai/builder-agent.md +480 -0
  113. moai_adk/templates/.claude/agents/moai/builder-command.md +1194 -0
  114. moai_adk/templates/.claude/agents/moai/builder-plugin.md +753 -0
  115. moai_adk/templates/.claude/agents/moai/builder-skill.md +672 -0
  116. moai_adk/templates/.claude/agents/moai/expert-backend.md +903 -0
  117. moai_adk/templates/.claude/agents/moai/expert-database.md +782 -0
  118. moai_adk/templates/.claude/agents/moai/expert-debug.md +407 -0
  119. moai_adk/templates/.claude/agents/moai/expert-devops.md +722 -0
  120. moai_adk/templates/.claude/agents/moai/expert-frontend.md +727 -0
  121. moai_adk/templates/.claude/agents/moai/expert-performance.md +661 -0
  122. moai_adk/templates/.claude/agents/moai/expert-refactoring.md +218 -0
  123. moai_adk/templates/.claude/agents/moai/expert-security.md +525 -0
  124. moai_adk/templates/.claude/agents/moai/expert-testing.md +737 -0
  125. moai_adk/templates/.claude/agents/moai/expert-uiux.md +1047 -0
  126. moai_adk/templates/.claude/agents/moai/manager-claude-code.md +438 -0
  127. moai_adk/templates/.claude/agents/moai/manager-docs.md +578 -0
  128. moai_adk/templates/.claude/agents/moai/manager-git.md +1092 -0
  129. moai_adk/templates/.claude/agents/moai/manager-project.md +897 -0
  130. moai_adk/templates/.claude/agents/moai/manager-quality.md +640 -0
  131. moai_adk/templates/.claude/agents/moai/manager-spec.md +815 -0
  132. moai_adk/templates/.claude/agents/moai/manager-strategy.md +786 -0
  133. moai_adk/templates/.claude/agents/moai/manager-tdd.md +797 -0
  134. moai_adk/templates/.claude/agents/moai/mcp-context7.md +464 -0
  135. moai_adk/templates/.claude/agents/moai/mcp-figma.md +1588 -0
  136. moai_adk/templates/.claude/agents/moai/mcp-notion.md +795 -0
  137. moai_adk/templates/.claude/agents/moai/mcp-playwright.md +475 -0
  138. moai_adk/templates/.claude/agents/moai/mcp-sequential-thinking.md +1038 -0
  139. moai_adk/templates/.claude/commands/moai/0-project.md +1339 -0
  140. moai_adk/templates/.claude/commands/moai/1-plan.md +1367 -0
  141. moai_adk/templates/.claude/commands/moai/2-run.md +825 -0
  142. moai_adk/templates/.claude/commands/moai/3-sync.md +1358 -0
  143. moai_adk/templates/.claude/commands/moai/9-feedback.md +320 -0
  144. moai_adk/templates/.claude/hooks/__init__.py +8 -0
  145. moai_adk/templates/.claude/hooks/moai/__init__.py +8 -0
  146. moai_adk/templates/.claude/hooks/moai/lib/README.md +143 -0
  147. moai_adk/templates/.claude/hooks/moai/lib/__init__.py +104 -0
  148. moai_adk/templates/.claude/hooks/moai/lib/checkpoint.py +247 -0
  149. moai_adk/templates/.claude/hooks/moai/lib/common.py +161 -0
  150. moai_adk/templates/.claude/hooks/moai/lib/config_manager.py +444 -0
  151. moai_adk/templates/.claude/hooks/moai/lib/config_validator.py +639 -0
  152. moai_adk/templates/.claude/hooks/moai/lib/example_config.json +104 -0
  153. moai_adk/templates/.claude/hooks/moai/lib/exceptions.py +171 -0
  154. moai_adk/templates/.claude/hooks/moai/lib/git_operations_manager.py +590 -0
  155. moai_adk/templates/.claude/hooks/moai/lib/language_validator.py +407 -0
  156. moai_adk/templates/.claude/hooks/moai/lib/models.py +104 -0
  157. moai_adk/templates/.claude/hooks/moai/lib/path_utils.py +219 -0
  158. moai_adk/templates/.claude/hooks/moai/lib/project.py +777 -0
  159. moai_adk/templates/.claude/hooks/moai/lib/test_hooks_improvements.py +443 -0
  160. moai_adk/templates/.claude/hooks/moai/lib/timeout.py +160 -0
  161. moai_adk/templates/.claude/hooks/moai/lib/tool_registry.py +804 -0
  162. moai_adk/templates/.claude/hooks/moai/lib/unified_timeout_manager.py +542 -0
  163. moai_adk/templates/.claude/hooks/moai/post_tool__ast_grep_scan.py +256 -0
  164. moai_adk/templates/.claude/hooks/moai/post_tool__code_formatter.py +253 -0
  165. moai_adk/templates/.claude/hooks/moai/post_tool__linter.py +307 -0
  166. moai_adk/templates/.claude/hooks/moai/pre_tool__security_guard.py +231 -0
  167. moai_adk/templates/.claude/hooks/moai/session_end__auto_cleanup.py +866 -0
  168. moai_adk/templates/.claude/hooks/moai/session_start__show_project_info.py +1125 -0
  169. moai_adk/templates/.claude/output-styles/moai/r2d2.md +643 -0
  170. moai_adk/templates/.claude/output-styles/moai/yoda.md +359 -0
  171. moai_adk/templates/.claude/settings.json +209 -0
  172. moai_adk/templates/.claude/skills/moai-ai-nano-banana/SKILL.md +302 -0
  173. moai_adk/templates/.claude/skills/moai-ai-nano-banana/examples.md +431 -0
  174. moai_adk/templates/.claude/skills/moai-ai-nano-banana/reference.md +139 -0
  175. moai_adk/templates/.claude/skills/moai-ai-nano-banana/scripts/batch_generate.py +560 -0
  176. moai_adk/templates/.claude/skills/moai-ai-nano-banana/scripts/generate_image.py +362 -0
  177. moai_adk/templates/.claude/skills/moai-docs-generation/SKILL.md +302 -0
  178. moai_adk/templates/.claude/skills/moai-docs-generation/examples.md +252 -0
  179. moai_adk/templates/.claude/skills/moai-docs-generation/modules/README.md +56 -0
  180. moai_adk/templates/.claude/skills/moai-docs-generation/modules/api-documentation.md +120 -0
  181. moai_adk/templates/.claude/skills/moai-docs-generation/modules/code-documentation.md +152 -0
  182. moai_adk/templates/.claude/skills/moai-docs-generation/modules/multi-format-output.md +185 -0
  183. moai_adk/templates/.claude/skills/moai-docs-generation/modules/user-guides.md +207 -0
  184. moai_adk/templates/.claude/skills/moai-docs-generation/reference.md +234 -0
  185. moai_adk/templates/.claude/skills/moai-domain-backend/SKILL.md +324 -0
  186. moai_adk/templates/.claude/skills/moai-domain-backend/examples.md +718 -0
  187. moai_adk/templates/.claude/skills/moai-domain-backend/reference.md +464 -0
  188. moai_adk/templates/.claude/skills/moai-domain-database/SKILL.md +326 -0
  189. moai_adk/templates/.claude/skills/moai-domain-database/examples.md +830 -0
  190. moai_adk/templates/.claude/skills/moai-domain-database/modules/README.md +53 -0
  191. moai_adk/templates/.claude/skills/moai-domain-database/modules/mongodb.md +231 -0
  192. moai_adk/templates/.claude/skills/moai-domain-database/modules/postgresql.md +169 -0
  193. moai_adk/templates/.claude/skills/moai-domain-database/modules/redis.md +262 -0
  194. moai_adk/templates/.claude/skills/moai-domain-database/reference.md +545 -0
  195. moai_adk/templates/.claude/skills/moai-domain-frontend/SKILL.md +194 -0
  196. moai_adk/templates/.claude/skills/moai-domain-frontend/examples.md +968 -0
  197. moai_adk/templates/.claude/skills/moai-domain-frontend/modules/component-architecture.md +723 -0
  198. moai_adk/templates/.claude/skills/moai-domain-frontend/modules/nextjs16-patterns.md +713 -0
  199. moai_adk/templates/.claude/skills/moai-domain-frontend/modules/performance-optimization.md +694 -0
  200. moai_adk/templates/.claude/skills/moai-domain-frontend/modules/react19-patterns.md +591 -0
  201. moai_adk/templates/.claude/skills/moai-domain-frontend/modules/state-management.md +680 -0
  202. moai_adk/templates/.claude/skills/moai-domain-frontend/modules/vue35-patterns.md +802 -0
  203. moai_adk/templates/.claude/skills/moai-domain-frontend/reference.md +664 -0
  204. moai_adk/templates/.claude/skills/moai-domain-uiux/SKILL.md +454 -0
  205. moai_adk/templates/.claude/skills/moai-domain-uiux/examples.md +560 -0
  206. moai_adk/templates/.claude/skills/moai-domain-uiux/modules/accessibility-wcag.md +260 -0
  207. moai_adk/templates/.claude/skills/moai-domain-uiux/modules/component-architecture.md +228 -0
  208. moai_adk/templates/.claude/skills/moai-domain-uiux/modules/icon-libraries.md +401 -0
  209. moai_adk/templates/.claude/skills/moai-domain-uiux/modules/theming-system.md +373 -0
  210. moai_adk/templates/.claude/skills/moai-domain-uiux/reference.md +243 -0
  211. moai_adk/templates/.claude/skills/moai-formats-data/SKILL.md +280 -0
  212. moai_adk/templates/.claude/skills/moai-formats-data/examples.md +804 -0
  213. moai_adk/templates/.claude/skills/moai-formats-data/modules/README.md +327 -0
  214. moai_adk/templates/.claude/skills/moai-formats-data/modules/SKILL-MODULARIZATION-TEMPLATE.md +278 -0
  215. moai_adk/templates/.claude/skills/moai-formats-data/modules/caching-performance.md +459 -0
  216. moai_adk/templates/.claude/skills/moai-formats-data/modules/data-validation.md +485 -0
  217. moai_adk/templates/.claude/skills/moai-formats-data/modules/json-optimization.md +374 -0
  218. moai_adk/templates/.claude/skills/moai-formats-data/modules/toon-encoding.md +308 -0
  219. moai_adk/templates/.claude/skills/moai-formats-data/reference.md +585 -0
  220. moai_adk/templates/.claude/skills/moai-foundation-claude/SKILL.md +243 -0
  221. moai_adk/templates/.claude/skills/moai-foundation-claude/examples.md +732 -0
  222. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/advanced-agent-patterns.md +370 -0
  223. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/best-practices-checklist.md +616 -0
  224. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-cli-reference-official.md +420 -0
  225. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-custom-slash-commands-official.md +729 -0
  226. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-devcontainers-official.md +381 -0
  227. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-discover-plugins-official.md +379 -0
  228. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-headless-official.md +378 -0
  229. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-hooks-official.md +670 -0
  230. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-iam-official.md +635 -0
  231. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-memory-official.md +543 -0
  232. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-plugin-marketplaces-official.md +308 -0
  233. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-plugins-official.md +432 -0
  234. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-sandboxing-official.md +282 -0
  235. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-settings-official.md +663 -0
  236. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-skills-official.md +467 -0
  237. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-statusline-official.md +293 -0
  238. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-sub-agents-official.md +420 -0
  239. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/complete-configuration-guide.md +175 -0
  240. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/skill-examples.md +1674 -0
  241. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/skill-formatting-guide.md +729 -0
  242. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/sub-agents/sub-agent-examples.md +1513 -0
  243. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/sub-agents/sub-agent-formatting-guide.md +1086 -0
  244. moai_adk/templates/.claude/skills/moai-foundation-claude/reference/sub-agents/sub-agent-integration-patterns.md +1100 -0
  245. moai_adk/templates/.claude/skills/moai-foundation-claude/reference.md +209 -0
  246. moai_adk/templates/.claude/skills/moai-foundation-context/SKILL.md +449 -0
  247. moai_adk/templates/.claude/skills/moai-foundation-context/examples.md +1048 -0
  248. moai_adk/templates/.claude/skills/moai-foundation-context/reference.md +246 -0
  249. moai_adk/templates/.claude/skills/moai-foundation-core/SKILL.md +414 -0
  250. moai_adk/templates/.claude/skills/moai-foundation-core/examples.md +358 -0
  251. moai_adk/templates/.claude/skills/moai-foundation-core/modules/README.md +296 -0
  252. moai_adk/templates/.claude/skills/moai-foundation-core/modules/agents-reference.md +359 -0
  253. moai_adk/templates/.claude/skills/moai-foundation-core/modules/commands-reference.md +432 -0
  254. moai_adk/templates/.claude/skills/moai-foundation-core/modules/delegation-advanced.md +279 -0
  255. moai_adk/templates/.claude/skills/moai-foundation-core/modules/delegation-implementation.md +267 -0
  256. moai_adk/templates/.claude/skills/moai-foundation-core/modules/delegation-patterns.md +228 -0
  257. moai_adk/templates/.claude/skills/moai-foundation-core/modules/execution-rules.md +687 -0
  258. moai_adk/templates/.claude/skills/moai-foundation-core/modules/modular-system.md +665 -0
  259. moai_adk/templates/.claude/skills/moai-foundation-core/modules/patterns.md +22 -0
  260. moai_adk/templates/.claude/skills/moai-foundation-core/modules/progressive-disclosure.md +649 -0
  261. moai_adk/templates/.claude/skills/moai-foundation-core/modules/spec-ears-format.md +200 -0
  262. moai_adk/templates/.claude/skills/moai-foundation-core/modules/spec-first-tdd.md +171 -0
  263. moai_adk/templates/.claude/skills/moai-foundation-core/modules/spec-tdd-implementation.md +275 -0
  264. moai_adk/templates/.claude/skills/moai-foundation-core/modules/token-optimization.md +708 -0
  265. moai_adk/templates/.claude/skills/moai-foundation-core/modules/trust-5-framework.md +239 -0
  266. moai_adk/templates/.claude/skills/moai-foundation-core/modules/trust-5-implementation.md +244 -0
  267. moai_adk/templates/.claude/skills/moai-foundation-core/modules/trust-5-validation.md +219 -0
  268. moai_adk/templates/.claude/skills/moai-foundation-core/reference.md +478 -0
  269. moai_adk/templates/.claude/skills/moai-foundation-philosopher/SKILL.md +311 -0
  270. moai_adk/templates/.claude/skills/moai-foundation-philosopher/examples.md +228 -0
  271. moai_adk/templates/.claude/skills/moai-foundation-philosopher/modules/assumption-matrix.md +80 -0
  272. moai_adk/templates/.claude/skills/moai-foundation-philosopher/modules/cognitive-bias.md +199 -0
  273. moai_adk/templates/.claude/skills/moai-foundation-philosopher/modules/first-principles.md +140 -0
  274. moai_adk/templates/.claude/skills/moai-foundation-philosopher/modules/trade-off-analysis.md +154 -0
  275. moai_adk/templates/.claude/skills/moai-foundation-philosopher/reference.md +157 -0
  276. moai_adk/templates/.claude/skills/moai-foundation-quality/SKILL.md +363 -0
  277. moai_adk/templates/.claude/skills/moai-foundation-quality/examples.md +1232 -0
  278. moai_adk/templates/.claude/skills/moai-foundation-quality/modules/best-practices.md +261 -0
  279. moai_adk/templates/.claude/skills/moai-foundation-quality/modules/integration-patterns.md +194 -0
  280. moai_adk/templates/.claude/skills/moai-foundation-quality/modules/proactive-analysis.md +229 -0
  281. moai_adk/templates/.claude/skills/moai-foundation-quality/modules/trust5-validation.md +169 -0
  282. moai_adk/templates/.claude/skills/moai-foundation-quality/reference.md +1266 -0
  283. moai_adk/templates/.claude/skills/moai-foundation-quality/scripts/quality-gate.sh +668 -0
  284. moai_adk/templates/.claude/skills/moai-foundation-quality/templates/github-actions-quality.yml +481 -0
  285. moai_adk/templates/.claude/skills/moai-foundation-quality/templates/quality-config.yaml +519 -0
  286. moai_adk/templates/.claude/skills/moai-lang-cpp/SKILL.md +430 -0
  287. moai_adk/templates/.claude/skills/moai-lang-cpp/examples.md +17 -0
  288. moai_adk/templates/.claude/skills/moai-lang-cpp/modules/advanced-patterns.md +401 -0
  289. moai_adk/templates/.claude/skills/moai-lang-cpp/reference.md +17 -0
  290. moai_adk/templates/.claude/skills/moai-lang-csharp/SKILL.md +193 -0
  291. moai_adk/templates/.claude/skills/moai-lang-csharp/examples.md +585 -0
  292. moai_adk/templates/.claude/skills/moai-lang-csharp/modules/aspnet-core.md +627 -0
  293. moai_adk/templates/.claude/skills/moai-lang-csharp/modules/blazor-components.md +767 -0
  294. moai_adk/templates/.claude/skills/moai-lang-csharp/modules/cqrs-validation.md +626 -0
  295. moai_adk/templates/.claude/skills/moai-lang-csharp/modules/csharp12-features.md +580 -0
  296. moai_adk/templates/.claude/skills/moai-lang-csharp/modules/efcore-patterns.md +622 -0
  297. moai_adk/templates/.claude/skills/moai-lang-csharp/reference.md +403 -0
  298. moai_adk/templates/.claude/skills/moai-lang-elixir/SKILL.md +394 -0
  299. moai_adk/templates/.claude/skills/moai-lang-elixir/examples.md +17 -0
  300. moai_adk/templates/.claude/skills/moai-lang-elixir/modules/advanced-patterns.md +531 -0
  301. moai_adk/templates/.claude/skills/moai-lang-elixir/reference.md +17 -0
  302. moai_adk/templates/.claude/skills/moai-lang-flutter/SKILL.md +472 -0
  303. moai_adk/templates/.claude/skills/moai-lang-flutter/examples.md +1090 -0
  304. moai_adk/templates/.claude/skills/moai-lang-flutter/reference.md +686 -0
  305. moai_adk/templates/.claude/skills/moai-lang-go/SKILL.md +377 -0
  306. moai_adk/templates/.claude/skills/moai-lang-go/examples.md +919 -0
  307. moai_adk/templates/.claude/skills/moai-lang-go/reference.md +737 -0
  308. moai_adk/templates/.claude/skills/moai-lang-java/SKILL.md +386 -0
  309. moai_adk/templates/.claude/skills/moai-lang-java/examples.md +864 -0
  310. moai_adk/templates/.claude/skills/moai-lang-java/reference.md +291 -0
  311. moai_adk/templates/.claude/skills/moai-lang-javascript/SKILL.md +418 -0
  312. moai_adk/templates/.claude/skills/moai-lang-javascript/examples.md +973 -0
  313. moai_adk/templates/.claude/skills/moai-lang-javascript/reference.md +1543 -0
  314. moai_adk/templates/.claude/skills/moai-lang-kotlin/SKILL.md +383 -0
  315. moai_adk/templates/.claude/skills/moai-lang-kotlin/examples.md +1006 -0
  316. moai_adk/templates/.claude/skills/moai-lang-kotlin/reference.md +562 -0
  317. moai_adk/templates/.claude/skills/moai-lang-php/SKILL.md +504 -0
  318. moai_adk/templates/.claude/skills/moai-lang-php/examples.md +17 -0
  319. moai_adk/templates/.claude/skills/moai-lang-php/modules/advanced-patterns.md +538 -0
  320. moai_adk/templates/.claude/skills/moai-lang-php/reference.md +17 -0
  321. moai_adk/templates/.claude/skills/moai-lang-python/SKILL.md +489 -0
  322. moai_adk/templates/.claude/skills/moai-lang-python/examples.md +977 -0
  323. moai_adk/templates/.claude/skills/moai-lang-python/reference.md +804 -0
  324. moai_adk/templates/.claude/skills/moai-lang-r/SKILL.md +389 -0
  325. moai_adk/templates/.claude/skills/moai-lang-r/examples.md +17 -0
  326. moai_adk/templates/.claude/skills/moai-lang-r/modules/advanced-patterns.md +489 -0
  327. moai_adk/templates/.claude/skills/moai-lang-r/reference.md +17 -0
  328. moai_adk/templates/.claude/skills/moai-lang-ruby/SKILL.md +432 -0
  329. moai_adk/templates/.claude/skills/moai-lang-ruby/examples.md +17 -0
  330. moai_adk/templates/.claude/skills/moai-lang-ruby/modules/advanced-patterns.md +309 -0
  331. moai_adk/templates/.claude/skills/moai-lang-ruby/modules/testing-patterns.md +306 -0
  332. moai_adk/templates/.claude/skills/moai-lang-ruby/reference.md +17 -0
  333. moai_adk/templates/.claude/skills/moai-lang-rust/SKILL.md +377 -0
  334. moai_adk/templates/.claude/skills/moai-lang-rust/examples.md +659 -0
  335. moai_adk/templates/.claude/skills/moai-lang-rust/reference.md +504 -0
  336. moai_adk/templates/.claude/skills/moai-lang-scala/SKILL.md +211 -0
  337. moai_adk/templates/.claude/skills/moai-lang-scala/examples.md +633 -0
  338. moai_adk/templates/.claude/skills/moai-lang-scala/modules/akka-actors.md +479 -0
  339. moai_adk/templates/.claude/skills/moai-lang-scala/modules/cats-effect.md +489 -0
  340. moai_adk/templates/.claude/skills/moai-lang-scala/modules/functional-programming.md +460 -0
  341. moai_adk/templates/.claude/skills/moai-lang-scala/modules/spark-data.md +498 -0
  342. moai_adk/templates/.claude/skills/moai-lang-scala/modules/zio-patterns.md +541 -0
  343. moai_adk/templates/.claude/skills/moai-lang-scala/reference.md +423 -0
  344. moai_adk/templates/.claude/skills/moai-lang-swift/SKILL.md +191 -0
  345. moai_adk/templates/.claude/skills/moai-lang-swift/examples.md +918 -0
  346. moai_adk/templates/.claude/skills/moai-lang-swift/modules/combine-reactive.md +256 -0
  347. moai_adk/templates/.claude/skills/moai-lang-swift/modules/concurrency.md +270 -0
  348. moai_adk/templates/.claude/skills/moai-lang-swift/modules/swift6-features.md +265 -0
  349. moai_adk/templates/.claude/skills/moai-lang-swift/modules/swiftui-patterns.md +314 -0
  350. moai_adk/templates/.claude/skills/moai-lang-swift/reference.md +672 -0
  351. moai_adk/templates/.claude/skills/moai-lang-typescript/SKILL.md +364 -0
  352. moai_adk/templates/.claude/skills/moai-lang-typescript/examples.md +1089 -0
  353. moai_adk/templates/.claude/skills/moai-lang-typescript/reference.md +731 -0
  354. moai_adk/templates/.claude/skills/moai-library-mermaid/SKILL.md +164 -0
  355. moai_adk/templates/.claude/skills/moai-library-mermaid/examples.md +270 -0
  356. moai_adk/templates/.claude/skills/moai-library-mermaid/modules/advanced-patterns.md +465 -0
  357. moai_adk/templates/.claude/skills/moai-library-mermaid/modules/optimization.md +440 -0
  358. moai_adk/templates/.claude/skills/moai-library-mermaid/reference.md +228 -0
  359. moai_adk/templates/.claude/skills/moai-library-nextra/SKILL.md +335 -0
  360. moai_adk/templates/.claude/skills/moai-library-nextra/examples.md +592 -0
  361. moai_adk/templates/.claude/skills/moai-library-nextra/modules/advanced-deployment-patterns.md +182 -0
  362. moai_adk/templates/.claude/skills/moai-library-nextra/modules/advanced-patterns.md +336 -0
  363. moai_adk/templates/.claude/skills/moai-library-nextra/modules/configuration.md +350 -0
  364. moai_adk/templates/.claude/skills/moai-library-nextra/modules/content-architecture-optimization.md +162 -0
  365. moai_adk/templates/.claude/skills/moai-library-nextra/modules/deployment.md +52 -0
  366. moai_adk/templates/.claude/skills/moai-library-nextra/modules/framework-core-configuration.md +186 -0
  367. moai_adk/templates/.claude/skills/moai-library-nextra/modules/i18n-setup.md +55 -0
  368. moai_adk/templates/.claude/skills/moai-library-nextra/modules/mdx-components.md +52 -0
  369. moai_adk/templates/.claude/skills/moai-library-nextra/modules/optimization.md +303 -0
  370. moai_adk/templates/.claude/skills/moai-library-nextra/reference.md +379 -0
  371. moai_adk/templates/.claude/skills/moai-library-shadcn/SKILL.md +373 -0
  372. moai_adk/templates/.claude/skills/moai-library-shadcn/examples.md +575 -0
  373. moai_adk/templates/.claude/skills/moai-library-shadcn/modules/advanced-patterns.md +394 -0
  374. moai_adk/templates/.claude/skills/moai-library-shadcn/modules/optimization.md +278 -0
  375. moai_adk/templates/.claude/skills/moai-library-shadcn/modules/shadcn-components.md +457 -0
  376. moai_adk/templates/.claude/skills/moai-library-shadcn/modules/shadcn-theming.md +373 -0
  377. moai_adk/templates/.claude/skills/moai-library-shadcn/reference.md +74 -0
  378. moai_adk/templates/.claude/skills/moai-platform-auth0/SKILL.md +283 -0
  379. moai_adk/templates/.claude/skills/moai-platform-auth0/examples.md +2446 -0
  380. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/adaptive-mfa.md +233 -0
  381. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/akamai-integration.md +214 -0
  382. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/application-credentials.md +280 -0
  383. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/attack-protection-log-events.md +224 -0
  384. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/attack-protection-overview.md +140 -0
  385. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/bot-detection.md +144 -0
  386. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/breached-password-detection.md +187 -0
  387. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/brute-force-protection.md +189 -0
  388. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/certifications.md +282 -0
  389. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/compliance-overview.md +263 -0
  390. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/continuous-session-protection.md +307 -0
  391. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/customize-mfa.md +177 -0
  392. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/dpop-implementation.md +283 -0
  393. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/fapi-implementation.md +259 -0
  394. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/gdpr-compliance.md +313 -0
  395. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/guardian-configuration.md +269 -0
  396. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/highly-regulated-identity.md +272 -0
  397. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/jwt-fundamentals.md +248 -0
  398. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/mdl-verification.md +210 -0
  399. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/mfa-api-management.md +278 -0
  400. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/mfa-factors.md +226 -0
  401. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/mfa-overview.md +174 -0
  402. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/mtls-sender-constraining.md +316 -0
  403. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/ropg-flow-mfa.md +216 -0
  404. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/security-center.md +325 -0
  405. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/security-guidance.md +277 -0
  406. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/state-parameters.md +177 -0
  407. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/step-up-authentication.md +251 -0
  408. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/suspicious-ip-throttling.md +240 -0
  409. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/tenant-access-control.md +179 -0
  410. moai_adk/templates/.claude/skills/moai-platform-auth0/modules/webauthn-fido.md +235 -0
  411. moai_adk/templates/.claude/skills/moai-platform-auth0/reference.md +224 -0
  412. moai_adk/templates/.claude/skills/moai-platform-clerk/SKILL.md +425 -0
  413. moai_adk/templates/.claude/skills/moai-platform-clerk/modules/advanced-patterns.md +417 -0
  414. moai_adk/templates/.claude/skills/moai-platform-clerk/reference.md +273 -0
  415. moai_adk/templates/.claude/skills/moai-platform-convex/SKILL.md +228 -0
  416. moai_adk/templates/.claude/skills/moai-platform-convex/examples.md +506 -0
  417. moai_adk/templates/.claude/skills/moai-platform-convex/modules/auth-integration.md +421 -0
  418. moai_adk/templates/.claude/skills/moai-platform-convex/modules/file-storage.md +474 -0
  419. moai_adk/templates/.claude/skills/moai-platform-convex/modules/reactive-queries.md +302 -0
  420. moai_adk/templates/.claude/skills/moai-platform-convex/modules/server-functions.md +452 -0
  421. moai_adk/templates/.claude/skills/moai-platform-convex/reference.md +385 -0
  422. moai_adk/templates/.claude/skills/moai-platform-firebase-auth/SKILL.md +249 -0
  423. moai_adk/templates/.claude/skills/moai-platform-firebase-auth/examples.md +514 -0
  424. moai_adk/templates/.claude/skills/moai-platform-firebase-auth/modules/custom-claims.md +374 -0
  425. moai_adk/templates/.claude/skills/moai-platform-firebase-auth/modules/phone-auth.md +372 -0
  426. moai_adk/templates/.claude/skills/moai-platform-firebase-auth/modules/social-auth.md +339 -0
  427. moai_adk/templates/.claude/skills/moai-platform-firebase-auth/reference.md +382 -0
  428. moai_adk/templates/.claude/skills/moai-platform-firestore/SKILL.md +230 -0
  429. moai_adk/templates/.claude/skills/moai-platform-firestore/examples.md +445 -0
  430. moai_adk/templates/.claude/skills/moai-platform-firestore/modules/offline-cache.md +392 -0
  431. moai_adk/templates/.claude/skills/moai-platform-firestore/modules/realtime-listeners.md +441 -0
  432. moai_adk/templates/.claude/skills/moai-platform-firestore/modules/security-rules.md +352 -0
  433. moai_adk/templates/.claude/skills/moai-platform-firestore/modules/transactions.md +452 -0
  434. moai_adk/templates/.claude/skills/moai-platform-firestore/reference.md +322 -0
  435. moai_adk/templates/.claude/skills/moai-platform-neon/SKILL.md +205 -0
  436. moai_adk/templates/.claude/skills/moai-platform-neon/examples.md +470 -0
  437. moai_adk/templates/.claude/skills/moai-platform-neon/modules/auto-scaling.md +349 -0
  438. moai_adk/templates/.claude/skills/moai-platform-neon/modules/branching-workflows.md +354 -0
  439. moai_adk/templates/.claude/skills/moai-platform-neon/modules/connection-pooling.md +412 -0
  440. moai_adk/templates/.claude/skills/moai-platform-neon/modules/pitr-backups.md +458 -0
  441. moai_adk/templates/.claude/skills/moai-platform-neon/reference.md +272 -0
  442. moai_adk/templates/.claude/skills/moai-platform-railway/SKILL.md +223 -0
  443. moai_adk/templates/.claude/skills/moai-platform-railway/examples.md +539 -0
  444. moai_adk/templates/.claude/skills/moai-platform-railway/modules/docker-deployment.md +261 -0
  445. moai_adk/templates/.claude/skills/moai-platform-railway/modules/multi-service.md +291 -0
  446. moai_adk/templates/.claude/skills/moai-platform-railway/modules/networking-domains.md +338 -0
  447. moai_adk/templates/.claude/skills/moai-platform-railway/modules/volumes-storage.md +353 -0
  448. moai_adk/templates/.claude/skills/moai-platform-railway/reference.md +374 -0
  449. moai_adk/templates/.claude/skills/moai-platform-supabase/SKILL.md +206 -0
  450. moai_adk/templates/.claude/skills/moai-platform-supabase/examples.md +502 -0
  451. moai_adk/templates/.claude/skills/moai-platform-supabase/modules/auth-integration.md +384 -0
  452. moai_adk/templates/.claude/skills/moai-platform-supabase/modules/edge-functions.md +371 -0
  453. moai_adk/templates/.claude/skills/moai-platform-supabase/modules/postgresql-pgvector.md +231 -0
  454. moai_adk/templates/.claude/skills/moai-platform-supabase/modules/realtime-presence.md +354 -0
  455. moai_adk/templates/.claude/skills/moai-platform-supabase/modules/row-level-security.md +286 -0
  456. moai_adk/templates/.claude/skills/moai-platform-supabase/modules/storage-cdn.md +319 -0
  457. moai_adk/templates/.claude/skills/moai-platform-supabase/modules/typescript-patterns.md +453 -0
  458. moai_adk/templates/.claude/skills/moai-platform-supabase/reference.md +284 -0
  459. moai_adk/templates/.claude/skills/moai-platform-vercel/SKILL.md +209 -0
  460. moai_adk/templates/.claude/skills/moai-platform-vercel/examples.md +502 -0
  461. moai_adk/templates/.claude/skills/moai-platform-vercel/modules/analytics-speed.md +348 -0
  462. moai_adk/templates/.claude/skills/moai-platform-vercel/modules/deployment-config.md +344 -0
  463. moai_adk/templates/.claude/skills/moai-platform-vercel/modules/edge-functions.md +222 -0
  464. moai_adk/templates/.claude/skills/moai-platform-vercel/modules/isr-caching.md +306 -0
  465. moai_adk/templates/.claude/skills/moai-platform-vercel/modules/kv-storage.md +399 -0
  466. moai_adk/templates/.claude/skills/moai-platform-vercel/reference.md +360 -0
  467. moai_adk/templates/.claude/skills/moai-plugin-builder/SKILL.md +473 -0
  468. moai_adk/templates/.claude/skills/moai-plugin-builder/examples.md +621 -0
  469. moai_adk/templates/.claude/skills/moai-plugin-builder/modules/migration.md +341 -0
  470. moai_adk/templates/.claude/skills/moai-plugin-builder/modules/validation.md +373 -0
  471. moai_adk/templates/.claude/skills/moai-plugin-builder/reference.md +464 -0
  472. moai_adk/templates/.claude/skills/moai-tool-ast-grep/SKILL.md +306 -0
  473. moai_adk/templates/.claude/skills/moai-tool-ast-grep/examples.md +1099 -0
  474. moai_adk/templates/.claude/skills/moai-tool-ast-grep/modules/language-specific.md +307 -0
  475. moai_adk/templates/.claude/skills/moai-tool-ast-grep/modules/pattern-syntax.md +237 -0
  476. moai_adk/templates/.claude/skills/moai-tool-ast-grep/modules/refactoring-patterns.md +260 -0
  477. moai_adk/templates/.claude/skills/moai-tool-ast-grep/modules/security-rules.md +239 -0
  478. moai_adk/templates/.claude/skills/moai-tool-ast-grep/reference.md +288 -0
  479. moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/languages/go.yml +90 -0
  480. moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/languages/python.yml +101 -0
  481. moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/languages/typescript.yml +83 -0
  482. moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/quality/complexity-check.yml +94 -0
  483. moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/quality/deprecated-apis.yml +84 -0
  484. moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/security/secrets-detection.yml +89 -0
  485. moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/security/sql-injection.yml +45 -0
  486. moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/security/xss-prevention.yml +50 -0
  487. moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/sgconfig.yml +54 -0
  488. moai_adk/templates/.claude/skills/moai-tool-opencode/SKILL.md +214 -0
  489. moai_adk/templates/.claude/skills/moai-tool-opencode/examples.md +697 -0
  490. moai_adk/templates/.claude/skills/moai-tool-opencode/index.md +96 -0
  491. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/configure/acp.md +115 -0
  492. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/configure/agents.md +241 -0
  493. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/configure/commands.md +197 -0
  494. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/configure/custom-tools.md +197 -0
  495. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/configure/formatters.md +164 -0
  496. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/configure/keybinds.md +150 -0
  497. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/configure/lsp-servers.md +156 -0
  498. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/configure/mcp-servers.md +214 -0
  499. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/configure/models.md +197 -0
  500. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/configure/permissions.md +162 -0
  501. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/configure/rules.md +129 -0
  502. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/configure/skills.md +192 -0
  503. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/configure/themes.md +200 -0
  504. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/configure/tools.md +169 -0
  505. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/core/config.md +211 -0
  506. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/core/enterprise.md +68 -0
  507. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/core/intro.md +127 -0
  508. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/core/migration-1.0.md +82 -0
  509. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/core/network.md +72 -0
  510. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/core/providers.md +310 -0
  511. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/core/troubleshooting.md +124 -0
  512. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/develop/ecosystem.md +75 -0
  513. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/develop/plugins.md +218 -0
  514. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/develop/sdk.md +266 -0
  515. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/develop/server.md +207 -0
  516. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/usage/cli.md +159 -0
  517. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/usage/github.md +181 -0
  518. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/usage/gitlab.md +122 -0
  519. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/usage/ide.md +74 -0
  520. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/usage/share.md +106 -0
  521. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/usage/tui.md +129 -0
  522. moai_adk/templates/.claude/skills/moai-tool-opencode/modules/usage/zen.md +118 -0
  523. moai_adk/templates/.claude/skills/moai-tool-opencode/reference.md +790 -0
  524. moai_adk/templates/.claude/skills/moai-workflow-jit-docs/SKILL.md +211 -0
  525. moai_adk/templates/.claude/skills/moai-workflow-jit-docs/examples.md +544 -0
  526. moai_adk/templates/.claude/skills/moai-workflow-jit-docs/modules/advanced-patterns.md +379 -0
  527. moai_adk/templates/.claude/skills/moai-workflow-jit-docs/modules/optimization.md +286 -0
  528. moai_adk/templates/.claude/skills/moai-workflow-jit-docs/reference.md +307 -0
  529. moai_adk/templates/.claude/skills/moai-workflow-project/README.md +190 -0
  530. moai_adk/templates/.claude/skills/moai-workflow-project/SKILL.md +260 -0
  531. moai_adk/templates/.claude/skills/moai-workflow-project/examples.md +547 -0
  532. moai_adk/templates/.claude/skills/moai-workflow-project/reference.md +275 -0
  533. moai_adk/templates/.claude/skills/moai-workflow-project/schemas/config-schema.json +316 -0
  534. moai_adk/templates/.claude/skills/moai-workflow-project/schemas/tab_schema.json +1434 -0
  535. moai_adk/templates/.claude/skills/moai-workflow-project/templates/config-template.json +71 -0
  536. moai_adk/templates/.claude/skills/moai-workflow-project/templates/doc-templates/product-template.md +44 -0
  537. moai_adk/templates/.claude/skills/moai-workflow-project/templates/doc-templates/structure-template.md +48 -0
  538. moai_adk/templates/.claude/skills/moai-workflow-project/templates/doc-templates/tech-template.md +92 -0
  539. moai_adk/templates/.claude/skills/moai-workflow-project/templates/question-templates/config-manager-setup.json +109 -0
  540. moai_adk/templates/.claude/skills/moai-workflow-project/templates/question-templates/language-initializer.json +228 -0
  541. moai_adk/templates/.claude/skills/moai-workflow-project/templates/question-templates/menu-project-config.json +130 -0
  542. moai_adk/templates/.claude/skills/moai-workflow-project/templates/question-templates/project-batch-questions.json +97 -0
  543. moai_adk/templates/.claude/skills/moai-workflow-project/templates/question-templates/spec-workflow-setup.json +150 -0
  544. moai_adk/templates/.claude/skills/moai-workflow-spec/SKILL.md +336 -0
  545. moai_adk/templates/.claude/skills/moai-workflow-spec/examples.md +900 -0
  546. moai_adk/templates/.claude/skills/moai-workflow-spec/modules/advanced-patterns.md +237 -0
  547. moai_adk/templates/.claude/skills/moai-workflow-spec/reference.md +704 -0
  548. moai_adk/templates/.claude/skills/moai-workflow-templates/SKILL.md +386 -0
  549. moai_adk/templates/.claude/skills/moai-workflow-templates/examples.md +552 -0
  550. moai_adk/templates/.claude/skills/moai-workflow-templates/modules/code-templates.md +124 -0
  551. moai_adk/templates/.claude/skills/moai-workflow-templates/modules/feedback-templates.md +100 -0
  552. moai_adk/templates/.claude/skills/moai-workflow-templates/modules/template-optimizer.md +138 -0
  553. moai_adk/templates/.claude/skills/moai-workflow-templates/reference.md +346 -0
  554. moai_adk/templates/.claude/skills/moai-workflow-testing/LICENSE.txt +202 -0
  555. moai_adk/templates/.claude/skills/moai-workflow-testing/SKILL.md +307 -0
  556. moai_adk/templates/.claude/skills/moai-workflow-testing/examples/ai-powered-testing.py +294 -0
  557. moai_adk/templates/.claude/skills/moai-workflow-testing/examples/console_logging.py +35 -0
  558. moai_adk/templates/.claude/skills/moai-workflow-testing/examples/element_discovery.py +40 -0
  559. moai_adk/templates/.claude/skills/moai-workflow-testing/examples/static_html_automation.py +34 -0
  560. moai_adk/templates/.claude/skills/moai-workflow-testing/examples.md +672 -0
  561. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/README.md +269 -0
  562. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/advanced-patterns.md +576 -0
  563. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/ai-debugging.md +302 -0
  564. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/context7-integration.md +286 -0
  565. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/review-workflows.md +500 -0
  566. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework/relevance-analysis.md +154 -0
  567. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework/safety-analysis.md +148 -0
  568. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework/scoring-algorithms.md +196 -0
  569. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework/timeliness-analysis.md +168 -0
  570. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework/truthfulness-analysis.md +136 -0
  571. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework/usability-analysis.md +153 -0
  572. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework.md +257 -0
  573. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review.md +263 -0
  574. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/code-review/analysis-patterns.md +340 -0
  575. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/code-review/core-classes.md +299 -0
  576. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/code-review/tool-integration.md +380 -0
  577. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/debugging/debugging-workflows.md +451 -0
  578. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/debugging/error-analysis.md +442 -0
  579. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/optimization.md +505 -0
  580. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance/optimization-patterns.md +473 -0
  581. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance/profiling-techniques.md +481 -0
  582. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization/ai-optimization.md +241 -0
  583. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization/bottleneck-detection.md +397 -0
  584. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization/optimization-plan.md +315 -0
  585. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization/profiler-core.md +277 -0
  586. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization/real-time-monitoring.md +187 -0
  587. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization.md +327 -0
  588. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/quality-metrics.md +415 -0
  589. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/refactoring/ai-workflows.md +620 -0
  590. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/refactoring/patterns.md +692 -0
  591. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/security-analysis.md +429 -0
  592. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/smart-refactoring.md +313 -0
  593. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/static-analysis.md +438 -0
  594. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd/core-classes.md +397 -0
  595. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd-context7/advanced-features.md +494 -0
  596. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd-context7/red-green-refactor.md +316 -0
  597. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd-context7/test-generation.md +471 -0
  598. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd-context7/test-patterns.md +371 -0
  599. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd-context7.md +265 -0
  600. moai_adk/templates/.claude/skills/moai-workflow-testing/modules/trust5-validation.md +428 -0
  601. moai_adk/templates/.claude/skills/moai-workflow-testing/reference/playwright-best-practices.md +57 -0
  602. moai_adk/templates/.claude/skills/moai-workflow-testing/reference.md +440 -0
  603. moai_adk/templates/.claude/skills/moai-workflow-testing/scripts/with_server.py +218 -0
  604. moai_adk/templates/.claude/skills/moai-workflow-testing/templates/alfred-integration.md +376 -0
  605. moai_adk/templates/.claude/skills/moai-workflow-testing/workflows/enterprise-testing-workflow.py +571 -0
  606. moai_adk/templates/.claude/skills/moai-workflow-worktree/SKILL.md +227 -0
  607. moai_adk/templates/.claude/skills/moai-workflow-worktree/examples.md +606 -0
  608. moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/integration-patterns.md +149 -0
  609. moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/moai-adk-integration.md +245 -0
  610. moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/parallel-advanced.md +310 -0
  611. moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/parallel-development.md +202 -0
  612. moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/parallel-workflows.md +302 -0
  613. moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/registry-architecture.md +271 -0
  614. moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/resource-optimization.md +300 -0
  615. moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/tools-integration.md +280 -0
  616. moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/troubleshooting.md +397 -0
  617. moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/worktree-commands.md +296 -0
  618. moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/worktree-management.md +217 -0
  619. moai_adk/templates/.claude/skills/moai-workflow-worktree/reference.md +357 -0
  620. moai_adk/templates/.git-hooks/pre-commit +103 -41
  621. moai_adk/templates/.git-hooks/pre-push +244 -31
  622. moai_adk/templates/.github/workflows/ci-universal.yml +513 -0
  623. moai_adk/templates/.github/workflows/security-secrets-check.yml +179 -0
  624. moai_adk/templates/.gitignore +181 -44
  625. moai_adk/templates/.lsp.json +152 -0
  626. moai_adk/templates/.mcp.json +6 -15
  627. moai_adk/templates/.moai/config/config.yaml +58 -0
  628. moai_adk/templates/.moai/config/multilingual-triggers.yaml +213 -0
  629. moai_adk/templates/.moai/config/questions/_schema.yaml +174 -0
  630. moai_adk/templates/.moai/config/questions/tab0-init.yaml +259 -0
  631. moai_adk/templates/.moai/config/questions/tab1-user.yaml +107 -0
  632. moai_adk/templates/.moai/config/questions/tab2-project.yaml +79 -0
  633. moai_adk/templates/.moai/config/questions/tab3-git.yaml +632 -0
  634. moai_adk/templates/.moai/config/questions/tab4-quality.yaml +183 -0
  635. moai_adk/templates/.moai/config/questions/tab5-system.yaml +96 -0
  636. moai_adk/templates/.moai/config/sections/git-strategy.yaml +116 -0
  637. moai_adk/templates/.moai/config/sections/language.yaml +11 -0
  638. moai_adk/templates/.moai/config/sections/project.yaml +13 -0
  639. moai_adk/templates/.moai/config/sections/quality.yaml +18 -0
  640. moai_adk/templates/.moai/config/sections/system.yaml +24 -0
  641. moai_adk/templates/.moai/config/sections/user.yaml +5 -0
  642. moai_adk/templates/.moai/config/statusline-config.yaml +92 -0
  643. moai_adk/templates/.moai/scripts/setup-glm.py +136 -0
  644. moai_adk/templates/CLAUDE.md +804 -499
  645. moai_adk/utils/__init__.py +24 -1
  646. moai_adk/utils/banner.py +7 -10
  647. moai_adk/utils/common.py +49 -30
  648. moai_adk/utils/link_validator.py +4 -12
  649. moai_adk/utils/safe_file_reader.py +2 -6
  650. moai_adk/utils/timeout.py +160 -0
  651. moai_adk/utils/toon_utils.py +256 -0
  652. moai_adk/version.py +22 -0
  653. moai_adk-0.41.0.dist-info/METADATA +3274 -0
  654. moai_adk-0.41.0.dist-info/RECORD +683 -0
  655. {moai_adk-0.25.4.dist-info โ†’ moai_adk-0.41.0.dist-info}/WHEEL +1 -1
  656. {moai_adk-0.25.4.dist-info โ†’ moai_adk-0.41.0.dist-info}/entry_points.txt +1 -0
  657. moai_adk/cli/commands/backup.py +0 -82
  658. moai_adk/cli/commands/improve_user_experience.py +0 -348
  659. moai_adk/cli/commands/migrate.py +0 -158
  660. moai_adk/cli/commands/validate_links.py +0 -118
  661. moai_adk/core/config/auto_spec_config.py +0 -346
  662. moai_adk/core/hooks/post_tool_auto_spec_completion.py +0 -925
  663. moai_adk/core/spec/confidence_scoring.py +0 -749
  664. moai_adk/core/spec/ears_template_engine.py +0 -1182
  665. moai_adk/core/spec/quality_validator.py +0 -721
  666. moai_adk/templates/.github/workflows/moai-gitflow.yml +0 -413
  667. moai_adk/templates/.github/workflows/moai-release-create.yml +0 -100
  668. moai_adk/templates/.github/workflows/moai-release-pipeline.yml +0 -188
  669. moai_adk/utils/user_experience.py +0 -531
  670. moai_adk-0.25.4.dist-info/METADATA +0 -2279
  671. moai_adk-0.25.4.dist-info/RECORD +0 -112
  672. {moai_adk-0.25.4.dist-info โ†’ moai_adk-0.41.0.dist-info}/licenses/LICENSE +0 -0
@@ -44,18 +44,28 @@ from __future__ import annotations
44
44
 
45
45
  import json
46
46
  import logging
47
+ import shutil
47
48
  import subprocess
48
49
  from datetime import datetime
49
50
  from pathlib import Path
50
- from typing import Any, cast
51
+ from typing import Any, Union, cast
51
52
 
52
53
  import click
54
+ import yaml
53
55
  from packaging import version
54
56
  from rich.console import Console
55
57
 
56
58
  from moai_adk import __version__
59
+ from moai_adk.core.merge import MergeAnalyzer
57
60
  from moai_adk.core.migration import VersionMigrator
61
+ from moai_adk.core.migration.alfred_to_moai_migrator import AlfredToMoaiMigrator
62
+
63
+ # Import new custom element restoration modules
64
+ from moai_adk.core.migration.custom_element_scanner import create_custom_element_scanner
65
+ from moai_adk.core.migration.selective_restorer import create_selective_restorer
66
+ from moai_adk.core.migration.user_selection_ui import create_user_selection_ui
58
67
  from moai_adk.core.template.processor import TemplateProcessor
68
+ from moai_adk.utils.common import reset_stdin
59
69
 
60
70
  console = Console()
61
71
  logger = logging.getLogger(__name__)
@@ -98,6 +108,45 @@ class TemplateSyncError(UpdateError):
98
108
  pass
99
109
 
100
110
 
111
+ def _get_config_path(project_path: Path) -> tuple[Path, bool]:
112
+ """Get config file path, preferring YAML over JSON.
113
+
114
+ Returns:
115
+ Tuple of (config_path, is_yaml)
116
+ """
117
+ yaml_path = project_path / ".moai" / "config" / "config.yaml"
118
+ json_path = project_path / ".moai" / "config" / "config.json"
119
+
120
+ if yaml_path.exists():
121
+ return yaml_path, True
122
+ return json_path, False
123
+
124
+
125
+ def _load_config(config_path: Path) -> dict[str, Any]:
126
+ """Load config from YAML or JSON file."""
127
+ if not config_path.exists():
128
+ return {}
129
+
130
+ is_yaml = config_path.suffix in (".yaml", ".yml")
131
+ content = config_path.read_text(encoding="utf-8")
132
+
133
+ if is_yaml:
134
+ return yaml.safe_load(content) or {}
135
+ return json.loads(content)
136
+
137
+
138
+ def _save_config(config_path: Path, config_data: dict[str, Any]) -> None:
139
+ """Save config to YAML or JSON file."""
140
+ is_yaml = config_path.suffix in (".yaml", ".yml")
141
+
142
+ if is_yaml:
143
+ content = yaml.safe_dump(config_data, default_flow_style=False, allow_unicode=True, sort_keys=False)
144
+ else:
145
+ content = json.dumps(config_data, indent=2, ensure_ascii=False) + "\n"
146
+
147
+ config_path.write_text(content, encoding="utf-8")
148
+
149
+
101
150
  def _is_installed_via_uv_tool() -> bool:
102
151
  """Check if moai-adk installed via uv tool.
103
152
 
@@ -220,9 +269,7 @@ def _get_latest_version() -> str:
220
269
  import urllib.request
221
270
 
222
271
  url = "https://pypi.org/pypi/moai-adk/json"
223
- with urllib.request.urlopen(
224
- url, timeout=5
225
- ) as response: # nosec B310 - URL is hardcoded HTTPS to PyPI API, no user input
272
+ with urllib.request.urlopen(url, timeout=5) as response: # nosec B310 - URL is hardcoded HTTPS to PyPI API, no user input
226
273
  data = json.loads(response.read().decode("utf-8"))
227
274
  return cast(str, data["info"]["version"])
228
275
  except (urllib.error.URLError, json.JSONDecodeError, KeyError, TimeoutError) as e:
@@ -280,42 +327,398 @@ def _get_project_config_version(project_path: Path) -> str:
280
327
  Returns "0.0.0" if template_version field not found (indicates no prior sync)
281
328
 
282
329
  Raises:
283
- ValueError: If config.json exists but cannot be parsed
330
+ ValueError: If config file exists but cannot be parsed
284
331
  """
285
332
 
286
- def _is_placeholder(value: str) -> bool:
333
+ def _is_placeholder_val(value: str) -> bool:
287
334
  """Check if value contains unsubstituted template placeholders."""
288
- return (
289
- isinstance(value, str) and value.startswith("{{") and value.endswith("}}")
290
- )
335
+ return isinstance(value, str) and value.startswith("{{") and value.endswith("}}")
291
336
 
292
- config_path = project_path / ".moai" / "config" / "config.json"
337
+ config_path, _ = _get_config_path(project_path)
293
338
 
294
339
  if not config_path.exists():
295
340
  # No config yet, treat as version 0.0.0 (needs initial sync)
296
341
  return "0.0.0"
297
342
 
298
343
  try:
299
- config_data = json.loads(config_path.read_text(encoding="utf-8"))
344
+ config_data = _load_config(config_path)
300
345
  # Check for template_version in project section
301
346
  template_version = config_data.get("project", {}).get("template_version")
302
- if template_version and not _is_placeholder(template_version):
347
+ if template_version and not _is_placeholder_val(template_version):
303
348
  return template_version
304
349
 
305
350
  # Fallback to moai version if no template_version exists
306
351
  moai_version = config_data.get("moai", {}).get("version")
307
- if moai_version and not _is_placeholder(moai_version):
352
+ if moai_version and not _is_placeholder_val(moai_version):
308
353
  return moai_version
309
354
 
310
355
  # If values are placeholders or don't exist, treat as uninitialized (0.0.0 triggers sync)
311
356
  return "0.0.0"
312
- except json.JSONDecodeError as e:
313
- raise ValueError(f"Failed to parse project config.json: {e}") from e
357
+ except (json.JSONDecodeError, yaml.YAMLError) as e:
358
+ raise ValueError(f"Failed to parse project config: {e}") from e
314
359
 
315
360
 
316
- def _detect_stale_cache(
317
- upgrade_output: str, current_version: str, latest_version: str
318
- ) -> bool:
361
+ def _ask_merge_strategy(yes: bool = False) -> str:
362
+ """
363
+ Ask user to choose merge strategy via CLI prompt.
364
+
365
+ Args:
366
+ yes: If True, auto-select "auto" (for --yes flag)
367
+
368
+ Returns:
369
+ "auto" or "manual"
370
+ """
371
+ if yes:
372
+ return "auto"
373
+
374
+ console.print("\n[cyan]๐Ÿ”€ Choose merge strategy:[/cyan]")
375
+ console.print("[cyan] [1] Auto-merge (default)[/cyan]")
376
+ console.print("[dim] โ†’ Template installs fresh + user changes preserved + minimal conflicts[/dim]")
377
+ console.print("[cyan] [2] Manual merge[/cyan]")
378
+ console.print("[dim] โ†’ Backup preserved + merge guide generated + you control merging[/dim]")
379
+
380
+ response = click.prompt("Select [1 or 2]", default="1")
381
+ if response == "2":
382
+ return "manual"
383
+ return "auto"
384
+
385
+
386
+ def _generate_manual_merge_guide(backup_path: Path, template_path: Path, project_path: Path) -> Path:
387
+ """
388
+ Generate comprehensive merge guide for manual merging.
389
+
390
+ Args:
391
+ backup_path: Path to backup directory
392
+ template_path: Path to template directory
393
+ project_path: Project root path
394
+
395
+ Returns:
396
+ Path to generated merge guide
397
+ """
398
+ guide_dir = project_path / ".moai" / "guides"
399
+ guide_dir.mkdir(parents=True, exist_ok=True)
400
+
401
+ guide_path = guide_dir / "merge-guide.md"
402
+
403
+ # Find changed files
404
+ changed_files = []
405
+ backup_claude = backup_path / ".claude"
406
+ backup_path / ".moai"
407
+
408
+ # Compare .claude/
409
+ if backup_claude.exists():
410
+ for file in backup_claude.rglob("*"):
411
+ if file.is_file():
412
+ rel_path = file.relative_to(backup_path)
413
+ current_file = project_path / rel_path
414
+ if current_file.exists():
415
+ if file.read_text(encoding="utf-8", errors="ignore") != current_file.read_text(
416
+ encoding="utf-8", errors="ignore"
417
+ ):
418
+ changed_files.append(f" - {rel_path}")
419
+ else:
420
+ changed_files.append(f" - {rel_path} (new)")
421
+
422
+ # Generate guide
423
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
424
+ guide_content = f"""# Merge Guide - Manual Merge Mode
425
+
426
+ **Generated**: {timestamp}
427
+ **Backup Location**: `{backup_path.relative_to(project_path)}/`
428
+
429
+ ## Summary
430
+
431
+ During this update, the following files were changed:
432
+
433
+ {chr(10).join(changed_files) if changed_files else " (No changes detected)"}
434
+
435
+ ## How to Merge
436
+
437
+ ### Option 1: Using diff (Terminal)
438
+
439
+ ```bash
440
+ # Compare specific files
441
+ diff {backup_path.name}/.claude/settings.json .claude/settings.json
442
+
443
+ # View all differences
444
+ diff -r {backup_path.name}/ .
445
+ ```
446
+
447
+ ### Option 2: Using Visual Merge Tool
448
+
449
+ ```bash
450
+ # macOS/Linux - Using meld
451
+ meld {backup_path.relative_to(project_path)}/ .
452
+
453
+ # Using VSCode
454
+ code --diff {backup_path.relative_to(project_path)}/.claude/settings.json .claude/settings.json
455
+ ```
456
+
457
+ ### Option 3: Manual Line-by-Line
458
+
459
+ 1. Open backup file in your editor
460
+ 2. Open current file side-by-side
461
+ 3. Manually copy your customizations
462
+
463
+ ## Key Files to Review
464
+
465
+ ### .claude/settings.json
466
+ - Contains MCP servers, hooks, environment variables
467
+ - **Action**: Restore any custom MCP servers and environment variables
468
+ - **Location**: {backup_path.relative_to(project_path)}/.claude/settings.json
469
+
470
+ ### .moai/config/config.json
471
+ - Contains project configuration and metadata
472
+ - **Action**: Verify user-specific settings are preserved
473
+ - **Location**: {backup_path.relative_to(project_path)}/.moai/config/config.json
474
+
475
+ ### .claude/commands/, .claude/agents/, .claude/hooks/
476
+ - Contains custom scripts and automation
477
+ - **Action**: Restore any custom scripts outside of /moai/ folders
478
+ - **Location**: {backup_path.relative_to(project_path)}/.claude/
479
+
480
+ ## Migration Checklist
481
+
482
+ - [ ] Compare `.claude/settings.json`
483
+ - [ ] Restore custom MCP servers
484
+ - [ ] Restore environment variables
485
+ - [ ] Verify hooks are properly configured
486
+
487
+ - [ ] Review `.moai/config/config.json`
488
+ - [ ] Check version was updated
489
+ - [ ] Verify user settings preserved
490
+
491
+ - [ ] Restore custom scripts
492
+ - [ ] Any custom commands outside /moai/
493
+ - [ ] Any custom agents outside /moai/
494
+ - [ ] Any custom hooks outside /moai/
495
+
496
+ - [ ] Run tests
497
+ ```bash
498
+ uv run pytest
499
+ moai-adk validate
500
+ ```
501
+
502
+ - [ ] Commit changes
503
+ ```bash
504
+ git add .
505
+ git commit -m "merge: Update templates with manual merge"
506
+ ```
507
+
508
+ ## Rollback if Needed
509
+
510
+ If you want to cancel and restore the backup:
511
+
512
+ ```bash
513
+ # Restore everything from backup
514
+ cp -r {backup_path.relative_to(project_path)}/.claude .
515
+ cp -r {backup_path.relative_to(project_path)}/.moai .
516
+ cp {backup_path.relative_to(project_path)}/CLAUDE.md .
517
+
518
+ # Or restore specific files
519
+ cp {backup_path.relative_to(project_path)}/.claude/settings.json .claude/
520
+ ```
521
+
522
+ ## Questions?
523
+
524
+ If you encounter merge conflicts or issues:
525
+
526
+ 1. Check the backup folder for original files
527
+ 2. Compare line-by-line using diff tools
528
+ 3. Consult documentation: https://adk.mo.ai.kr/update-merge
529
+
530
+ ---
531
+
532
+ **Backup**: `{backup_path}/`
533
+ **Generated**: {timestamp}
534
+ """
535
+
536
+ guide_path.write_text(guide_content, encoding="utf-8")
537
+ logger.info(f"โœ… Merge guide created: {guide_path}")
538
+ return guide_path
539
+
540
+
541
+ def _migrate_legacy_logs(project_path: Path, dry_run: bool = False) -> bool:
542
+ """Migrate legacy log files to unified directory structure.
543
+
544
+ Creates new unified directory structure (.moai/docs/, .moai/logs/archive/) and
545
+ migrates files from legacy locations to new unified structure:
546
+ - .moai/memory/last-session-state.json โ†’ .moai/logs/sessions/
547
+ - .moai/error_logs/ โ†’ .moai/logs/errors/
548
+ - .moai/reports/ โ†’ .moai/docs/reports/
549
+
550
+ Args:
551
+ project_path: Project directory path (absolute)
552
+ dry_run: If True, only simulate migration without making changes
553
+
554
+ Returns:
555
+ True if migration succeeded or no migration needed, False otherwise
556
+
557
+ Raises:
558
+ Exception: If migration fails during actual execution
559
+ """
560
+ try:
561
+ # Define source and target directories
562
+ legacy_memory = project_path / ".moai" / "memory"
563
+ legacy_error_logs = project_path / ".moai" / "error_logs"
564
+ legacy_reports = project_path / ".moai" / "reports"
565
+
566
+ # Create new unified directory structure
567
+ new_logs_dir = project_path / ".moai" / "logs"
568
+ new_docs_dir = project_path / ".moai" / "docs"
569
+ new_sessions_dir = new_logs_dir / "sessions"
570
+ new_errors_dir = new_logs_dir / "errors"
571
+ new_archive_dir = new_logs_dir / "archive"
572
+ new_docs_reports_dir = new_docs_dir / "reports"
573
+
574
+ migration_log = []
575
+ files_migrated = 0
576
+ files_skipped = 0
577
+
578
+ # Check if any legacy directories exist
579
+ has_legacy_files = legacy_memory.exists() or legacy_error_logs.exists() or legacy_reports.exists()
580
+
581
+ if not has_legacy_files:
582
+ if not dry_run:
583
+ # Create new directory structure anyway for consistency
584
+ new_logs_dir.mkdir(parents=True, exist_ok=True)
585
+ new_docs_dir.mkdir(parents=True, exist_ok=True)
586
+ new_sessions_dir.mkdir(parents=True, exist_ok=True)
587
+ new_errors_dir.mkdir(parents=True, exist_ok=True)
588
+ new_archive_dir.mkdir(parents=True, exist_ok=True)
589
+ new_docs_reports_dir.mkdir(parents=True, exist_ok=True)
590
+ return True
591
+
592
+ if dry_run:
593
+ console.print("[cyan]๐Ÿ” Legacy log migration (dry run):[/cyan]")
594
+
595
+ # Create new directories if not dry run
596
+ if not dry_run:
597
+ new_logs_dir.mkdir(parents=True, exist_ok=True)
598
+ new_docs_dir.mkdir(parents=True, exist_ok=True)
599
+ new_sessions_dir.mkdir(parents=True, exist_ok=True)
600
+ new_errors_dir.mkdir(parents=True, exist_ok=True)
601
+ new_archive_dir.mkdir(parents=True, exist_ok=True)
602
+ new_docs_reports_dir.mkdir(parents=True, exist_ok=True)
603
+
604
+ # Migration 1: .moai/memory/last-session-state.json โ†’ .moai/logs/sessions/
605
+ if legacy_memory.exists():
606
+ session_file = legacy_memory / "last-session-state.json"
607
+ if session_file.exists():
608
+ target_file = new_sessions_dir / "last-session-state.json"
609
+
610
+ if target_file.exists():
611
+ files_skipped += 1
612
+ migration_log.append(f"Skipped: {session_file.relative_to(project_path)} (target already exists)")
613
+ else:
614
+ if not dry_run:
615
+ shutil.copy2(session_file, target_file)
616
+ # Preserve original timestamp
617
+ shutil.copystat(session_file, target_file)
618
+ src_path = session_file.relative_to(project_path)
619
+ dst_path = target_file.relative_to(project_path)
620
+ migration_log.append(f"Migrated: {src_path} โ†’ {dst_path}")
621
+ else:
622
+ src_path = session_file.relative_to(project_path)
623
+ dst_path = target_file.relative_to(project_path)
624
+ migration_log.append(f"Would migrate: {src_path} โ†’ {dst_path}")
625
+ files_migrated += 1
626
+
627
+ # Migration 2: .moai/error_logs/ โ†’ .moai/logs/errors/
628
+ if legacy_error_logs.exists() and legacy_error_logs.is_dir():
629
+ for error_file in legacy_error_logs.rglob("*"):
630
+ if error_file.is_file():
631
+ relative_path = error_file.relative_to(legacy_error_logs)
632
+ target_file = new_errors_dir / relative_path
633
+
634
+ # Ensure target directory exists
635
+ if not dry_run:
636
+ target_file.parent.mkdir(parents=True, exist_ok=True)
637
+
638
+ if target_file.exists():
639
+ files_skipped += 1
640
+ error_path = error_file.relative_to(project_path)
641
+ migration_log.append(f"Skipped: {error_path} (target already exists)")
642
+ else:
643
+ if not dry_run:
644
+ shutil.copy2(error_file, target_file)
645
+ shutil.copystat(error_file, target_file)
646
+ error_path = error_file.relative_to(project_path)
647
+ target_path = target_file.relative_to(project_path)
648
+ migration_log.append(f"Migrated: {error_path} โ†’ {target_path}")
649
+ else:
650
+ error_path = error_file.relative_to(project_path)
651
+ target_path = target_file.relative_to(project_path)
652
+ migration_log.append(f"Would migrate: {error_path} โ†’ {target_path}")
653
+ files_migrated += 1
654
+
655
+ # Migration 3: .moai/reports/ โ†’ .moai/docs/reports/
656
+ if legacy_reports.exists() and legacy_reports.is_dir():
657
+ for report_file in legacy_reports.rglob("*"):
658
+ if report_file.is_file():
659
+ relative_path = report_file.relative_to(legacy_reports)
660
+ target_file = new_docs_reports_dir / relative_path
661
+
662
+ # Ensure target directory exists
663
+ if not dry_run:
664
+ target_file.parent.mkdir(parents=True, exist_ok=True)
665
+
666
+ if target_file.exists():
667
+ files_skipped += 1
668
+ report_path = report_file.relative_to(project_path)
669
+ migration_log.append(f"Skipped: {report_path} (target already exists)")
670
+ else:
671
+ if not dry_run:
672
+ shutil.copy2(report_file, target_file)
673
+ shutil.copystat(report_file, target_file)
674
+ report_path = report_file.relative_to(project_path)
675
+ target_path = target_file.relative_to(project_path)
676
+ migration_log.append(f"Migrated: {report_path} โ†’ {target_path}")
677
+ else:
678
+ report_path = report_file.relative_to(project_path)
679
+ target_path = target_file.relative_to(project_path)
680
+ migration_log.append(f"Would migrate: {report_path} โ†’ {target_path}")
681
+ files_migrated += 1
682
+
683
+ # Create migration log
684
+ migration_log_path = new_logs_dir / "migration-log.json"
685
+ if not dry_run and files_migrated > 0:
686
+ migration_data = {
687
+ "migration_timestamp": datetime.now().isoformat(),
688
+ "moai_adk_version": __version__,
689
+ "files_migrated": files_migrated,
690
+ "files_skipped": files_skipped,
691
+ "migration_log": migration_log,
692
+ "legacy_directories_found": [
693
+ str(d.relative_to(project_path))
694
+ for d in [legacy_memory, legacy_error_logs, legacy_reports]
695
+ if d.exists()
696
+ ],
697
+ }
698
+ json_content = json.dumps(migration_data, indent=2, ensure_ascii=False)
699
+ migration_log_path.write_text(json_content + "\n", encoding="utf-8")
700
+
701
+ # Display results
702
+ if files_migrated > 0 or files_skipped > 0:
703
+ if dry_run:
704
+ console.print(f" [yellow]Would migrate {files_migrated} files, skip {files_skipped} files[/yellow]")
705
+ else:
706
+ console.print(f" [green]โœ“ Migrated {files_migrated} legacy log files[/green]")
707
+ if files_skipped > 0:
708
+ console.print(f" [yellow]โš  Skipped {files_skipped} files (already exist)[/yellow]")
709
+ console.print(f" [dim] Migration log: {migration_log_path.relative_to(project_path)}[/dim]")
710
+ elif has_legacy_files:
711
+ console.print(" [dim] No files to migrate[/dim]")
712
+
713
+ return True
714
+
715
+ except Exception as e:
716
+ console.print(f" [red]โœ— Log migration failed: {e}[/red]")
717
+ logger.error(f"Legacy log migration failed: {e}", exc_info=True)
718
+ return False
719
+
720
+
721
+ def _detect_stale_cache(upgrade_output: str, current_version: str, latest_version: str) -> bool:
319
722
  """
320
723
  Detect if uv cache is stale by comparing versions.
321
724
 
@@ -410,9 +813,7 @@ def _clear_uv_package_cache(package_name: str = "moai-adk") -> bool:
410
813
  return False
411
814
 
412
815
 
413
- def _execute_upgrade_with_retry(
414
- installer_cmd: list[str], package_name: str = "moai-adk"
415
- ) -> bool:
816
+ def _execute_upgrade_with_retry(installer_cmd: list[str], package_name: str = "moai-adk") -> bool:
416
817
  """
417
818
  Execute upgrade with automatic cache retry on stale detection.
418
819
 
@@ -459,9 +860,7 @@ def _execute_upgrade_with_retry(
459
860
  """
460
861
  # Stage 1: First upgrade attempt
461
862
  try:
462
- result = subprocess.run(
463
- installer_cmd, capture_output=True, text=True, timeout=60, check=False
464
- )
863
+ result = subprocess.run(installer_cmd, capture_output=True, text=True, timeout=60, check=False)
465
864
  except subprocess.TimeoutExpired:
466
865
  raise # Re-raise timeout for caller to handle
467
866
  except Exception:
@@ -530,9 +929,7 @@ def _execute_upgrade(installer_cmd: list[str]) -> bool:
530
929
  subprocess.TimeoutExpired: If upgrade times out
531
930
  """
532
931
  try:
533
- result = subprocess.run(
534
- installer_cmd, capture_output=True, text=True, timeout=60, check=False
535
- )
932
+ result = subprocess.run(installer_cmd, capture_output=True, text=True, timeout=60, check=False)
536
933
  return result.returncode == 0
537
934
  except subprocess.TimeoutExpired:
538
935
  raise # Re-raise timeout for caller to handle
@@ -540,12 +937,539 @@ def _execute_upgrade(installer_cmd: list[str]) -> bool:
540
937
  return False
541
938
 
542
939
 
543
- def _sync_templates(project_path: Path, force: bool = False) -> bool:
940
+ def _preserve_user_settings(project_path: Path) -> dict[str, Path | None]:
941
+ """Back up user-specific settings files before template sync.
942
+
943
+ Args:
944
+ project_path: Project directory path
945
+
946
+ Returns:
947
+ Dictionary with backup paths of preserved files
948
+ """
949
+ preserved = {}
950
+ claude_dir = project_path / ".claude"
951
+
952
+ # Preserve settings.local.json (user MCP and GLM configuration)
953
+ settings_local = claude_dir / "settings.local.json"
954
+ if settings_local.exists():
955
+ try:
956
+ backup_dir = project_path / ".moai-backups" / "settings-backup"
957
+ backup_dir.mkdir(parents=True, exist_ok=True)
958
+ backup_path = backup_dir / "settings.local.json"
959
+ backup_path.write_text(settings_local.read_text(encoding="utf-8"))
960
+ preserved["settings.local.json"] = backup_path
961
+ console.print(" [cyan]๐Ÿ’พ Backed up user settings[/cyan]")
962
+ except Exception as e:
963
+ logger.warning(f"Failed to backup settings.local.json: {e}")
964
+ preserved["settings.local.json"] = None
965
+ else:
966
+ preserved["settings.local.json"] = None
967
+
968
+ return preserved
969
+
970
+
971
+ def _restore_user_settings(project_path: Path, preserved: dict[str, Path | None]) -> bool:
972
+ """Restore user-specific settings files after template sync.
973
+
974
+ Args:
975
+ project_path: Project directory path
976
+ preserved: Dictionary of backup paths from _preserve_user_settings()
977
+
978
+ Returns:
979
+ True if restoration succeeded, False otherwise
980
+ """
981
+ claude_dir = project_path / ".claude"
982
+ claude_dir.mkdir(parents=True, exist_ok=True)
983
+
984
+ success = True
985
+
986
+ # Restore settings.local.json
987
+ if preserved.get("settings.local.json"):
988
+ try:
989
+ backup_path = preserved["settings.local.json"]
990
+ settings_local = claude_dir / "settings.local.json"
991
+ settings_local.write_text(backup_path.read_text(encoding="utf-8"))
992
+ console.print(" [cyan]โœ“ Restored user settings[/cyan]")
993
+ except Exception as e:
994
+ console.print(f" [yellow]โš ๏ธ Failed to restore settings.local.json: {e}[/yellow]")
995
+ logger.warning(f"Failed to restore settings.local.json: {e}")
996
+ success = False
997
+
998
+ return success
999
+
1000
+
1001
+ def _get_template_skill_names() -> set[str]:
1002
+ """Get set of skill folder names from installed template.
1003
+
1004
+ Returns:
1005
+ Set of skill folder names that are part of the template package.
1006
+ """
1007
+ template_path = Path(__file__).parent.parent.parent / "templates"
1008
+ skills_path = template_path / ".claude" / "skills"
1009
+
1010
+ if not skills_path.exists():
1011
+ return set()
1012
+
1013
+ return {d.name for d in skills_path.iterdir() if d.is_dir()}
1014
+
1015
+
1016
+ def _get_template_command_names() -> set[str]:
1017
+ """Get set of command file names from installed template.
1018
+
1019
+ Returns:
1020
+ Set of .md command file names from .claude/commands/moai/ in template.
1021
+ """
1022
+ template_path = Path(__file__).parent.parent.parent / "templates"
1023
+ commands_path = template_path / ".claude" / "commands" / "moai"
1024
+
1025
+ if not commands_path.exists():
1026
+ return set()
1027
+
1028
+ return {f.name for f in commands_path.iterdir() if f.is_file() and f.suffix == ".md"}
1029
+
1030
+
1031
+ def _get_template_agent_names() -> set[str]:
1032
+ """Get set of agent file names from installed template.
1033
+
1034
+ Returns:
1035
+ Set of agent file names from .claude/agents/ in template.
1036
+ """
1037
+ template_path = Path(__file__).parent.parent.parent / "templates"
1038
+ agents_path = template_path / ".claude" / "agents"
1039
+
1040
+ if not agents_path.exists():
1041
+ return set()
1042
+
1043
+ return {f.name for f in agents_path.iterdir() if f.is_file()}
1044
+
1045
+
1046
+ def _get_template_hook_names() -> set[str]:
1047
+ """Get set of hook file names from installed template.
1048
+
1049
+ Returns:
1050
+ Set of .py hook file names from .claude/hooks/moai/ in template.
1051
+ """
1052
+ template_path = Path(__file__).parent.parent.parent / "templates"
1053
+ hooks_path = template_path / ".claude" / "hooks" / "moai"
1054
+
1055
+ if not hooks_path.exists():
1056
+ return set()
1057
+
1058
+ return {f.name for f in hooks_path.iterdir() if f.is_file() and f.suffix == ".py"}
1059
+
1060
+
1061
+ def _detect_custom_commands(project_path: Path, template_commands: set[str]) -> list[str]:
1062
+ """Detect custom commands NOT in template (user-created).
1063
+
1064
+ Args:
1065
+ project_path: Project path (absolute)
1066
+ template_commands: Set of template command file names
1067
+
1068
+ Returns:
1069
+ Sorted list of custom command file names.
1070
+ """
1071
+ commands_path = project_path / ".claude" / "commands" / "moai"
1072
+
1073
+ if not commands_path.exists():
1074
+ return []
1075
+
1076
+ project_commands = {f.name for f in commands_path.iterdir() if f.is_file() and f.suffix == ".md"}
1077
+ custom_commands = project_commands - template_commands
1078
+
1079
+ return sorted(custom_commands)
1080
+
1081
+
1082
+ def _detect_custom_agents(project_path: Path, template_agents: set[str]) -> list[str]:
1083
+ """Detect custom agents NOT in template (user-created).
1084
+
1085
+ Args:
1086
+ project_path: Project path (absolute)
1087
+ template_agents: Set of template agent file names
1088
+
1089
+ Returns:
1090
+ Sorted list of custom agent file names.
1091
+ """
1092
+ agents_path = project_path / ".claude" / "agents"
1093
+
1094
+ if not agents_path.exists():
1095
+ return []
1096
+
1097
+ project_agents = {f.name for f in agents_path.iterdir() if f.is_file()}
1098
+ custom_agents = project_agents - template_agents
1099
+
1100
+ return sorted(custom_agents)
1101
+
1102
+
1103
+ def _detect_custom_hooks(project_path: Path, template_hooks: set[str]) -> list[str]:
1104
+ """Detect custom hooks NOT in template (user-created).
1105
+
1106
+ Args:
1107
+ project_path: Project path (absolute)
1108
+ template_hooks: Set of template hook file names
1109
+
1110
+ Returns:
1111
+ Sorted list of custom hook file names.
1112
+ """
1113
+ hooks_path = project_path / ".claude" / "hooks" / "moai"
1114
+
1115
+ if not hooks_path.exists():
1116
+ return []
1117
+
1118
+ project_hooks = {f.name for f in hooks_path.iterdir() if f.is_file() and f.suffix == ".py"}
1119
+ custom_hooks = project_hooks - template_hooks
1120
+
1121
+ return sorted(custom_hooks)
1122
+
1123
+
1124
+ def _group_custom_files_by_type(
1125
+ custom_commands: list[str],
1126
+ custom_agents: list[str],
1127
+ custom_hooks: list[str],
1128
+ ) -> dict[str, list[str]]:
1129
+ """Group custom files by type for UI display.
1130
+
1131
+ Args:
1132
+ custom_commands: List of custom command file names
1133
+ custom_agents: List of custom agent file names
1134
+ custom_hooks: List of custom hook file names
1135
+
1136
+ Returns:
1137
+ Dictionary with keys: commands, agents, hooks
1138
+ """
1139
+ return {
1140
+ "commands": custom_commands,
1141
+ "agents": custom_agents,
1142
+ "hooks": custom_hooks,
1143
+ }
1144
+
1145
+
1146
+ def _prompt_custom_files_restore(
1147
+ custom_commands: list[str],
1148
+ custom_agents: list[str],
1149
+ custom_hooks: list[str],
1150
+ yes: bool = False,
1151
+ ) -> dict[str, list[str]]:
1152
+ """Interactive fuzzy checkbox for custom files restore with search support.
1153
+
1154
+ Args:
1155
+ custom_commands: List of custom command file names
1156
+ custom_agents: List of custom agent file names
1157
+ custom_hooks: List of custom hook file names
1158
+ yes: Auto-confirm flag (skips restoration in CI/CD mode)
1159
+
1160
+ Returns:
1161
+ Dictionary with selected files grouped by type.
1162
+ """
1163
+ # If no custom files, skip UI
1164
+ if not (custom_commands or custom_agents or custom_hooks):
1165
+ return {
1166
+ "commands": [],
1167
+ "agents": [],
1168
+ "hooks": [],
1169
+ }
1170
+
1171
+ # In --yes mode, skip restoration (safest default)
1172
+ if yes:
1173
+ console.print("\n[dim] Skipping custom files restoration (--yes mode)[/dim]\n")
1174
+ return {
1175
+ "commands": [],
1176
+ "agents": [],
1177
+ "hooks": [],
1178
+ }
1179
+
1180
+ # Try to use new UI, fallback to questionary if import fails
1181
+ try:
1182
+ from moai_adk.cli.ui.prompts import create_grouped_choices, fuzzy_checkbox
1183
+
1184
+ # Build grouped choices for fuzzy checkbox
1185
+ groups: dict[str, list[dict[str, str]]] = {}
1186
+
1187
+ if custom_commands:
1188
+ groups["Commands (.claude/commands/moai/)"] = [
1189
+ {"name": cmd, "value": f"cmd:{cmd}"} for cmd in custom_commands
1190
+ ]
1191
+
1192
+ if custom_agents:
1193
+ groups["Agents (.claude/agents/)"] = [{"name": agent, "value": f"agent:{agent}"} for agent in custom_agents]
1194
+
1195
+ if custom_hooks:
1196
+ groups["Hooks (.claude/hooks/moai/)"] = [{"name": hook, "value": f"hook:{hook}"} for hook in custom_hooks]
1197
+
1198
+ choices = create_grouped_choices(groups)
1199
+
1200
+ console.print("\n[#DA7756]๐Ÿ“ฆ Custom files detected in backup:[/#DA7756]")
1201
+ console.print("[dim] Use fuzzy search to find files quickly[/dim]\n")
1202
+
1203
+ selected = fuzzy_checkbox(
1204
+ "Select custom files to restore:",
1205
+ choices=choices,
1206
+ instruction="[Space] Toggle [Tab] All [Enter] Confirm [Type to search]",
1207
+ )
1208
+
1209
+ except ImportError:
1210
+ # Fallback to questionary if new UI not available
1211
+ import questionary
1212
+ from questionary import Choice, Separator
1213
+
1214
+ choices_legacy: list[Union[Separator, Choice]] = []
1215
+
1216
+ if custom_commands:
1217
+ choices_legacy.append(Separator("Commands (.claude/commands/moai/)"))
1218
+ for cmd in custom_commands:
1219
+ choices_legacy.append(Choice(title=cmd, value=f"cmd:{cmd}"))
1220
+
1221
+ if custom_agents:
1222
+ choices_legacy.append(Separator("Agents (.claude/agents/)"))
1223
+ for agent in custom_agents:
1224
+ choices_legacy.append(Choice(title=agent, value=f"agent:{agent}"))
1225
+
1226
+ if custom_hooks:
1227
+ choices_legacy.append(Separator("Hooks (.claude/hooks/moai/)"))
1228
+ for hook in custom_hooks:
1229
+ choices_legacy.append(Choice(title=hook, value=f"hook:{hook}"))
1230
+
1231
+ console.print("\n[cyan]๐Ÿ“ฆ Custom files detected in backup:[/cyan]")
1232
+ console.print("[dim] Select files to restore (none selected by default)[/dim]\n")
1233
+
1234
+ selected = questionary.checkbox(
1235
+ "Select custom files to restore:",
1236
+ choices=choices_legacy,
1237
+ ).ask()
1238
+
1239
+ # Parse results
1240
+ result_commands = []
1241
+ result_agents = []
1242
+ result_hooks = []
1243
+
1244
+ if selected:
1245
+ for item in selected:
1246
+ if item.startswith("cmd:"):
1247
+ result_commands.append(item[4:])
1248
+ elif item.startswith("agent:"):
1249
+ result_agents.append(item[6:])
1250
+ elif item.startswith("hook:"):
1251
+ result_hooks.append(item[5:])
1252
+
1253
+ return {
1254
+ "commands": result_commands,
1255
+ "agents": result_agents,
1256
+ "hooks": result_hooks,
1257
+ }
1258
+
1259
+
1260
+ def _restore_custom_files(
1261
+ project_path: Path,
1262
+ backup_path: Path,
1263
+ selected_commands: list[str],
1264
+ selected_agents: list[str],
1265
+ selected_hooks: list[str],
1266
+ ) -> bool:
1267
+ """Restore selected custom files from backup to project.
1268
+
1269
+ Args:
1270
+ project_path: Project directory path
1271
+ backup_path: Backup directory path
1272
+ selected_commands: List of command files to restore
1273
+ selected_agents: List of agent files to restore
1274
+ selected_hooks: List of hook files to restore
1275
+
1276
+ Returns:
1277
+ True if all restorations succeeded, False otherwise.
1278
+ """
1279
+ import shutil
1280
+
1281
+ success = True
1282
+
1283
+ # Restore commands
1284
+ if selected_commands:
1285
+ commands_dst = project_path / ".claude" / "commands" / "moai"
1286
+ commands_dst.mkdir(parents=True, exist_ok=True)
1287
+
1288
+ for cmd_file in selected_commands:
1289
+ src = backup_path / ".claude" / "commands" / "moai" / cmd_file
1290
+ dst = commands_dst / cmd_file
1291
+
1292
+ if src.exists():
1293
+ try:
1294
+ shutil.copy2(src, dst)
1295
+ except Exception as e:
1296
+ logger.warning(f"Failed to restore command {cmd_file}: {e}")
1297
+ success = False
1298
+ else:
1299
+ logger.warning(f"Command file not in backup: {cmd_file}")
1300
+ success = False
1301
+
1302
+ # Restore agents
1303
+ if selected_agents:
1304
+ agents_dst = project_path / ".claude" / "agents"
1305
+ agents_dst.mkdir(parents=True, exist_ok=True)
1306
+
1307
+ for agent_file in selected_agents:
1308
+ src = backup_path / ".claude" / "agents" / agent_file
1309
+ dst = agents_dst / agent_file
1310
+
1311
+ if src.exists():
1312
+ try:
1313
+ shutil.copy2(src, dst)
1314
+ except Exception as e:
1315
+ logger.warning(f"Failed to restore agent {agent_file}: {e}")
1316
+ success = False
1317
+ else:
1318
+ logger.warning(f"Agent file not in backup: {agent_file}")
1319
+ success = False
1320
+
1321
+ # Restore hooks
1322
+ if selected_hooks:
1323
+ hooks_dst = project_path / ".claude" / "hooks" / "moai"
1324
+ hooks_dst.mkdir(parents=True, exist_ok=True)
1325
+
1326
+ for hook_file in selected_hooks:
1327
+ src = backup_path / ".claude" / "hooks" / "moai" / hook_file
1328
+ dst = hooks_dst / hook_file
1329
+
1330
+ if src.exists():
1331
+ try:
1332
+ shutil.copy2(src, dst)
1333
+ except Exception as e:
1334
+ logger.warning(f"Failed to restore hook {hook_file}: {e}")
1335
+ success = False
1336
+ else:
1337
+ logger.warning(f"Hook file not in backup: {hook_file}")
1338
+ success = False
1339
+
1340
+ return success
1341
+
1342
+
1343
+ def _detect_custom_skills(project_path: Path, template_skills: set[str]) -> list[str]:
1344
+ """Detect skills NOT in template (user-created).
1345
+
1346
+ Args:
1347
+ project_path: Project path (absolute)
1348
+ template_skills: Set of template skill names
1349
+
1350
+ Returns:
1351
+ Sorted list of custom skill names.
1352
+ """
1353
+ skills_path = project_path / ".claude" / "skills"
1354
+
1355
+ if not skills_path.exists():
1356
+ return []
1357
+
1358
+ project_skills = {d.name for d in skills_path.iterdir() if d.is_dir()}
1359
+ custom_skills = project_skills - template_skills
1360
+
1361
+ return sorted(custom_skills)
1362
+
1363
+
1364
+ def _prompt_skill_restore(custom_skills: list[str], yes: bool = False) -> list[str]:
1365
+ """Interactive fuzzy checkbox for skill restore with search support.
1366
+
1367
+ Args:
1368
+ custom_skills: List of custom skill names
1369
+ yes: Auto-confirm flag (skips restoration in CI/CD mode)
1370
+
1371
+ Returns:
1372
+ List of skills user selected to restore.
1373
+ """
1374
+ if not custom_skills:
1375
+ return []
1376
+
1377
+ console.print("\n[#DA7756]๐Ÿ“ฆ Custom skills detected in backup:[/#DA7756]")
1378
+ for skill in custom_skills:
1379
+ console.print(f" โ€ข {skill}")
1380
+ console.print()
1381
+
1382
+ if yes:
1383
+ console.print("[dim] Skipping restoration (--yes mode)[/dim]\n")
1384
+ return []
1385
+
1386
+ # Try new UI, fallback to questionary
1387
+ try:
1388
+ from moai_adk.cli.ui.prompts import fuzzy_checkbox
1389
+
1390
+ choices = [{"name": skill, "value": skill} for skill in custom_skills]
1391
+
1392
+ selected = fuzzy_checkbox(
1393
+ "Select skills to restore (type to search):",
1394
+ choices=choices,
1395
+ instruction="[Space] Toggle [Tab] All [Enter] Confirm [Type to search]",
1396
+ )
1397
+
1398
+ except ImportError:
1399
+ import questionary
1400
+
1401
+ selected = questionary.checkbox(
1402
+ "Select skills to restore (none selected by default):",
1403
+ choices=[questionary.Choice(title=skill, checked=False) for skill in custom_skills],
1404
+ ).ask()
1405
+
1406
+ return selected if selected else []
1407
+
1408
+
1409
+ def _restore_selected_skills(skills: list[str], backup_path: Path, project_path: Path) -> bool:
1410
+ """Restore selected skills from backup.
1411
+
1412
+ Args:
1413
+ skills: List of skill names to restore
1414
+ backup_path: Backup directory path
1415
+ project_path: Project path (absolute)
1416
+
1417
+ Returns:
1418
+ True if all restorations succeeded.
1419
+ """
1420
+ import shutil
1421
+
1422
+ if not skills:
1423
+ return True
1424
+
1425
+ console.print("\n[cyan]๐Ÿ“ฅ Restoring selected skills...[/cyan]")
1426
+ skills_dst = project_path / ".claude" / "skills"
1427
+ skills_dst.mkdir(parents=True, exist_ok=True)
1428
+
1429
+ success = True
1430
+ for skill_name in skills:
1431
+ src = backup_path / ".claude" / "skills" / skill_name
1432
+ dst = skills_dst / skill_name
1433
+
1434
+ if src.exists():
1435
+ try:
1436
+ shutil.copytree(src, dst, dirs_exist_ok=True)
1437
+ console.print(f" [green]โœ“ Restored: {skill_name}[/green]")
1438
+ except Exception as e:
1439
+ console.print(f" [red]โœ— Failed: {skill_name} - {e}[/red]")
1440
+ success = False
1441
+ else:
1442
+ console.print(f" [yellow]โš  Not in backup: {skill_name}[/yellow]")
1443
+ success = False
1444
+
1445
+ return success
1446
+
1447
+
1448
+ def _show_post_update_guidance(backup_path: Path) -> None:
1449
+ """Show post-update guidance for running /moai:0-project update.
1450
+
1451
+ Args:
1452
+ backup_path: Backup directory path for reference
1453
+ """
1454
+ console.print("\n" + "[cyan]" + "=" * 60 + "[/cyan]")
1455
+ console.print("[green]โœ… Update complete![/green]")
1456
+ console.print("\n[yellow]๐Ÿ“ IMPORTANT - Next step:[/yellow]")
1457
+ console.print(" Run [cyan]/moai:0-project update[/cyan] in Claude Code")
1458
+ console.print("\n This will:")
1459
+ console.print(" โ€ข Merge your settings with new templates")
1460
+ console.print(" โ€ข Validate configuration compatibility")
1461
+ console.print("\n[dim]๐Ÿ’ก Personal instructions should go in CLAUDE.local.md[/dim]")
1462
+ console.print(f"[dim]๐Ÿ“‚ Backup location: {backup_path}[/dim]")
1463
+ console.print("[cyan]" + "=" * 60 + "[/cyan]\n")
1464
+
1465
+
1466
+ def _sync_templates(project_path: Path, force: bool = False, yes: bool = False) -> bool:
544
1467
  """Sync templates to project with rollback mechanism.
545
1468
 
546
1469
  Args:
547
1470
  project_path: Project path (absolute)
548
1471
  force: Force update without backup
1472
+ yes: Auto-confirm flag (skips interactive prompts)
549
1473
 
550
1474
  Returns:
551
1475
  True if sync succeeded, False otherwise
@@ -554,6 +1478,20 @@ def _sync_templates(project_path: Path, force: bool = False) -> bool:
554
1478
 
555
1479
  backup_path = None
556
1480
  try:
1481
+ # NEW: Detect custom files and skills BEFORE backup/sync
1482
+ template_skills = _get_template_skill_names()
1483
+ _detect_custom_skills(project_path, template_skills)
1484
+
1485
+ # Detect custom commands, agents, and hooks
1486
+ template_commands = _get_template_command_names()
1487
+ _detect_custom_commands(project_path, template_commands)
1488
+
1489
+ template_agents = _get_template_agent_names()
1490
+ _detect_custom_agents(project_path, template_agents)
1491
+
1492
+ template_hooks = _get_template_hook_names()
1493
+ _detect_custom_hooks(project_path, template_hooks)
1494
+
557
1495
  processor = TemplateProcessor(project_path)
558
1496
 
559
1497
  # Create pre-sync backup for rollback
@@ -563,6 +1501,25 @@ def _sync_templates(project_path: Path, force: bool = False) -> bool:
563
1501
  backup_path = backup.create_backup()
564
1502
  console.print(f"๐Ÿ’พ Created backup: {backup_path.name}")
565
1503
 
1504
+ # Merge analysis using Pure Python semantic heuristics
1505
+ try:
1506
+ analyzer = MergeAnalyzer(project_path)
1507
+ # Template source path from installed package
1508
+ template_path = Path(__file__).parent.parent.parent / "templates"
1509
+
1510
+ console.print("\n[cyan]๐Ÿ” Starting merge analysis...[/cyan]")
1511
+ console.print("[dim] Analyzing templates with semantic heuristics.[/dim]\n")
1512
+ analysis = analyzer.analyze_merge(backup_path, template_path)
1513
+
1514
+ # Ask user confirmation
1515
+ if not analyzer.ask_user_confirmation(analysis):
1516
+ console.print("[yellow]โš ๏ธ User cancelled the update.[/yellow]")
1517
+ backup.restore_backup(backup_path)
1518
+ return False
1519
+ except Exception as e:
1520
+ console.print(f"[yellow]โš ๏ธ Merge analysis failed: {e}[/yellow]")
1521
+ console.print("[yellow]Proceeding with automatic merge.[/yellow]")
1522
+
566
1523
  # Load existing config
567
1524
  existing_config = _load_existing_config(project_path)
568
1525
 
@@ -571,18 +1528,34 @@ def _sync_templates(project_path: Path, force: bool = False) -> bool:
571
1528
  if context:
572
1529
  processor.set_context(context)
573
1530
 
574
- # Copy templates
1531
+ # Copy templates (including moai folder)
575
1532
  processor.copy_templates(backup=False, silent=True)
576
1533
 
1534
+ # Stage 1.5: Alfred โ†’ Moai migration (AFTER template sync)
1535
+ # Execute migration after template copy (moai folders must exist first)
1536
+ migrator = AlfredToMoaiMigrator(project_path)
1537
+ if migrator.needs_migration():
1538
+ console.print("\n[cyan]๐Ÿ”„ Migrating folder structure: Alfred โ†’ Moai[/cyan]")
1539
+ try:
1540
+ if not migrator.execute_migration(backup_path):
1541
+ console.print("[red]โŒ Alfred โ†’ Moai migration failed[/red]")
1542
+ if backup_path:
1543
+ console.print("[yellow]๐Ÿ”„ Restoring from backup...[/yellow]")
1544
+ backup = TemplateBackup(project_path)
1545
+ backup.restore_backup(backup_path)
1546
+ return False
1547
+ except Exception as e:
1548
+ console.print(f"[red]โŒ Error during migration: {e}[/red]")
1549
+ if backup_path:
1550
+ backup = TemplateBackup(project_path)
1551
+ backup.restore_backup(backup_path)
1552
+ return False
1553
+
577
1554
  # Validate template substitution
578
- validation_passed = _validate_template_substitution_with_rollback(
579
- project_path, backup_path
580
- )
1555
+ validation_passed = _validate_template_substitution_with_rollback(project_path, backup_path)
581
1556
  if not validation_passed:
582
1557
  if backup_path:
583
- console.print(
584
- f"[yellow]๐Ÿ”„ Rolling back to backup: {backup_path.name}[/yellow]"
585
- )
1558
+ console.print(f"[yellow]๐Ÿ”„ Rolling back to backup: {backup_path.name}[/yellow]")
586
1559
  backup.restore_backup(backup_path)
587
1560
  return False
588
1561
 
@@ -593,13 +1566,50 @@ def _sync_templates(project_path: Path, force: bool = False) -> bool:
593
1566
  # Set optimized=false
594
1567
  set_optimized_false(project_path)
595
1568
 
1569
+ # Update companyAnnouncements in settings.local.json
1570
+ try:
1571
+ import sys
1572
+
1573
+ utils_dir = (
1574
+ Path(__file__).parent.parent.parent / "templates" / ".claude" / "hooks" / "moai" / "shared" / "utils"
1575
+ )
1576
+
1577
+ if utils_dir.exists():
1578
+ sys.path.insert(0, str(utils_dir))
1579
+ try:
1580
+ from announcement_translator import auto_translate_and_update
1581
+
1582
+ console.print("[cyan]Updating announcements...[/cyan]")
1583
+ auto_translate_and_update(project_path)
1584
+ console.print("[green]โœ“ Announcements updated[/green]")
1585
+ except Exception as e:
1586
+ console.print(f"[yellow]โš ๏ธ Announcement update failed: {e}[/yellow]")
1587
+ finally:
1588
+ sys.path.remove(str(utils_dir))
1589
+
1590
+ except Exception as e:
1591
+ console.print(f"[yellow]โš ๏ธ Announcement module not available: {e}[/yellow]")
1592
+
1593
+ # NEW: Interactive custom element restore using new system
1594
+ _handle_custom_element_restoration(project_path, backup_path, yes)
1595
+
1596
+ # NEW: Migrate legacy logs to unified structure
1597
+ console.print("\n[cyan]๐Ÿ“ Migrating legacy log files...[/cyan]")
1598
+ if not _migrate_legacy_logs(project_path):
1599
+ console.print("[yellow]โš ๏ธ Legacy log migration failed, but update continuing[/yellow]")
1600
+
1601
+ # Clean up legacy presets directory
1602
+ _cleanup_legacy_presets(project_path)
1603
+
1604
+ # NEW: Show post-update guidance
1605
+ if backup_path:
1606
+ _show_post_update_guidance(backup_path)
1607
+
596
1608
  return True
597
1609
  except Exception as e:
598
1610
  console.print(f"[red]โœ— Template sync failed: {e}[/red]")
599
1611
  if backup_path:
600
- console.print(
601
- f"[yellow]๐Ÿ”„ Rolling back to backup: {backup_path.name}[/yellow]"
602
- )
1612
+ console.print(f"[yellow]๐Ÿ”„ Rolling back to backup: {backup_path.name}[/yellow]")
603
1613
  try:
604
1614
  backup = TemplateBackup(project_path)
605
1615
  backup.restore_backup(backup_path)
@@ -626,47 +1636,38 @@ def get_latest_version() -> str | None:
626
1636
 
627
1637
 
628
1638
  def set_optimized_false(project_path: Path) -> None:
629
- """Set config.json's optimized field to false.
1639
+ """Set config's optimized field to false.
630
1640
 
631
1641
  Args:
632
1642
  project_path: Project path (absolute).
633
1643
  """
634
- config_path = project_path / ".moai" / "config" / "config.json"
1644
+ config_path, _ = _get_config_path(project_path)
635
1645
  if not config_path.exists():
636
1646
  return
637
1647
 
638
1648
  try:
639
- config_data = json.loads(config_path.read_text(encoding="utf-8"))
1649
+ config_data = _load_config(config_path)
640
1650
  config_data.setdefault("project", {})["optimized"] = False
641
- config_path.write_text(
642
- json.dumps(config_data, indent=2, ensure_ascii=False) + "\n",
643
- encoding="utf-8",
644
- )
645
- except (json.JSONDecodeError, KeyError):
646
- # Ignore errors if config.json is invalid
1651
+ _save_config(config_path, config_data)
1652
+ except (json.JSONDecodeError, yaml.YAMLError, KeyError):
1653
+ # Ignore errors if config is invalid
647
1654
  pass
648
1655
 
649
1656
 
650
1657
  def _load_existing_config(project_path: Path) -> dict[str, Any]:
651
- """Load existing config.json if available."""
652
- config_path = project_path / ".moai" / "config" / "config.json"
1658
+ """Load existing config (YAML or JSON) if available."""
1659
+ config_path, _ = _get_config_path(project_path)
653
1660
  if config_path.exists():
654
1661
  try:
655
- return json.loads(config_path.read_text(encoding="utf-8"))
656
- except json.JSONDecodeError:
657
- console.print(
658
- "[yellow]โš  Existing config.json could not be parsed. Proceeding with defaults.[/yellow]"
659
- )
1662
+ return _load_config(config_path)
1663
+ except (json.JSONDecodeError, yaml.YAMLError):
1664
+ console.print("[yellow]โš  Existing config could not be parsed. Proceeding with defaults.[/yellow]")
660
1665
  return {}
661
1666
 
662
1667
 
663
1668
  def _is_placeholder(value: Any) -> bool:
664
1669
  """Check if a string value is an unsubstituted template placeholder."""
665
- return (
666
- isinstance(value, str)
667
- and value.strip().startswith("{{")
668
- and value.strip().endswith("}}")
669
- )
1670
+ return isinstance(value, str) and value.strip().startswith("{{") and value.strip().endswith("}}")
670
1671
 
671
1672
 
672
1673
  def _coalesce(*values: Any, default: str = "") -> str:
@@ -730,19 +1731,90 @@ def _build_template_context(
730
1731
  )
731
1732
 
732
1733
  # Detect OS for cross-platform Hook path configuration
733
- hook_project_dir = (
734
- "%CLAUDE_PROJECT_DIR%"
735
- if platform.system() == "Windows"
736
- else "$CLAUDE_PROJECT_DIR"
737
- )
1734
+ hook_project_dir = "%CLAUDE_PROJECT_DIR%" if platform.system() == "Windows" else "$CLAUDE_PROJECT_DIR"
738
1735
 
739
- # Extract language configuration
740
- language_config = existing_config.get("language", {})
741
- if not isinstance(language_config, dict):
742
- language_config = {}
1736
+ # Detect OS for cross-platform statusline command
1737
+ # Windows: Use python -m for better PATH compatibility
1738
+ # Unix: Use moai-adk directly (assumes installed via uv tool)
1739
+ if platform.system() == "Windows":
1740
+ statusline_command = "python -m moai_adk statusline"
1741
+ else:
1742
+ statusline_command = "moai-adk statusline"
1743
+
1744
+ # Extract and resolve language configuration using centralized resolver
1745
+ try:
1746
+ from moai_adk.core.language_config_resolver import get_resolver
1747
+
1748
+ # Use language resolver to get complete configuration
1749
+ resolver = get_resolver(str(project_path))
1750
+ resolved_config = resolver.resolve_config()
1751
+
1752
+ # Extract language configuration with environment variable priority
1753
+ language_config = {
1754
+ "conversation_language": resolved_config.get("conversation_language", "en"),
1755
+ "conversation_language_name": resolved_config.get("conversation_language_name", "English"),
1756
+ "agent_prompt_language": resolved_config.get("agent_prompt_language", "en"),
1757
+ }
1758
+
1759
+ # Extract user personalization
1760
+ user_name = resolved_config.get("user_name", "")
1761
+ personalized_greeting = resolver.get_personalized_greeting(resolved_config)
1762
+ config_source = resolved_config.get("config_source", "config_file")
1763
+
1764
+ except ImportError:
1765
+ # Fallback to basic language config extraction if resolver not available
1766
+ language_config = existing_config.get("language", {})
1767
+ if not isinstance(language_config, dict):
1768
+ language_config = {}
1769
+
1770
+ user_name = existing_config.get("user", {}).get("name", "")
1771
+ conv_lang = language_config.get("conversation_language")
1772
+ personalized_greeting = f"{user_name}๋‹˜" if user_name and conv_lang == "ko" else user_name
1773
+ config_source = "config_file"
1774
+
1775
+ # Enhanced version formatting (matches TemplateProcessor.get_enhanced_version_context)
1776
+ def format_short_version(v: str) -> str:
1777
+ """Remove 'v' prefix if present."""
1778
+ return v[1:] if v.startswith("v") else v
1779
+
1780
+ def format_display_version(v: str) -> str:
1781
+ """Format display version with proper formatting."""
1782
+ if v == "unknown":
1783
+ return "MoAI-ADK unknown version"
1784
+ elif v.startswith("v"):
1785
+ return f"MoAI-ADK {v}"
1786
+ else:
1787
+ return f"MoAI-ADK v{v}"
1788
+
1789
+ def format_trimmed_version(v: str, max_length: int = 10) -> str:
1790
+ """Format version with maximum length for UI displays."""
1791
+ if v == "unknown":
1792
+ return "unknown"
1793
+ clean_version = v[1:] if v.startswith("v") else v
1794
+ if len(clean_version) > max_length:
1795
+ return clean_version[:max_length]
1796
+ return clean_version
1797
+
1798
+ def format_semver_version(v: str) -> str:
1799
+ """Format version as semantic version."""
1800
+ if v == "unknown":
1801
+ return "0.0.0"
1802
+ clean_version = v[1:] if v.startswith("v") else v
1803
+ import re
1804
+
1805
+ semver_match = re.match(r"^(\d+\.\d+\.\d+)", clean_version)
1806
+ if semver_match:
1807
+ return semver_match.group(1)
1808
+ return "0.0.0"
743
1809
 
744
1810
  return {
745
1811
  "MOAI_VERSION": version_for_config,
1812
+ "MOAI_VERSION_SHORT": format_short_version(version_for_config),
1813
+ "MOAI_VERSION_DISPLAY": format_display_version(version_for_config),
1814
+ "MOAI_VERSION_TRIMMED": format_trimmed_version(version_for_config),
1815
+ "MOAI_VERSION_SEMVER": format_semver_version(version_for_config),
1816
+ "MOAI_VERSION_VALID": "true" if version_for_config != "unknown" else "false",
1817
+ "MOAI_VERSION_SOURCE": "config_cached",
746
1818
  "PROJECT_NAME": project_name,
747
1819
  "PROJECT_MODE": project_mode,
748
1820
  "PROJECT_DESCRIPTION": project_description,
@@ -750,12 +1822,23 @@ def _build_template_context(
750
1822
  "CREATION_TIMESTAMP": created_at,
751
1823
  "PROJECT_DIR": hook_project_dir,
752
1824
  "CONVERSATION_LANGUAGE": language_config.get("conversation_language", "en"),
753
- "CONVERSATION_LANGUAGE_NAME": language_config.get(
754
- "conversation_language_name", "English"
1825
+ "CONVERSATION_LANGUAGE_NAME": language_config.get("conversation_language_name", "English"),
1826
+ "AGENT_PROMPT_LANGUAGE": language_config.get("agent_prompt_language", "en"),
1827
+ "GIT_COMMIT_MESSAGES_LANGUAGE": language_config.get("git_commit_messages", "en"),
1828
+ "CODE_COMMENTS_LANGUAGE": language_config.get("code_comments", "en"),
1829
+ "DOCUMENTATION_LANGUAGE": language_config.get(
1830
+ "documentation", language_config.get("conversation_language", "en")
755
1831
  ),
1832
+ "ERROR_MESSAGES_LANGUAGE": language_config.get(
1833
+ "error_messages", language_config.get("conversation_language", "en")
1834
+ ),
1835
+ "USER_NAME": user_name,
1836
+ "PERSONALIZED_GREETING": personalized_greeting,
1837
+ "LANGUAGE_CONFIG_SOURCE": config_source,
756
1838
  "CODEBASE_LANGUAGE": project_section.get("language", "generic"),
757
1839
  "PROJECT_OWNER": project_section.get("author", "@user"),
758
1840
  "AUTHOR": project_section.get("author", "@user"),
1841
+ "STATUSLINE_COMMAND": statusline_command,
759
1842
  }
760
1843
 
761
1844
 
@@ -765,18 +1848,18 @@ def _preserve_project_metadata(
765
1848
  existing_config: dict[str, Any],
766
1849
  version_for_config: str,
767
1850
  ) -> None:
768
- """Restore project-specific metadata in the new config.json.
1851
+ """Restore project-specific metadata in the new config (YAML or JSON).
769
1852
 
770
1853
  Also updates template_version to track which template version is synchronized.
771
1854
  """
772
- config_path = project_path / ".moai" / "config" / "config.json"
1855
+ config_path, _ = _get_config_path(project_path)
773
1856
  if not config_path.exists():
774
1857
  return
775
1858
 
776
1859
  try:
777
- config_data = json.loads(config_path.read_text(encoding="utf-8"))
778
- except json.JSONDecodeError:
779
- console.print("[red]โœ— Failed to parse config.json after template copy[/red]")
1860
+ config_data = _load_config(config_path)
1861
+ except (json.JSONDecodeError, yaml.YAMLError):
1862
+ console.print("[red]โœ— Failed to parse config after template copy[/red]")
780
1863
  return
781
1864
 
782
1865
  project_data = config_data.setdefault("project", {})
@@ -796,9 +1879,7 @@ def _preserve_project_metadata(
796
1879
  if locale:
797
1880
  project_data["locale"] = locale
798
1881
 
799
- language = _coalesce(
800
- existing_project.get("language"), existing_config.get("language")
801
- )
1882
+ language = _coalesce(existing_project.get("language"), existing_config.get("language"))
802
1883
  if language:
803
1884
  project_data["language"] = language
804
1885
 
@@ -808,9 +1889,7 @@ def _preserve_project_metadata(
808
1889
  # This allows Stage 2 to compare package vs project template versions
809
1890
  project_data["template_version"] = version_for_config
810
1891
 
811
- config_path.write_text(
812
- json.dumps(config_data, indent=2, ensure_ascii=False) + "\n", encoding="utf-8"
813
- )
1892
+ _save_config(config_path, config_data)
814
1893
 
815
1894
 
816
1895
  def _apply_context_to_file(processor: TemplateProcessor, target_path: Path) -> None:
@@ -823,9 +1902,7 @@ def _apply_context_to_file(processor: TemplateProcessor, target_path: Path) -> N
823
1902
  except UnicodeDecodeError:
824
1903
  return
825
1904
 
826
- substituted, warnings = processor._substitute_variables(
827
- content
828
- ) # pylint: disable=protected-access
1905
+ substituted, warnings = processor._substitute_variables(content) # pylint: disable=protected-access
829
1906
  if warnings:
830
1907
  console.print("[yellow]โš  Template warnings:[/yellow]")
831
1908
  for warning in warnings:
@@ -856,28 +1933,20 @@ def _validate_template_substitution(project_path: Path) -> None:
856
1933
  unsubstituted = re.findall(r"\{\{([A-Z_]+)\}\}", content)
857
1934
  if unsubstituted:
858
1935
  unique_vars = sorted(set(unsubstituted))
859
- issues_found.append(
860
- f"{file_path.relative_to(project_path)}: {', '.join(unique_vars)}"
861
- )
1936
+ issues_found.append(f"{file_path.relative_to(project_path)}: {', '.join(unique_vars)}")
862
1937
  except Exception as e:
863
- console.print(
864
- f"[yellow]โš ๏ธ Could not validate {file_path.relative_to(project_path)}: {e}[/yellow]"
865
- )
1938
+ console.print(f"[yellow]โš ๏ธ Could not validate {file_path.relative_to(project_path)}: {e}[/yellow]")
866
1939
 
867
1940
  if issues_found:
868
1941
  console.print("[red]โœ— Template substitution validation failed:[/red]")
869
1942
  for issue in issues_found:
870
1943
  console.print(f" {issue}")
871
- console.print(
872
- "[yellow]๐Ÿ’ก Run '/alfred:0-project' to fix template variables[/yellow]"
873
- )
1944
+ console.print("[yellow]๐Ÿ’ก Run '/moai:0-project' to fix template variables[/yellow]")
874
1945
  else:
875
1946
  console.print("[green]โœ… Template substitution validation passed[/green]")
876
1947
 
877
1948
 
878
- def _validate_template_substitution_with_rollback(
879
- project_path: Path, backup_path: Path | None
880
- ) -> bool:
1949
+ def _validate_template_substitution_with_rollback(project_path: Path, backup_path: Path | None) -> bool:
881
1950
  """Validate template substitution with rollback capability.
882
1951
 
883
1952
  Returns:
@@ -903,13 +1972,9 @@ def _validate_template_substitution_with_rollback(
903
1972
  unsubstituted = re.findall(r"\{\{([A-Z_]+)\}\}", content)
904
1973
  if unsubstituted:
905
1974
  unique_vars = sorted(set(unsubstituted))
906
- issues_found.append(
907
- f"{file_path.relative_to(project_path)}: {', '.join(unique_vars)}"
908
- )
1975
+ issues_found.append(f"{file_path.relative_to(project_path)}: {', '.join(unique_vars)}")
909
1976
  except Exception as e:
910
- console.print(
911
- f"[yellow]โš ๏ธ Could not validate {file_path.relative_to(project_path)}: {e}[/yellow]"
912
- )
1977
+ console.print(f"[yellow]โš ๏ธ Could not validate {file_path.relative_to(project_path)}: {e}[/yellow]")
913
1978
 
914
1979
  if issues_found:
915
1980
  console.print("[red]โœ— Template substitution validation failed:[/red]")
@@ -917,13 +1982,9 @@ def _validate_template_substitution_with_rollback(
917
1982
  console.print(f" {issue}")
918
1983
 
919
1984
  if backup_path:
920
- console.print(
921
- "[yellow]๐Ÿ”„ Rolling back due to validation failure...[/yellow]"
922
- )
1985
+ console.print("[yellow]๐Ÿ”„ Rolling back due to validation failure...[/yellow]")
923
1986
  else:
924
- console.print(
925
- "[yellow]๐Ÿ’ก Run '/alfred:0-project' to fix template variables[/yellow]"
926
- )
1987
+ console.print("[yellow]๐Ÿ’ก Run '/moai:0-project' to fix template variables[/yellow]")
927
1988
  console.print("[red]โš ๏ธ No backup available - manual fix required[/red]")
928
1989
 
929
1990
  return False
@@ -978,18 +2039,14 @@ def _show_network_error_help() -> None:
978
2039
  console.print("Options:")
979
2040
  console.print(" 1. Check network connection")
980
2041
  console.print(" 2. Try again with: [cyan]moai-adk update --force[/cyan]")
981
- console.print(
982
- " 3. Skip version check: [cyan]moai-adk update --templates-only[/cyan]"
983
- )
2042
+ console.print(" 3. Skip version check: [cyan]moai-adk update --templates-only[/cyan]")
984
2043
 
985
2044
 
986
2045
  def _show_template_sync_failure_help() -> None:
987
2046
  """Show help when template sync fails."""
988
2047
  console.print("[yellow]โš ๏ธ Template sync failed[/yellow]\n")
989
2048
  console.print("Rollback options:")
990
- console.print(
991
- " 1. Restore from backup: [cyan]cp -r .moai-backups/TIMESTAMP .moai/[/cyan]"
992
- )
2049
+ console.print(" 1. Restore from backup: [cyan]cp -r .moai-backups/TIMESTAMP .moai/[/cyan]")
993
2050
  console.print(" 2. Skip backup and retry: [cyan]moai-adk update --force[/cyan]")
994
2051
  console.print(" 3. Report issue: https://github.com/modu-ai/moai-adk/issues")
995
2052
 
@@ -1027,24 +2084,17 @@ def _execute_migration_if_needed(project_path: Path, yes: bool = False) -> bool:
1027
2084
  console.print()
1028
2085
  console.print(" This will migrate configuration files to new locations:")
1029
2086
  console.print(" โ€ข .moai/config.json โ†’ .moai/config/config.json")
1030
- console.print(
1031
- " โ€ข .claude/statusline-config.yaml โ†’ .moai/config/statusline-config.yaml"
1032
- )
2087
+ console.print(" โ€ข .claude/statusline-config.yaml โ†’ .moai/config/statusline-config.yaml")
1033
2088
  console.print()
1034
2089
  console.print(" A backup will be created automatically.")
1035
2090
  console.print()
1036
2091
 
1037
2092
  # Confirm with user (unless --yes)
1038
2093
  if not yes:
1039
- if not click.confirm(
1040
- "Do you want to proceed with migration?", default=True
1041
- ):
1042
- console.print(
1043
- "[yellow]โš ๏ธ Migration skipped. Some features may not work correctly.[/yellow]"
1044
- )
1045
- console.print(
1046
- "[cyan]๐Ÿ’ก Run 'moai-adk migrate' manually when ready[/cyan]"
1047
- )
2094
+ reset_stdin() # Reset stdin before interactive prompt
2095
+ if not click.confirm("Do you want to proceed with migration?", default=True):
2096
+ console.print("[yellow]โš ๏ธ Migration skipped. Some features may not work correctly.[/yellow]")
2097
+ console.print("[cyan]๐Ÿ’ก Run 'moai-adk migrate' manually when ready[/cyan]")
1048
2098
  return False
1049
2099
 
1050
2100
  # Execute migration
@@ -1056,9 +2106,7 @@ def _execute_migration_if_needed(project_path: Path, yes: bool = False) -> bool:
1056
2106
  return True
1057
2107
  else:
1058
2108
  console.print("[red]โŒ Migration failed[/red]")
1059
- console.print(
1060
- "[cyan]๐Ÿ’ก Use 'moai-adk migrate --rollback' to restore from backup[/cyan]"
1061
- )
2109
+ console.print("[cyan]๐Ÿ’ก Use 'moai-adk migrate --rollback' to restore from backup[/cyan]")
1062
2110
  return False
1063
2111
 
1064
2112
  except Exception as e:
@@ -1076,14 +2124,29 @@ def _execute_migration_if_needed(project_path: Path, yes: bool = False) -> bool:
1076
2124
  )
1077
2125
  @click.option("--force", is_flag=True, help="Skip backup and force the update")
1078
2126
  @click.option("--check", is_flag=True, help="Only check version (do not update)")
2127
+ @click.option("--templates-only", is_flag=True, help="Skip package upgrade, sync templates only")
2128
+ @click.option("--yes", is_flag=True, help="Auto-confirm all prompts (CI/CD mode)")
1079
2129
  @click.option(
1080
- "--templates-only", is_flag=True, help="Skip package upgrade, sync templates only"
2130
+ "--merge",
2131
+ "merge_strategy",
2132
+ flag_value="auto",
2133
+ help="Auto-merge: Apply template + preserve user changes",
2134
+ )
2135
+ @click.option(
2136
+ "--manual",
2137
+ "merge_strategy",
2138
+ flag_value="manual",
2139
+ help="Manual merge: Preserve backup, generate merge guide",
1081
2140
  )
1082
- @click.option("--yes", is_flag=True, help="Auto-confirm all prompts (CI/CD mode)")
1083
2141
  def update(
1084
- path: str, force: bool, check: bool, templates_only: bool, yes: bool
2142
+ path: str,
2143
+ force: bool,
2144
+ check: bool,
2145
+ templates_only: bool,
2146
+ yes: bool,
2147
+ merge_strategy: str | None,
1085
2148
  ) -> None:
1086
- """Update command with 3-stage workflow (v0.6.3+).
2149
+ """Update command with 3-stage workflow + merge strategy selection (v0.26.0+).
1087
2150
 
1088
2151
  Stage 1 (Package Version Check):
1089
2152
  - Fetches current and latest versions from PyPI
@@ -1095,18 +2158,34 @@ def update(
1095
2158
  - If versions match: skips Stage 3 (already up-to-date)
1096
2159
  - Performance improvement: 70-80% faster for unchanged projects (3-4s vs 12-18s)
1097
2160
 
1098
- Stage 3 (Template Sync):
2161
+ Stage 3 (Template Sync with Merge Strategy - NEW in v0.26.0):
1099
2162
  - Syncs templates only if versions differ
2163
+ - User chooses merge strategy:
2164
+ * Auto-merge (default): Template + preserved user changes
2165
+ * Manual merge: Backup + comprehensive merge guide (full control)
1100
2166
  - Updates .claude/, .moai/, CLAUDE.md, config.json
1101
2167
  - Preserves specs and reports
1102
2168
  - Saves new template_version to config.json
1103
2169
 
1104
2170
  Examples:
1105
- python -m moai_adk update # auto 3-stage workflow
1106
- python -m moai_adk update --force # force template sync
2171
+ python -m moai_adk update # interactive merge strategy selection
2172
+ python -m moai_adk update --merge # auto-merge (template + user changes)
2173
+ python -m moai_adk update --manual # manual merge (backup + guide)
2174
+ python -m moai_adk update --force # force template sync (no backup)
1107
2175
  python -m moai_adk update --check # check version only
1108
2176
  python -m moai_adk update --templates-only # skip package upgrade
1109
- python -m moai_adk update --yes # CI/CD mode (auto-confirm)
2177
+ python -m moai_adk update --yes # CI/CD mode (auto-confirm + auto-merge)
2178
+
2179
+ Merge Strategies:
2180
+ --merge: Auto-merge applies template + preserves your changes (default)
2181
+ Generated files: backup, merge report
2182
+ --manual: Manual merge preserves backup + generates comprehensive guide
2183
+ Generated files: backup, merge guide
2184
+
2185
+ Generated Files:
2186
+ - Backup: .moai-backups/pre-update-backup_{timestamp}/
2187
+ - Report: .moai/reports/merge-report.md (auto-merge only)
2188
+ - Guide: .moai/guides/merge-guide.md (manual merge only)
1110
2189
  """
1111
2190
  try:
1112
2191
  project_path = Path(path).resolve()
@@ -1120,14 +2199,24 @@ def update(
1120
2199
  # Note: If --check is used, always fetch versions even if --templates-only is also present
1121
2200
  if check or not templates_only:
1122
2201
  try:
1123
- current = _get_current_version()
1124
- latest = _get_latest_version()
2202
+ # Try to use new spinner UI
2203
+ try:
2204
+ from moai_adk.cli.ui.progress import SpinnerContext
2205
+
2206
+ with SpinnerContext("Checking for updates...") as spinner:
2207
+ current = _get_current_version()
2208
+ spinner.update("Fetching latest version from PyPI...")
2209
+ latest = _get_latest_version()
2210
+ spinner.success("Version check complete")
2211
+ except ImportError:
2212
+ # Fallback to simple console output
2213
+ console.print("[dim]Checking for updates...[/dim]")
2214
+ current = _get_current_version()
2215
+ latest = _get_latest_version()
1125
2216
  except RuntimeError as e:
1126
2217
  console.print(f"[red]Error: {e}[/red]")
1127
2218
  if not force:
1128
- console.print(
1129
- "[yellow]โš  Cannot check for updates. Use --force to update anyway.[/yellow]"
1130
- )
2219
+ console.print("[yellow]โš  Cannot check for updates. Use --force to update anyway.[/yellow]")
1131
2220
  raise click.Abort()
1132
2221
  # With --force, proceed to Stage 2 even if version check fails
1133
2222
  current = __version__
@@ -1139,23 +2228,24 @@ def update(
1139
2228
  if check:
1140
2229
  comparison = _compare_versions(current, latest)
1141
2230
  if comparison < 0:
1142
- console.print(
1143
- f"\n[yellow]๐Ÿ“ฆ Update available: {current} โ†’ {latest}[/yellow]"
1144
- )
2231
+ console.print(f"\n[yellow]๐Ÿ“ฆ Update available: {current} โ†’ {latest}[/yellow]")
1145
2232
  console.print(" Run 'moai-adk update' to upgrade")
1146
2233
  elif comparison == 0:
1147
2234
  console.print(f"[green]โœ“ Already up to date ({current})[/green]")
1148
2235
  else:
1149
- console.print(
1150
- f"[cyan]โ„น๏ธ Dev version: {current} (latest: {latest})[/cyan]"
1151
- )
2236
+ console.print(f"[cyan]โ„น๏ธ Dev version: {current} (latest: {latest})[/cyan]")
1152
2237
  return
1153
2238
 
1154
2239
  # Step 2: Handle --templates-only (skip upgrade, go straight to sync)
1155
2240
  if templates_only:
1156
2241
  console.print("[cyan]๐Ÿ“„ Syncing templates only...[/cyan]")
2242
+
2243
+ # Preserve user-specific settings before sync
2244
+ console.print(" [cyan]๐Ÿ’พ Preserving user settings...[/cyan]")
2245
+ preserved_settings = _preserve_user_settings(project_path)
2246
+
1157
2247
  try:
1158
- if not _sync_templates(project_path, force):
2248
+ if not _sync_templates(project_path, force, yes):
1159
2249
  raise TemplateSyncError("Template sync returned False")
1160
2250
  except TemplateSyncError:
1161
2251
  console.print("[red]Error: Template sync failed[/red]")
@@ -1166,10 +2256,11 @@ def update(
1166
2256
  _show_template_sync_failure_help()
1167
2257
  raise click.Abort()
1168
2258
 
2259
+ # Restore user-specific settings after sync
2260
+ _restore_user_settings(project_path, preserved_settings)
2261
+
1169
2262
  console.print(" [green]โœ… .claude/ update complete[/green]")
1170
- console.print(
1171
- " [green]โœ… .moai/ update complete (specs/reports preserved)[/green]"
1172
- )
2263
+ console.print(" [green]โœ… .moai/ update complete (specs/reports preserved)[/green]")
1173
2264
  console.print(" [green]๐Ÿ”„ CLAUDE.md merge complete[/green]")
1174
2265
  console.print(" [green]๐Ÿ”„ config.json merge complete[/green]")
1175
2266
  console.print("\n[green]โœ“ Template sync complete![/green]")
@@ -1184,6 +2275,7 @@ def update(
1184
2275
 
1185
2276
  # Confirm upgrade (unless --yes)
1186
2277
  if not yes:
2278
+ reset_stdin() # Reset stdin before interactive prompt
1187
2279
  if not click.confirm(f"Upgrade {current} โ†’ {latest}?", default=True):
1188
2280
  console.print("Cancelled")
1189
2281
  return
@@ -1204,9 +2296,7 @@ def update(
1204
2296
  try:
1205
2297
  upgrade_result = _execute_upgrade(installer_cmd)
1206
2298
  if not upgrade_result:
1207
- raise UpgradeError(
1208
- f"Upgrade command failed: {' '.join(installer_cmd)}"
1209
- )
2299
+ raise UpgradeError(f"Upgrade command failed: {' '.join(installer_cmd)}")
1210
2300
  except subprocess.TimeoutExpired:
1211
2301
  _show_timeout_error_help()
1212
2302
  raise click.Abort()
@@ -1216,9 +2306,7 @@ def update(
1216
2306
 
1217
2307
  # Prompt re-run
1218
2308
  console.print("\n[green]โœ“ Upgrade complete![/green]")
1219
- console.print(
1220
- "[cyan]๐Ÿ“ข Run 'moai-adk update' again to sync templates[/cyan]"
1221
- )
2309
+ console.print("[cyan]๐Ÿ“ข Run 'moai-adk update' again to sync templates[/cyan]")
1222
2310
  return
1223
2311
 
1224
2312
  # Stage 1.5: Migration Check (NEW in v0.24.0)
@@ -1227,9 +2315,12 @@ def update(
1227
2315
  # Execute migration if needed
1228
2316
  if not _execute_migration_if_needed(project_path, yes):
1229
2317
  console.print("[yellow]โš ๏ธ Update continuing without migration[/yellow]")
1230
- console.print(
1231
- "[cyan]๐Ÿ’ก Some features may require migration to work correctly[/cyan]"
1232
- )
2318
+ console.print("[cyan]๐Ÿ’ก Some features may require migration to work correctly[/cyan]")
2319
+
2320
+ # Migrate config.json โ†’ config.yaml (v0.32.0+)
2321
+ console.print("\n[cyan]๐Ÿ” Checking for config format migration...[/cyan]")
2322
+ if not _migrate_config_json_to_yaml(project_path):
2323
+ console.print("[yellow]โš ๏ธ Config migration failed, continuing with existing format[/yellow]")
1233
2324
 
1234
2325
  # Stage 2: Config Version Comparison
1235
2326
  try:
@@ -1246,32 +2337,66 @@ def update(
1246
2337
  console.print(f" Project config: {project_config_version}")
1247
2338
 
1248
2339
  try:
1249
- config_comparison = _compare_versions(
1250
- package_config_version, project_config_version
1251
- )
2340
+ config_comparison = _compare_versions(package_config_version, project_config_version)
1252
2341
  except version.InvalidVersion as e:
1253
2342
  # Handle invalid version strings (e.g., unsubstituted template placeholders, corrupted configs)
1254
2343
  console.print(f"[yellow]โš  Invalid version format in config: {e}[/yellow]")
1255
- console.print(
1256
- "[cyan]โ„น๏ธ Forcing template sync to repair configuration...[/cyan]"
1257
- )
2344
+ console.print("[cyan]โ„น๏ธ Forcing template sync to repair configuration...[/cyan]")
1258
2345
  # Force template sync by treating project version as outdated
1259
2346
  config_comparison = 1 # package_config_version > project_config_version
1260
2347
 
1261
2348
  # If versions are equal, no sync needed
1262
2349
  if config_comparison <= 0:
1263
- console.print(
1264
- f"\n[green]โœ“ Project already has latest template version ({project_config_version})[/green]"
1265
- )
1266
- console.print(
1267
- "[cyan]โ„น๏ธ Templates are up to date! No changes needed.[/cyan]"
1268
- )
2350
+ console.print(f"\n[green]โœ“ Project already has latest template version ({project_config_version})[/green]")
2351
+ console.print("[cyan]โ„น๏ธ Templates are up to date! No changes needed.[/cyan]")
1269
2352
  return
1270
2353
 
1271
2354
  # Stage 3: Template Sync (Only if package_config_version > project_config_version)
1272
- console.print(
1273
- f"\n[cyan]๐Ÿ“„ Syncing templates ({project_config_version} โ†’ {package_config_version})...[/cyan]"
1274
- )
2355
+ console.print(f"\n[cyan]๐Ÿ“„ Syncing templates ({project_config_version} โ†’ {package_config_version})...[/cyan]")
2356
+
2357
+ # Determine merge strategy (default: auto-merge)
2358
+ final_merge_strategy = merge_strategy or "auto"
2359
+
2360
+ # Handle merge strategy
2361
+ if final_merge_strategy == "manual":
2362
+ # Manual merge mode: Create full backup + generate guide, no template sync
2363
+ console.print("\n[cyan]๐Ÿ”€ Manual merge mode selected[/cyan]")
2364
+
2365
+ # Create full project backup
2366
+ console.print(" [cyan]๐Ÿ’พ Creating full project backup...[/cyan]")
2367
+ try:
2368
+ from moai_adk.core.migration.backup_manager import BackupManager
2369
+
2370
+ backup_manager = BackupManager(project_path)
2371
+ full_backup_path = backup_manager.create_full_project_backup(description="pre-update-backup")
2372
+ console.print(f" [green]โœ“ Backup: {full_backup_path.relative_to(project_path)}/[/green]")
2373
+
2374
+ # Generate merge guide
2375
+ console.print(" [cyan]๐Ÿ“‹ Generating merge guide...[/cyan]")
2376
+ template_path = Path(__file__).parent.parent.parent / "templates"
2377
+ guide_path = _generate_manual_merge_guide(full_backup_path, template_path, project_path)
2378
+ console.print(f" [green]โœ“ Guide: {guide_path.relative_to(project_path)}[/green]")
2379
+
2380
+ # Summary
2381
+ console.print("\n[green]โœ“ Manual merge setup complete![/green]")
2382
+ console.print(f"[cyan]๐Ÿ“ Backup location: {full_backup_path.relative_to(project_path)}/[/cyan]")
2383
+ console.print(f"[cyan]๐Ÿ“‹ Merge guide: {guide_path.relative_to(project_path)}[/cyan]")
2384
+ console.print("\n[yellow]โš ๏ธ Next steps:[/yellow]")
2385
+ console.print("[yellow] 1. Review the merge guide[/yellow]")
2386
+ console.print("[yellow] 2. Compare files using diff or visual tools[/yellow]")
2387
+ console.print("[yellow] 3. Manually merge your customizations[/yellow]")
2388
+ console.print("[yellow] 4. Test and commit changes[/yellow]")
2389
+
2390
+ except Exception as e:
2391
+ console.print(f"[red]Error: Manual merge setup failed - {e}[/red]")
2392
+ raise click.Abort()
2393
+
2394
+ return
2395
+
2396
+ # Auto merge mode: Preserve user-specific settings before sync
2397
+ console.print("\n[cyan]๐Ÿ”€ Auto-merge mode selected[/cyan]")
2398
+ console.print(" [cyan]๐Ÿ’พ Preserving user settings...[/cyan]")
2399
+ preserved_settings = _preserve_user_settings(project_path)
1275
2400
 
1276
2401
  # Create backup unless --force
1277
2402
  if not force:
@@ -1279,19 +2404,21 @@ def update(
1279
2404
  try:
1280
2405
  processor = TemplateProcessor(project_path)
1281
2406
  backup_path = processor.create_backup()
1282
- console.print(
1283
- f" [green]โœ“ Backup: {backup_path.relative_to(project_path)}/[/green]"
1284
- )
2407
+ console.print(f" [green]โœ“ Backup: {backup_path.relative_to(project_path)}/[/green]")
1285
2408
  except Exception as e:
1286
2409
  console.print(f" [yellow]โš  Backup failed: {e}[/yellow]")
1287
2410
  console.print(" [yellow]โš  Continuing without backup...[/yellow]")
1288
2411
  else:
1289
2412
  console.print(" [yellow]โš  Skipping backup (--force)[/yellow]")
1290
2413
 
1291
- # Sync templates
2414
+ # Sync templates (NO spinner - user interaction may be required)
2415
+ # SpinnerContext blocks stdin, causing hang when click.confirm() is called
1292
2416
  try:
1293
- if not _sync_templates(project_path, force):
2417
+ console.print(" [cyan]Syncing templates...[/cyan]")
2418
+ if not _sync_templates(project_path, force, yes):
1294
2419
  raise TemplateSyncError("Template sync returned False")
2420
+ _restore_user_settings(project_path, preserved_settings)
2421
+ console.print(" [green]โœ“ Template sync complete[/green]")
1295
2422
  except TemplateSyncError:
1296
2423
  console.print("[red]Error: Template sync failed[/red]")
1297
2424
  _show_template_sync_failure_help()
@@ -1302,20 +2429,263 @@ def update(
1302
2429
  raise click.Abort()
1303
2430
 
1304
2431
  console.print(" [green]โœ… .claude/ update complete[/green]")
1305
- console.print(
1306
- " [green]โœ… .moai/ update complete (specs/reports preserved)[/green]"
1307
- )
2432
+ console.print(" [green]โœ… .moai/ update complete (specs/reports preserved)[/green]")
1308
2433
  console.print(" [green]๐Ÿ”„ CLAUDE.md merge complete[/green]")
1309
2434
  console.print(" [green]๐Ÿ”„ config.json merge complete[/green]")
1310
- console.print(
1311
- " [yellow]โš™๏ธ Set optimized=false (optimization needed)[/yellow]"
1312
- )
2435
+ console.print(" [yellow]โš™๏ธ Set optimized=false (optimization needed)[/yellow]")
1313
2436
 
1314
2437
  console.print("\n[green]โœ“ Update complete![/green]")
1315
- console.print(
1316
- "[cyan]โ„น๏ธ Next step: Run /alfred:0-project update to optimize template changes[/cyan]"
1317
- )
2438
+ console.print("[cyan]โ„น๏ธ Next step: Run /moai:0-project update to optimize template changes[/cyan]")
1318
2439
 
1319
2440
  except Exception as e:
1320
2441
  console.print(f"[red]โœ— Update failed: {e}[/red]")
1321
2442
  raise click.ClickException(str(e)) from e
2443
+
2444
+
2445
+ def _handle_custom_element_restoration(project_path: Path, backup_path: Path | None, yes: bool = False) -> None:
2446
+ """Handle custom element restoration using the enhanced system.
2447
+
2448
+ This function provides an improved interface for restoring user-created custom elements
2449
+ (agents, commands, skills, hooks) from backup during MoAI-ADK updates.
2450
+
2451
+ Key improvements:
2452
+ - Preserves unselected elements (fixes disappearing issue)
2453
+ - Only overwrites/creates selected elements from backup
2454
+ - Interactive checkbox selection with arrow key navigation
2455
+ - Includes all categories (Agents, Commands, Skills, Hooks)
2456
+
2457
+ Args:
2458
+ project_path: Path to the MoAI-ADK project directory
2459
+ backup_path: Path to the backup directory (None if no backup)
2460
+ yes: Whether to automatically accept defaults (non-interactive mode)
2461
+ """
2462
+ if not backup_path:
2463
+ # No backup available, cannot restore
2464
+ return
2465
+
2466
+ try:
2467
+ # Create scanner to find custom elements in backup (not current project)
2468
+ backup_scanner = create_custom_element_scanner(backup_path)
2469
+
2470
+ # Get count of custom elements in backup
2471
+ backup_element_count = backup_scanner.get_element_count()
2472
+
2473
+ if backup_element_count == 0:
2474
+ # No custom elements found in backup
2475
+ console.print("[green]โœ“ No custom elements found in backup to restore[/green]")
2476
+ return
2477
+
2478
+ # Create enhanced user selection UI
2479
+ # IMPORTANT: Use backup_path, not project_path!
2480
+ # At this point, custom elements in project have been deleted by copy_templates().
2481
+ # The UI must scan the BACKUP to find elements available for restoration.
2482
+ ui = create_user_selection_ui(backup_path)
2483
+
2484
+ console.print(f"\n[cyan]๐Ÿ” Found {backup_element_count} custom elements in backup[/cyan]")
2485
+
2486
+ # If yes mode is enabled, restore all elements automatically
2487
+ if yes:
2488
+ console.print(f"[cyan]๐Ÿ”„ Auto-restoring {backup_element_count} custom elements...[/cyan]")
2489
+ backup_custom_elements = backup_scanner.scan_custom_elements()
2490
+ selected_elements = []
2491
+
2492
+ # Collect all element paths from backup
2493
+ for element_type, elements in backup_custom_elements.items():
2494
+ if element_type == "skills":
2495
+ for skill in elements:
2496
+ selected_elements.append(str(skill.path))
2497
+ else:
2498
+ for element_path in elements:
2499
+ selected_elements.append(str(element_path))
2500
+ else:
2501
+ # Interactive mode - prompt user for selection using enhanced UI
2502
+ selected_elements = ui.prompt_user_selection(backup_available=True)
2503
+
2504
+ if not selected_elements:
2505
+ console.print("[yellow]โš  No elements selected for restoration[/yellow]")
2506
+ console.print("[green]โœ“ All existing custom elements will be preserved[/green]")
2507
+ return
2508
+
2509
+ # Confirm selection
2510
+ if not ui.confirm_selection(selected_elements):
2511
+ console.print("[yellow]โš  Restoration cancelled by user[/yellow]")
2512
+ console.print("[green]โœ“ All existing custom elements will be preserved[/green]")
2513
+ return
2514
+
2515
+ # Perform selective restoration - ONLY restore selected elements
2516
+ if selected_elements:
2517
+ console.print(f"[cyan]๐Ÿ”„ Restoring {len(selected_elements)} selected elements from backup...[/cyan]")
2518
+ restorer = create_selective_restorer(project_path, backup_path)
2519
+ success, stats = restorer.restore_elements(selected_elements)
2520
+
2521
+ if success:
2522
+ console.print(f"[green]โœ… Successfully restored {stats['success']} custom elements[/green]")
2523
+ console.print("[green]โœ“ All unselected elements remain preserved[/green]")
2524
+ else:
2525
+ console.print(f"[yellow]โš ๏ธ Partial restoration: {stats['success']}/{stats['total']} elements[/yellow]")
2526
+ if stats["failed"] > 0:
2527
+ console.print(f"[red]โŒ Failed to restore {stats['failed']} elements[/red]")
2528
+ console.print("[yellow]โš ๏ธ All other elements remain preserved[/yellow]")
2529
+ else:
2530
+ console.print("[green]โœ“ No elements selected, all custom elements preserved[/green]")
2531
+
2532
+ except Exception as e:
2533
+ console.print(f"[yellow]โš ๏ธ Custom element restoration failed: {e}[/yellow]")
2534
+ logger.warning(f"Custom element restoration error: {e}")
2535
+ console.print("[yellow]โš ๏ธ All existing custom elements remain as-is[/yellow]")
2536
+ # Don't fail the entire update process, just log the error
2537
+ pass
2538
+
2539
+
2540
+ def _cleanup_legacy_presets(project_path: Path) -> None:
2541
+ """Remove legacy presets directory entirely.
2542
+
2543
+ This function removes the entire .moai/config/presets/ directory as it is
2544
+ no longer used. All preset settings are now consolidated in sections/git-strategy.yaml.
2545
+
2546
+ Args:
2547
+ project_path: Project directory path (absolute)
2548
+ """
2549
+ import shutil
2550
+
2551
+ presets_dir = project_path / ".moai" / "config" / "presets"
2552
+
2553
+ if not presets_dir.exists() or not presets_dir.is_dir():
2554
+ return
2555
+
2556
+ try:
2557
+ # Remove entire presets directory (no longer needed)
2558
+ shutil.rmtree(presets_dir)
2559
+ console.print(" [cyan]๐Ÿงน Removed legacy presets directory (now in sections/git-strategy.yaml)[/cyan]")
2560
+ logger.info(f"Removed legacy presets directory: {presets_dir}")
2561
+ except Exception as e:
2562
+ logger.warning(f"Failed to remove legacy presets directory {presets_dir}: {e}")
2563
+
2564
+
2565
+ def _migrate_config_json_to_yaml(project_path: Path) -> bool:
2566
+ """Migrate legacy config.json to config.yaml format.
2567
+
2568
+ This function:
2569
+ 1. Checks if config.json exists
2570
+ 2. Converts it to config.yaml using YAML format
2571
+ 3. Removes the old config.json file
2572
+ 4. Also migrates preset files from JSON to YAML
2573
+
2574
+ Args:
2575
+ project_path: Project directory path (absolute)
2576
+
2577
+ Returns:
2578
+ bool: True if migration successful or not needed, False on error
2579
+ """
2580
+ try:
2581
+ import yaml
2582
+ except ImportError:
2583
+ console.print(" [yellow]โš ๏ธ PyYAML not available, skipping config migration[/yellow]")
2584
+ return True # Not a critical error
2585
+
2586
+ config_dir = project_path / ".moai" / "config"
2587
+ json_path = config_dir / "config.json"
2588
+ yaml_path = config_dir / "config.yaml"
2589
+
2590
+ # Check if migration needed
2591
+ if not json_path.exists():
2592
+ # No JSON file, migration not needed
2593
+ return True
2594
+
2595
+ if yaml_path.exists():
2596
+ # YAML already exists, just remove JSON
2597
+ try:
2598
+ json_path.unlink()
2599
+ console.print(" [cyan]๐Ÿ”„ Removed legacy config.json (YAML version exists)[/cyan]")
2600
+ logger.info(f"Removed legacy config.json: {json_path}")
2601
+ return True
2602
+ except Exception as e:
2603
+ console.print(f" [yellow]โš ๏ธ Failed to remove legacy config.json: {e}[/yellow]")
2604
+ logger.warning(f"Failed to remove {json_path}: {e}")
2605
+ return True # Not critical
2606
+
2607
+ # Perform migration
2608
+ try:
2609
+ # Read JSON config
2610
+ with open(json_path, "r", encoding="utf-8") as f:
2611
+ config_data = json.load(f)
2612
+
2613
+ # Write YAML config
2614
+ with open(yaml_path, "w", encoding="utf-8") as f:
2615
+ yaml.safe_dump(
2616
+ config_data,
2617
+ f,
2618
+ default_flow_style=False,
2619
+ allow_unicode=True,
2620
+ sort_keys=False,
2621
+ )
2622
+
2623
+ # Remove old JSON file
2624
+ json_path.unlink()
2625
+
2626
+ console.print(" [green]โœ“ Migrated config.json โ†’ config.yaml[/green]")
2627
+ logger.info(f"Migrated config from JSON to YAML: {json_path} โ†’ {yaml_path}")
2628
+
2629
+ # Migrate preset files if they exist
2630
+ _migrate_preset_files_to_yaml(config_dir)
2631
+
2632
+ return True
2633
+
2634
+ except Exception as e:
2635
+ console.print(f" [red]โœ— Config migration failed: {e}[/red]")
2636
+ logger.error(f"Failed to migrate config.json to YAML: {e}")
2637
+ return False
2638
+
2639
+
2640
+ def _migrate_preset_files_to_yaml(config_dir: Path) -> None:
2641
+ """Migrate preset files from JSON to YAML format.
2642
+
2643
+ Args:
2644
+ config_dir: .moai/config directory path
2645
+ """
2646
+ try:
2647
+ import yaml
2648
+ except ImportError:
2649
+ return
2650
+
2651
+ presets_dir = config_dir / "presets"
2652
+ if not presets_dir.exists():
2653
+ return
2654
+
2655
+ migrated_count = 0
2656
+ for json_file in presets_dir.glob("*.json"):
2657
+ yaml_file = json_file.with_suffix(".yaml")
2658
+
2659
+ # Skip if YAML already exists
2660
+ if yaml_file.exists():
2661
+ # Just remove the JSON file
2662
+ try:
2663
+ json_file.unlink()
2664
+ migrated_count += 1
2665
+ except Exception as e:
2666
+ logger.warning(f"Failed to remove {json_file}: {e}")
2667
+ continue
2668
+
2669
+ # Migrate JSON โ†’ YAML
2670
+ try:
2671
+ with open(json_file, "r", encoding="utf-8") as f:
2672
+ preset_data = json.load(f)
2673
+
2674
+ with open(yaml_file, "w", encoding="utf-8") as f:
2675
+ yaml.safe_dump(
2676
+ preset_data,
2677
+ f,
2678
+ default_flow_style=False,
2679
+ allow_unicode=True,
2680
+ sort_keys=False,
2681
+ )
2682
+
2683
+ json_file.unlink()
2684
+ migrated_count += 1
2685
+
2686
+ except Exception as e:
2687
+ logger.warning(f"Failed to migrate preset {json_file}: {e}")
2688
+
2689
+ if migrated_count > 0:
2690
+ console.print(f" [cyan]๐Ÿ”„ Migrated {migrated_count} preset file(s) to YAML[/cyan]")
2691
+ logger.info(f"Migrated {migrated_count} preset files to YAML")