moai-adk 0.9.0__py3-none-any.whl → 0.15.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 (186) hide show
  1. moai_adk/cli/commands/init.py +14 -2
  2. moai_adk/cli/commands/update.py +214 -56
  3. moai_adk/core/issue_creator.py +2 -2
  4. moai_adk/core/project/detector.py +201 -12
  5. moai_adk/core/project/initializer.py +62 -1
  6. moai_adk/core/project/phase_executor.py +48 -6
  7. moai_adk/core/tags/ci_validator.py +34 -4
  8. moai_adk/core/tags/pre_commit_validator.py +40 -2
  9. moai_adk/core/tags/reporter.py +2 -3
  10. moai_adk/core/tags/validator.py +1 -1
  11. moai_adk/core/template_engine.py +20 -5
  12. moai_adk/templates/.claude/agents/alfred/backend-expert.md +319 -0
  13. moai_adk/templates/.claude/agents/alfred/devops-expert.md +464 -0
  14. moai_adk/templates/.claude/agents/alfred/doc-syncer.md +1 -1
  15. moai_adk/templates/.claude/agents/alfred/frontend-expert.md +357 -0
  16. moai_adk/templates/.claude/agents/alfred/git-manager.md +2 -2
  17. moai_adk/templates/.claude/agents/alfred/implementation-planner.md +76 -3
  18. moai_adk/templates/.claude/agents/alfred/project-manager.md +49 -10
  19. moai_adk/templates/.claude/agents/alfred/quality-gate.md +3 -3
  20. moai_adk/templates/.claude/agents/alfred/spec-builder.md +108 -3
  21. moai_adk/templates/.claude/agents/alfred/tag-agent.md +74 -0
  22. moai_adk/templates/.claude/agents/alfred/tdd-implementer.md +107 -5
  23. moai_adk/templates/.claude/agents/alfred/trust-checker.md +2 -2
  24. moai_adk/templates/.claude/agents/alfred/ui-ux-expert.md +571 -0
  25. moai_adk/templates/.claude/commands/alfred/0-project.md +465 -129
  26. moai_adk/templates/.claude/commands/alfred/1-plan.md +139 -65
  27. moai_adk/templates/.claude/commands/alfred/2-run.md +214 -50
  28. moai_adk/templates/.claude/commands/alfred/3-sync.md +372 -46
  29. moai_adk/templates/.claude/commands/alfred/9-feedback.md +1 -1
  30. moai_adk/templates/.claude/hooks/alfred/core/project.py +25 -27
  31. moai_adk/templates/.claude/hooks/alfred/core/timeout.py +136 -0
  32. moai_adk/templates/.claude/hooks/alfred/core/ttl_cache.py +108 -0
  33. moai_adk/templates/.claude/hooks/alfred/core/version_cache.py +4 -4
  34. moai_adk/templates/.claude/hooks/alfred/handlers/__init__.py +29 -0
  35. moai_adk/templates/.claude/hooks/alfred/post_tool__log_changes.py +11 -19
  36. moai_adk/templates/.claude/hooks/alfred/pre_tool__auto_checkpoint.py +11 -19
  37. moai_adk/templates/.claude/hooks/alfred/session_end__cleanup.py +11 -19
  38. moai_adk/templates/.claude/hooks/alfred/session_start__show_project_info.py +10 -18
  39. moai_adk/templates/.claude/hooks/alfred/shared/core/__init__.py +2 -2
  40. moai_adk/templates/.claude/hooks/alfred/shared/core/checkpoint.py +3 -3
  41. moai_adk/templates/.claude/hooks/alfred/shared/core/context.py +5 -5
  42. moai_adk/templates/.claude/hooks/alfred/shared/core/project.py +40 -41
  43. moai_adk/templates/.claude/hooks/alfred/shared/core/tags.py +55 -23
  44. moai_adk/templates/.claude/hooks/alfred/shared/core/version_cache.py +4 -4
  45. moai_adk/templates/.claude/hooks/alfred/shared/handlers/notification.py +132 -3
  46. moai_adk/templates/.claude/hooks/alfred/shared/handlers/session.py +9 -10
  47. moai_adk/templates/.claude/hooks/alfred/shared/handlers/tool.py +3 -6
  48. moai_adk/templates/.claude/hooks/alfred/shared/handlers/user.py +19 -0
  49. moai_adk/templates/.claude/hooks/alfred/user_prompt__jit_load_docs.py +14 -22
  50. moai_adk/templates/.claude/hooks/alfred/utils/__init__.py +1 -0
  51. moai_adk/templates/.claude/hooks/alfred/utils/timeout.py +161 -0
  52. moai_adk/templates/.claude/settings.json +5 -5
  53. moai_adk/templates/.claude/skills/moai-alfred-agent-guide/SKILL.md +70 -0
  54. moai_adk/templates/.claude/skills/moai-alfred-agent-guide/examples.md +62 -0
  55. moai_adk/templates/{.moai/memory/CLAUDE-AGENTS-GUIDE.md → .claude/skills/moai-alfred-agent-guide/reference.md} +34 -0
  56. moai_adk/templates/.claude/skills/moai-alfred-config-schema/SKILL.md +56 -0
  57. moai_adk/templates/.claude/skills/moai-alfred-config-schema/examples.md +28 -0
  58. moai_adk/templates/.claude/skills/moai-alfred-config-schema/reference.md +444 -0
  59. moai_adk/templates/.claude/skills/moai-alfred-context-budget/SKILL.md +62 -0
  60. moai_adk/templates/.claude/skills/moai-alfred-context-budget/examples.md +28 -0
  61. moai_adk/templates/.claude/skills/moai-alfred-context-budget/reference.md +405 -0
  62. moai_adk/templates/.claude/skills/moai-alfred-dev-guide/SKILL.md +51 -0
  63. moai_adk/templates/.claude/skills/moai-alfred-dev-guide/examples.md +355 -0
  64. moai_adk/templates/.claude/skills/moai-alfred-dev-guide/reference.md +239 -0
  65. moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/SKILL.md +323 -0
  66. moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/examples.md +286 -0
  67. moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/reference.md +126 -0
  68. moai_adk/templates/.claude/skills/moai-alfred-gitflow-policy/SKILL.md +74 -0
  69. moai_adk/templates/.claude/skills/moai-alfred-gitflow-policy/examples.md +4 -0
  70. moai_adk/templates/.claude/skills/moai-alfred-gitflow-policy/reference.md +269 -0
  71. moai_adk/templates/.claude/skills/moai-alfred-issue-labels/SKILL.md +19 -0
  72. moai_adk/templates/.claude/skills/moai-alfred-issue-labels/examples.md +4 -0
  73. moai_adk/templates/.claude/skills/moai-alfred-persona-roles/SKILL.md +198 -0
  74. moai_adk/templates/.claude/skills/moai-alfred-persona-roles/examples.md +431 -0
  75. moai_adk/templates/.claude/skills/moai-alfred-persona-roles/reference.md +141 -0
  76. moai_adk/templates/.claude/skills/moai-alfred-practices/SKILL.md +89 -0
  77. moai_adk/templates/.claude/skills/moai-alfred-practices/examples.md +122 -0
  78. moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/SKILL.md +508 -0
  79. moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/examples.md +481 -0
  80. moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/reference.md +100 -0
  81. moai_adk/templates/.claude/skills/moai-alfred-reporting/SKILL.md +273 -0
  82. moai_adk/templates/.claude/skills/moai-alfred-rules/SKILL.md +77 -0
  83. moai_adk/templates/.claude/skills/moai-alfred-rules/examples.md +265 -0
  84. moai_adk/templates/.claude/skills/moai-alfred-session-state/SKILL.md +19 -0
  85. moai_adk/templates/.claude/skills/moai-alfred-session-state/examples.md +4 -0
  86. moai_adk/templates/.claude/skills/moai-alfred-session-state/reference.md +84 -0
  87. moai_adk/templates/.claude/skills/{moai-spec-authoring → moai-alfred-spec-authoring}/SKILL.md +5 -5
  88. moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-extended/SKILL.md +115 -0
  89. moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-extended/examples.md +4 -0
  90. moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-extended/reference.md +348 -0
  91. moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/SKILL.md +19 -0
  92. moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/examples.md +4 -0
  93. moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/reference.md +211 -0
  94. moai_adk/templates/.claude/skills/moai-alfred-workflow/SKILL.md +288 -0
  95. moai_adk/templates/.claude/skills/moai-cc-skill-descriptions/SKILL.md +19 -0
  96. moai_adk/templates/.claude/skills/moai-cc-skill-descriptions/examples.md +4 -0
  97. moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/SKILL.md +3 -3
  98. moai_adk/templates/.claude/skills/moai-design-systems/SKILL.md +802 -0
  99. moai_adk/templates/.claude/skills/moai-design-systems/examples.md +1238 -0
  100. moai_adk/templates/.claude/skills/moai-design-systems/reference.md +673 -0
  101. moai_adk/templates/.claude/skills/moai-domain-frontend/SKILL.md +17 -13
  102. moai_adk/templates/.claude/skills/moai-lang-go/SKILL.md +15 -12
  103. moai_adk/templates/.claude/skills/moai-lang-java/SKILL.md +14 -12
  104. moai_adk/templates/.claude/skills/moai-lang-php/SKILL.md +14 -11
  105. moai_adk/templates/.claude/skills/moai-lang-python/SKILL.md +10 -8
  106. moai_adk/templates/.claude/skills/moai-lang-rust/SKILL.md +15 -12
  107. moai_adk/templates/.claude/skills/moai-lang-scala/SKILL.md +13 -11
  108. moai_adk/templates/.claude/skills/moai-lang-typescript/SKILL.md +16 -10
  109. moai_adk/templates/.claude/skills/moai-project-documentation.md +622 -0
  110. moai_adk/templates/.git-hooks/pre-push +143 -0
  111. moai_adk/templates/.github/workflows/c-tag-validation.yml +11 -0
  112. moai_adk/templates/.github/workflows/cpp-tag-validation.yml +11 -0
  113. moai_adk/templates/.github/workflows/csharp-tag-validation.yml +11 -0
  114. moai_adk/templates/.github/workflows/dart-tag-validation.yml +11 -0
  115. moai_adk/templates/.github/workflows/go-tag-validation.yml +130 -0
  116. moai_adk/templates/.github/workflows/java-tag-validation.yml +11 -0
  117. moai_adk/templates/.github/workflows/javascript-tag-validation.yml +135 -0
  118. moai_adk/templates/.github/workflows/kotlin-tag-validation.yml +11 -0
  119. moai_adk/templates/.github/workflows/moai-gitflow.yml +182 -25
  120. moai_adk/templates/.github/workflows/moai-release-pipeline.yml +35 -29
  121. moai_adk/templates/.github/workflows/php-tag-validation.yml +11 -0
  122. moai_adk/templates/.github/workflows/python-tag-validation.yml +118 -0
  123. moai_adk/templates/.github/workflows/release.yml +76 -7
  124. moai_adk/templates/.github/workflows/ruby-tag-validation.yml +11 -0
  125. moai_adk/templates/.github/workflows/rust-tag-validation.yml +11 -0
  126. moai_adk/templates/.github/workflows/shell-tag-validation.yml +11 -0
  127. moai_adk/templates/.github/workflows/spec-issue-sync.yml +208 -41
  128. moai_adk/templates/.github/workflows/swift-tag-validation.yml +11 -0
  129. moai_adk/templates/.github/workflows/tag-report.yml +269 -0
  130. moai_adk/templates/.github/workflows/tag-validation.yml +186 -0
  131. moai_adk/templates/.github/workflows/typescript-tag-validation.yml +154 -0
  132. moai_adk/templates/.moai/config.json +3 -1
  133. moai_adk/templates/CLAUDE.md +940 -45
  134. moai_adk/templates/workflows/go-tag-validation.yml +30 -0
  135. moai_adk/templates/workflows/javascript-tag-validation.yml +41 -0
  136. moai_adk/templates/workflows/python-tag-validation.yml +42 -0
  137. moai_adk/templates/workflows/typescript-tag-validation.yml +31 -0
  138. moai_adk/utils/banner.py +5 -5
  139. {moai_adk-0.9.0.dist-info → moai_adk-0.15.0.dist-info}/METADATA +1166 -455
  140. {moai_adk-0.9.0.dist-info → moai_adk-0.15.0.dist-info}/RECORD +169 -109
  141. moai_adk/templates/.claude/hooks/alfred/alfred_hooks.py +0 -209
  142. moai_adk/templates/.claude/hooks/alfred/notification__handle_events.py +0 -102
  143. moai_adk/templates/.claude/hooks/alfred/stop__handle_interrupt.py +0 -102
  144. moai_adk/templates/.claude/hooks/alfred/subagent_stop__handle_subagent_end.py +0 -102
  145. moai_adk/templates/.claude/output-styles/alfred/agentic-coding.md +0 -640
  146. moai_adk/templates/.claude/output-styles/alfred/moai-adk-learning.md +0 -696
  147. moai_adk/templates/.claude/output-styles/alfred/study-with-alfred.md +0 -474
  148. moai_adk/templates/.github/ISSUE_TEMPLATE/spec.yml +0 -176
  149. moai_adk/templates/.github/PULL_REQUEST_TEMPLATE.md +0 -69
  150. moai_adk/templates/.moai/memory/DEVELOPMENT-GUIDE.md +0 -344
  151. moai_adk/templates/.moai/memory/SPEC-METADATA.md +0 -356
  152. moai_adk/templates/.moai/memory/gitflow-protection-policy.md +0 -330
  153. moai_adk/templates/.moai/project/product.md +0 -161
  154. moai_adk/templates/.moai/project/structure.md +0 -156
  155. moai_adk/templates/.moai/project/tech.md +0 -227
  156. moai_adk/templates/README.md +0 -256
  157. moai_adk/templates/__init__.py +0 -2
  158. /moai_adk/templates/{.moai/memory/ISSUE-LABEL-MAPPING.md → .claude/skills/moai-alfred-issue-labels/reference.md} +0 -0
  159. /moai_adk/templates/{.moai/memory/CLAUDE-PRACTICES.md → .claude/skills/moai-alfred-practices/reference.md} +0 -0
  160. /moai_adk/templates/{.moai/memory/CLAUDE-RULES.md → .claude/skills/moai-alfred-rules/reference.md} +0 -0
  161. /moai_adk/templates/.claude/skills/{moai-spec-authoring → moai-alfred-spec-authoring}/README.md +0 -0
  162. /moai_adk/templates/.claude/skills/{moai-spec-authoring → moai-alfred-spec-authoring}/examples/validate-spec.sh +0 -0
  163. /moai_adk/templates/.claude/skills/{moai-spec-authoring → moai-alfred-spec-authoring}/examples.md +0 -0
  164. /moai_adk/templates/.claude/skills/{moai-spec-authoring → moai-alfred-spec-authoring}/reference.md +0 -0
  165. /moai_adk/templates/{.moai/memory/SKILLS-DESCRIPTION-POLICY.md → .claude/skills/moai-cc-skill-descriptions/reference.md} +0 -0
  166. /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/CHECKLIST.md +0 -0
  167. /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/EXAMPLES.md +0 -0
  168. /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/INTERACTIVE-DISCOVERY.md +0 -0
  169. /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/METADATA.md +0 -0
  170. /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/PARALLEL-ANALYSIS-REPORT.md +0 -0
  171. /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/PYTHON-VERSION-MATRIX.md +0 -0
  172. /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/SKILL-FACTORY-WORKFLOW.md +0 -0
  173. /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/SKILL-UPDATE-ADVISOR.md +0 -0
  174. /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/STEP-BY-STEP-GUIDE.md +0 -0
  175. /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/STRUCTURE.md +0 -0
  176. /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/WEB-RESEARCH.md +0 -0
  177. /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/reference.md +0 -0
  178. /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/scripts/generate-structure.sh +0 -0
  179. /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/scripts/validate-skill.sh +0 -0
  180. /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/templates/SKILL_TEMPLATE.md +0 -0
  181. /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/templates/examples-template.md +0 -0
  182. /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/templates/reference-template.md +0 -0
  183. /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/templates/scripts-template.sh +0 -0
  184. {moai_adk-0.9.0.dist-info → moai_adk-0.15.0.dist-info}/WHEEL +0 -0
  185. {moai_adk-0.9.0.dist-info → moai_adk-0.15.0.dist-info}/entry_points.txt +0 -0
  186. {moai_adk-0.9.0.dist-info → moai_adk-0.15.0.dist-info}/licenses/LICENSE +0 -0
