@mokoconsulting/mcp-mokogitea-api 1.2.0

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.
Files changed (86) hide show
  1. package/.gitattributes +94 -0
  2. package/.gitmessage +9 -0
  3. package/.mokogitea/ISSUE_TEMPLATE/adr.md +110 -0
  4. package/.mokogitea/ISSUE_TEMPLATE/bug_report.md +48 -0
  5. package/.mokogitea/ISSUE_TEMPLATE/config.yml +18 -0
  6. package/.mokogitea/ISSUE_TEMPLATE/documentation.md +52 -0
  7. package/.mokogitea/ISSUE_TEMPLATE/enterprise_support.md +85 -0
  8. package/.mokogitea/ISSUE_TEMPLATE/feature_request.md +51 -0
  9. package/.mokogitea/ISSUE_TEMPLATE/firewall-request.md +190 -0
  10. package/.mokogitea/ISSUE_TEMPLATE/mcp_api_integration.md +48 -0
  11. package/.mokogitea/ISSUE_TEMPLATE/mcp_connection_issue.md +67 -0
  12. package/.mokogitea/ISSUE_TEMPLATE/mcp_tool_request.md +49 -0
  13. package/.mokogitea/ISSUE_TEMPLATE/question.md +82 -0
  14. package/.mokogitea/ISSUE_TEMPLATE/rfc.md +126 -0
  15. package/.mokogitea/ISSUE_TEMPLATE/security.md +51 -0
  16. package/.mokogitea/ISSUE_TEMPLATE/version.md +24 -0
  17. package/.mokogitea/auto-assign.yml +76 -0
  18. package/.mokogitea/auto-dev-issue.yml +207 -0
  19. package/.mokogitea/auto-release.yml +337 -0
  20. package/.mokogitea/branch-protection.yml +251 -0
  21. package/.mokogitea/changelog-validation.yml +101 -0
  22. package/.mokogitea/codeql-analysis.yml +115 -0
  23. package/.mokogitea/copilot-agent.yml +44 -0
  24. package/.mokogitea/deploy-demo.yml +734 -0
  25. package/.mokogitea/deploy-dev.yml +700 -0
  26. package/.mokogitea/enterprise-firewall-setup.yml +758 -0
  27. package/.mokogitea/manifest.xml +25 -0
  28. package/.mokogitea/mcp-auto-release.yml +278 -0
  29. package/.mokogitea/mcp-build-test.yml +65 -0
  30. package/.mokogitea/mcp-sdk-check.yml +109 -0
  31. package/.mokogitea/mcp-tool-inventory.yml +61 -0
  32. package/.mokogitea/pr-branch-check.yml +90 -0
  33. package/.mokogitea/repository-cleanup.yml +525 -0
  34. package/.mokogitea/standards-compliance.yml +2614 -0
  35. package/.mokogitea/sync-version-on-merge.yml +133 -0
  36. package/.mokogitea/workflows/auto-assign.yml +76 -0
  37. package/.mokogitea/workflows/auto-bump.yml +66 -0
  38. package/.mokogitea/workflows/auto-dev-issue.yml +207 -0
  39. package/.mokogitea/workflows/auto-release.yml +341 -0
  40. package/.mokogitea/workflows/branch-cleanup.yml +48 -0
  41. package/.mokogitea/workflows/cascade-dev.yml +10 -0
  42. package/.mokogitea/workflows/changelog-validation.yml +101 -0
  43. package/.mokogitea/workflows/ci-generic.yml +204 -0
  44. package/.mokogitea/workflows/cleanup.yml +87 -0
  45. package/.mokogitea/workflows/codeql-analysis.yml +115 -0
  46. package/.mokogitea/workflows/copilot-agent.yml +44 -0
  47. package/.mokogitea/workflows/deploy-manual.yml +126 -0
  48. package/.mokogitea/workflows/enterprise-firewall-setup.yml +758 -0
  49. package/.mokogitea/workflows/gitleaks.yml +96 -0
  50. package/.mokogitea/workflows/issue-branch.yml +73 -0
  51. package/.mokogitea/workflows/mcp-auto-release.yml +280 -0
  52. package/.mokogitea/workflows/mcp-build-test.yml +65 -0
  53. package/.mokogitea/workflows/mcp-sdk-check.yml +109 -0
  54. package/.mokogitea/workflows/mcp-tool-inventory.yml +61 -0
  55. package/.mokogitea/workflows/notify.yml +70 -0
  56. package/.mokogitea/workflows/npm-publish.yml +51 -0
  57. package/.mokogitea/workflows/pr-check.yml +508 -0
  58. package/.mokogitea/workflows/pre-release.yml +11 -0
  59. package/.mokogitea/workflows/repo-health.yml +711 -0
  60. package/.mokogitea/workflows/repository-cleanup.yml +525 -0
  61. package/.mokogitea/workflows/security-audit.yml +82 -0
  62. package/.mokogitea/workflows/standards-compliance.yml +2614 -0
  63. package/.mokogitea/workflows/sync-version-on-merge.yml +130 -0
  64. package/.mokogitea/workflows/update-server.yml +312 -0
  65. package/CHANGELOG.md +145 -0
  66. package/CLAUDE.md +43 -0
  67. package/CONTRIBUTING.md +161 -0
  68. package/README.md +286 -0
  69. package/SECURITY.md +91 -0
  70. package/automation/ci-issue-reporter.sh +237 -0
  71. package/config.example.json +13 -0
  72. package/dist/client.d.ts +15 -0
  73. package/dist/client.js +104 -0
  74. package/dist/config.d.ts +4 -0
  75. package/dist/config.js +48 -0
  76. package/dist/index.d.ts +3 -0
  77. package/dist/index.js +1119 -0
  78. package/dist/types.d.ts +20 -0
  79. package/dist/types.js +16 -0
  80. package/package.json +34 -0
  81. package/scripts/setup.mjs +40 -0
  82. package/src/client.ts +120 -0
  83. package/src/config.ts +58 -0
  84. package/src/index.ts +1712 -0
  85. package/src/types.ts +37 -0
  86. package/tsconfig.json +19 -0
