moai-adk 0.15.0__py3-none-any.whl → 0.25.4__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (417) hide show
  1. moai_adk/__init__.py +1 -2
  2. moai_adk/__main__.py +85 -2
  3. moai_adk/cli/__init__.py +0 -1
  4. moai_adk/cli/commands/__init__.py +0 -1
  5. moai_adk/cli/commands/analyze.py +127 -0
  6. moai_adk/cli/commands/backup.py +5 -3
  7. moai_adk/cli/commands/doctor.py +35 -11
  8. moai_adk/cli/commands/improve_user_experience.py +348 -0
  9. moai_adk/cli/commands/init.py +150 -23
  10. moai_adk/cli/commands/language.py +269 -0
  11. moai_adk/cli/commands/migrate.py +158 -0
  12. moai_adk/cli/commands/status.py +13 -12
  13. moai_adk/cli/commands/update.py +364 -60
  14. moai_adk/cli/commands/validate_links.py +118 -0
  15. moai_adk/cli/main.py +3 -2
  16. moai_adk/cli/prompts/init_prompts.py +79 -82
  17. moai_adk/core/__init__.py +0 -1
  18. moai_adk/core/analysis/__init__.py +9 -0
  19. moai_adk/core/analysis/session_analyzer.py +439 -0
  20. moai_adk/core/claude_integration.py +421 -0
  21. moai_adk/core/command_helpers.py +270 -0
  22. moai_adk/core/config/__init__.py +6 -0
  23. moai_adk/core/config/auto_spec_config.py +346 -0
  24. moai_adk/core/config/migration.py +133 -12
  25. moai_adk/core/context_manager.py +279 -0
  26. moai_adk/core/diagnostics/slash_commands.py +0 -1
  27. moai_adk/core/error_recovery_system.py +1289 -0
  28. moai_adk/core/git/__init__.py +0 -1
  29. moai_adk/core/git/branch.py +0 -1
  30. moai_adk/core/git/branch_manager.py +4 -4
  31. moai_adk/core/git/checkpoint.py +1 -5
  32. moai_adk/core/git/commit.py +0 -1
  33. moai_adk/core/git/event_detector.py +3 -5
  34. moai_adk/core/git/manager.py +0 -1
  35. moai_adk/core/hooks/post_tool_auto_spec_completion.py +925 -0
  36. moai_adk/core/integration/__init__.py +22 -0
  37. moai_adk/core/integration/engine.py +169 -0
  38. moai_adk/core/integration/integration_tester.py +225 -0
  39. moai_adk/core/integration/models.py +88 -0
  40. moai_adk/core/integration/utils.py +211 -0
  41. moai_adk/core/issue_creator.py +28 -18
  42. moai_adk/core/language_config.py +202 -0
  43. moai_adk/core/language_validator.py +556 -0
  44. moai_adk/core/mcp/setup.py +113 -0
  45. moai_adk/core/migration/__init__.py +18 -0
  46. moai_adk/core/migration/backup_manager.py +208 -0
  47. moai_adk/core/migration/file_migrator.py +218 -0
  48. moai_adk/core/migration/version_detector.py +143 -0
  49. moai_adk/core/migration/version_migrator.py +228 -0
  50. moai_adk/core/performance/__init__.py +6 -0
  51. moai_adk/core/performance/cache_system.py +318 -0
  52. moai_adk/core/performance/parallel_processor.py +116 -0
  53. moai_adk/core/project/__init__.py +0 -1
  54. moai_adk/core/project/backup_utils.py +2 -7
  55. moai_adk/core/project/checker.py +3 -3
  56. moai_adk/core/project/detector.py +20 -40
  57. moai_adk/core/project/initializer.py +42 -17
  58. moai_adk/core/project/phase_executor.py +415 -58
  59. moai_adk/core/project/validator.py +6 -25
  60. moai_adk/core/quality/__init__.py +1 -1
  61. moai_adk/core/quality/trust_checker.py +64 -110
  62. moai_adk/core/quality/validators/__init__.py +1 -1
  63. moai_adk/core/quality/validators/base_validator.py +1 -1
  64. moai_adk/core/rollback_manager.py +993 -0
  65. moai_adk/core/session_manager.py +667 -0
  66. moai_adk/core/spec/confidence_scoring.py +749 -0
  67. moai_adk/core/spec/ears_template_engine.py +1182 -0
  68. moai_adk/core/spec/quality_validator.py +721 -0
  69. moai_adk/core/spec_status_manager.py +488 -0
  70. moai_adk/core/template/__init__.py +0 -1
  71. moai_adk/core/template/backup.py +41 -1
  72. moai_adk/core/template/config.py +11 -12
  73. moai_adk/core/template/languages.py +0 -1
  74. moai_adk/core/template/merger.py +79 -22
  75. moai_adk/core/template/processor.py +614 -40
  76. moai_adk/core/template_engine.py +36 -27
  77. moai_adk/foundation/git/commit_templates.py +565 -0
  78. moai_adk/foundation/trust/trust_principles.py +725 -0
  79. moai_adk/foundation/trust/validation_checklist.py +1678 -0
  80. moai_adk/statusline/__init__.py +38 -0
  81. moai_adk/statusline/alfred_detector.py +107 -0
  82. moai_adk/statusline/config.py +364 -0
  83. moai_adk/statusline/enhanced_output_style_detector.py +364 -0
  84. moai_adk/statusline/git_collector.py +190 -0
  85. moai_adk/statusline/main.py +228 -0
  86. moai_adk/statusline/metrics_tracker.py +78 -0
  87. moai_adk/statusline/renderer.py +327 -0
  88. moai_adk/statusline/update_checker.py +135 -0
  89. moai_adk/statusline/version_reader.py +647 -0
  90. moai_adk/templates/.git-hooks/pre-commit +66 -0
  91. moai_adk/templates/.git-hooks/pre-push +116 -4
  92. moai_adk/templates/.github/workflows/moai-gitflow.yml +1 -7
  93. moai_adk/templates/.github/workflows/spec-issue-sync.yml +0 -1
  94. moai_adk/templates/.gitignore +44 -0
  95. moai_adk/templates/.mcp.json +22 -0
  96. moai_adk/templates/CLAUDE.md +450 -1071
  97. moai_adk/utils/__init__.py +0 -1
  98. moai_adk/utils/banner.py +0 -1
  99. moai_adk/utils/common.py +308 -0
  100. moai_adk/utils/link_validator.py +249 -0
  101. moai_adk/utils/logger.py +4 -9
  102. moai_adk/utils/safe_file_reader.py +210 -0
  103. moai_adk/utils/user_experience.py +531 -0
  104. moai_adk-0.25.4.dist-info/METADATA +2279 -0
  105. moai_adk-0.25.4.dist-info/RECORD +112 -0
  106. moai_adk/core/tags/__init__.py +0 -86
  107. moai_adk/core/tags/ci_validator.py +0 -463
  108. moai_adk/core/tags/cli.py +0 -283
  109. moai_adk/core/tags/generator.py +0 -109
  110. moai_adk/core/tags/inserter.py +0 -99
  111. moai_adk/core/tags/mapper.py +0 -126
  112. moai_adk/core/tags/parser.py +0 -76
  113. moai_adk/core/tags/pre_commit_validator.py +0 -393
  114. moai_adk/core/tags/reporter.py +0 -956
  115. moai_adk/core/tags/tags.py +0 -149
  116. moai_adk/core/tags/validator.py +0 -897
  117. moai_adk/templates/.claude/agents/alfred/backend-expert.md +0 -319
  118. moai_adk/templates/.claude/agents/alfred/cc-manager.md +0 -316
  119. moai_adk/templates/.claude/agents/alfred/debug-helper.md +0 -208
  120. moai_adk/templates/.claude/agents/alfred/devops-expert.md +0 -464
  121. moai_adk/templates/.claude/agents/alfred/doc-syncer.md +0 -214
  122. moai_adk/templates/.claude/agents/alfred/frontend-expert.md +0 -357
  123. moai_adk/templates/.claude/agents/alfred/git-manager.md +0 -406
  124. moai_adk/templates/.claude/agents/alfred/implementation-planner.md +0 -423
  125. moai_adk/templates/.claude/agents/alfred/project-manager.md +0 -312
  126. moai_adk/templates/.claude/agents/alfred/quality-gate.md +0 -343
  127. moai_adk/templates/.claude/agents/alfred/skill-factory.md +0 -865
  128. moai_adk/templates/.claude/agents/alfred/spec-builder.md +0 -392
  129. moai_adk/templates/.claude/agents/alfred/tag-agent.md +0 -361
  130. moai_adk/templates/.claude/agents/alfred/tdd-implementer.md +0 -428
  131. moai_adk/templates/.claude/agents/alfred/trust-checker.md +0 -375
  132. moai_adk/templates/.claude/agents/alfred/ui-ux-expert.md +0 -571
  133. moai_adk/templates/.claude/commands/alfred/0-project.md +0 -1525
  134. moai_adk/templates/.claude/commands/alfred/1-plan.md +0 -802
  135. moai_adk/templates/.claude/commands/alfred/2-run.md +0 -709
  136. moai_adk/templates/.claude/commands/alfred/3-sync.md +0 -1009
  137. moai_adk/templates/.claude/commands/alfred/9-feedback.md +0 -149
  138. moai_adk/templates/.claude/hooks/alfred/core/project.py +0 -748
  139. moai_adk/templates/.claude/hooks/alfred/core/timeout.py +0 -136
  140. moai_adk/templates/.claude/hooks/alfred/core/ttl_cache.py +0 -108
  141. moai_adk/templates/.claude/hooks/alfred/core/version_cache.py +0 -198
  142. moai_adk/templates/.claude/hooks/alfred/handlers/__init__.py +0 -29
  143. moai_adk/templates/.claude/hooks/alfred/post_tool__log_changes.py +0 -94
  144. moai_adk/templates/.claude/hooks/alfred/pre_tool__auto_checkpoint.py +0 -100
  145. moai_adk/templates/.claude/hooks/alfred/session_end__cleanup.py +0 -94
  146. moai_adk/templates/.claude/hooks/alfred/session_start__show_project_info.py +0 -94
  147. moai_adk/templates/.claude/hooks/alfred/shared/core/__init__.py +0 -170
  148. moai_adk/templates/.claude/hooks/alfred/shared/core/checkpoint.py +0 -271
  149. moai_adk/templates/.claude/hooks/alfred/shared/core/context.py +0 -67
  150. moai_adk/templates/.claude/hooks/alfred/shared/core/project.py +0 -749
  151. moai_adk/templates/.claude/hooks/alfred/shared/core/tags.py +0 -230
  152. moai_adk/templates/.claude/hooks/alfred/shared/core/version_cache.py +0 -198
  153. moai_adk/templates/.claude/hooks/alfred/shared/handlers/__init__.py +0 -21
  154. moai_adk/templates/.claude/hooks/alfred/shared/handlers/notification.py +0 -154
  155. moai_adk/templates/.claude/hooks/alfred/shared/handlers/session.py +0 -174
  156. moai_adk/templates/.claude/hooks/alfred/shared/handlers/tool.py +0 -87
  157. moai_adk/templates/.claude/hooks/alfred/shared/handlers/user.py +0 -61
  158. moai_adk/templates/.claude/hooks/alfred/user_prompt__jit_load_docs.py +0 -112
  159. moai_adk/templates/.claude/hooks/alfred/utils/__init__.py +0 -1
  160. moai_adk/templates/.claude/hooks/alfred/utils/timeout.py +0 -161
  161. moai_adk/templates/.claude/settings.json +0 -144
  162. moai_adk/templates/.claude/skills/moai-alfred-agent-guide/SKILL.md +0 -70
  163. moai_adk/templates/.claude/skills/moai-alfred-agent-guide/examples.md +0 -62
  164. moai_adk/templates/.claude/skills/moai-alfred-agent-guide/reference.md +0 -242
  165. moai_adk/templates/.claude/skills/moai-alfred-config-schema/SKILL.md +0 -56
  166. moai_adk/templates/.claude/skills/moai-alfred-config-schema/examples.md +0 -28
  167. moai_adk/templates/.claude/skills/moai-alfred-config-schema/reference.md +0 -444
  168. moai_adk/templates/.claude/skills/moai-alfred-context-budget/SKILL.md +0 -62
  169. moai_adk/templates/.claude/skills/moai-alfred-context-budget/examples.md +0 -28
  170. moai_adk/templates/.claude/skills/moai-alfred-context-budget/reference.md +0 -405
  171. moai_adk/templates/.claude/skills/moai-alfred-dev-guide/SKILL.md +0 -51
  172. moai_adk/templates/.claude/skills/moai-alfred-dev-guide/examples.md +0 -355
  173. moai_adk/templates/.claude/skills/moai-alfred-dev-guide/reference.md +0 -239
  174. moai_adk/templates/.claude/skills/moai-alfred-ears-authoring/SKILL.md +0 -113
  175. moai_adk/templates/.claude/skills/moai-alfred-ears-authoring/examples.md +0 -29
  176. moai_adk/templates/.claude/skills/moai-alfred-ears-authoring/reference.md +0 -28
  177. moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/SKILL.md +0 -323
  178. moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/examples.md +0 -286
  179. moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/reference.md +0 -126
  180. moai_adk/templates/.claude/skills/moai-alfred-git-workflow/SKILL.md +0 -122
  181. moai_adk/templates/.claude/skills/moai-alfred-git-workflow/examples.md +0 -29
  182. moai_adk/templates/.claude/skills/moai-alfred-git-workflow/reference.md +0 -29
  183. moai_adk/templates/.claude/skills/moai-alfred-gitflow-policy/SKILL.md +0 -74
  184. moai_adk/templates/.claude/skills/moai-alfred-gitflow-policy/examples.md +0 -4
  185. moai_adk/templates/.claude/skills/moai-alfred-gitflow-policy/reference.md +0 -269
  186. moai_adk/templates/.claude/skills/moai-alfred-interactive-questions/SKILL.md +0 -237
  187. moai_adk/templates/.claude/skills/moai-alfred-interactive-questions/examples.md +0 -615
  188. moai_adk/templates/.claude/skills/moai-alfred-interactive-questions/reference.md +0 -653
  189. moai_adk/templates/.claude/skills/moai-alfred-issue-labels/SKILL.md +0 -19
  190. moai_adk/templates/.claude/skills/moai-alfred-issue-labels/examples.md +0 -4
  191. moai_adk/templates/.claude/skills/moai-alfred-issue-labels/reference.md +0 -150
  192. moai_adk/templates/.claude/skills/moai-alfred-language-detection/SKILL.md +0 -113
  193. moai_adk/templates/.claude/skills/moai-alfred-language-detection/examples.md +0 -29
  194. moai_adk/templates/.claude/skills/moai-alfred-language-detection/reference.md +0 -28
  195. moai_adk/templates/.claude/skills/moai-alfred-persona-roles/SKILL.md +0 -198
  196. moai_adk/templates/.claude/skills/moai-alfred-persona-roles/examples.md +0 -431
  197. moai_adk/templates/.claude/skills/moai-alfred-persona-roles/reference.md +0 -141
  198. moai_adk/templates/.claude/skills/moai-alfred-practices/SKILL.md +0 -89
  199. moai_adk/templates/.claude/skills/moai-alfred-practices/examples.md +0 -122
  200. moai_adk/templates/.claude/skills/moai-alfred-practices/reference.md +0 -369
  201. moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/SKILL.md +0 -508
  202. moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/examples.md +0 -481
  203. moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/reference.md +0 -100
  204. moai_adk/templates/.claude/skills/moai-alfred-reporting/SKILL.md +0 -273
  205. moai_adk/templates/.claude/skills/moai-alfred-rules/SKILL.md +0 -77
  206. moai_adk/templates/.claude/skills/moai-alfred-rules/examples.md +0 -265
  207. moai_adk/templates/.claude/skills/moai-alfred-rules/reference.md +0 -539
  208. moai_adk/templates/.claude/skills/moai-alfred-session-state/SKILL.md +0 -19
  209. moai_adk/templates/.claude/skills/moai-alfred-session-state/examples.md +0 -4
  210. moai_adk/templates/.claude/skills/moai-alfred-session-state/reference.md +0 -84
  211. moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/README.md +0 -137
  212. moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/SKILL.md +0 -219
  213. moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/examples/validate-spec.sh +0 -161
  214. moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/examples.md +0 -541
  215. moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/reference.md +0 -622
  216. moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-extended/SKILL.md +0 -115
  217. moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-extended/examples.md +0 -4
  218. moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-extended/reference.md +0 -348
  219. moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-validation/SKILL.md +0 -113
  220. moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-validation/examples.md +0 -29
  221. moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-validation/reference.md +0 -28
  222. moai_adk/templates/.claude/skills/moai-alfred-tag-scanning/SKILL.md +0 -113
  223. moai_adk/templates/.claude/skills/moai-alfred-tag-scanning/examples.md +0 -29
  224. moai_adk/templates/.claude/skills/moai-alfred-tag-scanning/reference.md +0 -28
  225. moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/SKILL.md +0 -19
  226. moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/examples.md +0 -4
  227. moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/reference.md +0 -211
  228. moai_adk/templates/.claude/skills/moai-alfred-trust-validation/SKILL.md +0 -113
  229. moai_adk/templates/.claude/skills/moai-alfred-trust-validation/examples.md +0 -29
  230. moai_adk/templates/.claude/skills/moai-alfred-trust-validation/reference.md +0 -28
  231. moai_adk/templates/.claude/skills/moai-alfred-workflow/SKILL.md +0 -288
  232. moai_adk/templates/.claude/skills/moai-cc-agents/SKILL.md +0 -269
  233. moai_adk/templates/.claude/skills/moai-cc-agents/templates/agent-template.md +0 -32
  234. moai_adk/templates/.claude/skills/moai-cc-claude-md/SKILL.md +0 -298
  235. moai_adk/templates/.claude/skills/moai-cc-claude-md/templates/CLAUDE-template.md +0 -26
  236. moai_adk/templates/.claude/skills/moai-cc-commands/SKILL.md +0 -307
  237. moai_adk/templates/.claude/skills/moai-cc-commands/templates/command-template.md +0 -21
  238. moai_adk/templates/.claude/skills/moai-cc-hooks/SKILL.md +0 -252
  239. moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/pre-bash-check.sh +0 -19
  240. moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/preserve-permissions.sh +0 -19
  241. moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/validate-bash-command.py +0 -24
  242. moai_adk/templates/.claude/skills/moai-cc-mcp-plugins/SKILL.md +0 -199
  243. moai_adk/templates/.claude/skills/moai-cc-mcp-plugins/templates/settings-mcp-template.json +0 -39
  244. moai_adk/templates/.claude/skills/moai-cc-memory/SKILL.md +0 -316
  245. moai_adk/templates/.claude/skills/moai-cc-memory/templates/session-summary-template.md +0 -18
  246. moai_adk/templates/.claude/skills/moai-cc-settings/SKILL.md +0 -263
  247. moai_adk/templates/.claude/skills/moai-cc-settings/templates/settings-complete-template.json +0 -30
  248. moai_adk/templates/.claude/skills/moai-cc-skill-descriptions/SKILL.md +0 -19
  249. moai_adk/templates/.claude/skills/moai-cc-skill-descriptions/examples.md +0 -4
  250. moai_adk/templates/.claude/skills/moai-cc-skill-descriptions/reference.md +0 -218
  251. moai_adk/templates/.claude/skills/moai-cc-skill-factory/CHECKLIST.md +0 -482
  252. moai_adk/templates/.claude/skills/moai-cc-skill-factory/EXAMPLES.md +0 -278
  253. moai_adk/templates/.claude/skills/moai-cc-skill-factory/INTERACTIVE-DISCOVERY.md +0 -524
  254. moai_adk/templates/.claude/skills/moai-cc-skill-factory/METADATA.md +0 -477
  255. moai_adk/templates/.claude/skills/moai-cc-skill-factory/PARALLEL-ANALYSIS-REPORT.md +0 -429
  256. moai_adk/templates/.claude/skills/moai-cc-skill-factory/PYTHON-VERSION-MATRIX.md +0 -391
  257. moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL-FACTORY-WORKFLOW.md +0 -431
  258. moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL-UPDATE-ADVISOR.md +0 -577
  259. moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL.md +0 -271
  260. moai_adk/templates/.claude/skills/moai-cc-skill-factory/STEP-BY-STEP-GUIDE.md +0 -466
  261. moai_adk/templates/.claude/skills/moai-cc-skill-factory/STRUCTURE.md +0 -583
  262. moai_adk/templates/.claude/skills/moai-cc-skill-factory/WEB-RESEARCH.md +0 -526
  263. moai_adk/templates/.claude/skills/moai-cc-skill-factory/reference.md +0 -465
  264. moai_adk/templates/.claude/skills/moai-cc-skill-factory/scripts/generate-structure.sh +0 -328
  265. moai_adk/templates/.claude/skills/moai-cc-skill-factory/scripts/validate-skill.sh +0 -312
  266. moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/SKILL_TEMPLATE.md +0 -245
  267. moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/examples-template.md +0 -285
  268. moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/reference-template.md +0 -278
  269. moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/scripts-template.sh +0 -303
  270. moai_adk/templates/.claude/skills/moai-cc-skills/SKILL.md +0 -291
  271. moai_adk/templates/.claude/skills/moai-cc-skills/templates/SKILL-template.md +0 -15
  272. moai_adk/templates/.claude/skills/moai-design-systems/SKILL.md +0 -802
  273. moai_adk/templates/.claude/skills/moai-design-systems/examples.md +0 -1238
  274. moai_adk/templates/.claude/skills/moai-design-systems/reference.md +0 -673
  275. moai_adk/templates/.claude/skills/moai-domain-backend/SKILL.md +0 -290
  276. moai_adk/templates/.claude/skills/moai-domain-backend/examples.md +0 -1633
  277. moai_adk/templates/.claude/skills/moai-domain-backend/reference.md +0 -660
  278. moai_adk/templates/.claude/skills/moai-domain-cli-tool/SKILL.md +0 -123
  279. moai_adk/templates/.claude/skills/moai-domain-cli-tool/examples.md +0 -29
  280. moai_adk/templates/.claude/skills/moai-domain-cli-tool/reference.md +0 -30
  281. moai_adk/templates/.claude/skills/moai-domain-data-science/SKILL.md +0 -123
  282. moai_adk/templates/.claude/skills/moai-domain-data-science/examples.md +0 -29
  283. moai_adk/templates/.claude/skills/moai-domain-data-science/reference.md +0 -30
  284. moai_adk/templates/.claude/skills/moai-domain-database/SKILL.md +0 -123
  285. moai_adk/templates/.claude/skills/moai-domain-database/examples.md +0 -29
  286. moai_adk/templates/.claude/skills/moai-domain-database/reference.md +0 -30
  287. moai_adk/templates/.claude/skills/moai-domain-devops/SKILL.md +0 -124
  288. moai_adk/templates/.claude/skills/moai-domain-devops/examples.md +0 -29
  289. moai_adk/templates/.claude/skills/moai-domain-devops/reference.md +0 -31
  290. moai_adk/templates/.claude/skills/moai-domain-frontend/SKILL.md +0 -128
  291. moai_adk/templates/.claude/skills/moai-domain-frontend/examples.md +0 -29
  292. moai_adk/templates/.claude/skills/moai-domain-frontend/reference.md +0 -31
  293. moai_adk/templates/.claude/skills/moai-domain-ml/SKILL.md +0 -123
  294. moai_adk/templates/.claude/skills/moai-domain-ml/examples.md +0 -29
  295. moai_adk/templates/.claude/skills/moai-domain-ml/reference.md +0 -30
  296. moai_adk/templates/.claude/skills/moai-domain-mobile-app/SKILL.md +0 -123
  297. moai_adk/templates/.claude/skills/moai-domain-mobile-app/examples.md +0 -29
  298. moai_adk/templates/.claude/skills/moai-domain-mobile-app/reference.md +0 -30
  299. moai_adk/templates/.claude/skills/moai-domain-security/SKILL.md +0 -123
  300. moai_adk/templates/.claude/skills/moai-domain-security/examples.md +0 -29
  301. moai_adk/templates/.claude/skills/moai-domain-security/reference.md +0 -30
  302. moai_adk/templates/.claude/skills/moai-domain-web-api/SKILL.md +0 -123
  303. moai_adk/templates/.claude/skills/moai-domain-web-api/examples.md +0 -29
  304. moai_adk/templates/.claude/skills/moai-domain-web-api/reference.md +0 -30
  305. moai_adk/templates/.claude/skills/moai-essentials-debug/SKILL.md +0 -303
  306. moai_adk/templates/.claude/skills/moai-essentials-debug/examples.md +0 -1064
  307. moai_adk/templates/.claude/skills/moai-essentials-debug/reference.md +0 -1047
  308. moai_adk/templates/.claude/skills/moai-essentials-perf/SKILL.md +0 -113
  309. moai_adk/templates/.claude/skills/moai-essentials-perf/examples.md +0 -29
  310. moai_adk/templates/.claude/skills/moai-essentials-perf/reference.md +0 -28
  311. moai_adk/templates/.claude/skills/moai-essentials-refactor/SKILL.md +0 -113
  312. moai_adk/templates/.claude/skills/moai-essentials-refactor/examples.md +0 -29
  313. moai_adk/templates/.claude/skills/moai-essentials-refactor/reference.md +0 -28
  314. moai_adk/templates/.claude/skills/moai-essentials-review/SKILL.md +0 -113
  315. moai_adk/templates/.claude/skills/moai-essentials-review/examples.md +0 -29
  316. moai_adk/templates/.claude/skills/moai-essentials-review/reference.md +0 -28
  317. moai_adk/templates/.claude/skills/moai-foundation-ears/SKILL.md +0 -116
  318. moai_adk/templates/.claude/skills/moai-foundation-ears/examples.md +0 -29
  319. moai_adk/templates/.claude/skills/moai-foundation-ears/reference.md +0 -28
  320. moai_adk/templates/.claude/skills/moai-foundation-git/SKILL.md +0 -122
  321. moai_adk/templates/.claude/skills/moai-foundation-git/examples.md +0 -29
  322. moai_adk/templates/.claude/skills/moai-foundation-git/reference.md +0 -29
  323. moai_adk/templates/.claude/skills/moai-foundation-langs/SKILL.md +0 -113
  324. moai_adk/templates/.claude/skills/moai-foundation-langs/examples.md +0 -29
  325. moai_adk/templates/.claude/skills/moai-foundation-langs/reference.md +0 -28
  326. moai_adk/templates/.claude/skills/moai-foundation-specs/SKILL.md +0 -113
  327. moai_adk/templates/.claude/skills/moai-foundation-specs/examples.md +0 -29
  328. moai_adk/templates/.claude/skills/moai-foundation-specs/reference.md +0 -28
  329. moai_adk/templates/.claude/skills/moai-foundation-tags/SKILL.md +0 -113
  330. moai_adk/templates/.claude/skills/moai-foundation-tags/examples.md +0 -29
  331. moai_adk/templates/.claude/skills/moai-foundation-tags/reference.md +0 -28
  332. moai_adk/templates/.claude/skills/moai-foundation-trust/SKILL.md +0 -307
  333. moai_adk/templates/.claude/skills/moai-foundation-trust/examples.md +0 -0
  334. moai_adk/templates/.claude/skills/moai-foundation-trust/reference.md +0 -1099
  335. moai_adk/templates/.claude/skills/moai-lang-c/SKILL.md +0 -124
  336. moai_adk/templates/.claude/skills/moai-lang-c/examples.md +0 -29
  337. moai_adk/templates/.claude/skills/moai-lang-c/reference.md +0 -31
  338. moai_adk/templates/.claude/skills/moai-lang-cpp/SKILL.md +0 -124
  339. moai_adk/templates/.claude/skills/moai-lang-cpp/examples.md +0 -29
  340. moai_adk/templates/.claude/skills/moai-lang-cpp/reference.md +0 -31
  341. moai_adk/templates/.claude/skills/moai-lang-csharp/SKILL.md +0 -123
  342. moai_adk/templates/.claude/skills/moai-lang-csharp/examples.md +0 -29
  343. moai_adk/templates/.claude/skills/moai-lang-csharp/reference.md +0 -30
  344. moai_adk/templates/.claude/skills/moai-lang-dart/SKILL.md +0 -123
  345. moai_adk/templates/.claude/skills/moai-lang-dart/examples.md +0 -29
  346. moai_adk/templates/.claude/skills/moai-lang-dart/reference.md +0 -30
  347. moai_adk/templates/.claude/skills/moai-lang-go/SKILL.md +0 -127
  348. moai_adk/templates/.claude/skills/moai-lang-go/examples.md +0 -29
  349. moai_adk/templates/.claude/skills/moai-lang-go/reference.md +0 -31
  350. moai_adk/templates/.claude/skills/moai-lang-java/SKILL.md +0 -126
  351. moai_adk/templates/.claude/skills/moai-lang-java/examples.md +0 -29
  352. moai_adk/templates/.claude/skills/moai-lang-java/reference.md +0 -31
  353. moai_adk/templates/.claude/skills/moai-lang-javascript/SKILL.md +0 -125
  354. moai_adk/templates/.claude/skills/moai-lang-javascript/examples.md +0 -29
  355. moai_adk/templates/.claude/skills/moai-lang-javascript/reference.md +0 -32
  356. moai_adk/templates/.claude/skills/moai-lang-kotlin/SKILL.md +0 -124
  357. moai_adk/templates/.claude/skills/moai-lang-kotlin/examples.md +0 -29
  358. moai_adk/templates/.claude/skills/moai-lang-kotlin/reference.md +0 -31
  359. moai_adk/templates/.claude/skills/moai-lang-php/SKILL.md +0 -126
  360. moai_adk/templates/.claude/skills/moai-lang-php/examples.md +0 -29
  361. moai_adk/templates/.claude/skills/moai-lang-php/reference.md +0 -30
  362. moai_adk/templates/.claude/skills/moai-lang-python/SKILL.md +0 -433
  363. moai_adk/templates/.claude/skills/moai-lang-python/examples.md +0 -624
  364. moai_adk/templates/.claude/skills/moai-lang-python/reference.md +0 -316
  365. moai_adk/templates/.claude/skills/moai-lang-r/SKILL.md +0 -123
  366. moai_adk/templates/.claude/skills/moai-lang-r/examples.md +0 -29
  367. moai_adk/templates/.claude/skills/moai-lang-r/reference.md +0 -30
  368. moai_adk/templates/.claude/skills/moai-lang-ruby/SKILL.md +0 -124
  369. moai_adk/templates/.claude/skills/moai-lang-ruby/examples.md +0 -29
  370. moai_adk/templates/.claude/skills/moai-lang-ruby/reference.md +0 -31
  371. moai_adk/templates/.claude/skills/moai-lang-rust/SKILL.md +0 -127
  372. moai_adk/templates/.claude/skills/moai-lang-rust/examples.md +0 -29
  373. moai_adk/templates/.claude/skills/moai-lang-rust/reference.md +0 -31
  374. moai_adk/templates/.claude/skills/moai-lang-scala/SKILL.md +0 -125
  375. moai_adk/templates/.claude/skills/moai-lang-scala/examples.md +0 -29
  376. moai_adk/templates/.claude/skills/moai-lang-scala/reference.md +0 -30
  377. moai_adk/templates/.claude/skills/moai-lang-shell/SKILL.md +0 -123
  378. moai_adk/templates/.claude/skills/moai-lang-shell/examples.md +0 -29
  379. moai_adk/templates/.claude/skills/moai-lang-shell/reference.md +0 -30
  380. moai_adk/templates/.claude/skills/moai-lang-sql/SKILL.md +0 -124
  381. moai_adk/templates/.claude/skills/moai-lang-sql/examples.md +0 -29
  382. moai_adk/templates/.claude/skills/moai-lang-sql/reference.md +0 -31
  383. moai_adk/templates/.claude/skills/moai-lang-swift/SKILL.md +0 -123
  384. moai_adk/templates/.claude/skills/moai-lang-swift/examples.md +0 -29
  385. moai_adk/templates/.claude/skills/moai-lang-swift/reference.md +0 -30
  386. moai_adk/templates/.claude/skills/moai-lang-typescript/SKILL.md +0 -133
  387. moai_adk/templates/.claude/skills/moai-lang-typescript/examples.md +0 -29
  388. moai_adk/templates/.claude/skills/moai-lang-typescript/reference.md +0 -34
  389. moai_adk/templates/.claude/skills/moai-project-documentation.md +0 -622
  390. moai_adk/templates/.github/workflows/c-tag-validation.yml +0 -11
  391. moai_adk/templates/.github/workflows/cpp-tag-validation.yml +0 -11
  392. moai_adk/templates/.github/workflows/csharp-tag-validation.yml +0 -11
  393. moai_adk/templates/.github/workflows/dart-tag-validation.yml +0 -11
  394. moai_adk/templates/.github/workflows/go-tag-validation.yml +0 -130
  395. moai_adk/templates/.github/workflows/java-tag-validation.yml +0 -11
  396. moai_adk/templates/.github/workflows/javascript-tag-validation.yml +0 -135
  397. moai_adk/templates/.github/workflows/kotlin-tag-validation.yml +0 -11
  398. moai_adk/templates/.github/workflows/php-tag-validation.yml +0 -11
  399. moai_adk/templates/.github/workflows/python-tag-validation.yml +0 -118
  400. moai_adk/templates/.github/workflows/release.yml +0 -118
  401. moai_adk/templates/.github/workflows/ruby-tag-validation.yml +0 -11
  402. moai_adk/templates/.github/workflows/rust-tag-validation.yml +0 -11
  403. moai_adk/templates/.github/workflows/shell-tag-validation.yml +0 -11
  404. moai_adk/templates/.github/workflows/swift-tag-validation.yml +0 -11
  405. moai_adk/templates/.github/workflows/tag-report.yml +0 -269
  406. moai_adk/templates/.github/workflows/tag-validation.yml +0 -186
  407. moai_adk/templates/.github/workflows/typescript-tag-validation.yml +0 -154
  408. moai_adk/templates/.moai/config.json +0 -115
  409. moai_adk/templates/workflows/go-tag-validation.yml +0 -30
  410. moai_adk/templates/workflows/javascript-tag-validation.yml +0 -41
  411. moai_adk/templates/workflows/python-tag-validation.yml +0 -42
  412. moai_adk/templates/workflows/typescript-tag-validation.yml +0 -31
  413. moai_adk-0.15.0.dist-info/METADATA +0 -3079
  414. moai_adk-0.15.0.dist-info/RECORD +0 -365
  415. {moai_adk-0.15.0.dist-info → moai_adk-0.25.4.dist-info}/WHEEL +0 -0
  416. {moai_adk-0.15.0.dist-info → moai_adk-0.25.4.dist-info}/entry_points.txt +0 -0
  417. {moai_adk-0.15.0.dist-info → moai_adk-0.25.4.dist-info}/licenses/LICENSE +0 -0
