tribunal-kit 5.7.0 → 5.8.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 (56) hide show
  1. package/.agent/ARCHITECTURE.md +6 -7
  2. package/.agent/agents/frontend-reviewer.md +13 -0
  3. package/.agent/agents/frontend-specialist.md +14 -0
  4. package/.agent/agents/logic-reviewer.md +11 -0
  5. package/.agent/agents/orchestrator.md +15 -0
  6. package/.agent/agents/security-auditor.md +13 -0
  7. package/.agent/agents/ui-ux-auditor.md +7 -31
  8. package/.agent/history/memory/.memory.idx +766 -0
  9. package/.agent/history/memory/MEMORY.md +62 -0
  10. package/.agent/routing_index.json +694 -714
  11. package/.agent/rules/GEMINI.md +58 -8
  12. package/.agent/scripts/_colors.js +131 -89
  13. package/.agent/scripts/_utils.js +163 -128
  14. package/.agent/scripts/auto_preview.js +207 -197
  15. package/.agent/scripts/bundle_analyzer.js +227 -192
  16. package/.agent/scripts/case_law_manager.js +991 -689
  17. package/.agent/scripts/checklist.js +233 -190
  18. package/.agent/scripts/context_broker.js +930 -605
  19. package/.agent/scripts/dependency_analyzer.js +275 -184
  20. package/.agent/scripts/graph_builder.js +412 -341
  21. package/.agent/scripts/graph_visualizer.js +392 -390
  22. package/.agent/scripts/graph_zoom.js +198 -156
  23. package/.agent/scripts/inner_loop_validator.js +523 -445
  24. package/.agent/scripts/lint_runner.js +199 -157
  25. package/.agent/scripts/marathon_harness.js +819 -661
  26. package/.agent/scripts/minify_context.js +115 -100
  27. package/.agent/scripts/mutation_runner.js +321 -280
  28. package/.agent/scripts/prompt_compiler.js +62 -42
  29. package/.agent/scripts/schema_validator.js +373 -280
  30. package/.agent/scripts/security_scan.js +333 -190
  31. package/.agent/scripts/session_manager.js +306 -270
  32. package/.agent/scripts/skill_evolution.js +810 -637
  33. package/.agent/scripts/skill_integrator.js +327 -307
  34. package/.agent/scripts/strengthen_skills.js +203 -193
  35. package/.agent/scripts/swarm_dispatcher.js +558 -457
  36. package/.agent/scripts/test_runner.js +178 -152
  37. package/.agent/scripts/verify_all.js +200 -168
  38. package/.agent/skills/fabel-protocol/SKILL.md +235 -0
  39. package/.agent/skills/thinking-protocol/SKILL.md +27 -0
  40. package/.agent/workflows/generate.md +1 -1
  41. package/.agent/workflows/tribunal-speed.md +1 -1
  42. package/README.md +53 -53
  43. package/bin/mcp-server.js +460 -175
  44. package/bin/tribunal-kit.js +1245 -987
  45. package/bin/wrapper.js +104 -74
  46. package/dist/cli.js +31 -0
  47. package/dist/commands/case.js +23 -0
  48. package/dist/commands/compile.js +84 -0
  49. package/dist/commands/init.js +42 -0
  50. package/dist/commands/learn.js +57 -0
  51. package/dist/commands/memory.js +456 -0
  52. package/package.json +2 -2
  53. package/scripts/benchmark.js +162 -125
  54. package/scripts/changelog.js +196 -168
  55. package/scripts/sync-version.js +94 -81
  56. package/scripts/validate-payload.js +85 -78
@@ -17,43 +17,52 @@
17
17
  * node .agent/scripts/checklist.js . --skip security,seo
18
18
  */
19
19
 
20
- 'use strict';
20
+ "use strict";
21
21
 
22
- const fs = require('fs');
23
- const path = require('path');
24
- const { execFileSync } = require('child_process');
22
+ const fs = require("fs");
23
+ const path = require("path");
24
+ const { execFileSync } = require("child_process");
25
25
 
