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,140 @@
1
+ # @CODE:CHECKPOINT-EVENT-001 | SPEC: SPEC-CHECKPOINT-EVENT-001.md | TEST: tests/unit/test_checkpoint.py
2
+ """
3
+ Checkpoint Manager - Event-driven checkpoint system.
4
+
5
+ SPEC: .moai/specs/SPEC-CHECKPOINT-EVENT-001/spec.md
6
+ """
7
+
8
+ from datetime import datetime
9
+ from pathlib import Path
10
+ from typing import Optional
11
+
12
+ import git
13
+
14
+ from moai_adk.core.git.branch_manager import BranchManager
15
+ from moai_adk.core.git.event_detector import EventDetector
16
+
17
+
18
+ class CheckpointManager:
19
+ """Manage creation and restoration of event-driven checkpoints."""
20
+
21
+ def __init__(self, repo: git.Repo, project_root: Path):
22
+ """
23
+ Initialize the CheckpointManager.
24
+
25
+ Args:
26
+ repo: GitPython Repo instance.
27
+ project_root: Project root directory.
28
+ """
29
+ self.repo = repo
30
+ self.project_root = project_root
31
+ self.event_detector = EventDetector()
32
+ self.branch_manager = BranchManager(repo)
33
+ self.log_file = project_root / ".moai" / "checkpoints.log"
34
+
35
+ # Ensure the log directory exists
36
+ self.log_file.parent.mkdir(parents=True, exist_ok=True)
37
+
38
+ def create_checkpoint_if_risky(
39
+ self,
40
+ operation: str,
41
+ deleted_files: Optional[list[str]] = None,
42
+ renamed_files: Optional[list[tuple[str, str]]] = None,
43
+ modified_files: Optional[list[Path]] = None,
44
+ ) -> Optional[str]:
45
+ """
46
+ Create a checkpoint when a risky operation is detected.
47
+
48
+ SPEC requirement: automatically create a checkpoint for risky actions.
49
+
50
+ Args:
51
+ operation: Operation type.
52
+ deleted_files: Files scheduled for deletion.
53
+ renamed_files: Files that will be renamed.
54
+ modified_files: Files that will be modified.
55
+
56
+ Returns:
57
+ Created checkpoint ID (branch name) or None when the operation is safe.
58
+ """
59
+ is_risky = False
60
+
61
+ # Identify large deletion operations
62
+ if deleted_files and self.event_detector.is_risky_deletion(deleted_files):
63
+ is_risky = True
64
+
65
+ # Identify large-scale refactoring
66
+ if renamed_files and self.event_detector.is_risky_refactoring(renamed_files):
67
+ is_risky = True
68
+
69
+ # Check for critical file modifications
70
+ if modified_files:
71
+ for file_path in modified_files:
72
+ if self.event_detector.is_critical_file(file_path):
73
+ is_risky = True
74
+ break
75
+
76
+ if not is_risky:
77
+ return None
78
+
79
+ # Create a checkpoint
80
+ checkpoint_id = self.branch_manager.create_checkpoint_branch(operation)
81
+
82
+ # Record checkpoint metadata
83
+ self._log_checkpoint(checkpoint_id, operation)
84
+
85
+ return checkpoint_id
86
+
87
+ def restore_checkpoint(self, checkpoint_id: str) -> None:
88
+ """
89
+ Restore the repository to the specified checkpoint.
90
+
91
+ SPEC requirement: capture the current state as a new checkpoint before restoring.
92
+
93
+ Args:
94
+ checkpoint_id: Target checkpoint ID (branch name).
95
+ """
96
+ # Save current state as a safety checkpoint before restoring
97
+ safety_checkpoint = self.branch_manager.create_checkpoint_branch("restore")
98
+ self._log_checkpoint(safety_checkpoint, "restore", is_safety=True)
99
+
100
+ # Check out the checkpoint branch
101
+ self.repo.git.checkout(checkpoint_id)
102
+
103
+ def list_checkpoints(self) -> list[str]:
104
+ """
105
+ List all checkpoints.
106
+
107
+ Returns:
108
+ List of checkpoint IDs.
109
+ """
110
+ return self.branch_manager.list_checkpoint_branches()
111
+
112
+ def _log_checkpoint(
113
+ self,
114
+ checkpoint_id: str,
115
+ operation: str,
116
+ is_safety: bool = False
117
+ ) -> None:
118
+ """
119
+ Append checkpoint metadata to the log file.
120
+
121
+ SPEC requirement: write metadata to .moai/checkpoints.log.
122
+
123
+ Args:
124
+ checkpoint_id: Checkpoint identifier.
125
+ operation: Operation type.
126
+ is_safety: Whether the checkpoint was created for safety.
127
+ """
128
+ timestamp = datetime.now().isoformat()
129
+
130
+ log_entry = f"""---
131
+ checkpoint_id: {checkpoint_id}
132
+ operation: {operation}
133
+ timestamp: {timestamp}
134
+ is_safety: {is_safety}
135
+ ---
136
+ """
137
+
138
+ # Append the entry to the log
139
+ with open(self.log_file, "a", encoding="utf-8") as f:
140
+ f.write(log_entry)
@@ -0,0 +1,68 @@
1
+ # @CODE:CORE-GIT-001 | SPEC: SPEC-CORE-GIT-001.md | TEST: tests/unit/test_git.py
2
+ """
3
+ Commit message formatting utilities.
4
+
5
+ SPEC: .moai/specs/SPEC-CORE-GIT-001/spec.md
6
+ """
7
+
8
+ from typing import Literal
9
+
10
+
11
+ def format_commit_message(
12
+ stage: Literal["red", "green", "refactor", "docs"],
13
+ description: str,
14
+ locale: str = "ko",
15
+ ) -> str:
16
+ """
17
+ Generate a commit message for each TDD stage.
18
+
19
+ Args:
20
+ stage: TDD stage (red, green, refactor, docs).
21
+ description: Commit description text.
22
+ locale: Language code (ko, en, ja, zh).
23
+
24
+ Returns:
25
+ Formatted commit message.
26
+
27
+ Examples:
28
+ >>> format_commit_message("red", "Add failing authentication test", "ko")
29
+ '🔴 RED: Add failing authentication test'
30
+
31
+ >>> format_commit_message("green", "Implement authentication", "en")
32
+ '🟢 GREEN: Implement authentication'
33
+
34
+ >>> format_commit_message("refactor", "Improve code structure", "ko")
35
+ '♻️ REFACTOR: Improve code structure'
36
+ """
37
+ templates = {
38
+ "ko": {
39
+ "red": "🔴 RED: {desc}",
40
+ "green": "🟢 GREEN: {desc}",
41
+ "refactor": "♻️ REFACTOR: {desc}",
42
+ "docs": "📝 DOCS: {desc}",
43
+ },
44
+ "en": {
45
+ "red": "🔴 RED: {desc}",
46
+ "green": "🟢 GREEN: {desc}",
47
+ "refactor": "♻️ REFACTOR: {desc}",
48
+ "docs": "📝 DOCS: {desc}",
49
+ },
50
+ "ja": {
51
+ "red": "🔴 RED: {desc}",
52
+ "green": "🟢 GREEN: {desc}",
53
+ "refactor": "♻️ REFACTOR: {desc}",
54
+ "docs": "📝 DOCS: {desc}",
55
+ },
56
+ "zh": {
57
+ "red": "🔴 RED: {desc}",
58
+ "green": "🟢 GREEN: {desc}",
59
+ "refactor": "♻️ REFACTOR: {desc}",
60
+ "docs": "📝 DOCS: {desc}",
61
+ },
62
+ }
63
+
64
+ template = templates.get(locale, templates["en"]).get(stage.lower())
65
+ if not template:
66
+ raise ValueError(f"Invalid stage: {stage}")
67
+
68
+ return template.format(desc=description)
@@ -0,0 +1,81 @@
1
+ # @CODE:CHECKPOINT-EVENT-001 | SPEC: SPEC-CHECKPOINT-EVENT-001.md | TEST: tests/unit/test_event_detector.py
2
+ """
3
+ Event Detector - Identify risky operations.
4
+
5
+ SPEC: .moai/specs/SPEC-CHECKPOINT-EVENT-001/spec.md
6
+ """
7
+
8
+ from pathlib import Path
9
+
10
+
11
+ class EventDetector:
12
+ """Detect potentially risky operations."""
13
+
14
+ # @CODE:CHECKPOINT-EVENT-001:DOMAIN - Critical file list
15
+ CRITICAL_FILES = {
16
+ "CLAUDE.md",
17
+ "config.json",
18
+ ".moai/config.json",
19
+ }
20
+
21
+ CRITICAL_DIRS = {
22
+ ".moai/memory",
23
+ }
24
+
25
+ def is_risky_deletion(self, deleted_files: list[str]) -> bool:
26
+ """
27
+ Detect large-scale file deletions.
28
+
29
+ SPEC requirement: deleting 10 or more files counts as risky.
30
+
31
+ Args:
32
+ deleted_files: Files slated for deletion.
33
+
34
+ Returns:
35
+ True when 10 or more files are deleted, otherwise False.
36
+ """
37
+ return len(deleted_files) >= 10
38
+
39
+ def is_risky_refactoring(self, renamed_files: list[tuple[str, str]]) -> bool:
40
+ """
41
+ Detect large-scale refactoring.
42
+
43
+ SPEC requirement: renaming 10 or more files counts as risky.
44
+
45
+ Args:
46
+ renamed_files: List of (old_name, new_name) pairs.
47
+
48
+ Returns:
49
+ True when 10 or more files are renamed, otherwise False.
50
+ """
51
+ return len(renamed_files) >= 10
52
+
53
+ def is_critical_file(self, file_path: Path) -> bool:
54
+ """
55
+ Determine whether the file is critical.
56
+
57
+ SPEC requirement: modifying CLAUDE.md, config.json, or .moai/memory/*.md is risky.
58
+
59
+ Args:
60
+ file_path: File path to inspect.
61
+
62
+ Returns:
63
+ True when the file is critical, otherwise False.
64
+ """
65
+ # Check whether the file name is in the critical list
66
+ if file_path.name in self.CRITICAL_FILES:
67
+ return True
68
+
69
+ # Convert to string for further checks
70
+ path_str = str(file_path)
71
+
72
+ # Detect .moai/config.json paths
73
+ if ".moai/config.json" in path_str or ".moai\\config.json" in path_str:
74
+ return True
75
+
76
+ # Detect files inside the .moai/memory/ directory
77
+ for critical_dir in self.CRITICAL_DIRS:
78
+ if critical_dir in path_str or critical_dir.replace("/", "\\") in path_str:
79
+ return True
80
+
81
+ return False
@@ -0,0 +1,127 @@
1
+ # @CODE:CORE-GIT-001 | SPEC: SPEC-CORE-GIT-001.md | TEST: tests/unit/test_git.py
2
+ """
3
+ Git repository management built on GitPython.
4
+
5
+ SPEC: .moai/specs/SPEC-CORE-GIT-001/spec.md
6
+ """
7
+
8
+ from git import InvalidGitRepositoryError, Repo
9
+
10
+
11
+ class GitManager:
12
+ """Manage interactions with a Git repository."""
13
+
14
+ def __init__(self, repo_path: str = "."):
15
+ """
16
+ Initialize the GitManager.
17
+
18
+ Args:
19
+ repo_path: Path to the Git repository (default: current directory)
20
+
21
+ Raises:
22
+ InvalidGitRepositoryError: Raised when the path is not a Git repository.
23
+ """
24
+ self.repo = Repo(repo_path)
25
+ self.git = self.repo.git
26
+
27
+ def is_repo(self) -> bool:
28
+ """
29
+ Check whether the path points to a Git repository.
30
+
31
+ Returns:
32
+ True when the location is a Git repository, otherwise False.
33
+
34
+ Examples:
35
+ >>> manager = GitManager("/path/to/repo")
36
+ >>> manager.is_repo()
37
+ True
38
+ """
39
+ try:
40
+ _ = self.repo.git_dir
41
+ return True
42
+ except (InvalidGitRepositoryError, Exception):
43
+ return False
44
+
45
+ def current_branch(self) -> str:
46
+ """
47
+ Return the active branch name.
48
+
49
+ Returns:
50
+ Name of the currently checked-out branch.
51
+
52
+ Examples:
53
+ >>> manager = GitManager()
54
+ >>> manager.current_branch()
55
+ 'main'
56
+ """
57
+ return self.repo.active_branch.name
58
+
59
+ def is_dirty(self) -> bool:
60
+ """
61
+ Check whether the working tree has uncommitted changes.
62
+
63
+ Returns:
64
+ True when the worktree is dirty, otherwise False.
65
+
66
+ Examples:
67
+ >>> manager = GitManager()
68
+ >>> manager.is_dirty()
69
+ False
70
+ """
71
+ return self.repo.is_dirty()
72
+
73
+ def create_branch(self, branch_name: str, from_branch: str | None = None) -> None:
74
+ """
75
+ Create and switch to a new branch.
76
+
77
+ Args:
78
+ branch_name: Name of the branch to create.
79
+ from_branch: Base branch (default: current branch).
80
+
81
+ Examples:
82
+ >>> manager = GitManager()
83
+ >>> manager.create_branch("feature/SPEC-AUTH-001")
84
+ >>> manager.current_branch()
85
+ 'feature/SPEC-AUTH-001'
86
+ """
87
+ if from_branch:
88
+ self.git.checkout("-b", branch_name, from_branch)
89
+ else:
90
+ self.git.checkout("-b", branch_name)
91
+
92
+ def commit(self, message: str, files: list[str] | None = None) -> None:
93
+ """
94
+ Stage files and create a commit.
95
+
96
+ Args:
97
+ message: Commit message.
98
+ files: Optional list of files to commit (default: all changes).
99
+
100
+ Examples:
101
+ >>> manager = GitManager()
102
+ >>> manager.commit("feat: add authentication", files=["auth.py"])
103
+ """
104
+ if files:
105
+ self.repo.index.add(files)
106
+ else:
107
+ self.git.add(A=True)
108
+
109
+ self.repo.index.commit(message)
110
+
111
+ def push(self, branch: str | None = None, set_upstream: bool = False) -> None:
112
+ """
113
+ Push commits to the remote repository.
114
+
115
+ Args:
116
+ branch: Branch to push (default: current branch).
117
+ set_upstream: Whether to set the upstream tracking branch.
118
+
119
+ Examples:
120
+ >>> manager = GitManager()
121
+ >>> manager.push(set_upstream=True)
122
+ """
123
+ if set_upstream:
124
+ target_branch = branch or self.current_branch()
125
+ self.git.push("--set-upstream", "origin", target_branch)
126
+ else:
127
+ self.git.push()
@@ -0,0 +1,2 @@
1
+ # @CODE:PY314-001 | SPEC: SPEC-PY314-001.md | TEST: tests/unit/test_foundation.py
2
+ """Project module: initialization and management"""
@@ -0,0 +1,84 @@
1
+ # @CODE:INIT-003:BACKUP | SPEC: .moai/specs/SPEC-INIT-003/spec.md | TEST: tests/unit/test_backup_utils.py
2
+ """Backup utility module (SPEC-INIT-003 v0.3.0)
3
+
4
+ Selective backup strategy:
5
+ - Back up only the required files (OR condition)
6
+ - Backup path: .moai-backups/{timestamp}/ (v0.3.0)
7
+ """
8
+
9
+ from datetime import datetime
10
+ from pathlib import Path
11
+
12
+ # Backup targets (OR condition - back up when any exist)
13
+ BACKUP_TARGETS = [
14
+ ".moai/config.json",
15
+ ".moai/project/",
16
+ ".moai/memory/",
17
+ ".claude/",
18
+ "CLAUDE.md",
19
+ ]
20
+
21
+ # User data protection paths (excluded from backups)
22
+ PROTECTED_PATHS = [
23
+ ".moai/specs/",
24
+ ".moai/reports/",
25
+ ]
26
+
27
+
28
+ def has_any_moai_files(project_path: Path) -> bool:
29
+ """Check whether any MoAI-ADK files exist (OR condition).
30
+
31
+ Args:
32
+ project_path: Project path.
33
+
34
+ Returns:
35
+ True when any backup target exists.
36
+ """
37
+ for target in BACKUP_TARGETS:
38
+ target_path = project_path / target
39
+ if target_path.exists():
40
+ return True
41
+ return False
42
+
43
+
44
+ def get_backup_targets(project_path: Path) -> list[str]:
45
+ """Return existing backup targets.
46
+
47
+ Args:
48
+ project_path: Project path.
49
+
50
+ Returns:
51
+ List of backup targets that exist.
52
+ """
53
+ targets: list[str] = []
54
+ for target in BACKUP_TARGETS:
55
+ target_path = project_path / target
56
+ if target_path.exists():
57
+ targets.append(target)
58
+ return targets
59
+
60
+
61
+ def generate_backup_dir_name() -> str:
62
+ """Generate a timestamp-based backup directory name (v0.3.0).
63
+
64
+ Returns:
65
+ Timestamp formatted as YYYYMMDD-HHMMSS.
66
+ Note: callers use .moai-backups/{timestamp}/ format.
67
+ """
68
+ timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
69
+ return timestamp
70
+
71
+
72
+ def is_protected_path(rel_path: Path) -> bool:
73
+ """Check whether the path is protected.
74
+
75
+ Args:
76
+ rel_path: Relative path.
77
+
78
+ Returns:
79
+ True when the path should be excluded from backups.
80
+ """
81
+ rel_str = str(rel_path).replace("\\", "/")
82
+ return any(
83
+ rel_str.startswith(p.lstrip("./").rstrip("/")) for p in PROTECTED_PATHS
84
+ )