@@ -11,7 +11,9 @@ Phase-based 5-step initialization process:
11
11
  5. Validation: Verification and finalization
12
12
  """
13
13
 
14
+ import json
14
15
  import time
16
+ from datetime import datetime
15
17
  from pathlib import Path
16
18
 
17
19
  from moai_adk.core.project.phase_executor import PhaseExecutor, ProgressCallback
@@ -55,6 +57,62 @@ class ProjectInitializer:
55
57
  self.validator = ProjectValidator()
56
58
  self.executor = PhaseExecutor(self.validator)
57
59
 
60
+ def _create_memory_files(self) -> list[str]:
61
+ """Create runtime session and memory files (auto-generated per user/session)
62
+
63
+ Returns:
64
+ List of created memory files
65
+
66
+ @CODE:INIT-MEMORY-001 | Auto-generate session memory files
67
+ """
68
+ memory_dir = self.path / ".moai" / "memory"
69
+ memory_dir.mkdir(parents=True, exist_ok=True)
70
+ created_files = []
71
+
72
+ # 1. project-notes.json - Project tracking notes (empty on init)
73
+ project_notes = {
74
+ "tech_debt": [],
75
+ "performance_bottlenecks": [],
76
+ "recent_patterns": {
77
+ "frequent_file_edits": [],
78
+ "test_failures": [],
79
+ "git_operations": "daily commits, feature branches"
80
+ },
81
+ "next_priorities": []
82
+ }
83
+ project_notes_file = memory_dir / "project-notes.json"
84
+ project_notes_file.write_text(json.dumps(project_notes, indent=2))
85
+ created_files.append(str(project_notes_file))
86
+
87
+ # 2. session-hint.json - Last session state
88
+ session_hint = {
89
+ "last_command": None,
90
+ "command_timestamp": None,
91
+ "hours_ago": None,
92
+ "active_spec": None,
93
+ "current_branch": "main"
94
+ }
95
+ session_hint_file = memory_dir / "session-hint.json"
96
+ session_hint_file.write_text(json.dumps(session_hint, indent=2))
97
+ created_files.append(str(session_hint_file))
98
+
99
+ # 3. user-patterns.json - User preferences and expertise
100
+ user_patterns = {
101
+ "tech_preferences": {},
102
+ "expertise_signals": {
103
+ "ask_question_skip_rate": 0.0,
104
+ "custom_workflows": 0,
105
+ "estimated_level": "beginner"
106
+ },
107
+ "skip_questions": [],
108
+ "last_updated": datetime.now().isoformat() + "Z"
109
+ }
110
+ user_patterns_file = memory_dir / "user-patterns.json"
111
+ user_patterns_file.write_text(json.dumps(user_patterns, indent=2))
112
+ created_files.append(str(user_patterns_file))
113
+
114
+ return created_files
115
+
58
116
  def initialize(
59
117
  self,
60
118
  mode: str = "personal",
@@ -144,6 +202,9 @@ class ProjectInitializer:
144
202
  self.path, mode, progress_callback
145
203
  )
146
204
 
205
+ # Phase 6: Create runtime memory files (auto-generated per user/session)
206
+ memory_files = self._create_memory_files()
207
+
147
208
  # Generate result
148
209
  duration = int((time.time() - start_time) * 1000) # ms
149
210
  return InstallationResult(
@@ -153,7 +214,7 @@ class ProjectInitializer:
153
214
  mode=mode,
154
215
  locale=locale,
155
216
  duration=duration,
156
- created_files=resource_files + config_files,
217
+ created_files=resource_files + config_files + memory_files,
157
218
  )
158
219
 
159
220
  except Exception as e:
@@ -1,4 +1,5 @@
1
1
  # @CODE:INIT-003:PHASE | SPEC: .moai/specs/SPEC-INIT-003/spec.md | TEST: tests/unit/test_init_reinit.py
2
+ # @CODE:TEST-COVERAGE-001 | SPEC: SPEC-TEST-COVERAGE-001.md | TEST: tests/unit/test_phase_executor.py
2
3
  """Phase-based installation executor (SPEC-INIT-003 v0.4.2)
