moai-adk 0.4.5__py3-none-any.whl â 0.20.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of moai-adk might be problematic. Click here for more details.
- moai_adk/__init__.py +1 -1
- moai_adk/__main__.py +74 -1
- moai_adk/cli/commands/__init__.py +1 -1
- moai_adk/cli/commands/analyze.py +119 -0
- moai_adk/cli/commands/backup.py +25 -1
- moai_adk/cli/commands/doctor.py +31 -5
- moai_adk/cli/commands/improve_user_experience.py +307 -0
- moai_adk/cli/commands/init.py +111 -10
- moai_adk/cli/commands/status.py +33 -3
- moai_adk/cli/commands/update.py +921 -130
- moai_adk/cli/commands/validate_links.py +120 -0
- moai_adk/cli/prompts/init_prompts.py +22 -87
- moai_adk/core/analysis/__init__.py +9 -0
- moai_adk/core/analysis/session_analyzer.py +388 -0
- moai_adk/core/analysis/tag_chain_analyzer.py +344 -0
- moai_adk/core/analysis/tag_chain_repair.py +879 -0
- moai_adk/core/config/__init__.py +19 -0
- moai_adk/core/config/migration.py +235 -0
- moai_adk/core/git/__init__.py +1 -1
- moai_adk/core/git/branch.py +1 -1
- moai_adk/core/git/commit.py +1 -1
- moai_adk/core/git/manager.py +1 -1
- moai_adk/core/issue_creator.py +313 -0
- moai_adk/core/mcp/setup.py +56 -0
- moai_adk/core/mcp/setup_old.py +296 -0
- moai_adk/core/project/backup_utils.py +1 -1
- moai_adk/core/project/checker.py +2 -2
- moai_adk/core/project/detector.py +211 -12
- moai_adk/core/project/initializer.py +85 -15
- moai_adk/core/project/phase_executor.py +76 -13
- moai_adk/core/project/validator.py +13 -13
- moai_adk/core/quality/__init__.py +1 -1
- moai_adk/core/quality/trust_checker.py +1 -1
- moai_adk/core/quality/validators/__init__.py +1 -1
- moai_adk/core/quality/validators/base_validator.py +1 -1
- moai_adk/core/tags/__init__.py +86 -0
- moai_adk/core/tags/auto_corrector.py +693 -0
- moai_adk/core/tags/ci_validator.py +463 -0
- moai_adk/core/tags/cli.py +283 -0
- moai_adk/core/tags/generator.py +109 -0
- moai_adk/core/tags/inserter.py +99 -0
- moai_adk/core/tags/mapper.py +126 -0
- moai_adk/core/tags/parser.py +76 -0
- moai_adk/core/tags/policy_validator.py +580 -0
- moai_adk/core/tags/pre_commit_validator.py +421 -0
- moai_adk/core/tags/reporter.py +956 -0
- moai_adk/core/tags/rollback_manager.py +525 -0
- moai_adk/core/tags/tags.py +149 -0
- moai_adk/core/tags/validator.py +897 -0
- moai_adk/core/template/__init__.py +1 -1
- moai_adk/core/template/backup.py +1 -1
- moai_adk/core/template/merger.py +50 -1
- moai_adk/core/template/processor.py +119 -13
- moai_adk/core/template_engine.py +268 -0
- moai_adk/templates/.claude/agents/alfred/backend-expert.md +348 -0
- moai_adk/templates/.claude/agents/alfred/cc-manager.md +209 -944
- moai_adk/templates/.claude/agents/alfred/database-expert.md +352 -0
- moai_adk/templates/.claude/agents/alfred/debug-helper.md +34 -5
- moai_adk/templates/.claude/agents/alfred/devops-expert.md +464 -0
- moai_adk/templates/.claude/agents/alfred/doc-syncer.md +38 -8
- moai_adk/templates/.claude/agents/alfred/format-expert.md +469 -0
- moai_adk/templates/.claude/agents/alfred/frontend-expert.md +357 -0
- moai_adk/templates/.claude/agents/alfred/git-manager.md +128 -9
- moai_adk/templates/.claude/agents/alfred/implementation-planner.md +104 -6
- moai_adk/templates/.claude/agents/alfred/project-manager.md +88 -16
- moai_adk/templates/.claude/agents/alfred/quality-gate.md +36 -9
- moai_adk/templates/.claude/agents/alfred/security-expert.md +270 -0
- moai_adk/templates/.claude/agents/alfred/skill-factory.md +865 -0
- moai_adk/templates/.claude/agents/alfred/spec-builder.md +214 -43
- moai_adk/templates/.claude/agents/alfred/tag-agent.md +111 -9
- moai_adk/templates/.claude/agents/alfred/tdd-implementer.md +309 -160
- moai_adk/templates/.claude/agents/alfred/trust-checker.md +36 -7
- moai_adk/templates/.claude/agents/alfred/ui-ux-expert.md +605 -0
- moai_adk/templates/.claude/commands/alfred/0-project.md +393 -966
- moai_adk/templates/.claude/commands/alfred/1-plan.md +651 -367
- moai_adk/templates/.claude/commands/alfred/2-run.md +388 -241
- moai_adk/templates/.claude/commands/alfred/3-sync.md +1921 -410
- moai_adk/templates/.claude/commands/alfred/9-feedback.md +153 -0
- moai_adk/templates/.claude/commands/alfred/release-new.md +3604 -0
- moai_adk/templates/.claude/hooks/alfred/core/project.py +484 -20
- moai_adk/templates/.claude/hooks/alfred/core/timeout.py +136 -0
- moai_adk/templates/.claude/hooks/alfred/core/ttl_cache.py +108 -0
- moai_adk/templates/.claude/hooks/alfred/core/version_cache.py +198 -0
- moai_adk/templates/.claude/hooks/alfred/handlers/__init__.py +14 -6
- moai_adk/templates/.claude/hooks/alfred/post_tool__enable_streaming_ui.py +50 -0
- moai_adk/templates/.claude/hooks/alfred/post_tool__log_changes.py +93 -0
- moai_adk/templates/.claude/hooks/alfred/post_tool__tag_auto_corrector.py +407 -0
- moai_adk/templates/.claude/hooks/alfred/pre_tool__auto_checkpoint.py +99 -0
- moai_adk/templates/.claude/hooks/alfred/pre_tool__realtime_tag_monitor.py +335 -0
- moai_adk/templates/.claude/hooks/alfred/pre_tool__tag_policy_validator.py +325 -0
- moai_adk/templates/.claude/hooks/alfred/session_end__cleanup.py +93 -0
- moai_adk/templates/.claude/hooks/alfred/session_start__auto_cleanup.py +580 -0
- moai_adk/templates/.claude/hooks/alfred/session_start__show_project_info.py +298 -0
- moai_adk/templates/.claude/hooks/alfred/shared/core/__init__.py +170 -0
- moai_adk/templates/.claude/hooks/alfred/{core â shared/core}/checkpoint.py +3 -3
- moai_adk/templates/.claude/hooks/alfred/{core â shared/core}/context.py +5 -5
- moai_adk/templates/.claude/hooks/alfred/shared/core/project.py +749 -0
- moai_adk/templates/.claude/hooks/alfred/shared/core/tags.py +230 -0
- moai_adk/templates/.claude/hooks/alfred/shared/core/version_cache.py +198 -0
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/__init__.py +21 -0
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/daily_analysis.py +351 -0
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/notification.py +154 -0
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/session.py +174 -0
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/tool.py +87 -0
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/user.py +61 -0
- moai_adk/templates/.claude/hooks/alfred/user_prompt__jit_load_docs.py +111 -0
- moai_adk/templates/.claude/hooks/alfred/utils/__init__.py +1 -0
- moai_adk/templates/.claude/hooks/alfred/utils/hook_config.py +94 -0
- moai_adk/templates/.claude/hooks/alfred/utils/timeout.py +161 -0
- moai_adk/templates/.claude/output-styles/alfred/alfred-moai-adk-beginner.md +267 -0
- moai_adk/templates/.claude/output-styles/alfred/keating-personal-tutor.md +440 -0
- moai_adk/templates/.claude/output-styles/alfred/r2d2-agentic-coding.md +583 -0
- moai_adk/templates/.claude/settings.json +96 -14
- moai_adk/templates/.claude/skills/moai-alfred-agent-guide/SKILL.md +70 -0
- moai_adk/templates/.claude/skills/moai-alfred-agent-guide/examples.md +62 -0
- moai_adk/templates/.claude/skills/moai-alfred-agent-guide/reference.md +242 -0
- moai_adk/templates/.claude/skills/moai-alfred-ask-user-questions/SKILL.md +237 -0
- moai_adk/templates/.claude/skills/moai-alfred-ask-user-questions/examples.md +871 -0
- moai_adk/templates/.claude/skills/moai-alfred-ask-user-questions/reference.md +653 -0
- moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/README.md +162 -0
- moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/SKILL.md +227 -0
- moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/examples.md +354 -0
- moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/reference.md +158 -0
- moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/SKILL.md +179 -79
- moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/examples.md +117 -0
- moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/scripts/pre-review-check.sh +62 -0
- moai_adk/templates/.claude/skills/moai-alfred-config-schema/SKILL.md +132 -0
- moai_adk/templates/.claude/skills/moai-alfred-config-schema/examples.md +28 -0
- moai_adk/templates/.claude/skills/moai-alfred-config-schema/reference.md +444 -0
- moai_adk/templates/.claude/skills/moai-alfred-context-budget/SKILL.md +62 -0
- moai_adk/templates/.claude/skills/moai-alfred-context-budget/examples.md +28 -0
- moai_adk/templates/.claude/skills/moai-alfred-context-budget/reference.md +405 -0
- moai_adk/templates/.claude/skills/moai-alfred-dev-guide/SKILL.md +51 -0
- moai_adk/templates/.claude/skills/moai-alfred-dev-guide/examples.md +355 -0
- moai_adk/templates/.claude/skills/moai-alfred-dev-guide/reference.md +239 -0
- moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/SKILL.md +323 -0
- moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/examples.md +286 -0
- moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/reference.md +126 -0
- moai_adk/templates/.claude/skills/moai-alfred-issue-labels/SKILL.md +229 -0
- moai_adk/templates/.claude/skills/moai-alfred-issue-labels/examples.md +4 -0
- moai_adk/templates/.claude/skills/moai-alfred-issue-labels/reference.md +150 -0
- moai_adk/templates/.claude/skills/moai-alfred-language-detection/SKILL.md +87 -73
- moai_adk/templates/.claude/skills/moai-alfred-language-detection/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-alfred-language-detection/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-alfred-personas/README.md +42 -0
- moai_adk/templates/.claude/skills/moai-alfred-personas/SKILL.md +429 -0
- moai_adk/templates/.claude/skills/moai-alfred-personas/examples.md +520 -0
- moai_adk/templates/.claude/skills/moai-alfred-personas/reference.md +405 -0
- moai_adk/templates/.claude/skills/moai-alfred-practices/SKILL.md +89 -0
- moai_adk/templates/.claude/skills/moai-alfred-practices/examples.md +122 -0
- moai_adk/templates/.claude/skills/moai-alfred-practices/reference.md +369 -0
- moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/SKILL.md +508 -0
- moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/examples.md +481 -0
- moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/reference.md +100 -0
- moai_adk/templates/.claude/skills/moai-alfred-rules/SKILL.md +77 -0
- moai_adk/templates/.claude/skills/moai-alfred-rules/examples.md +265 -0
- moai_adk/templates/.claude/skills/moai-alfred-rules/reference.md +539 -0
- moai_adk/templates/.claude/skills/moai-alfred-session-state/SKILL.md +320 -0
- moai_adk/templates/.claude/skills/moai-alfred-session-state/examples.md +4 -0
- moai_adk/templates/.claude/skills/moai-alfred-session-state/reference.md +84 -0
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/README.md +137 -0
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/SKILL.md +219 -0
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/examples/validate-spec.sh +161 -0
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/examples.md +541 -0
- moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/reference.md +622 -0
- moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/SKILL.md +19 -0
- moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/examples.md +4 -0
- moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/reference.md +211 -0
- moai_adk/templates/.claude/skills/moai-alfred-workflow/SKILL.md +288 -0
- moai_adk/templates/.claude/skills/moai-cc-agents/SKILL.md +269 -0
- moai_adk/templates/.claude/skills/moai-cc-agents/templates/agent-template.md +32 -0
- moai_adk/templates/.claude/skills/moai-cc-claude-md/SKILL.md +298 -0
- moai_adk/templates/.claude/skills/moai-cc-claude-md/templates/CLAUDE-template.md +26 -0
- moai_adk/templates/.claude/skills/moai-cc-commands/SKILL.md +307 -0
- moai_adk/templates/.claude/skills/moai-cc-commands/templates/command-template.md +21 -0
- moai_adk/templates/.claude/skills/moai-cc-hooks/SKILL.md +252 -0
- moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/pre-bash-check.sh +19 -0
- moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/preserve-permissions.sh +19 -0
- moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/validate-bash-command.py +24 -0
- moai_adk/templates/.claude/skills/moai-cc-mcp-plugins/SKILL.md +199 -0
- moai_adk/templates/.claude/skills/moai-cc-mcp-plugins/templates/settings-mcp-template.json +39 -0
- moai_adk/templates/.claude/skills/moai-cc-memory/SKILL.md +316 -0
- moai_adk/templates/.claude/skills/moai-cc-memory/templates/session-summary-template.md +18 -0
- moai_adk/templates/.claude/skills/moai-cc-settings/SKILL.md +263 -0
- moai_adk/templates/.claude/skills/moai-cc-settings/templates/settings-complete-template.json +30 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/CHECKLIST.md +482 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/EXAMPLES.md +303 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/INTERACTIVE-DISCOVERY.md +524 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/METADATA.md +477 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/PARALLEL-ANALYSIS-REPORT.md +429 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/PYTHON-VERSION-MATRIX.md +391 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL-FACTORY-WORKFLOW.md +431 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL-UPDATE-ADVISOR.md +577 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL.md +273 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/STEP-BY-STEP-GUIDE.md +466 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/STRUCTURE.md +583 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/WEB-RESEARCH.md +526 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/reference.md +608 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/scripts/generate-structure.sh +328 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/scripts/validate-skill.sh +312 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/SKILL_TEMPLATE.md +245 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/examples-template.md +285 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/reference-template.md +278 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/scripts-template.sh +303 -0
- moai_adk/templates/.claude/skills/moai-cc-skills/SKILL.md +291 -0
- moai_adk/templates/.claude/skills/moai-cc-skills/templates/SKILL-template.md +15 -0
- moai_adk/templates/.claude/skills/moai-change-logger/SKILL.md +563 -0
- moai_adk/templates/.claude/skills/moai-design-systems/SKILL.md +802 -0
- moai_adk/templates/.claude/skills/moai-design-systems/examples.md +1238 -0
- moai_adk/templates/.claude/skills/moai-design-systems/reference.md +673 -0
- moai_adk/templates/.claude/skills/moai-domain-backend/SKILL.md +234 -43
- moai_adk/templates/.claude/skills/moai-domain-backend/examples.md +1633 -0
- moai_adk/templates/.claude/skills/moai-domain-backend/reference.md +660 -0
- moai_adk/templates/.claude/skills/moai-domain-cli-tool/SKILL.md +97 -69
- moai_adk/templates/.claude/skills/moai-domain-cli-tool/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-cli-tool/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-data-science/SKILL.md +97 -72
- moai_adk/templates/.claude/skills/moai-domain-data-science/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-data-science/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-database/SKILL.md +97 -74
- moai_adk/templates/.claude/skills/moai-domain-database/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-database/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-devops/SKILL.md +98 -74
- moai_adk/templates/.claude/skills/moai-domain-devops/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-devops/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/SKILL.md +102 -73
- moai_adk/templates/.claude/skills/moai-domain-frontend/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-domain-ml/SKILL.md +97 -73
- moai_adk/templates/.claude/skills/moai-domain-ml/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-ml/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-mobile-app/SKILL.md +97 -67
- moai_adk/templates/.claude/skills/moai-domain-mobile-app/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-mobile-app/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-security/SKILL.md +97 -79
- moai_adk/templates/.claude/skills/moai-domain-security/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-security/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-domain-web-api/SKILL.md +97 -71
- moai_adk/templates/.claude/skills/moai-domain-web-api/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-domain-web-api/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-essentials-debug/SKILL.md +265 -64
- moai_adk/templates/.claude/skills/moai-essentials-debug/examples.md +1064 -0
- moai_adk/templates/.claude/skills/moai-essentials-debug/reference.md +1047 -0
- moai_adk/templates/.claude/skills/moai-essentials-perf/SKILL.md +87 -78
- moai_adk/templates/.claude/skills/moai-essentials-perf/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-essentials-perf/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-essentials-refactor/SKILL.md +87 -70
- moai_adk/templates/.claude/skills/moai-essentials-refactor/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-essentials-refactor/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-essentials-review/SKILL.md +87 -86
- moai_adk/templates/.claude/skills/moai-essentials-review/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-essentials-review/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-foundation-ears/SKILL.md +80 -62
- moai_adk/templates/.claude/skills/moai-foundation-ears/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-ears/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-foundation-git/SKILL.md +207 -50
- moai_adk/templates/.claude/skills/moai-foundation-git/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-git/reference.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-langs/SKILL.md +90 -71
- moai_adk/templates/.claude/skills/moai-foundation-langs/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-langs/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-foundation-specs/SKILL.md +78 -58
- moai_adk/templates/.claude/skills/moai-foundation-specs/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-specs/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-foundation-tags/SKILL.md +78 -51
- moai_adk/templates/.claude/skills/moai-foundation-tags/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-foundation-tags/reference.md +28 -0
- moai_adk/templates/.claude/skills/moai-foundation-trust/.!11330!examples.md +0 -0
- moai_adk/templates/.claude/skills/moai-foundation-trust/SKILL.md +253 -32
- moai_adk/templates/.claude/skills/moai-foundation-trust/examples.md +0 -0
- moai_adk/templates/.claude/skills/moai-foundation-trust/reference.md +1099 -0
- moai_adk/templates/.claude/skills/moai-jit-docs-enhanced/SKILL.md +460 -0
- moai_adk/templates/.claude/skills/moai-lang-c/SKILL.md +98 -74
- moai_adk/templates/.claude/skills/moai-lang-c/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-c/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-cpp/SKILL.md +98 -76
- moai_adk/templates/.claude/skills/moai-lang-cpp/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-cpp/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/SKILL.md +2358 -70
- moai_adk/templates/.claude/skills/moai-lang-csharp/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-csharp/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-dart/SKILL.md +2962 -68
- moai_adk/templates/.claude/skills/moai-lang-dart/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-dart/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-go/SKILL.md +1898 -70
- moai_adk/templates/.claude/skills/moai-lang-go/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-go/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-java/SKILL.md +1465 -68
- moai_adk/templates/.claude/skills/moai-lang-java/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-java/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-javascript/SKILL.md +2364 -66
- moai_adk/templates/.claude/skills/moai-lang-javascript/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-javascript/reference.md +32 -0
- moai_adk/templates/.claude/skills/moai-lang-kotlin/SKILL.md +1630 -69
- moai_adk/templates/.claude/skills/moai-lang-kotlin/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-kotlin/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-php/SKILL.md +89 -61
- moai_adk/templates/.claude/skills/moai-lang-php/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-php/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-python/SKILL.md +735 -66
- moai_adk/templates/.claude/skills/moai-lang-python/examples.md +624 -0
- moai_adk/templates/.claude/skills/moai-lang-python/reference.md +316 -0
- moai_adk/templates/.claude/skills/moai-lang-r/SKILL.md +97 -73
- moai_adk/templates/.claude/skills/moai-lang-r/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-r/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-ruby/SKILL.md +98 -73
- moai_adk/templates/.claude/skills/moai-lang-ruby/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-ruby/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-rust/SKILL.md +1834 -70
- moai_adk/templates/.claude/skills/moai-lang-rust/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-rust/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-scala/SKILL.md +99 -74
- moai_adk/templates/.claude/skills/moai-lang-scala/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-scala/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-shell/SKILL.md +97 -74
- moai_adk/templates/.claude/skills/moai-lang-shell/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-shell/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-sql/SKILL.md +98 -74
- moai_adk/templates/.claude/skills/moai-lang-sql/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-sql/reference.md +31 -0
- moai_adk/templates/.claude/skills/moai-lang-swift/SKILL.md +1959 -69
- moai_adk/templates/.claude/skills/moai-lang-swift/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-swift/reference.md +30 -0
- moai_adk/templates/.claude/skills/moai-lang-template/SKILL.md +348 -0
- moai_adk/templates/.claude/skills/moai-lang-template/VARIABLES.md +98 -0
- moai_adk/templates/.claude/skills/moai-lang-typescript/SKILL.md +1230 -66
- moai_adk/templates/.claude/skills/moai-lang-typescript/examples.md +29 -0
- moai_adk/templates/.claude/skills/moai-lang-typescript/reference.md +34 -0
- moai_adk/templates/.claude/skills/moai-learning-optimizer/SKILL.md +575 -0
- moai_adk/templates/.claude/skills/moai-project-batch-questions/README.md +50 -0
- moai_adk/templates/.claude/skills/moai-project-batch-questions/SKILL.md +304 -0
- moai_adk/templates/.claude/skills/moai-project-batch-questions/examples.md +417 -0
- moai_adk/templates/.claude/skills/moai-project-batch-questions/reference.md +704 -0
- moai_adk/templates/.claude/skills/moai-project-config-manager/README.md +87 -0
- moai_adk/templates/.claude/skills/moai-project-config-manager/SKILL.md +552 -0
- moai_adk/templates/.claude/skills/moai-project-config-manager/examples.md +1109 -0
- moai_adk/templates/.claude/skills/moai-project-config-manager/reference.md +514 -0
- moai_adk/templates/.claude/skills/moai-project-config-manager/validate.py +106 -0
- moai_adk/templates/.claude/skills/moai-project-documentation/README.md +11 -0
- moai_adk/templates/.claude/skills/moai-project-documentation/SKILL.md +622 -0
- moai_adk/templates/.claude/skills/moai-project-documentation/examples.md +20 -0
- moai_adk/templates/.claude/skills/moai-project-documentation/reference.md +12 -0
- moai_adk/templates/.claude/skills/moai-project-language-initializer/README.md +152 -0
- moai_adk/templates/.claude/skills/moai-project-language-initializer/SKILL.md +285 -0
- moai_adk/templates/.claude/skills/moai-project-language-initializer/examples.md +333 -0
- moai_adk/templates/.claude/skills/moai-project-language-initializer/reference.md +386 -0
- moai_adk/templates/.claude/skills/moai-project-template-optimizer/README.md +49 -0
- moai_adk/templates/.claude/skills/moai-project-template-optimizer/SKILL.md +319 -0
- moai_adk/templates/.claude/skills/moai-project-template-optimizer/examples.md +58 -0
- moai_adk/templates/.claude/skills/moai-project-template-optimizer/reference.md +123 -0
- moai_adk/templates/.claude/skills/moai-session-info/SKILL.md +314 -0
- moai_adk/templates/.claude/skills/moai-streaming-ui/SKILL.md +552 -0
- moai_adk/templates/.claude/skills/moai-tag-policy-validator/SKILL.md +570 -0
- moai_adk/templates/.git-hooks/pre-commit +66 -0
- moai_adk/templates/.git-hooks/pre-push +255 -0
- moai_adk/templates/.github/workflows/c-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/cpp-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/csharp-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/dart-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/go-tag-validation.yml +130 -0
- moai_adk/templates/.github/workflows/java-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/javascript-tag-validation.yml +135 -0
- moai_adk/templates/.github/workflows/kotlin-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/moai-gitflow.yml +166 -3
- moai_adk/templates/.github/workflows/moai-release-create.yml +100 -0
- moai_adk/templates/.github/workflows/moai-release-pipeline.yml +188 -0
- moai_adk/templates/.github/workflows/php-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/python-tag-validation.yml +118 -0
- moai_adk/templates/.github/workflows/release.yml +118 -0
- moai_adk/templates/.github/workflows/ruby-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/rust-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/shell-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/spec-issue-sync.yml +338 -0
- moai_adk/templates/.github/workflows/swift-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/tag-report.yml +269 -0
- moai_adk/templates/.github/workflows/tag-validation.yml +186 -0
- moai_adk/templates/.github/workflows/typescript-tag-validation.yml +154 -0
- moai_adk/templates/.mcp.json +31 -0
- moai_adk/templates/.moai/config.json +80 -7
- moai_adk/templates/CLAUDE.md +562 -546
- moai_adk/utils/banner.py +5 -5
- moai_adk/utils/common.py +294 -0
- moai_adk/utils/link_validator.py +235 -0
- moai_adk/utils/logger.py +8 -8
- moai_adk/utils/user_experience.py +451 -0
- moai_adk-0.20.1.dist-info/METADATA +233 -0
- moai_adk-0.20.1.dist-info/RECORD +404 -0
- moai_adk/templates/.claude/hooks/alfred/README.md +0 -230
- moai_adk/templates/.claude/hooks/alfred/alfred_hooks.py +0 -156
- moai_adk/templates/.claude/hooks/alfred/core/__init__.py +0 -85
- moai_adk/templates/.claude/hooks/alfred/handlers/notification.py +0 -25
- moai_adk/templates/.claude/hooks/alfred/handlers/session.py +0 -92
- moai_adk/templates/.claude/hooks/alfred/handlers/tool.py +0 -70
- moai_adk/templates/.claude/hooks/alfred/handlers/user.py +0 -41
- moai_adk/templates/.claude/output-styles/alfred/agentic-coding.md +0 -636
- moai_adk/templates/.claude/output-styles/alfred/moai-adk-learning.md +0 -692
- moai_adk/templates/.claude/output-styles/alfred/study-with-alfred.md +0 -470
- moai_adk/templates/.claude/skills/moai-alfred-debugger-pro/SKILL.md +0 -103
- moai_adk/templates/.claude/skills/moai-alfred-ears-authoring/SKILL.md +0 -103
- moai_adk/templates/.claude/skills/moai-alfred-git-workflow/SKILL.md +0 -95
- moai_adk/templates/.claude/skills/moai-alfred-performance-optimizer/SKILL.md +0 -105
- moai_adk/templates/.claude/skills/moai-alfred-refactoring-coach/SKILL.md +0 -97
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-validation/SKILL.md +0 -97
- moai_adk/templates/.claude/skills/moai-alfred-tag-scanning/SKILL.md +0 -90
- moai_adk/templates/.claude/skills/moai-alfred-trust-validation/SKILL.md +0 -99
- moai_adk/templates/.claude/skills/moai-alfred-tui-survey/SKILL.md +0 -87
- moai_adk/templates/.claude/skills/moai-alfred-tui-survey/examples.md +0 -62
- moai_adk/templates/.claude/skills/moai-claude-code/SKILL.md +0 -94
- moai_adk/templates/.claude/skills/moai-claude-code/examples.md +0 -513
- moai_adk/templates/.claude/skills/moai-claude-code/reference.md +0 -433
- moai_adk/templates/.claude/skills/moai-claude-code/templates/agent-full.md +0 -332
- moai_adk/templates/.claude/skills/moai-claude-code/templates/command-full.md +0 -384
- moai_adk/templates/.claude/skills/moai-claude-code/templates/plugin-full.json +0 -363
- moai_adk/templates/.claude/skills/moai-claude-code/templates/settings-full.json +0 -595
- moai_adk/templates/.claude/skills/moai-claude-code/templates/skill-full.md +0 -496
- moai_adk/templates/.claude/skills/moai-lang-clojure/SKILL.md +0 -100
- moai_adk/templates/.claude/skills/moai-lang-elixir/SKILL.md +0 -99
- moai_adk/templates/.claude/skills/moai-lang-haskell/SKILL.md +0 -100
- moai_adk/templates/.claude/skills/moai-lang-julia/SKILL.md +0 -98
- moai_adk/templates/.claude/skills/moai-lang-lua/SKILL.md +0 -98
- moai_adk/templates/.github/PULL_REQUEST_TEMPLATE.md +0 -69
- moai_adk/templates/.moai/memory/development-guide.md +0 -344
- moai_adk/templates/.moai/memory/gitflow-protection-policy.md +0 -220
- moai_adk/templates/.moai/memory/spec-metadata.md +0 -356
- moai_adk/templates/.moai/project/product.md +0 -161
- moai_adk/templates/.moai/project/structure.md +0 -156
- moai_adk/templates/.moai/project/tech.md +0 -227
- moai_adk/templates/__init__.py +0 -2
- moai_adk-0.4.5.dist-info/METADATA +0 -369
- moai_adk-0.4.5.dist-info/RECORD +0 -152
- {moai_adk-0.4.5.dist-info â moai_adk-0.20.1.dist-info}/WHEEL +0 -0
- {moai_adk-0.4.5.dist-info â moai_adk-0.20.1.dist-info}/entry_points.txt +0 -0
- {moai_adk-0.4.5.dist-info â moai_adk-0.20.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# @CODE:HOOKS-CLARITY-CLEAN | SPEC: Daily analysis handler with self-learning
|
|
3
|
+
"""Daily Analysis Handler: Trigger daily session analysis and self-learning
|
|
4
|
+
|
|
5
|
+
This handler implements daily session analysis with self-learning capabilities
|
|
6
|
+
for continuous improvement and adaptation of Claude Code usage patterns.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any, Dict
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class AnalysisResult:
|
|
18
|
+
"""Result of daily analysis operation"""
|
|
19
|
+
continue_execution: bool = True
|
|
20
|
+
analysis_completed: bool = False
|
|
21
|
+
days_since_last_analysis: int = 0
|
|
22
|
+
report_path: str = ""
|
|
23
|
+
message: str = ""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def handle_daily_analysis(session_data: Dict[str, Any]) -> AnalysisResult:
|
|
27
|
+
"""Handle daily session analysis
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
session_data: Session start data from Claude Code
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
AnalysisResult: Analysis operation result
|
|
34
|
+
"""
|
|
35
|
+
project_root = Path(session_data.get("projectPath", "."))
|
|
36
|
+
moai_dir = project_root / ".moai"
|
|
37
|
+
|
|
38
|
+
if not moai_dir.exists():
|
|
39
|
+
return AnalysisResult(
|
|
40
|
+
message="No .moai directory found - skipping daily analysis"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# Check last analysis date
|
|
44
|
+
last_analysis_file = moai_dir / "last_analysis_date.json"
|
|
45
|
+
cutoff_days = 1 # Run analysis every day
|
|
46
|
+
|
|
47
|
+
today = datetime.now()
|
|
48
|
+
last_analysis_date = None
|
|
49
|
+
|
|
50
|
+
if last_analysis_file.exists():
|
|
51
|
+
try:
|
|
52
|
+
last_data = json.loads(last_analysis_file.read_text(encoding="utf-8"))
|
|
53
|
+
last_analysis_str = last_data.get("last_analysis_date")
|
|
54
|
+
if last_analysis_str:
|
|
55
|
+
last_analysis_date = datetime.fromisoformat(last_analysis_str)
|
|
56
|
+
except (json.JSONDecodeError, ValueError, KeyError):
|
|
57
|
+
pass # If file is corrupt, ignore and proceed
|
|
58
|
+
|
|
59
|
+
days_since_last = (today - last_analysis_date).days if last_analysis_date else 999
|
|
60
|
+
|
|
61
|
+
if days_since_last < cutoff_days:
|
|
62
|
+
return AnalysisResult(
|
|
63
|
+
analysis_completed=False,
|
|
64
|
+
days_since_last_analysis=days_since_last,
|
|
65
|
+
message=f"Analysis not due yet (last: {days_since_last} days ago)"
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Run analysis
|
|
69
|
+
return _run_daily_analysis(project_root, moai_dir, today)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _run_daily_analysis(project_root: Path, moai_dir: Path, analysis_date: datetime) -> AnalysisResult:
|
|
73
|
+
"""Run the actual daily analysis
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
project_root: Project root directory
|
|
77
|
+
moai_dir: .moai directory
|
|
78
|
+
analysis_date: Current analysis date
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
AnalysisResult: Analysis operation result
|
|
82
|
+
"""
|
|
83
|
+
try:
|
|
84
|
+
# Import session analyzer from moai-adk package
|
|
85
|
+
from moai_adk.core.analysis import SessionAnalyzer
|
|
86
|
+
|
|
87
|
+
# Create analyzer for last 1 day
|
|
88
|
+
analyzer = SessionAnalyzer(days_back=1, verbose=False)
|
|
89
|
+
|
|
90
|
+
# Run analysis
|
|
91
|
+
analysis_results = analyzer.parse_sessions()
|
|
92
|
+
|
|
93
|
+
# Generate report
|
|
94
|
+
reports_dir = moai_dir / "reports"
|
|
95
|
+
reports_dir.mkdir(exist_ok=True)
|
|
96
|
+
|
|
97
|
+
report_filename = f"daily-{analysis_date.strftime('%Y-%m-%d')}.md"
|
|
98
|
+
report_path = reports_dir / report_filename
|
|
99
|
+
|
|
100
|
+
# Generate report content
|
|
101
|
+
report_content = _generate_daily_report(analysis_results, analysis_date)
|
|
102
|
+
report_path.write_text(report_content, encoding="utf-8")
|
|
103
|
+
|
|
104
|
+
# Update last analysis date
|
|
105
|
+
last_analysis_file = moai_dir / "last_analysis_date.json"
|
|
106
|
+
last_analysis_data = {
|
|
107
|
+
"last_analysis_date": analysis_date.isoformat(),
|
|
108
|
+
"report_file": report_filename,
|
|
109
|
+
"metrics": {
|
|
110
|
+
"total_sessions": analysis_results.get("total_sessions", 0),
|
|
111
|
+
"total_events": analysis_results.get("total_events", 0),
|
|
112
|
+
"success_rate": analysis_results.get("success_rate", 0.0)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
last_analysis_file.write_text(json.dumps(last_analysis_data, indent=2), encoding="utf-8")
|
|
116
|
+
|
|
117
|
+
# Self-learning: Store patterns and insights
|
|
118
|
+
_store_learning_patterns(moai_dir, analysis_results, analysis_date)
|
|
119
|
+
|
|
120
|
+
return AnalysisResult(
|
|
121
|
+
continue_execution=True,
|
|
122
|
+
analysis_completed=True,
|
|
123
|
+
days_since_last_analysis=1,
|
|
124
|
+
report_path=str(report_path.relative_to(project_root)),
|
|
125
|
+
message=f"Daily analysis completed: {len(analysis_results.get('tool_usage', {}))} tools analyzed"
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
except Exception as e:
|
|
129
|
+
return AnalysisResult(
|
|
130
|
+
analysis_completed=False,
|
|
131
|
+
message=f"Analysis failed: {str(e)}"
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _generate_daily_report(analysis_results: Dict[str, Any], analysis_date: datetime) -> str:
|
|
136
|
+
"""Generate daily analysis report content
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
analysis_results: Results from session analysis
|
|
140
|
+
analysis_date: Analysis date
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
str: Markdown report content
|
|
144
|
+
"""
|
|
145
|
+
report_lines = [
|
|
146
|
+
"# Daily Session Analysis Report",
|
|
147
|
+
"",
|
|
148
|
+
f"**Analysis Date**: {analysis_date.strftime('%Y-%m-%d %H:%M:%S')}",
|
|
149
|
+
"**Analysis Period**: Last 24 hours",
|
|
150
|
+
"",
|
|
151
|
+
"## Summary Metrics",
|
|
152
|
+
"",
|
|
153
|
+
f"- **Total Sessions**: {analysis_results.get('total_sessions', 0)}",
|
|
154
|
+
f"- **Total Events**: {analysis_results.get('total_events', 0)}",
|
|
155
|
+
f"- **Success Rate**: {analysis_results.get('success_rate', 0):.1%}",
|
|
156
|
+
f"- **Failed Sessions**: {analysis_results.get('failed_sessions', 0)}",
|
|
157
|
+
"",
|
|
158
|
+
"## Tool Usage",
|
|
159
|
+
""
|
|
160
|
+
]
|
|
161
|
+
|
|
162
|
+
tool_usage = analysis_results.get("tool_usage", {})
|
|
163
|
+
if tool_usage:
|
|
164
|
+
for tool, count in sorted(tool_usage.items(), key=lambda x: x[1], reverse=True)[:10]:
|
|
165
|
+
report_lines.append(f"- **{tool}**: {count} uses")
|
|
166
|
+
|
|
167
|
+
report_lines.extend([
|
|
168
|
+
"",
|
|
169
|
+
"## Error Patterns",
|
|
170
|
+
""
|
|
171
|
+
])
|
|
172
|
+
|
|
173
|
+
error_patterns = analysis_results.get("error_patterns", {})
|
|
174
|
+
if error_patterns:
|
|
175
|
+
for error, count in sorted(error_patterns.items(), key=lambda x: x[1], reverse=True)[:5]:
|
|
176
|
+
report_lines.append(f"- **{error}**: {count} occurrences")
|
|
177
|
+
else:
|
|
178
|
+
report_lines.append("- No error patterns detected")
|
|
179
|
+
|
|
180
|
+
report_lines.extend([
|
|
181
|
+
"",
|
|
182
|
+
"## Daily Insights",
|
|
183
|
+
"",
|
|
184
|
+
"1. Monitor tool usage patterns for daily optimization opportunities",
|
|
185
|
+
"2. Address any recurring error patterns immediately",
|
|
186
|
+
"3. Review frequently used tools for performance optimization",
|
|
187
|
+
"4. Track daily productivity and workflow efficiency",
|
|
188
|
+
"",
|
|
189
|
+
"---",
|
|
190
|
+
"*Generated by MoAI-ADK Daily Analysis*"
|
|
191
|
+
])
|
|
192
|
+
|
|
193
|
+
return "\n".join(report_lines)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
197
|
+
"""Convert AnalysisResult to dictionary for JSON serialization"""
|
|
198
|
+
return {
|
|
199
|
+
"continue": self.continue_execution,
|
|
200
|
+
"hookSpecificOutput": {
|
|
201
|
+
"analysis_completed": self.analysis_completed,
|
|
202
|
+
"days_since_last_analysis": self.days_since_last_analysis,
|
|
203
|
+
"report_path": self.report_path,
|
|
204
|
+
"message": self.message
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _store_learning_patterns(moai_dir: Path, analysis_results: Dict[str, Any], analysis_date: datetime) -> None:
|
|
210
|
+
"""Store daily analysis results for self-learning and pattern recognition
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
moai_dir: .moai directory
|
|
214
|
+
analysis_results: Results from session analysis
|
|
215
|
+
analysis_date: Analysis date
|
|
216
|
+
"""
|
|
217
|
+
memory_dir = moai_dir / "memory"
|
|
218
|
+
patterns_file = memory_dir / "daily-patterns.json"
|
|
219
|
+
|
|
220
|
+
# Load existing patterns
|
|
221
|
+
if patterns_file.exists():
|
|
222
|
+
patterns_data = json.loads(patterns_file.read_text(encoding="utf-8"))
|
|
223
|
+
else:
|
|
224
|
+
patterns_data = {
|
|
225
|
+
"version": "1.0.0",
|
|
226
|
+
"created_at": analysis_date.isoformat(),
|
|
227
|
+
"last_updated": analysis_date.isoformat(),
|
|
228
|
+
"patterns": {
|
|
229
|
+
"tool_usage": {},
|
|
230
|
+
"error_patterns": {},
|
|
231
|
+
"success_patterns": {},
|
|
232
|
+
"workflow_optimizations": {}
|
|
233
|
+
},
|
|
234
|
+
"insights": {
|
|
235
|
+
"most_used_tools": [],
|
|
236
|
+
"common_errors": [],
|
|
237
|
+
"optimization_suggestions": []
|
|
238
|
+
},
|
|
239
|
+
"metadata": {
|
|
240
|
+
"total_days_analyzed": 0,
|
|
241
|
+
"patterns_identified": 0,
|
|
242
|
+
"insights_generated": 0
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
# Update tool usage patterns
|
|
247
|
+
tool_usage = analysis_results.get("tool_usage", {})
|
|
248
|
+
for tool, count in tool_usage.items():
|
|
249
|
+
if tool not in patterns_data["patterns"]["tool_usage"]:
|
|
250
|
+
patterns_data["patterns"]["tool_usage"][tool] = []
|
|
251
|
+
patterns_data["patterns"]["tool_usage"][tool].append({
|
|
252
|
+
"date": analysis_date.isoformat(),
|
|
253
|
+
"count": count,
|
|
254
|
+
"type": "usage"
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
# Update error patterns
|
|
258
|
+
error_patterns = analysis_results.get("error_patterns", {})
|
|
259
|
+
for error, count in error_patterns.items():
|
|
260
|
+
if error not in patterns_data["patterns"]["error_patterns"]:
|
|
261
|
+
patterns_data["patterns"]["error_patterns"][error] = []
|
|
262
|
+
patterns_data["patterns"]["error_patterns"][error].append({
|
|
263
|
+
"date": analysis_date.isoformat(),
|
|
264
|
+
"count": count,
|
|
265
|
+
"type": "error"
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
# Update success rate patterns
|
|
269
|
+
success_rate = analysis_results.get("success_rate", 0.0)
|
|
270
|
+
if "daily_success_rates" not in patterns_data["patterns"]:
|
|
271
|
+
patterns_data["patterns"]["daily_success_rates"] = []
|
|
272
|
+
patterns_data["patterns"]["daily_success_rates"].append({
|
|
273
|
+
"date": analysis_date.isoformat(),
|
|
274
|
+
"rate": success_rate
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
# Generate insights
|
|
278
|
+
insights = _generate_insights(patterns_data, analysis_results)
|
|
279
|
+
patterns_data["insights"].update(insights)
|
|
280
|
+
|
|
281
|
+
# Update metadata
|
|
282
|
+
patterns_data["last_updated"] = analysis_date.isoformat()
|
|
283
|
+
patterns_data["metadata"]["total_days_analyzed"] += 1
|
|
284
|
+
patterns_data["metadata"]["patterns_identified"] = len(tool_usage) + len(error_patterns)
|
|
285
|
+
patterns_data["metadata"]["insights_generated"] = len([v for v in insights.values() if v])
|
|
286
|
+
|
|
287
|
+
# Save updated patterns
|
|
288
|
+
patterns_file.write_text(json.dumps(patterns_data, indent=2), encoding="utf-8")
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def _generate_insights(patterns_data: Dict[str, Any], current_results: Dict[str, Any]) -> Dict[str, Any]:
|
|
292
|
+
"""Generate insights from analysis patterns
|
|
293
|
+
|
|
294
|
+
Args:
|
|
295
|
+
patterns_data: Existing patterns data
|
|
296
|
+
current_results: Current day's analysis results
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
Dict[str, Any]: Generated insights
|
|
300
|
+
"""
|
|
301
|
+
insights = {}
|
|
302
|
+
|
|
303
|
+
# Most used tools insight
|
|
304
|
+
tool_usage = current_results.get("tool_usage", {})
|
|
305
|
+
if tool_usage:
|
|
306
|
+
most_used = max(tool_usage.items(), key=lambda x: x[1])
|
|
307
|
+
insights["most_used_tools"] = [{
|
|
308
|
+
"tool": most_used[0],
|
|
309
|
+
"count": most_used[1],
|
|
310
|
+
"date": datetime.now().isoformat()
|
|
311
|
+
}]
|
|
312
|
+
|
|
313
|
+
# Common errors insight
|
|
314
|
+
error_patterns = current_results.get("error_patterns", {})
|
|
315
|
+
if error_patterns:
|
|
316
|
+
most_common_error = max(error_patterns.items(), key=lambda x: x[1])
|
|
317
|
+
insights["common_errors"] = [{
|
|
318
|
+
"error": most_common_error[0],
|
|
319
|
+
"count": most_common_error[1],
|
|
320
|
+
"date": datetime.now().isoformat()
|
|
321
|
+
}]
|
|
322
|
+
|
|
323
|
+
# Optimization suggestions
|
|
324
|
+
suggestions = []
|
|
325
|
+
|
|
326
|
+
# Suggest optimization for frequently used tools
|
|
327
|
+
if tool_usage:
|
|
328
|
+
top_tools = sorted(tool_usage.items(), key=lambda x: x[1], reverse=True)[:3]
|
|
329
|
+
suggestions.append({
|
|
330
|
+
"type": "tool_optimization",
|
|
331
|
+
"description": f"Focus on optimizing {top_tools[0][0]} usage ({top_tools[0][1]} uses)",
|
|
332
|
+
"priority": "high"
|
|
333
|
+
})
|
|
334
|
+
|
|
335
|
+
# Suggest error resolution
|
|
336
|
+
if error_patterns:
|
|
337
|
+
for error, count in error_patterns.items():
|
|
338
|
+
if count >= 3: # Errors occurring 3+ times
|
|
339
|
+
suggestions.append({
|
|
340
|
+
"type": "error_resolution",
|
|
341
|
+
"description": f"Address recurring error: {error} ({count} occurrences)",
|
|
342
|
+
"priority": "critical"
|
|
343
|
+
})
|
|
344
|
+
|
|
345
|
+
insights["optimization_suggestions"] = suggestions
|
|
346
|
+
|
|
347
|
+
return insights
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
# Add to_dict method to AnalysisResult
|
|
351
|
+
AnalysisResult.to_dict = to_dict
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Notification and control handlers
|
|
3
|
+
|
|
4
|
+
Notification, Stop, SubagentStop event handling
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from core import HookPayload, HookResult
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _get_command_state_file(cwd: str) -> Path:
|
|
15
|
+
"""Get the path to command state tracking file"""
|
|
16
|
+
state_dir = Path(cwd) / ".moai" / "memory"
|
|
17
|
+
state_dir.mkdir(parents=True, exist_ok=True)
|
|
18
|
+
return state_dir / "command-execution-state.json"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _load_command_state(cwd: str) -> dict:
|
|
22
|
+
"""Load current command execution state"""
|
|
23
|
+
try:
|
|
24
|
+
state_file = _get_command_state_file(cwd)
|
|
25
|
+
if state_file.exists():
|
|
26
|
+
with open(state_file, "r", encoding="utf-8") as f:
|
|
27
|
+
return json.load(f)
|
|
28
|
+
except Exception:
|
|
29
|
+
pass
|
|
30
|
+
return {"last_command": None, "last_timestamp": None, "is_running": False}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _save_command_state(cwd: str, state: dict) -> None:
|
|
34
|
+
"""Save command execution state"""
|
|
35
|
+
try:
|
|
36
|
+
state_file = _get_command_state_file(cwd)
|
|
37
|
+
with open(state_file, "w", encoding="utf-8") as f:
|
|
38
|
+
json.dump(state, f, indent=2)
|
|
39
|
+
except Exception:
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _is_duplicate_command(current_cmd: str, last_cmd: str, last_timestamp: str) -> bool:
|
|
44
|
+
"""Check if current command is a duplicate of the last one within 3 seconds"""
|
|
45
|
+
if not last_cmd or not last_timestamp or current_cmd != last_cmd:
|
|
46
|
+
return False
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
last_time = datetime.fromisoformat(last_timestamp)
|
|
50
|
+
current_time = datetime.now()
|
|
51
|
+
time_diff = (current_time - last_time).total_seconds()
|
|
52
|
+
# Consider it a duplicate if same command within 3 seconds
|
|
53
|
+
return time_diff < 3
|
|
54
|
+
except Exception:
|
|
55
|
+
return False
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def handle_notification(payload: HookPayload) -> HookResult:
|
|
59
|
+
"""Notification event handler
|
|
60
|
+
|
|
61
|
+
Detects and warns about duplicate command executions
|
|
62
|
+
(When the same /alfred: command is triggered multiple times within 3 seconds)
|
|
63
|
+
"""
|
|
64
|
+
cwd = payload.get("cwd", ".")
|
|
65
|
+
notification = payload.get("notification", {})
|
|
66
|
+
|
|
67
|
+
# Extract command information from notification
|
|
68
|
+
current_cmd = None
|
|
69
|
+
if isinstance(notification, dict):
|
|
70
|
+
# Check if notification contains command information
|
|
71
|
+
text = notification.get("text", "") or str(notification)
|
|
72
|
+
if "/alfred:" in text:
|
|
73
|
+
# Extract /alfred: command
|
|
74
|
+
import re
|
|
75
|
+
|
|
76
|
+
match = re.search(r"/alfred:\S+", text)
|
|
77
|
+
if match:
|
|
78
|
+
current_cmd = match.group()
|
|
79
|
+
|
|
80
|
+
if not current_cmd:
|
|
81
|
+
return HookResult()
|
|
82
|
+
|
|
83
|
+
# Load current state
|
|
84
|
+
state = _load_command_state(cwd)
|
|
85
|
+
last_cmd = state.get("last_command")
|
|
86
|
+
last_timestamp = state.get("last_timestamp")
|
|
87
|
+
|
|
88
|
+
# Check for duplicate
|
|
89
|
+
if _is_duplicate_command(current_cmd, last_cmd, last_timestamp):
|
|
90
|
+
warning_msg = (
|
|
91
|
+
f"â ī¸ Duplicate command detected: '{current_cmd}' "
|
|
92
|
+
f"is running multiple times within 3 seconds.\n"
|
|
93
|
+
f"This may indicate a system issue. Check logs in `.moai/logs/command-invocations.log`"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# Update state - mark as duplicate detected
|
|
97
|
+
state["duplicate_detected"] = True
|
|
98
|
+
state["duplicate_command"] = current_cmd
|
|
99
|
+
state["duplicate_timestamp"] = datetime.now().isoformat()
|
|
100
|
+
_save_command_state(cwd, state)
|
|
101
|
+
|
|
102
|
+
return HookResult(system_message=warning_msg, continue_execution=True)
|
|
103
|
+
|
|
104
|
+
# Update state with current command
|
|
105
|
+
state["last_command"] = current_cmd
|
|
106
|
+
state["last_timestamp"] = datetime.now().isoformat()
|
|
107
|
+
state["is_running"] = True
|
|
108
|
+
state["duplicate_detected"] = False
|
|
109
|
+
_save_command_state(cwd, state)
|
|
110
|
+
|
|
111
|
+
return HookResult()
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def handle_stop(payload: HookPayload) -> HookResult:
|
|
115
|
+
"""Stop event handler
|
|
116
|
+
|
|
117
|
+
Marks command execution as complete
|
|
118
|
+
"""
|
|
119
|
+
cwd = payload.get("cwd", ".")
|
|
120
|
+
state = _load_command_state(cwd)
|
|
121
|
+
state["is_running"] = False
|
|
122
|
+
state["last_timestamp"] = datetime.now().isoformat()
|
|
123
|
+
_save_command_state(cwd, state)
|
|
124
|
+
|
|
125
|
+
return HookResult()
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def handle_subagent_stop(payload: HookPayload) -> HookResult:
|
|
129
|
+
"""SubagentStop event handler
|
|
130
|
+
|
|
131
|
+
Records when a sub-agent finishes execution
|
|
132
|
+
"""
|
|
133
|
+
cwd = payload.get("cwd", ".")
|
|
134
|
+
|
|
135
|
+
# Extract subagent name if available
|
|
136
|
+
subagent_name = (
|
|
137
|
+
payload.get("subagent", {}).get("name")
|
|
138
|
+
if isinstance(payload.get("subagent"), dict)
|
|
139
|
+
else None
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
state_file = _get_command_state_file(cwd).parent / "subagent-execution.log"
|
|
144
|
+
timestamp = datetime.now().isoformat()
|
|
145
|
+
|
|
146
|
+
with open(state_file, "a", encoding="utf-8") as f:
|
|
147
|
+
f.write(f"{timestamp} | Subagent Stop | {subagent_name}\n")
|
|
148
|
+
except Exception:
|
|
149
|
+
pass
|
|
150
|
+
|
|
151
|
+
return HookResult()
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
__all__ = ["handle_notification", "handle_stop", "handle_subagent_stop"]
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Session event handlers
|
|
3
|
+
|
|
4
|
+
SessionStart, SessionEnd event handling
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from core import HookPayload, HookResult
|
|
8
|
+
from core.checkpoint import list_checkpoints
|
|
9
|
+
from core.project import count_specs, get_git_info, get_package_version_info
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def handle_session_start(payload: HookPayload) -> HookResult:
|
|
13
|
+
"""SessionStart event handler with GRACEFUL DEGRADATION
|
|
14
|
+
|
|
15
|
+
When Claude Code Session starts, it displays a summary of project status.
|
|
16
|
+
You can check the language, Git status, SPEC progress, and checkpoint list at a glance.
|
|
17
|
+
All optional operations are wrapped in try-except to ensure hook completes quickly even if
|
|
18
|
+
Git commands, file I/O, or other operations timeout or fail.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
payload: Claude Code event payload (cwd key required)
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
HookResult(system_message=project status summary message)
|
|
25
|
+
|
|
26
|
+
Message Format:
|
|
27
|
+
đ MoAI-ADK Session Started
|
|
28
|
+
[Version: {version}] - optional if version check fails
|
|
29
|
+
[Branch: {branch} ({commit hash})] - optional if git fails
|
|
30
|
+
[Changes: {Number of Changed Files}] - optional if git fails
|
|
31
|
+
[SPEC Progress: {Complete}/{Total} ({percent}%)] - optional if specs fail
|
|
32
|
+
[Checkpoints: {number} available] - optional if checkpoint list fails
|
|
33
|
+
|
|
34
|
+
Graceful Degradation Strategy:
|
|
35
|
+
- OPTIONAL: Version info (skip if timeout/failure)
|
|
36
|
+
- OPTIONAL: Git info (skip if timeout/failure)
|
|
37
|
+
- OPTIONAL: SPEC progress (skip if timeout/failure)
|
|
38
|
+
- OPTIONAL: Checkpoint list (skip if timeout/failure)
|
|
39
|
+
- Always display SOMETHING to user, never return empty message
|
|
40
|
+
|
|
41
|
+
Note:
|
|
42
|
+
- Claude Code processes SessionStart in several stages (clear â compact)
|
|
43
|
+
- Display message only at "compact" stage to prevent duplicate output
|
|
44
|
+
- "clear" step returns minimal result (empty hookSpecificOutput)
|
|
45
|
+
- CRITICAL: All optional operations must complete within 2-3 seconds total
|
|
46
|
+
|
|
47
|
+
TDD History:
|
|
48
|
+
- RED: Session startup message format test
|
|
49
|
+
- GREEN: Generate status message by combining helper functions
|
|
50
|
+
- REFACTOR: Improved message format, improved readability, added checkpoint list
|
|
51
|
+
- FIX: Prevent duplicate output of clear step (only compact step is displayed)
|
|
52
|
+
- UPDATE: Migrated to Claude Code standard Hook schema
|
|
53
|
+
- HOTFIX: Add graceful degradation for timeout scenarios (Issue #66)
|
|
54
|
+
- Phase 3: Add major version warning and release notes display (@TEST:MAJOR-UPDATE-001-07/08)
|
|
55
|
+
|
|
56
|
+
@TAG:CHECKPOINT-EVENT-001
|
|
57
|
+
@TAG:HOOKS-TIMEOUT-001
|
|
58
|
+
@CODE:MAJOR-UPDATE-WARN-001
|
|
59
|
+
"""
|
|
60
|
+
# Claude Code SessionStart runs in several stages (clear, compact, etc.)
|
|
61
|
+
# Ignore the "clear" stage and output messages only at the "compact" stage
|
|
62
|
+
event_phase = payload.get("phase", "")
|
|
63
|
+
if event_phase == "clear":
|
|
64
|
+
# Return minimal valid Hook result for clear phase
|
|
65
|
+
return HookResult(continue_execution=True)
|
|
66
|
+
|
|
67
|
+
cwd = payload.get("cwd", ".")
|
|
68
|
+
|
|
69
|
+
# OPTIONAL: Git info - skip if timeout/failure
|
|
70
|
+
git_info = {}
|
|
71
|
+
try:
|
|
72
|
+
git_info = get_git_info(cwd)
|
|
73
|
+
except Exception:
|
|
74
|
+
# Graceful degradation - continue without git info
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
# OPTIONAL: SPEC progress - skip if timeout/failure
|
|
78
|
+
specs = {"completed": 0, "total": 0, "percentage": 0}
|
|
79
|
+
try:
|
|
80
|
+
specs = count_specs(cwd)
|
|
81
|
+
except Exception:
|
|
82
|
+
# Graceful degradation - continue without spec info
|
|
83
|
+
pass
|
|
84
|
+
|
|
85
|
+
# OPTIONAL: Checkpoint list - skip if timeout/failure
|
|
86
|
+
checkpoints = []
|
|
87
|
+
try:
|
|
88
|
+
checkpoints = list_checkpoints(cwd, max_count=10)
|
|
89
|
+
except Exception:
|
|
90
|
+
# Graceful degradation - continue without checkpoints
|
|
91
|
+
pass
|
|
92
|
+
|
|
93
|
+
# OPTIONAL: Package version info - skip if timeout/failure
|
|
94
|
+
version_info = {}
|
|
95
|
+
try:
|
|
96
|
+
version_info = get_package_version_info()
|
|
97
|
+
except Exception:
|
|
98
|
+
# Graceful degradation - continue without version info
|
|
99
|
+
pass
|
|
100
|
+
|
|
101
|
+
# Build message with available information
|
|
102
|
+
branch = git_info.get("branch", "N/A") if git_info else "N/A"
|
|
103
|
+
commit = git_info.get("commit", "N/A")[:7] if git_info else "N/A"
|
|
104
|
+
changes = git_info.get("changes", 0) if git_info else 0
|
|
105
|
+
spec_progress = f"{specs['completed']}/{specs['total']}" if specs["total"] > 0 else "0/0"
|
|
106
|
+
|
|
107
|
+
# system_message: displayed directly to the user
|
|
108
|
+
lines = [
|
|
109
|
+
"đ MoAI-ADK Session Started",
|
|
110
|
+
"", # Blank line after title
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
# Add version info first (at the top, right after title)
|
|
114
|
+
if version_info and version_info.get("current") != "unknown":
|
|
115
|
+
if version_info.get("update_available"):
|
|
116
|
+
# Check if this is a major version update
|
|
117
|
+
if version_info.get("is_major_update"):
|
|
118
|
+
# Major version warning
|
|
119
|
+
lines.append(
|
|
120
|
+
f" â ī¸ Major version update available: {version_info['current']} â {version_info['latest']}"
|
|
121
|
+
)
|
|
122
|
+
lines.append(" Breaking changes detected. Review release notes:")
|
|
123
|
+
if version_info.get("release_notes_url"):
|
|
124
|
+
lines.append(f" đ {version_info['release_notes_url']}")
|
|
125
|
+
else:
|
|
126
|
+
# Regular update
|
|
127
|
+
lines.append(
|
|
128
|
+
f" đŋ MoAI-ADK Ver: {version_info['current']} â {version_info['latest']} available â¨"
|
|
129
|
+
)
|
|
130
|
+
if version_info.get("release_notes_url"):
|
|
131
|
+
lines.append(f" đ Release Notes: {version_info['release_notes_url']}")
|
|
132
|
+
|
|
133
|
+
# Add upgrade recommendation
|
|
134
|
+
if version_info.get("upgrade_command"):
|
|
135
|
+
lines.append(f" âŦī¸ Upgrade: {version_info['upgrade_command']}")
|
|
136
|
+
else:
|
|
137
|
+
# No update available - show current version only
|
|
138
|
+
lines.append(f" đŋ MoAI-ADK Ver: {version_info['current']}")
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# Add Git info only if available (not degraded)
|
|
142
|
+
if git_info:
|
|
143
|
+
lines.append(f" đŋ Branch: {branch} ({commit})")
|
|
144
|
+
lines.append(f" đ Changes: {changes}")
|
|
145
|
+
|
|
146
|
+
# Add last commit message if available
|
|
147
|
+
last_commit = git_info.get("last_commit", "")
|
|
148
|
+
if last_commit:
|
|
149
|
+
lines.append(f" đ¨ Last: {last_commit}")
|
|
150
|
+
|
|
151
|
+
# Add Checkpoint list (show only the latest 3 items)
|
|
152
|
+
if checkpoints:
|
|
153
|
+
lines.append(f" đī¸ Checkpoints: {len(checkpoints)} available")
|
|
154
|
+
for cp in reversed(checkpoints[-3:]): # Latest 3 items
|
|
155
|
+
branch_short = cp["branch"].replace("before-", "")
|
|
156
|
+
lines.append(f" đ {branch_short}")
|
|
157
|
+
lines.append("") # Blank line before restore command
|
|
158
|
+
lines.append(" âŠī¸ Restore: /alfred:0-project restore")
|
|
159
|
+
|
|
160
|
+
# Add SPEC progress only if available (not degraded) - at the bottom
|
|
161
|
+
if specs["total"] > 0:
|
|
162
|
+
lines.append(f" đ SPEC Progress: {spec_progress} ({specs['percentage']}%)")
|
|
163
|
+
|
|
164
|
+
system_message = "\n".join(lines)
|
|
165
|
+
|
|
166
|
+
return HookResult(system_message=system_message)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def handle_session_end(payload: HookPayload) -> HookResult:
|
|
170
|
+
"""SessionEnd event handler (default implementation)"""
|
|
171
|
+
return HookResult()
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
__all__ = ["handle_session_start", "handle_session_end"]
|