tribunal-kit 4.4.0 → 4.4.2

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 (90) hide show
  1. package/.agent/agents/api-architect.md +66 -66
  2. package/.agent/agents/db-latency-auditor.md +216 -216
  3. package/.agent/agents/precedence-reviewer.md +250 -250
  4. package/.agent/agents/resilience-reviewer.md +88 -88
  5. package/.agent/agents/schema-reviewer.md +67 -67
  6. package/.agent/agents/throughput-optimizer.md +299 -299
  7. package/.agent/agents/ui-ux-auditor.md +292 -292
  8. package/.agent/agents/vitals-reviewer.md +223 -223
  9. package/.agent/history/architecture-graph.yaml +32 -1
  10. package/.agent/history/graph-cache.json +66 -19
  11. package/.agent/history/snapshots/bin__tribunal-kit.js.json +19 -0
  12. package/.agent/history/snapshots/eslint.config.js.json +9 -0
  13. package/.agent/history/snapshots/migrate_refs.js.json +3 -3
  14. package/.agent/history/snapshots/scripts__changelog.js.json +2 -1
  15. package/.agent/history/snapshots/scripts__sync-version.js.json +2 -1
  16. package/.agent/history/snapshots/scripts__validate-payload.js.json +1 -0
  17. package/.agent/history/snapshots/test__integration__bridges.test.js.json +2 -1
  18. package/.agent/history/snapshots/test__integration__init.test.js.json +1 -0
  19. package/.agent/history/snapshots/test__integration__routing.test.js.json +1 -0
  20. package/.agent/history/snapshots/test__integration__swarm_dispatcher.test.js.json +2 -1
  21. package/.agent/history/snapshots/test__integration__wave2.test.js.json +2 -1
  22. package/.agent/history/snapshots/test__unit__args.test.js.json +11 -1
  23. package/.agent/history/snapshots/test__unit__case_law_manager.test.js.json +1 -0
  24. package/.agent/history/snapshots/test__unit__context_broker.test.js.json +11 -0
  25. package/.agent/history/snapshots/test__unit__copyDir.test.js.json +11 -1
  26. package/.agent/history/snapshots/test__unit__graph_tools.test.js.json +1 -0
  27. package/.agent/history/snapshots/test__unit__inner_loop_validator.test.js.json +11 -0
  28. package/.agent/history/snapshots/test__unit__selfInstall.test.js.json +11 -1
  29. package/.agent/history/snapshots/test__unit__semver.test.js.json +11 -1
  30. package/.agent/history/snapshots/test__unit__swarm_dispatcher.test.js.json +1 -0
  31. package/.agent/scripts/_colors.js +154 -2
  32. package/.agent/scripts/_utils.js +205 -3
  33. package/.agent/scripts/append_flow.js +72 -72
  34. package/.agent/scripts/auto_preview.js +197 -197
  35. package/.agent/scripts/bundle_analyzer.js +90 -119
  36. package/.agent/scripts/case_law_manager.js +18 -13
  37. package/.agent/scripts/checklist.js +100 -88
  38. package/.agent/scripts/colors.js +7 -13
  39. package/.agent/scripts/compress_skills.js +141 -141
  40. package/.agent/scripts/consolidate_skills.js +149 -149
  41. package/.agent/scripts/context_broker.js +605 -609
  42. package/.agent/scripts/deep_compress.js +150 -150
  43. package/.agent/scripts/dependency_analyzer.js +68 -106
  44. package/.agent/scripts/graph_builder.js +341 -311
  45. package/.agent/scripts/graph_visualizer.js +390 -384
  46. package/.agent/scripts/graph_zoom.js +6 -4
  47. package/.agent/scripts/inner_loop_validator.js +445 -465
  48. package/.agent/scripts/lint_runner.js +27 -28
  49. package/.agent/scripts/minify_context.js +100 -100
  50. package/.agent/scripts/mutation_runner.js +280 -280
  51. package/.agent/scripts/patch_skills_meta.js +156 -156
  52. package/.agent/scripts/patch_skills_output.js +244 -244
  53. package/.agent/scripts/schema_validator.js +280 -297
  54. package/.agent/scripts/security_scan.js +37 -64
  55. package/.agent/scripts/session_manager.js +270 -276
  56. package/.agent/scripts/skill_evolution.js +637 -644
  57. package/.agent/scripts/skill_integrator.js +307 -313
  58. package/.agent/scripts/strengthen_skills.js +193 -193
  59. package/.agent/scripts/strip_tribunal.js +47 -47
  60. package/.agent/scripts/swarm_dispatcher.js +360 -360
  61. package/.agent/scripts/test_runner.js +32 -39
  62. package/.agent/scripts/utils.js +10 -25
  63. package/.agent/scripts/verify_all.js +84 -92
  64. package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +1 -1
  65. package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +1 -1
  66. package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +1 -1
  67. package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +1 -1
  68. package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +1 -1
  69. package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +1 -1
  70. package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +1 -1
  71. package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +1 -1
  72. package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +1 -1
  73. package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +1 -1
  74. package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +1 -1
  75. package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +1 -1
  76. package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +1 -1
  77. package/.agent/skills/doc.md +1 -1
  78. package/.agent/skills/knowledge-graph/SKILL.md +52 -52
  79. package/.agent/skills/ui-ux-pro-max/SKILL.md +562 -562
  80. package/.agent/workflows/generate.md +183 -183
  81. package/.agent/workflows/tribunal-speed.md +183 -183
  82. package/README.md +1 -1
  83. package/bin/tribunal-kit.js +76 -87
  84. package/package.json +6 -3
  85. package/scripts/changelog.js +167 -167
  86. package/scripts/sync-version.js +81 -81
  87. package/.agent/history/architecture-explorer.html +0 -352
  88. package/.agent/scripts/__pycache__/_colors.cpython-311.pyc +0 -0
  89. package/.agent/scripts/__pycache__/_utils.cpython-311.pyc +0 -0
  90. package/.agent/scripts/__pycache__/case_law_manager.cpython-311.pyc +0 -0
