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.
- moai_adk/__init__.py +8 -0
- moai_adk/__main__.py +86 -0
- moai_adk/cli/__init__.py +2 -0
- moai_adk/cli/commands/__init__.py +16 -0
- moai_adk/cli/commands/backup.py +56 -0
- moai_adk/cli/commands/doctor.py +184 -0
- moai_adk/cli/commands/init.py +284 -0
- moai_adk/cli/commands/restore.py +77 -0
- moai_adk/cli/commands/status.py +79 -0
- moai_adk/cli/commands/update.py +133 -0
- moai_adk/cli/main.py +12 -0
- moai_adk/cli/prompts/__init__.py +5 -0
- moai_adk/cli/prompts/init_prompts.py +159 -0
- moai_adk/core/__init__.py +2 -0
- moai_adk/core/git/__init__.py +24 -0
- moai_adk/core/git/branch.py +26 -0
- moai_adk/core/git/branch_manager.py +137 -0
- moai_adk/core/git/checkpoint.py +140 -0
- moai_adk/core/git/commit.py +68 -0
- moai_adk/core/git/event_detector.py +81 -0
- moai_adk/core/git/manager.py +127 -0
- moai_adk/core/project/__init__.py +2 -0
- moai_adk/core/project/backup_utils.py +84 -0
- moai_adk/core/project/checker.py +302 -0
- moai_adk/core/project/detector.py +105 -0
- moai_adk/core/project/initializer.py +174 -0
- moai_adk/core/project/phase_executor.py +297 -0
- moai_adk/core/project/validator.py +118 -0
- moai_adk/core/quality/__init__.py +6 -0
- moai_adk/core/quality/trust_checker.py +441 -0
- moai_adk/core/quality/validators/__init__.py +6 -0
- moai_adk/core/quality/validators/base_validator.py +19 -0
- moai_adk/core/template/__init__.py +8 -0
- moai_adk/core/template/backup.py +95 -0
- moai_adk/core/template/config.py +95 -0
- moai_adk/core/template/languages.py +44 -0
- moai_adk/core/template/merger.py +117 -0
- moai_adk/core/template/processor.py +310 -0
- moai_adk/templates/.claude/agents/alfred/cc-manager.md +474 -0
- moai_adk/templates/.claude/agents/alfred/code-builder.md +534 -0
- moai_adk/templates/.claude/agents/alfred/debug-helper.md +302 -0
- moai_adk/templates/.claude/agents/alfred/doc-syncer.md +175 -0
- moai_adk/templates/.claude/agents/alfred/git-manager.md +200 -0
- moai_adk/templates/.claude/agents/alfred/project-manager.md +152 -0
- moai_adk/templates/.claude/agents/alfred/spec-builder.md +256 -0
- moai_adk/templates/.claude/agents/alfred/tag-agent.md +247 -0
- moai_adk/templates/.claude/agents/alfred/trust-checker.md +332 -0
- moai_adk/templates/.claude/commands/alfred/0-project.md +523 -0
- moai_adk/templates/.claude/commands/alfred/1-spec.md +531 -0
- moai_adk/templates/.claude/commands/alfred/2-build.md +413 -0
- moai_adk/templates/.claude/commands/alfred/3-sync.md +552 -0
- moai_adk/templates/.claude/hooks/alfred/README.md +238 -0
- moai_adk/templates/.claude/hooks/alfred/alfred_hooks.py +165 -0
- moai_adk/templates/.claude/hooks/alfred/core/__init__.py +79 -0
- moai_adk/templates/.claude/hooks/alfred/core/checkpoint.py +271 -0
- moai_adk/templates/.claude/hooks/alfred/core/context.py +110 -0
- moai_adk/templates/.claude/hooks/alfred/core/project.py +284 -0
- moai_adk/templates/.claude/hooks/alfred/core/tags.py +244 -0
- moai_adk/templates/.claude/hooks/alfred/handlers/__init__.py +23 -0
- moai_adk/templates/.claude/hooks/alfred/handlers/compact.py +51 -0
- moai_adk/templates/.claude/hooks/alfred/handlers/notification.py +25 -0
- moai_adk/templates/.claude/hooks/alfred/handlers/session.py +80 -0
- moai_adk/templates/.claude/hooks/alfred/handlers/tool.py +71 -0
- moai_adk/templates/.claude/hooks/alfred/handlers/user.py +41 -0
- moai_adk/templates/.claude/output-styles/alfred/agentic-coding.md +635 -0
- moai_adk/templates/.claude/output-styles/alfred/moai-adk-learning.md +691 -0
- moai_adk/templates/.claude/output-styles/alfred/study-with-alfred.md +469 -0
- moai_adk/templates/.claude/settings.json +135 -0
- moai_adk/templates/.github/PULL_REQUEST_TEMPLATE.md +68 -0
- moai_adk/templates/.github/workflows/moai-gitflow.yml +255 -0
- moai_adk/templates/.gitignore +41 -0
- moai_adk/templates/.moai/config.json +89 -0
- moai_adk/templates/.moai/memory/development-guide.md +367 -0
- moai_adk/templates/.moai/memory/spec-metadata.md +277 -0
- moai_adk/templates/.moai/project/product.md +121 -0
- moai_adk/templates/.moai/project/structure.md +150 -0
- moai_adk/templates/.moai/project/tech.md +221 -0
- moai_adk/templates/CLAUDE.md +733 -0
- moai_adk/templates/__init__.py +2 -0
- moai_adk/utils/__init__.py +8 -0
- moai_adk/utils/banner.py +42 -0
- moai_adk/utils/logger.py +152 -0
- moai_adk-0.3.0.dist-info/METADATA +20 -0
- moai_adk-0.3.0.dist-info/RECORD +87 -0
- moai_adk-0.3.0.dist-info/WHEEL +4 -0
- moai_adk-0.3.0.dist-info/entry_points.txt +2 -0
- 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
|