26
26
  const {
27
- RED, GREEN, YELLOW, BLUE, BOLD, DIM, CYAN, RESET,
28
- banner, sectionHeader, summaryTable, timer, formatMs,
29
- ok, fail, skip,
30
- } = require('./_colors');
31
-
32
- const { walkDir } = require('./_utils');
27
+ RED,
28
+ GREEN,
29
+ YELLOW,
30
+ BOLD,
31
+ DIM,
32
+ CYAN,
33
+ RESET,
34
+ banner,
35
+ sectionHeader,
36
+ summaryTable,
37
+ timer,
38
+ formatMs,
39
+ fail,
40
+ } = require("./_colors");
41
+
42
+ const { walkDir } = require("./_utils");
33
43
 
34
44
  // ── Results Tracking ────────────────────────────────────────────────────────
35
45
 
36
46
  const RESULTS = [];
37
47
 
38
48
  function trackOk(label, ms) {
39
- const timing = ms != null ? `${DIM}(${formatMs(ms)})${RESET}` : '';
40
- console.log(` ${GREEN}✅ ${label}${RESET} ${timing}`);
41
- RESULTS.push({ name: label, status: 'pass', ms });
49
+ const timing = ms != null ? `${DIM}(${formatMs(ms)})${RESET}` : "";
50
+ console.log(` ${GREEN}✅ ${label}${RESET} ${timing}`);
51
+ RESULTS.push({ name: label, status: "pass", ms });
42
52
  }
43
53
 
44
54
  function trackFail(label, ms, note) {
45
- const timing = ms != null ? `${DIM}(${formatMs(ms)})${RESET}` : '';
46
- console.log(` ${RED}❌ ${label}${RESET} ${timing}`);
47
- if (note) console.log(` ${note.slice(0, 500)}`);
48
- RESULTS.push({ name: label, status: 'fail', ms });
55
+ const timing = ms != null ? `${DIM}(${formatMs(ms)})${RESET}` : "";
56
+ console.log(` ${RED}❌ ${label}${RESET} ${timing}`);
57
+ if (note) console.log(` ${note.slice(0, 500)}`);
58
+ RESULTS.push({ name: label, status: "fail", ms });
49
59
  }
50
60
 
51
61
  function trackSkip(label, reason) {
52
- console.log(` ${YELLOW}⏭️ ${label} — ${reason}${RESET}`);
53
- RESULTS.push({ name: label, status: 'skip' });
62
+ console.log(` ${YELLOW}⏭️ ${label} — ${reason}${RESET}`);
63
+ RESULTS.push({ name: label, status: "skip" });
54
64
  }
55
65
 
56
-
57
66
  /**
58
67
  * Run a shell command and return true if it exits with code 0.
59
68
  * @param {string} label - Human-readable label for the check.
@@ -62,34 +71,33 @@ function trackSkip(label, reason) {
62
71
  * @returns {boolean}
63
72
  */
