devforgeai 1.0.4 → 1.0.6
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.
- package/CLAUDE.md +120 -0
- package/package.json +9 -1
- package/src/CLAUDE.md +699 -0
- package/src/claude/scripts/README.md +396 -0
- package/src/claude/scripts/audit-command-skill-overlap.sh +67 -0
- package/src/claude/scripts/check-hooks-fast.sh +70 -0
- package/src/claude/scripts/devforgeai-validate +6 -0
- package/src/claude/scripts/devforgeai_cli/README.md +531 -0
- package/src/claude/scripts/devforgeai_cli/__init__.py +12 -0
- package/src/claude/scripts/devforgeai_cli/cli.py +716 -0
- package/src/claude/scripts/devforgeai_cli/commands/__init__.py +1 -0
- package/src/claude/scripts/devforgeai_cli/commands/check_hooks.py +384 -0
- package/src/claude/scripts/devforgeai_cli/commands/invoke_hooks.py +149 -0
- package/src/claude/scripts/devforgeai_cli/commands/phase_commands.py +731 -0
- package/src/claude/scripts/devforgeai_cli/commands/validate_installation.py +412 -0
- package/src/claude/scripts/devforgeai_cli/context_extraction.py +426 -0
- package/src/claude/scripts/devforgeai_cli/feedback/AC_TO_TEST_MAPPING.md +636 -0
- package/src/claude/scripts/devforgeai_cli/feedback/DELIVERY_SUMMARY.txt +329 -0
- package/src/claude/scripts/devforgeai_cli/feedback/README_TEST_SPECS.md +486 -0
- package/src/claude/scripts/devforgeai_cli/feedback/TEST_IMPLEMENTATION_GUIDE.md +529 -0
- package/src/claude/scripts/devforgeai_cli/feedback/TEST_SPECIFICATIONS.md +2652 -0
- package/src/claude/scripts/devforgeai_cli/feedback/TEST_SPECS_INDEX.md +398 -0
- package/src/claude/scripts/devforgeai_cli/feedback/__init__.py +34 -0
- package/src/claude/scripts/devforgeai_cli/feedback/adaptive_questioning_engine.py +581 -0
- package/src/claude/scripts/devforgeai_cli/feedback/aggregation.py +179 -0
- package/src/claude/scripts/devforgeai_cli/feedback/commands.py +535 -0
- package/src/claude/scripts/devforgeai_cli/feedback/config_defaults.py +58 -0
- package/src/claude/scripts/devforgeai_cli/feedback/config_manager.py +423 -0
- package/src/claude/scripts/devforgeai_cli/feedback/config_models.py +192 -0
- package/src/claude/scripts/devforgeai_cli/feedback/config_schema.py +140 -0
- package/src/claude/scripts/devforgeai_cli/feedback/coverage.json +1 -0
- package/src/claude/scripts/devforgeai_cli/feedback/feature_flag.py +152 -0
- package/src/claude/scripts/devforgeai_cli/feedback/feedback_indexer.py +394 -0
- package/src/claude/scripts/devforgeai_cli/feedback/hot_reload.py +226 -0
- package/src/claude/scripts/devforgeai_cli/feedback/longitudinal.py +115 -0
- package/src/claude/scripts/devforgeai_cli/feedback/models.py +67 -0
- package/src/claude/scripts/devforgeai_cli/feedback/question_router.py +236 -0
- package/src/claude/scripts/devforgeai_cli/feedback/retrospective.py +233 -0
- package/src/claude/scripts/devforgeai_cli/feedback/skip_tracker.py +177 -0
- package/src/claude/scripts/devforgeai_cli/feedback/skip_tracking.py +221 -0
- package/src/claude/scripts/devforgeai_cli/feedback/template_engine.py +549 -0
- package/src/claude/scripts/devforgeai_cli/feedback/validation.py +163 -0
- package/src/claude/scripts/devforgeai_cli/headless/__init__.py +30 -0
- package/src/claude/scripts/devforgeai_cli/headless/answer_models.py +206 -0
- package/src/claude/scripts/devforgeai_cli/headless/answer_resolver.py +204 -0
- package/src/claude/scripts/devforgeai_cli/headless/exceptions.py +36 -0
- package/src/claude/scripts/devforgeai_cli/headless/pattern_matcher.py +156 -0
- package/src/claude/scripts/devforgeai_cli/hooks.py +313 -0
- package/src/claude/scripts/devforgeai_cli/metrics/__init__.py +46 -0
- package/src/claude/scripts/devforgeai_cli/metrics/command_metrics.py +142 -0
- package/src/claude/scripts/devforgeai_cli/metrics/failure_modes.py +152 -0
- package/src/claude/scripts/devforgeai_cli/metrics/story_segmentation.py +181 -0
- package/src/claude/scripts/devforgeai_cli/orchestrate_hooks.py +780 -0
- package/src/claude/scripts/devforgeai_cli/phase_state.py +1229 -0
- package/src/claude/scripts/devforgeai_cli/session/__init__.py +30 -0
- package/src/claude/scripts/devforgeai_cli/session/checkpoint.py +268 -0
- package/src/claude/scripts/devforgeai_cli/tests/__init__.py +1 -0
- package/src/claude/scripts/devforgeai_cli/tests/conftest.py +29 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/TEST_EXECUTION_GUIDE.md +298 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/__init__.py +3 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_adaptive_questioning_engine.py +2171 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_aggregation.py +476 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_config_defaults.py +133 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_config_manager.py +592 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_config_models.py +373 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_config_schema.py +130 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_configuration_management.py +1355 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_edge_cases.py +308 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_feature_flag.py +307 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_feedback_indexer.py +384 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_hot_reload.py +580 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_integration.py +402 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_models.py +105 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_question_routing.py +262 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_retrospective.py +333 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_skip_tracker.py +410 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_skip_tracking.py +159 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_skip_tracking_integration.py +1155 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_template_engine.py +1389 -0
- package/src/claude/scripts/devforgeai_cli/tests/feedback/test_validation_comprehensive.py +210 -0
- package/src/claude/scripts/devforgeai_cli/tests/fixtures/autonomous-deferral-story.md +46 -0
- package/src/claude/scripts/devforgeai_cli/tests/fixtures/missing-impl-notes.md +31 -0
- package/src/claude/scripts/devforgeai_cli/tests/fixtures/valid-deferral-story.md +46 -0
- package/src/claude/scripts/devforgeai_cli/tests/fixtures/valid-story-complete.md +48 -0
- package/src/claude/scripts/devforgeai_cli/tests/manual_test_invoke_hooks.sh +200 -0
- package/src/claude/scripts/devforgeai_cli/tests/session/DELIVERABLES.md +518 -0
- package/src/claude/scripts/devforgeai_cli/tests/session/TEST_SUMMARY.md +468 -0
- package/src/claude/scripts/devforgeai_cli/tests/session/__init__.py +6 -0
- package/src/claude/scripts/devforgeai_cli/tests/session/fixtures/corrupted-checkpoint.json +1 -0
- package/src/claude/scripts/devforgeai_cli/tests/session/fixtures/missing-fields-checkpoint.json +4 -0
- package/src/claude/scripts/devforgeai_cli/tests/session/fixtures/valid-checkpoint.json +15 -0
- package/src/claude/scripts/devforgeai_cli/tests/session/test_checkpoint.py +851 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_check_hooks.py +1886 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_depends_on_normalizer.py +171 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_dod_validator.py +97 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_invoke_hooks.py +1902 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_phase_commands.py +320 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_phase_commands_error_handling.py +1021 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_phase_commands_import.py +697 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_phase_state.py +2187 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_skip_tracking.py +2141 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_skip_tracking_coverage_gap.py +195 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_subagent_enforcement.py +539 -0
- package/src/claude/scripts/devforgeai_cli/tests/test_validate_installation.py +361 -0
- package/src/claude/scripts/devforgeai_cli/utils/__init__.py +11 -0
- package/src/claude/scripts/devforgeai_cli/utils/depends_on_normalizer.py +149 -0
- package/src/claude/scripts/devforgeai_cli/utils/markdown_parser.py +219 -0
- package/src/claude/scripts/devforgeai_cli/utils/story_analyzer.py +249 -0
- package/src/claude/scripts/devforgeai_cli/utils/yaml_parser.py +152 -0
- package/src/claude/scripts/devforgeai_cli/validators/__init__.py +27 -0
- package/src/claude/scripts/devforgeai_cli/validators/ast_grep_validator.py +373 -0
- package/src/claude/scripts/devforgeai_cli/validators/context_validator.py +180 -0
- package/src/claude/scripts/devforgeai_cli/validators/dod_validator.py +309 -0
- package/src/claude/scripts/devforgeai_cli/validators/git_validator.py +107 -0
- package/src/claude/scripts/devforgeai_cli/validators/grep_fallback.py +300 -0
- package/src/claude/scripts/install_hooks.sh +186 -0
- package/src/claude/scripts/invoke_feedback_hooks.sh +59 -0
- package/src/claude/scripts/migrate-ac-headers.sh +122 -0
- package/src/claude/scripts/plan_file_kb.sh +704 -0
- package/src/claude/scripts/requirements.txt +8 -0
- package/src/claude/scripts/session_catalog.sh +543 -0
- package/src/claude/scripts/setup.py +55 -0
- package/src/claude/scripts/start-devforgeai.sh +16 -0
- package/src/claude/scripts/statusline.sh +27 -0
- package/src/claude/scripts/validate_deferrals.py +344 -0
- package/src/claude/skills/devforgeai-qa/SKILL.md +1 -1
- package/src/claude/skills/researching-market/SKILL.md +2 -1
- package/src/cli/lib/copier.js +13 -1
- package/src/claude/skills/designing-systems/scripts/__pycache__/detect_anti_patterns.cpython-312.pyc +0 -0
- package/src/claude/skills/designing-systems/scripts/__pycache__/validate_all_context.cpython-312.pyc +0 -0
- package/src/claude/skills/designing-systems/scripts/__pycache__/validate_architecture.cpython-312.pyc +0 -0
- package/src/claude/skills/designing-systems/scripts/__pycache__/validate_dependencies.cpython-312.pyc +0 -0
- package/src/claude/skills/devforgeai-story-creation/scripts/__pycache__/migrate_story_v1_to_v2.cpython-312.pyc +0 -0
- package/src/claude/skills/devforgeai-story-creation/scripts/tests/__pycache__/measure_accuracy.cpython-312.pyc +0 -0
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Validate Installation Command for DevForgeAI CLI.
|
|
4
|
+
|
|
5
|
+
STORY-314: Add Post-Install Validation Command
|
|
6
|
+
|
|
7
|
+
Provides comprehensive post-installation validation that checks:
|
|
8
|
+
1. CLI availability (devforgeai-validate --version)
|
|
9
|
+
2. Context files (6 files in devforgeai/specs/context/)
|
|
10
|
+
3. Hook installation (.git/hooks/pre-commit exists)
|
|
11
|
+
4. PYTHONPATH configuration
|
|
12
|
+
5. Git repository (.git/ exists)
|
|
13
|
+
6. Settings file (.claude/settings.json exists)
|
|
14
|
+
|
|
15
|
+
Each check returns a ValidationResult with pass/fail status,
|
|
16
|
+
descriptive message, and actionable fix instruction for failures.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import subprocess
|
|
20
|
+
import sys
|
|
21
|
+
from dataclasses import dataclass, field
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from typing import List, Optional
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# =============================================================================
|
|
27
|
+
# Constants
|
|
28
|
+
# =============================================================================
|
|
29
|
+
|
|
30
|
+
# The 6 required context files
|
|
31
|
+
REQUIRED_CONTEXT_FILES = [
|
|
32
|
+
'tech-stack.md',
|
|
33
|
+
'source-tree.md',
|
|
34
|
+
'dependencies.md',
|
|
35
|
+
'coding-standards.md',
|
|
36
|
+
'architecture-constraints.md',
|
|
37
|
+
'anti-patterns.md'
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# =============================================================================
|
|
42
|
+
# Data Classes
|
|
43
|
+
# =============================================================================
|
|
44
|
+
|
|
45
|
+
@dataclass
|
|
46
|
+
class ValidationResult:
|
|
47
|
+
"""Result of a single validation check."""
|
|
48
|
+
passed: bool
|
|
49
|
+
message: str
|
|
50
|
+
fix_instruction: str = ""
|
|
51
|
+
|
|
52
|
+
def __post_init__(self):
|
|
53
|
+
"""Ensure fix_instruction has proper format for failures."""
|
|
54
|
+
if not self.passed and self.fix_instruction and not self.fix_instruction.startswith("To fix:"):
|
|
55
|
+
self.fix_instruction = f"To fix: {self.fix_instruction}"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass
|
|
59
|
+
class InstallationValidationResult:
|
|
60
|
+
"""Result of complete installation validation."""
|
|
61
|
+
success: bool
|
|
62
|
+
passed_count: int
|
|
63
|
+
failed_count: int
|
|
64
|
+
checks: List[ValidationResult] = field(default_factory=list)
|
|
65
|
+
exit_code: int = 0
|
|
66
|
+
summary: str = ""
|
|
67
|
+
|
|
68
|
+
def __post_init__(self):
|
|
69
|
+
"""Generate summary and exit code from results."""
|
|
70
|
+
if not self.summary:
|
|
71
|
+
if self.success:
|
|
72
|
+
self.summary = f"PASS ({self.passed_count}/{self.passed_count + self.failed_count} checks passed)"
|
|
73
|
+
else:
|
|
74
|
+
self.summary = f"FAIL ({self.passed_count}/{self.passed_count + self.failed_count} checks passed)"
|
|
75
|
+
|
|
76
|
+
if self.exit_code == 0 and not self.success:
|
|
77
|
+
self.exit_code = 1
|
|
78
|
+
|
|
79
|
+
def format_output(self) -> str:
|
|
80
|
+
"""Format validation results for display."""
|
|
81
|
+
lines = []
|
|
82
|
+
lines.append("DevForgeAI Installation Validation")
|
|
83
|
+
lines.append("=" * 38)
|
|
84
|
+
lines.append("")
|
|
85
|
+
|
|
86
|
+
for check in self.checks:
|
|
87
|
+
marker = "[✓]" if check.passed else "[✗]"
|
|
88
|
+
lines.append(f"{marker} {check.message}")
|
|
89
|
+
if not check.passed and check.fix_instruction:
|
|
90
|
+
lines.append(f" {check.fix_instruction}")
|
|
91
|
+
|
|
92
|
+
lines.append("")
|
|
93
|
+
lines.append(f"Result: {self.summary}")
|
|
94
|
+
|
|
95
|
+
return "\n".join(lines)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
# =============================================================================
|
|
99
|
+
# Individual Check Functions
|
|
100
|
+
# =============================================================================
|
|
101
|
+
|
|
102
|
+
def check_cli_available() -> ValidationResult:
|
|
103
|
+
"""
|
|
104
|
+
Check 1: Verify devforgeai-validate CLI is installed and working.
|
|
105
|
+
|
|
106
|
+
Runs: devforgeai-validate --version
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
ValidationResult with pass/fail and version info or fix instruction.
|
|
110
|
+
"""
|
|
111
|
+
try:
|
|
112
|
+
result = subprocess.run(
|
|
113
|
+
["devforgeai-validate", "--version"],
|
|
114
|
+
capture_output=True,
|
|
115
|
+
text=True,
|
|
116
|
+
timeout=10
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
if result.returncode == 0:
|
|
120
|
+
version_output = result.stdout.strip()
|
|
121
|
+
return ValidationResult(
|
|
122
|
+
passed=True,
|
|
123
|
+
message=f"CLI available: {version_output}"
|
|
124
|
+
)
|
|
125
|
+
else:
|
|
126
|
+
return ValidationResult(
|
|
127
|
+
passed=False,
|
|
128
|
+
message="CLI not installed",
|
|
129
|
+
fix_instruction="To fix: pip install -e .claude/scripts/"
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
except FileNotFoundError:
|
|
133
|
+
return ValidationResult(
|
|
134
|
+
passed=False,
|
|
135
|
+
message="CLI not installed",
|
|
136
|
+
fix_instruction="To fix: pip install -e .claude/scripts/"
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
except subprocess.TimeoutExpired:
|
|
140
|
+
return ValidationResult(
|
|
141
|
+
passed=False,
|
|
142
|
+
message="CLI command timed out",
|
|
143
|
+
fix_instruction="To fix: Check for hanging processes and reinstall: pip install -e .claude/scripts/"
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
except Exception as e:
|
|
147
|
+
return ValidationResult(
|
|
148
|
+
passed=False,
|
|
149
|
+
message=f"CLI check error: {e}",
|
|
150
|
+
fix_instruction="To fix: pip install -e .claude/scripts/"
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def check_context_files(project_root: str) -> ValidationResult:
|
|
155
|
+
"""
|
|
156
|
+
Check 2: Verify all 6 context files exist.
|
|
157
|
+
|
|
158
|
+
Checks: devforgeai/specs/context/{tech-stack,source-tree,...}.md
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
project_root: Path to project root directory.
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
ValidationResult with count of present files and missing list.
|
|
165
|
+
"""
|
|
166
|
+
root_path = Path(project_root)
|
|
167
|
+
context_dir = root_path / "devforgeai" / "specs" / "context"
|
|
168
|
+
|
|
169
|
+
present_files = []
|
|
170
|
+
missing_files = []
|
|
171
|
+
|
|
172
|
+
for filename in REQUIRED_CONTEXT_FILES:
|
|
173
|
+
file_path = context_dir / filename
|
|
174
|
+
if file_path.exists():
|
|
175
|
+
present_files.append(filename)
|
|
176
|
+
else:
|
|
177
|
+
missing_files.append(filename)
|
|
178
|
+
|
|
179
|
+
present_count = len(present_files)
|
|
180
|
+
total_count = len(REQUIRED_CONTEXT_FILES)
|
|
181
|
+
|
|
182
|
+
if present_count == total_count:
|
|
183
|
+
return ValidationResult(
|
|
184
|
+
passed=True,
|
|
185
|
+
message=f"Context files: {present_count}/{total_count} present"
|
|
186
|
+
)
|
|
187
|
+
else:
|
|
188
|
+
missing_str = ", ".join(missing_files)
|
|
189
|
+
return ValidationResult(
|
|
190
|
+
passed=False,
|
|
191
|
+
message=f"Context files: {present_count}/{total_count} present. Missing: {missing_str}",
|
|
192
|
+
fix_instruction="To fix: Run /create-context to generate missing context files"
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def check_hooks_installed(project_root: str) -> ValidationResult:
|
|
197
|
+
"""
|
|
198
|
+
Check 3: Verify Git hooks are installed.
|
|
199
|
+
|
|
200
|
+
Checks: .git/hooks/pre-commit exists
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
project_root: Path to project root directory.
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
ValidationResult indicating hook installation status.
|
|
207
|
+
"""
|
|
208
|
+
root_path = Path(project_root)
|
|
209
|
+
hooks_dir = root_path / ".git" / "hooks"
|
|
210
|
+
pre_commit = hooks_dir / "pre-commit"
|
|
211
|
+
|
|
212
|
+
if pre_commit.exists():
|
|
213
|
+
return ValidationResult(
|
|
214
|
+
passed=True,
|
|
215
|
+
message="Hooks: pre-commit installed"
|
|
216
|
+
)
|
|
217
|
+
elif not (root_path / ".git").exists():
|
|
218
|
+
return ValidationResult(
|
|
219
|
+
passed=False,
|
|
220
|
+
message="Hooks not installed (no .git directory)",
|
|
221
|
+
fix_instruction="To fix: Initialize Git first (git init), then run: bash .claude/scripts/install_hooks.sh"
|
|
222
|
+
)
|
|
223
|
+
else:
|
|
224
|
+
return ValidationResult(
|
|
225
|
+
passed=False,
|
|
226
|
+
message="Hooks not installed",
|
|
227
|
+
fix_instruction="To fix: Run: bash .claude/scripts/install_hooks.sh"
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def check_pythonpath() -> ValidationResult:
|
|
232
|
+
"""
|
|
233
|
+
Check 4: Verify PYTHONPATH is configured correctly.
|
|
234
|
+
|
|
235
|
+
Tests that devforgeai_cli module can be imported successfully.
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
ValidationResult indicating PYTHONPATH configuration status.
|
|
239
|
+
"""
|
|
240
|
+
try:
|
|
241
|
+
# Try to import the CLI module - if we're running, it's working
|
|
242
|
+
import devforgeai_cli
|
|
243
|
+
return ValidationResult(
|
|
244
|
+
passed=True,
|
|
245
|
+
message="PYTHONPATH: configured correctly"
|
|
246
|
+
)
|
|
247
|
+
except ImportError:
|
|
248
|
+
return ValidationResult(
|
|
249
|
+
passed=False,
|
|
250
|
+
message="PYTHONPATH not configured",
|
|
251
|
+
fix_instruction="To fix: See coding-standards.md for PYTHONPATH configuration. "
|
|
252
|
+
"Run: export PYTHONPATH=\".:$PYTHONPATH\""
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def check_git_repository(project_root: str) -> ValidationResult:
|
|
257
|
+
"""
|
|
258
|
+
Check 5: Verify project is a Git repository.
|
|
259
|
+
|
|
260
|
+
Checks: .git/ directory exists
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
project_root: Path to project root directory.
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
ValidationResult indicating Git repository status.
|
|
267
|
+
"""
|
|
268
|
+
root_path = Path(project_root)
|
|
269
|
+
git_dir = root_path / ".git"
|
|
270
|
+
|
|
271
|
+
if git_dir.exists() and git_dir.is_dir():
|
|
272
|
+
return ValidationResult(
|
|
273
|
+
passed=True,
|
|
274
|
+
message="Git repository: initialized"
|
|
275
|
+
)
|
|
276
|
+
else:
|
|
277
|
+
return ValidationResult(
|
|
278
|
+
passed=False,
|
|
279
|
+
message="Not a Git repository",
|
|
280
|
+
fix_instruction="To fix: Run: git init"
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def check_settings_file(project_root: str) -> ValidationResult:
|
|
285
|
+
"""
|
|
286
|
+
Check 6: Verify Claude settings file exists.
|
|
287
|
+
|
|
288
|
+
Checks: .claude/settings.json exists
|
|
289
|
+
|
|
290
|
+
Args:
|
|
291
|
+
project_root: Path to project root directory.
|
|
292
|
+
|
|
293
|
+
Returns:
|
|
294
|
+
ValidationResult indicating settings file status.
|
|
295
|
+
"""
|
|
296
|
+
root_path = Path(project_root)
|
|
297
|
+
settings_file = root_path / ".claude" / "settings.json"
|
|
298
|
+
|
|
299
|
+
if settings_file.exists():
|
|
300
|
+
return ValidationResult(
|
|
301
|
+
passed=True,
|
|
302
|
+
message="Settings file: present"
|
|
303
|
+
)
|
|
304
|
+
else:
|
|
305
|
+
return ValidationResult(
|
|
306
|
+
passed=False,
|
|
307
|
+
message="Settings missing",
|
|
308
|
+
fix_instruction="To fix: Run installer to create .claude/settings.json"
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
# =============================================================================
|
|
313
|
+
# Main Command Function
|
|
314
|
+
# =============================================================================
|
|
315
|
+
|
|
316
|
+
def validate_installation_command(project_root: str) -> InstallationValidationResult:
|
|
317
|
+
"""
|
|
318
|
+
Run all 6 installation validation checks.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
project_root: Path to project root directory.
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
InstallationValidationResult with all check results.
|
|
325
|
+
"""
|
|
326
|
+
checks = []
|
|
327
|
+
|
|
328
|
+
# Run all 6 checks
|
|
329
|
+
checks.append(check_cli_available())
|
|
330
|
+
checks.append(check_context_files(project_root))
|
|
331
|
+
checks.append(check_hooks_installed(project_root))
|
|
332
|
+
checks.append(check_pythonpath())
|
|
333
|
+
checks.append(check_git_repository(project_root))
|
|
334
|
+
checks.append(check_settings_file(project_root))
|
|
335
|
+
|
|
336
|
+
# Calculate totals
|
|
337
|
+
passed_count = sum(1 for check in checks if check.passed)
|
|
338
|
+
failed_count = sum(1 for check in checks if not check.passed)
|
|
339
|
+
success = failed_count == 0
|
|
340
|
+
|
|
341
|
+
return InstallationValidationResult(
|
|
342
|
+
success=success,
|
|
343
|
+
passed_count=passed_count,
|
|
344
|
+
failed_count=failed_count,
|
|
345
|
+
checks=checks,
|
|
346
|
+
exit_code=0 if success else 1
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
# =============================================================================
|
|
351
|
+
# CLI Entry Point (for standalone use)
|
|
352
|
+
# =============================================================================
|
|
353
|
+
|
|
354
|
+
def main(project_root: str = ".", output_format: str = "text") -> int:
|
|
355
|
+
"""
|
|
356
|
+
Main entry point for validate-installation command.
|
|
357
|
+
|
|
358
|
+
Args:
|
|
359
|
+
project_root: Project root directory.
|
|
360
|
+
output_format: Output format ('text' or 'json').
|
|
361
|
+
|
|
362
|
+
Returns:
|
|
363
|
+
Exit code: 0 if all checks pass, 1 if any fail.
|
|
364
|
+
"""
|
|
365
|
+
result = validate_installation_command(project_root)
|
|
366
|
+
|
|
367
|
+
if output_format == "json":
|
|
368
|
+
import json
|
|
369
|
+
output = {
|
|
370
|
+
"success": result.success,
|
|
371
|
+
"passed_count": result.passed_count,
|
|
372
|
+
"failed_count": result.failed_count,
|
|
373
|
+
"exit_code": result.exit_code,
|
|
374
|
+
"summary": result.summary,
|
|
375
|
+
"checks": [
|
|
376
|
+
{
|
|
377
|
+
"passed": check.passed,
|
|
378
|
+
"message": check.message,
|
|
379
|
+
"fix_instruction": check.fix_instruction
|
|
380
|
+
}
|
|
381
|
+
for check in result.checks
|
|
382
|
+
]
|
|
383
|
+
}
|
|
384
|
+
print(json.dumps(output, indent=2))
|
|
385
|
+
else:
|
|
386
|
+
print(result.format_output())
|
|
387
|
+
|
|
388
|
+
return result.exit_code
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
if __name__ == "__main__":
|
|
392
|
+
import argparse
|
|
393
|
+
|
|
394
|
+
parser = argparse.ArgumentParser(
|
|
395
|
+
description="Validate DevForgeAI installation"
|
|
396
|
+
)
|
|
397
|
+
parser.add_argument(
|
|
398
|
+
"--project-root",
|
|
399
|
+
default=".",
|
|
400
|
+
help="Project root directory (default: current directory)"
|
|
401
|
+
)
|
|
402
|
+
parser.add_argument(
|
|
403
|
+
"--format",
|
|
404
|
+
choices=["text", "json"],
|
|
405
|
+
default="text",
|
|
406
|
+
help="Output format (default: text)"
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
args = parser.parse_args()
|
|
410
|
+
|
|
411
|
+
exit_code = main(args.project_root, args.format)
|
|
412
|
+
sys.exit(exit_code)
|