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,956 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# @CODE:DOC-TAG-004 | Component 4: Documentation & Reporting system
|
|
3
|
+
"""TAG reporting and documentation generation for MoAI-ADK
|
|
4
|
+
|
|
5
|
+
This module provides automated reporting for TAG system health and coverage:
|
|
6
|
+
- Generates TAG inventories across entire codebase
|
|
7
|
+
- Creates coverage matrices showing SPEC implementation status
|
|
8
|
+
- Analyzes SPEC→CODE→TEST→DOC chain completeness
|
|
9
|
+
- Produces statistics and metrics in multiple formats
|
|
10
|
+
- Formats reports as Markdown, JSON, CSV, and HTML (optional)
|
|
11
|
+
|
|
12
|
+
Architecture:
|
|
13
|
+
ReportGenerator (orchestrator)
|
|
14
|
+
├── InventoryGenerator (tag-inventory.md)
|
|
15
|
+
├── MatrixGenerator (tag-matrix.md)
|
|
16
|
+
├── CoverageAnalyzer (coverage analysis)
|
|
17
|
+
├── StatisticsGenerator (tag-statistics.json)
|
|
18
|
+
└── ReportFormatter (multi-format output)
|
|
19
|
+
|
|
20
|
+
Usage:
|
|
21
|
+
generator = ReportGenerator()
|
|
22
|
+
result = generator.generate_all_reports("/path/to/project", "/path/to/output")
|
|
23
|
+
print(f"Generated reports: {result.inventory_path}, {result.matrix_path}")
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
import json
|
|
27
|
+
import re
|
|
28
|
+
from dataclasses import dataclass, field
|
|
29
|
+
from datetime import datetime
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
from typing import Dict, List, Set
|
|
32
|
+
|
|
33
|
+
# ============================================================================
|
|
34
|
+
# Data Models
|
|
35
|
+
# ============================================================================
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class TagInventory:
|
|
39
|
+
"""Single TAG inventory item with metadata
|
|
40
|
+
|
|
41
|
+
Attributes:
|
|
42
|
+
tag_id: TAG identifier (e.g., "DOC-TAG-001")
|
|
43
|
+
file_path: File path where TAG is located
|
|
44
|
+
line_number: Line number of TAG
|
|
45
|
+
context: Surrounding code snippet
|
|
46
|
+
related_tags: List of related TAG strings
|
|
47
|
+
last_modified: Last modification timestamp
|
|
48
|
+
status: TAG status (active|deprecated|orphan|incomplete)
|
|
49
|
+
"""
|
|
50
|
+
tag_id: str
|
|
51
|
+
file_path: str
|
|
52
|
+
line_number: int
|
|
53
|
+
context: str
|
|
54
|
+
related_tags: List[str] = field(default_factory=list)
|
|
55
|
+
last_modified: datetime = field(default_factory=datetime.now)
|
|
56
|
+
status: str = "active"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass
|
|
60
|
+
class TagMatrix:
|
|
61
|
+
"""Coverage matrix showing implementation status
|
|
62
|
+
|
|
63
|
+
Attributes:
|
|
64
|
+
rows: Dict mapping SPEC ID to coverage status
|
|
65
|
+
{
|
|
66
|
+
"AUTH-001": {
|
|
67
|
+
"SPEC": True,
|
|
68
|
+
"CODE": True,
|
|
69
|
+
"TEST": False,
|
|
70
|
+
"DOC": False
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
completion_percentages: Dict mapping SPEC ID to completion percentage
|
|
74
|
+
"""
|
|
75
|
+
rows: Dict[str, Dict[str, bool]] = field(default_factory=dict)
|
|
76
|
+
completion_percentages: Dict[str, float] = field(default_factory=dict)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@dataclass
|
|
80
|
+
class CoverageMetrics:
|
|
81
|
+
"""Coverage metrics for a single SPEC
|
|
82
|
+
|
|
83
|
+
Attributes:
|
|
84
|
+
spec_id: SPEC identifier
|
|
85
|
+
has_code: Whether CODE implementation exists
|
|
86
|
+
has_test: Whether TEST exists
|
|
87
|
+
has_doc: Whether DOC exists
|
|
88
|
+
coverage_percentage: Overall completion percentage
|
|
89
|
+
"""
|
|
90
|
+
spec_id: str
|
|
91
|
+
has_code: bool = False
|
|
92
|
+
has_test: bool = False
|
|
93
|
+
has_doc: bool = False
|
|
94
|
+
coverage_percentage: float = 0.0
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@dataclass
|
|
98
|
+
class StatisticsReport:
|
|
99
|
+
"""Overall TAG statistics
|
|
100
|
+
|
|
101
|
+
Attributes:
|
|
102
|
+
generated_at: Report generation timestamp
|
|
103
|
+
total_tags: Total TAG count
|
|
104
|
+
by_type: Count by TAG type (SPEC, CODE, TEST, DOC)
|
|
105
|
+
by_domain: Count by domain (AUTH, USER, etc.)
|
|
106
|
+
coverage: Coverage metrics
|
|
107
|
+
issues: Issue counts (orphans, incomplete chains, etc.)
|
|
108
|
+
"""
|
|
109
|
+
generated_at: datetime
|
|
110
|
+
total_tags: int
|
|
111
|
+
by_type: Dict[str, int] = field(default_factory=dict)
|
|
112
|
+
by_domain: Dict[str, int] = field(default_factory=dict)
|
|
113
|
+
coverage: Dict[str, float] = field(default_factory=dict)
|
|
114
|
+
issues: Dict[str, int] = field(default_factory=dict)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@dataclass
|
|
118
|
+
class ReportResult:
|
|
119
|
+
"""Result of report generation
|
|
120
|
+
|
|
121
|
+
Attributes:
|
|
122
|
+
inventory_path: Path to generated inventory file
|
|
123
|
+
matrix_path: Path to generated matrix file
|
|
124
|
+
statistics_path: Path to generated statistics file
|
|
125
|
+
success: Whether generation succeeded
|
|
126
|
+
error_message: Error message if failed
|
|
127
|
+
"""
|
|
128
|
+
inventory_path: Path
|
|
129
|
+
matrix_path: Path
|
|
130
|
+
statistics_path: Path
|
|
131
|
+
success: bool = True
|
|
132
|
+
error_message: str = ""
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
# ============================================================================
|
|
136
|
+
# Core Generators
|
|
137
|
+
# ============================================================================
|
|
138
|
+
|
|
139
|
+
class InventoryGenerator:
|
|
140
|
+
"""Generates TAG inventory across codebase
|
|
141
|
+
|
|
142
|
+
Scans entire codebase for TAGs and creates comprehensive inventory
|
|
143
|
+
grouped by domain and type.
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
TAG_PATTERN = re.compile(r"@(SPEC|CODE|TEST|DOC):([A-Z]+(?:-[A-Z]+)*-\d{3})")
|
|
147
|
+
IGNORE_PATTERNS = [".git/*", "node_modules/*", "__pycache__/*", "*.pyc", ".venv/*", "venv/*"]
|
|
148
|
+
|
|
149
|
+
def generate_inventory(self, root_path: str) -> List[TagInventory]:
|
|
150
|
+
"""Scan directory and generate TAG inventory
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
root_path: Root directory to scan
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
List of TagInventory objects
|
|
157
|
+
"""
|
|
158
|
+
inventory: list[TagInventory] = []
|
|
159
|
+
root = Path(root_path)
|
|
160
|
+
|
|
161
|
+
if not root.exists() or not root.is_dir():
|
|
162
|
+
return inventory
|
|
163
|
+
|
|
164
|
+
# Scan all files recursively
|
|
165
|
+
for filepath in root.rglob("*"):
|
|
166
|
+
if not filepath.is_file():
|
|
167
|
+
continue
|
|
168
|
+
|
|
169
|
+
# Check ignore patterns
|
|
170
|
+
if self._should_ignore(filepath, root):
|
|
171
|
+
continue
|
|
172
|
+
|
|
173
|
+
# Extract TAGs from file
|
|
174
|
+
tags = self._extract_tags_from_file(filepath, root)
|
|
175
|
+
inventory.extend(tags)
|
|
176
|
+
|
|
177
|
+
return inventory
|
|
178
|
+
|
|
179
|
+
def _should_ignore(self, filepath: Path, root: Path) -> bool:
|
|
180
|
+
"""Check if file should be ignored
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
filepath: File path to check
|
|
184
|
+
root: Root directory
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
True if file should be ignored
|
|
188
|
+
"""
|
|
189
|
+
try:
|
|
190
|
+
relative = filepath.relative_to(root)
|
|
191
|
+
relative_str = str(relative)
|
|
192
|
+
|
|
193
|
+
for pattern in self.IGNORE_PATTERNS:
|
|
194
|
+
pattern_clean = pattern.replace("/*", "").replace("*", "")
|
|
195
|
+
if pattern_clean in relative_str:
|
|
196
|
+
return True
|
|
197
|
+
|
|
198
|
+
return False
|
|
199
|
+
|
|
200
|
+
except ValueError:
|
|
201
|
+
return True
|
|
202
|
+
|
|
203
|
+
def _extract_tags_from_file(self, filepath: Path, root: Path) -> List[TagInventory]:
|
|
204
|
+
"""Extract TAGs from a single file
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
filepath: File to scan
|
|
208
|
+
root: Root directory for relative paths
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
List of TagInventory objects
|
|
212
|
+
"""
|
|
213
|
+
inventory = []
|
|
214
|
+
|
|
215
|
+
try:
|
|
216
|
+
content = filepath.read_text(encoding="utf-8", errors="ignore")
|
|
217
|
+
lines = content.splitlines()
|
|
218
|
+
|
|
219
|
+
# Get file modification time
|
|
220
|
+
last_modified = datetime.fromtimestamp(filepath.stat().st_mtime)
|
|
221
|
+
|
|
222
|
+
for line_num, line in enumerate(lines, start=1):
|
|
223
|
+
matches = self.TAG_PATTERN.findall(line)
|
|
224
|
+
|
|
225
|
+
for tag_type, domain in matches:
|
|
226
|
+
tag_id = domain
|
|
227
|
+
|
|
228
|
+
# Extract context (±2 lines)
|
|
229
|
+
context_lines = []
|
|
230
|
+
for i in range(max(0, line_num - 3), min(len(lines), line_num + 2)):
|
|
231
|
+
if i < len(lines):
|
|
232
|
+
context_lines.append(lines[i])
|
|
233
|
+
context = "\n".join(context_lines)
|
|
234
|
+
|
|
235
|
+
# Create inventory item
|
|
236
|
+
relative_path = str(filepath.relative_to(root))
|
|
237
|
+
inventory.append(TagInventory(
|
|
238
|
+
tag_id=tag_id,
|
|
239
|
+
file_path=relative_path,
|
|
240
|
+
line_number=line_num,
|
|
241
|
+
context=context,
|
|
242
|
+
related_tags=[], # Will be populated later
|
|
243
|
+
last_modified=last_modified,
|
|
244
|
+
status="active"
|
|
245
|
+
))
|
|
246
|
+
|
|
247
|
+
except Exception:
|
|
248
|
+
pass
|
|
249
|
+
|
|
250
|
+
return inventory
|
|
251
|
+
|
|
252
|
+
def group_by_domain(self, inventory: List[TagInventory]) -> Dict[str, List[TagInventory]]:
|
|
253
|
+
"""Group inventory by domain
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
inventory: List of TagInventory objects
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
Dict mapping domain prefix to list of tags
|
|
260
|
+
"""
|
|
261
|
+
grouped: Dict[str, List[TagInventory]] = {}
|
|
262
|
+
|
|
263
|
+
for item in inventory:
|
|
264
|
+
# Extract domain prefix (e.g., "AUTH" from "AUTH-LOGIN-001")
|
|
265
|
+
parts = item.tag_id.split("-")
|
|
266
|
+
if parts:
|
|
267
|
+
domain = parts[0]
|
|
268
|
+
if domain not in grouped:
|
|
269
|
+
grouped[domain] = []
|
|
270
|
+
grouped[domain].append(item)
|
|
271
|
+
|
|
272
|
+
return grouped
|
|
273
|
+
|
|
274
|
+
def format_as_markdown(self, grouped: Dict[str, List[TagInventory]]) -> str:
|
|
275
|
+
"""Format grouped inventory as markdown
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
grouped: Grouped inventory dict
|
|
279
|
+
|
|
280
|
+
Returns:
|
|
281
|
+
Markdown-formatted string
|
|
282
|
+
"""
|
|
283
|
+
lines = []
|
|
284
|
+
lines.append("# TAG Inventory")
|
|
285
|
+
lines.append("")
|
|
286
|
+
lines.append(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
|
287
|
+
|
|
288
|
+
# Calculate totals
|
|
289
|
+
total_tags = sum(len(tags) for tags in grouped.values())
|
|
290
|
+
lines.append(f"Total TAGs: {total_tags}")
|
|
291
|
+
lines.append("")
|
|
292
|
+
|
|
293
|
+
# Group by domain
|
|
294
|
+
lines.append("## By Domain")
|
|
295
|
+
lines.append("")
|
|
296
|
+
|
|
297
|
+
for domain in sorted(grouped.keys()):
|
|
298
|
+
lines.append(f"### {domain}")
|
|
299
|
+
lines.append("")
|
|
300
|
+
|
|
301
|
+
for item in sorted(grouped[domain], key=lambda x: x.tag_id):
|
|
302
|
+
lines.append(f"- **{item.tag_id}** (`{item.file_path}:{item.line_number}`)")
|
|
303
|
+
|
|
304
|
+
lines.append("")
|
|
305
|
+
|
|
306
|
+
return "\n".join(lines)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
class MatrixGenerator:
|
|
310
|
+
"""Generates TAG coverage matrix
|
|
311
|
+
|
|
312
|
+
Creates matrix showing SPEC implementation status across
|
|
313
|
+
CODE, TEST, and DOC components.
|
|
314
|
+
"""
|
|
315
|
+
|
|
316
|
+
def generate_matrix(self, tags: Dict[str, Set[str]]) -> TagMatrix:
|
|
317
|
+
"""Generate coverage matrix from tags
|
|
318
|
+
|
|
319
|
+
Args:
|
|
320
|
+
tags: Dict mapping type to set of domain IDs
|
|
321
|
+
{"SPEC": {"AUTH-001"}, "CODE": {"AUTH-001"}, ...}
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
TagMatrix object
|
|
325
|
+
"""
|
|
326
|
+
matrix = TagMatrix()
|
|
327
|
+
|
|
328
|
+
# Get all unique domains
|
|
329
|
+
all_domains = set()
|
|
330
|
+
for tag_set in tags.values():
|
|
331
|
+
all_domains.update(tag_set)
|
|
332
|
+
|
|
333
|
+
# Build matrix rows
|
|
334
|
+
for domain in all_domains:
|
|
335
|
+
matrix.rows[domain] = {
|
|
336
|
+
"SPEC": domain in tags.get("SPEC", set()),
|
|
337
|
+
"CODE": domain in tags.get("CODE", set()),
|
|
338
|
+
"TEST": domain in tags.get("TEST", set()),
|
|
339
|
+
"DOC": domain in tags.get("DOC", set())
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
# Calculate completion percentage
|
|
343
|
+
matrix.completion_percentages[domain] = self.calculate_completion_percentage(domain, tags)
|
|
344
|
+
|
|
345
|
+
return matrix
|
|
346
|
+
|
|
347
|
+
def calculate_completion_percentage(self, spec_id: str, tags: Dict[str, Set[str]]) -> float:
|
|
348
|
+
"""Calculate completion percentage for a SPEC
|
|
349
|
+
|
|
350
|
+
Args:
|
|
351
|
+
spec_id: SPEC domain ID
|
|
352
|
+
tags: Tags dict
|
|
353
|
+
|
|
354
|
+
Returns:
|
|
355
|
+
Completion percentage (0-100)
|
|
356
|
+
"""
|
|
357
|
+
components = ["SPEC", "CODE", "TEST", "DOC"]
|
|
358
|
+
present = sum(1 for comp in components if spec_id in tags.get(comp, set()))
|
|
359
|
+
|
|
360
|
+
return (present / len(components)) * 100.0
|
|
361
|
+
|
|
362
|
+
def format_as_markdown_table(self, matrix: TagMatrix) -> str:
|
|
363
|
+
"""Format matrix as markdown table
|
|
364
|
+
|
|
365
|
+
Args:
|
|
366
|
+
matrix: TagMatrix object
|
|
367
|
+
|
|
368
|
+
Returns:
|
|
369
|
+
Markdown table string
|
|
370
|
+
"""
|
|
371
|
+
lines = []
|
|
372
|
+
lines.append("# TAG Coverage Matrix")
|
|
373
|
+
lines.append("")
|
|
374
|
+
lines.append(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
|
375
|
+
lines.append("")
|
|
376
|
+
|
|
377
|
+
# Table header
|
|
378
|
+
lines.append("| SPEC | CODE | TEST | DOC | Completion |")
|
|
379
|
+
lines.append("|------|------|------|-----|------------|")
|
|
380
|
+
|
|
381
|
+
# Table rows
|
|
382
|
+
for domain in sorted(matrix.rows.keys()):
|
|
383
|
+
row = matrix.rows[domain]
|
|
384
|
+
spec_mark = "✅" if row["SPEC"] else "❌"
|
|
385
|
+
code_mark = "✅" if row["CODE"] else "❌"
|
|
386
|
+
test_mark = "✅" if row["TEST"] else "❌"
|
|
387
|
+
doc_mark = "✅" if row["DOC"] else "❌"
|
|
388
|
+
completion = f"{matrix.completion_percentages[domain]:.0f}%"
|
|
389
|
+
|
|
390
|
+
lines.append(f"| {domain} ({spec_mark}) | {code_mark} | {test_mark} | {doc_mark} | {completion} |")
|
|
391
|
+
|
|
392
|
+
lines.append("")
|
|
393
|
+
|
|
394
|
+
# Summary
|
|
395
|
+
total_specs = len(matrix.rows)
|
|
396
|
+
fully_implemented = sum(1 for pct in matrix.completion_percentages.values() if pct == 100.0)
|
|
397
|
+
|
|
398
|
+
lines.append("## Summary")
|
|
399
|
+
lines.append("")
|
|
400
|
+
lines.append(f"- Total SPECs: {total_specs}")
|
|
401
|
+
lines.append(f"- Fully Implemented (100%): {fully_implemented}")
|
|
402
|
+
lines.append("")
|
|
403
|
+
|
|
404
|
+
return "\n".join(lines)
|
|
405
|
+
|
|
406
|
+
def format_as_csv(self, matrix: TagMatrix) -> str:
|
|
407
|
+
"""Format matrix as CSV
|
|
408
|
+
|
|
409
|
+
Args:
|
|
410
|
+
matrix: TagMatrix object
|
|
411
|
+
|
|
412
|
+
Returns:
|
|
413
|
+
CSV string
|
|
414
|
+
"""
|
|
415
|
+
lines = []
|
|
416
|
+
lines.append("SPEC,CODE,TEST,DOC,Completion")
|
|
417
|
+
|
|
418
|
+
for domain in sorted(matrix.rows.keys()):
|
|
419
|
+
row = matrix.rows[domain]
|
|
420
|
+
spec = "1" if row["SPEC"] else "0"
|
|
421
|
+
code = "1" if row["CODE"] else "0"
|
|
422
|
+
test = "1" if row["TEST"] else "0"
|
|
423
|
+
"1" if row["DOC"] else "0"
|
|
424
|
+
completion = f"{matrix.completion_percentages[domain]:.1f}"
|
|
425
|
+
|
|
426
|
+
lines.append(f"{domain},{spec},{code},{test},{completion}")
|
|
427
|
+
|
|
428
|
+
return "\n".join(lines)
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
class CoverageAnalyzer:
|
|
432
|
+
"""Analyzes TAG coverage and chain integrity
|
|
433
|
+
|
|
434
|
+
Analyzes SPEC→CODE→TEST→DOC chains to identify
|
|
435
|
+
coverage gaps and orphan TAGs.
|
|
436
|
+
"""
|
|
437
|
+
|
|
438
|
+
TAG_PATTERN = re.compile(r"@(SPEC|CODE|TEST|DOC):([A-Z]+(?:-[A-Z]+)*-\d{3})")
|
|
439
|
+
IGNORE_PATTERNS = [".git/*", "node_modules/*", "__pycache__/*", "*.pyc", ".venv/*", "venv/*"]
|
|
440
|
+
|
|
441
|
+
def analyze_spec_coverage(self, spec_id: str, root_path: str) -> CoverageMetrics:
|
|
442
|
+
"""Analyze coverage for a specific SPEC
|
|
443
|
+
|
|
444
|
+
Args:
|
|
445
|
+
spec_id: SPEC domain ID
|
|
446
|
+
root_path: Root directory to scan
|
|
447
|
+
|
|
448
|
+
Returns:
|
|
449
|
+
CoverageMetrics object
|
|
450
|
+
"""
|
|
451
|
+
tags = self._collect_tags(root_path)
|
|
452
|
+
|
|
453
|
+
metrics = CoverageMetrics(spec_id=spec_id)
|
|
454
|
+
metrics.has_code = spec_id in tags.get("CODE", set())
|
|
455
|
+
metrics.has_test = spec_id in tags.get("TEST", set())
|
|
456
|
+
metrics.has_doc = spec_id in tags.get("DOC", set())
|
|
457
|
+
|
|
458
|
+
# Calculate coverage percentage
|
|
459
|
+
components = [metrics.has_code, metrics.has_test, metrics.has_doc]
|
|
460
|
+
metrics.coverage_percentage = (sum(components) / 3.0) * 100.0
|
|
461
|
+
|
|
462
|
+
return metrics
|
|
463
|
+
|
|
464
|
+
def get_specs_without_code(self, root_path: str) -> List[str]:
|
|
465
|
+
"""Find SPECs without CODE implementation
|
|
466
|
+
|
|
467
|
+
Args:
|
|
468
|
+
root_path: Root directory to scan
|
|
469
|
+
|
|
470
|
+
Returns:
|
|
471
|
+
List of SPEC IDs without CODE
|
|
472
|
+
"""
|
|
473
|
+
tags = self._collect_tags(root_path)
|
|
474
|
+
|
|
475
|
+
specs = tags.get("SPEC", set())
|
|
476
|
+
codes = tags.get("CODE", set())
|
|
477
|
+
|
|
478
|
+
return list(specs - codes)
|
|
479
|
+
|
|
480
|
+
def get_code_without_tests(self, root_path: str) -> List[str]:
|
|
481
|
+
"""Find CODE without TEST
|
|
482
|
+
|
|
483
|
+
Args:
|
|
484
|
+
root_path: Root directory to scan
|
|
485
|
+
|
|
486
|
+
Returns:
|
|
487
|
+
List of CODE IDs without TEST
|
|
488
|
+
"""
|
|
489
|
+
tags = self._collect_tags(root_path)
|
|
490
|
+
|
|
491
|
+
codes = tags.get("CODE", set())
|
|
492
|
+
tests = tags.get("TEST", set())
|
|
493
|
+
|
|
494
|
+
return list(codes - tests)
|
|
495
|
+
|
|
496
|
+
def get_code_without_docs(self, root_path: str) -> List[str]:
|
|
497
|
+
"""Find CODE without DOC
|
|
498
|
+
|
|
499
|
+
Args:
|
|
500
|
+
root_path: Root directory to scan
|
|
501
|
+
|
|
502
|
+
Returns:
|
|
503
|
+
List of CODE IDs without DOC
|
|
504
|
+
"""
|
|
505
|
+
tags = self._collect_tags(root_path)
|
|
506
|
+
|
|
507
|
+
codes = tags.get("CODE", set())
|
|
508
|
+
docs = tags.get("DOC", set())
|
|
509
|
+
|
|
510
|
+
return list(codes - docs)
|
|
511
|
+
|
|
512
|
+
def calculate_overall_coverage(self, root_path: str) -> float:
|
|
513
|
+
"""Calculate overall coverage percentage
|
|
514
|
+
|
|
515
|
+
Args:
|
|
516
|
+
root_path: Root directory to scan
|
|
517
|
+
|
|
518
|
+
Returns:
|
|
519
|
+
Overall coverage percentage (0-100)
|
|
520
|
+
"""
|
|
521
|
+
tags = self._collect_tags(root_path)
|
|
522
|
+
|
|
523
|
+
specs = tags.get("SPEC", set())
|
|
524
|
+
if not specs:
|
|
525
|
+
return 0.0 if tags.get("CODE", set()) else 100.0
|
|
526
|
+
|
|
527
|
+
# Calculate average coverage for all SPECs
|
|
528
|
+
total_coverage = 0.0
|
|
529
|
+
for spec_id in specs:
|
|
530
|
+
metrics = self.analyze_spec_coverage(spec_id, root_path)
|
|
531
|
+
total_coverage += metrics.coverage_percentage
|
|
532
|
+
|
|
533
|
+
return total_coverage / len(specs)
|
|
534
|
+
|
|
535
|
+
def _collect_tags(self, root_path: str) -> Dict[str, Set[str]]:
|
|
536
|
+
"""Collect all TAGs from directory
|
|
537
|
+
|
|
538
|
+
Args:
|
|
539
|
+
root_path: Root directory to scan
|
|
540
|
+
|
|
541
|
+
Returns:
|
|
542
|
+
Dict mapping type to set of domain IDs
|
|
543
|
+
"""
|
|
544
|
+
tags: Dict[str, Set[str]] = {
|
|
545
|
+
"SPEC": set(),
|
|
546
|
+
"CODE": set(),
|
|
547
|
+
"TEST": set(),
|
|
548
|
+
"DOC": set()
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
root = Path(root_path)
|
|
552
|
+
if not root.exists():
|
|
553
|
+
return tags
|
|
554
|
+
|
|
555
|
+
for filepath in root.rglob("*"):
|
|
556
|
+
if not filepath.is_file():
|
|
557
|
+
continue
|
|
558
|
+
|
|
559
|
+
# Check ignore patterns
|
|
560
|
+
if self._should_ignore(filepath, root):
|
|
561
|
+
continue
|
|
562
|
+
|
|
563
|
+
# Extract tags
|
|
564
|
+
try:
|
|
565
|
+
content = filepath.read_text(encoding="utf-8", errors="ignore")
|
|
566
|
+
matches = self.TAG_PATTERN.findall(content)
|
|
567
|
+
|
|
568
|
+
for tag_type, domain in matches:
|
|
569
|
+
tags[tag_type].add(domain)
|
|
570
|
+
|
|
571
|
+
except Exception:
|
|
572
|
+
pass
|
|
573
|
+
|
|
574
|
+
return tags
|
|
575
|
+
|
|
576
|
+
def _should_ignore(self, filepath: Path, root: Path) -> bool:
|
|
577
|
+
"""Check if file should be ignored
|
|
578
|
+
|
|
579
|
+
Args:
|
|
580
|
+
filepath: File path
|
|
581
|
+
root: Root directory
|
|
582
|
+
|
|
583
|
+
Returns:
|
|
584
|
+
True if should ignore
|
|
585
|
+
"""
|
|
586
|
+
try:
|
|
587
|
+
relative = filepath.relative_to(root)
|
|
588
|
+
relative_str = str(relative)
|
|
589
|
+
|
|
590
|
+
for pattern in self.IGNORE_PATTERNS:
|
|
591
|
+
pattern_clean = pattern.replace("/*", "").replace("*", "")
|
|
592
|
+
if pattern_clean in relative_str:
|
|
593
|
+
return True
|
|
594
|
+
|
|
595
|
+
return False
|
|
596
|
+
|
|
597
|
+
except ValueError:
|
|
598
|
+
return True
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
class StatisticsGenerator:
|
|
602
|
+
"""Generates overall TAG statistics
|
|
603
|
+
|
|
604
|
+
Produces aggregated statistics and metrics for TAG system health.
|
|
605
|
+
"""
|
|
606
|
+
|
|
607
|
+
TAG_PATTERN = re.compile(r"@(SPEC|CODE|TEST|DOC):([A-Z]+(?:-[A-Z]+)*-\d{3})")
|
|
608
|
+
|
|
609
|
+
def generate_statistics(self, tags: Dict[str, Set[str]]) -> StatisticsReport:
|
|
610
|
+
"""Generate statistics from tags
|
|
611
|
+
|
|
612
|
+
Args:
|
|
613
|
+
tags: Dict mapping type to set of domain IDs
|
|
614
|
+
|
|
615
|
+
Returns:
|
|
616
|
+
StatisticsReport object
|
|
617
|
+
"""
|
|
618
|
+
report = StatisticsReport(
|
|
619
|
+
generated_at=datetime.now(),
|
|
620
|
+
total_tags=0,
|
|
621
|
+
by_type={},
|
|
622
|
+
by_domain={},
|
|
623
|
+
coverage={},
|
|
624
|
+
issues={}
|
|
625
|
+
)
|
|
626
|
+
|
|
627
|
+
# Count by type
|
|
628
|
+
for tag_type, domains in tags.items():
|
|
629
|
+
report.by_type[tag_type] = len(domains)
|
|
630
|
+
report.total_tags += len(domains)
|
|
631
|
+
|
|
632
|
+
# Count by domain
|
|
633
|
+
all_domains = set()
|
|
634
|
+
for domains in tags.values():
|
|
635
|
+
all_domains.update(domains)
|
|
636
|
+
|
|
637
|
+
for domain in all_domains:
|
|
638
|
+
# Extract domain prefix
|
|
639
|
+
parts = domain.split("-")
|
|
640
|
+
if parts:
|
|
641
|
+
domain_prefix = parts[0]
|
|
642
|
+
if domain_prefix not in report.by_domain:
|
|
643
|
+
report.by_domain[domain_prefix] = 0
|
|
644
|
+
report.by_domain[domain_prefix] += 1
|
|
645
|
+
|
|
646
|
+
# Calculate coverage metrics
|
|
647
|
+
specs = tags.get("SPEC", set())
|
|
648
|
+
codes = tags.get("CODE", set())
|
|
649
|
+
tests = tags.get("TEST", set())
|
|
650
|
+
|
|
651
|
+
if specs:
|
|
652
|
+
spec_to_code = len(specs & codes) / len(specs) * 100.0
|
|
653
|
+
report.coverage["spec_to_code"] = round(spec_to_code, 2)
|
|
654
|
+
|
|
655
|
+
if codes:
|
|
656
|
+
code_to_test = len(codes & tests) / len(codes) * 100.0
|
|
657
|
+
report.coverage["code_to_test"] = round(code_to_test, 2)
|
|
658
|
+
|
|
659
|
+
# Calculate overall coverage
|
|
660
|
+
if specs:
|
|
661
|
+
total_coverage = 0.0
|
|
662
|
+
for spec in specs:
|
|
663
|
+
components = 0
|
|
664
|
+
if spec in codes:
|
|
665
|
+
components += 1
|
|
666
|
+
if spec in tests:
|
|
667
|
+
components += 1
|
|
668
|
+
if spec in tags.get("DOC", set()):
|
|
669
|
+
components += 1
|
|
670
|
+
total_coverage += (components / 3.0) * 100.0
|
|
671
|
+
|
|
672
|
+
report.coverage["overall_percentage"] = round(total_coverage / len(specs), 2)
|
|
673
|
+
else:
|
|
674
|
+
report.coverage["overall_percentage"] = 0.0
|
|
675
|
+
|
|
676
|
+
# Detect issues
|
|
677
|
+
orphan_codes = codes - tests
|
|
678
|
+
orphan_tests = tests - codes
|
|
679
|
+
report.issues["orphan_count"] = len(orphan_codes) + len(orphan_tests)
|
|
680
|
+
|
|
681
|
+
incomplete_specs = specs - codes
|
|
682
|
+
incomplete_chains = len(incomplete_specs)
|
|
683
|
+
for spec in specs & codes:
|
|
684
|
+
if spec not in tests:
|
|
685
|
+
incomplete_chains += 1
|
|
686
|
+
|
|
687
|
+
report.issues["incomplete_chains"] = incomplete_chains
|
|
688
|
+
report.issues["deprecated_count"] = 0 # Placeholder
|
|
689
|
+
|
|
690
|
+
return report
|
|
691
|
+
|
|
692
|
+
def format_as_json(self, stats: StatisticsReport) -> str:
|
|
693
|
+
"""Format statistics as JSON
|
|
694
|
+
|
|
695
|
+
Args:
|
|
696
|
+
stats: StatisticsReport object
|
|
697
|
+
|
|
698
|
+
Returns:
|
|
699
|
+
JSON string
|
|
700
|
+
"""
|
|
701
|
+
data = {
|
|
702
|
+
"generated_at": stats.generated_at.isoformat(),
|
|
703
|
+
"total_tags": stats.total_tags,
|
|
704
|
+
"by_type": stats.by_type,
|
|
705
|
+
"by_domain": stats.by_domain,
|
|
706
|
+
"coverage": stats.coverage,
|
|
707
|
+
"issues": stats.issues
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
return json.dumps(data, indent=2)
|
|
711
|
+
|
|
712
|
+
def format_as_human_readable(self, stats: StatisticsReport) -> str:
|
|
713
|
+
"""Format statistics as human-readable text
|
|
714
|
+
|
|
715
|
+
Args:
|
|
716
|
+
stats: StatisticsReport object
|
|
717
|
+
|
|
718
|
+
Returns:
|
|
719
|
+
Human-readable string
|
|
720
|
+
"""
|
|
721
|
+
lines = []
|
|
722
|
+
lines.append("# TAG Statistics")
|
|
723
|
+
lines.append("")
|
|
724
|
+
lines.append(f"Generated: {stats.generated_at.strftime('%Y-%m-%d %H:%M:%S')}")
|
|
725
|
+
lines.append("")
|
|
726
|
+
|
|
727
|
+
lines.append(f"Total TAGs: {stats.total_tags}")
|
|
728
|
+
lines.append("")
|
|
729
|
+
|
|
730
|
+
lines.append("## By Type")
|
|
731
|
+
for tag_type, count in sorted(stats.by_type.items()):
|
|
732
|
+
lines.append(f"- {tag_type}: {count}")
|
|
733
|
+
lines.append("")
|
|
734
|
+
|
|
735
|
+
lines.append("## By Domain")
|
|
736
|
+
for domain, count in sorted(stats.by_domain.items()):
|
|
737
|
+
lines.append(f"- {domain}: {count}")
|
|
738
|
+
lines.append("")
|
|
739
|
+
|
|
740
|
+
lines.append("## Coverage")
|
|
741
|
+
for metric, value in sorted(stats.coverage.items()):
|
|
742
|
+
lines.append(f"- {metric}: {value}%")
|
|
743
|
+
lines.append("")
|
|
744
|
+
|
|
745
|
+
return "\n".join(lines)
|
|
746
|
+
|
|
747
|
+
|
|
748
|
+
class ReportFormatter:
|
|
749
|
+
"""Formats reports in multiple output formats
|
|
750
|
+
|
|
751
|
+
Provides formatting utilities for inventory, matrix, and statistics
|
|
752
|
+
in Markdown, HTML, CSV, and JSON formats.
|
|
753
|
+
"""
|
|
754
|
+
|
|
755
|
+
def format_inventory_md(self, inventory: List[TagInventory]) -> str:
|
|
756
|
+
"""Format inventory as markdown
|
|
757
|
+
|
|
758
|
+
Args:
|
|
759
|
+
inventory: List of TagInventory objects
|
|
760
|
+
|
|
761
|
+
Returns:
|
|
762
|
+
Markdown string
|
|
763
|
+
"""
|
|
764
|
+
generator = InventoryGenerator()
|
|
765
|
+
grouped = generator.group_by_domain(inventory)
|
|
766
|
+
return generator.format_as_markdown(grouped)
|
|
767
|
+
|
|
768
|
+
def format_matrix_md(self, matrix: TagMatrix) -> str:
|
|
769
|
+
"""Format matrix as markdown
|
|
770
|
+
|
|
771
|
+
Args:
|
|
772
|
+
matrix: TagMatrix object
|
|
773
|
+
|
|
774
|
+
Returns:
|
|
775
|
+
Markdown string
|
|
776
|
+
"""
|
|
777
|
+
generator = MatrixGenerator()
|
|
778
|
+
return generator.format_as_markdown_table(matrix)
|
|
779
|
+
|
|
780
|
+
def format_table(self, headers: List[str], rows: List[List[str]]) -> str:
|
|
781
|
+
"""Format data as markdown table
|
|
782
|
+
|
|
783
|
+
Args:
|
|
784
|
+
headers: Table headers
|
|
785
|
+
rows: Table rows
|
|
786
|
+
|
|
787
|
+
Returns:
|
|
788
|
+
Markdown table string
|
|
789
|
+
"""
|
|
790
|
+
lines = []
|
|
791
|
+
|
|
792
|
+
# Header row
|
|
793
|
+
lines.append("| " + " | ".join(headers) + " |")
|
|
794
|
+
|
|
795
|
+
# Separator row
|
|
796
|
+
lines.append("| " + " | ".join(["---"] * len(headers)) + " |")
|
|
797
|
+
|
|
798
|
+
# Data rows
|
|
799
|
+
for row in rows:
|
|
800
|
+
lines.append("| " + " | ".join(row) + " |")
|
|
801
|
+
|
|
802
|
+
return "\n".join(lines)
|
|
803
|
+
|
|
804
|
+
def format_html_dashboard(self, inventory: List[TagInventory]) -> str:
|
|
805
|
+
"""Format inventory as HTML dashboard (OPTIONAL)
|
|
806
|
+
|
|
807
|
+
Args:
|
|
808
|
+
inventory: List of TagInventory objects
|
|
809
|
+
|
|
810
|
+
Returns:
|
|
811
|
+
HTML string
|
|
812
|
+
|
|
813
|
+
Raises:
|
|
814
|
+
NotImplementedError: HTML formatting is optional
|
|
815
|
+
"""
|
|
816
|
+
raise NotImplementedError("HTML dashboard formatting is optional")
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
class ReportGenerator:
|
|
820
|
+
"""Main orchestrator for report generation
|
|
821
|
+
|
|
822
|
+
Coordinates all generators to produce complete reporting suite:
|
|
823
|
+
- tag-inventory.md
|
|
824
|
+
- tag-matrix.md
|
|
825
|
+
- tag-statistics.json
|
|
826
|
+
"""
|
|
827
|
+
|
|
828
|
+
def __init__(self):
|
|
829
|
+
"""Initialize report generator"""
|
|
830
|
+
self.inventory_gen = InventoryGenerator()
|
|
831
|
+
self.matrix_gen = MatrixGenerator()
|
|
832
|
+
self.coverage_analyzer = CoverageAnalyzer()
|
|
833
|
+
self.stats_gen = StatisticsGenerator()
|
|
834
|
+
self.formatter = ReportFormatter()
|
|
835
|
+
|
|
836
|
+
def generate_inventory_report(self, root_path: str) -> str:
|
|
837
|
+
"""Generate inventory report
|
|
838
|
+
|
|
839
|
+
Args:
|
|
840
|
+
root_path: Root directory to scan
|
|
841
|
+
|
|
842
|
+
Returns:
|
|
843
|
+
Markdown inventory report
|
|
844
|
+
"""
|
|
845
|
+
inventory = self.inventory_gen.generate_inventory(root_path)
|
|
846
|
+
return self.formatter.format_inventory_md(inventory)
|
|
847
|
+
|
|
848
|
+
def generate_matrix_report(self, root_path: str) -> str:
|
|
849
|
+
"""Generate coverage matrix report
|
|
850
|
+
|
|
851
|
+
Args:
|
|
852
|
+
root_path: Root directory to scan
|
|
853
|
+
|
|
854
|
+
Returns:
|
|
855
|
+
Markdown matrix report
|
|
856
|
+
"""
|
|
857
|
+
tags = self.coverage_analyzer._collect_tags(root_path)
|
|
858
|
+
matrix = self.matrix_gen.generate_matrix(tags)
|
|
859
|
+
return self.formatter.format_matrix_md(matrix)
|
|
860
|
+
|
|
861
|
+
def generate_statistics_report(self, root_path: str) -> str:
|
|
862
|
+
"""Generate statistics report
|
|
863
|
+
|
|
864
|
+
Args:
|
|
865
|
+
root_path: Root directory to scan
|
|
866
|
+
|
|
867
|
+
Returns:
|
|
868
|
+
JSON statistics report
|
|
869
|
+
"""
|
|
870
|
+
tags = self.coverage_analyzer._collect_tags(root_path)
|
|
871
|
+
stats = self.stats_gen.generate_statistics(tags)
|
|
872
|
+
return self.stats_gen.format_as_json(stats)
|
|
873
|
+
|
|
874
|
+
def generate_combined_report(self, root_path: str) -> str:
|
|
875
|
+
"""Generate combined report with all sections
|
|
876
|
+
|
|
877
|
+
Args:
|
|
878
|
+
root_path: Root directory to scan
|
|
879
|
+
|
|
880
|
+
Returns:
|
|
881
|
+
Combined markdown report
|
|
882
|
+
"""
|
|
883
|
+
lines = []
|
|
884
|
+
lines.append("# MoAI-ADK TAG System Report")
|
|
885
|
+
lines.append("")
|
|
886
|
+
lines.append(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
|
887
|
+
lines.append("")
|
|
888
|
+
|
|
889
|
+
# Inventory section
|
|
890
|
+
lines.append("---")
|
|
891
|
+
lines.append("")
|
|
892
|
+
lines.append(self.generate_inventory_report(root_path))
|
|
893
|
+
lines.append("")
|
|
894
|
+
|
|
895
|
+
# Matrix section
|
|
896
|
+
lines.append("---")
|
|
897
|
+
lines.append("")
|
|
898
|
+
lines.append(self.generate_matrix_report(root_path))
|
|
899
|
+
lines.append("")
|
|
900
|
+
|
|
901
|
+
# Statistics section
|
|
902
|
+
lines.append("---")
|
|
903
|
+
lines.append("")
|
|
904
|
+
lines.append("# Statistics")
|
|
905
|
+
lines.append("")
|
|
906
|
+
lines.append("```json")
|
|
907
|
+
lines.append(self.generate_statistics_report(root_path))
|
|
908
|
+
lines.append("```")
|
|
909
|
+
lines.append("")
|
|
910
|
+
|
|
911
|
+
return "\n".join(lines)
|
|
912
|
+
|
|
913
|
+
def generate_all_reports(self, root_path: str, output_dir: str) -> ReportResult:
|
|
914
|
+
"""Generate all reports and save to output directory
|
|
915
|
+
|
|
916
|
+
Args:
|
|
917
|
+
root_path: Root directory to scan
|
|
918
|
+
output_dir: Output directory for reports
|
|
919
|
+
|
|
920
|
+
Returns:
|
|
921
|
+
ReportResult with file paths
|
|
922
|
+
"""
|
|
923
|
+
output = Path(output_dir)
|
|
924
|
+
output.mkdir(parents=True, exist_ok=True)
|
|
925
|
+
|
|
926
|
+
try:
|
|
927
|
+
# Generate inventory
|
|
928
|
+
inventory_path = output / "tag-inventory.md"
|
|
929
|
+
inventory_report = self.generate_inventory_report(root_path)
|
|
930
|
+
inventory_path.write_text(inventory_report, encoding="utf-8")
|
|
931
|
+
|
|
932
|
+
# Generate matrix
|
|
933
|
+
matrix_path = output / "tag-matrix.md"
|
|
934
|
+
matrix_report = self.generate_matrix_report(root_path)
|
|
935
|
+
matrix_path.write_text(matrix_report, encoding="utf-8")
|
|
936
|
+
|
|
937
|
+
# Generate statistics
|
|
938
|
+
statistics_path = output / "tag-statistics.json"
|
|
939
|
+
statistics_report = self.generate_statistics_report(root_path)
|
|
940
|
+
statistics_path.write_text(statistics_report, encoding="utf-8")
|
|
941
|
+
|
|
942
|
+
return ReportResult(
|
|
943
|
+
inventory_path=inventory_path,
|
|
944
|
+
matrix_path=matrix_path,
|
|
945
|
+
statistics_path=statistics_path,
|
|
946
|
+
success=True
|
|
947
|
+
)
|
|
948
|
+
|
|
949
|
+
except Exception as e:
|
|
950
|
+
return ReportResult(
|
|
951
|
+
inventory_path=output / "tag-inventory.md",
|
|
952
|
+
matrix_path=output / "tag-matrix.md",
|
|
953
|
+
statistics_path=output / "tag-statistics.json",
|
|
954
|
+
success=False,
|
|
955
|
+
error_message=str(e)
|
|
956
|
+
)
|