3
4
 
4
5
  Runs the project initialization across five phases:
@@ -7,6 +8,8 @@ Runs the project initialization across five phases:
7
8
  - Phase 3: Resource (copy templates while preserving user content)
8
9
  - Phase 4: Configuration (generate configuration files)
9
10
  - Phase 5: Validation (verify and finalize)
11
+
12
+ Test coverage includes 5-phase integration tests with backup, configuration, and validation
10
13
  """
11
14
 
12
15
  import json
@@ -142,7 +145,7 @@ class PhaseExecutor:
142
145
  # Set template variable context (if provided)
143
146
  if config:
144
147
  # @TAG:LANG-FIX-001:PY-CONFIG | Read language from nested config structure
145
- language_config = config.get("language", {})
148
+ language_config: dict[str, Any] = config.get("language", {})
146
149
  if not isinstance(language_config, dict):
147
150
  language_config = {}
148
151
 
@@ -193,6 +196,43 @@ class PhaseExecutor:
193
196
  "Phase 4: Generating configurations...", progress_callback
194
197
  )
195
198
 
199
+ # Read existing config to preserve user settings (Issue #165)
200
+ config_path = project_path / ".moai" / "config.json"
201
+ existing_config: dict[str, Any] = {}
202
+ if config_path.exists():
203
+ try:
204
+ with open(config_path, "r", encoding="utf-8") as f:
205
+ existing_config = json.load(f)
206
+ except (json.JSONDecodeError, OSError):
207
+ # If config reading fails, start fresh
208
+ existing_config = {}
209
+
210
+ # Merge user settings from existing config (preserve customization)
211
+ if existing_config:
212
+ # Preserve user.nickname if it exists
213
+ if "user" in existing_config and isinstance(existing_config.get("user"), dict):
214
+ if "user" not in config:
215
+ config["user"] = {}
216
+ user_config = config["user"]
217
+ if isinstance(user_config, dict):
218
+ existing_user = existing_config["user"]
219
+ if isinstance(existing_user, dict) and "nickname" in existing_user:
220
+ user_config["nickname"] = existing_user["nickname"]
221
+
222
+ # Preserve language settings if they exist
223
+ if "language" in existing_config and isinstance(existing_config.get("language"), dict):
224
+ if "language" not in config:
225
+ config["language"] = {}
226
+ lang_config = config["language"]
227
+ if isinstance(lang_config, dict):
228
+ existing_lang = existing_config["language"]
229
+ if isinstance(existing_lang, dict):
230
+ # Preserve conversation_language settings
231
+ if "conversation_language" in existing_lang:
232
+ lang_config["conversation_language"] = existing_lang["conversation_language"]
233
+ if "conversation_language_name" in existing_lang:
234
+ lang_config["conversation_language_name"] = existing_lang["conversation_language_name"]
235
+
196
236
  # Ensure project section exists and set defaults
197
237
  if "project" not in config:
198
238
  config["project"] = {}
@@ -202,7 +242,6 @@ class PhaseExecutor:
202
242
  project_config["optimized"] = False # Default value
203
243
 
204
244
  # Write config.json
205
- config_path = project_path / ".moai" / "config.json"
206
245
  with open(config_path, "w", encoding="utf-8") as f:
207
246
  json.dump(config, f, indent=2, ensure_ascii=False)
208
247
 
@@ -216,9 +255,8 @@ class PhaseExecutor:
216
255
  ) -> None:
217
256
  """Phase 5: validation and wrap-up.
