tribunal-kit 5.8.4 → 5.8.5
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/ARCHITECTURE.md +3 -3
- package/.agent/history/integrity_manifest.json +75 -7
- package/.agent/history/memory/.memory.idx +1065 -1
- package/.agent/history/memory/MEMORY.md +71 -1
- package/.agent/rules/GEMINI.md +1 -1
- package/.agent/scripts/_utils.js +28 -7
- package/.agent/scripts/context_broker.js +0 -19
- package/.agent/scripts/guardrail_engine.js +1 -1
- package/.agent/scripts/integrity_manifest.js +10 -4
- package/.agent/scripts/marathon_harness.js +10 -1
- package/.agent/scripts/skill_evolution.js +36 -21
- package/.agent/scripts/swarm_dispatcher.js +65 -6
- package/.agent/skills/api-patterns/scripts/__pycache__/api_validator.cpython-311.pyc +0 -0
- package/.agent/skills/better-colors/SKILL.md +12 -4
- package/.agent/skills/database-design/scripts/__pycache__/schema_validator.cpython-311.pyc +0 -0
- package/.agent/skills/fixing-accessibility/SKILL.md +6 -4
- package/.agent/skills/frontend-design/SKILL.md +80 -81
- package/.agent/skills/frontend-design/scripts/__pycache__/accessibility_checker.cpython-311.pyc +0 -0
- package/.agent/skills/frontend-design/scripts/__pycache__/ux_audit.cpython-311.pyc +0 -0
- package/.agent/skills/geo-fundamentals/scripts/__pycache__/geo_checker.cpython-311.pyc +0 -0
- package/.agent/skills/i18n-localization/scripts/__pycache__/i18n_checker.cpython-311.pyc +0 -0
- package/.agent/skills/impeccable/SKILL.md +2 -0
- package/.agent/skills/lint-and-validate/scripts/__pycache__/lint_runner.cpython-311.pyc +0 -0
- package/.agent/skills/lint-and-validate/scripts/__pycache__/type_coverage.cpython-311.pyc +0 -0
- package/.agent/skills/mobile-design/scripts/__pycache__/mobile_audit.cpython-311.pyc +0 -0
- package/.agent/skills/motion-engineering/SKILL.md +66 -164
- package/.agent/skills/nextjs-react-expert/scripts/__pycache__/convert_rules.cpython-311.pyc +0 -0
- package/.agent/skills/nextjs-react-expert/scripts/__pycache__/react_performance_checker.cpython-311.pyc +0 -0
- package/.agent/skills/performance-profiling/scripts/__pycache__/lighthouse_audit.cpython-311.pyc +0 -0
- package/.agent/skills/seo-fundamentals/scripts/__pycache__/seo_checker.cpython-311.pyc +0 -0
- package/.agent/skills/testing-patterns/scripts/__pycache__/test_runner.cpython-311.pyc +0 -0
- package/.agent/skills/vulnerability-scanner/scripts/__pycache__/security_scan.cpython-311.pyc +0 -0
- package/.agent/skills/webapp-testing/scripts/__pycache__/playwright_runner.cpython-311.pyc +0 -0
- package/.agent/workflows/tribunal-full.md +5 -5
- package/CONTRIBUTING.md +1 -1
- package/README.md +4 -4
- package/bin/mcp-server.js +45 -45
- package/bin/wrapper.js +50 -25
- package/dist/cli.js +30 -0
- package/dist/commands/init.js +25 -1
- package/dist/commands/native.js +228 -0
- package/dist/commands/validate.js +67 -0
- package/dist/mcp/server.js +4 -138
- package/package.json +11 -10
- package/scripts/benchmark.js +42 -0
- package/scripts/sync-version.js +129 -76
package/dist/mcp/server.js
CHANGED
|
@@ -1,142 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
+
|
|
3
4
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Uses in-process require() for commands instead of spawning child processes.
|
|
7
|
-
* Protocol: MCP 2024-11-05 over JSON-RPC 2.0 / stdio
|
|
5
|
+
* Compatibility entry point for the historical dist/mcp/server.js path.
|
|
6
|
+
* bin/mcp-server.js is the single canonical MCP implementation.
|
|
8
7
|
*/
|
|
9
|
-
|
|
10
|
-
const path = require('path');
|
|
11
|
-
|
|
12
|
-
const PKG = require('../../package.json');
|
|
13
|
-
|
|
14
|
-
// Timeout for spawned processes (30 seconds)
|
|
15
|
-
const SPAWN_TIMEOUT_MS = 30000;
|
|
16
|
-
|
|
17
|
-
const readline = require('readline');
|
|
18
|
-
const rl = readline.createInterface({
|
|
19
|
-
input: process.stdin,
|
|
20
|
-
output: process.stdout,
|
|
21
|
-
terminal: false
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
function handleRequest(req) {
|
|
25
|
-
if (req.method === 'initialize') {
|
|
26
|
-
return {
|
|
27
|
-
protocolVersion: "2024-11-05",
|
|
28
|
-
capabilities: { tools: {} },
|
|
29
|
-
serverInfo: {
|
|
30
|
-
name: "tribunal-kit-mcp",
|
|
31
|
-
version: PKG.version
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (req.method === 'tools/list') {
|
|
37
|
-
return {
|
|
38
|
-
tools: [
|
|
39
|
-
{
|
|
40
|
-
name: "run_tribunal_audit",
|
|
41
|
-
description: "Runs a full anti-hallucination audit across the workspace.",
|
|
42
|
-
inputSchema: { type: "object", properties: {}, additionalProperties: false }
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
name: "sync_ide_bridges",
|
|
46
|
-
description: "Synchronize IDE bridge files with the current GEMINI.md rules.",
|
|
47
|
-
inputSchema: { type: "object", properties: {}, additionalProperties: false }
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
name: "search_case_law",
|
|
51
|
-
description: "Search historical code rejections and legal precedent.",
|
|
52
|
-
inputSchema: {
|
|
53
|
-
type: "object",
|
|
54
|
-
properties: {
|
|
55
|
-
query: { type: "string", description: "Search query" }
|
|
56
|
-
},
|
|
57
|
-
required: ["query"],
|
|
58
|
-
additionalProperties: false
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
]
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (req.method === 'tools/call') {
|
|
66
|
-
const toolName = req.params && req.params.name;
|
|
67
|
-
if (!toolName) {
|
|
68
|
-
throw { code: -32602, message: "Missing required parameter: params.name" };
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (toolName === 'run_tribunal_audit') {
|
|
72
|
-
// Validate uses the Rust binary — still needs spawn
|
|
73
|
-
const CLI = path.resolve(__dirname, '../../bin/wrapper.js');
|
|
74
|
-
const result = spawnSync(process.execPath, [CLI, 'validate', '--quiet'], {
|
|
75
|
-
encoding: 'utf8',
|
|
76
|
-
timeout: SPAWN_TIMEOUT_MS,
|
|
77
|
-
});
|
|
78
|
-
return { content: [{ type: "text", text: result.stdout || result.stderr || "No output" }] };
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (toolName === 'sync_ide_bridges') {
|
|
82
|
-
// In-process — no spawn needed
|
|
83
|
-
const CLI = path.resolve(__dirname, '../../bin/wrapper.js');
|
|
84
|
-
const result = spawnSync(process.execPath, [CLI, 'sync', '--quiet'], {
|
|
85
|
-
encoding: 'utf8',
|
|
86
|
-
timeout: SPAWN_TIMEOUT_MS,
|
|
87
|
-
});
|
|
88
|
-
return { content: [{ type: "text", text: result.stdout || result.stderr || "Sync complete" }] };
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (toolName === 'search_case_law') {
|
|
92
|
-
const query = req.params && req.params.arguments && req.params.arguments.query;
|
|
93
|
-
if (!query || typeof query !== 'string') {
|
|
94
|
-
throw { code: -32602, message: "Missing or invalid required argument: query (string)" };
|
|
95
|
-
}
|
|
96
|
-
const script = path.resolve(__dirname, '../../.agent/scripts/case_law_manager.js');
|
|
97
|
-
const result = spawnSync(process.execPath, [script, 'search-cases', '--query', query], {
|
|
98
|
-
encoding: 'utf8',
|
|
99
|
-
timeout: SPAWN_TIMEOUT_MS,
|
|
100
|
-
});
|
|
101
|
-
return { content: [{ type: "text", text: result.stdout || result.stderr || "No results" }] };
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
throw { code: -32601, message: `Unknown tool: ${toolName}` };
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
throw { code: -32601, message: `Unknown method: ${req.method}` };
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
rl.on('line', (line) => {
|
|
111
|
-
if (!line.trim()) return;
|
|
112
|
-
|
|
113
|
-
let req;
|
|
114
|
-
try {
|
|
115
|
-
req = JSON.parse(line);
|
|
116
|
-
} catch (parseErr) {
|
|
117
|
-
const errorRes = {
|
|
118
|
-
jsonrpc: "2.0", id: null,
|
|
119
|
-
error: { code: -32700, message: "Parse error: " + parseErr.message }
|
|
120
|
-
};
|
|
121
|
-
console.log(JSON.stringify(errorRes));
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
const result = handleRequest(req);
|
|
127
|
-
const res = { jsonrpc: "2.0", id: req.id, result };
|
|
128
|
-
console.log(JSON.stringify(res));
|
|
129
|
-
|
|
130
|
-
if (req.method === 'initialize') {
|
|
131
|
-
console.log(JSON.stringify({ jsonrpc: "2.0", method: "notifications/initialized", params: {} }));
|
|
132
|
-
}
|
|
133
|
-
} catch (e) {
|
|
134
|
-
const code = (e && typeof e.code === 'number') ? e.code : -32603;
|
|
135
|
-
const message = (e && e.message) ? e.message : "Internal server error";
|
|
136
|
-
const errorRes = {
|
|
137
|
-
jsonrpc: "2.0", id: req.id || null,
|
|
138
|
-
error: { code, message }
|
|
139
|
-
};
|
|
140
|
-
console.log(JSON.stringify(errorRes));
|
|
141
|
-
}
|
|
142
|
-
});
|
|
8
|
+
module.exports = require("../../bin/mcp-server.js");
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tribunal-kit",
|
|
3
|
-
"version": "5.8.
|
|
4
|
-
"description": "The operating system for AI software engineering — governance, memory, review pipelines, and reusable skills for every coding agent. 44 specialist agents, 34 workflows,
|
|
3
|
+
"version": "5.8.5",
|
|
4
|
+
"description": "The operating system for AI software engineering — governance, memory, review pipelines, and reusable skills for every coding agent. 44 specialist agents, 34 workflows, 19 parallel Tribunal code reviewers, MCP server, Rust core engine, and long-running autonomous agent harness for Cursor, VSCode, Windsurf, Claude Code, and Aider.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
7
7
|
"ai-agent",
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
"benchmark:rust": "cargo build --release && node scripts/benchmark.js",
|
|
94
94
|
"build:rust": "cargo build --release",
|
|
95
95
|
"test:rust": "cargo test --manifest-path crates/core/Cargo.toml",
|
|
96
|
-
"build": "
|
|
96
|
+
"build": "npm run build:rust"
|
|
97
97
|
},
|
|
98
98
|
"devDependencies": {
|
|
99
99
|
"eslint": "^9.1.1",
|
|
@@ -101,12 +101,12 @@
|
|
|
101
101
|
"typescript": "^5.4.5"
|
|
102
102
|
},
|
|
103
103
|
"optionalDependencies": {
|
|
104
|
-
"@tribunal-kit/core-darwin-arm64": "^5.8.
|
|
105
|
-
"@tribunal-kit/core-darwin-x64": "^5.8.
|
|
106
|
-
"@tribunal-kit/core-linux-arm64": "^5.8.
|
|
107
|
-
"@tribunal-kit/core-linux-x64": "^5.8.
|
|
108
|
-
"@tribunal-kit/core-win32-arm64": "^5.8.
|
|
109
|
-
"@tribunal-kit/core-win32-x64": "^5.8.
|
|
104
|
+
"@tribunal-kit/core-darwin-arm64": "^5.8.5",
|
|
105
|
+
"@tribunal-kit/core-darwin-x64": "^5.8.5",
|
|
106
|
+
"@tribunal-kit/core-linux-arm64": "^5.8.5",
|
|
107
|
+
"@tribunal-kit/core-linux-x64": "^5.8.5",
|
|
108
|
+
"@tribunal-kit/core-win32-arm64": "^5.8.5",
|
|
109
|
+
"@tribunal-kit/core-win32-x64": "^5.8.5"
|
|
110
110
|
},
|
|
111
111
|
"jest": {
|
|
112
112
|
"testMatch": [
|
|
@@ -115,7 +115,8 @@
|
|
|
115
115
|
"testEnvironment": "node",
|
|
116
116
|
"coverageDirectory": "coverage",
|
|
117
117
|
"collectCoverageFrom": [
|
|
118
|
-
"bin/**/*.js"
|
|
118
|
+
"bin/**/*.js",
|
|
119
|
+
".agent/scripts/**/*.js"
|
|
119
120
|
]
|
|
120
121
|
}
|
|
121
122
|
}
|
package/scripts/benchmark.js
CHANGED
|
@@ -142,6 +142,48 @@ async function main() {
|
|
|
142
142
|
);
|
|
143
143
|
results.push(initRealResult);
|
|
144
144
|
|
|
145
|
+
// 5. DAG scheduling benchmark
|
|
146
|
+
console.log(c("cyan", " ▸ Benchmarking: DAG scheduling calculation"));
|
|
147
|
+
const dagResult = await benchmark(
|
|
148
|
+
"DAG wave scheduling",
|
|
149
|
+
() => {
|
|
150
|
+
const workers = [
|
|
151
|
+
{ task_id: "w1", dependencies: [] },
|
|
152
|
+
{ task_id: "w2", dependencies: ["w1"] },
|
|
153
|
+
{ task_id: "w3", dependencies: ["w1"] },
|
|
154
|
+
{ task_id: "w4", dependencies: ["w2", "w3"] },
|
|
155
|
+
];
|
|
156
|
+
const inDegree = {};
|
|
157
|
+
const adjList = {};
|
|
158
|
+
workers.forEach((w) => {
|
|
159
|
+
inDegree[w.task_id] = 0;
|
|
160
|
+
adjList[w.task_id] = [];
|
|
161
|
+
});
|
|
162
|
+
workers.forEach((w) => {
|
|
163
|
+
w.dependencies.forEach((dep) => {
|
|
164
|
+
adjList[dep].push(w.task_id);
|
|
165
|
+
inDegree[w.task_id] += 1;
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
let currentWave = Object.keys(inDegree).filter((id) => inDegree[id] === 0);
|
|
169
|
+
const waves = [];
|
|
170
|
+
while (currentWave.length > 0) {
|
|
171
|
+
waves.push(currentWave);
|
|
172
|
+
const next = [];
|
|
173
|
+
currentWave.forEach((id) => {
|
|
174
|
+
adjList[id].forEach((nbr) => {
|
|
175
|
+
inDegree[nbr] -= 1;
|
|
176
|
+
if (inDegree[nbr] === 0) next.push(nbr);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
currentWave = next;
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
100,
|
|
183
|
+
);
|
|
184
|
+
results.push(dagResult);
|
|
185
|
+
|
|
186
|
+
|
|
145
187
|
// Print results table
|
|
146
188
|
console.log();
|
|
147
189
|
console.log(bold(` Results`));
|
package/scripts/sync-version.js
CHANGED
|
@@ -1,94 +1,147 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* sync-version.js —
|
|
3
|
+
* sync-version.js — Release metadata consistency check for Tribunal Kit.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Run manually or as a preversion npm script:
|
|
9
|
-
* node scripts/sync-version.js
|
|
5
|
+
* Verifies the package version, native package metadata, lockfile metadata,
|
|
6
|
+
* and public asset-count claims before a release. It intentionally performs
|
|
7
|
+
* no implicit writes: a failed check makes stale release metadata visible.
|
|
10
8
|
*/
|
|
11
9
|
|
|
10
|
+
"use strict";
|
|
11
|
+
|
|
12
12
|
const fs = require("fs");
|
|
13
13
|
const path = require("path");
|
|
14
14
|
|
|
15
15
|
const ROOT = path.resolve(__dirname, "..");
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
const PKG_PATH = path.join(ROOT, "package.json");
|
|
17
|
+
const PKG = JSON.parse(fs.readFileSync(PKG_PATH, "utf8"));
|
|
18
|
+
const VERSION = PKG.version;
|
|
19
|
+
|
|
20
|
+
function readText(relativePath) {
|
|
21
|
+
return fs.readFileSync(path.join(ROOT, relativePath), "utf8");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function readJson(relativePath) {
|
|
25
|
+
return JSON.parse(readText(relativePath));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function countDirectory(relativePath, predicate) {
|
|
29
|
+
const directory = path.join(ROOT, relativePath);
|
|
30
|
+
if (!fs.existsSync(directory)) return 0;
|
|
31
|
+
return fs.readdirSync(directory, { withFileTypes: true }).filter(predicate).length;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function countReviewers() {
|
|
35
|
+
const agentsDir = path.join(ROOT, ".agent", "agents");
|
|
36
|
+
return countDirectory(".agent/agents", (entry) => {
|
|
37
|
+
if (!entry.isFile() || !entry.name.endsWith(".md")) return false;
|
|
38
|
+
const content = fs.readFileSync(path.join(agentsDir, entry.name), "utf8");
|
|
39
|
+
return /reviewer|auditor|tester|throughput-optimizer/i.test(entry.name) || /^role:\s*reviewer\s*$/im.test(content);
|
|
40
|
+
});
|
|
25
41
|
}
|
|
26
42
|
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
expected
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
43
|
+
|
|
44
|
+
const COUNTS = {
|
|
45
|
+
agents: countDirectory(".agent/agents", (entry) => entry.isFile() && entry.name.endsWith(".md")),
|
|
46
|
+
reviewers: countReviewers(),
|
|
47
|
+
skills: countDirectory(".agent/skills", (entry) => entry.isDirectory() && fs.existsSync(path.join(ROOT, ".agent", "skills", entry.name, "SKILL.md"))),
|
|
48
|
+
workflows: countDirectory(".agent/workflows", (entry) => entry.isFile() && entry.name.endsWith(".md")),
|
|
49
|
+
scripts: countDirectory(".agent/scripts", (entry) => entry.isFile() && /\.(?:js|py)$/.test(entry.name)),
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const failures = [];
|
|
53
|
+
|
|
54
|
+
function fail(message) {
|
|
55
|
+
failures.push(message);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function checkVersionMetadata() {
|
|
59
|
+
const expectedOptionalVersion = `^${VERSION}`;
|
|
60
|
+
for (const [name, declaredVersion] of Object.entries(PKG.optionalDependencies || {})) {
|
|
61
|
+
if (declaredVersion !== expectedOptionalVersion) {
|
|
62
|
+
fail(`package.json optional dependency ${name} is ${declaredVersion}, expected ${expectedOptionalVersion}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const lock = readJson("package-lock.json");
|
|
67
|
+
if (lock.version !== VERSION || lock.packages?.[""]?.version !== VERSION) {
|
|
68
|
+
fail(`package-lock.json root version does not match package.json (${VERSION})`);
|
|
69
|
+
}
|
|
70
|
+
for (const [name, declaredVersion] of Object.entries(lock.packages?.[""]?.optionalDependencies || {})) {
|
|
71
|
+
if (declaredVersion !== expectedOptionalVersion) {
|
|
72
|
+
fail(`package-lock.json optional dependency ${name} is ${declaredVersion}, expected ${expectedOptionalVersion}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const cargoToml = readText("crates/core/Cargo.toml");
|
|
77
|
+
const cargoTomlVersion = cargoToml.match(/^version\s*=\s*"([^"]+)"/m)?.[1];
|
|
78
|
+
if (cargoTomlVersion !== VERSION) {
|
|
79
|
+
fail(`crates/core/Cargo.toml version is ${cargoTomlVersion || "missing"}, expected ${VERSION}`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const cargoLock = readText("Cargo.lock");
|
|
83
|
+
const cargoLockVersion = cargoLock.match(/name\s*=\s*"tribunal-core"\s*\nversion\s*=\s*"([^"]+)"/)?.[1];
|
|
84
|
+
if (cargoLockVersion !== VERSION) {
|
|
85
|
+
fail(`Cargo.lock tribunal-core version is ${cargoLockVersion || "missing"}, expected ${VERSION}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const readmeRelease = readText("README.md").match(/Release-v([0-9]+\.[0-9]+\.[0-9]+)/)?.[1];
|
|
89
|
+
if (readmeRelease !== VERSION) {
|
|
90
|
+
fail(`README release badge is ${readmeRelease || "missing"}, expected ${VERSION}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const DOCUMENTS = [
|
|
95
|
+
"README.md",
|
|
96
|
+
".agent/ARCHITECTURE.md",
|
|
97
|
+
".agent/rules/GEMINI.md",
|
|
98
|
+
"CONTRIBUTING.md",
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
const CLAIM_PATTERNS = [
|
|
102
|
+
{ entity: "agents", regex: /(\d+)\s*(?:specialist\s+)?agents?\b/gi },
|
|
103
|
+
{
|
|
104
|
+
entity: "reviewers",
|
|
105
|
+
regex: /(\d+)\s*(?:-\s*)?(?:(?:parallel|domain(?:-specific)?|tribunal|code)\s+)*reviewers?\b/gi,
|
|
106
|
+
},
|
|
107
|
+
{ entity: "skills", regex: /(\d+)\s*(?:valid\s+|modular\s+)?skills?(?:\s+(?:packages?|modules?))?\b/gi },
|
|
108
|
+
{ entity: "workflows", regex: /(\d+)\s*(?:slash\s+)?workflows?\b/gi },
|
|
109
|
+
{ entity: "scripts", regex: /(\d+)\s*(?:JS\s+)?(?:automation\s+)?scripts?\b/gi },
|
|
110
|
+
];
|
|
111
|
+
|
|
112
|
+
function checkDocumentCounts() {
|
|
113
|
+
for (const relativePath of DOCUMENTS) {
|
|
114
|
+
const content = readText(relativePath);
|
|
115
|
+
for (const { entity, regex } of CLAIM_PATTERNS) {
|
|
116
|
+
regex.lastIndex = 0;
|
|
117
|
+
let match;
|
|
118
|
+
while ((match = regex.exec(content)) !== null) {
|
|
119
|
+
const claimed = Number.parseInt(match[1], 10);
|
|
120
|
+
if (claimed < 5 || claimed > 500) continue;
|
|
121
|
+
if (claimed !== COUNTS[entity]) {
|
|
122
|
+
const line = content.slice(0, match.index).split(/\r?\n/).length;
|
|
123
|
+
fail(`${relativePath}:${line} says ${claimed} ${entity}, actual is ${COUNTS[entity]}`);
|
|
124
|
+
}
|
|
78
125
|
}
|
|
79
126
|
}
|
|
80
127
|
}
|
|
81
128
|
}
|
|
82
129
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
);
|
|
130
|
+
console.log(`\n Tribunal Kit v${VERSION} — Release Metadata Check`);
|
|
131
|
+
console.log(" ────────────────────────────────────────────────");
|
|
132
|
+
console.log(` Agents: ${COUNTS.agents} (${COUNTS.reviewers} reviewers)`);
|
|
133
|
+
console.log(` Skills: ${COUNTS.skills}`);
|
|
134
|
+
console.log(` Workflows: ${COUNTS.workflows}`);
|
|
135
|
+
console.log(` Scripts: ${COUNTS.scripts}`);
|
|
136
|
+
|
|
137
|
+
checkVersionMetadata();
|
|
138
|
+
checkDocumentCounts();
|
|
139
|
+
|
|
140
|
+
if (failures.length > 0) {
|
|
141
|
+
console.log();
|
|
142
|
+
for (const message of failures) console.log(` ✗ ${message}`);
|
|
143
|
+
console.log(`\n Found ${failures.length} release metadata inconsistency${failures.length === 1 ? "" : "ies"}.`);
|
|
144
|
+
process.exitCode = 1;
|
|
87
145
|
} else {
|
|
88
|
-
console.log(
|
|
89
|
-
`\n ❌ Found ${staleFound} stale reference(s). Update manually or run the sync tool.`,
|
|
90
|
-
);
|
|
91
|
-
process.exit(1);
|
|
146
|
+
console.log(`\n ✓ Version metadata and public count claims are in sync across ${DOCUMENTS.length} documents.\n`);
|
|
92
147
|
}
|
|
93
|
-
|
|
94
|
-
console.log();
|