moai-adk 0.3.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 (87) hide show
  1. moai_adk/__init__.py +8 -0
  2. moai_adk/__main__.py +86 -0
  3. moai_adk/cli/__init__.py +2 -0
  4. moai_adk/cli/commands/__init__.py +16 -0
  5. moai_adk/cli/commands/backup.py +56 -0
  6. moai_adk/cli/commands/doctor.py +184 -0
  7. moai_adk/cli/commands/init.py +284 -0
  8. moai_adk/cli/commands/restore.py +77 -0
  9. moai_adk/cli/commands/status.py +79 -0
  10. moai_adk/cli/commands/update.py +133 -0
  11. moai_adk/cli/main.py +12 -0
  12. moai_adk/cli/prompts/__init__.py +5 -0
  13. moai_adk/cli/prompts/init_prompts.py +159 -0
  14. moai_adk/core/__init__.py +2 -0
  15. moai_adk/core/git/__init__.py +24 -0
  16. moai_adk/core/git/branch.py +26 -0
  17. moai_adk/core/git/branch_manager.py +137 -0
  18. moai_adk/core/git/checkpoint.py +140 -0
  19. moai_adk/core/git/commit.py +68 -0
  20. moai_adk/core/git/event_detector.py +81 -0
  21. moai_adk/core/git/manager.py +127 -0
  22. moai_adk/core/project/__init__.py +2 -0
  23. moai_adk/core/project/backup_utils.py +84 -0
  24. moai_adk/core/project/checker.py +302 -0
  25. moai_adk/core/project/detector.py +105 -0
  26. moai_adk/core/project/initializer.py +174 -0
  27. moai_adk/core/project/phase_executor.py +297 -0
  28. moai_adk/core/project/validator.py +118 -0
  29. moai_adk/core/quality/__init__.py +6 -0
  30. moai_adk/core/quality/trust_checker.py +441 -0
  31. moai_adk/core/quality/validators/__init__.py +6 -0
  32. moai_adk/core/quality/validators/base_validator.py +19 -0
  33. moai_adk/core/template/__init__.py +8 -0
  34. moai_adk/core/template/backup.py +95 -0
  35. moai_adk/core/template/config.py +95 -0
  36. moai_adk/core/template/languages.py +44 -0
  37. moai_adk/core/template/merger.py +117 -0
  38. moai_adk/core/template/processor.py +310 -0
  39. moai_adk/templates/.claude/agents/alfred/cc-manager.md +474 -0
  40. moai_adk/templates/.claude/agents/alfred/code-builder.md +534 -0
  41. moai_adk/templates/.claude/agents/alfred/debug-helper.md +302 -0
  42. moai_adk/templates/.claude/agents/alfred/doc-syncer.md +175 -0
  43. moai_adk/templates/.claude/agents/alfred/git-manager.md +200 -0
  44. moai_adk/templates/.claude/agents/alfred/project-manager.md +152 -0
  45. moai_adk/templates/.claude/agents/alfred/spec-builder.md +256 -0
  46. moai_adk/templates/.claude/agents/alfred/tag-agent.md +247 -0
  47. moai_adk/templates/.claude/agents/alfred/trust-checker.md +332 -0
  48. moai_adk/templates/.claude/commands/alfred/0-project.md +523 -0
  49. moai_adk/templates/.claude/commands/alfred/1-spec.md +531 -0
  50. moai_adk/templates/.claude/commands/alfred/2-build.md +413 -0
  51. moai_adk/templates/.claude/commands/alfred/3-sync.md +552 -0
  52. moai_adk/templates/.claude/hooks/alfred/README.md +238 -0
  53. moai_adk/templates/.claude/hooks/alfred/alfred_hooks.py +165 -0
  54. moai_adk/templates/.claude/hooks/alfred/core/__init__.py +79 -0
  55. moai_adk/templates/.claude/hooks/alfred/core/checkpoint.py +271 -0
  56. moai_adk/templates/.claude/hooks/alfred/core/context.py +110 -0
  57. moai_adk/templates/.claude/hooks/alfred/core/project.py +284 -0
  58. moai_adk/templates/.claude/hooks/alfred/core/tags.py +244 -0
  59. moai_adk/templates/.claude/hooks/alfred/handlers/__init__.py +23 -0
  60. moai_adk/templates/.claude/hooks/alfred/handlers/compact.py +51 -0
  61. moai_adk/templates/.claude/hooks/alfred/handlers/notification.py +25 -0
  62. moai_adk/templates/.claude/hooks/alfred/handlers/session.py +80 -0
  63. moai_adk/templates/.claude/hooks/alfred/handlers/tool.py +71 -0
  64. moai_adk/templates/.claude/hooks/alfred/handlers/user.py +41 -0
  65. moai_adk/templates/.claude/output-styles/alfred/agentic-coding.md +635 -0
  66. moai_adk/templates/.claude/output-styles/alfred/moai-adk-learning.md +691 -0
  67. moai_adk/templates/.claude/output-styles/alfred/study-with-alfred.md +469 -0
  68. moai_adk/templates/.claude/settings.json +135 -0
  69. moai_adk/templates/.github/PULL_REQUEST_TEMPLATE.md +68 -0
  70. moai_adk/templates/.github/workflows/moai-gitflow.yml +255 -0
  71. moai_adk/templates/.gitignore +41 -0
  72. moai_adk/templates/.moai/config.json +89 -0
  73. moai_adk/templates/.moai/memory/development-guide.md +367 -0
  74. moai_adk/templates/.moai/memory/spec-metadata.md +277 -0
  75. moai_adk/templates/.moai/project/product.md +121 -0
  76. moai_adk/templates/.moai/project/structure.md +150 -0
  77. moai_adk/templates/.moai/project/tech.md +221 -0
  78. moai_adk/templates/CLAUDE.md +733 -0
  79. moai_adk/templates/__init__.py +2 -0
  80. moai_adk/utils/__init__.py +8 -0
  81. moai_adk/utils/banner.py +42 -0
  82. moai_adk/utils/logger.py +152 -0
  83. moai_adk-0.3.0.dist-info/METADATA +20 -0
  84. moai_adk-0.3.0.dist-info/RECORD +87 -0
  85. moai_adk-0.3.0.dist-info/WHEEL +4 -0
  86. moai_adk-0.3.0.dist-info/entry_points.txt +2 -0
  87. moai_adk-0.3.0.dist-info/licenses/LICENSE +21 -0