218
257
 
219
- @CODE:INIT-004:PHASE5 | Phase 5 verification logic
258
+ @CODE:INIT-PHASE-001 | Phase 5 verification logic
220
259
  @REQ:VALIDATION-001 | SPEC-INIT-004: Verify required files after initialization completion
221
- @CODE:INIT-004:PHASE5-INTEGRATION | Integration of validation in Phase 5
222
260
 
223
261
  Args:
224
262
  project_path: Project path.
@@ -230,8 +268,8 @@ class PhaseExecutor:
230
268
  "Phase 5: Validation and finalization...", progress_callback
231
269
  )
232
270
 
233
- # @CODE:INIT-004:VERIFY-001 | Validate installation results
234
- # @CODE:INIT-004:VALIDATION-CHECK | Comprehensive installation validation
271
+ # Validate installation results
272
+ # Comprehensive installation validation
235
273
  # Verifies all required files including 4 Alfred command files:
236
274
  # - 0-project.md, 1-plan.md, 2-run.md, 3-sync.md
237
275
  self.validator.validate_installation(project_path)
@@ -312,8 +350,12 @@ class PhaseExecutor:
312
350
  cwd=project_path,
313
351
  check=True,
314
352
  capture_output=True,
353
+ timeout=30, # Default timeout for git operations
315
354
  )
