moai-adk 0.34.0__py3-none-any.whl → 1.1.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.
- moai_adk/__main__.py +136 -5
- moai_adk/astgrep/__init__.py +37 -0
- moai_adk/astgrep/analyzer.py +522 -0
- moai_adk/astgrep/models.py +124 -0
- moai_adk/astgrep/rules.py +179 -0
- moai_adk/cli/commands/analyze.py +11 -2
- moai_adk/cli/commands/doctor.py +7 -1
- moai_adk/cli/commands/init.py +321 -11
- moai_adk/cli/commands/language.py +7 -1
- moai_adk/cli/commands/rank.py +449 -0
- moai_adk/cli/commands/status.py +7 -1
- moai_adk/cli/commands/switch.py +325 -0
- moai_adk/cli/commands/update.py +296 -23
- moai_adk/cli/prompts/init_prompts.py +362 -66
- moai_adk/cli/prompts/translations/__init__.py +573 -0
- moai_adk/cli/ui/prompts.py +61 -2
- moai_adk/cli/worktree/cli.py +106 -1
- moai_adk/cli/worktree/manager.py +155 -0
- moai_adk/core/config/unified.py +244 -63
- moai_adk/core/credentials.py +264 -0
- moai_adk/core/error_recovery_system.py +22 -4
- moai_adk/core/git/conflict_detector.py +10 -1
- moai_adk/core/git/event_detector.py +16 -5
- moai_adk/core/integration/engine.py +2 -2
- moai_adk/core/integration/integration_tester.py +5 -5
- moai_adk/core/language_config_resolver.py +9 -3
- moai_adk/core/merge/analyzer.py +509 -324
- moai_adk/core/migration/alfred_to_moai_migrator.py +7 -1
- moai_adk/core/migration/backup_manager.py +54 -4
- moai_adk/core/migration/file_migrator.py +174 -2
- moai_adk/core/migration/interactive_checkbox_ui.py +42 -31
- moai_adk/core/migration/version_detector.py +123 -19
- moai_adk/core/migration/version_migrator.py +44 -9
- moai_adk/core/model_allocator.py +241 -0
- moai_adk/core/project/backup_utils.py +12 -2
- moai_adk/core/project/initializer.py +44 -87
- moai_adk/core/project/phase_executor.py +95 -33
- moai_adk/core/project/validator.py +16 -1
- moai_adk/core/quality/trust_checker.py +30 -10
- moai_adk/core/rollback_manager.py +60 -25
- moai_adk/core/template/backup.py +88 -6
- moai_adk/core/template/config.py +33 -9
- moai_adk/core/template/merger.py +34 -8
- moai_adk/core/template/processor.py +334 -11
- moai_adk/core/template_engine.py +10 -1
- moai_adk/core/template_variable_synchronizer.py +16 -2
- moai_adk/core/version_sync.py +54 -6
- moai_adk/foundation/__init__.py +1 -20
- moai_adk/foundation/testing.py +1 -1
- moai_adk/loop/__init__.py +54 -0
- moai_adk/loop/controller.py +305 -0
- moai_adk/loop/feedback.py +230 -0
- moai_adk/loop/state.py +209 -0
- moai_adk/loop/storage.py +220 -0
- moai_adk/lsp/__init__.py +70 -0
- moai_adk/lsp/client.py +320 -0
- moai_adk/lsp/models.py +261 -0
- moai_adk/lsp/protocol.py +404 -0
- moai_adk/lsp/server_manager.py +248 -0
- moai_adk/project/configuration.py +8 -1
- moai_adk/py.typed +0 -0
- moai_adk/ralph/__init__.py +37 -0
- moai_adk/ralph/engine.py +307 -0
- moai_adk/rank/__init__.py +21 -0
- moai_adk/rank/auth.py +425 -0
- moai_adk/rank/client.py +557 -0
- moai_adk/rank/config.py +147 -0
- moai_adk/rank/hook.py +1503 -0
- moai_adk/rank/py.typed +0 -0
- moai_adk/statusline/__init__.py +3 -0
- moai_adk/statusline/enhanced_output_style_detector.py +5 -5
- moai_adk/statusline/main.py +20 -1
- moai_adk/statusline/memory_collector.py +268 -0
- moai_adk/statusline/renderer.py +54 -38
- moai_adk/tag_system/__init__.py +48 -0
- moai_adk/tag_system/atomic_ops.py +117 -0
- moai_adk/tag_system/linkage.py +335 -0
- moai_adk/tag_system/parser.py +176 -0
- moai_adk/tag_system/validator.py +200 -0
- moai_adk/templates/.claude/agents/moai/builder-agent.md +19 -3
- moai_adk/templates/.claude/agents/moai/builder-command.md +62 -16
- moai_adk/templates/.claude/agents/moai/builder-plugin.md +763 -0
- moai_adk/templates/.claude/agents/moai/builder-skill.md +21 -5
- moai_adk/templates/.claude/agents/moai/expert-backend.md +103 -39
- moai_adk/templates/.claude/agents/moai/expert-debug.md +9 -3
- moai_adk/templates/.claude/agents/moai/expert-devops.md +16 -14
- moai_adk/templates/.claude/agents/moai/expert-frontend.md +45 -31
- moai_adk/templates/.claude/agents/moai/expert-performance.md +13 -9
- moai_adk/templates/.claude/agents/moai/expert-refactoring.md +228 -0
- moai_adk/templates/.claude/agents/moai/expert-security.md +19 -3
- moai_adk/templates/.claude/agents/moai/expert-testing.md +13 -9
- moai_adk/templates/.claude/agents/moai/manager-claude-code.md +8 -2
- moai_adk/templates/.claude/agents/moai/manager-docs.md +10 -5
- moai_adk/templates/.claude/agents/moai/manager-git.md +99 -27
- moai_adk/templates/.claude/agents/moai/manager-project.md +87 -7
- moai_adk/templates/.claude/agents/moai/manager-quality.md +22 -5
- moai_adk/templates/.claude/agents/moai/manager-spec.md +8 -2
- moai_adk/templates/.claude/agents/moai/manager-strategy.md +45 -14
- moai_adk/templates/.claude/agents/moai/manager-tdd.md +16 -3
- moai_adk/templates/.claude/commands/moai/0-project.md +239 -1185
- moai_adk/templates/.claude/commands/moai/1-plan.md +383 -363
- moai_adk/templates/.claude/commands/moai/2-run.md +254 -347
- moai_adk/templates/.claude/commands/moai/3-sync.md +174 -100
- moai_adk/templates/.claude/commands/moai/9-feedback.md +49 -33
- moai_adk/templates/.claude/commands/moai/alfred.md +339 -0
- moai_adk/templates/.claude/commands/moai/cancel-loop.md +163 -0
- moai_adk/templates/.claude/commands/moai/fix.md +264 -0
- moai_adk/templates/.claude/commands/moai/loop.md +363 -0
- moai_adk/templates/.claude/hooks/moai/lib/README.md +143 -0
- moai_adk/templates/.claude/hooks/moai/lib/__init__.py +37 -81
- moai_adk/templates/.claude/hooks/moai/lib/alfred_detector.py +105 -0
- moai_adk/templates/.claude/hooks/moai/lib/atomic_write.py +122 -0
- moai_adk/templates/.claude/hooks/moai/lib/checkpoint.py +4 -1
- moai_adk/templates/.claude/hooks/moai/lib/common.py +35 -5
- moai_adk/templates/.claude/hooks/moai/lib/config.py +376 -0
- moai_adk/templates/.claude/hooks/moai/lib/config_manager.py +24 -28
- moai_adk/templates/.claude/hooks/moai/lib/config_validator.py +14 -14
- moai_adk/templates/.claude/hooks/moai/lib/enhanced_output_style_detector.py +372 -0
- moai_adk/templates/.claude/hooks/moai/lib/exceptions.py +171 -0
- moai_adk/templates/.claude/hooks/moai/lib/file_utils.py +95 -0
- moai_adk/templates/.claude/hooks/moai/lib/git_collector.py +190 -0
- moai_adk/templates/.claude/hooks/moai/lib/git_operations_manager.py +15 -13
- moai_adk/templates/.claude/hooks/moai/lib/language_detector.py +298 -0
- moai_adk/templates/.claude/hooks/moai/lib/language_validator.py +125 -25
- moai_adk/templates/.claude/hooks/moai/lib/main.py +341 -0
- moai_adk/templates/.claude/hooks/moai/lib/memory_collector.py +268 -0
- moai_adk/templates/.claude/hooks/moai/lib/metrics_tracker.py +78 -0
- moai_adk/templates/.claude/hooks/moai/lib/models.py +9 -7
- moai_adk/templates/.claude/hooks/moai/lib/path_utils.py +204 -13
- moai_adk/templates/.claude/hooks/moai/lib/project.py +23 -14
- moai_adk/templates/.claude/hooks/moai/lib/renderer.py +359 -0
- moai_adk/templates/.claude/hooks/moai/lib/tag_linkage.py +333 -0
- moai_adk/templates/.claude/hooks/moai/lib/tag_parser.py +176 -0
- moai_adk/templates/.claude/hooks/moai/lib/tag_validator.py +200 -0
- moai_adk/templates/.claude/hooks/moai/lib/timeout.py +5 -5
- moai_adk/templates/.claude/hooks/moai/lib/tool_registry.py +896 -0
- moai_adk/templates/.claude/hooks/moai/lib/unified_timeout_manager.py +30 -18
- moai_adk/templates/.claude/hooks/moai/lib/update_checker.py +129 -0
- moai_adk/templates/.claude/hooks/moai/lib/version_reader.py +741 -0
- moai_adk/templates/.claude/hooks/moai/post_tool__ast_grep_scan.py +276 -0
- moai_adk/templates/.claude/hooks/moai/post_tool__code_formatter.py +255 -0
- moai_adk/templates/.claude/hooks/moai/post_tool__coverage_guard.py +325 -0
- moai_adk/templates/.claude/hooks/moai/post_tool__linter.py +315 -0
- moai_adk/templates/.claude/hooks/moai/post_tool__lsp_diagnostic.py +508 -0
- moai_adk/templates/.claude/hooks/moai/pre_commit__tag_validator.py +287 -0
- moai_adk/templates/.claude/hooks/moai/pre_tool__security_guard.py +268 -0
- moai_adk/templates/.claude/hooks/moai/pre_tool__tdd_enforcer.py +208 -0
- moai_adk/templates/.claude/hooks/moai/session_end__auto_cleanup.py +93 -61
- moai_adk/templates/.claude/hooks/moai/session_end__rank_submit.py +69 -0
- moai_adk/templates/.claude/hooks/moai/session_start__show_project_info.py +165 -70
- moai_adk/templates/.claude/hooks/moai/shared/utils/announcement_translator.py +206 -0
- moai_adk/templates/.claude/hooks/moai/stop__loop_controller.py +621 -0
- moai_adk/templates/.claude/output-styles/moai/alfred.md +758 -0
- moai_adk/templates/.claude/output-styles/moai/r2d2.md +86 -3
- moai_adk/templates/.claude/output-styles/moai/yoda.md +2 -2
- moai_adk/templates/.claude/settings.json +154 -77
- moai_adk/templates/.claude/skills/moai-docs-generation/SKILL.md +252 -198
- moai_adk/templates/.claude/skills/moai-docs-generation/examples.md +169 -323
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/README.md +39 -27
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/api-documentation.md +115 -125
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/code-documentation.md +150 -150
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/multi-format-output.md +182 -175
- moai_adk/templates/.claude/skills/moai-docs-generation/modules/user-guides.md +198 -138
- moai_adk/templates/.claude/skills/moai-docs-generation/reference.md +226 -320
- moai_adk/templates/.claude/skills/moai-domain-backend/SKILL.md +43 -222
- moai_adk/templates/.claude/skills/moai-domain-database/SKILL.md +75 -219
- moai_adk/templates/.claude/skills/moai-domain-frontend/SKILL.md +103 -463
- moai_adk/templates/.claude/skills/moai-domain-frontend/modules/component-architecture.md +723 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/modules/nextjs16-patterns.md +713 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/modules/performance-optimization.md +694 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/modules/react19-patterns.md +591 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/modules/state-management.md +680 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/modules/vue35-patterns.md +802 -0
- moai_adk/templates/.claude/skills/moai-domain-uiux/SKILL.md +118 -339
- moai_adk/templates/.claude/skills/moai-formats-data/SKILL.md +74 -377
- moai_adk/templates/.claude/skills/moai-formats-data/modules/README.md +299 -70
- moai_adk/templates/.claude/skills/moai-foundation-claude/SKILL.md +205 -182
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/advanced-agent-patterns.md +370 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-cli-reference-official.md +420 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-custom-slash-commands-official.md +32 -22
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-devcontainers-official.md +381 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-discover-plugins-official.md +379 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-headless-official.md +378 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-hooks-official.md +110 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-plugin-marketplaces-official.md +308 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-plugins-official.md +640 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-sandboxing-official.md +282 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-skills-official.md +425 -71
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-statusline-official.md +293 -0
- moai_adk/templates/.claude/skills/moai-foundation-claude/reference/claude-code-sub-agents-official.md +325 -143
- moai_adk/templates/.claude/skills/moai-foundation-context/SKILL.md +96 -316
- moai_adk/templates/.claude/skills/moai-foundation-core/SKILL.md +116 -294
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/delegation-advanced.md +279 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/delegation-implementation.md +267 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/delegation-patterns.md +121 -650
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/patterns.md +22 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/spec-ears-format.md +200 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/spec-first-tdd.md +37 -730
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/spec-tdd-implementation.md +275 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/trust-5-framework.md +77 -819
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/trust-5-implementation.md +244 -0
- moai_adk/templates/.claude/skills/moai-foundation-core/modules/trust-5-validation.md +219 -0
- moai_adk/templates/.claude/skills/moai-foundation-philosopher/SKILL.md +14 -18
- moai_adk/templates/.claude/skills/moai-foundation-quality/SKILL.md +86 -270
- moai_adk/templates/.claude/skills/moai-framework-electron/SKILL.md +288 -0
- moai_adk/templates/.claude/skills/moai-framework-electron/examples.md +2082 -0
- moai_adk/templates/.claude/skills/moai-framework-electron/reference.md +1649 -0
- moai_adk/templates/.claude/skills/moai-lang-cpp/SKILL.md +76 -582
- moai_adk/templates/.claude/skills/moai-lang-cpp/examples.md +1239 -0
- moai_adk/templates/.claude/skills/moai-lang-cpp/modules/advanced-patterns.md +401 -0
- moai_adk/templates/.claude/skills/moai-lang-cpp/reference.md +1136 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/SKILL.md +82 -436
- moai_adk/templates/.claude/skills/moai-lang-csharp/examples.md +585 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/modules/aspnet-core.md +627 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/modules/blazor-components.md +767 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/modules/cqrs-validation.md +626 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/modules/csharp12-features.md +580 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/modules/efcore-patterns.md +622 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/reference.md +403 -0
- moai_adk/templates/.claude/skills/moai-lang-elixir/SKILL.md +65 -542
- moai_adk/templates/.claude/skills/moai-lang-elixir/examples.md +1171 -0
- moai_adk/templates/.claude/skills/moai-lang-elixir/modules/advanced-patterns.md +531 -0
- moai_adk/templates/.claude/skills/moai-lang-elixir/reference.md +889 -0
- moai_adk/templates/.claude/skills/moai-lang-flutter/SKILL.md +32 -405
- moai_adk/templates/.claude/skills/moai-lang-go/SKILL.md +114 -293
- moai_adk/templates/.claude/skills/moai-lang-java/SKILL.md +83 -307
- moai_adk/templates/.claude/skills/moai-lang-javascript/SKILL.md +179 -0
- moai_adk/templates/.claude/skills/moai-lang-javascript/examples.md +973 -0
- moai_adk/templates/.claude/skills/moai-lang-javascript/reference.md +1543 -0
- moai_adk/templates/.claude/skills/moai-lang-kotlin/SKILL.md +42 -279
- moai_adk/templates/.claude/skills/moai-lang-php/SKILL.md +94 -556
- moai_adk/templates/.claude/skills/moai-lang-php/examples.md +1608 -0
- moai_adk/templates/.claude/skills/moai-lang-php/modules/advanced-patterns.md +538 -0
- moai_adk/templates/.claude/skills/moai-lang-php/reference.md +1323 -0
- moai_adk/templates/.claude/skills/moai-lang-python/SKILL.md +108 -358
- moai_adk/templates/.claude/skills/moai-lang-r/SKILL.md +84 -482
- moai_adk/templates/.claude/skills/moai-lang-r/examples.md +1154 -0
- moai_adk/templates/.claude/skills/moai-lang-r/modules/advanced-patterns.md +489 -0
- moai_adk/templates/.claude/skills/moai-lang-r/reference.md +1087 -0
- moai_adk/templates/.claude/skills/moai-lang-ruby/SKILL.md +106 -610
- moai_adk/templates/.claude/skills/moai-lang-ruby/examples.md +1106 -0
- moai_adk/templates/.claude/skills/moai-lang-ruby/modules/advanced-patterns.md +309 -0
- moai_adk/templates/.claude/skills/moai-lang-ruby/modules/testing-patterns.md +306 -0
- moai_adk/templates/.claude/skills/moai-lang-ruby/reference.md +1024 -0
- moai_adk/templates/.claude/skills/moai-lang-rust/SKILL.md +51 -265
- moai_adk/templates/.claude/skills/moai-lang-scala/SKILL.md +106 -442
- moai_adk/templates/.claude/skills/moai-lang-scala/modules/akka-actors.md +479 -0
- moai_adk/templates/.claude/skills/moai-lang-scala/modules/cats-effect.md +489 -0
- moai_adk/templates/.claude/skills/moai-lang-scala/modules/functional-programming.md +460 -0
- moai_adk/templates/.claude/skills/moai-lang-scala/modules/spark-data.md +498 -0
- moai_adk/templates/.claude/skills/moai-lang-scala/modules/zio-patterns.md +541 -0
- moai_adk/templates/.claude/skills/moai-lang-swift/SKILL.md +88 -457
- moai_adk/templates/.claude/skills/moai-lang-swift/modules/combine-reactive.md +256 -0
- moai_adk/templates/.claude/skills/moai-lang-swift/modules/concurrency.md +270 -0
- moai_adk/templates/.claude/skills/moai-lang-swift/modules/swift6-features.md +265 -0
- moai_adk/templates/.claude/skills/moai-lang-swift/modules/swiftui-patterns.md +314 -0
- moai_adk/templates/.claude/skills/moai-lang-typescript/SKILL.md +75 -283
- moai_adk/templates/.claude/skills/moai-library-mermaid/SKILL.md +97 -252
- moai_adk/templates/.claude/skills/moai-library-nextra/SKILL.md +64 -240
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/advanced-patterns.md +331 -12
- moai_adk/templates/.claude/skills/moai-library-nextra/modules/configuration.md +330 -37
- moai_adk/templates/.claude/skills/moai-library-shadcn/SKILL.md +90 -287
- moai_adk/templates/.claude/skills/moai-platform-auth0/SKILL.md +200 -206
- moai_adk/templates/.claude/skills/moai-platform-auth0/examples.md +2446 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/adaptive-mfa.md +233 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/akamai-integration.md +214 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/application-credentials.md +280 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/attack-protection-log-events.md +224 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/attack-protection-overview.md +140 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/bot-detection.md +144 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/breached-password-detection.md +187 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/brute-force-protection.md +189 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/certifications.md +282 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/compliance-overview.md +263 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/continuous-session-protection.md +307 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/customize-mfa.md +177 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/dpop-implementation.md +283 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/fapi-implementation.md +259 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/gdpr-compliance.md +313 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/guardian-configuration.md +269 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/highly-regulated-identity.md +272 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/jwt-fundamentals.md +248 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/mdl-verification.md +210 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/mfa-api-management.md +278 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/mfa-factors.md +226 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/mfa-overview.md +174 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/mtls-sender-constraining.md +316 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/ropg-flow-mfa.md +216 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/security-center.md +325 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/security-guidance.md +277 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/state-parameters.md +177 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/step-up-authentication.md +251 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/suspicious-ip-throttling.md +240 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/tenant-access-control.md +179 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/modules/webauthn-fido.md +235 -0
- moai_adk/templates/.claude/skills/moai-platform-auth0/reference.md +224 -0
- moai_adk/templates/.claude/skills/moai-platform-clerk/SKILL.md +75 -330
- moai_adk/templates/.claude/skills/moai-platform-clerk/examples.md +1426 -0
- moai_adk/templates/.claude/skills/moai-platform-clerk/modules/advanced-patterns.md +417 -0
- moai_adk/templates/.claude/skills/moai-platform-clerk/reference.md +273 -0
- moai_adk/templates/.claude/skills/moai-platform-convex/SKILL.md +100 -340
- moai_adk/templates/.claude/skills/moai-platform-convex/examples.md +506 -0
- moai_adk/templates/.claude/skills/moai-platform-convex/modules/auth-integration.md +421 -0
- moai_adk/templates/.claude/skills/moai-platform-convex/modules/file-storage.md +474 -0
- moai_adk/templates/.claude/skills/moai-platform-convex/modules/reactive-queries.md +302 -0
- moai_adk/templates/.claude/skills/moai-platform-convex/modules/server-functions.md +452 -0
- moai_adk/templates/.claude/skills/moai-platform-convex/reference.md +385 -0
- moai_adk/templates/.claude/skills/moai-platform-firebase-auth/SKILL.md +113 -326
- moai_adk/templates/.claude/skills/moai-platform-firebase-auth/examples.md +514 -0
- moai_adk/templates/.claude/skills/moai-platform-firebase-auth/modules/custom-claims.md +374 -0
- moai_adk/templates/.claude/skills/moai-platform-firebase-auth/modules/phone-auth.md +372 -0
- moai_adk/templates/.claude/skills/moai-platform-firebase-auth/modules/social-auth.md +339 -0
- moai_adk/templates/.claude/skills/moai-platform-firebase-auth/reference.md +382 -0
- moai_adk/templates/.claude/skills/moai-platform-firestore/SKILL.md +71 -302
- moai_adk/templates/.claude/skills/moai-platform-firestore/examples.md +445 -0
- moai_adk/templates/.claude/skills/moai-platform-firestore/modules/offline-cache.md +392 -0
- moai_adk/templates/.claude/skills/moai-platform-firestore/modules/realtime-listeners.md +441 -0
- moai_adk/templates/.claude/skills/moai-platform-firestore/modules/security-rules.md +352 -0
- moai_adk/templates/.claude/skills/moai-platform-firestore/modules/transactions.md +452 -0
- moai_adk/templates/.claude/skills/moai-platform-firestore/reference.md +322 -0
- moai_adk/templates/.claude/skills/moai-platform-neon/SKILL.md +101 -412
- moai_adk/templates/.claude/skills/moai-platform-neon/examples.md +470 -0
- moai_adk/templates/.claude/skills/moai-platform-neon/modules/auto-scaling.md +349 -0
- moai_adk/templates/.claude/skills/moai-platform-neon/modules/branching-workflows.md +354 -0
- moai_adk/templates/.claude/skills/moai-platform-neon/modules/connection-pooling.md +412 -0
- moai_adk/templates/.claude/skills/moai-platform-neon/modules/pitr-backups.md +458 -0
- moai_adk/templates/.claude/skills/moai-platform-neon/reference.md +272 -0
- moai_adk/templates/.claude/skills/moai-platform-railway/SKILL.md +96 -327
- moai_adk/templates/.claude/skills/moai-platform-railway/examples.md +539 -0
- moai_adk/templates/.claude/skills/moai-platform-railway/modules/docker-deployment.md +261 -0
- moai_adk/templates/.claude/skills/moai-platform-railway/modules/multi-service.md +291 -0
- moai_adk/templates/.claude/skills/moai-platform-railway/modules/networking-domains.md +338 -0
- moai_adk/templates/.claude/skills/moai-platform-railway/modules/volumes-storage.md +353 -0
- moai_adk/templates/.claude/skills/moai-platform-railway/reference.md +374 -0
- moai_adk/templates/.claude/skills/moai-platform-supabase/SKILL.md +103 -428
- moai_adk/templates/.claude/skills/moai-platform-supabase/examples.md +502 -0
- moai_adk/templates/.claude/skills/moai-platform-supabase/modules/auth-integration.md +384 -0
- moai_adk/templates/.claude/skills/moai-platform-supabase/modules/edge-functions.md +371 -0
- moai_adk/templates/.claude/skills/moai-platform-supabase/modules/postgresql-pgvector.md +231 -0
- moai_adk/templates/.claude/skills/moai-platform-supabase/modules/realtime-presence.md +354 -0
- moai_adk/templates/.claude/skills/moai-platform-supabase/modules/row-level-security.md +286 -0
- moai_adk/templates/.claude/skills/moai-platform-supabase/modules/storage-cdn.md +319 -0
- moai_adk/templates/.claude/skills/moai-platform-supabase/modules/typescript-patterns.md +453 -0
- moai_adk/templates/.claude/skills/moai-platform-supabase/reference.md +284 -0
- moai_adk/templates/.claude/skills/moai-platform-vercel/SKILL.md +96 -446
- moai_adk/templates/.claude/skills/moai-platform-vercel/examples.md +502 -0
- moai_adk/templates/.claude/skills/moai-platform-vercel/modules/analytics-speed.md +348 -0
- moai_adk/templates/.claude/skills/moai-platform-vercel/modules/deployment-config.md +344 -0
- moai_adk/templates/.claude/skills/moai-platform-vercel/modules/edge-functions.md +222 -0
- moai_adk/templates/.claude/skills/moai-platform-vercel/modules/isr-caching.md +306 -0
- moai_adk/templates/.claude/skills/moai-platform-vercel/modules/kv-storage.md +399 -0
- moai_adk/templates/.claude/skills/moai-platform-vercel/reference.md +360 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/SKILL.md +193 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/examples.md +1099 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/modules/language-specific.md +307 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/modules/pattern-syntax.md +237 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/modules/refactoring-patterns.md +260 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/modules/security-rules.md +239 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/reference.md +288 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/languages/go.yml +90 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/languages/python.yml +101 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/languages/typescript.yml +83 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/quality/complexity-check.yml +94 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/quality/deprecated-apis.yml +84 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/security/secrets-detection.yml +89 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/security/sql-injection.yml +45 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/security/xss-prevention.yml +50 -0
- moai_adk/templates/.claude/skills/moai-tool-ast-grep/rules/sgconfig.yml +54 -0
- moai_adk/templates/.claude/skills/moai-workflow-jit-docs/SKILL.md +225 -423
- moai_adk/templates/.claude/skills/moai-workflow-loop/SKILL.md +197 -0
- moai_adk/templates/.claude/skills/moai-workflow-loop/examples.md +1063 -0
- moai_adk/templates/.claude/skills/moai-workflow-loop/reference.md +1414 -0
- moai_adk/templates/.claude/skills/moai-workflow-project/SKILL.md +211 -314
- moai_adk/templates/.claude/skills/moai-workflow-project/schemas/tab_schema.json +15 -43
- moai_adk/templates/.claude/skills/moai-workflow-spec/SKILL.md +119 -316
- moai_adk/templates/.claude/skills/moai-workflow-spec/modules/advanced-patterns.md +237 -0
- moai_adk/templates/.claude/skills/moai-workflow-templates/SKILL.md +96 -203
- moai_adk/templates/.claude/skills/moai-workflow-testing/SKILL.md +201 -388
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/README.md +52 -3
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/ai-debugging.md +263 -806
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/context7-integration.md +286 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/review-workflows.md +500 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework/relevance-analysis.md +154 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework/safety-analysis.md +148 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework/scoring-algorithms.md +196 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework/timeliness-analysis.md +168 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework/truthfulness-analysis.md +136 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework/usability-analysis.md +153 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review/trust5-framework.md +257 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/automated-code-review.md +191 -1344
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/code-review/analysis-patterns.md +340 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/code-review/core-classes.md +299 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/code-review/tool-integration.md +380 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/debugging/debugging-workflows.md +451 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/debugging/error-analysis.md +442 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance/optimization-patterns.md +473 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance/profiling-techniques.md +481 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization/ai-optimization.md +241 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization/bottleneck-detection.md +397 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization/optimization-plan.md +315 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization/profiler-core.md +277 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization/real-time-monitoring.md +187 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/performance-optimization.md +287 -1194
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/quality-metrics.md +415 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/refactoring/ai-workflows.md +620 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/refactoring/patterns.md +692 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/security-analysis.md +429 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/smart-refactoring.md +262 -1192
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/static-analysis.md +438 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd/core-classes.md +397 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd-context7/advanced-features.md +494 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd-context7/red-green-refactor.md +316 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd-context7/test-generation.md +471 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd-context7/test-patterns.md +371 -0
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/tdd-context7.md +227 -1222
- moai_adk/templates/.claude/skills/moai-workflow-testing/modules/trust5-validation.md +428 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/SKILL.md +228 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/integration-patterns.md +149 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/moai-adk-integration.md +245 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/parallel-advanced.md +310 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/parallel-development.md +202 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/parallel-workflows.md +302 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/registry-architecture.md +271 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/resource-optimization.md +300 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/tools-integration.md +280 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/troubleshooting.md +397 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/worktree-commands.md +296 -0
- moai_adk/templates/.claude/skills/moai-workflow-worktree/modules/worktree-management.md +217 -0
- moai_adk/templates/.git-hooks/pre-push +162 -59
- moai_adk/templates/.github/workflows/ci-universal.yml +934 -133
- moai_adk/templates/.gitignore +65 -107
- moai_adk/templates/.lsp.json +152 -0
- moai_adk/templates/.mcp.json +2 -20
- moai_adk/templates/.moai/announcements/en.json +18 -0
- moai_adk/templates/.moai/announcements/ja.json +18 -0
- moai_adk/templates/.moai/announcements/ko.json +18 -0
- moai_adk/templates/.moai/announcements/zh.json +18 -0
- moai_adk/templates/.moai/config/config.yaml +8 -2
- moai_adk/templates/.moai/config/multilingual-triggers.yaml +213 -0
- moai_adk/templates/.moai/config/sections/language.yaml +2 -2
- moai_adk/templates/.moai/config/sections/llm.yaml +41 -0
- moai_adk/templates/.moai/config/sections/pricing.yaml +30 -0
- moai_adk/templates/.moai/config/sections/project.yaml +2 -2
- moai_adk/templates/.moai/config/sections/quality.yaml +43 -5
- moai_adk/templates/.moai/config/sections/ralph.yaml +55 -0
- moai_adk/templates/.moai/config/sections/system.yaml +46 -1
- moai_adk/templates/.moai/config/sections/user.yaml +1 -1
- moai_adk/templates/.moai/config/statusline-config.yaml +2 -2
- moai_adk/templates/.moai/llm-configs/glm.json +22 -0
- moai_adk/templates/CLAUDE.ja.md +343 -0
- moai_adk/templates/CLAUDE.ko.md +343 -0
- moai_adk/templates/CLAUDE.md +200 -499
- moai_adk/templates/CLAUDE.zh.md +343 -0
- moai_adk/utils/common.py +37 -0
- moai_adk/version.py +1 -1
- moai_adk-1.1.0.dist-info/METADATA +2443 -0
- moai_adk-1.1.0.dist-info/RECORD +701 -0
- {moai_adk-0.34.0.dist-info → moai_adk-1.1.0.dist-info}/entry_points.txt +2 -0
- moai_adk-1.1.0.dist-info/licenses/LICENSE +99 -0
- moai_adk/core/config/auto_spec_config.py +0 -340
- moai_adk/core/hooks/post_tool_auto_spec_completion.py +0 -901
- moai_adk/core/spec/confidence_scoring.py +0 -680
- moai_adk/core/spec/ears_template_engine.py +0 -1247
- moai_adk/core/spec/quality_validator.py +0 -687
- moai_adk/templates/.claude/agents/moai/ai-nano-banana.md +0 -670
- moai_adk/templates/.claude/agents/moai/expert-database.md +0 -777
- moai_adk/templates/.claude/agents/moai/expert-uiux.md +0 -1041
- moai_adk/templates/.claude/agents/moai/mcp-context7.md +0 -458
- moai_adk/templates/.claude/agents/moai/mcp-figma.md +0 -1607
- moai_adk/templates/.claude/agents/moai/mcp-notion.md +0 -789
- moai_adk/templates/.claude/agents/moai/mcp-playwright.md +0 -469
- moai_adk/templates/.claude/agents/moai/mcp-sequential-thinking.md +0 -1032
- moai_adk/templates/.claude/skills/moai-ai-nano-banana/SKILL.md +0 -438
- moai_adk/templates/.claude/skills/moai-ai-nano-banana/examples.md +0 -431
- moai_adk/templates/.claude/skills/moai-domain-uiux/modules/design-system-tokens.md +0 -405
- moai_adk/templates/.claude/skills/moai-library-nextra/advanced-patterns.md +0 -336
- moai_adk/templates/.claude/skills/moai-mcp-figma/SKILL.md +0 -402
- moai_adk/templates/.claude/skills/moai-mcp-figma/advanced-patterns.md +0 -607
- moai_adk/templates/.claude/skills/moai-mcp-notion/SKILL.md +0 -300
- moai_adk/templates/.claude/skills/moai-mcp-notion/advanced-patterns.md +0 -537
- moai_adk/templates/.claude/skills/moai-workflow-project/__init__.py +0 -520
- moai_adk/templates/.claude/skills/moai-workflow-project/complete_workflow_demo_fixed.py +0 -574
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/complete_project_setup.py +0 -317
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/complete_workflow_demo.py +0 -663
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/config-migration-example.json +0 -190
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/question-examples.json +0 -175
- moai_adk/templates/.claude/skills/moai-workflow-project/examples/quick_start.py +0 -196
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/__init__.py +0 -17
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/advanced-patterns.md +0 -158
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/ask_user_integration.py +0 -340
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/batch_questions.py +0 -713
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/config_manager.py +0 -538
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/documentation_manager.py +0 -1336
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/language_initializer.py +0 -730
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/migration_manager.py +0 -608
- moai_adk/templates/.claude/skills/moai-workflow-project/modules/template_optimizer.py +0 -1005
- moai_adk/templates/.claude/skills/moai-workflow-project/test_integration_simple.py +0 -436
- moai_adk/templates/.claude/skills/moai-worktree/SKILL.md +0 -411
- moai_adk/templates/.claude/skills/moai-worktree/modules/integration-patterns.md +0 -982
- moai_adk/templates/.claude/skills/moai-worktree/modules/parallel-development.md +0 -778
- moai_adk/templates/.claude/skills/moai-worktree/modules/worktree-commands.md +0 -646
- moai_adk/templates/.claude/skills/moai-worktree/modules/worktree-management.md +0 -782
- moai_adk/templates/.moai/config/questions/_schema.yaml +0 -151
- moai_adk/templates/.moai/config/questions/tab0-init.yaml +0 -251
- moai_adk/templates/.moai/config/questions/tab1-user.yaml +0 -108
- moai_adk/templates/.moai/config/questions/tab2-project.yaml +0 -81
- moai_adk/templates/.moai/config/questions/tab3-git.yaml +0 -634
- moai_adk/templates/.moai/config/questions/tab4-quality.yaml +0 -170
- moai_adk/templates/.moai/config/questions/tab5-system.yaml +0 -87
- moai_adk/templates/.moai/scripts/setup-glm.py +0 -136
- moai_adk-0.34.0.dist-info/METADATA +0 -2999
- moai_adk-0.34.0.dist-info/RECORD +0 -463
- moai_adk-0.34.0.dist-info/licenses/LICENSE +0 -21
- /moai_adk/foundation/{git.py → git/__init__.py} +0 -0
- /moai_adk/templates/.claude/skills/moai-library-mermaid/{advanced-patterns.md → modules/advanced-patterns.md} +0 -0
- /moai_adk/templates/.claude/skills/moai-library-mermaid/{optimization.md → modules/optimization.md} +0 -0
- /moai_adk/templates/.claude/skills/moai-library-nextra/{optimization.md → modules/optimization.md} +0 -0
- /moai_adk/templates/.claude/skills/moai-workflow-jit-docs/{advanced-patterns.md → modules/advanced-patterns.md} +0 -0
- /moai_adk/templates/.claude/skills/moai-workflow-jit-docs/{optimization.md → modules/optimization.md} +0 -0
- /moai_adk/templates/.claude/skills/moai-workflow-testing/{advanced-patterns.md → modules/advanced-patterns.md} +0 -0
- /moai_adk/templates/.claude/skills/moai-workflow-testing/{optimization.md → modules/optimization.md} +0 -0
- /moai_adk/templates/.claude/skills/{moai-worktree → moai-workflow-worktree}/examples.md +0 -0
- /moai_adk/templates/.claude/skills/{moai-worktree → moai-workflow-worktree}/reference.md +0 -0
- {moai_adk-0.34.0.dist-info → moai_adk-1.1.0.dist-info}/WHEEL +0 -0
moai_adk/core/merge/analyzer.py
CHANGED
|
@@ -1,107 +1,117 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Pure Python Merge Analyzer
|
|
2
2
|
|
|
3
|
-
Analyzes template merge differences using
|
|
3
|
+
Analyzes template merge differences using semantic heuristics
|
|
4
4
|
for intelligent backup vs new template comparison and recommendations.
|
|
5
|
+
|
|
6
|
+
This module replaces the previous Claude Code headless implementation
|
|
7
|
+
with a pure Python approach that works without API keys.
|
|
5
8
|
"""
|
|
6
9
|
|
|
7
10
|
import json
|
|
8
11
|
import logging
|
|
9
12
|
import re
|
|
10
|
-
import subprocess
|
|
11
13
|
from difflib import unified_diff
|
|
12
14
|
from pathlib import Path
|
|
13
15
|
from typing import Any
|
|
14
16
|
|
|
15
17
|
import click
|
|
18
|
+
import yaml
|
|
16
19
|
from rich.console import Console
|
|
17
|
-
from rich.live import Live
|
|
18
|
-
from rich.spinner import Spinner
|
|
19
20
|
from rich.table import Table
|
|
20
21
|
|
|
22
|
+
from moai_adk.utils.common import reset_stdin
|
|
23
|
+
|
|
21
24
|
console = Console()
|
|
22
25
|
logger = logging.getLogger(__name__)
|
|
23
26
|
|
|
24
27
|
|
|
25
28
|
class MergeAnalyzer:
|
|
26
|
-
"""Merge analyzer using
|
|
29
|
+
"""Merge analyzer using semantic heuristics for intelligent template merge analysis
|
|
27
30
|
|
|
28
31
|
Compares backed-up user configurations with new templates,
|
|
29
|
-
analyzes them using
|
|
32
|
+
analyzes them using Python-based semantic analysis, and provides merge recommendations.
|
|
30
33
|
"""
|
|
31
34
|
|
|
32
35
|
# Primary files to analyze
|
|
33
36
|
ANALYZED_FILES = [
|
|
34
37
|
"CLAUDE.md",
|
|
35
38
|
".claude/settings.json",
|
|
36
|
-
".moai/config/config.
|
|
39
|
+
".moai/config/config.yaml",
|
|
37
40
|
".gitignore",
|
|
38
41
|
]
|
|
39
42
|
|
|
40
|
-
#
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
# Risk factors for scoring
|
|
44
|
+
RISK_FACTORS = {
|
|
45
|
+
"user_section_modified": 3,
|
|
46
|
+
"permission_change": 2,
|
|
47
|
+
"env_variable_removed": 2,
|
|
48
|
+
"large_diff": 1,
|
|
49
|
+
"config_key_removed": 2,
|
|
50
|
+
"breaking_schema_change": 3,
|
|
51
|
+
"custom_content_loss": 3,
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# User-customizable sections in CLAUDE.md (should be preserved)
|
|
55
|
+
CLAUDE_MD_USER_SECTIONS = [
|
|
56
|
+
"Project Information",
|
|
57
|
+
"User Personalization",
|
|
58
|
+
"Custom Rules",
|
|
59
|
+
"Local Configuration",
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
# Critical settings.json keys that require careful handling
|
|
63
|
+
SETTINGS_CRITICAL_KEYS = [
|
|
64
|
+
"permissions.deny",
|
|
65
|
+
"permissions.allow",
|
|
66
|
+
"env",
|
|
67
|
+
"hooks",
|
|
68
|
+
]
|
|
44
69
|
|
|
45
70
|
def __init__(self, project_path: Path):
|
|
46
71
|
"""Initialize analyzer with project path."""
|
|
47
72
|
self.project_path = project_path
|
|
48
73
|
|
|
49
74
|
def analyze_merge(self, backup_path: Path, template_path: Path) -> dict[str, Any]:
|
|
50
|
-
"""Perform merge analysis using
|
|
75
|
+
"""Perform merge analysis using semantic heuristics
|
|
51
76
|
|
|
52
77
|
Args:
|
|
53
78
|
backup_path: Path to backed-up configuration directory
|
|
54
79
|
template_path: Path to new template directory
|
|
55
80
|
|
|
56
81
|
Returns:
|
|
57
|
-
Dictionary containing analysis results
|
|
58
|
-
- files: List of changes by file
|
|
59
|
-
- safe_to_auto_merge: Whether auto-merge is safe
|
|
60
|
-
- user_action_required: Whether user intervention is needed
|
|
61
|
-
- summary: Overall summary
|
|
62
|
-
- error: Error message (if any)
|
|
82
|
+
Dictionary containing analysis results
|
|
63
83
|
"""
|
|
64
84
|
# 1. Collect files to compare
|
|
65
85
|
diff_files = self._collect_diff_files(backup_path, template_path)
|
|
66
86
|
|
|
67
|
-
# 2.
|
|
68
|
-
|
|
87
|
+
# 2. Perform semantic analysis for each file
|
|
88
|
+
files_analysis = []
|
|
89
|
+
total_risk_score = 0
|
|
69
90
|
|
|
70
|
-
|
|
71
|
-
|
|
91
|
+
for file_name, info in diff_files.items():
|
|
92
|
+
if not info["has_diff"] and info["backup_exists"] and info["template_exists"]:
|
|
93
|
+
# No changes, skip
|
|
94
|
+
continue
|
|
72
95
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
input=prompt,
|
|
78
|
-
capture_output=True,
|
|
79
|
-
text=True,
|
|
80
|
-
timeout=self.CLAUDE_TIMEOUT,
|
|
81
|
-
)
|
|
96
|
+
# Analyze based on file type
|
|
97
|
+
analysis = self._analyze_file_semantic(file_name, backup_path, template_path, info)
|
|
98
|
+
files_analysis.append(analysis)
|
|
99
|
+
total_risk_score += analysis.get("risk_score", 0)
|
|
82
100
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
except subprocess.TimeoutExpired:
|
|
99
|
-
console.print("[yellow]⚠️ Claude analysis timeout (exceeded 120 seconds)[/yellow]")
|
|
100
|
-
return self._fallback_analysis(backup_path, template_path, diff_files)
|
|
101
|
-
except FileNotFoundError:
|
|
102
|
-
console.print("[red]❌ Claude Code not found.[/red]")
|
|
103
|
-
console.print("[cyan] Install Claude Code: https://claude.com/claude-code[/cyan]")
|
|
104
|
-
return self._fallback_analysis(backup_path, template_path, diff_files)
|
|
101
|
+
# 3. Determine overall safety
|
|
102
|
+
risk_level = self._calculate_risk_level(total_risk_score)
|
|
103
|
+
safe_to_merge = risk_level == "low"
|
|
104
|
+
user_action_required = risk_level == "high"
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
"files": files_analysis,
|
|
108
|
+
"safe_to_auto_merge": safe_to_merge,
|
|
109
|
+
"user_action_required": user_action_required,
|
|
110
|
+
"summary": f"{len(files_analysis)} files need attention",
|
|
111
|
+
"risk_assessment": risk_level.capitalize(),
|
|
112
|
+
"total_risk_score": total_risk_score,
|
|
113
|
+
"analysis_method": "pure_python_semantic",
|
|
114
|
+
}
|
|
105
115
|
|
|
106
116
|
def ask_user_confirmation(self, analysis: dict[str, Any]) -> bool:
|
|
107
117
|
"""Display analysis results and request user confirmation
|
|
@@ -115,19 +125,21 @@ class MergeAnalyzer:
|
|
|
115
125
|
# 1. Display analysis results
|
|
116
126
|
self._display_analysis(analysis)
|
|
117
127
|
|
|
118
|
-
# 2.
|
|
128
|
+
# 2. Show warnings for high-risk items
|
|
119
129
|
if analysis.get("user_action_required", False):
|
|
120
130
|
console.print(
|
|
121
|
-
"\n
|
|
122
|
-
style="warning",
|
|
131
|
+
"\n[yellow]User intervention may be required. Please review:[/yellow]",
|
|
123
132
|
)
|
|
124
133
|
for file_info in analysis.get("files", []):
|
|
125
134
|
if file_info.get("conflict_severity") in ["medium", "high"]:
|
|
126
135
|
console.print(
|
|
127
|
-
f"
|
|
136
|
+
f" [yellow]{file_info['filename']}: {file_info.get('note', '')}[/yellow]",
|
|
128
137
|
)
|
|
129
138
|
|
|
130
139
|
# 3. Confirmation prompt
|
|
140
|
+
# Reset stdin to ensure interactive prompt works after SpinnerContext
|
|
141
|
+
reset_stdin()
|
|
142
|
+
|
|
131
143
|
proceed = click.confirm(
|
|
132
144
|
"\nProceed with merge?",
|
|
133
145
|
default=analysis.get("safe_to_auto_merge", False),
|
|
@@ -150,17 +162,27 @@ class MergeAnalyzer:
|
|
|
150
162
|
if not backup_file.exists() and not template_file.exists():
|
|
151
163
|
continue
|
|
152
164
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
165
|
+
# Read file contents
|
|
166
|
+
backup_content: str | None = None
|
|
167
|
+
template_content: str | None = None
|
|
168
|
+
|
|
169
|
+
if backup_file.exists():
|
|
170
|
+
try:
|
|
171
|
+
backup_content = backup_file.read_text(encoding="utf-8")
|
|
172
|
+
except Exception as e:
|
|
173
|
+
logger.warning(f"Failed to read backup file {backup_file}: {e}")
|
|
159
174
|
|
|
160
|
-
if
|
|
161
|
-
|
|
162
|
-
|
|
175
|
+
if template_file.exists():
|
|
176
|
+
try:
|
|
177
|
+
template_content = template_file.read_text(encoding="utf-8")
|
|
178
|
+
except Exception as e:
|
|
179
|
+
logger.warning(f"Failed to read template file {template_file}: {e}")
|
|
163
180
|
|
|
181
|
+
# Calculate diff
|
|
182
|
+
has_diff = False
|
|
183
|
+
diff_lines = 0
|
|
184
|
+
|
|
185
|
+
if backup_content and template_content:
|
|
164
186
|
if backup_content != template_content:
|
|
165
187
|
diff = list(
|
|
166
188
|
unified_diff(
|
|
@@ -169,85 +191,440 @@ class MergeAnalyzer:
|
|
|
169
191
|
lineterm="",
|
|
170
192
|
)
|
|
171
193
|
)
|
|
172
|
-
|
|
173
|
-
|
|
194
|
+
has_diff = True
|
|
195
|
+
diff_lines = len(diff)
|
|
196
|
+
|
|
197
|
+
diff_info: dict[str, Any] = {
|
|
198
|
+
"backup_exists": backup_file.exists(),
|
|
199
|
+
"template_exists": template_file.exists(),
|
|
200
|
+
"has_diff": has_diff,
|
|
201
|
+
"diff_lines": diff_lines,
|
|
202
|
+
"backup_content": backup_content,
|
|
203
|
+
"template_content": template_content,
|
|
204
|
+
}
|
|
174
205
|
|
|
175
206
|
diff_files[file_name] = diff_info
|
|
176
207
|
|
|
177
208
|
return diff_files
|
|
178
209
|
|
|
179
|
-
def
|
|
210
|
+
def _analyze_file_semantic(
|
|
180
211
|
self,
|
|
212
|
+
file_name: str,
|
|
181
213
|
backup_path: Path,
|
|
182
214
|
template_path: Path,
|
|
183
|
-
|
|
184
|
-
) -> str:
|
|
185
|
-
"""
|
|
215
|
+
info: dict[str, Any],
|
|
216
|
+
) -> dict[str, Any]:
|
|
217
|
+
"""Perform semantic analysis based on file type
|
|
186
218
|
|
|
187
219
|
Returns:
|
|
188
|
-
Analysis
|
|
220
|
+
Analysis result for the specific file
|
|
189
221
|
"""
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
222
|
+
# Route to appropriate analyzer based on file type
|
|
223
|
+
if file_name == "CLAUDE.md":
|
|
224
|
+
return self._analyze_claude_md(file_name, info)
|
|
225
|
+
elif file_name == ".claude/settings.json":
|
|
226
|
+
return self._analyze_settings_json(file_name, info)
|
|
227
|
+
elif file_name == ".moai/config/config.yaml":
|
|
228
|
+
return self._analyze_config_yaml(file_name, info)
|
|
229
|
+
elif file_name == ".gitignore":
|
|
230
|
+
return self._analyze_gitignore(file_name, info)
|
|
231
|
+
else:
|
|
232
|
+
return self._analyze_generic(file_name, info)
|
|
233
|
+
|
|
234
|
+
def _analyze_claude_md(self, file_name: str, info: dict[str, Any]) -> dict[str, Any]:
|
|
235
|
+
"""Analyze CLAUDE.md with section-aware logic
|
|
236
|
+
|
|
237
|
+
Detects user-customized sections and determines merge strategy.
|
|
238
|
+
"""
|
|
239
|
+
risk_score = 0
|
|
240
|
+
notes = []
|
|
241
|
+
recommendation = "use_template"
|
|
242
|
+
|
|
243
|
+
backup_content = info.get("backup_content", "")
|
|
244
|
+
template_content = info.get("template_content", "")
|
|
245
|
+
|
|
246
|
+
if not info["backup_exists"]:
|
|
247
|
+
return {
|
|
248
|
+
"filename": file_name,
|
|
249
|
+
"changes": "New file from template",
|
|
250
|
+
"recommendation": "use_template",
|
|
251
|
+
"conflict_severity": "low",
|
|
252
|
+
"risk_score": 0,
|
|
253
|
+
"note": "New file will be created",
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if not info["template_exists"]:
|
|
257
|
+
return {
|
|
258
|
+
"filename": file_name,
|
|
259
|
+
"changes": "File removed in template",
|
|
260
|
+
"recommendation": "keep_existing",
|
|
261
|
+
"conflict_severity": "medium",
|
|
262
|
+
"risk_score": self.RISK_FACTORS["custom_content_loss"],
|
|
263
|
+
"note": "Template no longer includes this file",
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
# Check for user-customized sections
|
|
267
|
+
user_customizations = []
|
|
268
|
+
for section in self.CLAUDE_MD_USER_SECTIONS:
|
|
269
|
+
pattern = rf"#+\s*{re.escape(section)}"
|
|
270
|
+
backup_has = bool(re.search(pattern, backup_content, re.IGNORECASE))
|
|
271
|
+
template_has = bool(re.search(pattern, template_content, re.IGNORECASE))
|
|
272
|
+
|
|
273
|
+
if backup_has and not template_has:
|
|
274
|
+
user_customizations.append(section)
|
|
275
|
+
risk_score += self.RISK_FACTORS["user_section_modified"]
|
|
276
|
+
|
|
277
|
+
# Analyze diff size
|
|
278
|
+
if info["diff_lines"] > 100:
|
|
279
|
+
risk_score += self.RISK_FACTORS["large_diff"]
|
|
280
|
+
notes.append("Large changes detected")
|
|
281
|
+
|
|
282
|
+
# Determine recommendation
|
|
283
|
+
if user_customizations:
|
|
284
|
+
recommendation = "smart_merge"
|
|
285
|
+
notes.append(f"User sections detected: {', '.join(user_customizations)}")
|
|
286
|
+
elif info["diff_lines"] > 50:
|
|
287
|
+
recommendation = "smart_merge"
|
|
288
|
+
else:
|
|
289
|
+
recommendation = "use_template"
|
|
290
|
+
|
|
291
|
+
severity = self._risk_score_to_severity(risk_score)
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
"filename": file_name,
|
|
295
|
+
"changes": f"{info['diff_lines']} lines changed",
|
|
296
|
+
"recommendation": recommendation,
|
|
297
|
+
"conflict_severity": severity,
|
|
298
|
+
"risk_score": risk_score,
|
|
299
|
+
"note": "; ".join(notes) if notes else "Standard template update",
|
|
300
|
+
"user_customizations": user_customizations,
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
def _analyze_settings_json(self, file_name: str, info: dict[str, Any]) -> dict[str, Any]:
|
|
304
|
+
"""Analyze settings.json with JSON structure comparison
|
|
305
|
+
|
|
306
|
+
Focuses on permissions, env variables, and hooks.
|
|
307
|
+
"""
|
|
308
|
+
risk_score = 0
|
|
309
|
+
notes = []
|
|
310
|
+
recommendation = "use_template"
|
|
311
|
+
|
|
312
|
+
if not info["backup_exists"]:
|
|
313
|
+
return {
|
|
314
|
+
"filename": file_name,
|
|
315
|
+
"changes": "New file from template",
|
|
316
|
+
"recommendation": "use_template",
|
|
317
|
+
"conflict_severity": "low",
|
|
318
|
+
"risk_score": 0,
|
|
319
|
+
"note": "New settings file will be created",
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if not info["template_exists"]:
|
|
323
|
+
return {
|
|
324
|
+
"filename": file_name,
|
|
325
|
+
"changes": "File removed in template",
|
|
326
|
+
"recommendation": "keep_existing",
|
|
327
|
+
"conflict_severity": "high",
|
|
328
|
+
"risk_score": self.RISK_FACTORS["breaking_schema_change"],
|
|
329
|
+
"note": "Critical: settings.json removed from template",
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
# Parse JSON
|
|
333
|
+
try:
|
|
334
|
+
backup_json = json.loads(info["backup_content"]) if info["backup_content"] else {}
|
|
335
|
+
template_json = json.loads(info["template_content"]) if info["template_content"] else {}
|
|
336
|
+
except json.JSONDecodeError as e:
|
|
337
|
+
logger.warning(f"JSON parse error in {file_name}: {e}")
|
|
338
|
+
return {
|
|
339
|
+
"filename": file_name,
|
|
340
|
+
"changes": "JSON parse error",
|
|
341
|
+
"recommendation": "smart_merge",
|
|
342
|
+
"conflict_severity": "high",
|
|
343
|
+
"risk_score": self.RISK_FACTORS["breaking_schema_change"],
|
|
344
|
+
"note": f"JSON parse error: {e}",
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
# Compare critical keys
|
|
348
|
+
critical_changes = []
|
|
349
|
+
|
|
350
|
+
# Check env variables
|
|
351
|
+
backup_env = backup_json.get("env", {})
|
|
352
|
+
template_env = template_json.get("env", {})
|
|
353
|
+
|
|
354
|
+
removed_env = set(backup_env.keys()) - set(template_env.keys())
|
|
355
|
+
if removed_env:
|
|
356
|
+
critical_changes.append(f"Env vars removed: {', '.join(removed_env)}")
|
|
357
|
+
risk_score += self.RISK_FACTORS["env_variable_removed"] * len(removed_env)
|
|
358
|
+
|
|
359
|
+
# Check permissions
|
|
360
|
+
backup_deny = set(backup_json.get("permissions", {}).get("deny", []))
|
|
361
|
+
template_deny = set(template_json.get("permissions", {}).get("deny", []))
|
|
362
|
+
|
|
363
|
+
if backup_deny != template_deny:
|
|
364
|
+
critical_changes.append("Permission deny list changed")
|
|
365
|
+
risk_score += self.RISK_FACTORS["permission_change"]
|
|
366
|
+
|
|
367
|
+
# Check hooks
|
|
368
|
+
backup_hooks = backup_json.get("hooks", {})
|
|
369
|
+
template_hooks = template_json.get("hooks", {})
|
|
370
|
+
|
|
371
|
+
if backup_hooks != template_hooks:
|
|
372
|
+
critical_changes.append("Hooks configuration changed")
|
|
373
|
+
risk_score += 1
|
|
374
|
+
|
|
375
|
+
# Determine recommendation
|
|
376
|
+
if critical_changes:
|
|
377
|
+
recommendation = "smart_merge"
|
|
378
|
+
notes.extend(critical_changes)
|
|
379
|
+
elif info["diff_lines"] > 20:
|
|
380
|
+
recommendation = "smart_merge"
|
|
381
|
+
else:
|
|
382
|
+
recommendation = "use_template"
|
|
383
|
+
|
|
384
|
+
severity = self._risk_score_to_severity(risk_score)
|
|
385
|
+
|
|
386
|
+
return {
|
|
387
|
+
"filename": file_name,
|
|
388
|
+
"changes": f"{info['diff_lines']} lines changed",
|
|
389
|
+
"recommendation": recommendation,
|
|
390
|
+
"conflict_severity": severity,
|
|
391
|
+
"risk_score": risk_score,
|
|
392
|
+
"note": "; ".join(notes) if notes else "Settings update available",
|
|
393
|
+
"critical_changes": critical_changes,
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
def _analyze_config_yaml(self, file_name: str, info: dict[str, Any]) -> dict[str, Any]:
|
|
397
|
+
"""Analyze config.yaml with YAML structure comparison
|
|
398
|
+
|
|
399
|
+
Preserves user settings while updating schema.
|
|
400
|
+
"""
|
|
401
|
+
risk_score = 0
|
|
402
|
+
notes = []
|
|
403
|
+
recommendation = "use_template"
|
|
404
|
+
|
|
405
|
+
if not info["backup_exists"]:
|
|
406
|
+
return {
|
|
407
|
+
"filename": file_name,
|
|
408
|
+
"changes": "New file from template",
|
|
409
|
+
"recommendation": "use_template",
|
|
410
|
+
"conflict_severity": "low",
|
|
411
|
+
"risk_score": 0,
|
|
412
|
+
"note": "New config file will be created",
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if not info["template_exists"]:
|
|
416
|
+
return {
|
|
417
|
+
"filename": file_name,
|
|
418
|
+
"changes": "File removed in template",
|
|
419
|
+
"recommendation": "keep_existing",
|
|
420
|
+
"conflict_severity": "medium",
|
|
421
|
+
"risk_score": self.RISK_FACTORS["config_key_removed"],
|
|
422
|
+
"note": "Config file removed from template",
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
# Parse YAML
|
|
426
|
+
try:
|
|
427
|
+
backup_yaml = yaml.safe_load(info["backup_content"]) if info["backup_content"] else {}
|
|
428
|
+
template_yaml = yaml.safe_load(info["template_content"]) if info["template_content"] else {}
|
|
429
|
+
|
|
430
|
+
# Handle None results
|
|
431
|
+
backup_yaml = backup_yaml or {}
|
|
432
|
+
template_yaml = template_yaml or {}
|
|
433
|
+
except yaml.YAMLError as e:
|
|
434
|
+
logger.warning(f"YAML parse error in {file_name}: {e}")
|
|
435
|
+
return {
|
|
436
|
+
"filename": file_name,
|
|
437
|
+
"changes": "YAML parse error",
|
|
438
|
+
"recommendation": "smart_merge",
|
|
439
|
+
"conflict_severity": "high",
|
|
440
|
+
"risk_score": self.RISK_FACTORS["breaking_schema_change"],
|
|
441
|
+
"note": f"YAML parse error: {e}",
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
# User-specific keys to preserve
|
|
445
|
+
user_keys = ["user", "language", "project"]
|
|
446
|
+
user_customizations = []
|
|
447
|
+
|
|
448
|
+
for key in user_keys:
|
|
449
|
+
backup_val = backup_yaml.get(key)
|
|
450
|
+
template_val = template_yaml.get(key)
|
|
451
|
+
|
|
452
|
+
if backup_val and backup_val != template_val:
|
|
453
|
+
user_customizations.append(key)
|
|
454
|
+
|
|
455
|
+
# Check for removed keys
|
|
456
|
+
backup_keys = set(self._flatten_keys(backup_yaml))
|
|
457
|
+
template_keys = set(self._flatten_keys(template_yaml))
|
|
458
|
+
removed_keys = backup_keys - template_keys
|
|
459
|
+
|
|
460
|
+
if removed_keys:
|
|
461
|
+
risk_score += self.RISK_FACTORS["config_key_removed"]
|
|
462
|
+
notes.append(f"Keys removed: {len(removed_keys)}")
|
|
463
|
+
|
|
464
|
+
# Determine recommendation
|
|
465
|
+
if user_customizations:
|
|
466
|
+
recommendation = "smart_merge"
|
|
467
|
+
notes.append(f"User settings: {', '.join(user_customizations)}")
|
|
468
|
+
risk_score += 1
|
|
469
|
+
elif info["diff_lines"] > 30:
|
|
470
|
+
recommendation = "smart_merge"
|
|
471
|
+
else:
|
|
472
|
+
recommendation = "use_template"
|
|
473
|
+
|
|
474
|
+
severity = self._risk_score_to_severity(risk_score)
|
|
475
|
+
|
|
476
|
+
return {
|
|
477
|
+
"filename": file_name,
|
|
478
|
+
"changes": f"{info['diff_lines']} lines changed",
|
|
479
|
+
"recommendation": recommendation,
|
|
480
|
+
"conflict_severity": severity,
|
|
481
|
+
"risk_score": risk_score,
|
|
482
|
+
"note": "; ".join(notes) if notes else "Config update available",
|
|
483
|
+
"user_customizations": user_customizations,
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
def _analyze_gitignore(self, file_name: str, info: dict[str, Any]) -> dict[str, Any]:
|
|
487
|
+
"""Analyze .gitignore with line-based comparison
|
|
488
|
+
|
|
489
|
+
Preserves user additions, only adds new template entries.
|
|
490
|
+
"""
|
|
491
|
+
risk_score = 0
|
|
492
|
+
notes = []
|
|
493
|
+
|
|
494
|
+
if not info["backup_exists"]:
|
|
495
|
+
return {
|
|
496
|
+
"filename": file_name,
|
|
497
|
+
"changes": "New file from template",
|
|
498
|
+
"recommendation": "use_template",
|
|
499
|
+
"conflict_severity": "low",
|
|
500
|
+
"risk_score": 0,
|
|
501
|
+
"note": "New .gitignore will be created",
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
if not info["template_exists"]:
|
|
505
|
+
return {
|
|
506
|
+
"filename": file_name,
|
|
507
|
+
"changes": "File removed in template",
|
|
508
|
+
"recommendation": "keep_existing",
|
|
509
|
+
"conflict_severity": "low",
|
|
510
|
+
"risk_score": 0,
|
|
511
|
+
"note": "Keep existing .gitignore",
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
# Line-based analysis
|
|
515
|
+
backup_lines = set(info["backup_content"].splitlines()) if info["backup_content"] else set()
|
|
516
|
+
template_lines = set(info["template_content"].splitlines()) if info["template_content"] else set()
|
|
517
|
+
|
|
518
|
+
# Filter out comments and empty lines
|
|
519
|
+
backup_entries = {line.strip() for line in backup_lines if line.strip() and not line.startswith("#")}
|
|
520
|
+
template_entries = {line.strip() for line in template_lines if line.strip() and not line.startswith("#")}
|
|
521
|
+
|
|
522
|
+
new_in_template = template_entries - backup_entries
|
|
523
|
+
removed_in_template = backup_entries - template_entries
|
|
524
|
+
|
|
525
|
+
if new_in_template:
|
|
526
|
+
notes.append(f"{len(new_in_template)} new entries in template")
|
|
527
|
+
|
|
528
|
+
if removed_in_template:
|
|
529
|
+
notes.append(f"{len(removed_in_template)} user entries to preserve")
|
|
530
|
+
risk_score += 1
|
|
531
|
+
|
|
532
|
+
# gitignore is typically safe to merge (additions only)
|
|
533
|
+
recommendation = "smart_merge" if removed_in_template else "use_template"
|
|
534
|
+
severity = "low"
|
|
535
|
+
|
|
536
|
+
return {
|
|
537
|
+
"filename": file_name,
|
|
538
|
+
"changes": f"{info['diff_lines']} lines changed",
|
|
539
|
+
"recommendation": recommendation,
|
|
540
|
+
"conflict_severity": severity,
|
|
541
|
+
"risk_score": risk_score,
|
|
542
|
+
"note": "; ".join(notes) if notes else "gitignore update",
|
|
543
|
+
"new_entries": list(new_in_template),
|
|
544
|
+
"user_entries": list(removed_in_template),
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
def _analyze_generic(self, file_name: str, info: dict[str, Any]) -> dict[str, Any]:
|
|
548
|
+
"""Generic file analysis for unknown file types"""
|
|
549
|
+
risk_score = 0
|
|
550
|
+
|
|
551
|
+
if not info["backup_exists"]:
|
|
552
|
+
return {
|
|
553
|
+
"filename": file_name,
|
|
554
|
+
"changes": "New file from template",
|
|
555
|
+
"recommendation": "use_template",
|
|
556
|
+
"conflict_severity": "low",
|
|
557
|
+
"risk_score": 0,
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
if not info["template_exists"]:
|
|
561
|
+
return {
|
|
562
|
+
"filename": file_name,
|
|
563
|
+
"changes": "File removed in template",
|
|
564
|
+
"recommendation": "keep_existing",
|
|
565
|
+
"conflict_severity": "medium",
|
|
566
|
+
"risk_score": self.RISK_FACTORS["custom_content_loss"],
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
if info["diff_lines"] > 100:
|
|
570
|
+
risk_score += self.RISK_FACTORS["large_diff"]
|
|
571
|
+
|
|
572
|
+
severity = self._risk_score_to_severity(risk_score)
|
|
573
|
+
|
|
574
|
+
return {
|
|
575
|
+
"filename": file_name,
|
|
576
|
+
"changes": f"{info['diff_lines']} lines changed",
|
|
577
|
+
"recommendation": "smart_merge" if info["diff_lines"] > 50 else "use_template",
|
|
578
|
+
"conflict_severity": severity,
|
|
579
|
+
"risk_score": risk_score,
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
def _flatten_keys(self, d: dict, parent_key: str = "") -> list[str]:
|
|
583
|
+
"""Flatten nested dictionary keys for comparison"""
|
|
584
|
+
keys = []
|
|
585
|
+
for k, v in d.items():
|
|
586
|
+
new_key = f"{parent_key}.{k}" if parent_key else k
|
|
587
|
+
keys.append(new_key)
|
|
588
|
+
if isinstance(v, dict):
|
|
589
|
+
keys.extend(self._flatten_keys(v, new_key))
|
|
590
|
+
return keys
|
|
591
|
+
|
|
592
|
+
def _risk_score_to_severity(self, score: int) -> str:
|
|
593
|
+
"""Convert risk score to severity level"""
|
|
594
|
+
if score <= 2:
|
|
595
|
+
return "low"
|
|
596
|
+
elif score <= 5:
|
|
597
|
+
return "medium"
|
|
598
|
+
else:
|
|
599
|
+
return "high"
|
|
600
|
+
|
|
601
|
+
def _calculate_risk_level(self, total_score: int) -> str:
|
|
602
|
+
"""Calculate overall risk level from total score"""
|
|
603
|
+
if total_score <= 3:
|
|
604
|
+
return "low"
|
|
605
|
+
elif total_score <= 8:
|
|
606
|
+
return "medium"
|
|
607
|
+
else:
|
|
608
|
+
return "high"
|
|
236
609
|
|
|
237
610
|
def _display_analysis(self, analysis: dict[str, Any]) -> None:
|
|
238
611
|
"""Display analysis results in Rich format"""
|
|
239
612
|
# Title
|
|
240
|
-
|
|
613
|
+
method = analysis.get("analysis_method", "semantic")
|
|
614
|
+
console.print(f"\n[bold]Merge Analysis Results ({method})[/bold]")
|
|
241
615
|
|
|
242
616
|
# Summary
|
|
243
617
|
summary = analysis.get("summary", "No analysis results")
|
|
244
|
-
console.print(f"\n
|
|
618
|
+
console.print(f"\n{summary}")
|
|
245
619
|
|
|
246
620
|
# Risk assessment
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
621
|
+
risk_level = analysis.get("risk_assessment", "Unknown")
|
|
622
|
+
risk_style = {
|
|
623
|
+
"Low": "green",
|
|
624
|
+
"Medium": "yellow",
|
|
625
|
+
"High": "red",
|
|
626
|
+
}.get(risk_level, "white")
|
|
627
|
+
console.print(f"Risk Level: [{risk_style}]{risk_level}[/{risk_style}]")
|
|
251
628
|
|
|
252
629
|
# Changes by file table
|
|
253
630
|
files_list = analysis.get("files")
|
|
@@ -259,223 +636,31 @@ Analyze the following items and provide a JSON response:
|
|
|
259
636
|
table.add_column("Risk", style="red")
|
|
260
637
|
|
|
261
638
|
for file_info in files_list:
|
|
262
|
-
# Ensure file_info is a dictionary
|
|
263
639
|
if not isinstance(file_info, dict):
|
|
264
640
|
continue
|
|
265
641
|
|
|
642
|
+
severity = file_info.get("conflict_severity", "low")
|
|
266
643
|
severity_style = {
|
|
267
644
|
"low": "green",
|
|
268
645
|
"medium": "yellow",
|
|
269
646
|
"high": "red",
|
|
270
|
-
}.get(
|
|
647
|
+
}.get(severity, "white")
|
|
271
648
|
|
|
272
649
|
table.add_row(
|
|
273
650
|
file_info.get("filename", "?"),
|
|
274
|
-
file_info.get("changes", "")[:
|
|
651
|
+
str(file_info.get("changes", ""))[:40],
|
|
275
652
|
file_info.get("recommendation", "?"),
|
|
276
|
-
|
|
653
|
+
severity,
|
|
277
654
|
style=severity_style,
|
|
278
655
|
)
|
|
279
656
|
|
|
280
657
|
console.print(table)
|
|
281
658
|
|
|
282
|
-
# Additional
|
|
659
|
+
# Additional notes
|
|
283
660
|
for file_info in files_list:
|
|
284
|
-
# Ensure file_info is a dictionary
|
|
285
661
|
if not isinstance(file_info, dict):
|
|
286
662
|
continue
|
|
287
|
-
|
|
288
663
|
if file_info.get("note"):
|
|
289
664
|
console.print(
|
|
290
|
-
f"\n
|
|
291
|
-
style="dim",
|
|
665
|
+
f"\n[dim]{file_info['filename']}: {file_info['note']}[/dim]",
|
|
292
666
|
)
|
|
293
|
-
|
|
294
|
-
def _parse_claude_response(self, response_text: str) -> dict[str, Any]:
|
|
295
|
-
"""Parse Claude Code response supporting both v1.x and v2.0+ formats.
|
|
296
|
-
|
|
297
|
-
Args:
|
|
298
|
-
response_text: Raw response text from Claude Code
|
|
299
|
-
|
|
300
|
-
Returns:
|
|
301
|
-
Parsed analysis dictionary
|
|
302
|
-
"""
|
|
303
|
-
try:
|
|
304
|
-
# First try direct JSON parsing (v1.x format)
|
|
305
|
-
return json.loads(response_text)
|
|
306
|
-
except json.JSONDecodeError:
|
|
307
|
-
# Try v2.0+ wrapped format
|
|
308
|
-
try:
|
|
309
|
-
# Look for JSON in the response
|
|
310
|
-
if '"type":' in response_text and '"result":' in response_text:
|
|
311
|
-
# Parse the wrapped v2.0+ format
|
|
312
|
-
response_obj = json.loads(response_text)
|
|
313
|
-
if "result" in response_obj:
|
|
314
|
-
result_text = response_obj["result"]
|
|
315
|
-
|
|
316
|
-
# Try to extract JSON from the result field
|
|
317
|
-
if isinstance(result_text, str):
|
|
318
|
-
# Look for JSON blocks in the result
|
|
319
|
-
if "```json" in result_text:
|
|
320
|
-
# Extract JSON from code block
|
|
321
|
-
start = result_text.find("```json") + 7
|
|
322
|
-
end = result_text.find("```", start)
|
|
323
|
-
if end != -1:
|
|
324
|
-
json_text = result_text[start:end].strip()
|
|
325
|
-
return json.loads(json_text)
|
|
326
|
-
elif result_text.strip().startswith("{"):
|
|
327
|
-
# Try direct JSON parsing
|
|
328
|
-
return json.loads(result_text)
|
|
329
|
-
else:
|
|
330
|
-
# Try to find JSON pattern in text
|
|
331
|
-
json_match = re.search(r"\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}", result_text)
|
|
332
|
-
if json_match:
|
|
333
|
-
try:
|
|
334
|
-
return json.loads(json_match.group(0))
|
|
335
|
-
except json.JSONDecodeError:
|
|
336
|
-
pass
|
|
337
|
-
|
|
338
|
-
# Fallback: try to find any JSON in the text
|
|
339
|
-
json_match = re.search(r"\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}", response_text)
|
|
340
|
-
if json_match:
|
|
341
|
-
return json.loads(json_match.group(0))
|
|
342
|
-
|
|
343
|
-
except (json.JSONDecodeError, KeyError, TypeError) as e:
|
|
344
|
-
console.print(f"[yellow]⚠️ Failed to parse Claude v2.0+ response: {e}[/yellow]")
|
|
345
|
-
logger.warning(f"Claude response parsing failed: {e}")
|
|
346
|
-
|
|
347
|
-
# If all parsing attempts fail, return error structure
|
|
348
|
-
logger.error(f"Could not parse Claude response. Raw response: {response_text[:500]}...")
|
|
349
|
-
return {
|
|
350
|
-
"files": [],
|
|
351
|
-
"safe_to_auto_merge": False,
|
|
352
|
-
"user_action_required": True,
|
|
353
|
-
"summary": "Failed to parse Claude response",
|
|
354
|
-
"risk_assessment": "High - Response parsing failed",
|
|
355
|
-
"error": "response_parse_failed",
|
|
356
|
-
"raw_response": response_text[:500] if response_text else "",
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
def _detect_claude_errors(self, stderr: str) -> str:
|
|
360
|
-
"""Detect and interpret Claude Code specific errors.
|
|
361
|
-
|
|
362
|
-
Args:
|
|
363
|
-
stderr: Standard error output from Claude Code
|
|
364
|
-
|
|
365
|
-
Returns:
|
|
366
|
-
User-friendly error message
|
|
367
|
-
"""
|
|
368
|
-
if not stderr:
|
|
369
|
-
return ""
|
|
370
|
-
|
|
371
|
-
error_lower = stderr.lower()
|
|
372
|
-
|
|
373
|
-
if "model not found" in error_lower or "unknown model" in error_lower:
|
|
374
|
-
return f"Claude model '{self.CLAUDE_MODEL}' not found. Please check available models with 'claude --models'"
|
|
375
|
-
|
|
376
|
-
if "permission denied" in error_lower:
|
|
377
|
-
return "Permission denied. Check file permissions and Claude Code access rights."
|
|
378
|
-
|
|
379
|
-
if "timeout" in error_lower:
|
|
380
|
-
return f"Claude analysis timed out after {self.CLAUDE_TIMEOUT} seconds. Consider increasing timeout."
|
|
381
|
-
|
|
382
|
-
if "file not found" in error_lower:
|
|
383
|
-
return "Required files not found. Check project structure and file paths."
|
|
384
|
-
|
|
385
|
-
if "invalid argument" in error_lower or "unknown option" in error_lower:
|
|
386
|
-
return "Invalid Claude Code arguments. This might be a version compatibility issue."
|
|
387
|
-
|
|
388
|
-
# Return generic error if no specific pattern matches
|
|
389
|
-
return f"Claude Code error: {stderr[:200]}"
|
|
390
|
-
|
|
391
|
-
def _build_claude_command(self) -> list[str]:
|
|
392
|
-
"""Build Claude Code headless command (based on official v4.0+)
|
|
393
|
-
|
|
394
|
-
Claude Code CLI official options:
|
|
395
|
-
- -p: Non-interactive headless mode
|
|
396
|
-
- --model: Explicit model selection (Haiku)
|
|
397
|
-
- --output-format: JSON response format
|
|
398
|
-
- --tools: Read-only tools only (space-separated - POSIX standard)
|
|
399
|
-
- --permission-mode: Auto-approval (background task)
|
|
400
|
-
|
|
401
|
-
Returns:
|
|
402
|
-
List of Claude CLI command arguments
|
|
403
|
-
"""
|
|
404
|
-
# Tools list space-separated (POSIX standard, officially recommended)
|
|
405
|
-
tools_str = " ".join(self.CLAUDE_TOOLS)
|
|
406
|
-
|
|
407
|
-
return [
|
|
408
|
-
"claude",
|
|
409
|
-
"-p", # Non-interactive headless mode
|
|
410
|
-
"--model",
|
|
411
|
-
self.CLAUDE_MODEL, # Explicit model specification (Haiku)
|
|
412
|
-
"--output-format",
|
|
413
|
-
"json", # Single JSON response
|
|
414
|
-
"--tools",
|
|
415
|
-
tools_str, # Space-separated (Read Glob Grep)
|
|
416
|
-
"--permission-mode",
|
|
417
|
-
"dontAsk", # Auto-approval (safe, read-only)
|
|
418
|
-
]
|
|
419
|
-
|
|
420
|
-
def _format_diff_summary(self, diff_files: dict[str, dict[str, Any]]) -> str:
|
|
421
|
-
"""Format diff_files for prompt"""
|
|
422
|
-
summary = []
|
|
423
|
-
for file_name, info in diff_files.items():
|
|
424
|
-
if info["backup_exists"] and info["template_exists"]:
|
|
425
|
-
status = f"✏️ Modified ({info['diff_lines']} lines)" if info["has_diff"] else "✓ Identical"
|
|
426
|
-
elif info["backup_exists"]:
|
|
427
|
-
status = "❌ Deleted from template"
|
|
428
|
-
else:
|
|
429
|
-
status = "✨ New file (from template)"
|
|
430
|
-
|
|
431
|
-
summary.append(f"- {file_name}: {status}")
|
|
432
|
-
|
|
433
|
-
return "\n".join(summary)
|
|
434
|
-
|
|
435
|
-
def _fallback_analysis(
|
|
436
|
-
self,
|
|
437
|
-
backup_path: Path,
|
|
438
|
-
template_path: Path,
|
|
439
|
-
diff_files: dict[str, dict[str, Any]],
|
|
440
|
-
) -> dict[str, Any]:
|
|
441
|
-
"""Fallback analysis when Claude call fails (difflib-based)
|
|
442
|
-
|
|
443
|
-
Returns basic analysis results when Claude is unavailable
|
|
444
|
-
"""
|
|
445
|
-
console.print(
|
|
446
|
-
"⚠️ Claude Code unavailable. Using fallback analysis.",
|
|
447
|
-
style="yellow",
|
|
448
|
-
)
|
|
449
|
-
|
|
450
|
-
files_analysis = []
|
|
451
|
-
has_high_risk = False
|
|
452
|
-
|
|
453
|
-
for file_name, info in diff_files.items():
|
|
454
|
-
if not info["has_diff"]:
|
|
455
|
-
continue
|
|
456
|
-
|
|
457
|
-
# Simple risk assessment
|
|
458
|
-
severity = "low"
|
|
459
|
-
if file_name in [".claude/settings.json", ".moai/config/config.json"]:
|
|
460
|
-
severity = "medium" if info["diff_lines"] > 10 else "low"
|
|
461
|
-
|
|
462
|
-
files_analysis.append(
|
|
463
|
-
{
|
|
464
|
-
"filename": file_name,
|
|
465
|
-
"changes": f"{info['diff_lines']} lines changed",
|
|
466
|
-
"recommendation": "smart_merge",
|
|
467
|
-
"conflict_severity": severity,
|
|
468
|
-
}
|
|
469
|
-
)
|
|
470
|
-
|
|
471
|
-
if severity == "high":
|
|
472
|
-
has_high_risk = True
|
|
473
|
-
|
|
474
|
-
return {
|
|
475
|
-
"files": files_analysis,
|
|
476
|
-
"safe_to_auto_merge": not has_high_risk,
|
|
477
|
-
"user_action_required": has_high_risk,
|
|
478
|
-
"summary": f"{len(files_analysis)} files changed (fallback analysis)",
|
|
479
|
-
"risk_assessment": ("High - Claude unavailable, manual review recommended" if has_high_risk else "Low"),
|
|
480
|
-
"fallback": True,
|
|
481
|
-
}
|