@@ -0,0 +1,525 @@
1
+ # Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
2
+ #
3
+ # This file is part of a Moko Consulting project.
4
+ #
5
+ # SPDX-License-Identifier: GPL-3.0-or-later
6
+ #
7
+ # FILE INFORMATION
8
+ # DEFGROUP: GitHub.Workflow
9
+ # INGROUP: MokoStandards.Maintenance
10
+ # REPO: https://github.com/mokoconsulting-tech/MokoStandards
11
+ # PATH: /templates/workflows/shared/repository-cleanup.yml.template
12
+ # VERSION: 04.06.00
13
+ # BRIEF: Recurring repository maintenance — labels, branches, workflows, logs, doc indexes
14
+ # NOTE: Synced via bulk-repo-sync to .github/workflows/repository-cleanup.yml in all governed repos.
15
+ # Runs on the 1st and 15th of each month at 6:00 AM UTC, and on manual dispatch.
16
+
17
+ name: Repository Cleanup
18
+
19
+ on:
20
+ schedule:
21
+ - cron: '0 6 1,15 * *'
22
+ workflow_dispatch:
23
+ inputs:
24
+ reset_labels:
25
+ description: 'Delete ALL existing labels and recreate the standard set'
26
+ type: boolean
27
+ default: false
28
+ clean_branches:
29
+ description: 'Delete old chore/sync-mokostandards-* branches'
30
+ type: boolean
31
+ default: true
32
+ clean_workflows:
33
+ description: 'Delete orphaned workflow runs (cancelled, stale)'
34
+ type: boolean
35
+ default: true
36
+ clean_logs:
37
+ description: 'Delete workflow run logs older than 30 days'
38
+ type: boolean
39
+ default: true
40
+ fix_templates:
41
+ description: 'Strip copyright comment blocks from issue templates'
42
+ type: boolean
43
+ default: true
44
+ rebuild_indexes:
45
+ description: 'Rebuild docs/ index files'
46
+ type: boolean
47
+ default: true
48
+ delete_closed_issues:
49
+ description: 'Delete issues that have been closed for more than 30 days'
50
+ type: boolean
51
+ default: false
52
+
53
+ env:
54
+ FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
55
+
56
+ permissions:
57
+ contents: write
58
+ issues: write
59
+ actions: write
60
+
61
+ jobs:
62
+ cleanup:
63
+ name: Repository Maintenance
64
+ runs-on: ubuntu-latest
65
+
66
+ steps:
67
+ - name: Checkout repository
68
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
69
+ with:
70
+ token: ${{ secrets.GH_TOKEN || github.token }}
71
+ fetch-depth: 0
72
+
73
+ - name: Check actor permission
74
+ env:
75
+ GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
76
+ run: |
77
+ ACTOR="${{ github.actor }}"
78
+ # Schedule triggers use github-actions[bot]
79
+ if [ "${{ github.event_name }}" = "schedule" ]; then
80
+ echo "✅ Scheduled run — authorized"
81
+ exit 0
82
+ fi
83
+ AUTHORIZED_USERS="jmiller github-actions[bot]"
84
+ for user in $AUTHORIZED_USERS; do
85
+ if [ "$ACTOR" = "$user" ]; then
86
+ echo "✅ ${ACTOR} authorized"
87
+ exit 0
88
+ fi
89
+ done
90
+ PERMISSION=$(gh api "repos/${{ github.repository }}/collaborators/${ACTOR}/permission" \
91
+ --jq '.permission' 2>/dev/null)
92
+ case "$PERMISSION" in
93
+ admin|maintain) echo "✅ ${ACTOR} has ${PERMISSION}" ;;
94
+ *) echo "❌ Admin or maintain required"; exit 1 ;;
95
+ esac
96
+
97
+ # ── Determine which tasks to run ─────────────────────────────────────
98
+ # On schedule: run all tasks with safe defaults (labels NOT reset)
99
+ # On dispatch: use input toggles
100
+ - name: Set task flags
101
+ id: tasks
102
+ run: |
103
+ if [ "${{ github.event_name }}" = "schedule" ]; then
104
+ echo "reset_labels=false" >> $GITHUB_OUTPUT
105
+ echo "clean_branches=true" >> $GITHUB_OUTPUT
106
+ echo "clean_workflows=true" >> $GITHUB_OUTPUT
107
+ echo "clean_logs=true" >> $GITHUB_OUTPUT
108
+ echo "fix_templates=true" >> $GITHUB_OUTPUT
109
+ echo "rebuild_indexes=true" >> $GITHUB_OUTPUT
110
+ echo "delete_closed_issues=false" >> $GITHUB_OUTPUT
111
+ else
112
+ echo "reset_labels=${{ inputs.reset_labels }}" >> $GITHUB_OUTPUT
113
+ echo "clean_branches=${{ inputs.clean_branches }}" >> $GITHUB_OUTPUT
114
+ echo "clean_workflows=${{ inputs.clean_workflows }}" >> $GITHUB_OUTPUT
115
+ echo "clean_logs=${{ inputs.clean_logs }}" >> $GITHUB_OUTPUT
116
+ echo "fix_templates=${{ inputs.fix_templates }}" >> $GITHUB_OUTPUT
117
+ echo "rebuild_indexes=${{ inputs.rebuild_indexes }}" >> $GITHUB_OUTPUT
118
+ echo "delete_closed_issues=${{ inputs.delete_closed_issues }}" >> $GITHUB_OUTPUT
119
+ fi
120
+
121
+ # ── DELETE RETIRED WORKFLOWS (always runs) ────────────────────────────
122
+ - name: Delete retired workflow files
123
+ run: |
124
+ echo "## 🗑️ Retired Workflow Cleanup" >> $GITHUB_STEP_SUMMARY
125
+ echo "" >> $GITHUB_STEP_SUMMARY
126
+
127
+ RETIRED=(
128
+ ".github/workflows/build.yml"
129
+ ".github/workflows/code-quality.yml"
130
+ ".github/workflows/release-cycle.yml"
131
+ ".github/workflows/release-pipeline.yml"
132
+ ".github/workflows/branch-cleanup.yml"
133
+ ".github/workflows/auto-update-changelog.yml"
134
+ ".github/workflows/enterprise-issue-manager.yml"
135
+ ".github/workflows/flush-actions-cache.yml"
136
+ ".github/workflows/mokostandards-script-runner.yml"
137
+ ".github/workflows/unified-ci.yml"
138
+ ".github/workflows/unified-platform-testing.yml"
139
+ ".github/workflows/reusable-build.yml"
140
+ ".github/workflows/reusable-ci-validation.yml"
141
+ ".github/workflows/reusable-deploy.yml"
142
+ ".github/workflows/reusable-php-quality.yml"
143
+ ".github/workflows/reusable-platform-testing.yml"
144
+ ".github/workflows/reusable-project-detector.yml"
145
+ ".github/workflows/reusable-release.yml"
146
+ ".github/workflows/reusable-script-executor.yml"
147
+ ".github/workflows/rebuild-docs-indexes.yml"
148
+ ".github/workflows/setup-project-v2.yml"
149
+ ".github/workflows/sync-docs-to-project.yml"
150
+ ".github/workflows/release.yml"
151
+ ".github/workflows/sync-changelogs.yml"
152
+ ".github/workflows/version_branch.yml"
153
+ "update.json"
154
+ ".github/workflows/auto-version-branch.yml"
155
+ ".github/workflows/publish-to-mokodolibarr.yml"
156
+ ".github/workflows/ci.yml"
157
+ ".github/workflows/deploy-rs.yml"
158
+ "sftp-config.json"
159
+ "sftp-config.json.template"
160
+ "scripts/sftp-config"
161
+ )
162
+
163
+ DELETED=0
164
+ for wf in "${RETIRED[@]}"; do
165
+ if [ -f "$wf" ]; then
166
+ git rm "$wf" 2>/dev/null || rm -f "$wf"
167
+ echo " Deleted: \`$(basename $wf)\`" >> $GITHUB_STEP_SUMMARY
168
+ DELETED=$((DELETED+1))
169
+ fi
170
+ done
171
+
172
+ if [ "$DELETED" -gt 0 ]; then
173
+ git config --local user.email "github-actions[bot]@users.noreply.github.com"
174
+ git config --local user.name "github-actions[bot]"
175
+ git add -A
176
+ git commit -m "chore: delete ${DELETED} retired workflow file(s) [skip ci]" \
177
+ --author="github-actions[bot] <github-actions[bot]@users.noreply.github.com>"
178
+ git push
179
+ echo "✅ ${DELETED} retired workflow(s) deleted" >> $GITHUB_STEP_SUMMARY
180
+ else
181
+ echo "✅ No retired workflows found" >> $GITHUB_STEP_SUMMARY
182
+ fi
183
+
184
+ # ── LABEL RESET ──────────────────────────────────────────────────────
185
+ - name: Reset labels to standard set
186
+ if: steps.tasks.outputs.reset_labels == 'true'
187
+ env:
188
+ GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
189
+ run: |
190
+ REPO="${{ github.repository }}"
191
+ echo "## 🏷️ Label Reset" >> $GITHUB_STEP_SUMMARY
192
+ echo "" >> $GITHUB_STEP_SUMMARY
193
+
194
+ gh api "repos/${REPO}/labels?per_page=100" --paginate --jq '.[].name' | while read -r label; do
195
+ ENCODED=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$label', safe=''))")
196
+ gh api -X DELETE "repos/${REPO}/labels/${ENCODED}" --silent 2>/dev/null || true
197
+ done
198
+
199
+ while IFS='|' read -r name color description; do
200
+ [ -z "$name" ] && continue
201
+ gh api "repos/${REPO}/labels" \
202
+ -f name="$name" -f color="$color" -f description="$description" \
203
+ --silent 2>/dev/null || true
204
+ done << 'LABELS'
205
+ joomla|7F52FF|Joomla extension or component
206
+ dolibarr|FF6B6B|Dolibarr module or extension
207
+ generic|808080|Generic project or library
208
+ php|4F5D95|PHP code changes
209
+ javascript|F7DF1E|JavaScript code changes
210
+ typescript|3178C6|TypeScript code changes
211
+ python|3776AB|Python code changes
212
+ css|1572B6|CSS/styling changes
213
+ html|E34F26|HTML template changes
214
+ documentation|0075CA|Documentation changes
215
+ ci-cd|000000|CI/CD pipeline changes
216
+ docker|2496ED|Docker configuration changes
217
+ tests|00FF00|Test suite changes
218
+ security|FF0000|Security-related changes
219
+ dependencies|0366D6|Dependency updates
220
+ config|F9D0C4|Configuration file changes
221
+ build|FFA500|Build system changes
222
+ automation|8B4513|Automated processes or scripts
223
+ mokostandards|B60205|MokoStandards compliance
224
+ needs-review|FBCA04|Awaiting code review
225
+ work-in-progress|D93F0B|Work in progress, not ready for merge
226
+ breaking-change|D73A4A|Breaking API or functionality change
227
+ priority: critical|B60205|Critical priority, must be addressed immediately
228
+ priority: high|D93F0B|High priority
229
+ priority: medium|FBCA04|Medium priority
230
+ priority: low|0E8A16|Low priority
231
+ type: bug|D73A4A|Something isn't working
232
+ type: feature|A2EEEF|New feature or request
233
+ type: enhancement|84B6EB|Enhancement to existing feature
234
+ type: refactor|F9D0C4|Code refactoring
235
+ type: chore|FEF2C0|Maintenance tasks
236
+ type: version|0E8A16|Version-related change
237
+ status: pending|FBCA04|Pending action or decision
238
+ status: in-progress|0E8A16|Currently being worked on
239
+ status: blocked|B60205|Blocked by another issue or dependency
240
+ status: on-hold|D4C5F9|Temporarily on hold
241
+ status: wontfix|FFFFFF|This will not be worked on
242
+ size/xs|C5DEF5|Extra small change (1-10 lines)
243
+ size/s|6FD1E2|Small change (11-30 lines)
244
+ size/m|F9DD72|Medium change (31-100 lines)
245
+ size/l|FFA07A|Large change (101-300 lines)
246
+ size/xl|FF6B6B|Extra large change (301-1000 lines)
247
+ size/xxl|B60205|Extremely large change (1000+ lines)
248
+ health: excellent|0E8A16|Health score 90-100
249
+ health: good|FBCA04|Health score 70-89
250
+ health: fair|FFA500|Health score 50-69
251
+ health: poor|FF6B6B|Health score below 50
252
+ standards-update|B60205|MokoStandards sync update
253
+ standards-drift|FBCA04|Repository drifted from MokoStandards
254
+ sync-report|0075CA|Bulk sync run report
255
+ sync-failure|D73A4A|Bulk sync failure requiring attention
256
+ push-failure|D73A4A|File push failure requiring attention
257
+ health-check|0E8A16|Repository health check results
258
+ version-drift|FFA500|Version mismatch detected
259
+ deploy-failure|CC0000|Automated deploy failure tracking
260
+ template-validation-failure|D73A4A|Template workflow validation failure
261
+ version|0E8A16|Version bump or release
262
+ LABELS
263
+
264
+ echo "✅ Standard labels created" >> $GITHUB_STEP_SUMMARY
265
+
266
+ # ── BRANCH CLEANUP ───────────────────────────────────────────────────
267
+ - name: Delete old sync branches
268
+ if: steps.tasks.outputs.clean_branches == 'true'
269
+ env:
270
+ GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
271
+ run: |
272
+ REPO="${{ github.repository }}"
273
+ CURRENT="chore/sync-mokostandards-v04.05"
274
+ echo "## 🌿 Branch Cleanup" >> $GITHUB_STEP_SUMMARY
275
+ echo "" >> $GITHUB_STEP_SUMMARY
276
+
277
+ FOUND=false
278
+ gh api "repos/${REPO}/branches?per_page=100" --jq '.[].name' | \
279
+ grep "^chore/sync-mokostandards" | \
280
+ grep -v "^${CURRENT}$" | while read -r branch; do
281
+ gh pr list --repo "$REPO" --head "$branch" --state open --json number --jq '.[].number' 2>/dev/null | while read -r pr; do
282
+ gh pr close "$pr" --repo "$REPO" --comment "Superseded by \`${CURRENT}\`" 2>/dev/null || true
283
+ echo " Closed PR #${pr}" >> $GITHUB_STEP_SUMMARY
284
+ done
285
+ gh api -X DELETE "repos/${REPO}/git/refs/heads/${branch}" --silent 2>/dev/null || true
286
+ echo " Deleted: \`${branch}\`" >> $GITHUB_STEP_SUMMARY
287
+ FOUND=true
288
+ done
289
+
290
+ if [ "$FOUND" != "true" ]; then
291
+ echo "✅ No old sync branches found" >> $GITHUB_STEP_SUMMARY
292
+ fi
293
+
294
+ # ── WORKFLOW RUN CLEANUP ─────────────────────────────────────────────
295
+ - name: Clean up workflow runs
296
+ if: steps.tasks.outputs.clean_workflows == 'true'
297
+ env:
298
+ GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
299
+ run: |
300
+ REPO="${{ github.repository }}"
301
+ echo "## 🔄 Workflow Run Cleanup" >> $GITHUB_STEP_SUMMARY
302
+ echo "" >> $GITHUB_STEP_SUMMARY
303
+
304
+ DELETED=0
305
+ # Delete cancelled and stale workflow runs
306
+ for status in cancelled stale; do
307
+ gh api "repos/${REPO}/actions/runs?status=${status}&per_page=100" \
308
+ --jq '.workflow_runs[].id' 2>/dev/null | while read -r run_id; do
309
+ gh api -X DELETE "repos/${REPO}/actions/runs/${run_id}" --silent 2>/dev/null || true
310
+ DELETED=$((DELETED+1))
311
+ done
312
+ done
313
+
314
+ echo "✅ Cleaned cancelled/stale workflow runs" >> $GITHUB_STEP_SUMMARY
315
+
316
+ # ── LOG CLEANUP ──────────────────────────────────────────────────────
317
+ - name: Delete old workflow run logs
318
+ if: steps.tasks.outputs.clean_logs == 'true'
319
+ env:
320
+ GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
321
+ run: |
322
+ REPO="${{ github.repository }}"
323
+ CUTOFF=$(date -u -d '30 days ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-30d +%Y-%m-%dT%H:%M:%SZ)
324
+ echo "## 📋 Log Cleanup" >> $GITHUB_STEP_SUMMARY
325
+ echo "" >> $GITHUB_STEP_SUMMARY
326
+ echo "Deleting logs older than: ${CUTOFF}" >> $GITHUB_STEP_SUMMARY
327
+
328
+ DELETED=0
329
+ gh api "repos/${REPO}/actions/runs?created=<${CUTOFF}&per_page=100" \
330
+ --jq '.workflow_runs[].id' 2>/dev/null | while read -r run_id; do
331
+ gh api -X DELETE "repos/${REPO}/actions/runs/${run_id}/logs" --silent 2>/dev/null || true
332
+ DELETED=$((DELETED+1))
333
+ done
334
+
335
+ echo "✅ Cleaned old workflow run logs" >> $GITHUB_STEP_SUMMARY
336
+
337
+ # ── ISSUE TEMPLATE FIX ──────────────────────────────────────────────
338
+ - name: Strip copyright headers from issue templates
339
+ if: steps.tasks.outputs.fix_templates == 'true'
340
+ run: |
341
+ echo "## 📋 Issue Template Cleanup" >> $GITHUB_STEP_SUMMARY
342
+ echo "" >> $GITHUB_STEP_SUMMARY
343
+
344
+ FIXED=0
345
+ for f in .github/ISSUE_TEMPLATE/*.md; do
346
+ [ -f "$f" ] || continue
347
+ if grep -q '^<!--$' "$f"; then
348
+ sed -i '/^<!--$/,/^-->$/d' "$f"
349
+ echo " Cleaned: \`$(basename $f)\`" >> $GITHUB_STEP_SUMMARY
350
+ FIXED=$((FIXED+1))
351
+ fi
352
+ done
353
+
354
+ if [ "$FIXED" -gt 0 ]; then
355
+ git config --local user.email "github-actions[bot]@users.noreply.github.com"
356
+ git config --local user.name "github-actions[bot]"
357
+ git add .github/ISSUE_TEMPLATE/
358
+ git commit -m "fix: strip copyright comment blocks from issue templates [skip ci]" \
359
+ --author="github-actions[bot] <github-actions[bot]@users.noreply.github.com>"
360
+ git push
361
+ echo "✅ ${FIXED} template(s) cleaned and committed" >> $GITHUB_STEP_SUMMARY
362
+ else
363
+ echo "✅ No templates need cleaning" >> $GITHUB_STEP_SUMMARY
364
+ fi
365
+
366
+ # ── REBUILD DOC INDEXES ─────────────────────────────────────────────
367
+ - name: Rebuild docs/ index files
368
+ if: steps.tasks.outputs.rebuild_indexes == 'true'
369
+ run: |
370
+ echo "## 📚 Documentation Index Rebuild" >> $GITHUB_STEP_SUMMARY
371
+ echo "" >> $GITHUB_STEP_SUMMARY
372
+
373
+ if [ ! -d "docs" ]; then
374
+ echo "⏭️ No docs/ directory — skipping" >> $GITHUB_STEP_SUMMARY
375
+ exit 0
376
+ fi
377
+
378
+ UPDATED=0
379
+ # Generate index.md for each docs/ subdirectory
380
+ find docs -type d | while read -r dir; do
381
+ INDEX="${dir}/index.md"
382
+ FILES=$(find "$dir" -maxdepth 1 -name "*.md" ! -name "index.md" -printf "- [%f](./%f)\n" 2>/dev/null | sort)
383
+ if [ -z "$FILES" ]; then
384
+ continue
385
+ fi
386
+
387
+ cat > "$INDEX" << INDEXEOF
388
+ # $(basename "$dir")
389
+
390
+ ## Documents
391
+
392
+ ${FILES}
393
+
394
+ ---
395
+ *Auto-generated by repository-cleanup workflow*
396
+ INDEXEOF
397
+ # Dedent
398
+ sed -i 's/^ //' "$INDEX"
399
+ UPDATED=$((UPDATED+1))
400
+ done
401
+
402
+ if [ "$UPDATED" -gt 0 ]; then
403
+ git config --local user.email "github-actions[bot]@users.noreply.github.com"
404
+ git config --local user.name "github-actions[bot]"
405
+ git add docs/
406
+ if ! git diff --cached --quiet; then
407
+ git commit -m "docs: rebuild documentation indexes [skip ci]" \
408
+ --author="github-actions[bot] <github-actions[bot]@users.noreply.github.com>"
409
+ git push
410
+ echo "✅ ${UPDATED} index file(s) rebuilt and committed" >> $GITHUB_STEP_SUMMARY
411
+ else
412
+ echo "✅ All indexes already up to date" >> $GITHUB_STEP_SUMMARY
413
+ fi
414
+ else
415
+ echo "✅ No indexes to rebuild" >> $GITHUB_STEP_SUMMARY
416
+ fi
417
+
418
+ # ── VERSION DRIFT DETECTION ──────────────────────────────────────────
419
+ - name: Check for version drift
420
+ run: |
421
+ echo "## 📦 Version Drift Check" >> $GITHUB_STEP_SUMMARY
422
+ echo "" >> $GITHUB_STEP_SUMMARY
423
+
424
+ if [ ! -f "README.md" ]; then
425
+ echo "⏭️ No README.md — skipping" >> $GITHUB_STEP_SUMMARY
426
+ exit 0
427
+ fi
428
+
429
+ README_VERSION=$(grep -oP '^\s*VERSION:\s*\K[0-9]{2}\.[0-9]{2}\.[0-9]{2}' README.md 2>/dev/null | head -1)
430
+ if [ -z "$README_VERSION" ]; then
431
+ echo "⚠️ No VERSION found in README.md FILE INFORMATION block" >> $GITHUB_STEP_SUMMARY
432
+ exit 0
433
+ fi
434
+
435
+ echo "**README version:** \`${README_VERSION}\`" >> $GITHUB_STEP_SUMMARY
436
+ echo "" >> $GITHUB_STEP_SUMMARY
437
+
438
+ DRIFT=0
439
+ CHECKED=0
440
+
441
+ # Check all files with FILE INFORMATION blocks
442
+ while IFS= read -r -d '' file; do
443
+ FILE_VERSION=$(grep -oP '^\s*\*?\s*VERSION:\s*\K[0-9]{2}\.[0-9]{2}\.[0-9]{2}' "$file" 2>/dev/null | head -1)
444
+ [ -z "$FILE_VERSION" ] && continue
445
+ CHECKED=$((CHECKED+1))
446
+ if [ "$FILE_VERSION" != "$README_VERSION" ]; then
447
+ echo " ⚠️ \`${file}\`: \`${FILE_VERSION}\` (expected \`${README_VERSION}\`)" >> $GITHUB_STEP_SUMMARY
448
+ DRIFT=$((DRIFT+1))
449
+ fi
450
+ done < <(find . -maxdepth 4 -type f \( -name "*.php" -o -name "*.md" -o -name "*.yml" \) ! -path "./.git/*" ! -path "./vendor/*" ! -path "./node_modules/*" -print0 2>/dev/null)
451
+
452
+ echo "" >> $GITHUB_STEP_SUMMARY
453
+ if [ "$DRIFT" -gt 0 ]; then
454
+ echo "⚠️ **${DRIFT}** file(s) out of ${CHECKED} have version drift" >> $GITHUB_STEP_SUMMARY
455
+ echo "Run \`sync-version-on-merge\` workflow or update manually" >> $GITHUB_STEP_SUMMARY
456
+ else
457
+ echo "✅ All ${CHECKED} file(s) match README version \`${README_VERSION}\`" >> $GITHUB_STEP_SUMMARY
458
+ fi
459
+
460
+ # ── PROTECT CUSTOM WORKFLOWS ────────────────────────────────────────
461
+ - name: Ensure custom workflow directory exists
462
+ run: |
463
+ echo "## 🔧 Custom Workflows" >> $GITHUB_STEP_SUMMARY
464
+ echo "" >> $GITHUB_STEP_SUMMARY
465
+
466
+ if [ ! -d ".github/workflows/custom" ]; then
467
+ mkdir -p .github/workflows/custom
468
+ cat > .github/workflows/custom/README.md << 'CWEOF'
469
+ # Custom Workflows
470
+
471
+ Place repo-specific workflows here. Files in this directory are:
472
+ - **Never overwritten** by MokoStandards bulk sync
473
+ - **Never deleted** by the repository-cleanup workflow
474
+ - Safe for custom CI, notifications, or repo-specific automation
475
+
476
+ Synced workflows live in `.github/workflows/` (parent directory).
477
+ CWEOF
478
+ sed -i 's/^ //' .github/workflows/custom/README.md
479
+ git config --local user.email "github-actions[bot]@users.noreply.github.com"
480
+ git config --local user.name "github-actions[bot]"
481
+ git add .github/workflows/custom/
482
+ if ! git diff --cached --quiet; then
483
+ git commit -m "chore: create .github/workflows/custom/ for repo-specific workflows [skip ci]" \
484
+ --author="github-actions[bot] <github-actions[bot]@users.noreply.github.com>"
485
+ git push
486
+ echo "✅ Created \`.github/workflows/custom/\` directory" >> $GITHUB_STEP_SUMMARY
487
+ fi
488
+ else
489
+ CUSTOM_COUNT=$(find .github/workflows/custom -name "*.yml" -o -name "*.yaml" 2>/dev/null | wc -l)
490
+ echo "✅ Custom workflow directory exists (${CUSTOM_COUNT} workflow(s))" >> $GITHUB_STEP_SUMMARY
491
+ fi
492
+
493
+ # ── DELETE CLOSED ISSUES ──────────────────────────────────────────────
494
+ - name: Delete old closed issues
495
+ if: steps.tasks.outputs.delete_closed_issues == 'true'
496
+ env:
497
+ GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
498
+ run: |
499
+ REPO="${{ github.repository }}"
500
+ CUTOFF=$(date -u -d '30 days ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-30d +%Y-%m-%dT%H:%M:%SZ)
501
+ echo "## 🗑️ Closed Issue Cleanup" >> $GITHUB_STEP_SUMMARY
502
+ echo "" >> $GITHUB_STEP_SUMMARY
503
+ echo "Deleting issues closed before: ${CUTOFF}" >> $GITHUB_STEP_SUMMARY
504
+
505
+ DELETED=0
506
+ gh api "repos/${REPO}/issues?state=closed&since=1970-01-01T00:00:00Z&per_page=100&sort=updated&direction=asc" \
507
+ --jq ".[] | select(.closed_at < \"${CUTOFF}\") | .number" 2>/dev/null | while read -r num; do
508
+ # Lock and close with "not_planned" to mark as cleaned up
509
+ gh api "repos/${REPO}/issues/${num}/lock" -X PUT -f lock_reason="resolved" --silent 2>/dev/null || true
510
+ echo " Locked issue #${num}" >> $GITHUB_STEP_SUMMARY
511
+ DELETED=$((DELETED+1))
512
+ done
513
+
514
+ if [ "$DELETED" -eq 0 ] 2>/dev/null; then
515
+ echo "✅ No old closed issues found" >> $GITHUB_STEP_SUMMARY
516
+ else
517
+ echo "✅ Locked ${DELETED} old closed issue(s)" >> $GITHUB_STEP_SUMMARY
518
+ fi
519
+
520
+ - name: Summary
521
+ if: always()
522
+ run: |
523
+ echo "" >> $GITHUB_STEP_SUMMARY
524
+ echo "---" >> $GITHUB_STEP_SUMMARY
525
+ echo "*Run by @${{ github.actor }} — trigger: ${{ github.event_name }}*" >> $GITHUB_STEP_SUMMARY