316
355
  # Intentionally avoid printing to keep progress output clean
356
+ except subprocess.TimeoutExpired:
357
+ # Timeout is non-fatal
358
+ pass
317
359
  except subprocess.CalledProcessError:
318
360
  # Only log on error; failures are non-fatal
319
361
  pass
@@ -16,6 +16,8 @@ import os
16
16
  from typing import Any, Dict, List, Optional
17
17
 
18
18
  import requests
19
+ from requests.adapters import HTTPAdapter
20
+ from urllib3.util import Retry
19
21
 
20
22
  from .pre_commit_validator import (
21
23
  PreCommitValidator,
@@ -87,16 +89,44 @@ class CIValidator(PreCommitValidator):
87
89
  'Accept': 'application/vnd.github.v3+json'
88
90
  }
89
91
 
92
+ # Create session with retry strategy
93
+ session = requests.Session()
94
+ retry = Retry(
95
+ total=3,
96
+ backoff_factor=0.5,
97
+ status_forcelist=[500, 502, 503, 504],
98
+ allowed_methods=["GET"]
99
+ )
100
+ adapter = HTTPAdapter(max_retries=retry)
101
+ session.mount("https://", adapter)
102
+
90
103
  try:
91
- response = requests.get(url, headers=headers, timeout=10)
104
+ # Dual timeout: (connect_timeout, read_timeout)
105
+ response = session.get(
106
+ url,
107
+ headers=headers,
108
+ timeout=(5, 10)
109
+ )
92
110
  response.raise_for_status()
