moai-adk 0.3.13__py3-none-any.whl → 0.4.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 (141) hide show
  1. moai_adk/__init__.py +1 -1
  2. moai_adk/__main__.py +1 -1
  3. moai_adk/cli/commands/__init__.py +1 -1
  4. moai_adk/cli/commands/doctor.py +2 -2
  5. moai_adk/cli/commands/init.py +10 -5
  6. moai_adk/cli/commands/status.py +1 -1
  7. moai_adk/cli/commands/update.py +210 -8
  8. moai_adk/cli/prompts/init_prompts.py +15 -19
  9. moai_adk/core/__init__.py +1 -1
  10. moai_adk/core/diagnostics/slash_commands.py +1 -1
  11. moai_adk/core/git/branch.py +1 -1
  12. moai_adk/core/git/manager.py +1 -1
  13. moai_adk/core/project/backup_utils.py +1 -0
  14. moai_adk/core/project/phase_executor.py +3 -1
  15. moai_adk/core/project/validator.py +3 -2
  16. moai_adk/core/quality/__init__.py +1 -1
  17. moai_adk/core/quality/trust_checker.py +1 -1
  18. moai_adk/core/quality/validators/__init__.py +1 -1
  19. moai_adk/core/quality/validators/base_validator.py +1 -1
  20. moai_adk/core/template/__init__.py +1 -1
  21. moai_adk/core/template/backup.py +12 -3
  22. moai_adk/core/template/config.py +24 -0
  23. moai_adk/core/template/languages.py +1 -1
  24. moai_adk/core/template/merger.py +74 -4
  25. moai_adk/core/template/processor.py +62 -14
  26. moai_adk/templates/.claude/agents/alfred/cc-manager.md +765 -191
  27. moai_adk/templates/.claude/agents/alfred/debug-helper.md +116 -103
  28. moai_adk/templates/.claude/agents/alfred/doc-syncer.md +130 -116
  29. moai_adk/templates/.claude/agents/alfred/git-manager.md +186 -174
  30. moai_adk/templates/.claude/agents/alfred/implementation-planner.md +227 -213
  31. moai_adk/templates/.claude/agents/alfred/project-manager.md +205 -125
  32. moai_adk/templates/.claude/agents/alfred/quality-gate.md +224 -209
  33. moai_adk/templates/.claude/agents/alfred/spec-builder.md +174 -160
  34. moai_adk/templates/.claude/agents/alfred/tag-agent.md +151 -139
  35. moai_adk/templates/.claude/agents/alfred/tdd-implementer.md +209 -196
  36. moai_adk/templates/.claude/agents/alfred/trust-checker.md +247 -233
  37. moai_adk/templates/.claude/commands/alfred/0-project.md +856 -355
  38. moai_adk/templates/.claude/commands/alfred/1-plan.md +572 -0
  39. moai_adk/templates/.claude/commands/alfred/2-run.md +470 -0
  40. moai_adk/templates/.claude/commands/alfred/3-sync.md +366 -356
  41. moai_adk/templates/.claude/hooks/alfred/README.md +52 -52
  42. moai_adk/templates/.claude/hooks/alfred/alfred_hooks.py +44 -48
  43. moai_adk/templates/.claude/hooks/alfred/core/__init__.py +17 -17
  44. moai_adk/templates/.claude/hooks/alfred/core/checkpoint.py +59 -59
  45. moai_adk/templates/.claude/hooks/alfred/core/context.py +19 -19
  46. moai_adk/templates/.claude/hooks/alfred/core/project.py +52 -52
  47. moai_adk/templates/.claude/hooks/alfred/handlers/__init__.py +1 -1
  48. moai_adk/templates/.claude/hooks/alfred/handlers/notification.py +4 -4
  49. moai_adk/templates/.claude/hooks/alfred/handlers/session.py +30 -51
  50. moai_adk/templates/.claude/hooks/alfred/handlers/tool.py +16 -17
  51. moai_adk/templates/.claude/hooks/alfred/handlers/user.py +11 -11
  52. moai_adk/templates/.claude/output-styles/alfred/agentic-coding.md +308 -307
  53. moai_adk/templates/.claude/output-styles/alfred/moai-adk-learning.md +297 -296
  54. moai_adk/templates/.claude/output-styles/alfred/study-with-alfred.md +191 -190
  55. moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/SKILL.md +112 -0
  56. moai_adk/templates/.claude/skills/moai-alfred-debugger-pro/SKILL.md +103 -0
  57. moai_adk/templates/.claude/skills/moai-alfred-ears-authoring/SKILL.md +103 -0
  58. moai_adk/templates/.claude/skills/moai-alfred-git-workflow/SKILL.md +95 -0
  59. moai_adk/templates/.claude/skills/moai-alfred-language-detection/SKILL.md +99 -0
  60. moai_adk/templates/.claude/skills/moai-alfred-performance-optimizer/SKILL.md +105 -0
  61. moai_adk/templates/.claude/skills/moai-alfred-refactoring-coach/SKILL.md +97 -0
  62. moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-validation/SKILL.md +97 -0
  63. moai_adk/templates/.claude/skills/moai-alfred-tag-scanning/SKILL.md +90 -0
  64. moai_adk/templates/.claude/skills/moai-alfred-trust-validation/SKILL.md +99 -0
  65. moai_adk/templates/.claude/skills/moai-alfred-tui-survey/SKILL.md +87 -0
  66. moai_adk/templates/.claude/skills/moai-alfred-tui-survey/examples.md +62 -0
  67. moai_adk/templates/.claude/skills/moai-claude-code/SKILL.md +94 -0
  68. moai_adk/templates/.claude/skills/moai-claude-code/examples.md +513 -0
  69. moai_adk/templates/.claude/skills/moai-claude-code/reference.md +433 -0
  70. moai_adk/templates/.claude/skills/moai-claude-code/templates/agent-full.md +332 -0
  71. moai_adk/templates/.claude/skills/moai-claude-code/templates/command-full.md +384 -0
  72. moai_adk/templates/.claude/skills/moai-claude-code/templates/plugin-full.json +363 -0
  73. moai_adk/templates/.claude/skills/moai-claude-code/templates/settings-full.json +595 -0
  74. moai_adk/templates/.claude/skills/moai-claude-code/templates/skill-full.md +496 -0
  75. moai_adk/templates/.claude/skills/moai-domain-backend/SKILL.md +99 -0
  76. moai_adk/templates/.claude/skills/moai-domain-cli-tool/SKILL.md +95 -0
  77. moai_adk/templates/.claude/skills/moai-domain-data-science/SKILL.md +98 -0
  78. moai_adk/templates/.claude/skills/moai-domain-database/SKILL.md +100 -0
  79. moai_adk/templates/.claude/skills/moai-domain-devops/SKILL.md +100 -0
  80. moai_adk/templates/.claude/skills/moai-domain-frontend/SKILL.md +99 -0
  81. moai_adk/templates/.claude/skills/moai-domain-ml/SKILL.md +99 -0
  82. moai_adk/templates/.claude/skills/moai-domain-mobile-app/SKILL.md +93 -0
  83. moai_adk/templates/.claude/skills/moai-domain-security/SKILL.md +105 -0
  84. moai_adk/templates/.claude/skills/moai-domain-web-api/SKILL.md +97 -0
  85. moai_adk/templates/.claude/skills/moai-essentials-debug/SKILL.md +102 -0
  86. moai_adk/templates/.claude/skills/moai-essentials-perf/SKILL.md +104 -0
  87. moai_adk/templates/.claude/skills/moai-essentials-refactor/SKILL.md +96 -0
  88. moai_adk/templates/.claude/skills/moai-essentials-review/SKILL.md +112 -0
  89. moai_adk/templates/.claude/skills/moai-foundation-ears/SKILL.md +98 -0
  90. moai_adk/templates/.claude/skills/moai-foundation-git/SKILL.md +90 -0
  91. moai_adk/templates/.claude/skills/moai-foundation-langs/SKILL.md +94 -0
  92. moai_adk/templates/.claude/skills/moai-foundation-specs/SKILL.md +93 -0
  93. moai_adk/templates/.claude/skills/moai-foundation-tags/SKILL.md +86 -0
  94. moai_adk/templates/.claude/skills/moai-foundation-trust/SKILL.md +86 -0
  95. moai_adk/templates/.claude/skills/moai-lang-c/SKILL.md +100 -0
  96. moai_adk/templates/.claude/skills/moai-lang-clojure/SKILL.md +100 -0
  97. moai_adk/templates/.claude/skills/moai-lang-cpp/SKILL.md +102 -0
  98. moai_adk/templates/.claude/skills/moai-lang-csharp/SKILL.md +100 -0
  99. moai_adk/templates/.claude/skills/moai-lang-dart/SKILL.md +98 -0
  100. moai_adk/templates/.claude/skills/moai-lang-elixir/SKILL.md +99 -0
  101. moai_adk/templates/.claude/skills/moai-lang-go/SKILL.md +100 -0
  102. moai_adk/templates/.claude/skills/moai-lang-haskell/SKILL.md +100 -0
  103. moai_adk/templates/.claude/skills/moai-lang-java/SKILL.md +98 -0
  104. moai_adk/templates/.claude/skills/moai-lang-javascript/SKILL.md +96 -0
  105. moai_adk/templates/.claude/skills/moai-lang-julia/SKILL.md +98 -0
  106. moai_adk/templates/.claude/skills/moai-lang-kotlin/SKILL.md +99 -0
  107. moai_adk/templates/.claude/skills/moai-lang-lua/SKILL.md +98 -0
  108. moai_adk/templates/.claude/skills/moai-lang-php/SKILL.md +98 -0
  109. moai_adk/templates/.claude/skills/moai-lang-python/SKILL.md +96 -0
  110. moai_adk/templates/.claude/skills/moai-lang-r/SKILL.md +99 -0
  111. moai_adk/templates/.claude/skills/moai-lang-ruby/SKILL.md +99 -0
  112. moai_adk/templates/.claude/skills/moai-lang-rust/SKILL.md +100 -0
  113. moai_adk/templates/.claude/skills/moai-lang-scala/SKILL.md +100 -0
  114. moai_adk/templates/.claude/skills/moai-lang-shell/SKILL.md +100 -0
  115. moai_adk/templates/.claude/skills/moai-lang-sql/SKILL.md +100 -0
  116. moai_adk/templates/.claude/skills/moai-lang-swift/SKILL.md +99 -0
  117. moai_adk/templates/.claude/skills/moai-lang-typescript/SKILL.md +96 -0
  118. moai_adk/templates/.github/PULL_REQUEST_TEMPLATE.md +44 -43
  119. moai_adk/templates/.github/workflows/moai-gitflow.yml +36 -35
  120. moai_adk/templates/.moai/config.json +9 -6
  121. moai_adk/templates/.moai/memory/development-guide.md +220 -221
  122. moai_adk/templates/.moai/memory/gitflow-protection-policy.md +85 -85
  123. moai_adk/templates/.moai/memory/spec-metadata.md +149 -150
  124. moai_adk/templates/.moai/project/product.md +90 -90
  125. moai_adk/templates/.moai/project/structure.md +85 -85
  126. moai_adk/templates/.moai/project/tech.md +117 -117
  127. moai_adk/templates/CLAUDE.md +354 -573
  128. moai_adk/templates/__init__.py +1 -1
  129. moai_adk/utils/__init__.py +1 -1
  130. moai_adk/utils/banner.py +7 -7
  131. moai_adk/utils/logger.py +1 -1
  132. moai_adk-0.4.1.dist-info/METADATA +303 -0
  133. moai_adk-0.4.1.dist-info/RECORD +152 -0
  134. moai_adk/templates/.claude/commands/alfred/1-spec.md +0 -532
  135. moai_adk/templates/.claude/commands/alfred/2-build.md +0 -432
  136. moai_adk/templates/.moai/hooks/pre-push.sample +0 -88
  137. moai_adk-0.3.13.dist-info/METADATA +0 -1586
  138. moai_adk-0.3.13.dist-info/RECORD +0 -90
  139. {moai_adk-0.3.13.dist-info → moai_adk-0.4.1.dist-info}/WHEEL +0 -0
  140. {moai_adk-0.3.13.dist-info → moai_adk-0.4.1.dist-info}/entry_points.txt +0 -0
  141. {moai_adk-0.3.13.dist-info → moai_adk-0.4.1.dist-info}/licenses/LICENSE +0 -0
