@soulbatical/tetra-dev-toolkit 1.1.1 → 1.3.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.
- package/bin/cleanup-repos.sh +287 -0
- package/bin/{vca-audit.js → tetra-audit.js} +16 -12
- package/bin/{vca-dev-token.js → tetra-dev-token.js} +7 -7
- package/bin/{vca-setup.js → tetra-setup.js} +54 -20
- package/lib/checks/health/file-organization.js +389 -0
- package/lib/checks/health/index.js +1 -0
- package/lib/checks/health/quality-toolkit.js +12 -8
- package/lib/checks/health/repo-visibility.js +1 -1
- package/lib/checks/health/scanner.js +3 -1
- package/lib/checks/health/stella-integration.js +7 -7
- package/lib/checks/health/types.js +1 -1
- package/lib/checks/hygiene/file-organization.js +105 -0
- package/lib/checks/index.js +4 -0
- package/lib/checks/stability/ci-pipeline.js +1 -1
- package/lib/checks/stability/husky-hooks.js +1 -1
- package/lib/checks/supabase/rpc-param-mismatch.js +453 -0
- package/lib/commands/dev-token.js +4 -4
- package/lib/config.js +16 -12
- package/lib/index.js +3 -3
- package/lib/reporters/terminal.js +1 -1
- package/lib/runner.js +16 -3
- package/package.json +6 -8
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# Repo Cleanup Script — Verplaats alles naar de juiste plek
|
|
4
|
+
#
|
|
5
|
+
# Wat het doet:
|
|
6
|
+
# 1. Stray .md files → /docs/_moved/{oorspronkelijk-pad}/
|
|
7
|
+
# 2. Stray .sh scripts → /scripts/_moved/{oorspronkelijk-pad}/
|
|
8
|
+
# 3. Nested docs/ (frontend/docs/, backend/docs/) → /docs/{subdir-naam}/
|
|
9
|
+
# 4. Root clutter files (.txt, .png, .csv, .py) → /docs/_cleanup/
|
|
10
|
+
# 5. Code dir clutter (.txt, .log, .env) → /docs/_cleanup/{code-dir}/
|
|
11
|
+
# 6. Clutter dirs (tmp/, logs/, data/, etc.) → .gitignore
|
|
12
|
+
# 7. .env/.env.local in code dirs → verwijder (secrets horen niet in git)
|
|
13
|
+
#
|
|
14
|
+
# DRY RUN: standaard toont het alleen wat het zou doen.
|
|
15
|
+
# EXECUTE: ./cleanup-repos.sh --execute
|
|
16
|
+
# =============================================================================
|
|
17
|
+
|
|
18
|
+
set -euo pipefail
|
|
19
|
+
|
|
20
|
+
DRY_RUN=true
|
|
21
|
+
[[ "${1:-}" == "--execute" ]] && DRY_RUN=false
|
|
22
|
+
|
|
23
|
+
BASE="$HOME/projecten"
|
|
24
|
+
PROJECTS=(sparkbuddy-live agentrook ralph-manager vincifox snelstart-mcp web-mcp)
|
|
25
|
+
|
|
26
|
+
# Colors
|
|
27
|
+
RED='\033[0;31m'
|
|
28
|
+
GREEN='\033[0;32m'
|
|
29
|
+
YELLOW='\033[1;33m'
|
|
30
|
+
BLUE='\033[0;34m'
|
|
31
|
+
NC='\033[0m'
|
|
32
|
+
|
|
33
|
+
# Counters
|
|
34
|
+
TOTAL_MOVED=0
|
|
35
|
+
TOTAL_GITIGNORED=0
|
|
36
|
+
TOTAL_DELETED=0
|
|
37
|
+
|
|
38
|
+
lower() { echo "$1" | tr '[:upper:]' '[:lower:]'; }
|
|
39
|
+
|
|
40
|
+
log() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
|
41
|
+
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
|
42
|
+
action() { echo -e "${GREEN}[MOVE]${NC} $1"; }
|
|
43
|
+
danger() { echo -e "${RED}[DEL]${NC} $1"; }
|
|
44
|
+
|
|
45
|
+
safe_move() {
|
|
46
|
+
local src="$1" dst="$2"
|
|
47
|
+
|
|
48
|
+
if $DRY_RUN; then
|
|
49
|
+
action "$src → $dst"
|
|
50
|
+
else
|
|
51
|
+
mkdir -p "$(dirname "$PROJECT_PATH/$dst")"
|
|
52
|
+
mv "$PROJECT_PATH/$src" "$PROJECT_PATH/$dst"
|
|
53
|
+
fi
|
|
54
|
+
TOTAL_MOVED=$((TOTAL_MOVED + 1))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
safe_delete() {
|
|
58
|
+
local target="$1"
|
|
59
|
+
if $DRY_RUN; then
|
|
60
|
+
danger "DELETE $target"
|
|
61
|
+
else
|
|
62
|
+
rm -f "$target"
|
|
63
|
+
fi
|
|
64
|
+
TOTAL_DELETED=$((TOTAL_DELETED + 1))
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
add_gitignore() {
|
|
68
|
+
local project_path="$1" entry="$2"
|
|
69
|
+
local gitignore="$project_path/.gitignore"
|
|
70
|
+
|
|
71
|
+
if [ -f "$gitignore" ] && grep -qF "$entry" "$gitignore" 2>/dev/null; then
|
|
72
|
+
return
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
if $DRY_RUN; then
|
|
76
|
+
log "Add to .gitignore: $entry"
|
|
77
|
+
else
|
|
78
|
+
echo "$entry" >> "$gitignore"
|
|
79
|
+
fi
|
|
80
|
+
TOTAL_GITIGNORED=$((TOTAL_GITIGNORED + 1))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
is_allowed_root_md() {
|
|
84
|
+
local name_lc
|
|
85
|
+
name_lc=$(lower "$1")
|
|
86
|
+
case "$name_lc" in
|
|
87
|
+
readme.md|claude.md|changelog.md|license.md|prompt.md|plan.md|contributing.md|code_of_conduct.md)
|
|
88
|
+
return 0 ;;
|
|
89
|
+
*) return 1 ;;
|
|
90
|
+
esac
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
# =============================================================================
|
|
94
|
+
# Main cleanup per project
|
|
95
|
+
# =============================================================================
|
|
96
|
+
|
|
97
|
+
for PROJECT in "${PROJECTS[@]}"; do
|
|
98
|
+
PROJECT_PATH="$BASE/$PROJECT"
|
|
99
|
+
[ -d "$PROJECT_PATH" ] || continue
|
|
100
|
+
|
|
101
|
+
echo ""
|
|
102
|
+
echo "================================================================"
|
|
103
|
+
echo -e "${BLUE}=== $PROJECT ===${NC}"
|
|
104
|
+
echo "================================================================"
|
|
105
|
+
|
|
106
|
+
# --- 1. Nested docs/ → merge into /docs/{subdir-naam}/ (FIRST, before stray .md scan) ---
|
|
107
|
+
log "Checking nested docs/ directories..."
|
|
108
|
+
for subdir in frontend backend backend-mcp backend-pdf mcp shell; do
|
|
109
|
+
nested_docs="$PROJECT_PATH/$subdir/docs"
|
|
110
|
+
[ -d "$nested_docs" ] || continue
|
|
111
|
+
|
|
112
|
+
file_count=$(find "$nested_docs" -type f 2>/dev/null | wc -l | tr -d ' ')
|
|
113
|
+
[[ "$file_count" == "0" ]] && continue
|
|
114
|
+
|
|
115
|
+
log "Moving $subdir/docs/ ($file_count files) → docs/$subdir/"
|
|
116
|
+
while IFS= read -r -d '' file; do
|
|
117
|
+
rel_from_nested="${file#$nested_docs/}"
|
|
118
|
+
safe_move "$subdir/docs/$rel_from_nested" "docs/$subdir/$rel_from_nested"
|
|
119
|
+
done < <(find "$nested_docs" -type f -print0 2>/dev/null)
|
|
120
|
+
done
|
|
121
|
+
|
|
122
|
+
# --- 2. Stray .md files → /docs/_moved/ ---
|
|
123
|
+
log "Checking stray .md files..."
|
|
124
|
+
while IFS= read -r -d '' file; do
|
|
125
|
+
rel="${file#$PROJECT_PATH/}"
|
|
126
|
+
name=$(basename "$file")
|
|
127
|
+
name_lc=$(lower "$name")
|
|
128
|
+
top_dir="${rel%%/*}"
|
|
129
|
+
|
|
130
|
+
# Skip README.md and CLAUDE.md anywhere (standard practice)
|
|
131
|
+
case "$name_lc" in
|
|
132
|
+
readme.md|claude.md) continue ;;
|
|
133
|
+
esac
|
|
134
|
+
|
|
135
|
+
# Skip root allowed .md files
|
|
136
|
+
[[ "$rel" == "$name" ]] && is_allowed_root_md "$name" && continue
|
|
137
|
+
|
|
138
|
+
# Skip /docs/, .ralph/, .claude/, .agents/, e2e/
|
|
139
|
+
case "$top_dir" in
|
|
140
|
+
docs|.ralph|.claude|.agents|e2e) continue ;;
|
|
141
|
+
esac
|
|
142
|
+
|
|
143
|
+
# Skip shell/templates/
|
|
144
|
+
[[ "$rel" == shell/templates/* ]] && continue
|
|
145
|
+
|
|
146
|
+
# Skip files already handled by nested docs merge (avoid double-move)
|
|
147
|
+
[[ "$rel" == */docs/* ]] && continue
|
|
148
|
+
|
|
149
|
+
safe_move "$rel" "docs/_moved/$rel"
|
|
150
|
+
done < <(find "$PROJECT_PATH" -maxdepth 5 -name "*.md" -type f \
|
|
151
|
+
-not -path "*/node_modules/*" -not -path "*/.git/*" -not -path "*/dist/*" \
|
|
152
|
+
-not -path "*/.next/*" -not -path "*/coverage/*" -print0 2>/dev/null)
|
|
153
|
+
|
|
154
|
+
# --- 3. Stray .sh scripts → /scripts/_moved/ ---
|
|
155
|
+
log "Checking stray .sh scripts..."
|
|
156
|
+
while IFS= read -r -d '' file; do
|
|
157
|
+
rel="${file#$PROJECT_PATH/}"
|
|
158
|
+
top_dir="${rel%%/*}"
|
|
159
|
+
|
|
160
|
+
# Skip root-level scripts
|
|
161
|
+
[[ "$rel" != */* ]] && continue
|
|
162
|
+
|
|
163
|
+
# Skip allowed dirs
|
|
164
|
+
case "$top_dir" in
|
|
165
|
+
scripts|shell|hooks|.husky|.ralph|.claude) continue ;;
|
|
166
|
+
esac
|
|
167
|
+
|
|
168
|
+
safe_move "$rel" "scripts/_moved/$rel"
|
|
169
|
+
done < <(find "$PROJECT_PATH" -maxdepth 5 -name "*.sh" -type f \
|
|
170
|
+
-not -path "*/node_modules/*" -not -path "*/.git/*" -not -path "*/dist/*" \
|
|
171
|
+
-print0 2>/dev/null)
|
|
172
|
+
|
|
173
|
+
# --- 4. Root clutter files → /docs/_cleanup/ ---
|
|
174
|
+
log "Checking root clutter..."
|
|
175
|
+
for file in "$PROJECT_PATH"/*; do
|
|
176
|
+
[ -f "$file" ] || continue
|
|
177
|
+
name=$(basename "$file")
|
|
178
|
+
name_lc=$(lower "$name")
|
|
179
|
+
|
|
180
|
+
# Skip dotfiles
|
|
181
|
+
[[ "$name" == .* ]] && continue
|
|
182
|
+
|
|
183
|
+
# Skip known config extensions and types handled by other checks
|
|
184
|
+
case "$name_lc" in
|
|
185
|
+
*.json|*.js|*.cjs|*.mjs|*.ts|*.toml|*.lock) continue ;;
|
|
186
|
+
*.md|*.sh|*.yml|*.yaml) continue ;;
|
|
187
|
+
dockerfile*|procfile) continue ;;
|
|
188
|
+
esac
|
|
189
|
+
|
|
190
|
+
# Check for clutter extensions
|
|
191
|
+
ext=".${name_lc##*.}"
|
|
192
|
+
case "$ext" in
|
|
193
|
+
.txt|.log|.pdf|.csv|.png|.jpg|.jpeg|.gif|.py|.bak|.tmp|.orig|.patch|.diff)
|
|
194
|
+
safe_move "$name" "docs/_cleanup/$name"
|
|
195
|
+
;;
|
|
196
|
+
esac
|
|
197
|
+
done
|
|
198
|
+
|
|
199
|
+
# --- 5. Code dir clutter → /docs/_cleanup/{code-dir}/ ---
|
|
200
|
+
log "Checking code dir clutter..."
|
|
201
|
+
for codeDir in backend frontend backend-mcp backend-pdf mcp; do
|
|
202
|
+
code_path="$PROJECT_PATH/$codeDir"
|
|
203
|
+
[ -d "$code_path" ] || continue
|
|
204
|
+
|
|
205
|
+
while IFS= read -r -d '' file; do
|
|
206
|
+
name=$(basename "$file")
|
|
207
|
+
name_lc=$(lower "$name")
|
|
208
|
+
rel="${file#$PROJECT_PATH/}"
|
|
209
|
+
rel_from_code="${file#$code_path/}"
|
|
210
|
+
sub_top="${rel_from_code%%/*}"
|
|
211
|
+
|
|
212
|
+
# Skip allowed subdirs
|
|
213
|
+
case "$sub_top" in
|
|
214
|
+
public|static|assets|fixtures|supabase|migrations|prisma|test-fixtures) continue ;;
|
|
215
|
+
esac
|
|
216
|
+
|
|
217
|
+
# .env files → DELETE (secrets!)
|
|
218
|
+
case "$name_lc" in
|
|
219
|
+
.env|.env.local|.env.development|.env.production|.env.staging)
|
|
220
|
+
danger "SECRET: $rel"
|
|
221
|
+
safe_delete "$file"
|
|
222
|
+
continue
|
|
223
|
+
;;
|
|
224
|
+
esac
|
|
225
|
+
|
|
226
|
+
# Skip templates
|
|
227
|
+
case "$name_lc" in
|
|
228
|
+
*.example|*.test) continue ;;
|
|
229
|
+
esac
|
|
230
|
+
|
|
231
|
+
# Skip standard web files
|
|
232
|
+
case "$name_lc" in
|
|
233
|
+
robots.txt|llms.txt|llms-full.txt|humans.txt|security.txt|ads.txt) continue ;;
|
|
234
|
+
esac
|
|
235
|
+
|
|
236
|
+
# Check for clutter extensions
|
|
237
|
+
ext=".${name_lc##*.}"
|
|
238
|
+
case "$ext" in
|
|
239
|
+
.txt|.log|.pdf|.csv|.bak|.tmp|.orig|.patch|.diff)
|
|
240
|
+
safe_move "$rel" "docs/_cleanup/$rel"
|
|
241
|
+
;;
|
|
242
|
+
esac
|
|
243
|
+
done < <(find "$code_path" -maxdepth 4 -type f \
|
|
244
|
+
-not -path "*/node_modules/*" -not -path "*/dist/*" -not -path "*/.next/*" \
|
|
245
|
+
-not -path "*/coverage/*" -not -path "*/.turbo/*" -not -path "*/test-results/*" \
|
|
246
|
+
\( -name "*.txt" -o -name "*.log" -o -name "*.pdf" -o -name "*.csv" \
|
|
247
|
+
-o -name "*.bak" -o -name "*.tmp" -o -name "*.orig" \
|
|
248
|
+
-o -name ".env" -o -name ".env.*" \) -print0 2>/dev/null)
|
|
249
|
+
done
|
|
250
|
+
|
|
251
|
+
# --- 6. Clutter dirs → .gitignore ---
|
|
252
|
+
log "Checking clutter directories..."
|
|
253
|
+
for dir_name in tmp temp logs log data venv .venv reports output out backup backups; do
|
|
254
|
+
if [ -d "$PROJECT_PATH/$dir_name" ]; then
|
|
255
|
+
add_gitignore "$PROJECT_PATH" "$dir_name/"
|
|
256
|
+
warn "Directory $dir_name/ → added to .gitignore"
|
|
257
|
+
fi
|
|
258
|
+
done
|
|
259
|
+
|
|
260
|
+
done
|
|
261
|
+
|
|
262
|
+
# =============================================================================
|
|
263
|
+
# Summary
|
|
264
|
+
# =============================================================================
|
|
265
|
+
|
|
266
|
+
echo ""
|
|
267
|
+
echo "================================================================"
|
|
268
|
+
if $DRY_RUN; then
|
|
269
|
+
echo -e "${YELLOW}DRY RUN COMPLETE${NC}"
|
|
270
|
+
echo " Files to move: $TOTAL_MOVED"
|
|
271
|
+
echo " Files to delete: $TOTAL_DELETED"
|
|
272
|
+
echo " Gitignore entries: $TOTAL_GITIGNORED"
|
|
273
|
+
echo ""
|
|
274
|
+
echo "Run with --execute to apply changes:"
|
|
275
|
+
echo " bash cleanup-repos.sh --execute"
|
|
276
|
+
else
|
|
277
|
+
echo -e "${GREEN}CLEANUP COMPLETE${NC}"
|
|
278
|
+
echo " Files moved: $TOTAL_MOVED"
|
|
279
|
+
echo " Files deleted: $TOTAL_DELETED"
|
|
280
|
+
echo " Gitignore entries: $TOTAL_GITIGNORED"
|
|
281
|
+
echo ""
|
|
282
|
+
echo "Next steps:"
|
|
283
|
+
echo " 1. Review /docs/_moved/ and /docs/_cleanup/ per project"
|
|
284
|
+
echo " 2. Delete what you don't need, keep what's useful"
|
|
285
|
+
echo " 3. git add + commit per project"
|
|
286
|
+
fi
|
|
287
|
+
echo "================================================================"
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Tetra Dev Toolkit - Main CLI
|
|
5
5
|
*
|
|
6
6
|
* Usage:
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
7
|
+
* tetra-audit # Run all checks
|
|
8
|
+
* tetra-audit security # Run security checks only
|
|
9
|
+
* tetra-audit stability # Run stability checks only
|
|
10
|
+
* tetra-audit hygiene # Run repo hygiene checks only
|
|
11
|
+
* tetra-audit quick # Run quick critical checks
|
|
12
|
+
* tetra-audit --ci # CI mode (GitHub Actions annotations)
|
|
13
|
+
* tetra-audit --json # JSON output
|
|
13
14
|
*/
|
|
14
15
|
|
|
15
16
|
import { program } from 'commander'
|
|
16
|
-
import { runAllChecks, runSecurityChecks, runStabilityChecks, runCodeQualityChecks, runQuickCheck } from '../lib/runner.js'
|
|
17
|
+
import { runAllChecks, runSecurityChecks, runStabilityChecks, runCodeQualityChecks, runHygieneChecks, runQuickCheck } from '../lib/runner.js'
|
|
17
18
|
import { formatResults, formatGitHubActions } from '../lib/reporters/terminal.js'
|
|
18
19
|
|
|
19
20
|
program
|
|
20
|
-
.name('
|
|
21
|
-
.description('
|
|
22
|
-
.version('1.
|
|
21
|
+
.name('tetra-audit')
|
|
22
|
+
.description('Tetra Dev Toolkit - Unified quality checks for all projects')
|
|
23
|
+
.version('1.2.0')
|
|
23
24
|
.argument('[suite]', 'Check suite to run: security, stability, quick, or all (default)')
|
|
24
25
|
.option('--ci', 'CI mode - output GitHub Actions annotations')
|
|
25
26
|
.option('--json', 'Output results as JSON')
|
|
@@ -40,6 +41,9 @@ program
|
|
|
40
41
|
case 'code-quality':
|
|
41
42
|
results = await runCodeQualityChecks()
|
|
42
43
|
break
|
|
44
|
+
case 'hygiene':
|
|
45
|
+
results = await runHygieneChecks()
|
|
46
|
+
break
|
|
43
47
|
case 'quick':
|
|
44
48
|
results = await runQuickCheck()
|
|
45
49
|
break
|
|
@@ -56,7 +60,7 @@ program
|
|
|
56
60
|
|
|
57
61
|
// Also print summary
|
|
58
62
|
console.log('')
|
|
59
|
-
console.log('##
|
|
63
|
+
console.log('## Tetra Quality Audit Results')
|
|
60
64
|
console.log('')
|
|
61
65
|
console.log(`- **Status**: ${results.passed ? '✅ PASSED' : '❌ FAILED'}`)
|
|
62
66
|
console.log(`- **Checks**: ${results.summary.passed} passed, ${results.summary.failed} failed`)
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Tetra Dev Toolkit - Dev Token CLI
|
|
5
5
|
*
|
|
6
6
|
* Manage Supabase dev tokens for API testing.
|
|
7
7
|
* Auto-detects project from package.json, finds Supabase config from .env files.
|
|
8
8
|
*
|
|
9
9
|
* Usage:
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* tetra-dev-token # Auto-refresh or show status
|
|
11
|
+
* tetra-dev-token --login # Interactive login (prompts for password)
|
|
12
|
+
* tetra-dev-token --status # Show current token status
|
|
13
|
+
* tetra-dev-token --project myapp # Override project detection
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { program } from 'commander'
|
|
17
17
|
import { runDevToken } from '../lib/commands/dev-token.js'
|
|
18
18
|
|
|
19
19
|
program
|
|
20
|
-
.name('
|
|
20
|
+
.name('tetra-dev-token')
|
|
21
21
|
.description('Manage Supabase dev tokens for API testing')
|
|
22
|
-
.version('1.
|
|
22
|
+
.version('1.2.0')
|
|
23
23
|
.option('--login', 'Interactive login (prompts for email/password)')
|
|
24
24
|
.option('--status', 'Show current token status')
|
|
25
25
|
.option('--project <name>', 'Override auto-detected project slug')
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Tetra Dev Toolkit - Setup CLI
|
|
5
5
|
*
|
|
6
6
|
* Sets up quality infrastructure in a project:
|
|
7
7
|
* - Husky pre-commit hooks
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
* - Configuration file
|
|
10
10
|
*
|
|
11
11
|
* Usage:
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* tetra-setup # Interactive setup
|
|
13
|
+
* tetra-setup hooks # Setup Husky hooks only
|
|
14
|
+
* tetra-setup ci # Setup GitHub Actions only
|
|
15
|
+
* tetra-setup config # Create .tetra-quality.json
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { program } from 'commander'
|
|
@@ -23,14 +23,14 @@ import { join } from 'path'
|
|
|
23
23
|
const projectRoot = process.cwd()
|
|
24
24
|
|
|
25
25
|
program
|
|
26
|
-
.name('
|
|
27
|
-
.description('Setup
|
|
28
|
-
.version('1.
|
|
26
|
+
.name('tetra-setup')
|
|
27
|
+
.description('Setup Tetra Dev Toolkit in your project')
|
|
28
|
+
.version('1.2.0')
|
|
29
29
|
.argument('[component]', 'Component to setup: hooks, ci, config, or all (default)')
|
|
30
30
|
.option('-f, --force', 'Overwrite existing files')
|
|
31
31
|
.action(async (component, options) => {
|
|
32
32
|
console.log('')
|
|
33
|
-
console.log('🔧
|
|
33
|
+
console.log('🔧 Tetra Dev Toolkit - Setup')
|
|
34
34
|
console.log('═'.repeat(50))
|
|
35
35
|
console.log('')
|
|
36
36
|
|
|
@@ -58,7 +58,7 @@ program
|
|
|
58
58
|
console.log('✅ Setup complete!')
|
|
59
59
|
console.log('')
|
|
60
60
|
console.log('Next steps:')
|
|
61
|
-
console.log(' 1. Run `
|
|
61
|
+
console.log(' 1. Run `tetra-audit` to check your project')
|
|
62
62
|
console.log(' 2. Commit the generated files')
|
|
63
63
|
console.log(' 3. Push to trigger CI checks')
|
|
64
64
|
console.log('')
|
|
@@ -95,14 +95,14 @@ async function setupHooks(options) {
|
|
|
95
95
|
const preCommitContent = `#!/bin/sh
|
|
96
96
|
. "$(dirname "$0")/_/husky.sh"
|
|
97
97
|
|
|
98
|
-
echo "🔍 Running
|
|
98
|
+
echo "🔍 Running Tetra quality checks..."
|
|
99
99
|
|
|
100
100
|
# Run quick security checks (fast, blocks commit on critical issues)
|
|
101
|
-
npx
|
|
101
|
+
npx tetra-audit quick
|
|
102
102
|
if [ $? -ne 0 ]; then
|
|
103
103
|
echo ""
|
|
104
104
|
echo "❌ Security issues found! Fix before committing."
|
|
105
|
-
echo " Run '
|
|
105
|
+
echo " Run 'tetra-audit' for detailed report."
|
|
106
106
|
exit 1
|
|
107
107
|
fi
|
|
108
108
|
|
|
@@ -120,6 +120,39 @@ echo "✅ Pre-commit checks passed"
|
|
|
120
120
|
console.log(' ⏭️ .husky/pre-commit already exists (use --force to overwrite)')
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
// Create or extend pre-push hook with hygiene check
|
|
124
|
+
const prePushPath = join(huskyDir, 'pre-push')
|
|
125
|
+
const hygieneBlock = `
|
|
126
|
+
# Tetra hygiene check — blocks push if repo contains clutter
|
|
127
|
+
echo "🧹 Running repo hygiene check..."
|
|
128
|
+
npx tetra-audit hygiene
|
|
129
|
+
if [ $? -ne 0 ]; then
|
|
130
|
+
echo ""
|
|
131
|
+
echo "❌ Repo hygiene issues found! Clean up before pushing."
|
|
132
|
+
echo " Run 'npx tetra-audit hygiene --verbose' for details."
|
|
133
|
+
echo " Run 'bash node_modules/@soulbatical/tetra-dev-toolkit/bin/cleanup-repos.sh' to auto-fix."
|
|
134
|
+
exit 1
|
|
135
|
+
fi
|
|
136
|
+
echo "✅ Repo hygiene passed"
|
|
137
|
+
`
|
|
138
|
+
|
|
139
|
+
if (!existsSync(prePushPath)) {
|
|
140
|
+
// No pre-push hook yet — create one
|
|
141
|
+
const prePushContent = `#!/bin/sh\n${hygieneBlock}\n`
|
|
142
|
+
writeFileSync(prePushPath, prePushContent)
|
|
143
|
+
execSync(`chmod +x ${prePushPath}`)
|
|
144
|
+
console.log(' ✅ Created .husky/pre-push with hygiene check')
|
|
145
|
+
} else {
|
|
146
|
+
// Pre-push hook exists — add hygiene check if not already there
|
|
147
|
+
const existing = readFileSync(prePushPath, 'utf-8')
|
|
148
|
+
if (!existing.includes('tetra-audit hygiene')) {
|
|
149
|
+
writeFileSync(prePushPath, existing.trimEnd() + '\n' + hygieneBlock)
|
|
150
|
+
console.log(' ✅ Added hygiene check to existing .husky/pre-push')
|
|
151
|
+
} else {
|
|
152
|
+
console.log(' ⏭️ .husky/pre-push already has hygiene check')
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
123
156
|
// Add prepare script to package.json
|
|
124
157
|
if (!pkg.scripts?.prepare?.includes('husky')) {
|
|
125
158
|
pkg.scripts = pkg.scripts || {}
|
|
@@ -149,7 +182,7 @@ on:
|
|
|
149
182
|
|
|
150
183
|
jobs:
|
|
151
184
|
quality:
|
|
152
|
-
name: 🔍
|
|
185
|
+
name: 🔍 Tetra Quality Audit
|
|
153
186
|
runs-on: ubuntu-latest
|
|
154
187
|
|
|
155
188
|
steps:
|
|
@@ -165,8 +198,8 @@ jobs:
|
|
|
165
198
|
- name: Install dependencies
|
|
166
199
|
run: npm ci
|
|
167
200
|
|
|
168
|
-
- name: Run
|
|
169
|
-
run: npx
|
|
201
|
+
- name: Run Tetra Quality Audit
|
|
202
|
+
run: npx tetra-audit --ci
|
|
170
203
|
|
|
171
204
|
- name: Upload results
|
|
172
205
|
if: always()
|
|
@@ -186,15 +219,16 @@ jobs:
|
|
|
186
219
|
async function setupConfig(options) {
|
|
187
220
|
console.log('📝 Setting up configuration...')
|
|
188
221
|
|
|
189
|
-
const configPath = join(projectRoot, '.
|
|
222
|
+
const configPath = join(projectRoot, '.tetra-quality.json')
|
|
190
223
|
if (!existsSync(configPath) || options.force) {
|
|
191
224
|
const config = {
|
|
192
|
-
"$schema": "https://
|
|
225
|
+
"$schema": "https://tetra-tools.dev/schemas/quality-toolkit.json",
|
|
193
226
|
"suites": {
|
|
194
227
|
"security": true,
|
|
195
228
|
"stability": true,
|
|
196
229
|
"codeQuality": true,
|
|
197
|
-
"supabase": "auto"
|
|
230
|
+
"supabase": "auto",
|
|
231
|
+
"hygiene": true
|
|
198
232
|
},
|
|
199
233
|
"security": {
|
|
200
234
|
"checkHardcodedSecrets": true,
|
|
@@ -218,7 +252,7 @@ async function setupConfig(options) {
|
|
|
218
252
|
}
|
|
219
253
|
|
|
220
254
|
writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n')
|
|
221
|
-
console.log(' ✅ Created .
|
|
255
|
+
console.log(' ✅ Created .tetra-quality.json')
|
|
222
256
|
} else {
|
|
223
257
|
console.log(' ⏭️ Config already exists (use --force to overwrite)')
|
|
224
258
|
}
|