tribunal-kit 4.3.1 → 4.4.1
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/.agent/agents/api-architect.md +66 -66
- package/.agent/agents/db-latency-auditor.md +216 -216
- package/.agent/agents/precedence-reviewer.md +250 -250
- package/.agent/agents/resilience-reviewer.md +88 -88
- package/.agent/agents/schema-reviewer.md +67 -67
- package/.agent/agents/throughput-optimizer.md +299 -299
- package/.agent/agents/ui-ux-auditor.md +292 -292
- package/.agent/agents/vitals-reviewer.md +223 -223
- package/.agent/scripts/_colors.js +18 -18
- package/.agent/scripts/_utils.js +42 -42
- package/.agent/scripts/append_flow.js +72 -72
- package/.agent/scripts/auto_preview.js +197 -197
- package/.agent/scripts/bundle_analyzer.js +290 -290
- package/.agent/scripts/case_law_manager.js +17 -6
- package/.agent/scripts/checklist.js +266 -266
- package/.agent/scripts/colors.js +17 -17
- package/.agent/scripts/compress_skills.js +141 -141
- package/.agent/scripts/consolidate_skills.js +149 -149
- package/.agent/scripts/context_broker.js +611 -609
- package/.agent/scripts/deep_compress.js +150 -150
- package/.agent/scripts/dependency_analyzer.js +272 -272
- package/.agent/scripts/graph_builder.js +151 -37
- package/.agent/scripts/graph_visualizer.js +384 -0
- package/.agent/scripts/inner_loop_validator.js +451 -465
- package/.agent/scripts/lint_runner.js +187 -187
- package/.agent/scripts/minify_context.js +100 -100
- package/.agent/scripts/mutation_runner.js +280 -0
- package/.agent/scripts/patch_skills_meta.js +156 -156
- package/.agent/scripts/patch_skills_output.js +244 -244
- package/.agent/scripts/schema_validator.js +297 -297
- package/.agent/scripts/security_scan.js +303 -303
- package/.agent/scripts/session_manager.js +276 -276
- package/.agent/scripts/skill_evolution.js +644 -644
- package/.agent/scripts/skill_integrator.js +313 -313
- package/.agent/scripts/strengthen_skills.js +193 -193
- package/.agent/scripts/strip_tribunal.js +47 -47
- package/.agent/scripts/swarm_dispatcher.js +360 -360
- package/.agent/scripts/test_runner.js +193 -193
- package/.agent/scripts/utils.js +32 -32
- package/.agent/scripts/verify_all.js +257 -256
- package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +1 -1
- package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +1 -1
- package/.agent/skills/doc.md +1 -1
- package/.agent/skills/knowledge-graph/SKILL.md +32 -16
- package/.agent/skills/testing-patterns/SKILL.md +19 -2
- package/.agent/skills/ui-ux-pro-max/SKILL.md +480 -43
- package/.agent/workflows/generate.md +183 -183
- package/.agent/workflows/tribunal-speed.md +183 -183
- package/README.md +1 -1
- package/bin/tribunal-kit.js +134 -17
- package/package.json +6 -3
- package/scripts/changelog.js +167 -167
- package/scripts/sync-version.js +81 -81
- package/.agent/scripts/__pycache__/_colors.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/_utils.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/case_law_manager.cpython-311.pyc +0 -0
|
@@ -1,266 +1,266 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* checklist.js — Priority-based project audit runner for the Tribunal Agent Kit.
|
|
4
|
-
*
|
|
5
|
-
* Runs a tiered audit sequence:
|
|
6
|
-
* Priority 1: Security
|
|
7
|
-
* Priority 2: Lint
|
|
8
|
-
* Priority 3: Schema validation
|
|
9
|
-
* Priority 4: Tests
|
|
10
|
-
* Priority 5: UX / Accessibility
|
|
11
|
-
* Priority 6: SEO
|
|
12
|
-
* Priority 7: Lighthouse / E2E (requires --url)
|
|
13
|
-
*
|
|
14
|
-
* Usage:
|
|
15
|
-
* node .agent/scripts/checklist.js .
|
|
16
|
-
* node .agent/scripts/checklist.js . --url http://localhost:3000
|
|
17
|
-
* node .agent/scripts/checklist.js . --skip security,seo
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
'use strict';
|
|
21
|
-
|
|
22
|
-
const fs = require('fs');
|
|
23
|
-
const path = require('path');
|
|
24
|
-
const { execFileSync } = require('child_process');
|
|
25
|
-
|
|
26
|
-
// ━━━ ANSI color output ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
27
|
-
const RED = '\x1b[91m';
|
|
28
|
-
const GREEN = '\x1b[92m';
|
|
29
|
-
const YELLOW = '\x1b[93m';
|
|
30
|
-
const BLUE = '\x1b[94m';
|
|
31
|
-
const BOLD = '\x1b[1m';
|
|
32
|
-
const RESET = '\x1b[0m';
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
function printHeader(title) {
|
|
36
|
-
console.log(`\n${BOLD}${BLUE}━━━ ${title} ━━━${RESET}`);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function printOk(msg) {
|
|
40
|
-
console.log(` ${GREEN}✅ ${msg}${RESET}`);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function printFail(msg) {
|
|
44
|
-
console.log(` ${RED}❌ ${msg}${RESET}`);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function printSkip(msg) {
|
|
48
|
-
console.log(` ${YELLOW}⏭️ Skipped: ${msg}${RESET}`);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Run a shell command and return true if it exits with code 0.
|
|
54
|
-
* @param {string} label - Human-readable label for the check.
|
|
55
|
-
* @param {string[]} cmd - Command and arguments array.
|
|
56
|
-
* @param {string} cwd - Working directory.
|
|
57
|
-
* @returns {boolean}
|
|
58
|
-
*/
|
|
59
|
-
function runCheck(label, cmd, cwd) {
|
|
60
|
-
try {
|
|
61
|
-
execFileSync(cmd[0], cmd.slice(1), {
|
|
62
|
-
cwd,
|
|
63
|
-
stdio: 'pipe',
|
|
64
|
-
timeout: 60000,
|
|
65
|
-
encoding: 'utf8',
|
|
66
|
-
});
|
|
67
|
-
printOk(`${label} passed`);
|
|
68
|
-
return true;
|
|
69
|
-
} catch (err) {
|
|
70
|
-
if (err.code === 'ENOENT') {
|
|
71
|
-
printSkip(`${label} — command not found (tool not installed)`);
|
|
72
|
-
return true; // Don't block on tools that aren't installed
|
|
73
|
-
}
|
|
74
|
-
if (err.killed) {
|
|
75
|
-
printFail(`${label} — timed out after 60s`);
|
|
76
|
-
return false;
|
|
77
|
-
}
|
|
78
|
-
printFail(`${label} failed`);
|
|
79
|
-
const output = (err.stdout || '') + (err.stderr || '');
|
|
80
|
-
if (output.trim()) {
|
|
81
|
-
console.log(` ${output.trim().slice(0, 500)}`);
|
|
82
|
-
}
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Scan for hardcoded secrets in source files.
|
|
90
|
-
* @param {string} projectRoot - Project root directory.
|
|
91
|
-
* @returns {boolean} True if no secrets found.
|
|
92
|
-
*/
|
|
93
|
-
function checkSecrets(projectRoot) {
|
|
94
|
-
printHeader('Security — Secret Scan');
|
|
95
|
-
const dangerousPatterns = [
|
|
96
|
-
'password=', 'secret=', 'api_key=',
|
|
97
|
-
'apikey=', 'auth_token=', 'private_key=',
|
|
98
|
-
];
|
|
99
|
-
let foundIssues = false;
|
|
100
|
-
const sourceExtensions = new Set(['.ts', '.tsx', '.js', '.jsx', '.py', '.env']);
|
|
101
|
-
const skipDirs = new Set(['node_modules', '.git', '.agent', 'dist', '__pycache__']);
|
|
102
|
-
|
|
103
|
-
function walk(dir) {
|
|
104
|
-
let entries;
|
|
105
|
-
try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
|
|
106
|
-
|
|
107
|
-
for (const entry of entries) {
|
|
108
|
-
const fullPath = path.join(dir, entry.name);
|
|
109
|
-
if (entry.isDirectory()) {
|
|
110
|
-
if (!skipDirs.has(entry.name)) walk(fullPath);
|
|
111
|
-
} else if (entry.isFile()) {
|
|
112
|
-
const ext = path.extname(entry.name);
|
|
113
|
-
if (!sourceExtensions.has(ext)) continue;
|
|
114
|
-
if (entry.name.startsWith('.env')) continue; // .env files are allowed
|
|
115
|
-
|
|
116
|
-
let content;
|
|
117
|
-
try { content = fs.readFileSync(fullPath, 'utf8'); } catch { continue; }
|
|
118
|
-
|
|
119
|
-
const lines = content.split('\n');
|
|
120
|
-
for (let i = 0; i < lines.length; i++) {
|
|
121
|
-
const lineLower = lines[i].toLowerCase().trim();
|
|
122
|
-
const hasPattern = dangerousPatterns.some(p => lineLower.includes(p));
|
|
123
|
-
if (hasPattern && lineLower.includes('=') && !lineLower.startsWith('#')) {
|
|
124
|
-
const rel = path.relative(projectRoot, fullPath);
|
|
125
|
-
printFail(`Possible secret: ${rel}:${i + 1} → ${lines[i].trim().slice(0, 80)}`);
|
|
126
|
-
foundIssues = true;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
walk(projectRoot);
|
|
134
|
-
|
|
135
|
-
if (!foundIssues) {
|
|
136
|
-
printOk('No hardcoded secrets detected');
|
|
137
|
-
}
|
|
138
|
-
return !foundIssues;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Run all checklist tiers. Returns number of failures.
|
|
144
|
-
* @param {string} projectRoot - Project root.
|
|
145
|
-
* @param {string|null} url - URL for Lighthouse/E2E checks.
|
|
146
|
-
* @param {string[]} skip - Tiers to skip.
|
|
147
|
-
* @returns {number}
|
|
148
|
-
*/
|
|
149
|
-
function runAll(projectRoot, url, skip) {
|
|
150
|
-
let failures = 0;
|
|
151
|
-
|
|
152
|
-
// Priority 1 — Security
|
|
153
|
-
if (!skip.includes('security')) {
|
|
154
|
-
printHeader('Priority 1 — Security');
|
|
155
|
-
if (!checkSecrets(projectRoot)) failures++;
|
|
156
|
-
} else {
|
|
157
|
-
printSkip('Security tier');
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Priority 2 — Lint
|
|
161
|
-
if (!skip.includes('lint')) {
|
|
162
|
-
printHeader('Priority 2 — Lint');
|
|
163
|
-
if (!runCheck('ESLint', ['npx', 'eslint', '.', '--max-warnings=0'], projectRoot)) failures++;
|
|
164
|
-
if (!runCheck('TypeScript', ['npx', 'tsc', '--noEmit'], projectRoot)) failures++;
|
|
165
|
-
} else {
|
|
166
|
-
printSkip('Lint tier');
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Priority 3 — Schema
|
|
170
|
-
if (!skip.includes('schema')) {
|
|
171
|
-
printHeader('Priority 3 — Schema');
|
|
172
|
-
printSkip('Schema check — run manually if you have DB migrations');
|
|
173
|
-
} else {
|
|
174
|
-
printSkip('Schema tier');
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Priority 4 — Tests
|
|
178
|
-
if (!skip.includes('tests')) {
|
|
179
|
-
printHeader('Priority 4 — Tests');
|
|
180
|
-
if (!runCheck('Test suite', ['npm', 'test', '--', '--passWithNoTests'], projectRoot)) failures++;
|
|
181
|
-
} else {
|
|
182
|
-
printSkip('Tests tier');
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Priority 5 — UX
|
|
186
|
-
if (!skip.includes('ux')) {
|
|
187
|
-
printHeader('Priority 5 — UX / Accessibility');
|
|
188
|
-
printSkip('UX audit — run /preview start then check manually or with Lighthouse');
|
|
189
|
-
} else {
|
|
190
|
-
printSkip('UX tier');
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Priority 6 — SEO
|
|
194
|
-
if (!skip.includes('seo')) {
|
|
195
|
-
printHeader('Priority 6 — SEO');
|
|
196
|
-
printSkip('SEO check — use /ui-ux-pro-max for SEO-sensitive pages');
|
|
197
|
-
} else {
|
|
198
|
-
printSkip('SEO tier');
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// Priority 7 — Lighthouse / E2E
|
|
202
|
-
if (url && !skip.includes('e2e')) {
|
|
203
|
-
printHeader('Priority 7 — Lighthouse / E2E');
|
|
204
|
-
if (!runCheck('Playwright E2E', ['npx', 'playwright', 'test'], projectRoot)) failures++;
|
|
205
|
-
} else if (!url) {
|
|
206
|
-
printSkip('E2E / Lighthouse — pass --url to enable');
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// ━━━ Summary ━━━
|
|
210
|
-
console.log(`\n${BOLD}━━━ Checklist Summary ━━━${RESET}`);
|
|
211
|
-
if (failures === 0) {
|
|
212
|
-
printOk('All checks passed — ready to proceed');
|
|
213
|
-
} else {
|
|
214
|
-
printFail(`${failures} tier(s) failed — fix Critical issues before proceeding`);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return failures;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Parse CLI arguments manually (no external dependencies).
|
|
223
|
-
*/
|
|
224
|
-
function parseArgs(argv) {
|
|
225
|
-
const args = { path: null, url: null, skip: [] };
|
|
226
|
-
const raw = argv.slice(2);
|
|
227
|
-
|
|
228
|
-
for (let i = 0; i < raw.length; i++) {
|
|
229
|
-
if (raw[i] === '--url' && raw[i + 1]) {
|
|
230
|
-
args.url = raw[++i];
|
|
231
|
-
} else if (raw[i] === '--skip' && raw[i + 1]) {
|
|
232
|
-
args.skip = raw[++i].split(',').map(s => s.trim().toLowerCase()).filter(Boolean);
|
|
233
|
-
} else if (!raw[i].startsWith('--') && !args.path) {
|
|
234
|
-
args.path = raw[i];
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
return args;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
function main() {
|
|
242
|
-
const args = parseArgs(process.argv);
|
|
243
|
-
|
|
244
|
-
if (!args.path) {
|
|
245
|
-
console.error(`Usage: node checklist.js <path> [--url <url>] [--skip security,lint,schema,tests,ux,seo,e2e]`);
|
|
246
|
-
process.exit(1);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const projectRoot = path.resolve(args.path);
|
|
250
|
-
if (!fs.existsSync(projectRoot) || !fs.statSync(projectRoot).isDirectory()) {
|
|
251
|
-
printFail(`Directory not found: ${projectRoot}`);
|
|
252
|
-
process.exit(1);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
console.log(`${BOLD}Tribunal Checklist — ${projectRoot}${RESET}`);
|
|
256
|
-
const failures = runAll(projectRoot, args.url, args.skip);
|
|
257
|
-
process.exit(failures > 0 ? 1 : 0);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
// ━━━ Exports for testing & programmatic use ━━━
|
|
262
|
-
module.exports = { runCheck, checkSecrets, runAll };
|
|
263
|
-
|
|
264
|
-
if (require.main === module) {
|
|
265
|
-
main();
|
|
266
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* checklist.js — Priority-based project audit runner for the Tribunal Agent Kit.
|
|
4
|
+
*
|
|
5
|
+
* Runs a tiered audit sequence:
|
|
6
|
+
* Priority 1: Security
|
|
7
|
+
* Priority 2: Lint
|
|
8
|
+
* Priority 3: Schema validation
|
|
9
|
+
* Priority 4: Tests
|
|
10
|
+
* Priority 5: UX / Accessibility
|
|
11
|
+
* Priority 6: SEO
|
|
12
|
+
* Priority 7: Lighthouse / E2E (requires --url)
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* node .agent/scripts/checklist.js .
|
|
16
|
+
* node .agent/scripts/checklist.js . --url http://localhost:3000
|
|
17
|
+
* node .agent/scripts/checklist.js . --skip security,seo
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
'use strict';
|
|
21
|
+
|
|
22
|
+
const fs = require('fs');
|
|
23
|
+
const path = require('path');
|
|
24
|
+
const { execFileSync } = require('child_process');
|
|
25
|
+
|
|
26
|
+
// ━━━ ANSI color output ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
27
|
+
const RED = '\x1b[91m';
|
|
28
|
+
const GREEN = '\x1b[92m';
|
|
29
|
+
const YELLOW = '\x1b[93m';
|
|
30
|
+
const BLUE = '\x1b[94m';
|
|
31
|
+
const BOLD = '\x1b[1m';
|
|
32
|
+
const RESET = '\x1b[0m';
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
function printHeader(title) {
|
|
36
|
+
console.log(`\n${BOLD}${BLUE}━━━ ${title} ━━━${RESET}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function printOk(msg) {
|
|
40
|
+
console.log(` ${GREEN}✅ ${msg}${RESET}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function printFail(msg) {
|
|
44
|
+
console.log(` ${RED}❌ ${msg}${RESET}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function printSkip(msg) {
|
|
48
|
+
console.log(` ${YELLOW}⏭️ Skipped: ${msg}${RESET}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Run a shell command and return true if it exits with code 0.
|
|
54
|
+
* @param {string} label - Human-readable label for the check.
|
|
55
|
+
* @param {string[]} cmd - Command and arguments array.
|
|
56
|
+
* @param {string} cwd - Working directory.
|
|
57
|
+
* @returns {boolean}
|
|
58
|
+
*/
|
|
59
|
+
function runCheck(label, cmd, cwd) {
|
|
60
|
+
try {
|
|
61
|
+
execFileSync(cmd[0], cmd.slice(1), {
|
|
62
|
+
cwd,
|
|
63
|
+
stdio: 'pipe',
|
|
64
|
+
timeout: 60000,
|
|
65
|
+
encoding: 'utf8',
|
|
66
|
+
});
|
|
67
|
+
printOk(`${label} passed`);
|
|
68
|
+
return true;
|
|
69
|
+
} catch (err) {
|
|
70
|
+
if (err.code === 'ENOENT') {
|
|
71
|
+
printSkip(`${label} — command not found (tool not installed)`);
|
|
72
|
+
return true; // Don't block on tools that aren't installed
|
|
73
|
+
}
|
|
74
|
+
if (err.killed) {
|
|
75
|
+
printFail(`${label} — timed out after 60s`);
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
printFail(`${label} failed`);
|
|
79
|
+
const output = (err.stdout || '') + (err.stderr || '');
|
|
80
|
+
if (output.trim()) {
|
|
81
|
+
console.log(` ${output.trim().slice(0, 500)}`);
|
|
82
|
+
}
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Scan for hardcoded secrets in source files.
|
|
90
|
+
* @param {string} projectRoot - Project root directory.
|
|
91
|
+
* @returns {boolean} True if no secrets found.
|
|
92
|
+
*/
|
|
93
|
+
function checkSecrets(projectRoot) {
|
|
94
|
+
printHeader('Security — Secret Scan');
|
|
95
|
+
const dangerousPatterns = [
|
|
96
|
+
'password=', 'secret=', 'api_key=',
|
|
97
|
+
'apikey=', 'auth_token=', 'private_key=',
|
|
98
|
+
];
|
|
99
|
+
let foundIssues = false;
|
|
100
|
+
const sourceExtensions = new Set(['.ts', '.tsx', '.js', '.jsx', '.py', '.env']);
|
|
101
|
+
const skipDirs = new Set(['node_modules', '.git', '.agent', 'dist', '__pycache__']);
|
|
102
|
+
|
|
103
|
+
function walk(dir) {
|
|
104
|
+
let entries;
|
|
105
|
+
try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
|
|
106
|
+
|
|
107
|
+
for (const entry of entries) {
|
|
108
|
+
const fullPath = path.join(dir, entry.name);
|
|
109
|
+
if (entry.isDirectory()) {
|
|
110
|
+
if (!skipDirs.has(entry.name)) walk(fullPath);
|
|
111
|
+
} else if (entry.isFile()) {
|
|
112
|
+
const ext = path.extname(entry.name);
|
|
113
|
+
if (!sourceExtensions.has(ext)) continue;
|
|
114
|
+
if (entry.name.startsWith('.env')) continue; // .env files are allowed
|
|
115
|
+
|
|
116
|
+
let content;
|
|
117
|
+
try { content = fs.readFileSync(fullPath, 'utf8'); } catch { continue; }
|
|
118
|
+
|
|
119
|
+
const lines = content.split('\n');
|
|
120
|
+
for (let i = 0; i < lines.length; i++) {
|
|
121
|
+
const lineLower = lines[i].toLowerCase().trim();
|
|
122
|
+
const hasPattern = dangerousPatterns.some(p => lineLower.includes(p));
|
|
123
|
+
if (hasPattern && lineLower.includes('=') && !lineLower.startsWith('#')) {
|
|
124
|
+
const rel = path.relative(projectRoot, fullPath);
|
|
125
|
+
printFail(`Possible secret: ${rel}:${i + 1} → ${lines[i].trim().slice(0, 80)}`);
|
|
126
|
+
foundIssues = true;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
walk(projectRoot);
|
|
134
|
+
|
|
135
|
+
if (!foundIssues) {
|
|
136
|
+
printOk('No hardcoded secrets detected');
|
|
137
|
+
}
|
|
138
|
+
return !foundIssues;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Run all checklist tiers. Returns number of failures.
|
|
144
|
+
* @param {string} projectRoot - Project root.
|
|
145
|
+
* @param {string|null} url - URL for Lighthouse/E2E checks.
|
|
146
|
+
* @param {string[]} skip - Tiers to skip.
|
|
147
|
+
* @returns {number}
|
|
148
|
+
*/
|
|
149
|
+
function runAll(projectRoot, url, skip) {
|
|
150
|
+
let failures = 0;
|
|
151
|
+
|
|
152
|
+
// Priority 1 — Security
|
|
153
|
+
if (!skip.includes('security')) {
|
|
154
|
+
printHeader('Priority 1 — Security');
|
|
155
|
+
if (!checkSecrets(projectRoot)) failures++;
|
|
156
|
+
} else {
|
|
157
|
+
printSkip('Security tier');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Priority 2 — Lint
|
|
161
|
+
if (!skip.includes('lint')) {
|
|
162
|
+
printHeader('Priority 2 — Lint');
|
|
163
|
+
if (!runCheck('ESLint', ['npx', 'eslint', '.', '--max-warnings=0'], projectRoot)) failures++;
|
|
164
|
+
if (!runCheck('TypeScript', ['npx', 'tsc', '--noEmit'], projectRoot)) failures++;
|
|
165
|
+
} else {
|
|
166
|
+
printSkip('Lint tier');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Priority 3 — Schema
|
|
170
|
+
if (!skip.includes('schema')) {
|
|
171
|
+
printHeader('Priority 3 — Schema');
|
|
172
|
+
printSkip('Schema check — run manually if you have DB migrations');
|
|
173
|
+
} else {
|
|
174
|
+
printSkip('Schema tier');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Priority 4 — Tests
|
|
178
|
+
if (!skip.includes('tests')) {
|
|
179
|
+
printHeader('Priority 4 — Tests');
|
|
180
|
+
if (!runCheck('Test suite', ['npm', 'test', '--', '--passWithNoTests'], projectRoot)) failures++;
|
|
181
|
+
} else {
|
|
182
|
+
printSkip('Tests tier');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Priority 5 — UX
|
|
186
|
+
if (!skip.includes('ux')) {
|
|
187
|
+
printHeader('Priority 5 — UX / Accessibility');
|
|
188
|
+
printSkip('UX audit — run /preview start then check manually or with Lighthouse');
|
|
189
|
+
} else {
|
|
190
|
+
printSkip('UX tier');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Priority 6 — SEO
|
|
194
|
+
if (!skip.includes('seo')) {
|
|
195
|
+
printHeader('Priority 6 — SEO');
|
|
196
|
+
printSkip('SEO check — use /ui-ux-pro-max for SEO-sensitive pages');
|
|
197
|
+
} else {
|
|
198
|
+
printSkip('SEO tier');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Priority 7 — Lighthouse / E2E
|
|
202
|
+
if (url && !skip.includes('e2e')) {
|
|
203
|
+
printHeader('Priority 7 — Lighthouse / E2E');
|
|
204
|
+
if (!runCheck('Playwright E2E', ['npx', 'playwright', 'test'], projectRoot)) failures++;
|
|
205
|
+
} else if (!url) {
|
|
206
|
+
printSkip('E2E / Lighthouse — pass --url to enable');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ━━━ Summary ━━━
|
|
210
|
+
console.log(`\n${BOLD}━━━ Checklist Summary ━━━${RESET}`);
|
|
211
|
+
if (failures === 0) {
|
|
212
|
+
printOk('All checks passed — ready to proceed');
|
|
213
|
+
} else {
|
|
214
|
+
printFail(`${failures} tier(s) failed — fix Critical issues before proceeding`);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return failures;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Parse CLI arguments manually (no external dependencies).
|
|
223
|
+
*/
|
|
224
|
+
function parseArgs(argv) {
|
|
225
|
+
const args = { path: null, url: null, skip: [] };
|
|
226
|
+
const raw = argv.slice(2);
|
|
227
|
+
|
|
228
|
+
for (let i = 0; i < raw.length; i++) {
|
|
229
|
+
if (raw[i] === '--url' && raw[i + 1]) {
|
|
230
|
+
args.url = raw[++i];
|
|
231
|
+
} else if (raw[i] === '--skip' && raw[i + 1]) {
|
|
232
|
+
args.skip = raw[++i].split(',').map(s => s.trim().toLowerCase()).filter(Boolean);
|
|
233
|
+
} else if (!raw[i].startsWith('--') && !args.path) {
|
|
234
|
+
args.path = raw[i];
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return args;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
function main() {
|
|
242
|
+
const args = parseArgs(process.argv);
|
|
243
|
+
|
|
244
|
+
if (!args.path) {
|
|
245
|
+
console.error(`Usage: node checklist.js <path> [--url <url>] [--skip security,lint,schema,tests,ux,seo,e2e]`);
|
|
246
|
+
process.exit(1);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const projectRoot = path.resolve(args.path);
|
|
250
|
+
if (!fs.existsSync(projectRoot) || !fs.statSync(projectRoot).isDirectory()) {
|
|
251
|
+
printFail(`Directory not found: ${projectRoot}`);
|
|
252
|
+
process.exit(1);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
console.log(`${BOLD}Tribunal Checklist — ${projectRoot}${RESET}`);
|
|
256
|
+
const failures = runAll(projectRoot, args.url, args.skip);
|
|
257
|
+
process.exit(failures > 0 ? 1 : 0);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
// ━━━ Exports for testing & programmatic use ━━━
|
|
262
|
+
module.exports = { runCheck, checkSecrets, runAll };
|
|
263
|
+
|
|
264
|
+
if (require.main === module) {
|
|
265
|
+
main();
|
|
266
|
+
}
|
package/.agent/scripts/colors.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* colors.js
|
|
3
|
-
* Shared ANSI color constants for Tribunal Kit Node scripts.
|
|
4
|
-
*/
|
|
5
|
-
'use strict';
|
|
6
|
-
|
|
7
|
-
module.exports = {
|
|
8
|
-
GREEN: "\x1b[92m",
|
|
9
|
-
YELLOW: "\x1b[93m",
|
|
10
|
-
CYAN: "\x1b[96m",
|
|
11
|
-
RED: "\x1b[91m",
|
|
12
|
-
BLUE: "\x1b[94m",
|
|
13
|
-
MAGENTA: "\x1b[95m",
|
|
14
|
-
BOLD: "\x1b[1m",
|
|
15
|
-
DIM: "\x1b[2m",
|
|
16
|
-
RESET: "\x1b[0m"
|
|
17
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* colors.js
|
|
3
|
+
* Shared ANSI color constants for Tribunal Kit Node scripts.
|
|
4
|
+
*/
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
GREEN: "\x1b[92m",
|
|
9
|
+
YELLOW: "\x1b[93m",
|
|
10
|
+
CYAN: "\x1b[96m",
|
|
11
|
+
RED: "\x1b[91m",
|
|
12
|
+
BLUE: "\x1b[94m",
|
|
13
|
+
MAGENTA: "\x1b[95m",
|
|
14
|
+
BOLD: "\x1b[1m",
|
|
15
|
+
DIM: "\x1b[2m",
|
|
16
|
+
RESET: "\x1b[0m"
|
|
17
|
+
};
|