moai_adk/__init__.py CHANGED
@@ -4,5 +4,5 @@
4
4
  SPEC-First TDD Framework with Alfred SuperAgent
5
5
  """
6
6
 
7
- __version__ = "0.3.13"
7
+ __version__ = "0.4.0"
8
8
  __all__ = ["__version__"]
moai_adk/__main__.py CHANGED
@@ -1,4 +1,4 @@
1
- # @CODE:CLI-001 | SPEC: SPEC-CLI-001.md | TEST: tests/unit/test_cli_commands.py
1
+ # @CODE:CLI-001 | SPEC: SPEC-CLI-001/spec.md | TEST: tests/unit/test_cli_commands.py
2
2
  """MoAI-ADK CLI Entry Point
3
3
 
4
4
  Implements the CLI entry point:
@@ -1,4 +1,4 @@
1
- # @CODE:CLI-001 | SPEC: SPEC-CLI-001.md | TEST: tests/unit/test_cli_commands.py
1
+ # @CODE:CLI-001 | SPEC: SPEC-CLI-001/spec.md | TEST: tests/unit/test_cli_commands.py
2
2
  """CLI command module
3
3
 
4
4
  Core commands:
@@ -1,5 +1,5 @@
1
- # @CODE:CLI-001 | SPEC: SPEC-CLI-001.md | TEST: tests/unit/test_doctor.py
2
- # @CODE:CLAUDE-COMMANDS-001:CLI | SPEC: SPEC-CLAUDE-COMMANDS-001.md | TEST: tests/unit/test_slash_commands.py
1
+ # @CODE:CLI-001 | SPEC: SPEC-CLI-001/spec.md | TEST: tests/unit/test_doctor.py
2
+ # @CODE:CLAUDE-COMMANDS-001:CLI | SPEC: SPEC-CLAUDE-COMMANDS-001/spec.md | TEST: tests/unit/test_slash_commands.py
3
3
  """MoAI-ADK doctor command