@@ -15,25 +15,16 @@ const fs = require('fs');
15
15
  const path = require('path');
16
16
  const { spawnSync } = require('child_process');
17
17
 
18
- const { RED, GREEN, YELLOW, BLUE, BOLD, RESET } = require('./colors.js');
18
+ const {
19
+ RED, GREEN, YELLOW, BLUE, BOLD, DIM, CYAN, RESET,
20
+ banner, sectionHeader, timer, formatMs,
21
+ ok, fail, skip,
22
+ } = require('./_colors');
19
23
 
20
- function header(title) {
21
- console.log(`\n${BOLD}${BLUE}━━━ ${title} ━━━${RESET}`);
22
- }
23
-
24
- function ok(msg) {
25
- console.log(` ${GREEN}✅ ${msg}${RESET}`);
26
- }
27
-
28
- function fail(msg) {
29
- console.log(` ${RED}❌ ${msg}${RESET}`);
30
- }
31
-
32
- function skip(msg) {
33
- console.log(` ${YELLOW}⏭️ ${msg}${RESET}`);
34
- }
24
+ const { loadJson } = require('./_utils');
35
25
 
36
26
  function runTests(label, cmd, cwd) {
27
+ const elapsed = timer();
37
28
  try {
38
29
  const executable = process.platform === 'win32' && (cmd[0] === 'npx' || cmd[0] === 'npm') ? `${cmd[0]}.cmd` : cmd[0];
39
30
  const result = spawnSync(executable, cmd.slice(1), {
@@ -43,6 +34,8 @@ function runTests(label, cmd, cwd) {
43
34
  shell: process.platform === 'win32'
44
35
  });
45
36
 
37
+ const ms = elapsed();
38
+
46
39
  if (result.error && !result.stdout && !result.stderr) {
47
40
  console.log(` Error: ${result.error.message}`);
48
41
  }
@@ -56,11 +49,11 @@ function runTests(label, cmd, cwd) {
56
49
  }
57
50
 
58
51
  if (result.status === 0) {
59
- ok(`${label} — all tests passed`);
52
+ ok(`${label} — all tests passed ${DIM}(${formatMs(ms)})${RESET}`);
60
53
  return true;
61
54
  }
62
55
 
63
- fail(`${label} — test failures detected`);
56
+ fail(`${label} — test failures detected ${DIM}(${formatMs(ms)})${RESET}`);
64
57
  return false;
65
58
  } catch {
66
59
  skip(`${label} — tool not installed`);
@@ -69,20 +62,15 @@ function runTests(label, cmd, cwd) {
69
62
  }
70
63
 
71
64
  function detectTestFramework(projectRoot) {
72
- const pkgJson = path.join(projectRoot, "package.json");
73
- if (fs.existsSync(pkgJson)) {
74
- try {
75
- const pkg = JSON.parse(fs.readFileSync(pkgJson, 'utf8'));
76
- const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
77
- const scripts = pkg.scripts || {};
78
-
79
- if (deps.vitest) return "vitest";
80
- if (deps.jest) return "jest";
81
- if (deps.mocha) return "mocha";
82
- if (scripts.test) return "npm-test";
83
- } catch {
84
- if (fs.readFileSync(pkgJson, 'utf8').includes('"test"')) return "npm-test";
85
- }
65
+ const pkg = loadJson(path.join(projectRoot, "package.json"));
66
+ if (pkg) {
67
+ const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
68
+ const scripts = pkg.scripts || {};
69
+
70
+ if (deps.vitest) return "vitest";
71
+ if (deps.jest) return "jest";
72
+ if (deps.mocha) return "mocha";
73
+ if (scripts.test) return "npm-test";
86
74
  }
87
75
 
88
76
  if (fs.existsSync(path.join(projectRoot, "pytest.ini")) ||
@@ -137,16 +125,18 @@ function main() {
137
125
  process.exit(1);
138
126
  }
139
127
 
140
- console.log(`${BOLD}Tribunal — test_runner.js${RESET}`);
141
- console.log(`Project: ${projectRoot}`);
142
-
143
128
  const framework = detectTestFramework(projectRoot);
129
+ console.log(banner('test_runner.js', {
130
+ Project: projectRoot,
131
+ Framework: framework || 'none detected',
132
+ }));
133
+
144
134
  if (!framework) {
145
135
  skip("No test framework detected in this project");
146
136
  process.exit(0);
147
137
  }
148
138
 
149
- header(`Running tests (${framework})`);
139
+ console.log(sectionHeader(`Running tests (${framework})`));
150
140
 
151
141
  let cmd = [];
152
142
  let passed = true;
@@ -181,9 +171,12 @@ function main() {
181
171
  passed = runTests("go test", cmd, projectRoot);
182
172
  }
183
173
 
184
- console.log(`\n${BOLD}━━━ Test Summary ━━━${RESET}`);
185
- if (passed) ok(`Tests passed (${framework})`);
186
- else fail(`Tests failed (${framework})`);
174
+ console.log(`\n${BOLD}${CYAN}━━━ Test Summary ━━━${RESET}`);
175
+ if (passed) {
176
+ console.log(`\n${GREEN}${BOLD} ✔ Tests passed (${framework}).${RESET}\n`);
177
+ } else {
178
+ console.log(`\n${RED}${BOLD} ✖ Tests failed (${framework}).${RESET}\n`);
179
+ }
187
180
 
188
181
  process.exit(passed ? 0 : 1);
189
182
  }
@@ -1,32 +1,17 @@
1
1
  /**
2
- * utils.js
3
- * Shared utilities for Tribunal Kit Node scripts.
2
+ * utils.js — Backward-compatible re-export of _utils.js
3
+ * ══════════════════════════════════════════════════════
4
+ * All utilities are defined in _utils.js.
5
+ * This file re-exports them for scripts that import from './utils.js'.
6
+ *
7
+ * New scripts should import from './_utils' directly.
4
8
  */
5
9
  'use strict';
6
10
 
7
- const path = require('path');
8
- const fs = require('fs');
9
-
10
- function findAgentDir() {
11
- let current = path.resolve(process.cwd());
12
- const root = path.parse(current).root;
13
- while (current !== root) {
14
- const candidate = path.join(current, '.agent');
15
- if (fs.existsSync(candidate) && fs.statSync(candidate).isDirectory()) {
16
- return candidate;
17
- }
18
- current = path.dirname(current);
19
- }
20
- console.error("\x1b[91m✖ Error: '.agent' directory not found. Please run 'npx tribunal-kit init' first.\x1b[0m");
21
- process.exit(1);
22
- }
23
-
24
- function ensureUtf8Stdout() {
25
- // In Node.js, process.stdout is typically already UTF-8 capable,
26
- // but this exists for compatibility with legacy python workflows.
27
- }
11
+ const _utils = require('./_utils');
28
12
 
29
13
  module.exports = {
30
- findAgentDir,
31
- ensureUtf8Stdout
14
+ ..._utils,
15
+ // Legacy export for compatibility
16
+ ensureUtf8Stdout: function() {},
32
17
  };
@@ -15,65 +15,68 @@ const fs = require('fs');
15
15
  const path = require('path');
16
16
  const { execFileSync } = require('child_process');
17
17
 
18
- // ━━━ ANSI colors ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
19
- const RED = '\x1b[91m';
20
- const GREEN = '\x1b[92m';
21
- const YELLOW = '\x1b[93m';
22
- const BLUE = '\x1b[94m';
23
- const BOLD = '\x1b[1m';
24
- const RESET = '\x1b[0m';
18
+ const {
19
+ RED, GREEN, YELLOW, BLUE, BOLD, DIM, CYAN, RESET,
20
+ banner, sectionHeader, summaryTable, timer, formatMs,
21
+ ok, fail, skip,
22
+ } = require('./_colors');
25
23
 
26
- const RESULTS = [];
24
+ const { walkDir, hasNpm, SOURCE_EXTENSIONS } = require('./_utils');
27
25
 
28
- function section(title) {
29
- console.log(`\n${BOLD}${BLUE}━━━ ${title} ━━━${RESET}`);
30
- }
26
+ // ── Results Tracking ────────────────────────────────────────────────────────
31
27
 
32
- function ok(label, note) {
33
- const msg = `${GREEN}✅ ${label}${RESET}` + (note ? ` ${YELLOW}(${note})${RESET}` : '');
34
- console.log(` ${msg}`);
35
- RESULTS.push({ label, passed: true, note: note || '' });
28
+ const RESULTS = [];
29
+
30
+ function trackOk(label, ms, note) {
31
+ const timing = ms != null ? `${DIM}(${formatMs(ms)})${RESET}` : '';
32
+ const noteStr = note ? ` ${DIM}${note}${RESET}` : '';
33
+ console.log(` ${GREEN}✅ ${label}${RESET} ${timing}${noteStr}`);
34
+ RESULTS.push({ name: label, status: 'pass', ms, note: note || '' });
36
35
  }
37
36
 
38
- function fail(label, note) {
37
+ function trackFail(label, ms, note) {
38
+ const timing = ms != null ? `${DIM}(${formatMs(ms)})${RESET}` : '';
39
39
  const noteStr = note ? `\n ${note}` : '';
40
- console.log(` ${RED}❌ ${label}${RESET}${noteStr}`);
41
- RESULTS.push({ label, passed: false, note: note || '' });
40
+ console.log(` ${RED}❌ ${label}${RESET} ${timing}${noteStr}`);
41
+ RESULTS.push({ name: label, status: 'fail', ms, note: note || '' });
42
42
  }
43
43
 
44
- function skip(label, reason) {
44
+ function trackSkip(label, reason) {
45
45
  console.log(` ${YELLOW}⏭️ ${label} — ${reason}${RESET}`);
46
- RESULTS.push({ label, passed: true, note: `skipped: ${reason}` });
46
+ RESULTS.push({ name: label, status: 'skip', note: `skipped: ${reason}` });
47
47
  }
48
48
 
49
+ // ── Command Runner ──────────────────────────────────────────────────────────
50
+
49
51
  /**
50
52
  * Run a shell command and return true if it exits with code 0.
51
53
  */
52
54
  function run(label, cmd, cwd) {
55
+ const elapsed = timer();
53
56
  try {
54
57
  const isWindows = process.platform === 'win32';
55
- let bin = cmd[0];
56
- if (isWindows && (bin === 'npm' || bin === 'npx')) bin += '.cmd';
57
58
 
58
- execFileSync(bin, cmd.slice(1), {
59
+ execFileSync(cmd[0], cmd.slice(1), {
59
60
  cwd,
60
61
  stdio: 'pipe',
61
62
  timeout: 120000,
62
63
  encoding: 'utf8',
64
+ shell: isWindows
63
65
  });
64
- ok(label);
66
+ trackOk(label, elapsed());
65
67
  return true;
66
68
  } catch (err) {
69
+ const ms = elapsed();
67
70
  if (err.code === 'ENOENT') {
68
- skip(label, 'tool not installed — skipping');
71
+ trackSkip(label, 'tool not installed — skipping');
69
72
  return true;
70
73
  }
71
74
  if (err.killed) {
72
- fail(label, 'timed out after 120s');
75
+ trackFail(label, ms, 'timed out after 120s');
73
76
  return false;
74
77
  }
75
78
  const output = ((err.stdout || '') + (err.stderr || '')).trim();
76
- fail(label, output ? output.slice(0, 500) : 'non-zero exit code');
79
+ trackFail(label, ms, output ? output.slice(0, 500) : 'non-zero exit code');
77
80
  return false;
78
81
  }
79
82
  }
@@ -81,140 +84,130 @@ function run(label, cmd, cwd) {
81
84
 
82
85
  /**
83
86
  * Scan source files for obviously hardcoded credentials.
87
+ * Uses shared walkDir from _utils.js to eliminate duplicated walker code.
84
88
  */
85
89
  function scanSecrets(cwd) {
90
+ const elapsed = timer();
86
91
  const patterns = ['password=', 'secret=', 'api_key=', 'private_key=', 'auth_token='];
87
92
  const found = [];
88
- const skipDirs = new Set(['node_modules', '.git', 'dist', '__pycache__', '.agent']);
89
-
90
- function walk(dir) {
91
- let entries;
92
- try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
93
-
94
- for (const entry of entries) {
95
- const fullPath = path.join(dir, entry.name);
96
- if (entry.isDirectory()) {
97
- if (!skipDirs.has(entry.name)) walk(fullPath);
98
- } else if (entry.isFile()) {
99
- if (!/\.(ts|js|tsx|jsx|py)$/.test(entry.name)) continue;
100
-
101
- let content;
102
- try { content = fs.readFileSync(fullPath, 'utf8'); } catch { continue; }
103
-
104
- const lines = content.split('\n');
105
- for (let i = 0; i < lines.length; i++) {
106
- const low = lines[i].toLowerCase().trim();
107
- const hasPattern = patterns.some(p => low.includes(p));
108
- if (hasPattern && !low.startsWith('#') && low.includes('=')) {
109
- const rel = path.relative(cwd, fullPath);
110
- found.push(`${rel}:${i + 1}`);
111
- }
112
- }
93
+
94
+ const sourceExtensions = new Set(['.ts', '.tsx', '.js', '.jsx', '.py']);
95
+ const files = walkDir(cwd, { extensions: sourceExtensions });
96
+
97
+ for (const fullPath of files) {
98
+ let content;
99
+ try { content = fs.readFileSync(fullPath, 'utf8'); } catch { continue; }
100
+
101
+ const lines = content.split('\n');
102
+ for (let i = 0; i < lines.length; i++) {
103
+ const low = lines[i].toLowerCase().trim();
104
+ const hasPattern = patterns.some(p => low.includes(p));
105
+ if (hasPattern && !low.startsWith('#') && low.includes('=')) {
106
+ const rel = path.relative(cwd, fullPath);
107
+ found.push(`${rel}:${i + 1}`);
113
108
  }
114
109
  }
115
110
  }
116
111
 
117
- walk(cwd);
118
-
112
+ const ms = elapsed();
119
113
  if (found.length > 0) {
120
- fail('Secret scan', found.slice(0, 5).join('\n '));
114
+ trackFail('Secret scan', ms, found.slice(0, 5).join('\n '));
121
115
  return false;
122
116
  }
123
- ok('Secret scan — no hardcoded credentials found');
117
+ trackOk('Secret scan — no hardcoded credentials found', ms, `${files.length} files scanned`);
124
118
  return true;
125
119
  }
126
120
 
127
121
 
128
- /**
129
- * Check if there's a package.json to run npm commands against.
130
- */
131
- function hasNpm(cwd) {
132
- return fs.existsSync(path.join(cwd, 'package.json'));
133
- }
134
-
135
-
136
122
  /**
137
123
  * Run all verification checks. Returns number of failures.
138
124
  */
139
125
  function verifyAll(cwd, skipped) {
140
126
  let failures = 0;
127
+ RESULTS.length = 0; // Reset for clean runs (prevents accumulation in tests)
128
+ const totalTimer = timer();
141
129
 
142
- section('1 — Secret Scan');
130
+ console.log(sectionHeader('Secret Scan', 1));
143
131
  if (!skipped.includes('secrets')) {
144
132
  if (!scanSecrets(cwd)) failures++;
145
133
  } else {
146
- skip('Secret scan', 'skipped by flag');
134
+ trackSkip('Secret scan', 'skipped by flag');
147
135
  }
148
136
 
149
- section('2 — TypeScript');
137
+ console.log(sectionHeader('TypeScript', 2));
150
138
  if (!skipped.includes('typescript')) {
151
139
  if (hasNpm(cwd)) {
152
140
  if (!run('tsc --noEmit', ['npx', 'tsc', '--noEmit'], cwd)) failures++;
153
141
  } else {
154
- skip('TypeScript', 'no package.json found in project');
142
+ trackSkip('TypeScript', 'no package.json found in project');
155
143
  }
156
144
  } else {
157
- skip('TypeScript', 'skipped by flag');
145
+ trackSkip('TypeScript', 'skipped by flag');
158
146
  }
159
147
 
160
- section('3 — ESLint');
148
+ console.log(sectionHeader('ESLint', 3));
161
149
  if (!skipped.includes('lint')) {
162
150
  if (hasNpm(cwd)) {
163
151
  if (!run('ESLint', ['npx', 'eslint', '.', '--max-warnings=0'], cwd)) failures++;
164
152
  } else {
165
- skip('ESLint', 'no package.json found in project');
153
+ trackSkip('ESLint', 'no package.json found in project');
166
154
  }
167
155
  } else {
168
- skip('ESLint', 'skipped by flag');
156
+ trackSkip('ESLint', 'skipped by flag');
169
157
  }
170
158
 
171
- section('4 — Unit Tests');
159
+ console.log(sectionHeader('Unit Tests', 4));
172
160
  if (!skipped.includes('tests')) {
173
161
  if (hasNpm(cwd)) {
174
162
  if (!run('Test suite', ['npm', 'test', '--', '--passWithNoTests'], cwd)) failures++;
175
163
  } else {
176
- skip('Tests', 'no package.json found in project');
164
+ trackSkip('Tests', 'no package.json found in project');
177
165
  }
178
166
  } else {
179
- skip('Tests', 'skipped by flag');
167
+ trackSkip('Tests', 'skipped by flag');
180
168
  }
181
169
 
182
- section('5 — Build');
170
+ console.log(sectionHeader('Build', 5));
183
171
  if (!skipped.includes('build')) {
184
172
  if (hasNpm(cwd)) {
185
173
  if (!run('npm run build', ['npm', 'run', 'build'], cwd)) failures++;
186
174
  } else {
187
- skip('Build', 'no package.json found in project');
175
+ trackSkip('Build', 'no package.json found in project');
188
176
  }
189
177
  } else {
190
- skip('Build', 'skipped by flag');
178
+ trackSkip('Build', 'skipped by flag');
191
179
  }
192
180
 
193
- section('6 — Dependency Audit');
181
+ console.log(sectionHeader('Dependency Audit', 6));
194
182
  if (!skipped.includes('deps')) {
195
183
  if (hasNpm(cwd)) {
196
184
  if (!run('npm audit', ['npm', 'audit', '--audit-level=high'], cwd)) failures++;
197
185
  } else {
198
- skip('Dependency audit', 'no package.json found in project');
186
+ trackSkip('Dependency audit', 'no package.json found in project');
199
187
  }
200
188
  } else {
201
- skip('Dependency audit', 'skipped by flag');
189
+ trackSkip('Dependency audit', 'skipped by flag');
202
190
  }
203
191
 
204
- // ━━━ Summary ━━━
205
- console.log(`\n${BOLD}━━━ Summary ━━━${RESET}`);
206
- for (const { label, passed, note } of RESULTS) {
207
- const status = passed ? `${GREEN}✅${RESET}` : `${RED}❌${RESET}`;
208
- const noteStr = (!passed && note) ? ` ${YELLOW}(${note})${RESET}` : '';
209
- console.log(` ${status} ${label}${noteStr}`);
210
- }
192
+ // ━━━ Summary Table ━━━
193
+ const totalMs = totalTimer();
194
+ console.log(`\n${BOLD}${CYAN}━━━ Verification Summary ━━━${RESET}`);
195
+ summaryTable(RESULTS);
196
+
197
+ const passCount = RESULTS.filter(r => r.status === 'pass').length;
198
+ const failCount = RESULTS.filter(r => r.status === 'fail').length;
199
+ const skipCount = RESULTS.filter(r => r.status === 'skip').length;
200
+
201
+ console.log(`\n ${DIM}Total: ${RESULTS.length} checks in ${formatMs(totalMs)}${RESET}`);
202
+ console.log(` ${GREEN}${passCount} passed${RESET} ${failCount > 0 ? `${RED}${failCount} failed${RESET} ` : ''}${skipCount > 0 ? `${YELLOW}${skipCount} skipped${RESET}` : ''}`);
211
203
 
212
204
  console.log();
213
205
  if (failures === 0) {
214
- console.log(`${GREEN}${BOLD}All checks passed — safe to deploy.${RESET}`);
206
+ console.log(`${GREEN}${BOLD}All checks passed — safe to deploy.${RESET}`);
215
207
  } else {
216
- console.log(`${RED}${BOLD}${failures} check(s) failed — fix before deploying.${RESET}`);
208
+ console.log(`${RED}${BOLD}${failures} check(s) failed — fix before deploying.${RESET}`);
217
209
  }
210
+ console.log();
218
211
 
219
212
  return failures;
220
213
  }
@@ -240,8 +233,7 @@ function main() {
240
233
  const args = parseArgs(process.argv);
241
234
  const cwd = process.cwd();
242
235
 
243
- console.log(`${BOLD}Tribunal — verify_all.js${RESET}`);
244
- console.log(`Project: ${cwd}\n`);
236
+ console.log(banner('verify_all.js', { Project: cwd }));
245
237
 
246
238
  const failures = verifyAll(cwd, args.skip);
247
239
  process.exit(failures > 0 ? 1 : 0);
@@ -73,4 +73,4 @@ project-name/
73
73
  - Use Content Collections for type safety
74
74
  - Leverage static generation
75
75
  - Add islands only where needed
76
- - Optimize images with Astro Image
76
+ - Optimize images with Astro Image
@@ -89,4 +89,4 @@ project-name/
89
89
  - Use type-safe messaging
90
90
  - Wrap Chrome APIs in promises
91
91
  - Minimize permissions
92
- - Handle offline gracefully
92
+ - Handle offline gracefully
@@ -85,4 +85,4 @@ npm publish
85
85
  - Support both interactive and non-interactive modes
86
86
  - Use consistent output styling
87
87
  - Validate inputs with Zod
88
- - Exit with proper codes (0 success, 1 error)
88
+ - Exit with proper codes (0 success, 1 error)
@@ -85,4 +85,4 @@ project-name/
85
85
  - Type-safe IPC with typed handlers
86
86
  - Custom title bar for native feel
87
87
  - Handle window state (maximize, minimize)
88
- - Auto-updates with electron-updater
88
+ - Auto-updates with electron-updater
@@ -80,4 +80,4 @@ project-name/
80
80
  - Validate all inputs with Zod
81
81
  - Centralized error handling
82
82
  - Environment-based config
83
- - Use Prisma for type-safe DB access
83
+ - Use Prisma for type-safe DB access
@@ -87,4 +87,4 @@ project_name/
87
87
  - Riverpod for state, React Query pattern for server state
88
88
  - Freezed for immutable data classes
89
89
  - Go Router for declarative navigation
90
- - Material 3 theming
90
+ - Material 3 theming
@@ -87,4 +87,4 @@ project-name/
87
87
  - Shared configs in packages/config
88
88
  - Shared types in packages/types
89
89
  - Internal packages with `workspace:*`
90
- - Use Turbo remote caching for CI
90
+ - Use Turbo remote caching for CI
@@ -119,4 +119,4 @@ project-name/
119
119
  - **Mutations**: Use Server Actions combined with React 19's `useActionState` to handle loading and error states instead of manual useState.
120
120
  - **Type Safety**: Share Zod schemas between Server Actions (input validation) and Client Forms.
121
121
  - **Security**: Always validate input data with Zod before passing it to Prisma.
122
- - **Styling**: Use native CSS variables in Tailwind v4 for easier dynamic theming.
122
+ - **Styling**: Use native CSS variables in Tailwind v4 for easier dynamic theming.
@@ -119,4 +119,4 @@ project-name/
119
119
  7. Run project:
120
120
  ```bash
121
121
  npm run dev
122
- ```
122
+ ```
@@ -166,4 +166,4 @@ export const metadata: Metadata = {
166
166
  - **React Server Components (RSC)**: Default all components to Server Components. Only add `'use client'` when you need state (`useState`) or event listeners (`onClick`).
167
167
  - **Image Optimization**: Use the `<Image />` component but remember `unoptimized: true` for static export or use an external image CDN (Cloudinary/Imgix).
168
168
  - **Font Optimization**: Use `next/font` (Google Fonts) to automatically host fonts and prevent layout shift.
169
- - **Responsive**: Mobile-first design using Tailwind prefixes like `sm:`, `md:`, `lg:`.
169
+ - **Responsive**: Mobile-first design using Tailwind prefixes like `sm:`, `md:`, `lg:`.
@@ -131,4 +131,4 @@ project-name/
131
131
  ```
132
132
  - **Data Fetching**: Sử dụng `useFetch` với `server: false` cho các tác vụ client-only, hoặc dùng Server Functions để type-safety tốt hơn.
133
133
  - **State**: Dùng `defineStore` (Pinia) cho global state, `useState` của Nuxt cho state đơn giản chia sẻ giữa Server/Client.
134
- - **Type Safety**: Tự động tạo type cho API routes (`$fetch` typed automatically).
134
+ - **Type Safety**: Tự động tạo type cho API routes (`$fetch` typed automatically).
@@ -80,4 +80,4 @@ project-name/
80
80
  - Pydantic v2 for validation
81
81
  - SQLAlchemy 2.0 async sessions
82
82
  - Alembic for migrations
83
- - pytest-asyncio for tests
83
+ - pytest-asyncio for tests
@@ -116,4 +116,4 @@ project-name/
116
116
  - **React 19**: Reduce usage of `useMemo` or `useCallback` thanks to React Compiler (if enabled).
117
117
  - **Components**: Build UI primitives (Box, Text) with NativeWind className for reusability.
118
118
  - **Assets**: Use `expo-image` instead of default `<Image />` for better caching and performance.
119
- - **API**: Always wrap API calls with TanStack Query, avoid direct calls in `useEffect`.
119
+ - **API**: Always wrap API calls with TanStack Query, avoid direct calls in `useEffect`.
@@ -174,4 +174,4 @@ By creating Skills, you transform a general AI model into an expert for your pro
174
174
  - ✅ Automatically add license headers
175
175
  - ✅ The Agent automatically knows how to work with your team
176
176
 
177
- Instead of constantly reminding the AI to "remember to add the license" or "fix the commit format," now the Agent will do it automatically!
177
+ Instead of constantly reminding the AI to "remember to add the license" or "fix the commit format," now the Agent will do it automatically!