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.

Files changed (433) hide show
  1. moai_adk/__init__.py +1 -1
  2. moai_adk/__main__.py +74 -1
  3. moai_adk/cli/commands/__init__.py +1 -1
  4. moai_adk/cli/commands/analyze.py +119 -0
  5. moai_adk/cli/commands/backup.py +25 -1
  6. moai_adk/cli/commands/doctor.py +31 -5
  7. moai_adk/cli/commands/improve_user_experience.py +307 -0
  8. moai_adk/cli/commands/init.py +111 -10
  9. moai_adk/cli/commands/status.py +33 -3
  10. moai_adk/cli/commands/update.py +921 -130
  11. moai_adk/cli/commands/validate_links.py +120 -0
  12. moai_adk/cli/prompts/init_prompts.py +22 -87
  13. moai_adk/core/analysis/__init__.py +9 -0
  14. moai_adk/core/analysis/session_analyzer.py +388 -0
  15. moai_adk/core/analysis/tag_chain_analyzer.py +344 -0
  16. moai_adk/core/analysis/tag_chain_repair.py +879 -0
  17. moai_adk/core/config/__init__.py +19 -0
  18. moai_adk/core/config/migration.py +235 -0
  19. moai_adk/core/git/__init__.py +1 -1
  20. moai_adk/core/git/branch.py +1 -1
  21. moai_adk/core/git/commit.py +1 -1
  22. moai_adk/core/git/manager.py +1 -1
  23. moai_adk/core/issue_creator.py +313 -0
  24. moai_adk/core/mcp/setup.py +56 -0
  25. moai_adk/core/mcp/setup_old.py +296 -0
  26. moai_adk/core/project/backup_utils.py +1 -1
  27. moai_adk/core/project/checker.py +2 -2
  28. moai_adk/core/project/detector.py +211 -12
  29. moai_adk/core/project/initializer.py +85 -15
  30. moai_adk/core/project/phase_executor.py +76 -13
  31. moai_adk/core/project/validator.py +13 -13
  32. moai_adk/core/quality/__init__.py +1 -1
  33. moai_adk/core/quality/trust_checker.py +1 -1
  34. moai_adk/core/quality/validators/__init__.py +1 -1
  35. moai_adk/core/quality/validators/base_validator.py +1 -1
  36. moai_adk/core/tags/__init__.py +86 -0
  37. moai_adk/core/tags/auto_corrector.py +693 -0
  38. moai_adk/core/tags/ci_validator.py +463 -0
  39. moai_adk/core/tags/cli.py +283 -0
  40. moai_adk/core/tags/generator.py +109 -0
  41. moai_adk/core/tags/inserter.py +99 -0
  42. moai_adk/core/tags/mapper.py +126 -0
  43. moai_adk/core/tags/parser.py +76 -0
  44. moai_adk/core/tags/policy_validator.py +580 -0
  45. moai_adk/core/tags/pre_commit_validator.py +421 -0
  46. moai_adk/core/tags/reporter.py +956 -0
  47. moai_adk/core/tags/rollback_manager.py +525 -0
  48. moai_adk/core/tags/tags.py +149 -0
  49. moai_adk/core/tags/validator.py +897 -0
  50. moai_adk/core/template/__init__.py +1 -1
  51. moai_adk/core/template/backup.py +1 -1
  52. moai_adk/core/template/merger.py +50 -1
  53. moai_adk/core/template/processor.py +119 -13
  54. moai_adk/core/template_engine.py +268 -0
  55. moai_adk/templates/.claude/agents/alfred/backend-expert.md +348 -0
  56. moai_adk/templates/.claude/agents/alfred/cc-manager.md +209 -944
  57. moai_adk/templates/.claude/agents/alfred/database-expert.md +352 -0
  58. moai_adk/templates/.claude/agents/alfred/debug-helper.md +34 -5
  59. moai_adk/templates/.claude/agents/alfred/devops-expert.md +464 -0
  60. moai_adk/templates/.claude/agents/alfred/doc-syncer.md +38 -8
  61. moai_adk/templates/.claude/agents/alfred/format-expert.md +469 -0
  62. moai_adk/templates/.claude/agents/alfred/frontend-expert.md +357 -0
  63. moai_adk/templates/.claude/agents/alfred/git-manager.md +128 -9
  64. moai_adk/templates/.claude/agents/alfred/implementation-planner.md +104 -6
  65. moai_adk/templates/.claude/agents/alfred/project-manager.md +88 -16
  66. moai_adk/templates/.claude/agents/alfred/quality-gate.md +36 -9
  67. moai_adk/templates/.claude/agents/alfred/security-expert.md +270 -0
  68. moai_adk/templates/.claude/agents/alfred/skill-factory.md +865 -0
  69. moai_adk/templates/.claude/agents/alfred/spec-builder.md +214 -43
  70. moai_adk/templates/.claude/agents/alfred/tag-agent.md +111 -9
  71. moai_adk/templates/.claude/agents/alfred/tdd-implementer.md +309 -160
  72. moai_adk/templates/.claude/agents/alfred/trust-checker.md +36 -7
  73. moai_adk/templates/.claude/agents/alfred/ui-ux-expert.md +605 -0
  74. moai_adk/templates/.claude/commands/alfred/0-project.md +393 -966
  75. moai_adk/templates/.claude/commands/alfred/1-plan.md +651 -367
  76. moai_adk/templates/.claude/commands/alfred/2-run.md +388 -241
  77. moai_adk/templates/.claude/commands/alfred/3-sync.md +1921 -410
  78. moai_adk/templates/.claude/commands/alfred/9-feedback.md +153 -0
  79. moai_adk/templates/.claude/commands/alfred/release-new.md +3604 -0
  80. moai_adk/templates/.claude/hooks/alfred/core/project.py +484 -20
  81. moai_adk/templates/.claude/hooks/alfred/core/timeout.py +136 -0
  82. moai_adk/templates/.claude/hooks/alfred/core/ttl_cache.py +108 -0
  83. moai_adk/templates/.claude/hooks/alfred/core/version_cache.py +198 -0
  84. moai_adk/templates/.claude/hooks/alfred/handlers/__init__.py +14 -6
  85. moai_adk/templates/.claude/hooks/alfred/post_tool__enable_streaming_ui.py +50 -0
  86. moai_adk/templates/.claude/hooks/alfred/post_tool__log_changes.py +93 -0
  87. moai_adk/templates/.claude/hooks/alfred/post_tool__tag_auto_corrector.py +407 -0
  88. moai_adk/templates/.claude/hooks/alfred/pre_tool__auto_checkpoint.py +99 -0
  89. moai_adk/templates/.claude/hooks/alfred/pre_tool__realtime_tag_monitor.py +335 -0
  90. moai_adk/templates/.claude/hooks/alfred/pre_tool__tag_policy_validator.py +325 -0
  91. moai_adk/templates/.claude/hooks/alfred/session_end__cleanup.py +93 -0
  92. moai_adk/templates/.claude/hooks/alfred/session_start__auto_cleanup.py +580 -0
  93. moai_adk/templates/.claude/hooks/alfred/session_start__show_project_info.py +298 -0
  94. moai_adk/templates/.claude/hooks/alfred/shared/core/__init__.py +170 -0
  95. moai_adk/templates/.claude/hooks/alfred/{core → shared/core}/checkpoint.py +3 -3
  96. moai_adk/templates/.claude/hooks/alfred/{core → shared/core}/context.py +5 -5
  97. moai_adk/templates/.claude/hooks/alfred/shared/core/project.py +749 -0
  98. moai_adk/templates/.claude/hooks/alfred/shared/core/tags.py +230 -0
  99. moai_adk/templates/.claude/hooks/alfred/shared/core/version_cache.py +198 -0
  100. moai_adk/templates/.claude/hooks/alfred/shared/handlers/__init__.py +21 -0
  101. moai_adk/templates/.claude/hooks/alfred/shared/handlers/daily_analysis.py +351 -0
  102. moai_adk/templates/.claude/hooks/alfred/shared/handlers/notification.py +154 -0
  103. moai_adk/templates/.claude/hooks/alfred/shared/handlers/session.py +174 -0
  104. moai_adk/templates/.claude/hooks/alfred/shared/handlers/tool.py +87 -0
  105. moai_adk/templates/.claude/hooks/alfred/shared/handlers/user.py +61 -0
  106. moai_adk/templates/.claude/hooks/alfred/user_prompt__jit_load_docs.py +111 -0
  107. moai_adk/templates/.claude/hooks/alfred/utils/__init__.py +1 -0
  108. moai_adk/templates/.claude/hooks/alfred/utils/hook_config.py +94 -0
  109. moai_adk/templates/.claude/hooks/alfred/utils/timeout.py +161 -0
  110. moai_adk/templates/.claude/output-styles/alfred/alfred-moai-adk-beginner.md +267 -0
  111. moai_adk/templates/.claude/output-styles/alfred/keating-personal-tutor.md +440 -0
  112. moai_adk/templates/.claude/output-styles/alfred/r2d2-agentic-coding.md +583 -0
  113. moai_adk/templates/.claude/settings.json +96 -14
  114. moai_adk/templates/.claude/skills/moai-alfred-agent-guide/SKILL.md +70 -0
  115. moai_adk/templates/.claude/skills/moai-alfred-agent-guide/examples.md +62 -0
  116. moai_adk/templates/.claude/skills/moai-alfred-agent-guide/reference.md +242 -0
  117. moai_adk/templates/.claude/skills/moai-alfred-ask-user-questions/SKILL.md +237 -0
  118. moai_adk/templates/.claude/skills/moai-alfred-ask-user-questions/examples.md +871 -0
  119. moai_adk/templates/.claude/skills/moai-alfred-ask-user-questions/reference.md +653 -0
  120. moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/README.md +162 -0
  121. moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/SKILL.md +227 -0
  122. moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/examples.md +354 -0
  123. moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/reference.md +158 -0
  124. moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/SKILL.md +179 -79
  125. moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/examples.md +117 -0
  126. moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/scripts/pre-review-check.sh +62 -0
  127. moai_adk/templates/.claude/skills/moai-alfred-config-schema/SKILL.md +132 -0
  128. moai_adk/templates/.claude/skills/moai-alfred-config-schema/examples.md +28 -0
  129. moai_adk/templates/.claude/skills/moai-alfred-config-schema/reference.md +444 -0
  130. moai_adk/templates/.claude/skills/moai-alfred-context-budget/SKILL.md +62 -0
  131. moai_adk/templates/.claude/skills/moai-alfred-context-budget/examples.md +28 -0
  132. moai_adk/templates/.claude/skills/moai-alfred-context-budget/reference.md +405 -0
  133. moai_adk/templates/.claude/skills/moai-alfred-dev-guide/SKILL.md +51 -0
  134. moai_adk/templates/.claude/skills/moai-alfred-dev-guide/examples.md +355 -0
  135. moai_adk/templates/.claude/skills/moai-alfred-dev-guide/reference.md +239 -0
  136. moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/SKILL.md +323 -0
  137. moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/examples.md +286 -0
  138. moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/reference.md +126 -0
  139. moai_adk/templates/.claude/skills/moai-alfred-issue-labels/SKILL.md +229 -0
  140. moai_adk/templates/.claude/skills/moai-alfred-issue-labels/examples.md +4 -0
  141. moai_adk/templates/.claude/skills/moai-alfred-issue-labels/reference.md +150 -0
  142. moai_adk/templates/.claude/skills/moai-alfred-language-detection/SKILL.md +87 -73
  143. moai_adk/templates/.claude/skills/moai-alfred-language-detection/examples.md +29 -0
  144. moai_adk/templates/.claude/skills/moai-alfred-language-detection/reference.md +28 -0
  145. moai_adk/templates/.claude/skills/moai-alfred-personas/README.md +42 -0
  146. moai_adk/templates/.claude/skills/moai-alfred-personas/SKILL.md +429 -0
  147. moai_adk/templates/.claude/skills/moai-alfred-personas/examples.md +520 -0
  148. moai_adk/templates/.claude/skills/moai-alfred-personas/reference.md +405 -0
  149. moai_adk/templates/.claude/skills/moai-alfred-practices/SKILL.md +89 -0
  150. moai_adk/templates/.claude/skills/moai-alfred-practices/examples.md +122 -0
  151. moai_adk/templates/.claude/skills/moai-alfred-practices/reference.md +369 -0
  152. moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/SKILL.md +508 -0
  153. moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/examples.md +481 -0
  154. moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/reference.md +100 -0
  155. moai_adk/templates/.claude/skills/moai-alfred-rules/SKILL.md +77 -0
  156. moai_adk/templates/.claude/skills/moai-alfred-rules/examples.md +265 -0
  157. moai_adk/templates/.claude/skills/moai-alfred-rules/reference.md +539 -0
  158. moai_adk/templates/.claude/skills/moai-alfred-session-state/SKILL.md +320 -0
  159. moai_adk/templates/.claude/skills/moai-alfred-session-state/examples.md +4 -0
  160. moai_adk/templates/.claude/skills/moai-alfred-session-state/reference.md +84 -0
  161. moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/README.md +137 -0
  162. moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/SKILL.md +219 -0
  163. moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/examples/validate-spec.sh +161 -0
  164. moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/examples.md +541 -0
  165. moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/reference.md +622 -0
  166. moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/SKILL.md +19 -0
  167. moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/examples.md +4 -0
  168. moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/reference.md +211 -0
  169. moai_adk/templates/.claude/skills/moai-alfred-workflow/SKILL.md +288 -0
  170. moai_adk/templates/.claude/skills/moai-cc-agents/SKILL.md +269 -0
  171. moai_adk/templates/.claude/skills/moai-cc-agents/templates/agent-template.md +32 -0
  172. moai_adk/templates/.claude/skills/moai-cc-claude-md/SKILL.md +298 -0
  173. moai_adk/templates/.claude/skills/moai-cc-claude-md/templates/CLAUDE-template.md +26 -0
  174. moai_adk/templates/.claude/skills/moai-cc-commands/SKILL.md +307 -0
  175. moai_adk/templates/.claude/skills/moai-cc-commands/templates/command-template.md +21 -0
  176. moai_adk/templates/.claude/skills/moai-cc-hooks/SKILL.md +252 -0
  177. moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/pre-bash-check.sh +19 -0
  178. moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/preserve-permissions.sh +19 -0
  179. moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/validate-bash-command.py +24 -0
  180. moai_adk/templates/.claude/skills/moai-cc-mcp-plugins/SKILL.md +199 -0
  181. moai_adk/templates/.claude/skills/moai-cc-mcp-plugins/templates/settings-mcp-template.json +39 -0
  182. moai_adk/templates/.claude/skills/moai-cc-memory/SKILL.md +316 -0
  183. moai_adk/templates/.claude/skills/moai-cc-memory/templates/session-summary-template.md +18 -0
  184. moai_adk/templates/.claude/skills/moai-cc-settings/SKILL.md +263 -0
  185. moai_adk/templates/.claude/skills/moai-cc-settings/templates/settings-complete-template.json +30 -0
  186. moai_adk/templates/.claude/skills/moai-cc-skill-factory/CHECKLIST.md +482 -0
  187. moai_adk/templates/.claude/skills/moai-cc-skill-factory/EXAMPLES.md +303 -0
  188. moai_adk/templates/.claude/skills/moai-cc-skill-factory/INTERACTIVE-DISCOVERY.md +524 -0
  189. moai_adk/templates/.claude/skills/moai-cc-skill-factory/METADATA.md +477 -0
  190. moai_adk/templates/.claude/skills/moai-cc-skill-factory/PARALLEL-ANALYSIS-REPORT.md +429 -0
  191. moai_adk/templates/.claude/skills/moai-cc-skill-factory/PYTHON-VERSION-MATRIX.md +391 -0
  192. moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL-FACTORY-WORKFLOW.md +431 -0
  193. moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL-UPDATE-ADVISOR.md +577 -0
  194. moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL.md +273 -0
  195. moai_adk/templates/.claude/skills/moai-cc-skill-factory/STEP-BY-STEP-GUIDE.md +466 -0
  196. moai_adk/templates/.claude/skills/moai-cc-skill-factory/STRUCTURE.md +583 -0
  197. moai_adk/templates/.claude/skills/moai-cc-skill-factory/WEB-RESEARCH.md +526 -0
  198. moai_adk/templates/.claude/skills/moai-cc-skill-factory/reference.md +608 -0
  199. moai_adk/templates/.claude/skills/moai-cc-skill-factory/scripts/generate-structure.sh +328 -0
  200. moai_adk/templates/.claude/skills/moai-cc-skill-factory/scripts/validate-skill.sh +312 -0
  201. moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/SKILL_TEMPLATE.md +245 -0
  202. moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/examples-template.md +285 -0
  203. moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/reference-template.md +278 -0
  204. moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/scripts-template.sh +303 -0
  205. moai_adk/templates/.claude/skills/moai-cc-skills/SKILL.md +291 -0
  206. moai_adk/templates/.claude/skills/moai-cc-skills/templates/SKILL-template.md +15 -0
  207. moai_adk/templates/.claude/skills/moai-change-logger/SKILL.md +563 -0
  208. moai_adk/templates/.claude/skills/moai-design-systems/SKILL.md +802 -0
  209. moai_adk/templates/.claude/skills/moai-design-systems/examples.md +1238 -0
  210. moai_adk/templates/.claude/skills/moai-design-systems/reference.md +673 -0
  211. moai_adk/templates/.claude/skills/moai-domain-backend/SKILL.md +234 -43
  212. moai_adk/templates/.claude/skills/moai-domain-backend/examples.md +1633 -0
  213. moai_adk/templates/.claude/skills/moai-domain-backend/reference.md +660 -0
  214. moai_adk/templates/.claude/skills/moai-domain-cli-tool/SKILL.md +97 -69
  215. moai_adk/templates/.claude/skills/moai-domain-cli-tool/examples.md +29 -0
  216. moai_adk/templates/.claude/skills/moai-domain-cli-tool/reference.md +30 -0
  217. moai_adk/templates/.claude/skills/moai-domain-data-science/SKILL.md +97 -72
  218. moai_adk/templates/.claude/skills/moai-domain-data-science/examples.md +29 -0
  219. moai_adk/templates/.claude/skills/moai-domain-data-science/reference.md +30 -0
  220. moai_adk/templates/.claude/skills/moai-domain-database/SKILL.md +97 -74
  221. moai_adk/templates/.claude/skills/moai-domain-database/examples.md +29 -0
  222. moai_adk/templates/.claude/skills/moai-domain-database/reference.md +30 -0
  223. moai_adk/templates/.claude/skills/moai-domain-devops/SKILL.md +98 -74
  224. moai_adk/templates/.claude/skills/moai-domain-devops/examples.md +29 -0
  225. moai_adk/templates/.claude/skills/moai-domain-devops/reference.md +31 -0
  226. moai_adk/templates/.claude/skills/moai-domain-frontend/SKILL.md +102 -73
  227. moai_adk/templates/.claude/skills/moai-domain-frontend/examples.md +29 -0
  228. moai_adk/templates/.claude/skills/moai-domain-frontend/reference.md +31 -0
  229. moai_adk/templates/.claude/skills/moai-domain-ml/SKILL.md +97 -73
  230. moai_adk/templates/.claude/skills/moai-domain-ml/examples.md +29 -0
  231. moai_adk/templates/.claude/skills/moai-domain-ml/reference.md +30 -0
  232. moai_adk/templates/.claude/skills/moai-domain-mobile-app/SKILL.md +97 -67
  233. moai_adk/templates/.claude/skills/moai-domain-mobile-app/examples.md +29 -0
  234. moai_adk/templates/.claude/skills/moai-domain-mobile-app/reference.md +30 -0
  235. moai_adk/templates/.claude/skills/moai-domain-security/SKILL.md +97 -79
  236. moai_adk/templates/.claude/skills/moai-domain-security/examples.md +29 -0
  237. moai_adk/templates/.claude/skills/moai-domain-security/reference.md +30 -0
  238. moai_adk/templates/.claude/skills/moai-domain-web-api/SKILL.md +97 -71
  239. moai_adk/templates/.claude/skills/moai-domain-web-api/examples.md +29 -0
  240. moai_adk/templates/.claude/skills/moai-domain-web-api/reference.md +30 -0
  241. moai_adk/templates/.claude/skills/moai-essentials-debug/SKILL.md +265 -64
  242. moai_adk/templates/.claude/skills/moai-essentials-debug/examples.md +1064 -0
  243. moai_adk/templates/.claude/skills/moai-essentials-debug/reference.md +1047 -0
  244. moai_adk/templates/.claude/skills/moai-essentials-perf/SKILL.md +87 -78
  245. moai_adk/templates/.claude/skills/moai-essentials-perf/examples.md +29 -0
  246. moai_adk/templates/.claude/skills/moai-essentials-perf/reference.md +28 -0
  247. moai_adk/templates/.claude/skills/moai-essentials-refactor/SKILL.md +87 -70
  248. moai_adk/templates/.claude/skills/moai-essentials-refactor/examples.md +29 -0
  249. moai_adk/templates/.claude/skills/moai-essentials-refactor/reference.md +28 -0
  250. moai_adk/templates/.claude/skills/moai-essentials-review/SKILL.md +87 -86
  251. moai_adk/templates/.claude/skills/moai-essentials-review/examples.md +29 -0
  252. moai_adk/templates/.claude/skills/moai-essentials-review/reference.md +28 -0
  253. moai_adk/templates/.claude/skills/moai-foundation-ears/SKILL.md +80 -62
  254. moai_adk/templates/.claude/skills/moai-foundation-ears/examples.md +29 -0
  255. moai_adk/templates/.claude/skills/moai-foundation-ears/reference.md +28 -0
  256. moai_adk/templates/.claude/skills/moai-foundation-git/SKILL.md +207 -50
  257. moai_adk/templates/.claude/skills/moai-foundation-git/examples.md +29 -0
  258. moai_adk/templates/.claude/skills/moai-foundation-git/reference.md +29 -0
  259. moai_adk/templates/.claude/skills/moai-foundation-langs/SKILL.md +90 -71
  260. moai_adk/templates/.claude/skills/moai-foundation-langs/examples.md +29 -0
  261. moai_adk/templates/.claude/skills/moai-foundation-langs/reference.md +28 -0
  262. moai_adk/templates/.claude/skills/moai-foundation-specs/SKILL.md +78 -58
  263. moai_adk/templates/.claude/skills/moai-foundation-specs/examples.md +29 -0
  264. moai_adk/templates/.claude/skills/moai-foundation-specs/reference.md +28 -0
  265. moai_adk/templates/.claude/skills/moai-foundation-tags/SKILL.md +78 -51
  266. moai_adk/templates/.claude/skills/moai-foundation-tags/examples.md +29 -0
  267. moai_adk/templates/.claude/skills/moai-foundation-tags/reference.md +28 -0
  268. moai_adk/templates/.claude/skills/moai-foundation-trust/.!11330!examples.md +0 -0
  269. moai_adk/templates/.claude/skills/moai-foundation-trust/SKILL.md +253 -32
  270. moai_adk/templates/.claude/skills/moai-foundation-trust/examples.md +0 -0
  271. moai_adk/templates/.claude/skills/moai-foundation-trust/reference.md +1099 -0
  272. moai_adk/templates/.claude/skills/moai-jit-docs-enhanced/SKILL.md +460 -0
  273. moai_adk/templates/.claude/skills/moai-lang-c/SKILL.md +98 -74
  274. moai_adk/templates/.claude/skills/moai-lang-c/examples.md +29 -0
  275. moai_adk/templates/.claude/skills/moai-lang-c/reference.md +31 -0
  276. moai_adk/templates/.claude/skills/moai-lang-cpp/SKILL.md +98 -76
  277. moai_adk/templates/.claude/skills/moai-lang-cpp/examples.md +29 -0
  278. moai_adk/templates/.claude/skills/moai-lang-cpp/reference.md +31 -0
  279. moai_adk/templates/.claude/skills/moai-lang-csharp/SKILL.md +2358 -70
  280. moai_adk/templates/.claude/skills/moai-lang-csharp/examples.md +29 -0
  281. moai_adk/templates/.claude/skills/moai-lang-csharp/reference.md +30 -0
  282. moai_adk/templates/.claude/skills/moai-lang-dart/SKILL.md +2962 -68
  283. moai_adk/templates/.claude/skills/moai-lang-dart/examples.md +29 -0
  284. moai_adk/templates/.claude/skills/moai-lang-dart/reference.md +30 -0
  285. moai_adk/templates/.claude/skills/moai-lang-go/SKILL.md +1898 -70
  286. moai_adk/templates/.claude/skills/moai-lang-go/examples.md +29 -0
  287. moai_adk/templates/.claude/skills/moai-lang-go/reference.md +31 -0
  288. moai_adk/templates/.claude/skills/moai-lang-java/SKILL.md +1465 -68
  289. moai_adk/templates/.claude/skills/moai-lang-java/examples.md +29 -0
  290. moai_adk/templates/.claude/skills/moai-lang-java/reference.md +31 -0
  291. moai_adk/templates/.claude/skills/moai-lang-javascript/SKILL.md +2364 -66
  292. moai_adk/templates/.claude/skills/moai-lang-javascript/examples.md +29 -0
  293. moai_adk/templates/.claude/skills/moai-lang-javascript/reference.md +32 -0
  294. moai_adk/templates/.claude/skills/moai-lang-kotlin/SKILL.md +1630 -69
  295. moai_adk/templates/.claude/skills/moai-lang-kotlin/examples.md +29 -0
  296. moai_adk/templates/.claude/skills/moai-lang-kotlin/reference.md +31 -0
  297. moai_adk/templates/.claude/skills/moai-lang-php/SKILL.md +89 -61
  298. moai_adk/templates/.claude/skills/moai-lang-php/examples.md +29 -0
  299. moai_adk/templates/.claude/skills/moai-lang-php/reference.md +30 -0
  300. moai_adk/templates/.claude/skills/moai-lang-python/SKILL.md +735 -66
  301. moai_adk/templates/.claude/skills/moai-lang-python/examples.md +624 -0
  302. moai_adk/templates/.claude/skills/moai-lang-python/reference.md +316 -0
  303. moai_adk/templates/.claude/skills/moai-lang-r/SKILL.md +97 -73
  304. moai_adk/templates/.claude/skills/moai-lang-r/examples.md +29 -0
  305. moai_adk/templates/.claude/skills/moai-lang-r/reference.md +30 -0
  306. moai_adk/templates/.claude/skills/moai-lang-ruby/SKILL.md +98 -73
  307. moai_adk/templates/.claude/skills/moai-lang-ruby/examples.md +29 -0
  308. moai_adk/templates/.claude/skills/moai-lang-ruby/reference.md +31 -0
  309. moai_adk/templates/.claude/skills/moai-lang-rust/SKILL.md +1834 -70
  310. moai_adk/templates/.claude/skills/moai-lang-rust/examples.md +29 -0
  311. moai_adk/templates/.claude/skills/moai-lang-rust/reference.md +31 -0
  312. moai_adk/templates/.claude/skills/moai-lang-scala/SKILL.md +99 -74
  313. moai_adk/templates/.claude/skills/moai-lang-scala/examples.md +29 -0
  314. moai_adk/templates/.claude/skills/moai-lang-scala/reference.md +30 -0
  315. moai_adk/templates/.claude/skills/moai-lang-shell/SKILL.md +97 -74
  316. moai_adk/templates/.claude/skills/moai-lang-shell/examples.md +29 -0
  317. moai_adk/templates/.claude/skills/moai-lang-shell/reference.md +30 -0
  318. moai_adk/templates/.claude/skills/moai-lang-sql/SKILL.md +98 -74
  319. moai_adk/templates/.claude/skills/moai-lang-sql/examples.md +29 -0
  320. moai_adk/templates/.claude/skills/moai-lang-sql/reference.md +31 -0
  321. moai_adk/templates/.claude/skills/moai-lang-swift/SKILL.md +1959 -69
  322. moai_adk/templates/.claude/skills/moai-lang-swift/examples.md +29 -0
  323. moai_adk/templates/.claude/skills/moai-lang-swift/reference.md +30 -0
  324. moai_adk/templates/.claude/skills/moai-lang-template/SKILL.md +348 -0
  325. moai_adk/templates/.claude/skills/moai-lang-template/VARIABLES.md +98 -0
  326. moai_adk/templates/.claude/skills/moai-lang-typescript/SKILL.md +1230 -66
  327. moai_adk/templates/.claude/skills/moai-lang-typescript/examples.md +29 -0
  328. moai_adk/templates/.claude/skills/moai-lang-typescript/reference.md +34 -0
  329. moai_adk/templates/.claude/skills/moai-learning-optimizer/SKILL.md +575 -0
  330. moai_adk/templates/.claude/skills/moai-project-batch-questions/README.md +50 -0
  331. moai_adk/templates/.claude/skills/moai-project-batch-questions/SKILL.md +304 -0
  332. moai_adk/templates/.claude/skills/moai-project-batch-questions/examples.md +417 -0
  333. moai_adk/templates/.claude/skills/moai-project-batch-questions/reference.md +704 -0
  334. moai_adk/templates/.claude/skills/moai-project-config-manager/README.md +87 -0
  335. moai_adk/templates/.claude/skills/moai-project-config-manager/SKILL.md +552 -0
  336. moai_adk/templates/.claude/skills/moai-project-config-manager/examples.md +1109 -0
  337. moai_adk/templates/.claude/skills/moai-project-config-manager/reference.md +514 -0
  338. moai_adk/templates/.claude/skills/moai-project-config-manager/validate.py +106 -0
  339. moai_adk/templates/.claude/skills/moai-project-documentation/README.md +11 -0
  340. moai_adk/templates/.claude/skills/moai-project-documentation/SKILL.md +622 -0
  341. moai_adk/templates/.claude/skills/moai-project-documentation/examples.md +20 -0
  342. moai_adk/templates/.claude/skills/moai-project-documentation/reference.md +12 -0
  343. moai_adk/templates/.claude/skills/moai-project-language-initializer/README.md +152 -0
  344. moai_adk/templates/.claude/skills/moai-project-language-initializer/SKILL.md +285 -0
  345. moai_adk/templates/.claude/skills/moai-project-language-initializer/examples.md +333 -0
  346. moai_adk/templates/.claude/skills/moai-project-language-initializer/reference.md +386 -0
  347. moai_adk/templates/.claude/skills/moai-project-template-optimizer/README.md +49 -0
  348. moai_adk/templates/.claude/skills/moai-project-template-optimizer/SKILL.md +319 -0
  349. moai_adk/templates/.claude/skills/moai-project-template-optimizer/examples.md +58 -0
  350. moai_adk/templates/.claude/skills/moai-project-template-optimizer/reference.md +123 -0
  351. moai_adk/templates/.claude/skills/moai-session-info/SKILL.md +314 -0
  352. moai_adk/templates/.claude/skills/moai-streaming-ui/SKILL.md +552 -0
  353. moai_adk/templates/.claude/skills/moai-tag-policy-validator/SKILL.md +570 -0
  354. moai_adk/templates/.git-hooks/pre-commit +66 -0
  355. moai_adk/templates/.git-hooks/pre-push +255 -0
  356. moai_adk/templates/.github/workflows/c-tag-validation.yml +11 -0
  357. moai_adk/templates/.github/workflows/cpp-tag-validation.yml +11 -0
  358. moai_adk/templates/.github/workflows/csharp-tag-validation.yml +11 -0
  359. moai_adk/templates/.github/workflows/dart-tag-validation.yml +11 -0
  360. moai_adk/templates/.github/workflows/go-tag-validation.yml +130 -0
  361. moai_adk/templates/.github/workflows/java-tag-validation.yml +11 -0
  362. moai_adk/templates/.github/workflows/javascript-tag-validation.yml +135 -0
  363. moai_adk/templates/.github/workflows/kotlin-tag-validation.yml +11 -0
  364. moai_adk/templates/.github/workflows/moai-gitflow.yml +166 -3
  365. moai_adk/templates/.github/workflows/moai-release-create.yml +100 -0
  366. moai_adk/templates/.github/workflows/moai-release-pipeline.yml +188 -0
  367. moai_adk/templates/.github/workflows/php-tag-validation.yml +11 -0
  368. moai_adk/templates/.github/workflows/python-tag-validation.yml +118 -0
  369. moai_adk/templates/.github/workflows/release.yml +118 -0
  370. moai_adk/templates/.github/workflows/ruby-tag-validation.yml +11 -0
  371. moai_adk/templates/.github/workflows/rust-tag-validation.yml +11 -0
  372. moai_adk/templates/.github/workflows/shell-tag-validation.yml +11 -0
  373. moai_adk/templates/.github/workflows/spec-issue-sync.yml +338 -0
  374. moai_adk/templates/.github/workflows/swift-tag-validation.yml +11 -0
  375. moai_adk/templates/.github/workflows/tag-report.yml +269 -0
  376. moai_adk/templates/.github/workflows/tag-validation.yml +186 -0
  377. moai_adk/templates/.github/workflows/typescript-tag-validation.yml +154 -0
  378. moai_adk/templates/.mcp.json +31 -0
  379. moai_adk/templates/.moai/config.json +80 -7
  380. moai_adk/templates/CLAUDE.md +562 -546
  381. moai_adk/utils/banner.py +5 -5
  382. moai_adk/utils/common.py +294 -0
  383. moai_adk/utils/link_validator.py +235 -0
  384. moai_adk/utils/logger.py +8 -8
  385. moai_adk/utils/user_experience.py +451 -0
  386. moai_adk-0.20.1.dist-info/METADATA +233 -0
  387. moai_adk-0.20.1.dist-info/RECORD +404 -0
  388. moai_adk/templates/.claude/hooks/alfred/README.md +0 -230
  389. moai_adk/templates/.claude/hooks/alfred/alfred_hooks.py +0 -156
  390. moai_adk/templates/.claude/hooks/alfred/core/__init__.py +0 -85
  391. moai_adk/templates/.claude/hooks/alfred/handlers/notification.py +0 -25
  392. moai_adk/templates/.claude/hooks/alfred/handlers/session.py +0 -92
  393. moai_adk/templates/.claude/hooks/alfred/handlers/tool.py +0 -70
  394. moai_adk/templates/.claude/hooks/alfred/handlers/user.py +0 -41
  395. moai_adk/templates/.claude/output-styles/alfred/agentic-coding.md +0 -636
  396. moai_adk/templates/.claude/output-styles/alfred/moai-adk-learning.md +0 -692
  397. moai_adk/templates/.claude/output-styles/alfred/study-with-alfred.md +0 -470
  398. moai_adk/templates/.claude/skills/moai-alfred-debugger-pro/SKILL.md +0 -103
  399. moai_adk/templates/.claude/skills/moai-alfred-ears-authoring/SKILL.md +0 -103
  400. moai_adk/templates/.claude/skills/moai-alfred-git-workflow/SKILL.md +0 -95
  401. moai_adk/templates/.claude/skills/moai-alfred-performance-optimizer/SKILL.md +0 -105
  402. moai_adk/templates/.claude/skills/moai-alfred-refactoring-coach/SKILL.md +0 -97
  403. moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-validation/SKILL.md +0 -97
  404. moai_adk/templates/.claude/skills/moai-alfred-tag-scanning/SKILL.md +0 -90
  405. moai_adk/templates/.claude/skills/moai-alfred-trust-validation/SKILL.md +0 -99
  406. moai_adk/templates/.claude/skills/moai-alfred-tui-survey/SKILL.md +0 -87
  407. moai_adk/templates/.claude/skills/moai-alfred-tui-survey/examples.md +0 -62
  408. moai_adk/templates/.claude/skills/moai-claude-code/SKILL.md +0 -94
  409. moai_adk/templates/.claude/skills/moai-claude-code/examples.md +0 -513
  410. moai_adk/templates/.claude/skills/moai-claude-code/reference.md +0 -433
  411. moai_adk/templates/.claude/skills/moai-claude-code/templates/agent-full.md +0 -332
  412. moai_adk/templates/.claude/skills/moai-claude-code/templates/command-full.md +0 -384
  413. moai_adk/templates/.claude/skills/moai-claude-code/templates/plugin-full.json +0 -363
  414. moai_adk/templates/.claude/skills/moai-claude-code/templates/settings-full.json +0 -595
  415. moai_adk/templates/.claude/skills/moai-claude-code/templates/skill-full.md +0 -496
  416. moai_adk/templates/.claude/skills/moai-lang-clojure/SKILL.md +0 -100
  417. moai_adk/templates/.claude/skills/moai-lang-elixir/SKILL.md +0 -99
  418. moai_adk/templates/.claude/skills/moai-lang-haskell/SKILL.md +0 -100
  419. moai_adk/templates/.claude/skills/moai-lang-julia/SKILL.md +0 -98
  420. moai_adk/templates/.claude/skills/moai-lang-lua/SKILL.md +0 -98
  421. moai_adk/templates/.github/PULL_REQUEST_TEMPLATE.md +0 -69
  422. moai_adk/templates/.moai/memory/development-guide.md +0 -344
  423. moai_adk/templates/.moai/memory/gitflow-protection-policy.md +0 -220
  424. moai_adk/templates/.moai/memory/spec-metadata.md +0 -356
  425. moai_adk/templates/.moai/project/product.md +0 -161
  426. moai_adk/templates/.moai/project/structure.md +0 -156
  427. moai_adk/templates/.moai/project/tech.md +0 -227
  428. moai_adk/templates/__init__.py +0 -2
  429. moai_adk-0.4.5.dist-info/METADATA +0 -369
  430. moai_adk-0.4.5.dist-info/RECORD +0 -152
  431. {moai_adk-0.4.5.dist-info → moai_adk-0.20.1.dist-info}/WHEEL +0 -0
  432. {moai_adk-0.4.5.dist-info → moai_adk-0.20.1.dist-info}/entry_points.txt +0 -0
  433. {moai_adk-0.4.5.dist-info → moai_adk-0.20.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,14 +1,110 @@
1
1
  #!/usr/bin/env python3
2
+ # @CODE:OFFLINE-001 | SPEC: SPEC-OFFLINE-SUPPORT-001 | TEST: tests/unit/test_network_detection.py
2
3
  """Project metadata utilities
3
4
 
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
5
10
  """
6
11
 
7
12
  import json
13
+ import signal
14
+ import socket
8
15
  import subprocess
16
+ from contextlib import contextmanager
9
17
  from pathlib import Path
10
18
  from typing import Any
11
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
+
12
108
 
13
109
  def detect_language(cwd: str) -> str:
14
110
  """Detect project language (supports 20 items languages)
@@ -89,9 +185,10 @@ def detect_language(cwd: str) -> str:
89
185
 
90
186
 
91
187
  def _run_git_command(args: list[str], cwd: str, timeout: int = 2) -> str:
92
- """Git command execution helper function
188
+ """Git command execution with HARD timeout protection
93
189
 
94
190
  Safely execute Git commands and return output.
191
+ Uses SIGALRM (kernel-level interrupt) to handle macOS subprocess timeout bug.
95
192
  Eliminates code duplication and provides consistent error handling.
96
193
 
97
194
  Args:
@@ -103,29 +200,46 @@ def _run_git_command(args: list[str], cwd: str, timeout: int = 2) -> str:
103
200
  Git command output (stdout, removing leading and trailing spaces)
104
201
 
105
202
  Raises:
106
- subprocess.TimeoutExpired: Timeout exceeded
203
+ subprocess.TimeoutExpired: Timeout exceeded (via TimeoutError)
107
204
  subprocess.CalledProcessError: Git command failed
108
205
 
109
206
  Examples:
110
207
  >>> _run_git_command(["branch", "--show-current"], ".")
111
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
112
214
  """
113
- result = subprocess.run(
114
- ["git"] + args,
115
- cwd=cwd,
116
- capture_output=True,
117
- text=True,
118
- timeout=timeout,
119
- check=True,
120
- )
121
- return result.stdout.strip()
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)
122
236
 