93
111
 
94
112
  files_data = response.json()
95
113
  return [file_info['filename'] for file_info in files_data]
96
114
 
97
- except Exception:
98
- # Return empty list on any error (network, auth, etc.)
115
+ except requests.exceptions.Timeout:
116
+ # Network timeout - return empty list gracefully
117
+ return []
118
+ except requests.exceptions.HTTPError as e:
119
+ # HTTP error (4xx, 5xx)
120
+ if e.response.status_code == 404:
121
+ # PR not found
122
+ return []
123
+ # Other HTTP errors: log but continue
124
+ return []
125
+ except requests.exceptions.RequestException:
126
+ # Network/connection errors
99
127
  return []
128
+ finally:
129
+ session.close()
100
130
 
101
131
  def validate_pr_changes(
102
132
  self,
@@ -260,7 +290,7 @@ class CIValidator(PreCommitValidator):
260
290
  tag = error.tag
261
291
  message = error.message
262
292
  locations = ', '.join([
263
- f"`{f}:{l}`" for f, l in error.locations[:3]
293
+ f"`{f}:{line}`" for f, line in error.locations[:3]
264
294
  ])
265
295
  if len(error.locations) > 3:
266
296
  locations += f" (+{len(error.locations) - 3} more)"
@@ -26,7 +26,7 @@ class ValidationError:
26
26
  locations: List[Tuple[str, int]] = field(default_factory=list)
27
27
 
28
28
  def __str__(self) -> str:
29
- loc_str = ", ".join([f"{f}:{l}" for f, l in self.locations])
29
+ loc_str = ", ".join([f"{f}:{line}" for f, line in self.locations])
30
30
  return f"{self.message}: {self.tag} at {loc_str}"
31
31
 
32
32
 
@@ -98,6 +98,37 @@ class PreCommitValidator:
98
98
  self.strict_mode = strict_mode
99
99
  self.check_orphans = check_orphans
100
100
  self.tag_pattern = re.compile(tag_pattern or self.DEFAULT_TAG_PATTERN)
101
+ # Document files to exclude from TAG validation
102
+ self.excluded_file_patterns = [
103
+ r"\.md$", # Markdown files
104
+ r"README", # README files
105
+ r"CHANGELOG", # CHANGELOG files
106
+ r"CONTRIBUTING", # CONTRIBUTING files
107
+ r"LICENSE", # LICENSE files
108
+ r"\.txt$", # Text files
109
+ r"\.rst$", # ReStructuredText files
110
+ r"test_.*\.py$", # Test files (test_*.py)
111
+ r".*_test\.py$", # Test files (*_test.py)
112
+ r"tests/", # Files in tests/ directory
113
+ r"validator\.py$", # Validator files (contain example TAGs in docstrings)
114
+ ]
115
+
116
+ def should_validate_file(self, filepath: str) -> bool:
117
+ """Check if file should be validated for TAGs
118
+
119
+ Document files (*.md, README, CONTRIBUTING, etc.) are excluded
120
+ because they often contain example TAGs that are not actual code.
121
+
122
+ Args:
123
+ filepath: File path to check
124
+
125
+ Returns:
126
+ True if file should be validated, False if excluded
127
+ """
128
+ for pattern in self.excluded_file_patterns:
129
+ if re.search(pattern, filepath):
130
+ return False
131
+ return True
101
132
 
102
133
  def validate_format(self, tag: str) -> bool:
103
134
  """Validate TAG format
@@ -137,6 +168,10 @@ class PreCommitValidator:
137
168
  tag_locations: Dict[str, List[Tuple[str, int]]] = {}
138
169
 
139
170
  for filepath in files:
171
+ # Skip document files (*.md, README, CONTRIBUTING, etc.)
172
+ if not self.should_validate_file(filepath):
173
+ continue
174
+
140
175
  try:
141
176
  path = Path(filepath)
142
177
  if not path.exists() or not path.is_file():
@@ -195,6 +230,10 @@ class PreCommitValidator:
195
230
  }
196
231
 
197
232
  for filepath in files:
233
+ # Skip document files (*.md, README, CONTRIBUTING, etc.)
234
+ if not self.should_validate_file(filepath):
235
+ continue
236
+
198
237
  try:
199
238
  path = Path(filepath)
200
239
  if not path.exists() or not path.is_file():
@@ -206,7 +245,6 @@ class PreCommitValidator:
206
245
  for line_num, line in enumerate(lines, start=1):
207
246
  matches = self.tag_pattern.findall(line)
208
247
  for prefix, domain in matches:
209
- tag = f"@{prefix}:{domain}"
210
248
  if domain not in tags_by_type[prefix]:
211
249
  tags_by_type[prefix][domain] = []
212
250
  tags_by_type[prefix][domain].append((filepath, line_num))
@@ -155,7 +155,7 @@ class InventoryGenerator:
155
155
  Returns:
156
156
  List of TagInventory objects
157
157
  """
158
- inventory = []
158
+ inventory: list[TagInventory] = []
159
159
  root = Path(root_path)
160
160
 
161
161
  if not root.exists() or not root.is_dir():
@@ -224,7 +224,6 @@ class InventoryGenerator:
224
224
 
225
225
  for tag_type, domain in matches:
226
226
  tag_id = domain
227
- full_tag = f"@{tag_type}:{domain}"
228
227
 
229
228
  # Extract context (±2 lines)
230
229
  context_lines = []
@@ -421,7 +420,7 @@ class MatrixGenerator:
421
420
  spec = "1" if row["SPEC"] else "0"
422
421
  code = "1" if row["CODE"] else "0"
423
422
  test = "1" if row["TEST"] else "0"
424
- doc = "1" if row["DOC"] else "0"
423
+ "1" if row["DOC"] else "0"
425
424
  completion = f"{matrix.completion_percentages[domain]:.1f}"
426
425
 
427
426
  lines.append(f"{domain},{spec},{code},{test},{completion}")
@@ -85,7 +85,7 @@ class ValidationIssue:
85
85
  "tag": self.tag,
86
86
  "message": self.message,
87
87
  "locations": [
88
- {"file": f, "line": l} for f, l in self.locations
88
+ {"file": f, "line": line} for f, line in self.locations
89
89
  ],
90
90
  "suggestion": self.suggestion
91
91
  }
