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
@@ -0,0 +1,297 @@
1
+ # @CODE:INIT-003:PHASE | SPEC: .moai/specs/SPEC-INIT-003/spec.md | TEST: tests/unit/test_init_reinit.py
2
+ """Phase-based installation executor (SPEC-INIT-003 v0.3.0)
3
+
4
+ Runs the project initialization across five phases:
5
+ - Phase 1: Preparation (create backup at .moai-backups/{timestamp}/, keep only latest)
6
+ - Phase 2: Directory (build directory structure)
7
+ - Phase 3: Resource (copy templates while preserving user content)
8
+ - Phase 4: Configuration (generate configuration files)
9
+ - Phase 5: Validation (verify and finalize)
10
+ """
11
+
12
+ import json
13
+ import shutil
14
+ import subprocess
15
+ from collections.abc import Callable
16
+ from pathlib import Path
17
+
18
+ from rich.console import Console
19
+
20
+ from moai_adk import __version__
21
+ from moai_adk.core.project.backup_utils import (
22
+ generate_backup_dir_name,
23
+ get_backup_targets,
24
+ has_any_moai_files,
25
+ is_protected_path,
26
+ )
27
+ from moai_adk.core.project.validator import ProjectValidator
28
+
29
+ console = Console()
30
+
31
+ # Progress callback type alias
32
+ ProgressCallback = Callable[[str, int, int], None]
33
+
34
+
35
+ class PhaseExecutor:
36
+ """Execute the installation across the five phases.
37
+
38
+ Phases:
39
+ 1. Preparation: Back up and verify the system.
40
+ 2. Directory: Create the directory structure.
41
+ 3. Resource: Copy template resources.
42
+ 4. Configuration: Generate configuration files.
43
+ 5. Validation: Perform final checks.
44
+ """
45
+
46
+ # Required directory structure
47
+ REQUIRED_DIRECTORIES = [
48
+ ".moai/",
49
+ ".moai/project/",
50
+ ".moai/specs/",
51
+ ".moai/reports/",
52
+ ".moai/memory/",
53
+ ".claude/",
54
+ ".claude/logs/",
55
+ ]
56
+
57
+ def __init__(self, validator: ProjectValidator) -> None:
58
+ """Initialize the executor.
59
+
60
+ Args:
61
+ validator: Project validation helper.
62
+ """
63
+ self.validator = validator
64
+ self.total_phases = 5
65
+ self.current_phase = 0
66
+
67
+ def execute_preparation_phase(
68
+ self,
69
+ project_path: Path,
70
+ backup_enabled: bool = True,
71
+ progress_callback: ProgressCallback | None = None,
72
+ ) -> None:
73
+ """Phase 1: preparation and backup.
74
+
75
+ Args:
76
+ project_path: Project path.
77
+ backup_enabled: Whether backups are enabled.
78
+ progress_callback: Optional progress callback.
79
+ """
80
+ self.current_phase = 1
81
+ self._report_progress(
82
+ "Phase 1: Preparation and backup...", progress_callback
83
+ )
84
+
85
+ # Validate system requirements
86
+ self.validator.validate_system_requirements()
87
+
88
+ # Verify the project path
89
+ self.validator.validate_project_path(project_path)
90
+
91
+ # Create a backup when needed
92
+ if backup_enabled and has_any_moai_files(project_path):
93
+ self._create_backup(project_path)
94
+
95
+ def execute_directory_phase(
96
+ self,
97
+ project_path: Path,
98
+ progress_callback: ProgressCallback | None = None,
99
+ ) -> None:
100
+ """Phase 2: create directories.
101
+
102
+ Args:
103
+ project_path: Project path.
104
+ progress_callback: Optional progress callback.
105
+ """
106
+ self.current_phase = 2
107
+ self._report_progress(
108
+ "Phase 2: Creating directory structure...", progress_callback
109
+ )
110
+
111
+ for directory in self.REQUIRED_DIRECTORIES:
112
+ dir_path = project_path / directory
113
+ dir_path.mkdir(parents=True, exist_ok=True)
114
+
115
+ def execute_resource_phase(
116
+ self,
117
+ project_path: Path,
118
+ progress_callback: ProgressCallback | None = None,
119
+ ) -> list[str]:
120
+ """Phase 3: install resources.
121
+
122
+ Args:
123
+ project_path: Project path.
124
+ progress_callback: Optional progress callback.
125
+
126
+ Returns:
127
+ List of created files or directories.
128
+ """
129
+ self.current_phase = 3
130
+ self._report_progress(
131
+ "Phase 3: Installing resources...", progress_callback
132
+ )
133
+
134
+ # Copy resources via TemplateProcessor in silent mode
135
+ from moai_adk.core.template import TemplateProcessor
136
+
137
+ processor = TemplateProcessor(project_path)
138
+ processor.copy_templates(backup=False, silent=True) # Avoid progress bar conflicts
139
+
140
+ # Return a simplified list of generated assets
141
+ return [
142
+ ".claude/",
143
+ ".moai/",
144
+ "CLAUDE.md",
145
+ ".gitignore",
146
+ ]
147
+
148
+ def execute_configuration_phase(
149
+ self,
150
+ project_path: Path,
151
+ config: dict[str, str],
152
+ progress_callback: ProgressCallback | None = None,
153
+ ) -> list[str]:
154
+ """Phase 4: generate configuration.
155
+
156
+ Args:
157
+ project_path: Project path.
158
+ config: Configuration dictionary.
159
+ progress_callback: Optional progress callback.
160
+
161
+ Returns:
162
+ List of created files.
163
+ """
164
+ self.current_phase = 4
165
+ self._report_progress(
166
+ "Phase 4: Generating configurations...", progress_callback
167
+ )
168
+
169
+ # Attach version metadata (v0.3.1+)
170
+ config["moai_adk_version"] = __version__
171
+ config["optimized"] = False # Default value
172
+
173
+ # Write config.json
174
+ config_path = project_path / ".moai" / "config.json"
175
+ with open(config_path, "w", encoding="utf-8") as f:
176
+ json.dump(config, f, indent=2, ensure_ascii=False)
177
+
178
+ return [str(config_path)]
179
+
180
+ def execute_validation_phase(
181
+ self,
182
+ project_path: Path,
183
+ mode: str = "personal",
184
+ progress_callback: ProgressCallback | None = None,
185
+ ) -> None:
186
+ """Phase 5: validation and wrap-up.
187
+
188
+ Args:
189
+ project_path: Project path.
190
+ mode: Project mode (personal/team).
191
+ progress_callback: Optional progress callback.
192
+ """
193
+ self.current_phase = 5
194
+ self._report_progress(
195
+ "Phase 5: Validation and finalization...", progress_callback
196
+ )
197
+
198
+ # Validate installation results
199
+ self.validator.validate_installation(project_path)
200
+
201
+ # Initialize Git for team mode
202
+ if mode == "team":
203
+ self._initialize_git(project_path)
204
+
205
+ def _create_backup(self, project_path: Path) -> None:
206
+ """Create a selective backup (v0.3.0).
207
+
208
+ Keep only the latest backup in .moai-backups/{timestamp}/.
209
+
210
+ Args:
211
+ project_path: Project path.
212
+ """
213
+ # Define backup directory
214
+ backups_dir = project_path / ".moai-backups"
215
+
216
+ # Remove all existing backups (keep only latest)
217
+ if backups_dir.exists():
218
+ for item in backups_dir.iterdir():
219
+ if item.is_dir():
220
+ shutil.rmtree(item)
221
+
222
+ # Create new backup directory (.moai-backups/{timestamp}/)
223
+ timestamp = generate_backup_dir_name()
224
+ backup_path = backups_dir / timestamp
225
+ backup_path.mkdir(parents=True, exist_ok=True)
226
+
227
+ # Collect backup targets
228
+ targets = get_backup_targets(project_path)
229
+ backed_up_files: list[str] = []
230
+
231
+ # Execute the backup
232
+ for target in targets:
233
+ src_path = project_path / target
234
+ dst_path = backup_path / target
235
+
236
+ if src_path.is_dir():
237
+ self._copy_directory_selective(src_path, dst_path)
238
+ backed_up_files.append(f"{target}/")
239
+ else:
240
+ dst_path.parent.mkdir(parents=True, exist_ok=True)
241
+ shutil.copy2(src_path, dst_path)
242
+ backed_up_files.append(target)
243
+
244
+ # Avoid additional console messages to prevent progress bar conflicts
245
+
246
+ def _copy_directory_selective(self, src: Path, dst: Path) -> None:
247
+ """Copy a directory while skipping protected paths.
248
+
249
+ Args:
250
+ src: Source directory.
251
+ dst: Destination directory.
252
+ """
253
+ dst.mkdir(parents=True, exist_ok=True)
254
+
255
+ for item in src.rglob("*"):
256
+ rel_path = item.relative_to(src)
257
+
258
+ # Skip protected paths
259
+ if is_protected_path(rel_path):
260
+ continue
261
+
262
+ dst_item = dst / rel_path
263
+ if item.is_file():
264
+ dst_item.parent.mkdir(parents=True, exist_ok=True)
265
+ shutil.copy2(item, dst_item)
266
+ elif item.is_dir():
267
+ dst_item.mkdir(parents=True, exist_ok=True)
268
+
269
+ def _initialize_git(self, project_path: Path) -> None:
270
+ """Initialize a Git repository.
271
+
272
+ Args:
273
+ project_path: Project path.
274
+ """
275
+ try:
276
+ subprocess.run(
277
+ ["git", "init"],
278
+ cwd=project_path,
279
+ check=True,
280
+ capture_output=True,
281
+ )
282
+ # Intentionally avoid printing to keep progress output clean
283
+ except subprocess.CalledProcessError:
284
+ # Only log on error; failures are non-fatal
285
+ pass
286
+
287
+ def _report_progress(
288
+ self, message: str, callback: ProgressCallback | None
289
+ ) -> None:
290
+ """Report progress.
291
+
292
+ Args:
293
+ message: Progress message.
294
+ callback: Callback function.
295
+ """
296
+ if callback:
297
+ callback(message, self.current_phase, self.total_phases)
@@ -0,0 +1,118 @@
1
+ # @CODE:CORE-PROJECT-003 | SPEC: SPEC-CORE-PROJECT-001.md
2
+ """Project initialization validation module.
3
+
4
+ Validates system requirements and installation results.
5
+ """
6
+
7
+ import shutil
8
+ from pathlib import Path
9
+
10
+
11
+ class ValidationError(Exception):
12
+ """Raised when validation fails."""
13
+
14
+ pass
15
+
16
+
17
+ class ProjectValidator:
18
+ """Validate project initialization."""
19
+
20
+ # Required directory structure
21
+ REQUIRED_DIRECTORIES = [
22
+ ".moai/",
23
+ ".moai/project/",
24
+ ".moai/specs/",
25
+ ".moai/memory/",
26
+ ".claude/",
27
+ ]
28
+
29
+ # Required files
30
+ REQUIRED_FILES = [
31
+ ".moai/config.json",
32
+ "CLAUDE.md",
33
+ ]
34
+
35
+ def validate_system_requirements(self) -> None:
36
+ """Verify system requirements.
37
+
38
+ Raises:
39
+ ValidationError: Raised when requirements are not satisfied.
40
+ """
41
+ # Ensure Git is installed
42
+ if not shutil.which("git"):
43
+ raise ValidationError("Git is not installed")
44
+
45
+ # Check Python version (3.10+)
46
+ import sys
47
+
48
+ if sys.version_info < (3, 10):
49
+ raise ValidationError(
50
+ f"Python 3.10+ required (current: {sys.version_info.major}.{sys.version_info.minor})"
51
+ )
52
+
53
+ def validate_project_path(self, project_path: Path) -> None:
54
+ """Verify the project path.
55
+
56
+ Args:
57
+ project_path: Project path.
58
+
59
+ Raises:
60
+ ValidationError: Raised when the path is invalid.
61
+ """
62
+ # Must be an absolute path
63
+ if not project_path.is_absolute():
64
+ raise ValidationError(f"Project path must be absolute: {project_path}")
65
+
66
+ # Parent directory must exist
67
+ if not project_path.parent.exists():
68
+ raise ValidationError(f"Parent directory does not exist: {project_path.parent}")
69
+
70
+ # Prevent initialization inside the MoAI-ADK package
71
+ if self._is_inside_moai_package(project_path):
72
+ raise ValidationError(
73
+ "Cannot initialize inside MoAI-ADK package directory"
74
+ )
75
+
76
+ def validate_installation(self, project_path: Path) -> None:
77
+ """Validate installation results.
78
+
79
+ Args:
80
+ project_path: Project path.
81
+
82
+ Raises:
83
+ ValidationError: Raised when installation was incomplete.
84
+ """
85
+ # Verify required directories
86
+ for directory in self.REQUIRED_DIRECTORIES:
87
+ dir_path = project_path / directory
88
+ if not dir_path.exists():
89
+ raise ValidationError(f"Required directory not found: {directory}")
90
+
91
+ # Verify required files
92
+ for file in self.REQUIRED_FILES:
93
+ file_path = project_path / file
94
+ if not file_path.exists():
95
+ raise ValidationError(f"Required file not found: {file}")
96
+
97
+ def _is_inside_moai_package(self, project_path: Path) -> bool:
98
+ """Determine whether the path is inside the MoAI-ADK package.
99
+
100
+ Args:
101
+ project_path: Path to check.
102
+
103
+ Returns:
104
+ True when the path resides within the package.
105
+ """
106
+ # The package root contains a pyproject.toml referencing moai-adk
107
+ current = project_path.resolve()
108
+ while current != current.parent:
109
+ pyproject = current / "pyproject.toml"
110
+ if pyproject.exists():
111
+ try:
112
+ content = pyproject.read_text(encoding="utf-8")
113
+ if "name = \"moai-adk\"" in content or 'name = "moai-adk"' in content:
114
+ return True
115
+ except Exception:
116
+ pass
117
+ current = current.parent
118
+ return False
@@ -0,0 +1,6 @@
1
+ # @CODE:TRUST-001 | SPEC: SPEC-TRUST-001.md | TEST: tests/unit/core/quality/
2
+ """TRUST 원칙 자동 검증 시스템"""
3
+
4
+ from moai_adk.core.quality.trust_checker import TrustChecker
5
+
6
+ __all__ = ["TrustChecker"]