@@ -1,748 +0,0 @@
1
- #!/usr/bin/env python3
2
- # @CODE:OFFLINE-001 | SPEC: SPEC-OFFLINE-SUPPORT-001 | TEST: tests/unit/test_network_detection.py
3
- """Project metadata utilities
4
-
5
- Project information inquiry (language, Git, SPEC progress, etc.)
6
-
7
- Network detection and caching support:
8
- - is_network_available(): Check network connectivity with timeout
9
- - get_package_version_info(): Get package version with offline cache support
10
- """
11
-
12
- import json
13
- import signal
14
- import socket
15
- import subprocess
16
- from contextlib import contextmanager
17
- from pathlib import Path
18
- from typing import Any
19
-
20
- # Cache directory for version check results
21
- CACHE_DIR_NAME = ".moai/cache"
22
-
23
-
24
- def find_project_root(start_path: str | Path = ".") -> Path:
25
- """Find MoAI-ADK project root by searching upward for .moai/config.json
26
-
27
- Traverses up the directory tree until it finds .moai/config.json or CLAUDE.md,
28
- which indicates the project root. This ensures cache and other files are
29
- always created in the correct location, regardless of where hooks execute.
30
-
31
- Args:
32
- start_path: Starting directory (default: current directory)
33
-
34
- Returns:
35
- Project root Path. If not found, returns start_path as absolute path.
36
-
37
- Examples:
38
- >>> find_project_root(".")
39
- Path("/Users/user/my-project")
40
- >>> find_project_root(".claude/hooks/alfred")
41
- Path("/Users/user/my-project") # Found root 3 levels up
42
-
43
- Notes:
44
- - Searches for .moai/config.json first (most reliable)
45
- - Falls back to CLAUDE.md if config.json not found
46
- - Max depth: 10 levels up (prevent infinite loop)
47
- - Returns absolute path for consistency
48
-
49
- TDD History:
50
- - RED: 4 test scenarios (root, nested, not found, symlinks)
51
- - GREEN: Minimal upward search with .moai/config.json detection
52
- - REFACTOR: Add CLAUDE.md fallback, max depth limit, absolute path return
53
- """
54
- current = Path(start_path).resolve()
55
- max_depth = 10 # Prevent infinite loop
56
-
57
- for _ in range(max_depth):
58
- # Check for .moai/config.json (primary indicator)
59
- if (current / ".moai" / "config.json").exists():
60
- return current
61
-
62
- # Check for CLAUDE.md (secondary indicator)
63
- if (current / "CLAUDE.md").exists():
64
- return current
65
-
66
- # Move up one level
67
- parent = current.parent
68
- if parent == current: # Reached filesystem root
69
- break
70
- current = parent
71
-
72
- # Not found - return start_path as absolute
73
- return Path(start_path).resolve()
74
-
75
-
76
- class TimeoutError(Exception):
77
- """Signal-based timeout exception"""
78
-
79
- pass
80
-
81
-
82
- @contextmanager
83
- def timeout_handler(seconds: int):
84
- """Hard timeout using SIGALRM (works on Unix systems including macOS)
85
-
86
- This uses kernel-level signal to interrupt ANY blocking operation,
87
- even if subprocess.run() timeout fails on macOS.
88
-
89
- Args:
90
- seconds: Timeout duration in seconds
91
-
92
- Raises:
93
- TimeoutError: If operation exceeds timeout
94
- """
95
-
96
- def _handle_timeout(signum, frame):
97
- raise TimeoutError(f"Operation timed out after {seconds} seconds")
98
-
99
- # Set the signal handler
100
- old_handler = signal.signal(signal.SIGALRM, _handle_timeout)
101
- signal.alarm(seconds)
102
- try:
103
- yield
104
- finally:
105
- signal.alarm(0) # Disable alarm
106
- signal.signal(signal.SIGALRM, old_handler)
107
-
108
-
109
- def detect_language(cwd: str) -> str:
110
- """Detect project language (supports 20 items languages)
111
-
112
- Browse the File system to detect your project's main development language.
113
- First, check configuration files such as pyproject.toml and tsconfig.json.
114
- Apply TypeScript first principles (if tsconfig.json exists).
115
-
116
- Args:
117
- cwd: Project root directory path (both absolute and relative paths are possible)
118
-
119
- Returns:
120
- Detected language name (lowercase). If detection fails, "Unknown Language" is returned.
121
- Supported languages: python, typescript, javascript, java, go, rust,
122
- dart, swift, kotlin, php, ruby, elixir, scala,
123
- clojure, cpp, c, csharp, haskell, shell, lua
124
-
125
- Examples:
126
- >>> detect_language("/path/to/python/project")
127
- 'python'
128
- >>> detect_language("/path/to/typescript/project")
129
- 'typescript'
130
- >>> detect_language("/path/to/unknown/project")
131
- 'Unknown Language'
132
-
133
- TDD History:
134
- - RED: Write a 21 items language detection test (20 items language + 1 items unknown)
135
- - GREEN: 20 items language + unknown implementation, all tests passed
136
- - REFACTOR: Optimize file inspection order, apply TypeScript priority principle
137
- """
138
- cwd_path = Path(cwd)
139
-
140
- # Language detection mapping
141
- language_files = {
142
- "pyproject.toml": "python",
143
- "tsconfig.json": "typescript",
144
- "package.json": "javascript",
145
- "pom.xml": "java",
146
- "go.mod": "go",
147
- "Cargo.toml": "rust",
148
- "pubspec.yaml": "dart",
149
- "Package.swift": "swift",
150
- "build.gradle.kts": "kotlin",
151
- "composer.json": "php",
152
- "Gemfile": "ruby",
153
- "mix.exs": "elixir",
154
- "build.sbt": "scala",
155
- "project.clj": "clojure",
156
- "CMakeLists.txt": "cpp",
157
- "Makefile": "c",
158
- }
159
-
160
- # Check standard language files
161
- for file_name, language in language_files.items():
162
- if (cwd_path / file_name).exists():
163
- # Special handling for package.json - prefer typescript if tsconfig exists
164
- if file_name == "package.json" and (cwd_path / "tsconfig.json").exists():
165
- return "typescript"
166
- return language
167
-
168
- # Check for C# project files (*.csproj)
169
- if any(cwd_path.glob("*.csproj")):
170
- return "csharp"
171
-
172
- # Check for Haskell project files (*.cabal)
173
- if any(cwd_path.glob("*.cabal")):
174
- return "haskell"
175
-
176
- # Check for Shell scripts (*.sh)
177
- if any(cwd_path.glob("*.sh")):
178
- return "shell"
179
-
180
- # Check for Lua files (*.lua)
181
- if any(cwd_path.glob("*.lua")):
182
- return "lua"
183
-
184
- return "Unknown Language"
185
-
186
-
187
- def _run_git_command(args: list[str], cwd: str, timeout: int = 2) -> str:
188
- """Git command execution with HARD timeout protection
189
-
190
- Safely execute Git commands and return output.
191
- Uses SIGALRM (kernel-level interrupt) to handle macOS subprocess timeout bug.
192
- Eliminates code duplication and provides consistent error handling.
193
-
194
- Args:
195
- args: Git command argument list (git adds automatically)
196
- cwd: Execution directory path
197
- timeout: Timeout (seconds, default 2 seconds)
198
-
199
- Returns:
200
- Git command output (stdout, removing leading and trailing spaces)
201
-
202
- Raises:
203
- subprocess.TimeoutExpired: Timeout exceeded (via TimeoutError)
204
- subprocess.CalledProcessError: Git command failed
205
-
206
- Examples:
207
- >>> _run_git_command(["branch", "--show-current"], ".")
208
- 'main'
209
-
210
- TDD History:
211
- - RED: Git command hang scenario test
212
- - GREEN: SIGALRM-based timeout implementation
213
- - REFACTOR: Exception conversion to subprocess.TimeoutExpired
214
- """
215
- try:
216
- with timeout_handler(timeout):
217
- result = subprocess.run(
218
- ["git"] + args,
219
- cwd=cwd,
220
- capture_output=True,
221
- text=True,
222
- check=False, # Don't raise on non-zero exit - we'll check manually
223
- )
224
-
225
- # Check exit code manually
226
- if result.returncode != 0:
227
- raise subprocess.CalledProcessError(
228
- result.returncode, ["git"] + args, result.stdout, result.stderr
229
- )
230
-
231
- return result.stdout.strip()
232
-
233
- except TimeoutError:
234
- # Convert to subprocess.TimeoutExpired for consistent error handling
235
- raise subprocess.TimeoutExpired(["git"] + args, timeout)
236
-
237
-
238
- def get_git_info(cwd: str) -> dict[str, Any]:
239
- """Gather Git repository information
240
-
241
- View the current status of a Git repository.
242
- Returns the branch name, commit hash, number of changes, and last commit message.
243
- If it is not a Git repository, it returns an empty dictionary.
244
-
245
- Args:
246
- cwd: Project root directory path
247
-
248
- Returns:
249
- Git information dictionary. Includes the following keys:
250
- - branch: Current branch name (str)
251
- - commit: Current commit hash (str, full hash)
252
- - changes: Number of changed files (int, staged + unstaged)
253
- - last_commit: Last commit message (str, subject only)
254
-
255
- Empty dictionary {} if it is not a Git repository or the query fails.
256
-
257
- Examples:
258
- >>> get_git_info("/path/to/git/repo")
259
- {'branch': 'main', 'commit': 'abc123...', 'changes': 3, 'last_commit': 'Fix bug'}
260
- >>> get_git_info("/path/to/non-git")
261
- {}
262
-
263
- Notes:
264
- - Timeout: 2 seconds for each Git command
265
- - Security: Safe execution with subprocess.run(shell=False)
266
- - Error handling: Returns an empty dictionary in case of all exceptions
267
- - Commit message limited to 50 characters for display purposes
268
-
269
- TDD History:
270
- - RED: 3 items scenario test (Git repo, non-Git, error)
271
- - GREEN: Implementation of subprocess-based Git command execution
272
- - REFACTOR: Add timeout (2 seconds), strengthen exception handling, remove duplicates with helper function
273
- - UPDATE: Added last_commit message field for SessionStart display
274
- """
275
- try:
276
- # Check if it's a git repository
277
- _run_git_command(["rev-parse", "--git-dir"], cwd)
278
-
279
- # Get branch name, commit hash, and changes
280
- branch = _run_git_command(["branch", "--show-current"], cwd)
281
- commit = _run_git_command(["rev-parse", "HEAD"], cwd)
282
- status_output = _run_git_command(["status", "--short"], cwd)
283
- changes = len([line for line in status_output.splitlines() if line])
284
-
285
- # Get last commit message (subject only, limited to 50 chars)
286
- last_commit = _run_git_command(["log", "-1", "--format=%s"], cwd)
287
- if len(last_commit) > 50:
288
- last_commit = last_commit[:47] + "..."
289
-
290
- return {
291
- "branch": branch,
292
- "commit": commit,
293
- "changes": changes,
294
- "last_commit": last_commit,
295
- }
296
-
297
- except (subprocess.TimeoutExpired, subprocess.CalledProcessError, FileNotFoundError):
298
- return {}
299
-
300
-
301
- def count_specs(cwd: str) -> dict[str, int]:
302
- """SPEC File count and progress calculation
303
-
304
- Browse the .moai/specs/ directory to find the number of SPEC Files and
305
- Counts the number of SPECs with status: completed.
306
-
307
- Args:
308
- cwd: Project root directory path (or any subdirectory, will search upward)
309
-
310
- Returns:
311
- SPEC progress dictionary. Includes the following keys:
312
- - completed: Number of completed SPECs (int)
313
- - total: total number of SPECs (int)
314
- - percentage: completion percentage (int, 0~100)
315
-
316
- All 0 if .moai/specs/ directory does not exist
317
-
318
- Examples:
319
- >>> count_specs("/path/to/project")
320
- {'completed': 2, 'total': 5, 'percentage': 40}
321
- >>> count_specs("/path/to/no-specs")
322
- {'completed': 0, 'total': 0, 'percentage': 0}
323
-
324
- Notes:
325
- - SPEC File Location: .moai/specs/SPEC-{ID}/spec.md
326
- - Completion condition: Include "status: completed" in YAML front matter
327
- - If parsing fails, the SPEC is considered incomplete.
328
- - Automatically finds project root to locate .moai/specs/
329
-
330
- TDD History:
331
- - RED: 5 items scenario test (0/0, 2/5, 5/5, no directory, parsing error)
332
- - GREEN: SPEC search with Path.iterdir(), YAML parsing implementation
333
- - REFACTOR: Strengthened exception handling, improved percentage calculation safety
334
- - UPDATE: Add project root detection for consistent path resolution
335
- """
336
- # Find project root to ensure we read specs from correct location
337
- project_root = find_project_root(cwd)
338
- specs_dir = project_root / ".moai" / "specs"
339
-
340
- if not specs_dir.exists():
341
- return {"completed": 0, "total": 0, "percentage": 0}
342
-
343
- completed = 0
344
- total = 0
345
-
346
- for spec_dir in specs_dir.iterdir():
347
- if not spec_dir.is_dir() or not spec_dir.name.startswith("SPEC-"):
348
- continue
349
-
350
- spec_file = spec_dir / "spec.md"
351
- if not spec_file.exists():
352
- continue
353
-
354
- total += 1
355
-
356
- # Parse YAML front matter
357
- try:
358
- content = spec_file.read_text()
359
- if content.startswith("---"):
360
- yaml_end = content.find("---", 3)
361
- if yaml_end > 0:
362
- yaml_content = content[3:yaml_end]
363
- if "status: completed" in yaml_content:
364
- completed += 1
365
- except (OSError, UnicodeDecodeError):
366
- # File read failure or encoding error - considered incomplete
367
- pass
368
-
369
- percentage = int(completed / total * 100) if total > 0 else 0
370
-
371
- return {
372
- "completed": completed,
373
- "total": total,
374
- "percentage": percentage,
375
- }
376
-
377
-
378
- def get_project_language(cwd: str) -> str:
379
- """Determine the primary project language (prefers config.json).
380
-
381
- Args:
382
- cwd: Project root directory (or any subdirectory, will search upward).
383
-
384
- Returns:
385
- Language string in lower-case.
386
-
387
- Notes:
388
- - Reads ``.moai/config.json`` first for a quick answer.
389
- - Falls back to ``detect_language`` if configuration is missing.
390
- - Automatically finds project root to locate .moai/config.json
391
- """
392
- # Find project root to ensure we read config from correct location
393
- project_root = find_project_root(cwd)
394
- config_path = project_root / ".moai" / "config.json"
395
- if config_path.exists():
396
- try:
397
- config = json.loads(config_path.read_text())
398
- lang = config.get("language", "")
399
- if lang:
400
- return lang
401
- except (OSError, json.JSONDecodeError):
402
- # Fall back to detection on parse errors
403
- pass
404
-
405
- # Fall back to the original language detection routine (use project root)
406
- return detect_language(str(project_root))
407
-
408
-
409
- # @CODE:CONFIG-INTEGRATION-001
410
- def get_version_check_config(cwd: str) -> dict[str, Any]:
411
- """Read version check configuration from .moai/config.json
412
-
413
- Returns version check settings with sensible defaults.
414
- Supports frequency-based cache TTL configuration.
415
-
416
- Args:
417
- cwd: Project root directory path
418
-
419
- Returns:
420
- dict with keys:
421
- - "enabled": Boolean (default: True)
422
- - "frequency": "always" | "daily" | "weekly" | "never" (default: "daily")
423
- - "cache_ttl_hours": TTL in hours based on frequency
424
-
425
- Frequency to TTL mapping:
426
- - "always": 0 hours (no caching)
427
- - "daily": 24 hours
428
- - "weekly": 168 hours (7 days)
429
- - "never": infinity (never check)
430
-
431
- TDD History:
432
- - RED: 8 test scenarios (defaults, custom, disabled, TTL, etc.)
433
- - GREEN: Minimal config reading with defaults
434
- - REFACTOR: Add validation and error handling
435
- """
436
- # TTL mapping by frequency
437
- ttl_by_frequency = {"always": 0, "daily": 24, "weekly": 168, "never": float("inf")}
438
-
439
- # Default configuration
440
- defaults = {"enabled": True, "frequency": "daily", "cache_ttl_hours": 24}
441
-
442
- # Find project root to ensure we read config from correct location
443
- project_root = find_project_root(cwd)
444
- config_path = project_root / ".moai" / "config.json"
445
- if not config_path.exists():
446
- return defaults
447
-
448
- try:
449
- config = json.loads(config_path.read_text())
450
-
451
- # Extract moai.version_check section
452
- moai_config = config.get("moai", {})
453
- version_check_config = moai_config.get("version_check", {})
454
-
455
- # Read enabled flag (default: True)
456
- enabled = version_check_config.get("enabled", defaults["enabled"])
457
-
458
- # Read frequency (default: "daily")
459
- frequency = moai_config.get("update_check_frequency", defaults["frequency"])
460
-
461
- # Validate frequency
462
- if frequency not in ttl_by_frequency:
463
- frequency = defaults["frequency"]
464
-
465
- # Calculate TTL from frequency
466
- cache_ttl_hours = ttl_by_frequency[frequency]
467
-
468
- # Allow explicit cache_ttl_hours override
469
- if "cache_ttl_hours" in version_check_config:
470
- cache_ttl_hours = version_check_config["cache_ttl_hours"]
471
-
472
- return {"enabled": enabled, "frequency": frequency, "cache_ttl_hours": cache_ttl_hours}
473
-
474
- except (OSError, json.JSONDecodeError, KeyError):
475
- # Config read or parse error - return defaults
476
- return defaults
477
-
478
-
479
- # @CODE:NETWORK-DETECT-001
480
- def is_network_available(timeout_seconds: float = 0.1) -> bool:
481
- """Quick network availability check using socket.
482
-
483
- Does NOT check PyPI specifically, just basic connectivity.
484
- Returns immediately on success (< 50ms typically).
485
- Returns False on any error without raising exceptions.
486
-
487
- Args:
488
- timeout_seconds: Socket timeout in seconds (default 0.1s)
489
-
490
- Returns:
491
- True if network appears available, False otherwise
492
-
493
- Examples:
494
- >>> is_network_available()
495
- True # Network is available
496
- >>> is_network_available(timeout_seconds=0.001)
497
- False # Timeout too short, returns False
498
-
499
- TDD History:
500
- - RED: 3 test scenarios (success, failure, timeout)
501
- - GREEN: Minimal socket.create_connection implementation
502
- - REFACTOR: Add error handling for all exception types
503
- """
504
- try:
505
- # Try connecting to Google's public DNS server (8.8.8.8:53)
506
- # This is a reliable host that's typically reachable
507
- connection = socket.create_connection(("8.8.8.8", 53), timeout=timeout_seconds)
508
- connection.close()
509
- return True
510
- except (socket.timeout, OSError, Exception):
511
- # Any connection error means network is unavailable
512
- # This includes: timeout, connection refused, network unreachable, etc.
513
- return False
514
-
515
-
516
- # @CODE:VERSION-DETECT-MAJOR-001
517
- def is_major_version_change(current: str, latest: str) -> bool:
518
- """Detect if version change is a major version bump.
519
-
520
- A major version change is when the first (major) component increases:
521
- - 0.8.1 → 1.0.0: True (0 → 1)
522
- - 1.2.3 → 2.0.0: True (1 → 2)
523
- - 0.8.1 → 0.9.0: False (0 → 0, minor changed)
524
- - 1.2.3 → 1.3.0: False (1 → 1)
525
-
526
- Args:
527
- current: Current version string (e.g., "0.8.1")
528
- latest: Latest version string (e.g., "1.0.0")
529
-
530
- Returns:
531
- True if major version increased, False otherwise
532
-
533
- Examples:
534
- >>> is_major_version_change("0.8.1", "1.0.0")
535
- True
536
- >>> is_major_version_change("0.8.1", "0.9.0")
537
- False
538
- >>> is_major_version_change("dev", "1.0.0")
539
- False # Invalid versions return False
540
-
541
- TDD History:
542
- - RED: 4 test scenarios (0→1, 1→2, minor, invalid)
543
- - GREEN: Minimal version parsing and comparison
544
- - REFACTOR: Improve error handling for invalid versions
545
- """
546
- try:
547
- # Parse version strings into integer components
548
- current_parts = [int(x) for x in current.split(".")]
549
- latest_parts = [int(x) for x in latest.split(".")]
550
-
551
- # Compare major version (first component)
552
- if len(current_parts) >= 1 and len(latest_parts) >= 1:
553
- return latest_parts[0] > current_parts[0]
554
-
555
- # If parsing succeeds but empty, no major change
556
- return False
557
-
558
- except (ValueError, AttributeError, IndexError):
559
- # Invalid version format - return False (no exception)
560
- return False
561
-
562
-
563
- # @CODE:VERSION-CACHE-INTEGRATION-001
564
- def get_package_version_info(cwd: str = ".") -> dict[str, Any]:
565
- """Check MoAI-ADK current and latest version with caching and offline support.
566
-
567
- Execution flow:
568
- 1. Try to load from cache (< 50ms)
569
- 2. If cache invalid, check network
570
- 3. If network available, query PyPI
571
- 4. If network unavailable, return current version only
572
- 5. Save result to cache for next time
573
-
574
- Args:
575
- cwd: Project root directory (for cache location)
576
-
577
- Returns:
578
- dict with keys:
579
- - "current": Current installed version
580
- - "latest": Latest version available on PyPI
581
- - "update_available": Boolean indicating if update is available
582
- - "upgrade_command": Recommended upgrade command (if update available)
583
- - "release_notes_url": URL to release notes (Phase 3)
584
- - "is_major_update": Boolean indicating major version change (Phase 3)
585
-
586
- Note:
587
- - Cache hit (< 24 hours): Returns in ~20ms, no network access
588
- - Cache miss + online: Query PyPI (1s timeout), cache result
589
- - Cache miss + offline: Return current version only (~100ms)
590
- - Offline + cached: Return from cache in ~20ms
591
-
592
- TDD History:
593
- - RED: 5 test scenarios (network detection, cache integration, offline mode)
594
- - GREEN: Integrate VersionCache with network detection
595
- - REFACTOR: Extract cache directory constant, improve error handling
596
- - Phase 3: Add release_notes_url and is_major_update fields (@CODE:VERSION-INTEGRATE-FIELDS-001)
597
- """
598
- import importlib.util
599
- import urllib.error
600
- import urllib.request
601
- from importlib.metadata import PackageNotFoundError, version
602
-
603
- # Import VersionCache from the same directory (using dynamic import for testing compatibility)
604
- try:
605
- version_cache_path = Path(__file__).parent / "version_cache.py"
606
- spec = importlib.util.spec_from_file_location("version_cache", version_cache_path)
607
- if spec and spec.loader:
608
- version_cache_module = importlib.util.module_from_spec(spec)
609
- spec.loader.exec_module(version_cache_module)
610
- version_cache_class = version_cache_module.VersionCache
611
- else:
612
- # Skip caching if module can't be loaded
613
- version_cache_class = None
614
- except (ImportError, OSError):
615
- # Graceful degradation: skip caching on import errors
616
- version_cache_class = None
617
-
618
- # 1. Find project root (ensure cache is always in correct location)
619
- # This prevents creating .moai/cache in wrong locations when hooks run
620
- # from subdirectories like .claude/hooks/alfred/
621
- project_root = find_project_root(cwd)
622
-
623
- # 2. Initialize cache (skip if VersionCache couldn't be imported)
624
- cache_dir = project_root / CACHE_DIR_NAME
625
- version_cache = version_cache_class(cache_dir) if version_cache_class else None
626
-
627
- # 2. Get current installed version first (needed for cache validation)
628
- current_version = "unknown"
629
- try:
630
- current_version = version("moai-adk")
631
- except PackageNotFoundError:
632
- current_version = "dev"
633
- # Dev mode - skip cache and return immediately
634
- return {
635
- "current": "dev",
636
- "latest": "unknown",
637
- "update_available": False,
638
- "upgrade_command": "",
639
- }
640
-
641
- # 3. Try to load from cache (fast path with version validation)
642
- if version_cache and version_cache.is_valid():
643
- cached_info = version_cache.load()
644
- if cached_info:
645
- # Only use cache if the cached version matches current installed version
646
- # This prevents stale cache when package is upgraded locally
647
- if cached_info.get("current") == current_version:
648
- # Ensure new fields exist for backward compatibility
649
- if "release_notes_url" not in cached_info:
650
- # Add missing fields to old cached data
651
- cached_info.setdefault("release_notes_url", None)
652
- cached_info.setdefault("is_major_update", False)
653
- return cached_info
654
- # else: cache is stale (version changed), fall through to re-check
655
-
656
- # 4. Cache miss or stale - need to query PyPI
657
- result = {
658
- "current": current_version,
659
- "latest": "unknown",
660
- "update_available": False,
661
- "upgrade_command": "",
662
- }
663
-
664
- # 5. Check if version check is enabled in config
665
- config = get_version_check_config(cwd)
666
- if not config["enabled"]:
667
- # Version check disabled - return only current version
668
- return result
669
-
670
- # 6. Check network before PyPI query
671
- if not is_network_available():
672
- # Offline mode - return current version only
673
- return result
674
-
675
- # 7. Network available - query PyPI
676
- pypi_data = None
677
- try:
678
- with timeout_handler(1):
679
- url = "https://pypi.org/pypi/moai-adk/json"
680
- headers = {"Accept": "application/json"}
681
- req = urllib.request.Request(url, headers=headers)
682
- with urllib.request.urlopen(req, timeout=0.8) as response:
683
- pypi_data = json.load(response)
684
- result["latest"] = pypi_data.get("info", {}).get("version", "unknown")
685
-
686
- # Extract release notes URL from project_urls
687
- try:
688
- project_urls = pypi_data.get("info", {}).get("project_urls", {})
689
- release_url = project_urls.get("Changelog", "")
690
- if not release_url:
691
- # Fallback to GitHub releases URL pattern
692
- release_url = (
693
- f"https://github.com/modu-ai/moai-adk/releases/tag/v{result['latest']}"
694
- )
695
- result["release_notes_url"] = release_url
696
- except (KeyError, AttributeError, TypeError):
697
- result["release_notes_url"] = None
698
-
699
- except (urllib.error.URLError, TimeoutError, Exception):
700
- # PyPI query failed - return current version
701
- result["release_notes_url"] = None
702
- pass
703
-
704
- # 7. Compare versions (simple comparison)
705
- if result["current"] != "unknown" and result["latest"] != "unknown":
706
- try:
707
- # Parse versions for comparison
708
- current_parts = [int(x) for x in result["current"].split(".")]
709
- latest_parts = [int(x) for x in result["latest"].split(".")]
710
-
711
- # Pad shorter version with zeros
712
- max_len = max(len(current_parts), len(latest_parts))
713
- current_parts.extend([0] * (max_len - len(current_parts)))
714
- latest_parts.extend([0] * (max_len - len(latest_parts)))
715
-
716
- if latest_parts > current_parts:
717
- result["update_available"] = True
718
- result["upgrade_command"] = f"uv pip install --upgrade moai-adk>={result['latest']}"
719
-
720
- # Detect major version change
721
- result["is_major_update"] = is_major_version_change(
722
- result["current"], result["latest"]
723
- )
724
- else:
725
- result["is_major_update"] = False
726
- except (ValueError, AttributeError):
727
- # Version parsing failed - skip comparison
728
- result["is_major_update"] = False
729
- pass
730
-
731
- # 8. Save result to cache (if caching is available)
732
- if version_cache:
733
- version_cache.save(result)
734
-
735
- return result
736
-
737
-
738
- __all__ = [
739
- "find_project_root",
740
- "detect_language",
741
- "get_git_info",
742
- "count_specs",
743
- "get_project_language",
744
- "get_version_check_config",
745
- "is_network_available",
746
- "is_major_version_change",
747
- "get_package_version_info",
748
- ]