tribunal-kit 5.8.0 → 5.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent/agents/project-planner.md +5 -0
- package/.agent/history/memory/.memory.idx +928 -1
- package/.agent/history/memory/MEMORY.md +62 -1
- package/.agent/rules/GEMINI.md +30 -5
- package/.agent/skills/fabel-protocol/SKILL.md +37 -1
- package/.agent/workflows/generate.md +1 -0
- package/.agent/workflows/tribunal-full.md +4 -3
- package/README.md +138 -12
- package/bin/mcp-server.js +38 -0
- package/bin/wrapper.js +5 -1
- package/dist/cli.js +13 -0
- package/dist/commands/align.js +201 -0
- package/package.json +21 -9
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const readline = require("readline");
|
|
6
|
+
const { log, err, ok, c, bold, warn } = require("../utils/logger");
|
|
7
|
+
|
|
8
|
+
function alignText(text) {
|
|
9
|
+
if (!text) return "";
|
|
10
|
+
|
|
11
|
+
let cleaned = text.trim();
|
|
12
|
+
let matches = true;
|
|
13
|
+
|
|
14
|
+
// 1. Strip Conversational Introduction Slop step-by-step
|
|
15
|
+
while (matches) {
|
|
16
|
+
matches = false;
|
|
17
|
+
const prefixes = [
|
|
18
|
+
/^(?:sure|certainly|okay|absolutely|great|of course|as requested|as you asked|happy to help|here is|here's|let's|i can help)(?:[^\n]*?)(?:[.!?;:]|\n)\s*/i,
|
|
19
|
+
/^(?:I'd be happy to help with that\.|I can certainly help you with that\.|Let me help you with that\.|Here's what you requested:)\s*/i,
|
|
20
|
+
/^(?:here is the implementation|here is the code|here are the details|here is your code|here's the implementation|here's the code|here's the solution|here are the details:)(?:[^\n]*?)(?:[.!?;:]|\n)\s*/i
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
for (const regex of prefixes) {
|
|
24
|
+
const temp = cleaned.replace(regex, "");
|
|
25
|
+
if (temp !== cleaned) {
|
|
26
|
+
cleaned = temp.trim();
|
|
27
|
+
matches = true;
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 2. Strip Conversational Conclusion Slop
|
|
34
|
+
const outroRegexes = [
|
|
35
|
+
/[\r\n\s]*(?:i hope this helps|let me know if you need|let me know if this works|please review the code|let me know if you have any questions|feel free to ask|hope that helps|happy coding)(?:.*)$/gi,
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
for (const regex of outroRegexes) {
|
|
39
|
+
cleaned = cleaned.replace(regex, "");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 3. Bullet-point collapse logic (1-2 item list -> prose)
|
|
43
|
+
const lines = cleaned.split(/\r?\n/);
|
|
44
|
+
const resultLines = [];
|
|
45
|
+
let i = 0;
|
|
46
|
+
|
|
47
|
+
while (i < lines.length) {
|
|
48
|
+
const line = lines[i];
|
|
49
|
+
const bulletMatch = line.match(/^(\s*)([-*]|\d+\.)\s+(.*)$/);
|
|
50
|
+
|
|
51
|
+
if (bulletMatch) {
|
|
52
|
+
const listItems = [];
|
|
53
|
+
const indent = bulletMatch[1];
|
|
54
|
+
let j = i;
|
|
55
|
+
|
|
56
|
+
while (j < lines.length) {
|
|
57
|
+
const nextLine = lines[j];
|
|
58
|
+
const nextMatch = nextLine.match(/^(\s*)([-*]|\d+\.)\s+(.*)$/);
|
|
59
|
+
if (nextMatch && nextMatch[1].length === indent.length) {
|
|
60
|
+
listItems.push({ index: j, content: nextMatch[3] });
|
|
61
|
+
j++;
|
|
62
|
+
} else if (nextLine.trim() === "") {
|
|
63
|
+
if (j + 1 < lines.length) {
|
|
64
|
+
const lookahead = lines[j + 1];
|
|
65
|
+
const lookaheadMatch = lookahead.match(/^(\s*)([-*]|\d+\.)\s+(.*)$/);
|
|
66
|
+
if (lookaheadMatch && lookaheadMatch[1].length === indent.length) {
|
|
67
|
+
j++;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
break;
|
|
72
|
+
} else {
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (listItems.length > 0 && listItems.length <= 2) {
|
|
78
|
+
const collapsedProse = listItems.map(item => {
|
|
79
|
+
let content = item.content.trim();
|
|
80
|
+
if (content && !/[.!?]$/.test(content)) {
|
|
81
|
+
content += ".";
|
|
82
|
+
}
|
|
83
|
+
if (content) {
|
|
84
|
+
content = content.charAt(0).toUpperCase() + content.slice(1);
|
|
85
|
+
}
|
|
86
|
+
return content;
|
|
87
|
+
}).join(" ");
|
|
88
|
+
resultLines.push(indent + collapsedProse);
|
|
89
|
+
i = j;
|
|
90
|
+
} else {
|
|
91
|
+
for (let k = i; k < j; k++) {
|
|
92
|
+
resultLines.push(lines[k]);
|
|
93
|
+
}
|
|
94
|
+
i = j;
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
resultLines.push(line);
|
|
98
|
+
i++;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
cleaned = resultLines.join("\n");
|
|
103
|
+
return cleaned.trim();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function validateCodeContent(text) {
|
|
107
|
+
const warnings = [];
|
|
108
|
+
|
|
109
|
+
// Next.js 15 unawaited dynamic properties check
|
|
110
|
+
const unawaitedNext15Regex = /(?<!await\s+)(cookies|headers|params)\s*\(\s*\)\s*\.\s*(get|has|set|delete|toString)/g;
|
|
111
|
+
if (unawaitedNext15Regex.test(text)) {
|
|
112
|
+
warnings.push("Next.js 15: Found unawaited call to cookies(), headers(), or params(). In Next.js 15+, these are async and must be awaited.");
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// React 19 useFormState check
|
|
116
|
+
if (text.includes("useFormState")) {
|
|
117
|
+
warnings.push("React 19: Found useFormState. In React 19, this is renamed to useActionState.");
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Drizzle .filter() check
|
|
121
|
+
const drizzleFilterRegex = /\.from\s*\([^)]*\)\s*\.\s*filter\s*\(/;
|
|
122
|
+
if (drizzleFilterRegex.test(text)) {
|
|
123
|
+
warnings.push("Drizzle ORM: Found .from().filter(). Drizzle does not use .filter(), use .where() instead.");
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// OpenAI gpt-5 or claude-4-opus checks
|
|
127
|
+
if (text.includes("gpt-5") || text.includes("claude-4-opus")) {
|
|
128
|
+
warnings.push("LLM Models: Found references to non-existent models (gpt-5, claude-4-opus).");
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return warnings;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function cmdAlign(flags, argv, quiet) {
|
|
135
|
+
let inputSource = null;
|
|
136
|
+
|
|
137
|
+
// Find if a file path is specified
|
|
138
|
+
const positionalArgs = argv.slice(3).filter(arg => !arg.startsWith("--"));
|
|
139
|
+
if (positionalArgs.length > 0) {
|
|
140
|
+
inputSource = positionalArgs[0];
|
|
141
|
+
} else if (flags.path) {
|
|
142
|
+
inputSource = flags.path;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
let textContent = "";
|
|
146
|
+
|
|
147
|
+
if (inputSource) {
|
|
148
|
+
// Read from file
|
|
149
|
+
const resolvedPath = path.resolve(inputSource);
|
|
150
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
151
|
+
err(`File not found: ${inputSource}`);
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
textContent = fs.readFileSync(resolvedPath, "utf8");
|
|
155
|
+
} else {
|
|
156
|
+
// Read from stdin
|
|
157
|
+
textContent = await new Promise((resolve) => {
|
|
158
|
+
let data = "";
|
|
159
|
+
const rl = readline.createInterface({
|
|
160
|
+
input: process.stdin,
|
|
161
|
+
output: process.stdout,
|
|
162
|
+
terminal: false
|
|
163
|
+
});
|
|
164
|
+
rl.on("line", (line) => {
|
|
165
|
+
data += line + "\n";
|
|
166
|
+
});
|
|
167
|
+
rl.on("close", () => {
|
|
168
|
+
resolve(data);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const aligned = alignText(textContent);
|
|
174
|
+
const warnings = validateCodeContent(aligned);
|
|
175
|
+
|
|
176
|
+
// Print warnings to stderr so they don't corrupt stdout piping
|
|
177
|
+
if (warnings.length > 0 && !quiet) {
|
|
178
|
+
process.stderr.write("\n" + bold(c("yellow", "⚠️ OCAE Alignment Validator Warnings:")) + "\n");
|
|
179
|
+
for (const warnMsg of warnings) {
|
|
180
|
+
process.stderr.write(` ${c("yellow", "●")} ${warnMsg}\n`);
|
|
181
|
+
}
|
|
182
|
+
process.stderr.write("\n");
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (flags.write && inputSource) {
|
|
186
|
+
// Write in-place to the file
|
|
187
|
+
fs.writeFileSync(path.resolve(inputSource), aligned, "utf8");
|
|
188
|
+
if (!quiet) {
|
|
189
|
+
ok(`Aligned output written in-place to: ${c("cyan", inputSource)}`);
|
|
190
|
+
}
|
|
191
|
+
} else {
|
|
192
|
+
// Print to stdout
|
|
193
|
+
process.stdout.write(aligned + "\n");
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
module.exports = {
|
|
198
|
+
cmdAlign,
|
|
199
|
+
alignText,
|
|
200
|
+
validateCodeContent
|
|
201
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tribunal-kit",
|
|
3
|
-
"version": "5.8.
|
|
4
|
-
"description": "Anti-Hallucination AI Agent Kit — 43 specialist agents,
|
|
3
|
+
"version": "5.8.1",
|
|
4
|
+
"description": "Anti-Hallucination AI Agent Kit for IDEs (Cursor, VSCode, Windsurf) — 43 specialist agents, 34 workflows, 20 parallel Tribunal code reviewers, Model Context Protocol (MCP) server, and long-running autonomous agent harness.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
7
7
|
"ai-agent",
|
|
@@ -33,7 +33,17 @@
|
|
|
33
33
|
"ai-coding",
|
|
34
34
|
"autonomous-agents",
|
|
35
35
|
"coding-assistant",
|
|
36
|
-
"automation"
|
|
36
|
+
"automation",
|
|
37
|
+
"model-context-protocol-server",
|
|
38
|
+
"mcp-server",
|
|
39
|
+
"claude-code",
|
|
40
|
+
"aider",
|
|
41
|
+
"cursor-rules-generator",
|
|
42
|
+
"agentic-ai",
|
|
43
|
+
"ai-code-reviewer",
|
|
44
|
+
"hallucination-mitigation",
|
|
45
|
+
"autonomous-workflows",
|
|
46
|
+
"code-correctness"
|
|
37
47
|
],
|
|
38
48
|
"homepage": "https://github.com/Harmitx7/tribunal-kit",
|
|
39
49
|
"repository": {
|
|
@@ -67,6 +77,8 @@
|
|
|
67
77
|
"changelog:preview": "node scripts/changelog.js --preview",
|
|
68
78
|
"sync": "node scripts/sync-version.js",
|
|
69
79
|
"validate-payload": "node scripts/validate-payload.js",
|
|
80
|
+
"benchmark": "node scripts/benchmark.js",
|
|
81
|
+
"benchmark:rust": "cargo build --release && node scripts/benchmark.js",
|
|
70
82
|
"build": "echo 'No build step required for this project'"
|
|
71
83
|
},
|
|
72
84
|
"devDependencies": {
|
|
@@ -75,12 +87,12 @@
|
|
|
75
87
|
"typescript": "^5.4.5"
|
|
76
88
|
},
|
|
77
89
|
"optionalDependencies": {
|
|
78
|
-
"@tribunal-kit/core-darwin-arm64": "^
|
|
79
|
-
"@tribunal-kit/core-darwin-x64": "^
|
|
80
|
-
"@tribunal-kit/core-linux-arm64": "^
|
|
81
|
-
"@tribunal-kit/core-linux-x64": "^
|
|
82
|
-
"@tribunal-kit/core-win32-arm64": "^
|
|
83
|
-
"@tribunal-kit/core-win32-x64": "^
|
|
90
|
+
"@tribunal-kit/core-darwin-arm64": "^5.8.1",
|
|
91
|
+
"@tribunal-kit/core-darwin-x64": "^5.8.1",
|
|
92
|
+
"@tribunal-kit/core-linux-arm64": "^5.8.1",
|
|
93
|
+
"@tribunal-kit/core-linux-x64": "^5.8.1",
|
|
94
|
+
"@tribunal-kit/core-win32-arm64": "^5.8.1",
|
|
95
|
+
"@tribunal-kit/core-win32-x64": "^5.8.1"
|
|
84
96
|
},
|
|
85
97
|
"jest": {
|
|
86
98
|
"testMatch": [
|