moai-adk 0.8.1__py3-none-any.whl → 0.8.2__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/cli/commands/update.py +15 -4
- moai_adk/core/tags/__init__.py +87 -0
- moai_adk/core/tags/ci_validator.py +435 -0
- moai_adk/core/tags/cli.py +283 -0
- moai_adk/core/tags/generator.py +109 -0
- moai_adk/core/tags/inserter.py +99 -0
- moai_adk/core/tags/mapper.py +126 -0
- moai_adk/core/tags/parser.py +76 -0
- moai_adk/core/tags/pre_commit_validator.py +355 -0
- moai_adk/core/tags/reporter.py +959 -0
- moai_adk/core/tags/tags.py +149 -0
- moai_adk/core/tags/validator.py +897 -0
- moai_adk/templates/.claude/agents/alfred/cc-manager.md +25 -2
- moai_adk/templates/.claude/agents/alfred/debug-helper.md +24 -12
- moai_adk/templates/.claude/agents/alfred/doc-syncer.md +19 -12
- moai_adk/templates/.claude/agents/alfred/git-manager.md +20 -12
- moai_adk/templates/.claude/agents/alfred/implementation-planner.md +19 -12
- moai_adk/templates/.claude/agents/alfred/project-manager.md +29 -2
- moai_adk/templates/.claude/agents/alfred/quality-gate.md +25 -2
- moai_adk/templates/.claude/agents/alfred/skill-factory.md +30 -2
- moai_adk/templates/.claude/agents/alfred/spec-builder.md +26 -11
- moai_adk/templates/.claude/agents/alfred/tag-agent.md +30 -8
- moai_adk/templates/.claude/agents/alfred/tdd-implementer.md +27 -12
- moai_adk/templates/.claude/agents/alfred/trust-checker.md +25 -2
- moai_adk/templates/.claude/commands/alfred/0-project.md +5 -0
- moai_adk/templates/.claude/commands/alfred/1-plan.md +17 -4
- moai_adk/templates/.claude/commands/alfred/2-run.md +7 -0
- moai_adk/templates/.claude/commands/alfred/3-sync.md +6 -0
- moai_adk/templates/.claude/hooks/alfred/.moai/cache/version-check.json +9 -0
- moai_adk/templates/.claude/hooks/alfred/README.md +258 -145
- moai_adk/templates/.claude/hooks/alfred/TROUBLESHOOTING.md +471 -0
- moai_adk/templates/.claude/hooks/alfred/alfred_hooks.py +92 -57
- moai_adk/templates/.claude/hooks/alfred/core/version_cache.py +198 -0
- moai_adk/templates/.claude/hooks/alfred/notification__handle_events.py +102 -0
- moai_adk/templates/.claude/hooks/alfred/post_tool__log_changes.py +102 -0
- moai_adk/templates/.claude/hooks/alfred/pre_tool__auto_checkpoint.py +108 -0
- moai_adk/templates/.claude/hooks/alfred/session_end__cleanup.py +102 -0
- moai_adk/templates/.claude/hooks/alfred/session_start__show_project_info.py +102 -0
- moai_adk/templates/.claude/hooks/alfred/{core → shared/core}/project.py +269 -13
- moai_adk/templates/.claude/hooks/alfred/shared/core/version_cache.py +198 -0
- moai_adk/templates/.claude/hooks/alfred/{handlers → shared/handlers}/session.py +21 -7
- moai_adk/templates/.claude/hooks/alfred/stop__handle_interrupt.py +102 -0
- moai_adk/templates/.claude/hooks/alfred/subagent_stop__handle_subagent_end.py +102 -0
- moai_adk/templates/.claude/hooks/alfred/user_prompt__jit_load_docs.py +120 -0
- moai_adk/templates/.claude/settings.json +5 -5
- moai_adk/templates/.claude/skills/moai-foundation-ears/SKILL.md +9 -6
- moai_adk/templates/.claude/skills/moai-spec-authoring/README.md +56 -56
- moai_adk/templates/.claude/skills/moai-spec-authoring/SKILL.md +101 -100
- moai_adk/templates/.claude/skills/moai-spec-authoring/examples/validate-spec.sh +3 -3
- moai_adk/templates/.claude/skills/moai-spec-authoring/examples.md +219 -219
- moai_adk/templates/.claude/skills/moai-spec-authoring/reference.md +287 -287
- moai_adk/templates/.github/ISSUE_TEMPLATE/spec.yml +9 -11
- moai_adk/templates/.github/PULL_REQUEST_TEMPLATE.md +9 -21
- moai_adk/templates/.github/workflows/moai-release-create.yml +100 -0
- moai_adk/templates/.github/workflows/moai-release-pipeline.yml +182 -0
- moai_adk/templates/.github/workflows/release.yml +49 -0
- moai_adk/templates/.github/workflows/tag-report.yml +261 -0
- moai_adk/templates/.github/workflows/tag-validation.yml +176 -0
- moai_adk/templates/.moai/config.json +6 -1
- moai_adk/templates/.moai/hooks/install.sh +79 -0
- moai_adk/templates/.moai/hooks/pre-commit.sh +66 -0
- moai_adk/templates/CLAUDE.md +39 -40
- moai_adk/templates/src/moai_adk/core/__init__.py +5 -0
- moai_adk/templates/src/moai_adk/core/tags/__init__.py +87 -0
- moai_adk/templates/src/moai_adk/core/tags/ci_validator.py +435 -0
- moai_adk/templates/src/moai_adk/core/tags/cli.py +283 -0
- moai_adk/templates/src/moai_adk/core/tags/pre_commit_validator.py +355 -0
- moai_adk/templates/src/moai_adk/core/tags/reporter.py +959 -0
- moai_adk/templates/src/moai_adk/core/tags/validator.py +897 -0
- {moai_adk-0.8.1.dist-info → moai_adk-0.8.2.dist-info}/METADATA +226 -1
- {moai_adk-0.8.1.dist-info → moai_adk-0.8.2.dist-info}/RECORD +83 -50
- moai_adk/templates/.claude/hooks/alfred/HOOK_SCHEMA_VALIDATION.md +0 -313
- moai_adk/templates/.moai/memory/config-schema.md +0 -444
- moai_adk/templates/.moai/memory/gitflow-protection-policy.md +0 -220
- moai_adk/templates/.moai/memory/spec-metadata.md +0 -356
- /moai_adk/templates/.claude/hooks/alfred/{core → shared/core}/__init__.py +0 -0
- /moai_adk/templates/.claude/hooks/alfred/{core → shared/core}/checkpoint.py +0 -0
- /moai_adk/templates/.claude/hooks/alfred/{core → shared/core}/context.py +0 -0
- /moai_adk/templates/.claude/hooks/alfred/{core → shared/core}/tags.py +0 -0
- /moai_adk/templates/.claude/hooks/alfred/{handlers → shared/handlers}/__init__.py +0 -0
- /moai_adk/templates/.claude/hooks/alfred/{handlers → shared/handlers}/notification.py +0 -0
- /moai_adk/templates/.claude/hooks/alfred/{handlers → shared/handlers}/tool.py +0 -0
- /moai_adk/templates/.claude/hooks/alfred/{handlers → shared/handlers}/user.py +0 -0
- /moai_adk/templates/.moai/memory/{issue-label-mapping.md → ISSUE-LABEL-MAPPING.md} +0 -0
- {moai_adk-0.8.1.dist-info → moai_adk-0.8.2.dist-info}/WHEEL +0 -0
- {moai_adk-0.8.1.dist-info → moai_adk-0.8.2.dist-info}/entry_points.txt +0 -0
- {moai_adk-0.8.1.dist-info → moai_adk-0.8.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# @CODE:DOC-TAG-004 | Component 4: Automated TAG reporting workflow
|
|
2
|
+
name: TAG Report Generation
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
# Scheduled: Daily at 09:00 UTC
|
|
6
|
+
schedule:
|
|
7
|
+
- cron: '0 9 * * *'
|
|
8
|
+
|
|
9
|
+
# Event: Push to main/develop
|
|
10
|
+
push:
|
|
11
|
+
branches:
|
|
12
|
+
- main
|
|
13
|
+
- develop
|
|
14
|
+
|
|
15
|
+
# Manual: Workflow dispatch
|
|
16
|
+
workflow_dispatch:
|
|
17
|
+
inputs:
|
|
18
|
+
output_format:
|
|
19
|
+
description: 'Report format (all|inventory|matrix|statistics)'
|
|
20
|
+
required: false
|
|
21
|
+
default: 'all'
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
generate-tag-reports:
|
|
25
|
+
name: Generate TAG Reports
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
|
|
28
|
+
permissions:
|
|
29
|
+
contents: write # Required to commit reports back to repo
|
|
30
|
+
pull-requests: write # Required to comment on PRs
|
|
31
|
+
|
|
32
|
+
steps:
|
|
33
|
+
- name: Checkout repository
|
|
34
|
+
uses: actions/checkout@v4
|
|
35
|
+
with:
|
|
36
|
+
fetch-depth: 0 # Full history for accurate file modification times
|
|
37
|
+
|
|
38
|
+
- name: Setup Python
|
|
39
|
+
uses: actions/setup-python@v5
|
|
40
|
+
with:
|
|
41
|
+
python-version: '3.11'
|
|
42
|
+
cache: 'pip'
|
|
43
|
+
|
|
44
|
+
- name: Install MoAI-ADK
|
|
45
|
+
run: |
|
|
46
|
+
python -m pip install --upgrade pip
|
|
47
|
+
pip install -e .
|
|
48
|
+
|
|
49
|
+
- name: Create reports directory
|
|
50
|
+
run: |
|
|
51
|
+
mkdir -p docs/reports
|
|
52
|
+
echo "Reports will be generated in docs/reports/"
|
|
53
|
+
|
|
54
|
+
- name: Generate TAG Inventory
|
|
55
|
+
run: |
|
|
56
|
+
python -c "
|
|
57
|
+
from moai_adk.core.tags.reporter import ReportGenerator
|
|
58
|
+
|
|
59
|
+
generator = ReportGenerator()
|
|
60
|
+
inventory = generator.generate_inventory_report('.')
|
|
61
|
+
|
|
62
|
+
with open('docs/reports/tag-inventory.md', 'w') as f:
|
|
63
|
+
f.write(inventory)
|
|
64
|
+
|
|
65
|
+
print('✅ Generated tag-inventory.md')
|
|
66
|
+
"
|
|
67
|
+
|
|
68
|
+
- name: Generate TAG Coverage Matrix
|
|
69
|
+
run: |
|
|
70
|
+
python -c "
|
|
71
|
+
from moai_adk.core.tags.reporter import ReportGenerator
|
|
72
|
+
|
|
73
|
+
generator = ReportGenerator()
|
|
74
|
+
matrix = generator.generate_matrix_report('.')
|
|
75
|
+
|
|
76
|
+
with open('docs/reports/tag-matrix.md', 'w') as f:
|
|
77
|
+
f.write(matrix)
|
|
78
|
+
|
|
79
|
+
print('✅ Generated tag-matrix.md')
|
|
80
|
+
"
|
|
81
|
+
|
|
82
|
+
- name: Generate TAG Statistics
|
|
83
|
+
run: |
|
|
84
|
+
python -c "
|
|
85
|
+
from moai_adk.core.tags.reporter import ReportGenerator
|
|
86
|
+
|
|
87
|
+
generator = ReportGenerator()
|
|
88
|
+
stats = generator.generate_statistics_report('.')
|
|
89
|
+
|
|
90
|
+
with open('docs/reports/tag-statistics.json', 'w') as f:
|
|
91
|
+
f.write(stats)
|
|
92
|
+
|
|
93
|
+
print('✅ Generated tag-statistics.json')
|
|
94
|
+
"
|
|
95
|
+
|
|
96
|
+
- name: Generate combined report
|
|
97
|
+
run: |
|
|
98
|
+
python -c "
|
|
99
|
+
from moai_adk.core.tags.reporter import ReportGenerator
|
|
100
|
+
from pathlib import Path
|
|
101
|
+
import json
|
|
102
|
+
|
|
103
|
+
generator = ReportGenerator()
|
|
104
|
+
result = generator.generate_all_reports('.', 'docs/reports')
|
|
105
|
+
|
|
106
|
+
if result.success:
|
|
107
|
+
print(f'✅ All reports generated successfully')
|
|
108
|
+
print(f' - Inventory: {result.inventory_path}')
|
|
109
|
+
print(f' - Matrix: {result.matrix_path}')
|
|
110
|
+
print(f' - Statistics: {result.statistics_path}')
|
|
111
|
+
|
|
112
|
+
# Read statistics for summary
|
|
113
|
+
stats = json.loads(result.statistics_path.read_text())
|
|
114
|
+
print(f'')
|
|
115
|
+
print(f'📊 Summary:')
|
|
116
|
+
print(f' - Total TAGs: {stats[\"total_tags\"]}')
|
|
117
|
+
print(f' - By Type: SPEC={stats[\"by_type\"].get(\"SPEC\", 0)}, CODE={stats[\"by_type\"].get(\"CODE\", 0)}, TEST={stats[\"by_type\"].get(\"TEST\", 0)}, DOC={stats[\"by_type\"].get(\"DOC\", 0)}')
|
|
118
|
+
print(f' - Coverage: {stats[\"coverage\"].get(\"overall_percentage\", 0)}%')
|
|
119
|
+
else:
|
|
120
|
+
print(f'❌ Report generation failed: {result.error_message}')
|
|
121
|
+
exit(1)
|
|
122
|
+
"
|
|
123
|
+
|
|
124
|
+
- name: Check for changes
|
|
125
|
+
id: git_status
|
|
126
|
+
run: |
|
|
127
|
+
if [ -n "$(git status --porcelain docs/reports/)" ]; then
|
|
128
|
+
echo "changes=true" >> $GITHUB_OUTPUT
|
|
129
|
+
echo "📝 TAG reports have changed"
|
|
130
|
+
else
|
|
131
|
+
echo "changes=false" >> $GITHUB_OUTPUT
|
|
132
|
+
echo "✅ TAG reports unchanged (no commit needed)"
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
- name: Commit reports
|
|
136
|
+
if: steps.git_status.outputs.changes == 'true'
|
|
137
|
+
run: |
|
|
138
|
+
git config --global user.name 'github-actions[bot]'
|
|
139
|
+
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
|
|
140
|
+
git add docs/reports/
|
|
141
|
+
git commit -m "docs(tags): Update TAG reports [automated]
|
|
142
|
+
|
|
143
|
+
- Updated tag-inventory.md
|
|
144
|
+
- Updated tag-matrix.md
|
|
145
|
+
- Updated tag-statistics.json
|
|
146
|
+
|
|
147
|
+
Generated by: GitHub Actions workflow (tag-report.yml)
|
|
148
|
+
Triggered: ${{ github.event_name }}
|
|
149
|
+
Commit: ${{ github.sha }}
|
|
150
|
+
|
|
151
|
+
🤖 Generated with MoAI-ADK TAG Reporting System
|
|
152
|
+
"
|
|
153
|
+
git push
|
|
154
|
+
|
|
155
|
+
- name: Create GitHub Release Notes
|
|
156
|
+
if: github.ref == 'refs/heads/main' && steps.git_status.outputs.changes == 'true'
|
|
157
|
+
run: |
|
|
158
|
+
echo "📊 TAG System Health Report" > report_summary.md
|
|
159
|
+
echo "" >> report_summary.md
|
|
160
|
+
echo "Generated: $(date -u +'%Y-%m-%d %H:%M:%S UTC')" >> report_summary.md
|
|
161
|
+
echo "" >> report_summary.md
|
|
162
|
+
|
|
163
|
+
# Extract key metrics from statistics
|
|
164
|
+
python -c "
|
|
165
|
+
import json
|
|
166
|
+
from pathlib import Path
|
|
167
|
+
|
|
168
|
+
stats = json.loads(Path('docs/reports/tag-statistics.json').read_text())
|
|
169
|
+
|
|
170
|
+
print(f'## Summary')
|
|
171
|
+
print(f'')
|
|
172
|
+
print(f'- **Total TAGs**: {stats[\"total_tags\"]}')
|
|
173
|
+
print(f'- **By Type**:')
|
|
174
|
+
print(f' - SPEC: {stats[\"by_type\"].get(\"SPEC\", 0)}')
|
|
175
|
+
print(f' - CODE: {stats[\"by_type\"].get(\"CODE\", 0)}')
|
|
176
|
+
print(f' - TEST: {stats[\"by_type\"].get(\"TEST\", 0)}')
|
|
177
|
+
print(f' - DOC: {stats[\"by_type\"].get(\"DOC\", 0)}')
|
|
178
|
+
print(f'')
|
|
179
|
+
print(f'## Coverage')
|
|
180
|
+
print(f'')
|
|
181
|
+
print(f'- **Overall**: {stats[\"coverage\"].get(\"overall_percentage\", 0)}%')
|
|
182
|
+
print(f'- **SPEC → CODE**: {stats[\"coverage\"].get(\"spec_to_code\", 0)}%')
|
|
183
|
+
print(f'- **CODE → TEST**: {stats[\"coverage\"].get(\"code_to_test\", 0)}%')
|
|
184
|
+
print(f'')
|
|
185
|
+
print(f'## Issues')
|
|
186
|
+
print(f'')
|
|
187
|
+
print(f'- **Orphan TAGs**: {stats[\"issues\"].get(\"orphan_count\", 0)}')
|
|
188
|
+
print(f'- **Incomplete Chains**: {stats[\"issues\"].get(\"incomplete_chains\", 0)}')
|
|
189
|
+
print(f'')
|
|
190
|
+
print(f'## Reports')
|
|
191
|
+
print(f'')
|
|
192
|
+
print(f'- [TAG Inventory](./docs/reports/tag-inventory.md)')
|
|
193
|
+
print(f'- [Coverage Matrix](./docs/reports/tag-matrix.md)')
|
|
194
|
+
print(f'- [Statistics (JSON)](./docs/reports/tag-statistics.json)')
|
|
195
|
+
" >> report_summary.md
|
|
196
|
+
|
|
197
|
+
cat report_summary.md
|
|
198
|
+
|
|
199
|
+
- name: Upload reports as artifacts
|
|
200
|
+
uses: actions/upload-artifact@v4
|
|
201
|
+
with:
|
|
202
|
+
name: tag-reports-${{ github.sha }}
|
|
203
|
+
path: docs/reports/
|
|
204
|
+
retention-days: 90
|
|
205
|
+
|
|
206
|
+
- name: Post summary to GitHub Actions UI
|
|
207
|
+
run: |
|
|
208
|
+
echo "## 📊 TAG Report Generation Complete" >> $GITHUB_STEP_SUMMARY
|
|
209
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
210
|
+
|
|
211
|
+
python -c "
|
|
212
|
+
import json
|
|
213
|
+
from pathlib import Path
|
|
214
|
+
|
|
215
|
+
stats = json.loads(Path('docs/reports/tag-statistics.json').read_text())
|
|
216
|
+
|
|
217
|
+
print(f'### Summary')
|
|
218
|
+
print(f'')
|
|
219
|
+
print(f'| Metric | Value |')
|
|
220
|
+
print(f'|--------|-------|')
|
|
221
|
+
print(f'| Total TAGs | {stats[\"total_tags\"]} |')
|
|
222
|
+
print(f'| SPEC | {stats[\"by_type\"].get(\"SPEC\", 0)} |')
|
|
223
|
+
print(f'| CODE | {stats[\"by_type\"].get(\"CODE\", 0)} |')
|
|
224
|
+
print(f'| TEST | {stats[\"by_type\"].get(\"TEST\", 0)} |')
|
|
225
|
+
print(f'| DOC | {stats[\"by_type\"].get(\"DOC\", 0)} |')
|
|
226
|
+
print(f'| Overall Coverage | {stats[\"coverage\"].get(\"overall_percentage\", 0)}% |')
|
|
227
|
+
print(f'| Orphan TAGs | {stats[\"issues\"].get(\"orphan_count\", 0)} |')
|
|
228
|
+
print(f'| Incomplete Chains | {stats[\"issues\"].get(\"incomplete_chains\", 0)} |')
|
|
229
|
+
print(f'')
|
|
230
|
+
print(f'### Generated Files')
|
|
231
|
+
print(f'')
|
|
232
|
+
print(f'- ✅ tag-inventory.md')
|
|
233
|
+
print(f'- ✅ tag-matrix.md')
|
|
234
|
+
print(f'- ✅ tag-statistics.json')
|
|
235
|
+
" >> $GITHUB_STEP_SUMMARY
|
|
236
|
+
|
|
237
|
+
- name: Fail workflow if issues detected (optional)
|
|
238
|
+
if: always()
|
|
239
|
+
run: |
|
|
240
|
+
python -c "
|
|
241
|
+
import json
|
|
242
|
+
from pathlib import Path
|
|
243
|
+
import sys
|
|
244
|
+
|
|
245
|
+
stats = json.loads(Path('docs/reports/tag-statistics.json').read_text())
|
|
246
|
+
|
|
247
|
+
orphan_count = stats['issues'].get('orphan_count', 0)
|
|
248
|
+
incomplete_count = stats['issues'].get('incomplete_chains', 0)
|
|
249
|
+
|
|
250
|
+
# Optional: Fail workflow if too many issues
|
|
251
|
+
# Uncomment to enable strict validation
|
|
252
|
+
# if orphan_count > 10 or incomplete_count > 10:
|
|
253
|
+
# print(f'❌ Too many TAG issues detected!')
|
|
254
|
+
# print(f' Orphans: {orphan_count}')
|
|
255
|
+
# print(f' Incomplete: {incomplete_count}')
|
|
256
|
+
# sys.exit(1)
|
|
257
|
+
|
|
258
|
+
print(f'✅ TAG system health check passed')
|
|
259
|
+
print(f' Orphans: {orphan_count}')
|
|
260
|
+
print(f' Incomplete: {incomplete_count}')
|
|
261
|
+
"
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
name: TAG Validation
|
|
2
|
+
|
|
3
|
+
# @DOC:DOC-TAG-004 | Component 2: CI/CD workflow for TAG validation
|
|
4
|
+
# Validates TAG annotations on every PR to ensure quality and consistency
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
pull_request:
|
|
8
|
+
types: [opened, synchronize, reopened, ready_for_review]
|
|
9
|
+
push:
|
|
10
|
+
branches: [main, develop, "feature/**"]
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
validate-tags:
|
|
14
|
+
name: 🏷️ Validate TAG Annotations
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
|
|
17
|
+
# Skip validation on draft PRs (allow WIP)
|
|
18
|
+
if: github.event.pull_request.draft == false || github.event_name == 'push'
|
|
19
|
+
|
|
20
|
+
steps:
|
|
21
|
+
- name: Checkout code
|
|
22
|
+
uses: actions/checkout@v4
|
|
23
|
+
with:
|
|
24
|
+
fetch-depth: 0 # Fetch all history for comprehensive validation
|
|
25
|
+
|
|
26
|
+
- name: Setup Python
|
|
27
|
+
uses: actions/setup-python@v5
|
|
28
|
+
with:
|
|
29
|
+
python-version: '3.12'
|
|
30
|
+
|
|
31
|
+
- name: Install uv
|
|
32
|
+
uses: astral-sh/setup-uv@v5
|
|
33
|
+
with:
|
|
34
|
+
version: "latest"
|
|
35
|
+
|
|
36
|
+
- name: Install dependencies
|
|
37
|
+
run: |
|
|
38
|
+
uv pip install --system -e .
|
|
39
|
+
uv pip install --system requests
|
|
40
|
+
|
|
41
|
+
- name: Get PR number
|
|
42
|
+
id: pr
|
|
43
|
+
run: |
|
|
44
|
+
if [ "${{ github.event_name }}" == "pull_request" ]; then
|
|
45
|
+
echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT
|
|
46
|
+
else
|
|
47
|
+
echo "number=0" >> $GITHUB_OUTPUT
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
- name: Run TAG validation (info mode)
|
|
51
|
+
if: github.event_name == 'push' || github.event.pull_request.draft == false
|
|
52
|
+
id: validate_info
|
|
53
|
+
continue-on-error: true
|
|
54
|
+
env:
|
|
55
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
56
|
+
run: |
|
|
57
|
+
if [ "${{ steps.pr.outputs.number }}" != "0" ]; then
|
|
58
|
+
python -m moai_adk.core.tags.ci_validator \
|
|
59
|
+
--pr-number ${{ steps.pr.outputs.number }} \
|
|
60
|
+
--output-json validation-report.json \
|
|
61
|
+
--output-comment pr-comment.md
|
|
62
|
+
else
|
|
63
|
+
echo "Skipping PR validation on push event"
|
|
64
|
+
echo '{"status": "skipped", "message": "Push event - no PR validation"}' > validation-report.json
|
|
65
|
+
echo "# TAG Validation Skipped\n\nPush event detected. TAG validation runs on PRs." > pr-comment.md
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
- name: Run TAG validation (strict mode)
|
|
69
|
+
if: github.event.pull_request.ready_for_review == true
|
|
70
|
+
id: validate_strict
|
|
71
|
+
continue-on-error: false
|
|
72
|
+
env:
|
|
73
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
74
|
+
run: |
|
|
75
|
+
python -m moai_adk.core.tags.ci_validator \
|
|
76
|
+
--pr-number ${{ steps.pr.outputs.number }} \
|
|
77
|
+
--strict \
|
|
78
|
+
--output-json validation-report-strict.json \
|
|
79
|
+
--output-comment pr-comment-strict.md
|
|
80
|
+
|
|
81
|
+
- name: Upload validation report
|
|
82
|
+
if: always()
|
|
83
|
+
uses: actions/upload-artifact@v4
|
|
84
|
+
with:
|
|
85
|
+
name: tag-validation-report
|
|
86
|
+
path: |
|
|
87
|
+
validation-report*.json
|
|
88
|
+
pr-comment*.md
|
|
89
|
+
retention-days: 30
|
|
90
|
+
|
|
91
|
+
- name: Post PR comment (info mode)
|
|
92
|
+
if: github.event_name == 'pull_request' && steps.pr.outputs.number != '0'
|
|
93
|
+
uses: actions/github-script@v7
|
|
94
|
+
with:
|
|
95
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
96
|
+
script: |
|
|
97
|
+
const fs = require('fs');
|
|
98
|
+
|
|
99
|
+
// Read the comment file
|
|
100
|
+
let comment = '';
|
|
101
|
+
try {
|
|
102
|
+
comment = fs.readFileSync('pr-comment.md', 'utf8');
|
|
103
|
+
} catch (error) {
|
|
104
|
+
comment = '## ⚠️ TAG Validation\n\nCould not read validation results.';
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Find existing comment
|
|
108
|
+
const { data: comments } = await github.rest.issues.listComments({
|
|
109
|
+
owner: context.repo.owner,
|
|
110
|
+
repo: context.repo.repo,
|
|
111
|
+
issue_number: context.issue.number,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const botComment = comments.find(comment =>
|
|
115
|
+
comment.user.login === 'github-actions[bot]' &&
|
|
116
|
+
comment.body.includes('TAG Validation')
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
// Create or update comment
|
|
120
|
+
const commentBody = comment + '\n\n---\n\n*Automated validation by [MoAI-ADK TAG System](https://github.com/YOUR_ORG/MoAI-ADK)*';
|
|
121
|
+
|
|
122
|
+
if (botComment) {
|
|
123
|
+
await github.rest.issues.updateComment({
|
|
124
|
+
owner: context.repo.owner,
|
|
125
|
+
repo: context.repo.repo,
|
|
126
|
+
comment_id: botComment.id,
|
|
127
|
+
body: commentBody
|
|
128
|
+
});
|
|
129
|
+
} else {
|
|
130
|
+
await github.rest.issues.createComment({
|
|
131
|
+
owner: context.repo.owner,
|
|
132
|
+
repo: context.repo.repo,
|
|
133
|
+
issue_number: context.issue.number,
|
|
134
|
+
body: commentBody
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
- name: Validation summary
|
|
139
|
+
if: always()
|
|
140
|
+
run: |
|
|
141
|
+
echo "## TAG Validation Summary" >> $GITHUB_STEP_SUMMARY
|
|
142
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
143
|
+
|
|
144
|
+
if [ -f validation-report.json ]; then
|
|
145
|
+
echo "### Info Mode Results" >> $GITHUB_STEP_SUMMARY
|
|
146
|
+
cat validation-report.json | python -c "import json, sys; r=json.load(sys.stdin); print(f\"- Status: {r.get('status', 'unknown')}\"); print(f\"- Errors: {r.get('statistics', {}).get('total_errors', 0)}\"); print(f\"- Warnings: {r.get('statistics', {}).get('total_warnings', 0)}\")" >> $GITHUB_STEP_SUMMARY || echo "- Could not parse report" >> $GITHUB_STEP_SUMMARY
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
if [ -f validation-report-strict.json ]; then
|
|
150
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
151
|
+
echo "### Strict Mode Results" >> $GITHUB_STEP_SUMMARY
|
|
152
|
+
cat validation-report-strict.json | python -c "import json, sys; r=json.load(sys.stdin); print(f\"- Status: {r.get('status', 'unknown')}\"); print(f\"- Errors: {r.get('statistics', {}).get('total_errors', 0)}\"); print(f\"- Warnings: {r.get('statistics', {}).get('total_warnings', 0)}\")" >> $GITHUB_STEP_SUMMARY || echo "- Could not parse report" >> $GITHUB_STEP_SUMMARY
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
- name: Set PR status check
|
|
156
|
+
if: github.event_name == 'pull_request'
|
|
157
|
+
run: |
|
|
158
|
+
if [ -f validation-report.json ]; then
|
|
159
|
+
STATUS=$(cat validation-report.json | python -c "import json, sys; r=json.load(sys.stdin); print('success' if r.get('is_valid', False) else 'failure')")
|
|
160
|
+
echo "Validation status: $STATUS"
|
|
161
|
+
if [ "$STATUS" = "failure" ]; then
|
|
162
|
+
exit 1
|
|
163
|
+
fi
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
# Optional: Require TAG validation to pass before merge
|
|
167
|
+
# Uncomment this job to enforce strict validation
|
|
168
|
+
#
|
|
169
|
+
# require-validation:
|
|
170
|
+
# name: Require TAG Validation
|
|
171
|
+
# runs-on: ubuntu-latest
|
|
172
|
+
# needs: validate-tags
|
|
173
|
+
# if: github.event.pull_request.draft == false
|
|
174
|
+
# steps:
|
|
175
|
+
# - name: Check validation passed
|
|
176
|
+
# run: echo "TAG validation passed"
|
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
"@SPEC:PROJECT-CONFIG-001": "@SPEC:MOAI-CONFIG-001"
|
|
5
5
|
},
|
|
6
6
|
"moai": {
|
|
7
|
-
"version": "{{MOAI_VERSION}}"
|
|
7
|
+
"version": "{{MOAI_VERSION}}",
|
|
8
|
+
"update_check_frequency": "daily",
|
|
9
|
+
"version_check": {
|
|
10
|
+
"enabled": true,
|
|
11
|
+
"cache_ttl_hours": 24
|
|
12
|
+
}
|
|
8
13
|
},
|
|
9
14
|
"constitution": {
|
|
10
15
|
"enforce_tdd": true,
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# @CODE:DOC-TAG-004 | Component 1: Pre-commit hook installer
|
|
3
|
+
#
|
|
4
|
+
# This script installs the TAG validation pre-commit hook into .git/hooks/
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# ./install.sh # Install hook
|
|
8
|
+
# ./install.sh --uninstall # Remove hook
|
|
9
|
+
|
|
10
|
+
set -e
|
|
11
|
+
|
|
12
|
+
# Colors
|
|
13
|
+
GREEN='\033[0;32m'
|
|
14
|
+
YELLOW='\033[1;33m'
|
|
15
|
+
RED='\033[0;31m'
|
|
16
|
+
NC='\033[0m'
|
|
17
|
+
|
|
18
|
+
# Get repository root
|
|
19
|
+
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo ".")
|
|
20
|
+
HOOK_SOURCE="${REPO_ROOT}/.moai/hooks/pre-commit.sh"
|
|
21
|
+
HOOK_TARGET="${REPO_ROOT}/.git/hooks/pre-commit"
|
|
22
|
+
|
|
23
|
+
# Function to install hook
|
|
24
|
+
install_hook() {
|
|
25
|
+
echo "🔧 Installing TAG validation pre-commit hook..."
|
|
26
|
+
|
|
27
|
+
# Check if source exists
|
|
28
|
+
if [ ! -f "$HOOK_SOURCE" ]; then
|
|
29
|
+
echo -e "${RED}Error: Hook source not found at $HOOK_SOURCE${NC}"
|
|
30
|
+
exit 1
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
# Check if target already exists
|
|
34
|
+
if [ -f "$HOOK_TARGET" ]; then
|
|
35
|
+
echo -e "${YELLOW}Warning: Pre-commit hook already exists.${NC}"
|
|
36
|
+
echo "Backing up existing hook to ${HOOK_TARGET}.backup"
|
|
37
|
+
cp "$HOOK_TARGET" "${HOOK_TARGET}.backup"
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Create .git/hooks directory if it doesn't exist
|
|
41
|
+
mkdir -p "$(dirname "$HOOK_TARGET")"
|
|
42
|
+
|
|
43
|
+
# Copy hook
|
|
44
|
+
cp "$HOOK_SOURCE" "$HOOK_TARGET"
|
|
45
|
+
chmod +x "$HOOK_TARGET"
|
|
46
|
+
|
|
47
|
+
echo -e "${GREEN}✓ Pre-commit hook installed successfully!${NC}"
|
|
48
|
+
echo ""
|
|
49
|
+
echo "The hook will now validate TAG annotations on every commit."
|
|
50
|
+
echo ""
|
|
51
|
+
echo "To uninstall: $0 --uninstall"
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# Function to uninstall hook
|
|
55
|
+
uninstall_hook() {
|
|
56
|
+
echo "🔧 Uninstalling TAG validation pre-commit hook..."
|
|
57
|
+
|
|
58
|
+
if [ ! -f "$HOOK_TARGET" ]; then
|
|
59
|
+
echo -e "${YELLOW}No pre-commit hook installed.${NC}"
|
|
60
|
+
exit 0
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# Check if backup exists
|
|
64
|
+
if [ -f "${HOOK_TARGET}.backup" ]; then
|
|
65
|
+
echo "Restoring backup..."
|
|
66
|
+
mv "${HOOK_TARGET}.backup" "$HOOK_TARGET"
|
|
67
|
+
echo -e "${GREEN}✓ Backup restored.${NC}"
|
|
68
|
+
else
|
|
69
|
+
rm "$HOOK_TARGET"
|
|
70
|
+
echo -e "${GREEN}✓ Pre-commit hook removed.${NC}"
|
|
71
|
+
fi
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# Parse command line arguments
|
|
75
|
+
if [ "$1" = "--uninstall" ]; then
|
|
76
|
+
uninstall_hook
|
|
77
|
+
else
|
|
78
|
+
install_hook
|
|
79
|
+
fi
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# @CODE:DOC-TAG-004 | Component 1: Pre-commit hook for TAG validation
|
|
3
|
+
#
|
|
4
|
+
# This hook validates TAG annotations in staged files before commit.
|
|
5
|
+
# It checks:
|
|
6
|
+
# - TAG format (@DOC:DOMAIN-TYPE-NNN)
|
|
7
|
+
# - Duplicate TAG detection
|
|
8
|
+
# - Orphan TAG detection (warnings only)
|
|
9
|
+
#
|
|
10
|
+
# Exit codes:
|
|
11
|
+
# 0 - Validation passed
|
|
12
|
+
# 1 - Validation failed (duplicates or format errors)
|
|
13
|
+
|
|
14
|
+
set -e # Exit on error
|
|
15
|
+
|
|
16
|
+
# Colors for output
|
|
17
|
+
RED='\033[0;31m'
|
|
18
|
+
GREEN='\033[0;32m'
|
|
19
|
+
YELLOW='\033[1;33m'
|
|
20
|
+
NC='\033[0m' # No Color
|
|
21
|
+
|
|
22
|
+
# Get repository root
|
|
23
|
+
REPO_ROOT=$(git rev-parse --show-toplevel)
|
|
24
|
+
|
|
25
|
+
# Check if Python module is available
|
|
26
|
+
if ! python3 -c "import moai_adk.core.tags.pre_commit_validator" 2>/dev/null; then
|
|
27
|
+
echo -e "${YELLOW}Warning: moai_adk TAG validator not found.${NC}"
|
|
28
|
+
echo "Skipping TAG validation. Install moai_adk to enable validation."
|
|
29
|
+
exit 0
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
# Get staged files
|
|
33
|
+
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
|
|
34
|
+
|
|
35
|
+
if [ -z "$STAGED_FILES" ]; then
|
|
36
|
+
echo -e "${GREEN}No staged files to validate.${NC}"
|
|
37
|
+
exit 0
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
echo "🔍 Validating TAG annotations in staged files..."
|
|
41
|
+
|
|
42
|
+
# Run TAG validation
|
|
43
|
+
# Pass staged files as arguments to validator
|
|
44
|
+
python3 -m moai_adk.core.tags.pre_commit_validator \
|
|
45
|
+
--files $STAGED_FILES
|
|
46
|
+
|
|
47
|
+
VALIDATION_RESULT=$?
|
|
48
|
+
|
|
49
|
+
# Check result
|
|
50
|
+
if [ $VALIDATION_RESULT -eq 0 ]; then
|
|
51
|
+
echo -e "${GREEN}✓ TAG validation passed.${NC}"
|
|
52
|
+
exit 0
|
|
53
|
+
else
|
|
54
|
+
echo -e "${RED}✗ TAG validation failed.${NC}"
|
|
55
|
+
echo ""
|
|
56
|
+
echo "Commit blocked due to TAG validation errors."
|
|
57
|
+
echo ""
|
|
58
|
+
echo "To fix:"
|
|
59
|
+
echo " 1. Fix duplicate TAGs or format errors shown above"
|
|
60
|
+
echo " 2. Stage your changes with 'git add'"
|
|
61
|
+
echo " 3. Try committing again"
|
|
62
|
+
echo ""
|
|
63
|
+
echo "To skip this validation (not recommended):"
|
|
64
|
+
echo " git commit --no-verify"
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|