moai-adk 0.9.1__py3-none-any.whl → 0.11.0__py3-none-any.whl

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

Potentially problematic release.


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

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