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/rank/client.py
ADDED
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
"""API client for MoAI Rank service with HMAC-SHA256 request signing.
|
|
2
|
+
|
|
3
|
+
This client handles all communication with the rank.mo.ai.kr service,
|
|
4
|
+
including secure request signing to prevent tampering.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import hashlib
|
|
8
|
+
import hmac
|
|
9
|
+
import json
|
|
10
|
+
import time
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from typing import Any, Optional
|
|
13
|
+
|
|
14
|
+
import requests
|
|
15
|
+
|
|
16
|
+
from moai_adk.rank.config import RankConfig
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class RankInfo:
|
|
21
|
+
"""Ranking information for a specific period."""
|
|
22
|
+
|
|
23
|
+
position: int
|
|
24
|
+
composite_score: float
|
|
25
|
+
total_participants: int
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class UserRank:
|
|
30
|
+
"""Complete user ranking data."""
|
|
31
|
+
|
|
32
|
+
username: str
|
|
33
|
+
daily: Optional[RankInfo]
|
|
34
|
+
weekly: Optional[RankInfo]
|
|
35
|
+
monthly: Optional[RankInfo]
|
|
36
|
+
all_time: Optional[RankInfo]
|
|
37
|
+
total_tokens: int
|
|
38
|
+
total_sessions: int
|
|
39
|
+
input_tokens: int
|
|
40
|
+
output_tokens: int
|
|
41
|
+
last_updated: str
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@dataclass
|
|
45
|
+
class LeaderboardEntry:
|
|
46
|
+
"""Single entry in the leaderboard."""
|
|
47
|
+
|
|
48
|
+
rank: int
|
|
49
|
+
username: str
|
|
50
|
+
total_tokens: int
|
|
51
|
+
composite_score: float
|
|
52
|
+
session_count: int
|
|
53
|
+
is_private: bool
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass
|
|
57
|
+
class ApiStatus:
|
|
58
|
+
"""API health status."""
|
|
59
|
+
|
|
60
|
+
status: str
|
|
61
|
+
version: str
|
|
62
|
+
timestamp: str
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@dataclass
|
|
66
|
+
class SessionSubmission:
|
|
67
|
+
"""Session data for submission.
|
|
68
|
+
|
|
69
|
+
Attributes:
|
|
70
|
+
session_hash: Unique hash for deduplication
|
|
71
|
+
ended_at: Session end timestamp (UTC ISO format)
|
|
72
|
+
input_tokens: Total input tokens consumed
|
|
73
|
+
output_tokens: Total output tokens generated
|
|
74
|
+
cache_creation_tokens: Tokens used for cache creation
|
|
75
|
+
cache_read_tokens: Tokens read from cache
|
|
76
|
+
model_name: Primary model used in the session
|
|
77
|
+
|
|
78
|
+
# Dashboard fields (for activity visualization)
|
|
79
|
+
started_at: Session start timestamp (UTC ISO format)
|
|
80
|
+
duration_seconds: Total session duration in seconds
|
|
81
|
+
turn_count: Number of user turns (messages)
|
|
82
|
+
tool_usage: Tool usage counts (e.g., {"Read": 5, "Write": 3})
|
|
83
|
+
model_usage: Per-model token usage (e.g., {"claude-opus-4-5": {"input": 5000, "output": 2000}})
|
|
84
|
+
code_metrics: Code change metrics (e.g., {"linesAdded": 100, "linesDeleted": 20, ...})
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
session_hash: str
|
|
88
|
+
ended_at: str
|
|
89
|
+
input_tokens: int
|
|
90
|
+
output_tokens: int
|
|
91
|
+
cache_creation_tokens: int = 0
|
|
92
|
+
cache_read_tokens: int = 0
|
|
93
|
+
model_name: Optional[str] = None
|
|
94
|
+
|
|
95
|
+
# Dashboard fields for activity visualization
|
|
96
|
+
started_at: Optional[str] = None
|
|
97
|
+
duration_seconds: int = 0
|
|
98
|
+
turn_count: int = 0
|
|
99
|
+
tool_usage: Optional[dict[str, int]] = None
|
|
100
|
+
model_usage: Optional[dict[str, dict[str, int]]] = None
|
|
101
|
+
code_metrics: Optional[dict[str, int]] = None
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class RankClientError(Exception):
|
|
105
|
+
"""Base exception for rank client errors."""
|
|
106
|
+
|
|
107
|
+
pass
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class AuthenticationError(RankClientError):
|
|
111
|
+
"""Raised when authentication fails."""
|
|
112
|
+
|
|
113
|
+
pass
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class ApiError(RankClientError):
|
|
117
|
+
"""Raised when API returns an error."""
|
|
118
|
+
|
|
119
|
+
def __init__(self, message: str, status_code: int, details: Optional[dict] = None):
|
|
120
|
+
super().__init__(message)
|
|
121
|
+
self.status_code = status_code
|
|
122
|
+
self.details = details or {}
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class RankClient:
|
|
126
|
+
"""HTTP client for MoAI Rank API with HMAC authentication."""
|
|
127
|
+
|
|
128
|
+
def __init__(
|
|
129
|
+
self,
|
|
130
|
+
api_key: Optional[str] = None,
|
|
131
|
+
config: Optional[RankConfig] = None,
|
|
132
|
+
timeout: int = 30,
|
|
133
|
+
):
|
|
134
|
+
"""Initialize the rank client.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
api_key: API key for authentication (loaded from config if not provided)
|
|
138
|
+
config: Configuration instance (uses defaults if not provided)
|
|
139
|
+
timeout: Request timeout in seconds
|
|
140
|
+
"""
|
|
141
|
+
self.config = config or RankConfig()
|
|
142
|
+
self._api_key = api_key or RankConfig.get_api_key()
|
|
143
|
+
self.timeout = timeout
|
|
144
|
+
self._session = requests.Session()
|
|
145
|
+
self._session.headers.update(
|
|
146
|
+
{
|
|
147
|
+
"User-Agent": "moai-adk/1.0",
|
|
148
|
+
"Content-Type": "application/json",
|
|
149
|
+
"Accept": "application/json",
|
|
150
|
+
}
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
@property
|
|
154
|
+
def api_key(self) -> Optional[str]:
|
|
155
|
+
"""Get the current API key."""
|
|
156
|
+
return self._api_key
|
|
157
|
+
|
|
158
|
+
@api_key.setter
|
|
159
|
+
def api_key(self, value: str) -> None:
|
|
160
|
+
"""Set the API key."""
|
|
161
|
+
self._api_key = value
|
|
162
|
+
|
|
163
|
+
def _compute_signature(self, timestamp: str, body: str) -> str:
|
|
164
|
+
"""Compute HMAC-SHA256 signature for request authentication.
|
|
165
|
+
|
|
166
|
+
The signature is computed as:
|
|
167
|
+
HMAC-SHA256(api_key, timestamp + ":" + body)
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
timestamp: Unix timestamp as string
|
|
171
|
+
body: Request body as JSON string
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
Hexadecimal signature string
|
|
175
|
+
"""
|
|
176
|
+
if not self._api_key:
|
|
177
|
+
raise AuthenticationError("API key not configured")
|
|
178
|
+
|
|
179
|
+
message = f"{timestamp}:{body}"
|
|
180
|
+
signature = hmac.new(
|
|
181
|
+
self._api_key.encode("utf-8"),
|
|
182
|
+
message.encode("utf-8"),
|
|
183
|
+
hashlib.sha256,
|
|
184
|
+
).hexdigest()
|
|
185
|
+
|
|
186
|
+
return signature
|
|
187
|
+
|
|
188
|
+
def _get_auth_headers(self, body: str = "") -> dict[str, str]:
|
|
189
|
+
"""Get authentication headers for a request.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
body: Request body for signature computation
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
Dictionary of authentication headers
|
|
196
|
+
"""
|
|
197
|
+
if not self._api_key:
|
|
198
|
+
raise AuthenticationError("API key not configured")
|
|
199
|
+
|
|
200
|
+
timestamp = str(int(time.time()))
|
|
201
|
+
signature = self._compute_signature(timestamp, body)
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
"X-API-Key": self._api_key,
|
|
205
|
+
"X-Timestamp": timestamp,
|
|
206
|
+
"X-Signature": signature,
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
def _make_request(
|
|
210
|
+
self,
|
|
211
|
+
method: str,
|
|
212
|
+
endpoint: str,
|
|
213
|
+
data: Optional[dict] = None,
|
|
214
|
+
auth: bool = False,
|
|
215
|
+
hmac_auth: bool = False,
|
|
216
|
+
) -> dict[str, Any]:
|
|
217
|
+
"""Make an HTTP request to the API.
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
method: HTTP method (GET, POST, etc.)
|
|
221
|
+
endpoint: API endpoint path
|
|
222
|
+
data: Request body data (for POST)
|
|
223
|
+
auth: Whether to include API key header
|
|
224
|
+
hmac_auth: Whether to include HMAC signature headers
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
Response data as dictionary
|
|
228
|
+
|
|
229
|
+
Raises:
|
|
230
|
+
AuthenticationError: If authentication fails
|
|
231
|
+
ApiError: If API returns an error
|
|
232
|
+
RankClientError: For other request failures
|
|
233
|
+
"""
|
|
234
|
+
url = f"{self.config.api_base_url}{endpoint}"
|
|
235
|
+
body_str = json.dumps(data) if data else ""
|
|
236
|
+
|
|
237
|
+
headers = {}
|
|
238
|
+
if hmac_auth:
|
|
239
|
+
headers.update(self._get_auth_headers(body_str))
|
|
240
|
+
elif auth:
|
|
241
|
+
if not self._api_key:
|
|
242
|
+
raise AuthenticationError("API key not configured")
|
|
243
|
+
headers["X-API-Key"] = self._api_key
|
|
244
|
+
|
|
245
|
+
try:
|
|
246
|
+
if method.upper() == "GET":
|
|
247
|
+
response = self._session.get(url, headers=headers, timeout=self.timeout)
|
|
248
|
+
elif method.upper() == "POST":
|
|
249
|
+
response = self._session.post(
|
|
250
|
+
url,
|
|
251
|
+
headers=headers,
|
|
252
|
+
data=body_str,
|
|
253
|
+
timeout=self.timeout,
|
|
254
|
+
)
|
|
255
|
+
else:
|
|
256
|
+
raise ValueError(f"Unsupported HTTP method: {method}")
|
|
257
|
+
|
|
258
|
+
# Parse response
|
|
259
|
+
try:
|
|
260
|
+
response_data = response.json()
|
|
261
|
+
except json.JSONDecodeError:
|
|
262
|
+
response_data = {"raw": response.text}
|
|
263
|
+
|
|
264
|
+
# Handle errors
|
|
265
|
+
if response.status_code == 401:
|
|
266
|
+
raise AuthenticationError(response_data.get("error", "Authentication failed"))
|
|
267
|
+
|
|
268
|
+
if response.status_code >= 400:
|
|
269
|
+
details = response_data.get("details")
|
|
270
|
+
raise ApiError(
|
|
271
|
+
response_data.get("error", f"API error: {response.status_code}"),
|
|
272
|
+
response.status_code,
|
|
273
|
+
details if isinstance(details, dict) else None,
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
return response_data
|
|
277
|
+
|
|
278
|
+
except requests.RequestException as e:
|
|
279
|
+
raise RankClientError(f"Request failed: {e}") from e
|
|
280
|
+
|
|
281
|
+
def check_status(self) -> ApiStatus:
|
|
282
|
+
"""Check API status and availability.
|
|
283
|
+
|
|
284
|
+
Returns:
|
|
285
|
+
ApiStatus with service health information
|
|
286
|
+
"""
|
|
287
|
+
data = self._make_request("GET", "/status")
|
|
288
|
+
return ApiStatus(
|
|
289
|
+
status=data.get("status", "unknown"),
|
|
290
|
+
version=data.get("version", "unknown"),
|
|
291
|
+
timestamp=data.get("timestamp", ""),
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
def get_user_rank(self) -> UserRank:
|
|
295
|
+
"""Get current user's rank and statistics.
|
|
296
|
+
|
|
297
|
+
Returns:
|
|
298
|
+
UserRank with complete ranking data
|
|
299
|
+
|
|
300
|
+
Raises:
|
|
301
|
+
AuthenticationError: If API key is invalid
|
|
302
|
+
"""
|
|
303
|
+
response = self._make_request("GET", "/rank", auth=True)
|
|
304
|
+
|
|
305
|
+
# API returns {"success": true, "data": {...}}
|
|
306
|
+
data = response.get("data", response)
|
|
307
|
+
|
|
308
|
+
def parse_rank_info(rank_data: Optional[dict]) -> Optional[RankInfo]:
|
|
309
|
+
if not rank_data:
|
|
310
|
+
return None
|
|
311
|
+
return RankInfo(
|
|
312
|
+
position=rank_data.get("position", 0),
|
|
313
|
+
composite_score=rank_data.get("compositeScore", 0.0),
|
|
314
|
+
total_participants=rank_data.get("totalParticipants", 0),
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
rankings = data.get("rankings", {})
|
|
318
|
+
stats = data.get("stats", {})
|
|
319
|
+
|
|
320
|
+
return UserRank(
|
|
321
|
+
username=data.get("username", "unknown"),
|
|
322
|
+
daily=parse_rank_info(rankings.get("daily")),
|
|
323
|
+
weekly=parse_rank_info(rankings.get("weekly")),
|
|
324
|
+
monthly=parse_rank_info(rankings.get("monthly")),
|
|
325
|
+
all_time=parse_rank_info(rankings.get("allTime")),
|
|
326
|
+
total_tokens=stats.get("totalTokens", 0),
|
|
327
|
+
total_sessions=stats.get("totalSessions", 0),
|
|
328
|
+
input_tokens=stats.get("inputTokens", 0),
|
|
329
|
+
output_tokens=stats.get("outputTokens", 0),
|
|
330
|
+
last_updated=data.get("lastUpdated", ""),
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
def get_leaderboard(
|
|
334
|
+
self,
|
|
335
|
+
period: str = "weekly",
|
|
336
|
+
limit: int = 10,
|
|
337
|
+
offset: int = 0,
|
|
338
|
+
) -> list[LeaderboardEntry]:
|
|
339
|
+
"""Get the leaderboard for a specific period.
|
|
340
|
+
|
|
341
|
+
Args:
|
|
342
|
+
period: Period type (daily, weekly, monthly, all_time)
|
|
343
|
+
limit: Maximum number of entries (1-100)
|
|
344
|
+
offset: Pagination offset
|
|
345
|
+
|
|
346
|
+
Returns:
|
|
347
|
+
List of LeaderboardEntry objects
|
|
348
|
+
"""
|
|
349
|
+
# Use the public leaderboard endpoint (no auth needed)
|
|
350
|
+
url = f"{self.config.base_url}/api/leaderboard"
|
|
351
|
+
params = {
|
|
352
|
+
"period": period,
|
|
353
|
+
"limit": str(min(limit, 100)),
|
|
354
|
+
"offset": str(offset),
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
try:
|
|
358
|
+
response = self._session.get(url, params=params, timeout=self.timeout)
|
|
359
|
+
data = response.json()
|
|
360
|
+
|
|
361
|
+
# Validate response is a dictionary before calling .get()
|
|
362
|
+
if not isinstance(data, dict):
|
|
363
|
+
raise ApiError(
|
|
364
|
+
f"Unexpected response format: {type(data).__name__}",
|
|
365
|
+
response.status_code,
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
if response.status_code >= 400:
|
|
369
|
+
raise ApiError(
|
|
370
|
+
data.get("error", "Failed to fetch leaderboard"),
|
|
371
|
+
response.status_code,
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
entries = []
|
|
375
|
+
|
|
376
|
+
# API returns: {"data": {"items": [...], "pagination": {...}}}
|
|
377
|
+
data_obj = data.get("data", {})
|
|
378
|
+
if isinstance(data_obj, dict):
|
|
379
|
+
leaderboard_data = data_obj.get("items", [])
|
|
380
|
+
elif isinstance(data_obj, list):
|
|
381
|
+
# Fallback for old API format
|
|
382
|
+
leaderboard_data = data_obj
|
|
383
|
+
else:
|
|
384
|
+
leaderboard_data = []
|
|
385
|
+
|
|
386
|
+
for item in leaderboard_data:
|
|
387
|
+
# Skip non-dict items
|
|
388
|
+
if not isinstance(item, dict):
|
|
389
|
+
continue
|
|
390
|
+
entries.append(
|
|
391
|
+
LeaderboardEntry(
|
|
392
|
+
rank=item.get("rank", 0),
|
|
393
|
+
username=item.get("username", "Unknown"),
|
|
394
|
+
total_tokens=item.get("totalTokens", 0),
|
|
395
|
+
composite_score=item.get("compositeScore", 0.0),
|
|
396
|
+
session_count=item.get("sessionCount", 0),
|
|
397
|
+
is_private=item.get("isPrivate", False),
|
|
398
|
+
)
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
return entries
|
|
402
|
+
|
|
403
|
+
except requests.RequestException as e:
|
|
404
|
+
raise RankClientError(f"Failed to fetch leaderboard: {e}") from e
|
|
405
|
+
|
|
406
|
+
def submit_session(self, session: SessionSubmission) -> dict[str, Any]:
|
|
407
|
+
"""Submit a Claude Code session with token usage.
|
|
408
|
+
|
|
409
|
+
This method uses HMAC authentication to prevent tampering.
|
|
410
|
+
|
|
411
|
+
Args:
|
|
412
|
+
session: Session data to submit
|
|
413
|
+
|
|
414
|
+
Returns:
|
|
415
|
+
API response with session ID and confirmation
|
|
416
|
+
|
|
417
|
+
Raises:
|
|
418
|
+
AuthenticationError: If API key or signature is invalid
|
|
419
|
+
ApiError: If submission fails
|
|
420
|
+
"""
|
|
421
|
+
data = {
|
|
422
|
+
"sessionHash": session.session_hash,
|
|
423
|
+
"endedAt": session.ended_at,
|
|
424
|
+
"inputTokens": session.input_tokens,
|
|
425
|
+
"outputTokens": session.output_tokens,
|
|
426
|
+
"cacheCreationTokens": session.cache_creation_tokens,
|
|
427
|
+
"cacheReadTokens": session.cache_read_tokens,
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if session.model_name:
|
|
431
|
+
data["modelName"] = session.model_name
|
|
432
|
+
|
|
433
|
+
# Dashboard fields (optional)
|
|
434
|
+
if session.started_at:
|
|
435
|
+
data["startedAt"] = session.started_at
|
|
436
|
+
|
|
437
|
+
if session.duration_seconds > 0:
|
|
438
|
+
data["durationSeconds"] = session.duration_seconds
|
|
439
|
+
|
|
440
|
+
if session.turn_count > 0:
|
|
441
|
+
data["turnCount"] = session.turn_count
|
|
442
|
+
|
|
443
|
+
if session.tool_usage:
|
|
444
|
+
data["toolUsage"] = session.tool_usage
|
|
445
|
+
|
|
446
|
+
if session.model_usage:
|
|
447
|
+
data["modelUsage"] = session.model_usage
|
|
448
|
+
|
|
449
|
+
if session.code_metrics:
|
|
450
|
+
data["codeMetrics"] = session.code_metrics
|
|
451
|
+
|
|
452
|
+
return self._make_request("POST", "/sessions", data=data, hmac_auth=True)
|
|
453
|
+
|
|
454
|
+
def submit_sessions_batch(self, sessions: list[SessionSubmission]) -> dict[str, Any]:
|
|
455
|
+
"""Submit multiple Claude Code sessions in a single batch request.
|
|
456
|
+
|
|
457
|
+
This method uses HMAC authentication and is more efficient than
|
|
458
|
+
submitting sessions individually when syncing many sessions.
|
|
459
|
+
|
|
460
|
+
Args:
|
|
461
|
+
sessions: List of session data to submit (max 100 per batch)
|
|
462
|
+
|
|
463
|
+
Returns:
|
|
464
|
+
API response with batch results:
|
|
465
|
+
- success: Overall success status
|
|
466
|
+
- processed: Number of sessions processed
|
|
467
|
+
- succeeded: Number of sessions successfully submitted
|
|
468
|
+
- failed: Number of sessions that failed
|
|
469
|
+
- results: List of individual results per session
|
|
470
|
+
|
|
471
|
+
Raises:
|
|
472
|
+
AuthenticationError: If API key or signature is invalid
|
|
473
|
+
ApiError: If batch submission fails
|
|
474
|
+
ValueError: If more than 100 sessions provided
|
|
475
|
+
"""
|
|
476
|
+
if len(sessions) > 100:
|
|
477
|
+
raise ValueError("Maximum 100 sessions per batch request")
|
|
478
|
+
|
|
479
|
+
sessions_data = []
|
|
480
|
+
for session in sessions:
|
|
481
|
+
session_data = {
|
|
482
|
+
"sessionHash": session.session_hash,
|
|
483
|
+
"endedAt": session.ended_at,
|
|
484
|
+
"inputTokens": session.input_tokens,
|
|
485
|
+
"outputTokens": session.output_tokens,
|
|
486
|
+
"cacheCreationTokens": session.cache_creation_tokens,
|
|
487
|
+
"cacheReadTokens": session.cache_read_tokens,
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
if session.model_name:
|
|
491
|
+
session_data["modelName"] = session.model_name
|
|
492
|
+
|
|
493
|
+
if session.started_at:
|
|
494
|
+
session_data["startedAt"] = session.started_at
|
|
495
|
+
|
|
496
|
+
if session.duration_seconds > 0:
|
|
497
|
+
session_data["durationSeconds"] = session.duration_seconds
|
|
498
|
+
|
|
499
|
+
if session.turn_count > 0:
|
|
500
|
+
session_data["turnCount"] = session.turn_count
|
|
501
|
+
|
|
502
|
+
if session.tool_usage:
|
|
503
|
+
session_data["toolUsage"] = session.tool_usage
|
|
504
|
+
|
|
505
|
+
if session.model_usage:
|
|
506
|
+
session_data["modelUsage"] = session.model_usage
|
|
507
|
+
|
|
508
|
+
if session.code_metrics:
|
|
509
|
+
session_data["codeMetrics"] = session.code_metrics
|
|
510
|
+
|
|
511
|
+
sessions_data.append(session_data)
|
|
512
|
+
|
|
513
|
+
data = {"sessions": sessions_data}
|
|
514
|
+
|
|
515
|
+
return self._make_request("POST", "/sessions/batch", data=data, hmac_auth=True)
|
|
516
|
+
|
|
517
|
+
def compute_session_hash(
|
|
518
|
+
self,
|
|
519
|
+
input_tokens: int,
|
|
520
|
+
output_tokens: int,
|
|
521
|
+
cache_creation_tokens: int,
|
|
522
|
+
cache_read_tokens: int,
|
|
523
|
+
model_name: Optional[str],
|
|
524
|
+
ended_at: str,
|
|
525
|
+
) -> str:
|
|
526
|
+
"""Compute a client-side session hash for deduplication.
|
|
527
|
+
|
|
528
|
+
Args:
|
|
529
|
+
input_tokens: Number of input tokens
|
|
530
|
+
output_tokens: Number of output tokens
|
|
531
|
+
cache_creation_tokens: Cache creation tokens
|
|
532
|
+
cache_read_tokens: Cache read tokens
|
|
533
|
+
model_name: Model name
|
|
534
|
+
ended_at: Session end timestamp
|
|
535
|
+
|
|
536
|
+
Returns:
|
|
537
|
+
SHA-256 hash string
|
|
538
|
+
"""
|
|
539
|
+
# Create a deterministic string from session data
|
|
540
|
+
# SECURITY: Use cryptographically secure random token instead of time.time_ns()
|
|
541
|
+
# to prevent session hash prediction even if timestamp is known
|
|
542
|
+
import secrets
|
|
543
|
+
|
|
544
|
+
data = ":".join(
|
|
545
|
+
[
|
|
546
|
+
str(input_tokens),
|
|
547
|
+
str(output_tokens),
|
|
548
|
+
str(cache_creation_tokens),
|
|
549
|
+
str(cache_read_tokens),
|
|
550
|
+
model_name or "",
|
|
551
|
+
ended_at,
|
|
552
|
+
# Cryptographically secure random component for uniqueness
|
|
553
|
+
secrets.token_hex(16),
|
|
554
|
+
]
|
|
555
|
+
)
|
|
556
|
+
|
|
557
|
+
return hashlib.sha256(data.encode()).hexdigest()
|
moai_adk/rank/config.py
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"""Secure configuration and credential storage for MoAI Rank.
|
|
2
|
+
|
|
3
|
+
Credentials are stored in ~/.moai/rank/credentials.json with
|
|
4
|
+
restricted permissions (chmod 600) to prevent unauthorized access.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
import os
|
|
9
|
+
import stat
|
|
10
|
+
from dataclasses import asdict, dataclass
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Optional
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class RankCredentials:
|
|
17
|
+
"""User credentials for MoAI Rank API."""
|
|
18
|
+
|
|
19
|
+
api_key: str
|
|
20
|
+
username: str
|
|
21
|
+
user_id: str
|
|
22
|
+
created_at: str
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class RankConfig:
|
|
26
|
+
"""Manages secure storage and retrieval of MoAI Rank credentials."""
|
|
27
|
+
|
|
28
|
+
# Service configuration
|
|
29
|
+
DEFAULT_BASE_URL = "https://rank.mo.ai.kr"
|
|
30
|
+
API_VERSION = "v1"
|
|
31
|
+
|
|
32
|
+
# Credential storage paths
|
|
33
|
+
CONFIG_DIR = Path.home() / ".moai" / "rank"
|
|
34
|
+
CREDENTIALS_FILE = CONFIG_DIR / "credentials.json"
|
|
35
|
+
LAST_SYNC_FILE = CONFIG_DIR / "last_sync.json"
|
|
36
|
+
|
|
37
|
+
def __init__(self, base_url: Optional[str] = None):
|
|
38
|
+
"""Initialize configuration with optional custom base URL.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
base_url: Override the default API base URL (for testing)
|
|
42
|
+
"""
|
|
43
|
+
self.base_url = base_url or os.environ.get("MOAI_RANK_URL", self.DEFAULT_BASE_URL)
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def api_base_url(self) -> str:
|
|
47
|
+
"""Get the full API base URL including version prefix."""
|
|
48
|
+
return f"{self.base_url}/api/{self.API_VERSION}"
|
|
49
|
+
|
|
50
|
+
@classmethod
|
|
51
|
+
def ensure_config_dir(cls) -> Path:
|
|
52
|
+
"""Create the configuration directory with secure permissions.
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Path to the configuration directory
|
|
56
|
+
"""
|
|
57
|
+
cls.CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
|
58
|
+
# Set directory permissions to owner-only (700)
|
|
59
|
+
os.chmod(cls.CONFIG_DIR, stat.S_IRWXU)
|
|
60
|
+
return cls.CONFIG_DIR
|
|
61
|
+
|
|
62
|
+
@classmethod
|
|
63
|
+
def save_credentials(cls, credentials: RankCredentials) -> None:
|
|
64
|
+
"""Save credentials securely to disk.
|
|
65
|
+
|
|
66
|
+
The credentials file is created with mode 600 (owner read/write only)
|
|
67
|
+
to prevent other users from accessing the API key.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
credentials: The credentials to save
|
|
71
|
+
"""
|
|
72
|
+
cls.ensure_config_dir()
|
|
73
|
+
|
|
74
|
+
# Write credentials with secure permissions
|
|
75
|
+
creds_data = asdict(credentials)
|
|
76
|
+
|
|
77
|
+
# Write to a temporary file first, then rename (atomic operation)
|
|
78
|
+
temp_file = cls.CREDENTIALS_FILE.with_suffix(".tmp")
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
with open(temp_file, "w") as f:
|
|
82
|
+
json.dump(creds_data, f, indent=2)
|
|
83
|
+
|
|
84
|
+
# Set file permissions to owner-only (600) before renaming
|
|
85
|
+
os.chmod(temp_file, stat.S_IRUSR | stat.S_IWUSR)
|
|
86
|
+
|
|
87
|
+
# Atomic rename
|
|
88
|
+
temp_file.rename(cls.CREDENTIALS_FILE)
|
|
89
|
+
except Exception:
|
|
90
|
+
# Clean up temp file on error
|
|
91
|
+
if temp_file.exists():
|
|
92
|
+
temp_file.unlink()
|
|
93
|
+
raise
|
|
94
|
+
|
|
95
|
+
@classmethod
|
|
96
|
+
def load_credentials(cls) -> Optional[RankCredentials]:
|
|
97
|
+
"""Load credentials from disk.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
RankCredentials if found and valid, None otherwise
|
|
101
|
+
"""
|
|
102
|
+
if not cls.CREDENTIALS_FILE.exists():
|
|
103
|
+
return None
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
with open(cls.CREDENTIALS_FILE) as f:
|
|
107
|
+
data = json.load(f)
|
|
108
|
+
|
|
109
|
+
return RankCredentials(
|
|
110
|
+
api_key=data["api_key"],
|
|
111
|
+
username=data["username"],
|
|
112
|
+
user_id=data["user_id"],
|
|
113
|
+
created_at=data["created_at"],
|
|
114
|
+
)
|
|
115
|
+
except (json.JSONDecodeError, KeyError, OSError):
|
|
116
|
+
return None
|
|
117
|
+
|
|
118
|
+
@classmethod
|
|
119
|
+
def delete_credentials(cls) -> bool:
|
|
120
|
+
"""Delete stored credentials.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
True if credentials were deleted, False if they didn't exist
|
|
124
|
+
"""
|
|
125
|
+
if cls.CREDENTIALS_FILE.exists():
|
|
126
|
+
cls.CREDENTIALS_FILE.unlink()
|
|
127
|
+
return True
|
|
128
|
+
return False
|
|
129
|
+
|
|
130
|
+
@classmethod
|
|
131
|
+
def has_credentials(cls) -> bool:
|
|
132
|
+
"""Check if credentials are stored.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
True if credentials file exists
|
|
136
|
+
"""
|
|
137
|
+
return cls.CREDENTIALS_FILE.exists()
|
|
138
|
+
|
|
139
|
+
@classmethod
|
|
140
|
+
def get_api_key(cls) -> Optional[str]:
|
|
141
|
+
"""Get the stored API key.
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
API key string if available, None otherwise
|
|
145
|
+
"""
|
|
146
|
+
creds = cls.load_credentials()
|
|
147
|
+
return creds.api_key if creds else None
|