123
237
 
124
238
  def get_git_info(cwd: str) -> dict[str, Any]:
125
239
  """Gather Git repository information
126
240
 
127
241
  View the current status of a Git repository.
128
- Returns the branch name, commit hash, and number of changes.
242
+ Returns the branch name, commit hash, number of changes, and last commit message.
129
243
  If it is not a Git repository, it returns an empty dictionary.
130
244
 
131
245
  Args:
@@ -136,12 +250,13 @@ def get_git_info(cwd: str) -> dict[str, Any]:
136
250
  - branch: Current branch name (str)
137
251
  - commit: Current commit hash (str, full hash)
138
252
  - changes: Number of changed files (int, staged + unstaged)
253
+ - last_commit: Last commit message (str, subject only)
139
254
 
140
255
  Empty dictionary {} if it is not a Git repository or the query fails.
141
256
 
142
257
  Examples:
143
258
  >>> get_git_info("/path/to/git/repo")
144
- {'branch': 'main', 'commit': 'abc123...', 'changes': 3}
259
+ {'branch': 'main', 'commit': 'abc123...', 'changes': 3, 'last_commit': 'Fix bug'}
145
260
  >>> get_git_info("/path/to/non-git")
146
261
  {}
147
262
 
@@ -149,11 +264,13 @@ def get_git_info(cwd: str) -> dict[str, Any]:
149
264
  - Timeout: 2 seconds for each Git command
150
265
  - Security: Safe execution with subprocess.run(shell=False)
151
266
  - Error handling: Returns an empty dictionary in case of all exceptions
267
+ - Commit message limited to 50 characters for display purposes
152
268
 
153
269
  TDD History:
154
270
  - RED: 3 items scenario test (Git repo, non-Git, error)
155
271
  - GREEN: Implementation of subprocess-based Git command execution
156
272
  - REFACTOR: Add timeout (2 seconds), strengthen exception handling, remove duplicates with helper function
273
+ - UPDATE: Added last_commit message field for SessionStart display
157
274
  """