@@ -31,13 +31,17 @@ class TemplateEngine:
31
31
  - File-based and string-based template rendering
32
32
  """
33
33
 
34
- def __init__(self, strict_undefined: bool = False):
34
+ def __init__(self, strict_undefined: bool = True):
35
35
  """
36
36
  Initialize the template engine.
37
37
 
38
38
  Args:
39
- strict_undefined: If True, raise error on undefined variables.
39
+ strict_undefined: If True, raise error on undefined variables (default: True).
40
40
  If False, render undefined variables as empty strings.
41
+
42
+ Note:
43
+ Changed to strict_undefined=True (v0.10.2+) for safer template rendering.
44
+ Variables must be explicitly provided to avoid silent template failures.
41
45
  """
42
46
  self.strict_undefined = strict_undefined
43
47
  self.undefined_behavior = StrictUndefined if strict_undefined else None
@@ -241,13 +245,24 @@ class TemplateVariableValidator:
241
245
  if var_name not in variables:
242
246
  errors.append(f"Missing required variable: {var_name}")
243
247
  elif not isinstance(variables[var_name], var_type):
244
- errors.append(f"Invalid type for {var_name}: expected {var_type.__name__}, got {type(variables[var_name]).__name__}")
248
+ actual_type = type(variables[var_name]).__name__
249
+ errors.append(
250
+ f"Invalid type for {var_name}: "
251
+ f"expected {var_type.__name__}, got {actual_type}"
252
+ )
245
253
 
246
254
  # Check optional variables (if present)
247
255
  for var_name, var_type in cls.OPTIONAL_VARIABLES.items():
248
256
  if var_name in variables:
249
257
  if not isinstance(variables[var_name], var_type):
250
- type_names = " or ".join(t.__name__ for t in var_type) if isinstance(var_type, tuple) else var_type.__name__
251
- errors.append(f"Invalid type for {var_name}: expected {type_names}, got {type(variables[var_name]).__name__}")
258
+ if isinstance(var_type, tuple):
259
+ type_names = " or ".join(t.__name__ for t in var_type)
260
+ else:
261
+ type_names = var_type.__name__
262
+ actual_type = type(variables[var_name]).__name__
263
+ errors.append(
264
+ f"Invalid type for {var_name}: "
265
+ f"expected {type_names}, got {actual_type}"
266
+ )
252
267
 
253
268
  return len(errors) == 0, errors