4
4
 
5
5
  System diagnostics command:
@@ -66,9 +66,9 @@ def create_progress_callback(progress: Progress, task_ids: Sequence[TaskID]):
66
66
  )
67
67
  @click.option(
68
68
  "--locale",
69
- type=click.Choice(["ko", "en", "ja", "zh"]),
70
- default="ko",
71
- help="Preferred language",
69
+ type=click.Choice(["ko", "en"]),
70
+ default=None,
71
+ help="Preferred language (default: en)",
72
72
  )
73
73
  @click.option(
74
74
  "--language",
@@ -95,13 +95,13 @@ def init(
95
95
  path: Project directory path (default: current directory)
96
96
  non_interactive: Skip prompts and use defaults
97
97
  mode: Project mode (personal/team)
98
- locale: Preferred language (ko/en/ja/zh)
98
+ locale: Preferred language (ko/en). When omitted, defaults to en.
99
99
  language: Programming language
100
100
  force: Force reinitialize without confirmation
101
101
  """
102
102
  try:
103
103
  # 1. Print banner
104
- print_banner()
104
+ print_banner(__version__)
105
105
 
106
106
  # 2. Check current directory mode
107
107
  is_current_dir = path == "."
@@ -114,6 +114,7 @@ def init(
114
114
  f"\n[cyan]🚀 Initializing project at {project_path}...[/cyan]\n"
115
115
  )
116
116
  project_name = project_path.name if is_current_dir else path
117
+ locale = locale or "en"
117
118
  else:
118
119
  # Interactive Mode
119
120
  print_welcome_message()
@@ -123,6 +124,7 @@ def init(
123
124
  project_name=None if is_current_dir else path,
124
125
  is_current_dir=is_current_dir,
125
126
  project_path=project_path,
127
+ initial_locale=locale,
126
128
  )
127
129
 
128
130
  # Override with prompt answers
@@ -133,6 +135,9 @@ def init(
133
135
 
134
136
  console.print("\n[cyan]🚀 Starting installation...[/cyan]\n")
135
137
 
138
+ if locale is None:
139
+ locale = answers["locale"]
140
+
136
141
  # 4. Check for reinitialization (SPEC-INIT-003 v0.3.0) - DEFAULT TO FORCE MODE
137
142
  initializer = ProjectInitializer(project_path)
138
143
 
@@ -1,4 +1,4 @@
1
- # @CODE:CLI-001 | SPEC: SPEC-CLI-001.md | TEST: tests/unit/test_cli_commands.py
1
+ # @CODE:CLI-001 | SPEC: SPEC-CLI-001/spec.md | TEST: tests/unit/test_cli_commands.py
2
2
  """MoAI-ADK status command
3
3
 
4
4
  Project status display:
@@ -1,6 +1,10 @@
1
1
  """Update command"""
2
+ from __future__ import annotations
3
+
2
4
  import json
5
+ from datetime import datetime
3
6
  from pathlib import Path
7
+ from typing import Any, cast
4
8
 
5
9
  import click
6
10
  from packaging import version
@@ -25,12 +29,186 @@ def get_latest_version() -> str | None:
25
29
  url = "https://pypi.org/pypi/moai-adk/json"
26
30
  with urllib.request.urlopen(url, timeout=5) as response: # nosec B310 - URL is hardcoded HTTPS to PyPI API, no user input
27
31
  data = json.loads(response.read().decode("utf-8"))
28
- return data["info"]["version"]
32
+ version_str: str = cast(str, data["info"]["version"])
33
+ return version_str
29
34
  except (urllib.error.URLError, json.JSONDecodeError, KeyError, TimeoutError):
30
35
  # Return None if PyPI check fails
31
36
  return None
32
37
 
33
38
 
39
+ def set_optimized_false(project_path: Path) -> None:
40
+ """Set config.json's optimized field to false.
41
+
42
+ Args:
43
+ project_path: Project path (absolute).
44
+ """
45
+ config_path = project_path / ".moai" / "config.json"
46
+ if not config_path.exists():
47
+ return
48
+
49
+ try:
50
+ config_data = json.loads(config_path.read_text(encoding="utf-8"))
51
+ config_data.setdefault("project", {})["optimized"] = False
52
+ config_path.write_text(
53
+ json.dumps(config_data, indent=2, ensure_ascii=False) + "\n",
54
+ encoding="utf-8"
55
+ )
56
+ except (json.JSONDecodeError, KeyError):
57
+ # Ignore errors if config.json is invalid
58
+ pass
59
+
60
+
61
+ def _load_existing_config(project_path: Path) -> dict[str, Any]:
62
+ """Load existing config.json if available."""
63
+ config_path = project_path / ".moai" / "config.json"
64
+ if config_path.exists():
65
+ try:
66
+ return json.loads(config_path.read_text(encoding="utf-8"))
67
+ except json.JSONDecodeError:
68
+ console.print("[yellow]⚠ Existing config.json could not be parsed. Proceeding with defaults.[/yellow]")
69
+ return {}
70
+
71
+
72
+ def _is_placeholder(value: Any) -> bool:
73
+ """Check if a string value is an unsubstituted template placeholder."""
74
+ return isinstance(value, str) and value.strip().startswith("{{") and value.strip().endswith("}}")
75
+
76
+
77
+ def _coalesce(*values: Any, default: str = "") -> str:
78
+ """Return the first non-empty, non-placeholder string value."""
79
+ for value in values:
80
+ if isinstance(value, str):
81
+ if not value.strip():
82
+ continue
83
+ if _is_placeholder(value):
84
+ continue
85
+ return value
86
+ for value in values:
87
+ if value is not None and not isinstance(value, str):
88
+ return str(value)
89
+ return default
90
+
91
+
92
+ def _extract_project_section(config: dict[str, Any]) -> dict[str, Any]:
93
+ """Return the nested project section if present."""
94
+ project_section = config.get("project")
95
+ if isinstance(project_section, dict):
96
+ return project_section
97
+ return {}
98
+
99
+
100
+ def _build_template_context(
101
+ project_path: Path,
102
+ existing_config: dict[str, Any],
103
+ version_for_config: str,
104
+ ) -> dict[str, str]:
105
+ """Build substitution context for template files."""
106
+ project_section = _extract_project_section(existing_config)
107
+
108
+ project_name = _coalesce(
109
+ project_section.get("name"),
110
+ existing_config.get("projectName"),
111
+ project_path.name,
112
+ )
113
+ project_mode = _coalesce(
114
+ project_section.get("mode"),
115
+ existing_config.get("mode"),
116
+ default="personal",
117
+ )
118
+ project_description = _coalesce(
119
+ project_section.get("description"),
120
+ existing_config.get("projectDescription"),
121
+ existing_config.get("description"),
122
+ )
123
+ project_version = _coalesce(
124
+ project_section.get("version"),
125
+ existing_config.get("projectVersion"),
126
+ existing_config.get("version"),
127
+ default="0.1.0",
128
+ )
129
+ created_at = _coalesce(
130
+ project_section.get("created_at"),
131
+ existing_config.get("created_at"),
132
+ default=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
133
+ )
134
+
135
+ return {
136
+ "MOAI_VERSION": version_for_config,
137
+ "PROJECT_NAME": project_name,
138
+ "PROJECT_MODE": project_mode,
139
+ "PROJECT_DESCRIPTION": project_description,
140
+ "PROJECT_VERSION": project_version,
141
+ "CREATION_TIMESTAMP": created_at,
142
+ }
143
+
144
+
145
+ def _preserve_project_metadata(
146
+ project_path: Path,
147
+ context: dict[str, str],
148
+ existing_config: dict[str, Any],
149
+ version_for_config: str,
150
+ ) -> None:
151
+ """Restore project-specific metadata in the new config.json."""
152
+ config_path = project_path / ".moai" / "config.json"
153
+ if not config_path.exists():
154
+ return
155
+
156
+ try:
157
+ config_data = json.loads(config_path.read_text(encoding="utf-8"))
158
+ except json.JSONDecodeError:
159
+ console.print("[red]✗ Failed to parse config.json after template copy[/red]")
160
+ return
161
+
162
+ project_data = config_data.setdefault("project", {})
163
+ project_data["name"] = context["PROJECT_NAME"]
164
+ project_data["mode"] = context["PROJECT_MODE"]
165
+ project_data["description"] = context["PROJECT_DESCRIPTION"]
166
+ project_data["created_at"] = context["CREATION_TIMESTAMP"]
167
+ project_data["moai_adk_version"] = version_for_config
168
+
169
+ if "optimized" not in project_data and isinstance(existing_config, dict):
170
+ existing_project = _extract_project_section(existing_config)
171
+ if isinstance(existing_project, dict) and "optimized" in existing_project:
172
+ project_data["optimized"] = bool(existing_project["optimized"])
173
+
174
+ # Preserve locale and language preferences when possible
175
+ existing_project = _extract_project_section(existing_config)
176
+ locale = _coalesce(existing_project.get("locale"), existing_config.get("locale"))
177
+ if locale:
178
+ project_data["locale"] = locale
179
+
180
+ language = _coalesce(existing_project.get("language"), existing_config.get("language"))
181
+ if language:
182
+ project_data["language"] = language
183
+
184
+ config_data.setdefault("moai", {})
185
+ config_data["moai"]["version"] = version_for_config
186
+
187
+ config_path.write_text(
188
+ json.dumps(config_data, indent=2, ensure_ascii=False) + "\n",
189
+ encoding="utf-8"
190
+ )
191
+
192
+
193
+ def _apply_context_to_file(processor: TemplateProcessor, target_path: Path) -> None:
194
+ """Apply the processor context to an existing file (post-merge pass)."""
195
+ if not processor.context or not target_path.exists():
196
+ return
197
+
198
+ try:
199
+ content = target_path.read_text(encoding="utf-8")
200
+ except UnicodeDecodeError:
201
+ return
202
+
203
+ substituted, warnings = processor._substitute_variables(content) # pylint: disable=protected-access
204
+ if warnings:
205
+ console.print("[yellow]⚠ Template warnings:[/yellow]")
206
+ for warning in warnings:
207
+ console.print(f" {warning}")
208
+
209
+ target_path.write_text(substituted, encoding="utf-8")
210
+
211
+
34
212
  @click.command()
35
213
  @click.option(
36
214
  "--path",
@@ -70,10 +248,13 @@ def update(path: str, force: bool, check: bool) -> None:
70
248
  console.print("[yellow]⚠ Project not initialized[/yellow]")
71
249
  raise click.Abort()
72
250
 
251
+ existing_config = _load_existing_config(project_path)
252
+
73
253
  # Phase 1: check versions
74
254
  console.print("[cyan]🔍 Checking versions...[/cyan]")
75
255
  current_version = __version__
76
256
  latest_version = get_latest_version()
257
+ version_for_config = current_version
77
258
 
78
259
  # Handle PyPI fetch failure
79
260
  if latest_version is None:
@@ -98,14 +279,18 @@ def update(path: str, force: bool, check: bool) -> None:
98
279
  console.print("[green]✓ Already up to date[/green]")
99
280
  return
100
281
 
101
- # Check if update is needed (version + optimized status) - skip with --force
282
+ # Check if update is needed (version only) - skip with --force
102
283
  if not force and latest_version is not None:
103
284
  current_ver = version.parse(current_version)
104
285
  latest_ver = version.parse(latest_version)
105
286
 
106
- # Don't update if current version is newer or equal
107
- if current_ver >= latest_ver:
108
- # Check optimized status in config.json
287
+ # Don't update if current version is newer
288
+ if current_ver > latest_ver:
289
+ console.print("[green]✓ Development version (newer than PyPI)[/green]")
290
+ return
291
+ # If versions are equal, check if we need to proceed
292
+ elif current_ver == latest_ver:
293
+ # Check if optimized=false (need to update templates)
109
294
  config_path = project_path / ".moai" / "config.json"
110
295
  if config_path.exists():
111
296
  try:
@@ -116,9 +301,8 @@ def update(path: str, force: bool, check: bool) -> None:
116
301
  # Already up to date and optimized - exit silently
117
302
  return
118
303
  else:
119
- console.print("[yellow]⚠ Optimization needed[/yellow]")
120
- console.print("[dim]Use /alfred:0-project update for template optimization[/dim]")
121
- return
304
+ # Proceed with template update (optimized=false)
305
+ console.print("[yellow] Template optimization needed[/yellow]")
122
306
  except (json.JSONDecodeError, KeyError):
123
307
  # If config.json is invalid, proceed with update
124
308
  pass
@@ -138,6 +322,11 @@ def update(path: str, force: bool, check: bool) -> None:
138
322
  # Phase 3: update templates
139
323
  console.print("\n[cyan]📄 Updating templates...[/cyan]")
140
324
  processor = TemplateProcessor(project_path)
325
+
326
+ context = _build_template_context(project_path, existing_config, version_for_config)
327
+ if context:
328
+ processor.set_context(context)
329
+
141
330
  processor.copy_templates(backup=False, silent=True) # Backup already handled
142
331
 
143
332
  console.print(" [green]✅ .claude/ update complete[/green]")
@@ -145,7 +334,20 @@ def update(path: str, force: bool, check: bool) -> None:
145
334
  console.print(" [green]🔄 CLAUDE.md merge complete[/green]")
146
335
  console.print(" [green]🔄 config.json merge complete[/green]")
147
336
 
337
+ _preserve_project_metadata(project_path, context, existing_config, version_for_config)
338
+ _apply_context_to_file(processor, project_path / "CLAUDE.md")
339
+
340
+ # Phase 4: set optimized=false
341
+ set_optimized_false(project_path)
342
+ console.print(" [yellow]⚙️ Set optimized=false (optimization needed)[/yellow]")
343
+
148
344
  console.print("\n[green]✓ Update complete![/green]")
345
+ if latest_version and version.parse(current_version) < version.parse(latest_version):
346
+ console.print(
347
+ "[yellow]⚠ Python package still on older version. "
348
+ "Run 'pip install --upgrade moai-adk' to upgrade the CLI package.[/yellow]"
349
+ )
350
+ console.print("\n[cyan]ℹ️ Next step: Run /alfred:0-project update to optimize template changes[/cyan]")
149
351
 
150
352
  except Exception as e:
151
353
  console.print(f"[red]✗ Update failed: {e}[/red]")
@@ -1,4 +1,4 @@
1
- # @CODE:CLI-PROMPTS-001 | SPEC: SPEC-CLI-001.md
1
+ # @CODE:CLI-PROMPTS-001 | SPEC: SPEC-CLI-001/spec.md
2
2
  """Project initialization prompts
3
3
 
4
4
  Collect interactive project settings
@@ -18,7 +18,7 @@ class ProjectSetupAnswers(TypedDict):
18
18
 
19
19
  project_name: str
20
20
  mode: str # personal | team
21
- locale: str # ko | en | ja | zh
21
+ locale: str # ko | en
22
22
  language: str | None
23
23
  author: str
24
24
 
@@ -27,6 +27,7 @@ def prompt_project_setup(
27
27
  project_name: str | None = None,
28
28
  is_current_dir: bool = False,
29
29
  project_path: Path | None = None,
30
+ initial_locale: str | None = None,
30
31
  ) -> ProjectSetupAnswers:
31
32
  """Project setup prompt
32
33
 
@@ -34,6 +35,7 @@ def prompt_project_setup(
34
35
  project_name: Project name (asks when None)
35
36
  is_current_dir: Whether the current directory is being used
36
37
  project_path: Project path (used to derive the name)
38
+ initial_locale: Preferred locale provided via CLI (optional)
37
39
 
38
40
  Returns:
39
41
  Project setup answers
@@ -88,23 +90,17 @@ def prompt_project_setup(
88
90
  if result is None:
89
91
  raise KeyboardInterrupt
90
92
  answers["mode"] = result
93
+ answers["locale"] = initial_locale or "en"
94
+ if initial_locale:
95
+ console.print(
96
+ f"[cyan]🌐 Preferred Language:[/cyan] {answers['locale']} (CLI 옵션으로 지정됨)"
97
+ )
98
+ else:
99
+ console.print(
100
+ "[cyan]🌐 Preferred Language:[/cyan] en (기본값, /alfred:0-project에서 변경 가능)"
101
+ )
91
102
 
92
- # 3. Locale
93
- result = questionary.select(
94
- "🌐 Preferred Language:",
95
- choices=[
96
- questionary.Choice("Korean", value="ko"),
97
- questionary.Choice("English", value="en"),
98
- questionary.Choice("Japanese", value="ja"),
99
- questionary.Choice("Chinese", value="zh"),
100
- ],
101
- default="ko",
102
- ).ask()
103
- if result is None:
104
- raise KeyboardInterrupt
105
- answers["locale"] = result
106
-
107
- # 4. Programming language (auto-detect or manual)
103
+ # 3. Programming language (auto-detect or manual)
108
104
  result = questionary.confirm(
109
105
  "🔍 Auto-detect programming language?",
110
106
  default=True,
@@ -144,7 +140,7 @@ def prompt_project_setup(
144
140
  raise KeyboardInterrupt
145
141
  answers["language"] = result
146
142
 
147
- # 5. Author information (optional)
143
+ # 4. Author information (optional)
148
144
  result = questionary.confirm(
149
145
  "👤 Add author information? (optional)",
150
146
  default=False,
moai_adk/core/__init__.py CHANGED
@@ -1,2 +1,2 @@
1
- # @CODE:PY314-001 | SPEC: SPEC-PY314-001.md | TEST: tests/unit/test_foundation.py
1
+ # @CODE:PY314-001 | SPEC: SPEC-PY314-001/spec.md | TEST: tests/unit/test_foundation.py
2
2
  """Core module: primary business logic"""
@@ -11,7 +11,7 @@ Functions:
11
11
 
12
12
  from pathlib import Path
13
13
 
14
- import yaml
14
+ import yaml # type: ignore[import-untyped]
15
15
 
16
16
 
17
17
  def validate_command_file(file_path: Path) -> dict:
@@ -1,4 +1,4 @@
1
- # @CODE:CORE-GIT-001 | SPEC: SPEC-CORE-GIT-001.md | TEST: tests/unit/test_git.py
1
+ # @CODE:CORE-GIT-001 | SPEC: SPEC-CORE-GIT-001/spec.md | TEST: tests/unit/test_git.py
2
2
  """
3
3
  Branch naming utilities.
4
4
 
@@ -1,4 +1,4 @@
1
- # @CODE:CORE-GIT-001 | SPEC: SPEC-CORE-GIT-001.md | TEST: tests/unit/test_git.py
1
+ # @CODE:CORE-GIT-001 | SPEC: SPEC-CORE-GIT-001/spec.md | TEST: tests/unit/test_git.py
2
2
  """
3
3
  Git repository management built on GitPython.
4
4
 
@@ -15,6 +15,7 @@ BACKUP_TARGETS = [
15
15
  ".moai/project/",
16
16
  ".moai/memory/",
17
17
  ".claude/",
18
+ ".github/",
18
19
  "CLAUDE.md",
19
20
  ]
20
21
 
@@ -53,6 +53,7 @@ class PhaseExecutor:
53
53
  ".moai/memory/",
54
54
  ".claude/",
55
55
  ".claude/logs/",
56
+ ".github/",
56
57
  ]
57
58
 
58
59
  def __init__(self, validator: ProjectValidator) -> None:
@@ -158,6 +159,7 @@ class PhaseExecutor:
158
159
  return [
159
160
  ".claude/",
160
161
  ".moai/",
162
+ ".github/",
161
163
  "CLAUDE.md",
162
164
  ".gitignore",
163
165
  ]
@@ -219,7 +221,7 @@ class PhaseExecutor:
219
221
  # @CODE:INIT-004:VERIFY-001 | Validate installation results
220
222
  # @CODE:INIT-004:VALIDATION-CHECK | Comprehensive installation validation
221
223
  # Verifies all required files including 4 Alfred command files:
222
- # - 0-project.md, 1-spec.md, 2-build.md, 3-sync.md
224
+ # - 0-project.md, 1-plan.md, 2-run.md, 3-sync.md
223
225
  self.validator.validate_installation(project_path)
224
226
 
225
227
  # Initialize Git for team mode
@@ -37,6 +37,7 @@ class ProjectValidator:
37
37
  ".moai/specs/",
38
38
  ".moai/memory/",
39
39
  ".claude/",
40
+ ".github/",
40
41
  ]
41
42
 
42
43
  # Required files
@@ -48,8 +49,8 @@ class ProjectValidator:
48
49
  # Required Alfred command files (SPEC-INIT-004)
49
50
  REQUIRED_ALFRED_COMMANDS = [
50
51
  "0-project.md",
51
- "1-spec.md",
52
- "2-build.md",
52
+ "1-plan.md",
53
+ "2-run.md",
53
54
  "3-sync.md",
54
55
  ]
55
56
 
@@ -1,4 +1,4 @@
1
- # @CODE:TRUST-001 | SPEC: SPEC-TRUST-001.md | TEST: tests/unit/core/quality/
1
+ # @CODE:TRUST-001 | SPEC: SPEC-TRUST-001/spec.md | TEST: tests/unit/core/quality/
2
2
  """TRUST 원칙 자동 검증 시스템"""
3
3
 
4
4
  from moai_adk.core.quality.trust_checker import TrustChecker
@@ -1,4 +1,4 @@
1
- # @CODE:TRUST-001 | SPEC: SPEC-TRUST-001.md | TEST: tests/unit/core/quality/test_trust_checker.py
1
+ # @CODE:TRUST-001 | SPEC: SPEC-TRUST-001/spec.md | TEST: tests/unit/core/quality/test_trust_checker.py
2
2
  """
3
3
  TRUST 원칙 통합 검증 시스템
4
4
 
@@ -1,4 +1,4 @@
1
- # @CODE:TRUST-001 | SPEC: SPEC-TRUST-001.md
1
+ # @CODE:TRUST-001 | SPEC: SPEC-TRUST-001/spec.md
2
2
  """TRUST 검증기 패키지"""
3
3
 
4
4
  from moai_adk.core.quality.validators.base_validator import ValidationResult
@@ -1,4 +1,4 @@
1
- # @CODE:TRUST-001:VALIDATOR | SPEC: SPEC-TRUST-001.md
1
+ # @CODE:TRUST-001:VALIDATOR | SPEC: SPEC-TRUST-001/spec.md
2
2
  """Base validator class and validation result"""
3
3
 
4
4
  from dataclasses import dataclass
@@ -1,4 +1,4 @@
1
- # @CODE:TEMPLATE-001 | SPEC: SPEC-INIT-003.md | Chain: TEMPLATE-001
1
+ # @CODE:TEMPLATE-001 | SPEC: SPEC-INIT-003/spec.md | Chain: TEMPLATE-001
2
2
  """Template management module."""
3
3
 
4
4
  from moai_adk.core.template.backup import TemplateBackup
@@ -1,4 +1,4 @@
1
- # @CODE:TEMPLATE-001 | SPEC: SPEC-INIT-003.md | Chain: TEMPLATE-001
1
+ # @CODE:TEMPLATE-001 | SPEC: SPEC-INIT-003/spec.md | Chain: TEMPLATE-001
2
2
  """Template backup manager (SPEC-INIT-003 v0.3.0).
3
3
 
4
4
  Creates and manages backups to protect user data during template updates.
@@ -28,6 +28,15 @@ class TemplateBackup:
28
28
  """
29
29
  self.target_path = target_path.resolve()
30
30
 
31
+ @property
32
+ def backup_dir(self) -> Path:
33
+ """Get the backup directory path.
34
+
35
+ Returns:
36
+ Path to .moai-backups directory.
37
+ """
38
+ return self.target_path / ".moai-backups"
39
+
31
40
  def has_existing_files(self) -> bool:
32
41
  """Check whether backup-worthy files already exist.
33
42
 
@@ -36,7 +45,7 @@ class TemplateBackup:
36
45
  """
37
46
  return any(
38
47
  (self.target_path / item).exists()
39
- for item in [".moai", ".claude", "CLAUDE.md"]
48
+ for item in [".moai", ".claude", ".github", "CLAUDE.md"]
40
49
  )
41
50
 
42
51
  def create_backup(self) -> Path:
@@ -50,7 +59,7 @@ class TemplateBackup:
50
59
  backup_path.mkdir(parents=True, exist_ok=True)
51
60
 
52
61
  # Copy backup targets
53
- for item in [".moai", ".claude", "CLAUDE.md"]:
62
+ for item in [".moai", ".claude", ".github", "CLAUDE.md"]:
54
63
  src = self.target_path / item
55
64
  if not src.exists():
56
65
  continue
@@ -93,3 +93,27 @@ class ConfigManager:
93
93
  result[key] = value
94
94
 
95
95
  return result
96
+
97
+ @staticmethod
98
+ def set_optimized(config_path: Path, value: bool) -> None:
99
+ """Set the optimized field in config.json.
100
+
101
+ Args:
102
+ config_path: Path to config.json.
103
+ value: Value to set (True or False).
104
+ """
105
+ if not config_path.exists():
106
+ return
107
+
108
+ try:
109
+ with open(config_path, encoding="utf-8") as f:
110
+ config = json.load(f)
111
+
112
+ config.setdefault("project", {})["optimized"] = value
113
+
114
+ with open(config_path, "w", encoding="utf-8") as f:
115
+ json.dump(config, f, ensure_ascii=False, indent=2)
116
+ f.write("\n") # Add trailing newline
117
+ except (json.JSONDecodeError, KeyError, OSError):
118
+ # Ignore errors if config.json is invalid or inaccessible
119
+ pass
@@ -1,4 +1,4 @@
1
- # @CODE:CORE-PROJECT-001 | SPEC: SPEC-CORE-PROJECT-001.md | TEST: tests/unit/test_language_mapping.py
1
+ # @CODE:CORE-PROJECT-001 | SPEC: SPEC-CORE-PROJECT-001/spec.md | TEST: tests/unit/test_language_mapping.py
2
2
  """Template mapping by language.
3
3
 
4
4
  Defines template paths for 20 programming languages.