moai_adk/__init__.py ADDED
@@ -0,0 +1,8 @@
1
+ # @CODE:PY314-001 | SPEC: SPEC-PY314-001.md | TEST: tests/unit/test_foundation.py
2
+ """MoAI Agentic Development Kit
3
+
4
+ SPEC-First TDD Framework with Alfred SuperAgent
5
+ """
6
+
7
+ __version__ = "0.3.0"
8
+ __all__ = ["__version__"]
moai_adk/__main__.py ADDED
@@ -0,0 +1,86 @@
1
+ # @CODE:CLI-001 | SPEC: SPEC-CLI-001.md | TEST: tests/unit/test_cli_commands.py
2
+ """MoAI-ADK CLI Entry Point
3
+
4
+ Implements the CLI entry point:
5
+ - Click-based CLI framework
6
+ - Rich console terminal output
7
+ - ASCII logo rendering
8
+ - --version and --help options
9
+ - Six core commands: init, doctor, status, backup, restore, update
10
+ """
11
+
12
+ import sys
13
+
14
+ import click
15
+ import pyfiglet
16
+ from rich.console import Console
17
+
18
+ from moai_adk import __version__
19
+ from moai_adk.cli.commands.backup import backup
20
+ from moai_adk.cli.commands.doctor import doctor
21
+ from moai_adk.cli.commands.init import init
22
+ from moai_adk.cli.commands.restore import restore
23
+ from moai_adk.cli.commands.status import status
24
+ from moai_adk.cli.commands.update import update
25
+
26
+ console = Console()
27
+
28
+
29
+ def show_logo() -> None:
30
+ """Render the MoAI-ADK ASCII logo with Pyfiglet"""
31
+ # Generate the "MoAI-ADK" banner using the ansi_shadow font
32
+ logo = pyfiglet.figlet_format("MoAI-ADK", font="ansi_shadow")
33
+
34
+ # Print with Rich styling
35
+ console.print(logo, style="cyan bold", highlight=False)
36
+ console.print(" Modu-AI's Agentic Development Kit w/ SuperAgent šŸŽ© Alfred", style="yellow bold")
37
+ console.print()
38
+ console.print(" Version: ", style="green", end="")
39
+ console.print(__version__, style="cyan bold")
40
+ console.print()
41
+ console.print(" Tip: Run ", style="yellow", end="")
42
+ console.print("python -m moai_adk --help", style="cyan", end="")
43
+ console.print(" to see available commands", style="yellow")
44
+
45
+
46
+ @click.group(invoke_without_command=True)
47
+ @click.version_option(version=__version__, prog_name="MoAI-ADK")
48
+ @click.pass_context
49
+ def cli(ctx: click.Context) -> None:
50
+ """MoAI Agentic Development Kit
51
+
52
+ SPEC-First TDD Framework with Alfred SuperAgent
53
+ """
54
+ # Display the logo when no subcommand is invoked
55
+ if ctx.invoked_subcommand is None:
56
+ show_logo()
57
+
58
+ cli.add_command(init)
59
+ cli.add_command(doctor)
60
+ cli.add_command(status)
61
+ cli.add_command(restore)
62
+ cli.add_command(backup)
63
+ cli.add_command(update)
64
+
65
+
66
+ def main() -> int:
67
+ """CLI entry point"""
68
+ try:
69
+ cli(standalone_mode=False)
70
+ return 0
71
+ except click.Abort:
72
+ # User cancelled with Ctrl+C
73
+ return 130
74
+ except click.ClickException as e:
75
+ e.show()
76
+ return e.exit_code
77
+ except Exception as e:
78
+ console.print(f"[red]Error:[/red] {e}")
79
+ return 1
80
+ finally:
81
+ # Flush the output buffer explicitly
82
+ console.file.flush()
83
+
84
+
85
+ if __name__ == "__main__":
86
+ sys.exit(main())
@@ -0,0 +1,2 @@
1
+ # @CODE:PY314-001 | SPEC: SPEC-PY314-001.md | TEST: tests/unit/test_foundation.py
2
+ """CLI module: Click-based command-line interface"""
@@ -0,0 +1,16 @@
1
+ # @CODE:CLI-001 | SPEC: SPEC-CLI-001.md | TEST: tests/unit/test_cli_commands.py
2
+ """CLI command module
3
+
4
+ Four core commands:
5
+ - init: initialize the project
6
+ - doctor: run system diagnostics
7
+ - status: show project status
8
+ - restore: restore backups
9
+ """
10
+
11
+ from moai_adk.cli.commands.doctor import doctor
12
+ from moai_adk.cli.commands.init import init
13
+ from moai_adk.cli.commands.restore import restore
14
+ from moai_adk.cli.commands.status import status
15
+
16
+ __all__ = ["init", "doctor", "status", "restore"]
@@ -0,0 +1,56 @@
1
+ """Backup command"""
2
+ from pathlib import Path
3
+
4
+ import click
5
+ from rich.console import Console
6
+
7
+ from moai_adk.core.template.processor import TemplateProcessor
8
+
9
+ console = Console()
10
+
11
+
12
+ @click.command()
13
+ @click.option(
14
+ "--path",
15
+ type=click.Path(exists=True),
16
+ default=".",
17
+ help="Project path (default: current directory)"
18
+ )
19
+ def backup(path: str) -> None:
20
+ """Create a backup of the current project.
21
+
22
+ Includes:
23
+ - .claude/ (entire directory)
24
+ - .moai/ (excluding specs and reports)
25
+ - CLAUDE.md
26
+
27
+ Backup location: .moai-backup/YYYYMMDD-HHMMSS/
28
+ """
29
+ try:
30
+ project_path = Path(path).resolve()
31
+
32
+ # Verify the project has been initialized
33
+ if not (project_path / ".moai").exists():
34
+ console.print("[yellow]⚠ Project not initialized[/yellow]")
35
+ raise click.Abort()
36
+
37
+ # Create the backup
38
+ console.print("[cyan]šŸ’¾ Creating backup...[/cyan]")
39
+ processor = TemplateProcessor(project_path)
40
+ backup_path = processor.create_backup()
41
+
42
+ # Success message
43
+ console.print(f"[green]āœ“ Backup completed: {backup_path.relative_to(project_path)}[/green]")
44
+
45
+ # Show backup contents
46
+ backup_items = list(backup_path.iterdir())
47
+ for item in backup_items:
48
+ if item.is_dir():
49
+ file_count = len(list(item.rglob("*")))
50
+ console.print(f" ā”œā”€ {item.name}/ ({file_count} files)")
51
+ else:
52
+ console.print(f" └─ {item.name}")
53
+
54
+ except Exception as e:
55
+ console.print(f"[red]āœ— Backup failed: {e}[/red]")
56
+ raise click.ClickException(str(e)) from e
@@ -0,0 +1,184 @@
1
+ # @CODE:CLI-001 | SPEC: SPEC-CLI-001.md | TEST: tests/unit/test_doctor.py
2
+ """MoAI-ADK doctor command
3
+
4
+ System diagnostics command:
5
+ - Check the Python version
6
+ - Verify Git installation
7
+ - Validate project structure
8
+ - Inspect language-specific tool chains
9
+ """
10
+
11
+ import json
12
+ from pathlib import Path
13
+
14
+ import click
15
+ import questionary
16
+ from rich.console import Console
17
+ from rich.table import Table
18
+
19
+ from moai_adk.core.project.checker import SystemChecker, check_environment
20
+ from moai_adk.core.project.detector import detect_project_language
21
+
22
+ console = Console()
23
+
24
+
25
+ @click.command()
26
+ @click.option("--verbose", "-v", is_flag=True, help="Show detailed tool versions and language detection")
27
+ @click.option("--fix", is_flag=True, help="Suggest fixes for missing tools")
28
+ @click.option("--export", type=click.Path(), help="Export diagnostics to JSON file")
29
+ @click.option("--check", type=str, help="Check specific tool only")
30
+ def doctor(verbose: bool, fix: bool, export: str | None, check: str | None) -> None:
31
+ """Check system requirements and project health
32
+
33
+ Verifies:
34
+ - Python version (>= 3.13)
35
+ - Git installation
36
+ - Project structure (.moai directory)
37
+ - Language-specific tool chains (20+ languages)
38
+ """
39
+ try:
40
+ console.print("[cyan]Running system diagnostics...[/cyan]\n")
41
+
42
+ # Run basic environment checks
43
+ results = check_environment()
44
+ diagnostics_data: dict = {"basic_checks": results}
45
+
46
+ # In verbose mode, verify language-specific toolchains
47
+ if verbose or fix:
48
+ language = detect_project_language()
49
+ diagnostics_data["detected_language"] = language
50
+
51
+ if verbose:
52
+ console.print(f"[dim]Detected language: {language or 'Unknown'}[/dim]\n")
53
+
54
+ if language:
55
+ checker = SystemChecker()
56
+ language_tools = checker.check_language_tools(language)
57
+ diagnostics_data["language_tools"] = language_tools
58
+
59
+ if verbose:
60
+ _display_language_tools(language, language_tools, checker)
61
+
62
+ # Specific tool check
63
+ if check:
64
+ _check_specific_tool(check)
65
+ return
66
+
67
+ # Build the base results table
68
+ table = Table(show_header=True, header_style="bold magenta")
69
+ table.add_column("Check", style="dim", width=40)
70
+ table.add_column("Status", justify="center")
71
+
72
+ for check_name, status in results.items():
73
+ icon = "āœ“" if status else "āœ—"
74
+ color = "green" if status else "red"
75
+ table.add_row(check_name, f"[{color}]{icon}[/{color}]")
76
+
77
+ console.print(table)
78
+
79
+ # In fix mode, suggest installation commands for missing tools
80
+ if fix and "language_tools" in diagnostics_data:
81
+ _suggest_fixes(diagnostics_data["language_tools"], diagnostics_data.get("detected_language"))
82
+
83
+ # When exporting, write diagnostics to JSON
84
+ if export:
85
+ _export_diagnostics(export, diagnostics_data)
86
+
87
+ # Summarize the overall result
88
+ all_passed = all(results.values())
89
+ if all_passed:
90
+ console.print("\n[green]āœ“ All checks passed[/green]")
91
+ else:
92
+ console.print("\n[yellow]⚠ Some checks failed[/yellow]")
93
+ console.print("[dim]Run [cyan]python -m moai_adk doctor --verbose[/cyan] for detailed diagnostics[/dim]")
94
+
95
+ except Exception as e:
96
+ console.print(f"[red]āœ— Diagnostic failed: {e}[/red]")
97
+ raise
98
+
99
+
100
+ def _display_language_tools(language: str, tools: dict[str, bool], checker: SystemChecker) -> None:
101
+ """Display a table of language-specific tools (helper)"""
102
+ table = Table(show_header=True, header_style="bold cyan", title=f"{language.title()} Tools")
103
+ table.add_column("Tool", style="dim")
104
+ table.add_column("Status", justify="center")
105
+ table.add_column("Version", style="blue")
106
+
107
+ for tool, available in tools.items():
108
+ icon = "āœ“" if available else "āœ—"
109
+ color = "green" if available else "red"
110
+ version = checker.get_tool_version(tool) if available else "not installed"
111
+
112
+ table.add_row(tool, f"[{color}]{icon}[/{color}]", version or "")
113
+
114
+ console.print(table)
115
+ console.print()
116
+
117
+
118
+ def _check_specific_tool(tool: str) -> None:
119
+ """Check only a specific tool (helper)"""
120
+ checker = SystemChecker()
121
+ available = checker._is_tool_available(tool)
122
+ version = checker.get_tool_version(tool) if available else None
123
+
124
+ if available:
125
+ console.print(f"[green]āœ“ {tool} is installed[/green]")
126
+ if version:
127
+ console.print(f" Version: {version}")
128
+ else:
129
+ console.print(f"[red]āœ— {tool} is not installed[/red]")
130
+
131
+
132
+ def _suggest_fixes(tools: dict[str, bool], language: str | None) -> None:
133
+ """Suggest installation commands for missing tools (helper)"""
134
+ missing_tools = [tool for tool, available in tools.items() if not available]
135
+
136
+ if not missing_tools:
137
+ console.print("\n[green]āœ“ All tools are installed[/green]")
138
+ return
139
+
140
+ console.print(f"\n[yellow]⚠ Missing {len(missing_tools)} tool(s)[/yellow]")
141
+
142
+ try:
143
+ proceed = questionary.confirm(
144
+ "Would you like to see install suggestions for missing tools?",
145
+ default=True,
146
+ ).ask()
147
+ except Exception:
148
+ proceed = True
149
+
150
+ if not proceed:
151
+ console.print("[yellow]User skipped install suggestions[/yellow]")
152
+ return
153
+
154
+ for tool in missing_tools:
155
+ install_cmd = _get_install_command(tool, language)
156
+ console.print(f" [red]āœ—[/red] {tool}")
157
+ if install_cmd:
158
+ console.print(f" Install: [cyan]{install_cmd}[/cyan]")
159
+
160
+
161
+ def _get_install_command(tool: str, language: str | None) -> str:
162
+ """Return the install command for a given tool (helper)"""
163
+ # Common tools
164
+ install_commands = {
165
+ "pytest": "pip install pytest",
166
+ "mypy": "pip install mypy",
167
+ "ruff": "pip install ruff",
168
+ "vitest": "npm install -D vitest",
169
+ "biome": "npm install -D @biomejs/biome",
170
+ "eslint": "npm install -D eslint",
171
+ "jest": "npm install -D jest",
172
+ }
173
+
174
+ return install_commands.get(tool, f"# Install {tool} for {language}")
175
+
176
+
177
+ def _export_diagnostics(export_path: str, data: dict) -> None:
178
+ """Export diagnostic results to a JSON file (helper)"""
179
+ try:
180
+ output = Path(export_path)
181
+ output.write_text(json.dumps(data, indent=2))
182
+ console.print(f"\n[green]āœ“ Diagnostics exported to {export_path}[/green]")
183
+ except Exception as e:
184
+ console.print(f"\n[red]āœ— Failed to export diagnostics: {e}[/red]")
@@ -0,0 +1,284 @@
1
+ # @CODE:CLI-001 | @CODE:INIT-003:CLI
2
+ # SPEC: SPEC-CLI-001.md, SPEC-INIT-003.md
3
+ # TEST: tests/unit/test_cli_commands.py, tests/unit/test_init_reinit.py
4
+ """MoAI-ADK init command
5
+
6
+ Project initialization command (interactive/non-interactive):
7
+ - Interactive Mode: Ask user for project settings
8
+ - Non-Interactive Mode: Use defaults or CLI options
9
+ """
10
+
11
+ import json
12
+ from pathlib import Path
13
+ from typing import Sequence
14
+
15
+ import click
16
+ from rich.console import Console
17
+ from rich.progress import BarColumn, Progress, SpinnerColumn, TaskID, TextColumn
18
+ from rich.prompt import Confirm
19
+
20
+ from moai_adk import __version__
21
+ from moai_adk.cli.prompts import prompt_project_setup
22
+ from moai_adk.core.project.initializer import ProjectInitializer
23
+ from moai_adk.utils.banner import print_banner, print_welcome_message
24
+
25
+ console = Console()
26
+
27
+
28
+ def create_progress_callback(progress: Progress, task_ids: Sequence[TaskID]):
29
+ """Create progress callback
30
+
31
+ Args:
32
+ progress: Rich Progress object
33
+ task_ids: List of task IDs (one per phase)
34
+
35
+ Returns:
36
+ Progress callback function
37
+ """
38
+
39
+ def callback(message: str, current: int, total: int) -> None:
40
+ """Update progress
41
+
42
+ Args:
43
+ message: Progress message
44
+ current: Current phase (1-based)
45
+ total: Total phases
46
+ """
47
+ # Complete current phase (1-based index → 0-based)
48
+ if 1 <= current <= len(task_ids):
49
+ progress.update(task_ids[current - 1], completed=1, description=message)
50
+
51
+ return callback
52
+
53
+
54
+ @click.command()
55
+ @click.argument("path", type=click.Path(), default=".")
56
+ @click.option(
57
+ "--non-interactive",
58
+ "-y",
59
+ is_flag=True,
60
+ help="Non-interactive mode (use defaults)",
61
+ )
62
+ @click.option(
63
+ "--mode",
64
+ type=click.Choice(["personal", "team"]),
65
+ default="personal",
66
+ help="Project mode",
67
+ )
68
+ @click.option(
69
+ "--locale",
70
+ type=click.Choice(["ko", "en", "ja", "zh"]),
71
+ default="ko",
72
+ help="Preferred language",
73
+ )
74
+ @click.option(
75
+ "--language",
76
+ type=str,
77
+ default=None,
78
+ help="Programming language (auto-detect if not specified)",
79
+ )
80
+ @click.option(
81
+ "--force",
82
+ is_flag=True,
83
+ help="Force reinitialize without confirmation",
84
+ )
85
+ def init(
86
+ path: str,
87
+ non_interactive: bool,
88
+ mode: str,
89
+ locale: str,
90
+ language: str | None,
91
+ force: bool,
92
+ ) -> None:
93
+ """Initialize a new MoAI-ADK project
94
+
95
+ Args:
96
+ path: Project directory path (default: current directory)
97
+ non_interactive: Skip prompts and use defaults
98
+ mode: Project mode (personal/team)
99
+ locale: Preferred language (ko/en/ja/zh)
100
+ language: Programming language
101
+ force: Force reinitialize without confirmation
102
+ """
103
+ try:
104
+ # 1. Print banner
105
+ print_banner()
106
+
107
+ # 2. Check current directory mode
108
+ is_current_dir = path == "."
109
+ project_path = Path(path).resolve()
110
+
111
+ # 3. Interactive vs Non-Interactive
112
+ if non_interactive:
113
+ # Non-Interactive Mode
114
+ console.print(
115
+ f"\n[cyan]šŸš€ Initializing project at {project_path}...[/cyan]\n"
116
+ )
117
+ project_name = project_path.name if is_current_dir else path
118
+ else:
119
+ # Interactive Mode
120
+ print_welcome_message()
121
+
122
+ # Interactive prompt
123
+ answers = prompt_project_setup(
124
+ project_name=None if is_current_dir else path,
125
+ is_current_dir=is_current_dir,
126
+ project_path=project_path,
127
+ )
128
+
129
+ # Override with prompt answers
130
+ mode = answers["mode"]
131
+ locale = answers["locale"]
132
+ language = answers["language"]
133
+ project_name = answers["project_name"]
134
+
135
+ console.print("\n[cyan]šŸš€ Starting installation...[/cyan]\n")
136
+
137
+ # 4. Check for reinitialization (SPEC-INIT-003 v0.3.0)
138
+ initializer = ProjectInitializer(project_path)
139
+
140
+ if initializer.is_initialized():
141
+ if non_interactive and not force:
142
+ # Non-interactive mode (without force): Reject reinitialization
143
+ console.print("\n[yellow]⚠ Project already initialized[/yellow]")
144
+ console.print(f"[dim] Location: {project_path}/.moai/[/dim]")
145
+ console.print("[dim] Use --force to reinitialize or interactive mode[/dim]\n")
146
+ raise click.Abort()
147
+
148
+ if force:
149
+ # Force mode: Reinitialize without confirmation
150
+ console.print("\n[green]šŸ”„ Force reinitializing project...[/green]\n")
151
+ else:
152
+ # Interactive mode: Reinitialization prompt
153
+ console.print("\nāš ļø [yellow]Project already initialized[/yellow]")
154
+ console.print(f" Location: {project_path}/.moai/\n")
155
+
156
+ console.print("[cyan]This will:[/cyan]")
157
+ console.print(" āœ“ Backup existing files to .moai-backups/{timestamp}/")
158
+ console.print(" • CLAUDE.md")
159
+ console.print(" • .claude/ (settings, commands, hooks)")
160
+ console.print(" • .moai/ (all configurations and specs)")
161
+ console.print(" āœ“ Update template files from moai-adk v0.3.0")
162
+ console.print(" • .claude/ → Latest Alfred commands")
163
+ console.print(" • .moai/memory/ → Latest development guides")
164
+ console.print(" • CLAUDE.md → Latest project documentation")
165
+ console.print(" āœ“ Preserve your content")
166
+ console.print(" • .moai/project/ (product/structure/tech.md)")
167
+ console.print(" • .moai/specs/ (all SPEC documents)\n")
168
+
169
+ if not Confirm.ask("Would you like to update the project templates?", default=True):
170
+ console.print("\n[yellow]Reinit cancelled.[/yellow]\n")
171
+ raise click.Abort()
172
+
173
+ console.print("\n[green]šŸ”„ Starting reinit process...[/green]\n")
174
+
175
+ # 5. Initialize project (Progress Bar with 5 phases)
176
+ is_reinit = initializer.is_initialized()
177
+
178
+ # Reinit mode: set config.json optimized to false (v0.3.1+)
179
+ if is_reinit:
180
+ config_path = project_path / ".moai" / "config.json"
181
+ if config_path.exists():
182
+ try:
183
+ with open(config_path, "r", encoding="utf-8") as f:
184
+ config_data = json.load(f)
185
+
186
+ # Update version and optimization flags
187
+ if "project" not in config_data:
188
+ config_data["project"] = {}
189
+
190
+ config_data["project"]["moai_adk_version"] = __version__
191
+ config_data["project"]["optimized"] = False
192
+
193
+ with open(config_path, "w", encoding="utf-8") as f:
194
+ json.dump(config_data, f, indent=2, ensure_ascii=False)
195
+ except Exception:
196
+ # Ignore read/write failures; config.json is regenerated during initialization
197
+ pass
198
+
199
+ with Progress(
200
+ SpinnerColumn(),
201
+ TextColumn("[progress.description]{task.description}"),
202
+ BarColumn(),
203
+ TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
204
+ console=console,
205
+ ) as progress:
206
+ # Create 5 phase tasks
207
+ phase_names = [
208
+ "Phase 1: Preparation and backup...",
209
+ "Phase 2: Creating directory structure...",
210
+ "Phase 3: Installing resources...",
211
+ "Phase 4: Generating configurations...",
212
+ "Phase 5: Validation and finalization...",
213
+ ]
214
+ task_ids = [progress.add_task(name, total=1) for name in phase_names]
215
+ callback = create_progress_callback(progress, task_ids)
216
+
217
+ result = initializer.initialize(
218
+ mode=mode,
219
+ locale=locale,
220
+ language=language,
221
+ backup_enabled=True,
222
+ progress_callback=callback,
223
+ reinit=is_reinit, # SPEC-INIT-003 v0.3.0
224
+ )
225
+
226
+ # 6. Output results
227
+ if result.success:
228
+ separator = "[dim]" + ("─" * 60) + "[/dim]"
229
+ console.print(
230
+ "\n[green bold]āœ… Initialization Completed Successfully![/green bold]"
231
+ )
232
+ console.print(separator)
233
+ console.print("\n[cyan]šŸ“Š Summary:[/cyan]")
234
+ console.print(f" [dim]šŸ“ Location:[/dim] {result.project_path}")
235
+ console.print(f" [dim]🌐 Language:[/dim] {result.language}")
236
+ console.print(f" [dim]šŸ”§ Mode:[/dim] {result.mode}")
237
+ console.print(
238
+ f" [dim]šŸŒ Locale:[/dim] {result.locale}"
239
+ )
240
+ console.print(
241
+ f" [dim]šŸ“„ Files:[/dim] {len(result.created_files)} created"
242
+ )
243
+ console.print(f" [dim]ā±ļø Duration:[/dim] {result.duration}ms")
244
+ console.print(f"\n{separator}")
245
+ console.print("\n[cyan]šŸš€ Next Steps:[/cyan]")
246
+ if not is_current_dir:
247
+ console.print(
248
+ f" [blue]1.[/blue] Run [bold]cd {project_name}[/bold] to enter the project"
249
+ )
250
+ console.print(
251
+ " [blue]2.[/blue] Check [bold].moai/config.json[/bold] for configuration"
252
+ )
253
+ console.print(
254
+ " [blue]3.[/blue] Read [bold]CLAUDE.md[/bold] for development guide\n"
255
+ )
256
+ else:
257
+ console.print(
258
+ " [blue]1.[/blue] Check [bold].moai/config.json[/bold] for configuration"
259
+ )
260
+ console.print(
261
+ " [blue]2.[/blue] Read [bold]CLAUDE.md[/bold] for development guide\n"
262
+ )
263
+ else:
264
+ console.print("\n[red bold]āŒ Initialization Failed![/red bold]")
265
+ if result.errors:
266
+ console.print("\n[red]Errors:[/red]")
267
+ for error in result.errors:
268
+ console.print(f" [red]•[/red] {error}")
269
+ console.print()
270
+ raise click.ClickException("Installation failed")
271
+
272
+ except KeyboardInterrupt:
273
+ console.print("\n\n[yellow]⚠ Initialization cancelled by user[/yellow]\n")
274
+ raise click.Abort()
275
+ except FileExistsError as e:
276
+ console.print("\n[yellow]⚠ Project already initialized[/yellow]")
277
+ console.print("[dim] Use 'python -m moai_adk status' to check configuration[/dim]\n")
278
+ raise click.Abort() from e
279
+ except Exception as e:
280
+ console.print(f"\n[red]āœ— Initialization failed: {e}[/red]\n")
281
+ raise click.ClickException(str(e)) from e
282
+ finally:
283
+ # Explicitly flush output buffer
284
+ console.file.flush()