158
275
  try:
159
276
  # Check if it's a git repository
@@ -165,10 +282,16 @@ def get_git_info(cwd: str) -> dict[str, Any]:
165
282
  status_output = _run_git_command(["status", "--short"], cwd)
166
283
  changes = len([line for line in status_output.splitlines() if line])
167
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
+
168
290
  return {
169
291
  "branch": branch,
170
292
  "commit": commit,
171
293
  "changes": changes,
294
+ "last_commit": last_commit,
172
295
  }
173
296
 
174
297
  except (subprocess.TimeoutExpired, subprocess.CalledProcessError, FileNotFoundError):
@@ -182,7 +305,7 @@ def count_specs(cwd: str) -> dict[str, int]:
182
305
  Counts the number of SPECs with status: completed.
183
306
 
184
307
  Args:
185
- cwd: Project root directory path
308
+ cwd: Project root directory path (or any subdirectory, will search upward)
186
309
 
187
310
  Returns:
188
311
  SPEC progress dictionary. Includes the following keys:
@@ -200,15 +323,19 @@ def count_specs(cwd: str) -> dict[str, int]:
200
323
 
201
324
  Notes:
202
325
  - SPEC File Location: .moai/specs/SPEC-{ID}/spec.md
203
- - Completion condition: Include status: completed in YAML front matter
326
+ - Completion condition: Include "status: completed" in YAML front matter
204
327
  - If parsing fails, the SPEC is considered incomplete.