64
73
  function runCheck(label, cmd, cwd) {
65
- const elapsed = timer();
66
- try {
67
- execFileSync(cmd[0], cmd.slice(1), {
68
- cwd,
69
- stdio: 'pipe',
70
- timeout: 60000,
71
- encoding: 'utf8',
72
- shell: process.platform === 'win32',
73
- });
74
- trackOk(`${label} passed`, elapsed());
75
- return true;
76
- } catch (err) {
77
- const ms = elapsed();
78
- if (err.code === 'ENOENT') {
79
- trackSkip(label, 'command not found (tool not installed)');
80
- return true; // Don't block on tools that aren't installed
81
- }
82
- if (err.killed) {
83
- trackFail(label, ms, 'timed out after 60s');
84
- return false;
85
- }
86
- const output = ((err.stdout || '') + (err.stderr || '')).trim();
87
- trackFail(`${label} failed`, ms, output || 'non-zero exit code');
88
- return false;
74
+ const elapsed = timer();
75
+ try {
76
+ execFileSync(cmd[0], cmd.slice(1), {
77
+ cwd,
78
+ stdio: "pipe",
79
+ timeout: 60000,
80
+ encoding: "utf8",
81
+ shell: process.platform === "win32",
82
+ });
83
+ trackOk(`${label} passed`, elapsed());
84
+ return true;
85
+ } catch (err) {
86
+ const ms = elapsed();
87
+ if (err.code === "ENOENT") {
88
+ trackSkip(label, "command not found (tool not installed)");
89
+ return true; // Don't block on tools that aren't installed
90
+ }
91
+ if (err.killed) {
92
+ trackFail(label, ms, "timed out after 60s");
93
+ return false;
89
94
  }
95
+ const output = ((err.stdout || "") + (err.stderr || "")).trim();
96
+ trackFail(`${label} failed`, ms, output || "non-zero exit code");
97
+ return false;
98
+ }
90
99
  }
91
100
 
92
-
93
101
  /**
94
102
  * Scan for hardcoded secrets in source files.
95
103
  * Uses shared walkDir from _utils.js.
@@ -97,45 +105,54 @@ function runCheck(label, cmd, cwd) {
97
105
  * @returns {boolean} True if no secrets found.
98
106
  */
99
107
  function checkSecrets(projectRoot) {
100
- const elapsed = timer();
101
- const dangerousPatterns = [
102
- 'password=', 'secret=', 'api_key=',
103
- 'apikey=', 'auth_token=', 'private_key=',
104
- ];
105
- let foundIssues = false;
106
- const sourceExtensions = new Set(['.ts', '.tsx', '.js', '.jsx', '.py']);
107
-
108
- const files = walkDir(projectRoot, { extensions: sourceExtensions });
109
-
110
- for (const fullPath of files) {
111
- // Skip .env files — they are allowed to contain secrets
112
- if (path.basename(fullPath).startsWith('.env')) continue;
113
-
114
- let content;
115
- try { content = fs.readFileSync(fullPath, 'utf8'); } catch { continue; }
116
-
117
- const lines = content.split('\n');
118
- for (let i = 0; i < lines.length; i++) {
119
- const lineLower = lines[i].toLowerCase().trim();
120
- const hasPattern = dangerousPatterns.some(p => lineLower.includes(p));
121
- if (hasPattern && lineLower.includes('=') && !lineLower.startsWith('#')) {
122
- const rel = path.relative(projectRoot, fullPath);
123
- fail(`Possible secret: ${rel}:${i + 1} → ${lines[i].trim().slice(0, 80)}`);
124
- foundIssues = true;
125
- }
126
- }
108
+ const elapsed = timer();
109
+ const dangerousPatterns = [
110
+ "password=",
111
+ "secret=",
112
+ "api_key=",
113
+ "apikey=",
114
+ "auth_token=",
115
+ "private_key=",
116
+ ];
117
+ let foundIssues = false;
118
+ const sourceExtensions = new Set([".ts", ".tsx", ".js", ".jsx", ".py"]);
119
+
120
+ const files = walkDir(projectRoot, { extensions: sourceExtensions });
121
+
122
+ for (const fullPath of files) {
123
+ // Skip .env files they are allowed to contain secrets
124
+ if (path.basename(fullPath).startsWith(".env")) continue;
125
+
126
+ let content;
127
+ try {
128
+ content = fs.readFileSync(fullPath, "utf8");
129
+ } catch {
130
+ continue;
127
131
  }
128
132
 
129
- const ms = elapsed();
130
- if (!foundIssues) {
131
- trackOk(`Secret scan ${files.length} files clean`, ms);
132
- } else {
133
- trackFail('Secret scan hardcoded credentials detected', ms);
133
+ const lines = content.split("\n");
134
+ for (let i = 0; i < lines.length; i++) {
135
+ const lineLower = lines[i].toLowerCase().trim();
136
+ const hasPattern = dangerousPatterns.some((p) => lineLower.includes(p));
137
+ if (hasPattern && lineLower.includes("=") && !lineLower.startsWith("#")) {
138
+ const rel = path.relative(projectRoot, fullPath);
139
+ fail(
140
+ `Possible secret: ${rel}:${i + 1} → ${lines[i].trim().slice(0, 80)}`,
141
+ );
142
+ foundIssues = true;
143
+ }
134
144
  }
135
- return !foundIssues;
145
+ }
146
+
147
+ const ms = elapsed();
148
+ if (!foundIssues) {
149
+ trackOk(`Secret scan — ${files.length} files clean`, ms);
150
+ } else {
151
+ trackFail("Secret scan — hardcoded credentials detected", ms);
152
+ }
153
+ return !foundIssues;
136
154
  }
137
155
 
138
-
139
156
  /**
140
157
  * Run all checklist tiers. Returns number of failures.
141
158
  * @param {string} projectRoot - Project root.
@@ -144,135 +161,161 @@ function checkSecrets(projectRoot) {
144
161
  * @returns {number}
145
162
  */
146
163
  function runAll(projectRoot, url, skipTiers) {
147
- let failures = 0;
148
- RESULTS.length = 0;
149
- const totalTimer = timer();
150
-
151
- // Priority 1 — Security
152
- if (!skipTiers.includes('security')) {
153
- console.log(sectionHeader('Security — Secret Scan', 1));
154
- if (!checkSecrets(projectRoot)) failures++;
155
- } else {
156
- trackSkip('Security', 'skipped by flag');
157
- }
158
-
159
- // Priority 2 — Lint
160
- if (!skipTiers.includes('lint')) {
161
- console.log(sectionHeader('Lint', 2));
162
- if (!runCheck('ESLint', ['npx', 'eslint', '.', '--max-warnings=0'], projectRoot)) failures++;
163
- if (!runCheck('TypeScript', ['npx', 'tsc', '--noEmit'], projectRoot)) failures++;
164
- } else {
165
- trackSkip('Lint', 'skipped by flag');
166
- }
167
-
168
- // Priority 3 — Schema
169
- if (!skipTiers.includes('schema')) {
170
- console.log(sectionHeader('Schema Validation', 3));
171
- trackSkip('Schema', 'run manually if you have DB migrations');
172
- } else {
173
- trackSkip('Schema', 'skipped by flag');
174
- }
175
-
176
- // Priority 4Tests
177
- if (!skipTiers.includes('tests')) {
178
- console.log(sectionHeader('Tests', 4));
179
- if (!runCheck('Test suite', ['npm', 'test', '--', '--passWithNoTests'], projectRoot)) failures++;
180
- } else {
181
- trackSkip('Tests', 'skipped by flag');
182
- }
183
-
184
- // Priority 5UX
185
- if (!skipTiers.includes('ux')) {
186
- console.log(sectionHeader('UX / Accessibility', 5));
187
- trackSkip('UX audit', 'run /preview start then check with Lighthouse');
188
- } else {
189
- trackSkip('UX', 'skipped by flag');
190
- }
191
-
192
- // Priority 6 — SEO
193
- if (!skipTiers.includes('seo')) {
194
- console.log(sectionHeader('SEO', 6));
195
- trackSkip('SEO check', 'use /ui-ux-pro-max for SEO-sensitive pages');
196
- } else {
197
- trackSkip('SEO', 'skipped by flag');
198
- }
199
-
200
- // Priority 7 — Lighthouse / E2E
201
- if (url && !skipTiers.includes('e2e')) {
202
- console.log(sectionHeader('Lighthouse / E2E', 7));
203
- if (!runCheck('Playwright E2E', ['npx', 'playwright', 'test'], projectRoot)) failures++;
204
- } else if (!url) {
205
- trackSkip('E2E / Lighthouse', 'pass --url to enable');
206
- }
207
-
208
- // ━━━ Summary ━━━
209
- const totalMs = totalTimer();
210
- console.log(`\n${BOLD}${CYAN}━━━ Checklist Summary ━━━${RESET}`);
211
- summaryTable(RESULTS);
212
-
213
- const passCount = RESULTS.filter(r => r.status === 'pass').length;
214
- const failCount = RESULTS.filter(r => r.status === 'fail').length;
215
- const skipCount = RESULTS.filter(r => r.status === 'skip').length;
216
-
217
- console.log(`\n ${DIM}Total: ${RESULTS.length} checks in ${formatMs(totalMs)}${RESET}`);
218
- console.log(` ${GREEN}${passCount} passed${RESET} ${failCount > 0 ? `${RED}${failCount} failed${RESET} ` : ''}${skipCount > 0 ? `${YELLOW}${skipCount} skipped${RESET}` : ''}`);
219
-
220
- console.log();
221
- if (failures === 0) {
222
- console.log(`${GREEN}${BOLD} ✔ All checks passed — ready to proceed.${RESET}`);
223
- } else {
224
- console.log(`${RED}${BOLD} ${failures} tier(s) failed — fix critical issues before proceeding.${RESET}`);
225
- }
226
- console.log();
227
-
228
- return failures;
164
+ let failures = 0;
165
+ RESULTS.length = 0;
166
+ const totalTimer = timer();
167
+
168
+ // Priority 1 — Security
169
+ if (!skipTiers.includes("security")) {
170
+ console.log(sectionHeader("Security — Secret Scan", 1));
171
+ if (!checkSecrets(projectRoot)) failures++;
172
+ } else {
173
+ trackSkip("Security", "skipped by flag");
174
+ }
175
+
176
+ // Priority 2 — Lint
177
+ if (!skipTiers.includes("lint")) {
178
+ console.log(sectionHeader("Lint", 2));
179
+ if (
180
+ !runCheck(
181
+ "ESLint",
182
+ ["npx", "eslint", ".", "--max-warnings=0"],
183
+ projectRoot,
184
+ )
185
+ )
186
+ failures++;
187
+ if (!runCheck("TypeScript", ["npx", "tsc", "--noEmit"], projectRoot))
188
+ failures++;
189
+ } else {
190
+ trackSkip("Lint", "skipped by flag");
191
+ }
192
+
193
+ // Priority 3Schema
194
+ if (!skipTiers.includes("schema")) {
195
+ console.log(sectionHeader("Schema Validation", 3));
196
+ trackSkip("Schema", "run manually if you have DB migrations");
197
+ } else {
198
+ trackSkip("Schema", "skipped by flag");
199
+ }
200
+
201
+ // Priority 4Tests
202
+ if (!skipTiers.includes("tests")) {
203
+ console.log(sectionHeader("Tests", 4));
204
+ if (
205
+ !runCheck(
206
+ "Test suite",
207
+ ["npm", "test", "--", "--passWithNoTests"],
208
+ projectRoot,
209
+ )
210
+ )
211
+ failures++;
212
+ } else {
213
+ trackSkip("Tests", "skipped by flag");
214
+ }
215
+
216
+ // Priority 5 — UX
217
+ if (!skipTiers.includes("ux")) {
218
+ console.log(sectionHeader("UX / Accessibility", 5));
219
+ trackSkip("UX audit", "run /preview start then check with Lighthouse");
220
+ } else {
221
+ trackSkip("UX", "skipped by flag");
222
+ }
223
+
224
+ // Priority 6 — SEO
225
+ if (!skipTiers.includes("seo")) {
226
+ console.log(sectionHeader("SEO", 6));
227
+ trackSkip("SEO check", "use /ui-ux-pro-max for SEO-sensitive pages");
228
+ } else {
229
+ trackSkip("SEO", "skipped by flag");
230
+ }
231
+
232
+ // Priority 7 Lighthouse / E2E
233
+ if (url && !skipTiers.includes("e2e")) {
234
+ console.log(sectionHeader("Lighthouse / E2E", 7));
235
+ if (!runCheck("Playwright E2E", ["npx", "playwright", "test"], projectRoot))
236
+ failures++;
237
+ } else if (!url) {
238
+ trackSkip("E2E / Lighthouse", "pass --url to enable");
239
+ }
240
+
241
+ // ━━━ Summary ━━━
242
+ const totalMs = totalTimer();
243
+ console.log(`\n${BOLD}${CYAN}━━━ Checklist Summary ━━━${RESET}`);
244
+ summaryTable(RESULTS);
245
+
246
+ const passCount = RESULTS.filter((r) => r.status === "pass").length;
247
+ const failCount = RESULTS.filter((r) => r.status === "fail").length;
248
+ const skipCount = RESULTS.filter((r) => r.status === "skip").length;
249
+
250
+ console.log(
251
+ `\n ${DIM}Total: ${RESULTS.length} checks in ${formatMs(totalMs)}${RESET}`,
252
+ );
253
+ console.log(
254
+ ` ${GREEN}${passCount} passed${RESET} ${failCount > 0 ? `${RED}${failCount} failed${RESET} ` : ""}${skipCount > 0 ? `${YELLOW}${skipCount} skipped${RESET}` : ""}`,
255
+ );
256
+
257
+ console.log();
258
+ if (failures === 0) {
259
+ console.log(
260
+ `${GREEN}${BOLD} ✔ All checks passed — ready to proceed.${RESET}`,
261
+ );
262
+ } else {
263
+ console.log(
264
+ `${RED}${BOLD} ✖ ${failures} tier(s) failed — fix critical issues before proceeding.${RESET}`,
265
+ );
266
+ }
267
+ console.log();
268
+
269
+ return failures;
229
270
  }
230
271
 
231
-
232
272
  /**
233
273
  * Parse CLI arguments manually (no external dependencies).
234
274
  */
235
275
  function parseArgs(argv) {
236
- const args = { path: null, url: null, skip: [] };
237
- const raw = argv.slice(2);
238
-
239
- for (let i = 0; i < raw.length; i++) {
240
- if (raw[i] === '--url' && raw[i + 1]) {
241
- args.url = raw[++i];
242
- } else if (raw[i] === '--skip' && raw[i + 1]) {
243
- args.skip = raw[++i].split(',').map(s => s.trim().toLowerCase()).filter(Boolean);
244
- } else if (!raw[i].startsWith('--') && !args.path) {
245
- args.path = raw[i];
246
- }
276
+ const args = { path: null, url: null, skip: [] };
277
+ const raw = argv.slice(2);
278
+
279
+ for (let i = 0; i < raw.length; i++) {
280
+ if (raw[i] === "--url" && raw[i + 1]) {
281
+ args.url = raw[++i];
282
+ } else if (raw[i] === "--skip" && raw[i + 1]) {
283
+ args.skip = raw[++i]
284
+ .split(",")
285
+ .map((s) => s.trim().toLowerCase())
286
+ .filter(Boolean);
287
+ } else if (!raw[i].startsWith("--") && !args.path) {
288
+ args.path = raw[i];
247
289
  }
248
- return args;
290
+ }
291
+ return args;
249
292
  }
250
293
 
251
-
252
294
  function main() {
253
- const args = parseArgs(process.argv);
295
+ const args = parseArgs(process.argv);
254
296
 
255
- if (!args.path) {
256
- console.error(`Usage: node checklist.js <path> [--url <url>] [--skip security,lint,schema,tests,ux,seo,e2e]`);
257
- process.exit(1);
258
- }
297
+ if (!args.path) {
298
+ console.error(
299
+ `Usage: node checklist.js <path> [--url <url>] [--skip security,lint,schema,tests,ux,seo,e2e]`,
300
+ );
301
+ process.exit(1);
302
+ }
259
303
 
260
- const projectRoot = path.resolve(args.path);
261
- if (!fs.existsSync(projectRoot) || !fs.statSync(projectRoot).isDirectory()) {
262
- fail(`Directory not found: ${projectRoot}`);
263
- process.exit(1);
264
- }
304
+ const projectRoot = path.resolve(args.path);
305
+ if (!fs.existsSync(projectRoot) || !fs.statSync(projectRoot).isDirectory()) {
306
+ fail(`Directory not found: ${projectRoot}`);
307
+ process.exit(1);
308
+ }
265
309
 
266
- console.log(banner('checklist.js', { Project: projectRoot }));
310
+ console.log(banner("checklist.js", { Project: projectRoot }));
267
311
 
268
- const failures = runAll(projectRoot, args.url, args.skip);
269
- process.exit(failures > 0 ? 1 : 0);
312
+ const failures = runAll(projectRoot, args.url, args.skip);
313
+ process.exit(failures > 0 ? 1 : 0);
270
314
  }
271
315
 
272
-
273
316
  // ━━━ Exports for testing & programmatic use ━━━
274
317
  module.exports = { runCheck, checkSecrets, runAll };
275
318
 
276
319
  if (require.main === module) {
277
- main();
320
+ main();
278
321
  }