moai-adk 0.3.0__tar.gz
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-0.3.0/.gitignore +60 -0
- moai_adk-0.3.0/LICENSE +21 -0
- moai_adk-0.3.0/PKG-INFO +20 -0
- moai_adk-0.3.0/pyproject.toml +73 -0
- moai_adk-0.3.0/src/moai_adk/__init__.py +8 -0
- moai_adk-0.3.0/src/moai_adk/__main__.py +86 -0
- moai_adk-0.3.0/src/moai_adk/cli/__init__.py +2 -0
- moai_adk-0.3.0/src/moai_adk/cli/commands/__init__.py +16 -0
- moai_adk-0.3.0/src/moai_adk/cli/commands/backup.py +56 -0
- moai_adk-0.3.0/src/moai_adk/cli/commands/doctor.py +184 -0
- moai_adk-0.3.0/src/moai_adk/cli/commands/init.py +284 -0
- moai_adk-0.3.0/src/moai_adk/cli/commands/restore.py +77 -0
- moai_adk-0.3.0/src/moai_adk/cli/commands/status.py +79 -0
- moai_adk-0.3.0/src/moai_adk/cli/commands/update.py +133 -0
- moai_adk-0.3.0/src/moai_adk/cli/main.py +12 -0
- moai_adk-0.3.0/src/moai_adk/cli/prompts/__init__.py +5 -0
- moai_adk-0.3.0/src/moai_adk/cli/prompts/init_prompts.py +159 -0
- moai_adk-0.3.0/src/moai_adk/core/__init__.py +2 -0
- moai_adk-0.3.0/src/moai_adk/core/git/__init__.py +24 -0
- moai_adk-0.3.0/src/moai_adk/core/git/branch.py +26 -0
- moai_adk-0.3.0/src/moai_adk/core/git/branch_manager.py +137 -0
- moai_adk-0.3.0/src/moai_adk/core/git/checkpoint.py +140 -0
- moai_adk-0.3.0/src/moai_adk/core/git/commit.py +68 -0
- moai_adk-0.3.0/src/moai_adk/core/git/event_detector.py +81 -0
- moai_adk-0.3.0/src/moai_adk/core/git/manager.py +127 -0
- moai_adk-0.3.0/src/moai_adk/core/project/__init__.py +2 -0
- moai_adk-0.3.0/src/moai_adk/core/project/backup_utils.py +84 -0
- moai_adk-0.3.0/src/moai_adk/core/project/checker.py +302 -0
- moai_adk-0.3.0/src/moai_adk/core/project/detector.py +105 -0
- moai_adk-0.3.0/src/moai_adk/core/project/initializer.py +174 -0
- moai_adk-0.3.0/src/moai_adk/core/project/phase_executor.py +297 -0
- moai_adk-0.3.0/src/moai_adk/core/project/validator.py +118 -0
- moai_adk-0.3.0/src/moai_adk/core/quality/__init__.py +6 -0
- moai_adk-0.3.0/src/moai_adk/core/quality/trust_checker.py +441 -0
- moai_adk-0.3.0/src/moai_adk/core/quality/validators/__init__.py +6 -0
- moai_adk-0.3.0/src/moai_adk/core/quality/validators/base_validator.py +19 -0
- moai_adk-0.3.0/src/moai_adk/core/template/__init__.py +8 -0
- moai_adk-0.3.0/src/moai_adk/core/template/backup.py +95 -0
- moai_adk-0.3.0/src/moai_adk/core/template/config.py +95 -0
- moai_adk-0.3.0/src/moai_adk/core/template/languages.py +44 -0
- moai_adk-0.3.0/src/moai_adk/core/template/merger.py +117 -0
- moai_adk-0.3.0/src/moai_adk/core/template/processor.py +310 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/agents/alfred/cc-manager.md +474 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/agents/alfred/code-builder.md +534 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/agents/alfred/debug-helper.md +302 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/agents/alfred/doc-syncer.md +175 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/agents/alfred/git-manager.md +200 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/agents/alfred/project-manager.md +152 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/agents/alfred/spec-builder.md +256 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/agents/alfred/tag-agent.md +247 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/agents/alfred/trust-checker.md +332 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/commands/alfred/0-project.md +523 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/commands/alfred/1-spec.md +531 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/commands/alfred/2-build.md +413 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/commands/alfred/3-sync.md +552 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/hooks/alfred/README.md +238 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/hooks/alfred/alfred_hooks.py +165 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/hooks/alfred/core/__init__.py +79 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/hooks/alfred/core/checkpoint.py +271 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/hooks/alfred/core/context.py +110 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/hooks/alfred/core/project.py +284 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/hooks/alfred/core/tags.py +244 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/hooks/alfred/handlers/__init__.py +23 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/hooks/alfred/handlers/compact.py +51 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/hooks/alfred/handlers/notification.py +25 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/hooks/alfred/handlers/session.py +80 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/hooks/alfred/handlers/tool.py +71 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/hooks/alfred/handlers/user.py +41 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/output-styles/alfred/agentic-coding.md +635 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/output-styles/alfred/moai-adk-learning.md +691 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/output-styles/alfred/study-with-alfred.md +469 -0
- moai_adk-0.3.0/src/moai_adk/templates/.claude/settings.json +135 -0
- moai_adk-0.3.0/src/moai_adk/templates/.github/PULL_REQUEST_TEMPLATE.md +68 -0
- moai_adk-0.3.0/src/moai_adk/templates/.github/workflows/moai-gitflow.yml +255 -0
- moai_adk-0.3.0/src/moai_adk/templates/.gitignore +41 -0
- moai_adk-0.3.0/src/moai_adk/templates/.moai/config.json +89 -0
- moai_adk-0.3.0/src/moai_adk/templates/.moai/memory/development-guide.md +367 -0
- moai_adk-0.3.0/src/moai_adk/templates/.moai/memory/spec-metadata.md +277 -0
- moai_adk-0.3.0/src/moai_adk/templates/.moai/project/product.md +121 -0
- moai_adk-0.3.0/src/moai_adk/templates/.moai/project/structure.md +150 -0
- moai_adk-0.3.0/src/moai_adk/templates/.moai/project/tech.md +221 -0
- moai_adk-0.3.0/src/moai_adk/templates/CLAUDE.md +733 -0
- moai_adk-0.3.0/src/moai_adk/templates/__init__.py +2 -0
- moai_adk-0.3.0/src/moai_adk/utils/__init__.py +8 -0
- moai_adk-0.3.0/src/moai_adk/utils/banner.py +42 -0
- moai_adk-0.3.0/src/moai_adk/utils/logger.py +152 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Build artifacts
|
|
2
|
+
build/
|
|
3
|
+
dist/
|
|
4
|
+
*.egg-info/
|
|
5
|
+
*.egg
|
|
6
|
+
|
|
7
|
+
# Cache
|
|
8
|
+
__pycache__/
|
|
9
|
+
.pytest_cache/
|
|
10
|
+
*.pyc
|
|
11
|
+
*.pyo
|
|
12
|
+
node_modules/
|
|
13
|
+
*.tsbuildinfo
|
|
14
|
+
.tscache/
|
|
15
|
+
|
|
16
|
+
# Backups
|
|
17
|
+
.moai-backups/
|
|
18
|
+
*.backup
|
|
19
|
+
*.bak
|
|
20
|
+
|
|
21
|
+
# Test coverage
|
|
22
|
+
.coverage
|
|
23
|
+
.coverage.*
|
|
24
|
+
coverage.json
|
|
25
|
+
htmlcov/
|
|
26
|
+
.pytest_cache/
|
|
27
|
+
|
|
28
|
+
# Documentation builds
|
|
29
|
+
site/
|
|
30
|
+
docs/_build/
|
|
31
|
+
|
|
32
|
+
# Reports (keep .gitkeep)
|
|
33
|
+
.moai/reports/*.md
|
|
34
|
+
.moai/reports/*.json
|
|
35
|
+
.moai/reports/*.html
|
|
36
|
+
|
|
37
|
+
# Virtual environment
|
|
38
|
+
venv/
|
|
39
|
+
.venv/
|
|
40
|
+
env/
|
|
41
|
+
.env/
|
|
42
|
+
|
|
43
|
+
# IDE
|
|
44
|
+
.vscode/
|
|
45
|
+
.idea/
|
|
46
|
+
*.swp
|
|
47
|
+
*.swo
|
|
48
|
+
*~
|
|
49
|
+
|
|
50
|
+
# OS
|
|
51
|
+
.DS_Store
|
|
52
|
+
Thumbs.db
|
|
53
|
+
|
|
54
|
+
# Logs
|
|
55
|
+
*.log
|
|
56
|
+
logs/
|
|
57
|
+
|
|
58
|
+
# Temporary files
|
|
59
|
+
*.tmp
|
|
60
|
+
*.temp
|
moai_adk-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 MoAI-ADK Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
moai_adk-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: moai-adk
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: MoAI Agentic Development Kit - SPEC-First TDD with Alfred SuperAgent
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Requires-Python: >=3.13
|
|
7
|
+
Requires-Dist: click>=8.1.0
|
|
8
|
+
Requires-Dist: gitpython>=3.1.45
|
|
9
|
+
Requires-Dist: pyfiglet>=1.0.2
|
|
10
|
+
Requires-Dist: questionary>=2.0.0
|
|
11
|
+
Requires-Dist: rich>=13.0.0
|
|
12
|
+
Provides-Extra: dev
|
|
13
|
+
Requires-Dist: mypy>=1.7.0; extra == 'dev'
|
|
14
|
+
Requires-Dist: pytest-cov>=7.0.0; extra == 'dev'
|
|
15
|
+
Requires-Dist: pytest-xdist>=3.8.0; extra == 'dev'
|
|
16
|
+
Requires-Dist: pytest>=8.4.2; extra == 'dev'
|
|
17
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
18
|
+
Provides-Extra: security
|
|
19
|
+
Requires-Dist: bandit>=1.8.0; extra == 'security'
|
|
20
|
+
Requires-Dist: pip-audit>=2.7.0; extra == 'security'
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "moai-adk"
|
|
3
|
+
version = "0.3.0"
|
|
4
|
+
description = "MoAI Agentic Development Kit - SPEC-First TDD with Alfred SuperAgent"
|
|
5
|
+
requires-python = ">=3.13"
|
|
6
|
+
dependencies = [
|
|
7
|
+
"click>=8.1.0",
|
|
8
|
+
"rich>=13.0.0",
|
|
9
|
+
"pyfiglet>=1.0.2",
|
|
10
|
+
"questionary>=2.0.0",
|
|
11
|
+
"gitpython>=3.1.45"
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[project.optional-dependencies]
|
|
15
|
+
dev = [
|
|
16
|
+
"pytest>=8.4.2",
|
|
17
|
+
"pytest-cov>=7.0.0",
|
|
18
|
+
"pytest-xdist>=3.8.0",
|
|
19
|
+
"ruff>=0.1.0",
|
|
20
|
+
"mypy>=1.7.0"
|
|
21
|
+
]
|
|
22
|
+
security = [
|
|
23
|
+
"pip-audit>=2.7.0",
|
|
24
|
+
"bandit>=1.8.0"
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[tool.pytest.ini_options]
|
|
28
|
+
testpaths = ["tests"]
|
|
29
|
+
python_files = "test_*.py"
|
|
30
|
+
python_classes = "Test*"
|
|
31
|
+
python_functions = "test_*"
|
|
32
|
+
addopts = "-v --cov=src/moai_adk --cov-report=html --cov-report=term-missing"
|
|
33
|
+
|
|
34
|
+
[tool.coverage.run]
|
|
35
|
+
source = ["src/moai_adk"]
|
|
36
|
+
omit = ["tests/*", "*/__pycache__/*"]
|
|
37
|
+
parallel = true
|
|
38
|
+
concurrency = ["multiprocessing"]
|
|
39
|
+
|
|
40
|
+
[tool.coverage.report]
|
|
41
|
+
precision = 2
|
|
42
|
+
show_missing = true
|
|
43
|
+
skip_covered = false
|
|
44
|
+
fail_under = 85
|
|
45
|
+
|
|
46
|
+
[tool.ruff]
|
|
47
|
+
line-length = 120
|
|
48
|
+
target-version = "py313"
|
|
49
|
+
|
|
50
|
+
[tool.ruff.lint]
|
|
51
|
+
select = ["E", "F", "W", "I", "N"]
|
|
52
|
+
ignore = []
|
|
53
|
+
|
|
54
|
+
[build-system]
|
|
55
|
+
requires = ["hatchling"]
|
|
56
|
+
build-backend = "hatchling.build"
|
|
57
|
+
|
|
58
|
+
[tool.hatch.build.targets.wheel]
|
|
59
|
+
# Include Python packages and templates
|
|
60
|
+
packages = ["src/moai_adk"]
|
|
61
|
+
|
|
62
|
+
# Ensure template files are included in both wheel and editable installs
|
|
63
|
+
[tool.hatch.build]
|
|
64
|
+
include = [
|
|
65
|
+
"src/moai_adk/**/*.py",
|
|
66
|
+
"src/moai_adk/templates/**/*",
|
|
67
|
+
"src/moai_adk/templates/.claude/**/*",
|
|
68
|
+
"src/moai_adk/templates/.moai/**/*",
|
|
69
|
+
"src/moai_adk/templates/.github/**/*"
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
[project.scripts]
|
|
73
|
+
moai-adk = "moai_adk.__main__:main"
|
|
@@ -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,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]")
|