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.
- 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/history/architecture-graph.yaml +32 -1
- package/.agent/history/graph-cache.json +66 -19
- package/.agent/history/snapshots/bin__tribunal-kit.js.json +19 -0
- package/.agent/history/snapshots/eslint.config.js.json +9 -0
- package/.agent/history/snapshots/migrate_refs.js.json +3 -3
- package/.agent/history/snapshots/scripts__changelog.js.json +2 -1
- package/.agent/history/snapshots/scripts__sync-version.js.json +2 -1
- package/.agent/history/snapshots/scripts__validate-payload.js.json +1 -0
- package/.agent/history/snapshots/test__integration__bridges.test.js.json +2 -1
- package/.agent/history/snapshots/test__integration__init.test.js.json +1 -0
- package/.agent/history/snapshots/test__integration__routing.test.js.json +1 -0
- package/.agent/history/snapshots/test__integration__swarm_dispatcher.test.js.json +2 -1
- package/.agent/history/snapshots/test__integration__wave2.test.js.json +2 -1
- package/.agent/history/snapshots/test__unit__args.test.js.json +11 -1
- package/.agent/history/snapshots/test__unit__case_law_manager.test.js.json +1 -0
- package/.agent/history/snapshots/test__unit__context_broker.test.js.json +11 -0
- package/.agent/history/snapshots/test__unit__copyDir.test.js.json +11 -1
- package/.agent/history/snapshots/test__unit__graph_tools.test.js.json +1 -0
- package/.agent/history/snapshots/test__unit__inner_loop_validator.test.js.json +11 -0
- package/.agent/history/snapshots/test__unit__selfInstall.test.js.json +11 -1
- package/.agent/history/snapshots/test__unit__semver.test.js.json +11 -1
- package/.agent/history/snapshots/test__unit__swarm_dispatcher.test.js.json +1 -0
- package/.agent/scripts/_colors.js +154 -2
- package/.agent/scripts/_utils.js +205 -3
- package/.agent/scripts/append_flow.js +72 -72
- package/.agent/scripts/auto_preview.js +197 -197
- package/.agent/scripts/bundle_analyzer.js +90 -119
- package/.agent/scripts/case_law_manager.js +18 -13
- package/.agent/scripts/checklist.js +100 -88
- package/.agent/scripts/colors.js +7 -13
- package/.agent/scripts/compress_skills.js +141 -141
- package/.agent/scripts/consolidate_skills.js +149 -149
- package/.agent/scripts/context_broker.js +605 -609
- package/.agent/scripts/deep_compress.js +150 -150
- package/.agent/scripts/dependency_analyzer.js +68 -106
- package/.agent/scripts/graph_builder.js +341 -311
- package/.agent/scripts/graph_visualizer.js +390 -384
- package/.agent/scripts/graph_zoom.js +6 -4
- package/.agent/scripts/inner_loop_validator.js +445 -465
- package/.agent/scripts/lint_runner.js +27 -28
- package/.agent/scripts/minify_context.js +100 -100
- package/.agent/scripts/mutation_runner.js +280 -280
- package/.agent/scripts/patch_skills_meta.js +156 -156
- package/.agent/scripts/patch_skills_output.js +244 -244
- package/.agent/scripts/schema_validator.js +280 -297
- package/.agent/scripts/security_scan.js +37 -64
- package/.agent/scripts/session_manager.js +270 -276
- package/.agent/scripts/skill_evolution.js +637 -644
- package/.agent/scripts/skill_integrator.js +307 -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 +32 -39
- package/.agent/scripts/utils.js +10 -25
- package/.agent/scripts/verify_all.js +84 -92
- 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 +52 -52
- package/.agent/skills/ui-ux-pro-max/SKILL.md +562 -562
- 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 +76 -87
- package/package.json +6 -3
- package/scripts/changelog.js +167 -167
- package/scripts/sync-version.js +81 -81
- package/.agent/history/architecture-explorer.html +0 -352
- 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
|
@@ -23,29 +23,34 @@ const fs = require('fs');
|
|
|
23
23
|
const path = require('path');
|
|
24
24
|
const { execFileSync } = require('child_process');
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const BOLD = '\x1b[1m';
|
|
32
|
-
const RESET = '\x1b[0m';
|
|
26
|
+
const {
|
|
27
|
+
RED, GREEN, YELLOW, BLUE, BOLD, DIM, CYAN, RESET,
|
|
28
|
+
banner, sectionHeader, summaryTable, timer, formatMs,
|
|
29
|
+
ok, fail, skip,
|
|
30
|
+
} = require('./_colors');
|
|
33
31
|
|
|
32
|
+
const { walkDir } = require('./_utils');
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
// ── Results Tracking ────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
const RESULTS = [];
|
|
38
37
|
|
|
39
|
-
function
|
|
40
|
-
|
|
38
|
+
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 });
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
function
|
|
44
|
-
|
|
44
|
+
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 });
|
|
45
49
|
}
|
|
46
50
|
|
|
47
|
-
function
|
|
48
|
-
console.log(` ${YELLOW}⏭️
|
|
51
|
+
function trackSkip(label, reason) {
|
|
52
|
+
console.log(` ${YELLOW}⏭️ ${label} — ${reason}${RESET}`);
|
|
53
|
+
RESULTS.push({ name: label, status: 'skip' });
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
|
|
@@ -57,29 +62,29 @@ function printSkip(msg) {
|
|
|
57
62
|
* @returns {boolean}
|
|
58
63
|
*/
|
|
59
64
|
function runCheck(label, cmd, cwd) {
|
|
65
|
+
const elapsed = timer();
|
|
60
66
|
try {
|
|
61
67
|
execFileSync(cmd[0], cmd.slice(1), {
|
|
62
68
|
cwd,
|
|
63
69
|
stdio: 'pipe',
|
|
64
70
|
timeout: 60000,
|
|
65
71
|
encoding: 'utf8',
|
|
72
|
+
shell: process.platform === 'win32',
|
|
66
73
|
});
|
|
67
|
-
|
|
74
|
+
trackOk(`${label} passed`, elapsed());
|
|
68
75
|
return true;
|
|
69
76
|
} catch (err) {
|
|
77
|
+
const ms = elapsed();
|
|
70
78
|
if (err.code === 'ENOENT') {
|
|
71
|
-
|
|
79
|
+
trackSkip(label, 'command not found (tool not installed)');
|
|
72
80
|
return true; // Don't block on tools that aren't installed
|
|
73
81
|
}
|
|
74
82
|
if (err.killed) {
|
|
75
|
-
|
|
83
|
+
trackFail(label, ms, 'timed out after 60s');
|
|
76
84
|
return false;
|
|
77
85
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (output.trim()) {
|
|
81
|
-
console.log(` ${output.trim().slice(0, 500)}`);
|
|
82
|
-
}
|
|
86
|
+
const output = ((err.stdout || '') + (err.stderr || '')).trim();
|
|
87
|
+
trackFail(`${label} failed`, ms, output || 'non-zero exit code');
|
|
83
88
|
return false;
|
|
84
89
|
}
|
|
85
90
|
}
|
|
@@ -87,53 +92,45 @@ function runCheck(label, cmd, cwd) {
|
|
|
87
92
|
|
|
88
93
|
/**
|
|
89
94
|
* Scan for hardcoded secrets in source files.
|
|
95
|
+
* Uses shared walkDir from _utils.js.
|
|
90
96
|
* @param {string} projectRoot - Project root directory.
|
|
91
97
|
* @returns {boolean} True if no secrets found.
|
|
92
98
|
*/
|
|
93
99
|
function checkSecrets(projectRoot) {
|
|
94
|
-
|
|
100
|
+
const elapsed = timer();
|
|
95
101
|
const dangerousPatterns = [
|
|
96
102
|
'password=', 'secret=', 'api_key=',
|
|
97
103
|
'apikey=', 'auth_token=', 'private_key=',
|
|
98
104
|
];
|
|
99
105
|
let foundIssues = false;
|
|
100
|
-
const sourceExtensions = new Set(['.ts', '.tsx', '.js', '.jsx', '.py'
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
}
|
|
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;
|
|
129
125
|
}
|
|
130
126
|
}
|
|
131
127
|
}
|
|
132
128
|
|
|
133
|
-
|
|
134
|
-
|
|
129
|
+
const ms = elapsed();
|
|
135
130
|
if (!foundIssues) {
|
|
136
|
-
|
|
131
|
+
trackOk(`Secret scan — ${files.length} files clean`, ms);
|
|
132
|
+
} else {
|
|
133
|
+
trackFail('Secret scan — hardcoded credentials detected', ms);
|
|
137
134
|
}
|
|
138
135
|
return !foundIssues;
|
|
139
136
|
}
|
|
@@ -143,76 +140,90 @@ function checkSecrets(projectRoot) {
|
|
|
143
140
|
* Run all checklist tiers. Returns number of failures.
|
|
144
141
|
* @param {string} projectRoot - Project root.
|
|
145
142
|
* @param {string|null} url - URL for Lighthouse/E2E checks.
|
|
146
|
-
* @param {string[]}
|
|
143
|
+
* @param {string[]} skipTiers - Tiers to skip.
|
|
147
144
|
* @returns {number}
|
|
148
145
|
*/
|
|
149
|
-
function runAll(projectRoot, url,
|
|
146
|
+
function runAll(projectRoot, url, skipTiers) {
|
|
150
147
|
let failures = 0;
|
|
148
|
+
RESULTS.length = 0;
|
|
149
|
+
const totalTimer = timer();
|
|
151
150
|
|
|
152
151
|
// Priority 1 — Security
|
|
153
|
-
if (!
|
|
154
|
-
|
|
152
|
+
if (!skipTiers.includes('security')) {
|
|
153
|
+
console.log(sectionHeader('Security — Secret Scan', 1));
|
|
155
154
|
if (!checkSecrets(projectRoot)) failures++;
|
|
156
155
|
} else {
|
|
157
|
-
|
|
156
|
+
trackSkip('Security', 'skipped by flag');
|
|
158
157
|
}
|
|
159
158
|
|
|
160
159
|
// Priority 2 — Lint
|
|
161
|
-
if (!
|
|
162
|
-
|
|
160
|
+
if (!skipTiers.includes('lint')) {
|
|
161
|
+
console.log(sectionHeader('Lint', 2));
|
|
163
162
|
if (!runCheck('ESLint', ['npx', 'eslint', '.', '--max-warnings=0'], projectRoot)) failures++;
|
|
164
163
|
if (!runCheck('TypeScript', ['npx', 'tsc', '--noEmit'], projectRoot)) failures++;
|
|
165
164
|
} else {
|
|
166
|
-
|
|
165
|
+
trackSkip('Lint', 'skipped by flag');
|
|
167
166
|
}
|
|
168
167
|
|
|
169
168
|
// Priority 3 — Schema
|
|
170
|
-
if (!
|
|
171
|
-
|
|
172
|
-
|
|
169
|
+
if (!skipTiers.includes('schema')) {
|
|
170
|
+
console.log(sectionHeader('Schema Validation', 3));
|
|
171
|
+
trackSkip('Schema', 'run manually if you have DB migrations');
|
|
173
172
|
} else {
|
|
174
|
-
|
|
173
|
+
trackSkip('Schema', 'skipped by flag');
|
|
175
174
|
}
|
|
176
175
|
|
|
177
176
|
// Priority 4 — Tests
|
|
178
|
-
if (!
|
|
179
|
-
|
|
177
|
+
if (!skipTiers.includes('tests')) {
|
|
178
|
+
console.log(sectionHeader('Tests', 4));
|
|
180
179
|
if (!runCheck('Test suite', ['npm', 'test', '--', '--passWithNoTests'], projectRoot)) failures++;
|
|
181
180
|
} else {
|
|
182
|
-
|
|
181
|
+
trackSkip('Tests', 'skipped by flag');
|
|
183
182
|
}
|
|
184
183
|
|
|
185
184
|
// Priority 5 — UX
|
|
186
|
-
if (!
|
|
187
|
-
|
|
188
|
-
|
|
185
|
+
if (!skipTiers.includes('ux')) {
|
|
186
|
+
console.log(sectionHeader('UX / Accessibility', 5));
|
|
187
|
+
trackSkip('UX audit', 'run /preview start then check with Lighthouse');
|
|
189
188
|
} else {
|
|
190
|
-
|
|
189
|
+
trackSkip('UX', 'skipped by flag');
|
|
191
190
|
}
|
|
192
191
|
|
|
193
192
|
// Priority 6 — SEO
|
|
194
|
-
if (!
|
|
195
|
-
|
|
196
|
-
|
|
193
|
+
if (!skipTiers.includes('seo')) {
|
|
194
|
+
console.log(sectionHeader('SEO', 6));
|
|
195
|
+
trackSkip('SEO check', 'use /ui-ux-pro-max for SEO-sensitive pages');
|
|
197
196
|
} else {
|
|
198
|
-
|
|
197
|
+
trackSkip('SEO', 'skipped by flag');
|
|
199
198
|
}
|
|
200
199
|
|
|
201
200
|
// Priority 7 — Lighthouse / E2E
|
|
202
|
-
if (url && !
|
|
203
|
-
|
|
201
|
+
if (url && !skipTiers.includes('e2e')) {
|
|
202
|
+
console.log(sectionHeader('Lighthouse / E2E', 7));
|
|
204
203
|
if (!runCheck('Playwright E2E', ['npx', 'playwright', 'test'], projectRoot)) failures++;
|
|
205
204
|
} else if (!url) {
|
|
206
|
-
|
|
205
|
+
trackSkip('E2E / Lighthouse', 'pass --url to enable');
|
|
207
206
|
}
|
|
208
207
|
|
|
209
208
|
// ━━━ Summary ━━━
|
|
210
|
-
|
|
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();
|
|
211
221
|
if (failures === 0) {
|
|
212
|
-
|
|
222
|
+
console.log(`${GREEN}${BOLD} ✔ All checks passed — ready to proceed.${RESET}`);
|
|
213
223
|
} else {
|
|
214
|
-
|
|
224
|
+
console.log(`${RED}${BOLD} ✖ ${failures} tier(s) failed — fix critical issues before proceeding.${RESET}`);
|
|
215
225
|
}
|
|
226
|
+
console.log();
|
|
216
227
|
|
|
217
228
|
return failures;
|
|
218
229
|
}
|
|
@@ -248,11 +259,12 @@ function main() {
|
|
|
248
259
|
|
|
249
260
|
const projectRoot = path.resolve(args.path);
|
|
250
261
|
if (!fs.existsSync(projectRoot) || !fs.statSync(projectRoot).isDirectory()) {
|
|
251
|
-
|
|
262
|
+
fail(`Directory not found: ${projectRoot}`);
|
|
252
263
|
process.exit(1);
|
|
253
264
|
}
|
|
254
265
|
|
|
255
|
-
console.log(
|
|
266
|
+
console.log(banner('checklist.js', { Project: projectRoot }));
|
|
267
|
+
|
|
256
268
|
const failures = runAll(projectRoot, args.url, args.skip);
|
|
257
269
|
process.exit(failures > 0 ? 1 : 0);
|
|
258
270
|
}
|
package/.agent/scripts/colors.js
CHANGED
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* colors.js
|
|
3
|
-
*
|
|
2
|
+
* colors.js — Backward-compatible re-export of _colors.js
|
|
3
|
+
* ════════════════════════════════════════════════════════
|
|
4
|
+
* All color constants and helpers are defined in _colors.js.
|
|
5
|
+
* This file re-exports them for scripts that import from './colors.js'.
|
|
6
|
+
*
|
|
7
|
+
* New scripts should import from './_colors' directly.
|
|
4
8
|
*/
|
|
5
9
|
'use strict';
|
|
6
10
|
|
|
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
|
-
};
|
|
11
|
+
module.exports = require('./_colors');
|
|
@@ -1,141 +1,141 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// compress_skills.js - Aggressive token reduction for .agent/skills/**/*.md files
|
|
3
|
-
|
|
4
|
-
'use strict';
|
|
5
|
-
|
|
6
|
-
const fs = require('fs');
|
|
7
|
-
const path = require('path');
|
|
8
|
-
|
|
9
|
-
const SECTION_PATTERNS = [
|
|
10
|
-
/^## 🏛️ Tribunal Integration[\s\S]*?(?=\n## |\n# |$)/gm,
|
|
11
|
-
/^## Tribunal Integration[\s\S]*?(?=\n## |\n# |$)/gm,
|
|
12
|
-
/^### ✅ Pre-Flight Self-Audit[\s\S]*?(?=\n## |\n### |\n# |$)/gm,
|
|
13
|
-
/^## Pre-Flight Self-Audit[\s\S]*?(?=\n## |\n# |$)/gm,
|
|
14
|
-
/^## Cross-Workflow Navigation[\s\S]*?(?=\n## |\n# |$)/gm,
|
|
15
|
-
/^## Output Format\s*\n```[\s\S]*?```\s*\n/gm,
|
|
16
|
-
/^## VBC Protocol[\s\S]*?(?=\n## |\n# |$)/gm,
|
|
17
|
-
/^## LLM Traps[\s\S]*?(?=\n## |\n# |$)/gm,
|
|
18
|
-
];
|
|
19
|
-
|
|
20
|
-
const CHATTY_INTRO = /(^# .+\n)\n[A-Z][^#\n]{60,}\n[A-Z][^#\n]{40,}\n\n---/gm;
|
|
21
|
-
|
|
22
|
-
function stripChattyIntro(content) {
|
|
23
|
-
return content.replace(CHATTY_INTRO, '$1\n---');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const OBVIOUS_COMMENT = /^(\s*)(\/\/ (default for most properties|shorthand|number of repeats|default: \d+|spring tension|resistance|weight|approximate duration|deceleration rate)[^\n]*)\n/gm;
|
|
27
|
-
|
|
28
|
-
function stripObviousComments(content) {
|
|
29
|
-
return content.replace(OBVIOUS_COMMENT, '');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const PERF_TEXT_BLOCK = /^```\n(✅ Use \w[^\n]*\n → [^\n]*\n\n?){3,}```\n/gm;
|
|
33
|
-
|
|
34
|
-
function compressPerfBlocks(content) {
|
|
35
|
-
return content.replace(PERF_TEXT_BLOCK, (match) => {
|
|
36
|
-
const lines = match.replace(/`|\n$/g, '').split('\n');
|
|
37
|
-
const bullets = [];
|
|
38
|
-
for (const line of lines) {
|
|
39
|
-
const stripped = line.trim();
|
|
40
|
-
if (stripped.startsWith('✅') || stripped.startsWith('❌')) {
|
|
41
|
-
bullets.push(`- ${stripped}`);
|
|
42
|
-
} else if (stripped.startsWith('→')) {
|
|
43
|
-
bullets[bullets.length - 1] += ` (${stripped.substring(1).trim()})`;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return bullets.join('\n') + '\n';
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function collapseBlanks(content) {
|
|
51
|
-
return content.replace(/\n{3,}/g, '\n\n');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const FILLER_BEFORE_SECTION = /(^# .+\n\n)([A-Z][^\n]+\n){1,4}(\n---\n)/gm;
|
|
55
|
-
|
|
56
|
-
function removeFillerBetweenTitleAndHr(content) {
|
|
57
|
-
return content.replace(FILLER_BEFORE_SECTION, '$1$3');
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const REDUNDANT_NOTE = /^\/\/ (motion\.\w+|Any HTML|Note:|Variant names propagate|\/\/ )[^\n]*\n/gm;
|
|
61
|
-
|
|
62
|
-
function stripRedundantNotes(content) {
|
|
63
|
-
return content.replace(REDUNDANT_NOTE, '');
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function compressFile(filePath) {
|
|
67
|
-
const original = fs.readFileSync(filePath, 'utf8');
|
|
68
|
-
let content = original;
|
|
69
|
-
|
|
70
|
-
for (const pattern of SECTION_PATTERNS) {
|
|
71
|
-
content = content.replace(pattern, '');
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
content = stripChattyIntro(content);
|
|
75
|
-
content = removeFillerBetweenTitleAndHr(content);
|
|
76
|
-
content = stripObviousComments(content);
|
|
77
|
-
content = stripRedundantNotes(content);
|
|
78
|
-
content = compressPerfBlocks(content);
|
|
79
|
-
content = collapseBlanks(content);
|
|
80
|
-
|
|
81
|
-
const originalLen = Buffer.byteLength(original, 'utf8');
|
|
82
|
-
const newLen = Buffer.byteLength(content.trim() + '\n', 'utf8');
|
|
83
|
-
|
|
84
|
-
fs.writeFileSync(filePath, content.trim() + '\n', 'utf8');
|
|
85
|
-
return [originalLen, newLen, originalLen - newLen];
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function main() {
|
|
89
|
-
const base = '.agent/skills';
|
|
90
|
-
if (!fs.existsSync(base)) {
|
|
91
|
-
console.error(`ERROR: '${base}' not found. Run from tribunal-kit root.`);
|
|
92
|
-
process.exit(1);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
let totalOrig = 0;
|
|
96
|
-
let totalNew = 0;
|
|
97
|
-
const results = [];
|
|
98
|
-
|
|
99
|
-
function walkDir(dir) {
|
|
100
|
-
const items = fs.readdirSync(dir, { withFileTypes: true });
|
|
101
|
-
for (const item of items) {
|
|
102
|
-
const fpath = path.join(dir, item.name);
|
|
103
|
-
if (item.isDirectory()) {
|
|
104
|
-
walkDir(fpath);
|
|
105
|
-
} else if (item.name.endsWith('.md')) {
|
|
106
|
-
const [orig, newL, saved] = compressFile(fpath);
|
|
107
|
-
totalOrig += orig;
|
|
108
|
-
totalNew += newL;
|
|
109
|
-
if (saved > 0) {
|
|
110
|
-
results.push([saved, fpath]);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
walkDir(base);
|
|
117
|
-
results.sort((a, b) => b[0] - a[0]);
|
|
118
|
-
|
|
119
|
-
console.log(`\n${'='.repeat(55)}`);
|
|
120
|
-
console.log(` Skill Compression Complete`);
|
|
121
|
-
console.log(`${'='.repeat(55)}`);
|
|
122
|
-
console.log(` Original : ${totalOrig} bytes (${Math.floor(totalOrig / 1024)}KB)`);
|
|
123
|
-
console.log(` After : ${totalNew} bytes (${Math.floor(totalNew / 1024)}KB)`);
|
|
124
|
-
|
|
125
|
-
const savedTotal = totalOrig - totalNew;
|
|
126
|
-
const pct = totalOrig ? (savedTotal / totalOrig * 100) : 0;
|
|
127
|
-
console.log(` Saved : ${savedTotal} bytes (${Math.floor(savedTotal / 1024)}KB) — ${pct.toFixed(1)}%`);
|
|
128
|
-
console.log(`\n Top savings:`);
|
|
129
|
-
|
|
130
|
-
for (const [saved, filePath] of results.slice(0, 15)) {
|
|
131
|
-
const parts = filePath.split(path.sep);
|
|
132
|
-
const skill = parts[parts.length - 2];
|
|
133
|
-
const fname = parts[parts.length - 1];
|
|
134
|
-
console.log(` -${Math.floor(saved / 1024).toString().padStart(2, ' ')}KB ${skill}/${fname}`);
|
|
135
|
-
}
|
|
136
|
-
console.log();
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (require.main === module) {
|
|
140
|
-
main();
|
|
141
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// compress_skills.js - Aggressive token reduction for .agent/skills/**/*.md files
|
|
3
|
+
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
9
|
+
const SECTION_PATTERNS = [
|
|
10
|
+
/^## 🏛️ Tribunal Integration[\s\S]*?(?=\n## |\n# |$)/gm,
|
|
11
|
+
/^## Tribunal Integration[\s\S]*?(?=\n## |\n# |$)/gm,
|
|
12
|
+
/^### ✅ Pre-Flight Self-Audit[\s\S]*?(?=\n## |\n### |\n# |$)/gm,
|
|
13
|
+
/^## Pre-Flight Self-Audit[\s\S]*?(?=\n## |\n# |$)/gm,
|
|
14
|
+
/^## Cross-Workflow Navigation[\s\S]*?(?=\n## |\n# |$)/gm,
|
|
15
|
+
/^## Output Format\s*\n```[\s\S]*?```\s*\n/gm,
|
|
16
|
+
/^## VBC Protocol[\s\S]*?(?=\n## |\n# |$)/gm,
|
|
17
|
+
/^## LLM Traps[\s\S]*?(?=\n## |\n# |$)/gm,
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const CHATTY_INTRO = /(^# .+\n)\n[A-Z][^#\n]{60,}\n[A-Z][^#\n]{40,}\n\n---/gm;
|
|
21
|
+
|
|
22
|
+
function stripChattyIntro(content) {
|
|
23
|
+
return content.replace(CHATTY_INTRO, '$1\n---');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const OBVIOUS_COMMENT = /^(\s*)(\/\/ (default for most properties|shorthand|number of repeats|default: \d+|spring tension|resistance|weight|approximate duration|deceleration rate)[^\n]*)\n/gm;
|
|
27
|
+
|
|
28
|
+
function stripObviousComments(content) {
|
|
29
|
+
return content.replace(OBVIOUS_COMMENT, '');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const PERF_TEXT_BLOCK = /^```\n(✅ Use \w[^\n]*\n → [^\n]*\n\n?){3,}```\n/gm;
|
|
33
|
+
|
|
34
|
+
function compressPerfBlocks(content) {
|
|
35
|
+
return content.replace(PERF_TEXT_BLOCK, (match) => {
|
|
36
|
+
const lines = match.replace(/`|\n$/g, '').split('\n');
|
|
37
|
+
const bullets = [];
|
|
38
|
+
for (const line of lines) {
|
|
39
|
+
const stripped = line.trim();
|
|
40
|
+
if (stripped.startsWith('✅') || stripped.startsWith('❌')) {
|
|
41
|
+
bullets.push(`- ${stripped}`);
|
|
42
|
+
} else if (stripped.startsWith('→')) {
|
|
43
|
+
bullets[bullets.length - 1] += ` (${stripped.substring(1).trim()})`;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return bullets.join('\n') + '\n';
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function collapseBlanks(content) {
|
|
51
|
+
return content.replace(/\n{3,}/g, '\n\n');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const FILLER_BEFORE_SECTION = /(^# .+\n\n)([A-Z][^\n]+\n){1,4}(\n---\n)/gm;
|
|
55
|
+
|
|
56
|
+
function removeFillerBetweenTitleAndHr(content) {
|
|
57
|
+
return content.replace(FILLER_BEFORE_SECTION, '$1$3');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const REDUNDANT_NOTE = /^\/\/ (motion\.\w+|Any HTML|Note:|Variant names propagate|\/\/ )[^\n]*\n/gm;
|
|
61
|
+
|
|
62
|
+
function stripRedundantNotes(content) {
|
|
63
|
+
return content.replace(REDUNDANT_NOTE, '');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function compressFile(filePath) {
|
|
67
|
+
const original = fs.readFileSync(filePath, 'utf8');
|
|
68
|
+
let content = original;
|
|
69
|
+
|
|
70
|
+
for (const pattern of SECTION_PATTERNS) {
|
|
71
|
+
content = content.replace(pattern, '');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
content = stripChattyIntro(content);
|
|
75
|
+
content = removeFillerBetweenTitleAndHr(content);
|
|
76
|
+
content = stripObviousComments(content);
|
|
77
|
+
content = stripRedundantNotes(content);
|
|
78
|
+
content = compressPerfBlocks(content);
|
|
79
|
+
content = collapseBlanks(content);
|
|
80
|
+
|
|
81
|
+
const originalLen = Buffer.byteLength(original, 'utf8');
|
|
82
|
+
const newLen = Buffer.byteLength(content.trim() + '\n', 'utf8');
|
|
83
|
+
|
|
84
|
+
fs.writeFileSync(filePath, content.trim() + '\n', 'utf8');
|
|
85
|
+
return [originalLen, newLen, originalLen - newLen];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function main() {
|
|
89
|
+
const base = '.agent/skills';
|
|
90
|
+
if (!fs.existsSync(base)) {
|
|
91
|
+
console.error(`ERROR: '${base}' not found. Run from tribunal-kit root.`);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let totalOrig = 0;
|
|
96
|
+
let totalNew = 0;
|
|
97
|
+
const results = [];
|
|
98
|
+
|
|
99
|
+
function walkDir(dir) {
|
|
100
|
+
const items = fs.readdirSync(dir, { withFileTypes: true });
|
|
101
|
+
for (const item of items) {
|
|
102
|
+
const fpath = path.join(dir, item.name);
|
|
103
|
+
if (item.isDirectory()) {
|
|
104
|
+
walkDir(fpath);
|
|
105
|
+
} else if (item.name.endsWith('.md')) {
|
|
106
|
+
const [orig, newL, saved] = compressFile(fpath);
|
|
107
|
+
totalOrig += orig;
|
|
108
|
+
totalNew += newL;
|
|
109
|
+
if (saved > 0) {
|
|
110
|
+
results.push([saved, fpath]);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
walkDir(base);
|
|
117
|
+
results.sort((a, b) => b[0] - a[0]);
|
|
118
|
+
|
|
119
|
+
console.log(`\n${'='.repeat(55)}`);
|
|
120
|
+
console.log(` Skill Compression Complete`);
|
|
121
|
+
console.log(`${'='.repeat(55)}`);
|
|
122
|
+
console.log(` Original : ${totalOrig} bytes (${Math.floor(totalOrig / 1024)}KB)`);
|
|
123
|
+
console.log(` After : ${totalNew} bytes (${Math.floor(totalNew / 1024)}KB)`);
|
|
124
|
+
|
|
125
|
+
const savedTotal = totalOrig - totalNew;
|
|
126
|
+
const pct = totalOrig ? (savedTotal / totalOrig * 100) : 0;
|
|
127
|
+
console.log(` Saved : ${savedTotal} bytes (${Math.floor(savedTotal / 1024)}KB) — ${pct.toFixed(1)}%`);
|
|
128
|
+
console.log(`\n Top savings:`);
|
|
129
|
+
|
|
130
|
+
for (const [saved, filePath] of results.slice(0, 15)) {
|
|
131
|
+
const parts = filePath.split(path.sep);
|
|
132
|
+
const skill = parts[parts.length - 2];
|
|
133
|
+
const fname = parts[parts.length - 1];
|
|
134
|
+
console.log(` -${Math.floor(saved / 1024).toString().padStart(2, ' ')}KB ${skill}/${fname}`);
|
|
135
|
+
}
|
|
136
|
+
console.log();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (require.main === module) {
|
|
140
|
+
main();
|
|
141
|
+
}
|