328
+ - Automatically finds project root to locate .moai/specs/
205
329
 
206
330
  TDD History:
207
331
  - RED: 5 items scenario test (0/0, 2/5, 5/5, no directory, parsing error)
208
332
  - GREEN: SPEC search with Path.iterdir(), YAML parsing implementation
209
333
  - REFACTOR: Strengthened exception handling, improved percentage calculation safety
334
+ - UPDATE: Add project root detection for consistent path resolution
210
335
  """
211
- specs_dir = Path(cwd) / ".moai" / "specs"
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"
212
339
 
213
340
  if not specs_dir.exists():
214
341
  return {"completed": 0, "total": 0, "percentage": 0}
@@ -252,7 +379,7 @@ def get_project_language(cwd: str) -> str:
252
379
  """Determine the primary project language (prefers config.json).
253
380
 
254
381
  Args:
255
- cwd: Project root directory.
382
+ cwd: Project root directory (or any subdirectory, will search upward).
256
383
 
257
384
  Returns:
258
385
  Language string in lower-case.
@@ -260,8 +387,11 @@ def get_project_language(cwd: str) -> str:
260
387
  Notes:
261
388
  - Reads ``.moai/config.json`` first for a quick answer.
262
389
  - Falls back to ``detect_language`` if configuration is missing.
390
+ - Automatically finds project root to locate .moai/config.json
263
391
  """
264
- config_path = Path(cwd) / ".moai" / "config.json"
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"
265
395
  if config_path.exists():
266
396
  try:
267
397
  config = json.loads(config_path.read_text())
@@ -272,13 +402,347 @@ def get_project_language(cwd: str) -> str:
272
402
  # Fall back to detection on parse errors
273
403
  pass
274
404
 
275
- # Fall back to the original language detection routine
276
- return detect_language(cwd)
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
277
736
 
278
737
 
279
738
  __all__ = [
739
+ "find_project_root",
280
740
  "detect_language",
281
741
  "get_git_info",
282
742
  "count_specs",
283
743
  "get_project_language",
744
+ "get_version_check_config",
745
+ "is_network_available",
746
+ "is_major_version_change",
747
+ "get_package_version_info",
284
748
  ]