tribunal-kit 5.8.0 → 5.8.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.
@@ -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
+ };
@@ -64,7 +64,32 @@ async function cmdInit(flags, quiet = false) {
64
64
  const newManifest = await (0, hasher_1.generateManifest)(agentSrc);
65
65
  diff = (0, hasher_1.diffManifests)(oldManifest, newManifest);
66
66
  incremental = true;
67
- (0, logger_1.log)(` ${(0, logger_1.c)('cyan', '✦')} Performing incremental update (${diff.added.length} added, ${diff.changed.length} changed, ${diff.removed.length} removed)`);
67
+
68
+ const addCount = diff.added.length;
69
+ const changeCount = diff.changed.length;
70
+ const removeCount = diff.removed.length;
71
+
72
+ (0, logger_1.log)(` ${(0, logger_1.c)('cyan', '↻')} ${(0, logger_1.bold)('Performing incremental update...')}`);
73
+
74
+ const addedPart = `${(0, logger_1.c)('green', `[+ ${addCount}]`)} added`;
75
+ const changedPart = `${(0, logger_1.c)('yellow', `[~ ${changeCount}]`)} changed`;
76
+ const removedPart = `${(0, logger_1.c)('red', `[- ${removeCount}]`)} removed`;
77
+ (0, logger_1.log)(` ${addedPart} ${changedPart} ${removedPart}`);
78
+
79
+ const totalChanges = addCount + changeCount + removeCount;
80
+ if (totalChanges > 0) {
81
+ const maxBarWidth = 30;
82
+ const addPct = Math.round((addCount / totalChanges) * maxBarWidth);
83
+ const changePct = Math.round((changeCount / totalChanges) * maxBarWidth);
84
+ const removePct = Math.max(0, maxBarWidth - addPct - changePct);
85
+
86
+ const bar =
87
+ (0, logger_1.c)('green', '█'.repeat(addPct)) +
88
+ (0, logger_1.c)('yellow', '█'.repeat(changePct)) +
89
+ (0, logger_1.c)('red', '█'.repeat(removePct));
90
+
91
+ (0, logger_1.log)(` Syncing: [${bar}] ${totalChanges} files`);
92
+ }
68
93
 
69
94
  // Backup ONLY changed or removed files
70
95
  const toBackup = [...diff.changed, ...diff.removed];
@@ -81,7 +106,7 @@ async function cmdInit(flags, quiet = false) {
81
106
  backedUpCount++;
82
107
  }
83
108
  }
84
- (0, logger_1.log)(` ${(0, logger_1.c)('gray', `✦ Backed up ${backedUpCount} modified/removed files to .backups/`)}`);
109
+ (0, logger_1.log)(` ${(0, logger_1.c)('gray', '✦')} Backed up ${backedUpCount} modified/removed files ${(0, logger_1.c)('gray', '→')} ${(0, logger_1.c)('gray', '.agent/.backups/')}`);
85
110
  }
86
111
 
87
112
  // Remove removed files
@@ -103,7 +128,7 @@ async function cmdInit(flags, quiet = false) {
103
128
  await fs_1.default.promises.rm(subPath, { recursive: true, force: true });
104
129
  }
105
130
  }
106
- (0, logger_1.log)(` ${(0, logger_1.c)('gray', '✦ Backed up existing configurations to .agent/.backups/')}`);
131
+ (0, logger_1.log)(` ${(0, logger_1.c)('gray', '✦')} Backed up existing configurations ${(0, logger_1.c)('gray', '→')} ${(0, logger_1.c)('gray', '.agent/.backups/')}`);
107
132
  }
108
133
  }
109
134
  // ────────────────────────────────────────────────────────
@@ -193,45 +218,58 @@ async function cmdInit(flags, quiet = false) {
193
218
  else {
194
219
  // ── Success card — W=62, rows padded by plain-text length ──
195
220
  const W = 62;
221
+ const borderCol = 'red';
196
222
  const agentsCount = fs_1.default.readdirSync(path_1.default.join(agentDest, 'agents')).length;
197
223
  const workflowsCount = fs_1.default.readdirSync(path_1.default.join(agentDest, 'workflows')).length;
198
224
  const skillsCount = fs_1.default.readdirSync(path_1.default.join(agentDest, 'skills')).length;
199
225
  const scriptsCount = fs_1.default.readdirSync(path_1.default.join(agentDest, 'scripts')).length;
200
- // Stat rows: compute trailing spaces from plain text so right ║ aligns
201
- const statRow = (icon, label, val, col) => {
202
- const plain = ` ${icon} ${label.padEnd(10)}${String(val).padStart(3)} installed`;
203
- const trail = ' '.repeat(Math.max(0, W - plain.length));
204
- return ` ${(0, logger_1.c)('cyan', '║')} ${icon} ${(0, logger_1.c)('white', label.padEnd(10))}${(0, logger_1.c)(col, String(val).padStart(3))} ${(0, logger_1.c)('gray', 'installed')}${trail}${(0, logger_1.c)('cyan', '║')}`;
226
+
227
+ const drawRow = (plainText, styledText) => {
228
+ const trail = ' '.repeat(Math.max(0, W - plainText.length));
229
+ return ` ${(0, logger_1.c)(borderCol, '')}${styledText}${trail}${(0, logger_1.c)(borderCol, '│')}`;
205
230
  };
206
- // Plain-text rows (header / blank)
207
- const plainRow = (text, wrapFn) => {
208
- const trail = ' '.repeat(Math.max(0, W - text.length));
209
- return ` ${(0, logger_1.c)('cyan', '║')}${wrapFn(text)}${trail}${(0, logger_1.c)('cyan', '║')}`;
231
+
232
+ const compRow = (icon, label, count, color) => {
233
+ const leftPlain = ` ${icon} ${label.padEnd(10)} `;
234
+ const rightPlain = ` [ ${String(count).padStart(3)} ]`;
235
+ const numDots = W - leftPlain.length - rightPlain.length - 4; // 4 spaces margin
236
+ const dots = '.'.repeat(Math.max(0, numDots));
237
+
238
+ const plain = `${leftPlain}${dots}${rightPlain}`;
239
+ const styled = ` ${icon} ${(0, logger_1.c)('white', label.padEnd(10))} ${(0, logger_1.c)('gray', dots)} ${(0, logger_1.c)('gray', '[')} ${(0, logger_1.c)(color, String(count).padStart(3))} ${(0, logger_1.c)('gray', ']')}`;
240
+ return drawRow(plain, styled);
210
241
  };
211
- // Next-step rows: fixed cmd column + description
242
+
212
243
  const stepRow = (cmd, desc) => {
213
- const plain = ` ${cmd.padEnd(16)}${desc}`;
214
- const trail = ' '.repeat(Math.max(0, W - plain.length));
215
- return ` ${(0, logger_1.c)('cyan', '║')} ${(0, logger_1.c)('white', cmd.padEnd(16))}${(0, logger_1.c)('gray', desc)}${trail}${(0, logger_1.c)('cyan', '║')}`;
244
+ const leftPlain = ` ${cmd.padEnd(16)}`;
245
+ const rightPlain = `▸ ${desc}`;
246
+ const plain = `${leftPlain}${rightPlain}`;
247
+ const styled = ` ${(0, logger_1.c)('white', cmd.padEnd(16))}${(0, logger_1.c)('gray', '▸')} ${(0, logger_1.c)('gray', desc)}`;
248
+ return drawRow(plain, styled);
216
249
  };
250
+
217
251
  console.log(` ${(0, logger_1.c)('green', '✔')} ${(0, logger_1.bold)((0, logger_1.c)('green', 'Installation complete'))} ${(0, logger_1.c)('gray', '—')} ${(0, logger_1.c)('white', String(copied))} files`);
218
252
  console.log(` ${(0, logger_1.c)('gray', ' ╰─')} ${(0, logger_1.c)('gray', agentDest)}`);
219
253
  console.log();
220
- console.log(` ${(0, logger_1.c)('cyan', '' + ''.repeat(W) + '')}`);
221
- console.log(plainRow(` What's inside:`, s => (0, logger_1.bold)((0, logger_1.c)('white', s))));
222
- console.log(` ${(0, logger_1.c)('cyan', '' + ''.repeat(W) + '')}`);
223
- console.log(statRow('🤖', 'Agents', agentsCount, 'magenta'));
224
- console.log(statRow('', 'Workflows', workflowsCount, 'yellow'));
225
- console.log(statRow('🧠', 'Skills', skillsCount, 'blue'));
226
- console.log(statRow('🔧', 'Scripts', scriptsCount, 'green'));
227
- console.log(` ${(0, logger_1.c)('cyan', '' + ''.repeat(W) + '╣')}`);
228
- console.log(plainRow('', () => ''));
229
- console.log(plainRow(` Next steps:`, s => (0, logger_1.c)('gray', s)));
230
- console.log(stepRow('/generate', 'Generate code with anti-hallucination'));
254
+ console.log(` ${(0, logger_1.c)(borderCol, '' + ''.repeat(W) + '')}`);
255
+ console.log(drawRow(` TRIBUNAL ENVIRONMENT SYNCHRONIZED`, ` ${(0, logger_1.bold)((0, logger_1.c)('white', 'TRIBUNAL ENVIRONMENT SYNCHRONIZED'))}`));
256
+ console.log(` ${(0, logger_1.c)(borderCol, '' + ''.repeat(W) + '')}`);
257
+ console.log(drawRow(` Guarding: Active & Enforcing`, ` ${(0, logger_1.c)('gray', 'Guarding:')} ${(0, logger_1.c)('green', 'Active & Enforcing')}`));
258
+ console.log(drawRow(` Manifest: Verified`, ` ${(0, logger_1.c)('gray', 'Manifest:')} ${(0, logger_1.c)('cyan', 'Verified')}`));
259
+ console.log(drawRow('', ''));
260
+ console.log(drawRow(' Installed Components:', (0, logger_1.bold)((0, logger_1.c)('white', ' Installed Components:'))));
261
+ console.log(compRow('🤖', 'Agents', agentsCount, 'magenta'));
262
+ console.log(compRow('', 'Workflows', workflowsCount, 'yellow'));
263
+ console.log(compRow('🧠', 'Skills', skillsCount, 'blue'));
264
+ console.log(compRow('🔧', 'Scripts', scriptsCount, 'green'));
265
+ console.log(` ${(0, logger_1.c)(borderCol, '├' + '─'.repeat(W) + '┤')}`);
266
+ console.log(drawRow('', ''));
267
+ console.log(drawRow(' Next Steps:', (0, logger_1.c)('gray', ' Next Steps:')));
268
+ console.log(stepRow('/generate', 'Generate code with reviews'));
231
269
  console.log(stepRow('/review', 'Audit existing code for issues'));
232
- console.log(stepRow('/tribunal-full', 'Run all 16 reviewers in parallel'));
233
- console.log(plainRow('', () => ''));
234
- console.log(` ${(0, logger_1.c)('cyan', '' + ''.repeat(W) + '')}`);
270
+ console.log(stepRow('/tribunal-full', 'Run all 20 reviewers in parallel'));
271
+ console.log(drawRow('', ''));
272
+ console.log(` ${(0, logger_1.c)(borderCol, '' + ''.repeat(W) + '')}`);
235
273
  console.log();
236
274
  (0, logger_1.log)(` ${(0, logger_1.c)('gray', '✦ Generating IDE bridge files...')}`);
237
275
  await generateIDEBridges(targetDir, agentDest, dryRun);
@@ -0,0 +1,116 @@
1
+ /**
2
+ * tribunal-kit ESM entry point.
3
+ *
4
+ * This thin wrapper re-exports the CJS modules as ESM using createRequire.
5
+ * The actual implementation remains in CommonJS (dist/cli.js) to avoid
6
+ * a full migration while providing ESM compatibility for modern bundlers.
7
+ */
8
+
9
+ import { createRequire } from 'node:module';
10
+ const require = createRequire(import.meta.url);
11
+
12
+ const cli = require('../cli.js');
13
+ const logger = require('../utils/logger.js');
14
+ const helpers = require('../utils/helpers.js');
15
+
16
+ // ── CLI Commands ─────────────────────────────────────────
17
+ export const main = cli.main;
18
+
19
+ // ── Logger Utilities ─────────────────────────────────────
20
+ export const C = logger.C;
21
+ export const colorize = logger.colorize;
22
+ export const c = logger.c;
23
+ export const bold = logger.bold;
24
+ export const setLogLevels = logger.setLogLevels;
25
+ export const log = logger.log;
26
+ export const ok = logger.ok;
27
+ export const warn = logger.warn;
28
+ export const err = logger.err;
29
+ export const dim = logger.dim;
30
+ export const dbg = logger.dbg;
31
+
32
+ // ── Helper Utilities ─────────────────────────────────────
33
+ export const runShellAsync = helpers.runShellAsync;
34
+ export const getKitAgent = helpers.getKitAgent;
35
+ export const banner = helpers.banner;
36
+
37
+ // ── Lazy command loaders (imported on demand) ────────────
38
+ export async function cmdInit(flags, quiet) {
39
+ const mod = require('../commands/init.js');
40
+ return mod.cmdInit(flags, quiet);
41
+ }
42
+
43
+ export async function cmdUpdate(flags) {
44
+ const mod = require('../commands/update.js');
45
+ return mod.cmdUpdate(flags);
46
+ }
47
+
48
+ export function cmdStatus(flags, quiet) {
49
+ const mod = require('../commands/status.js');
50
+ return mod.cmdStatus(flags, quiet);
51
+ }
52
+
53
+ export async function cmdLearn(flags, quiet) {
54
+ const mod = require('../commands/learn.js');
55
+ return mod.cmdLearn(flags, quiet);
56
+ }
57
+
58
+ export async function cmdCase(flags, argv, quiet) {
59
+ const mod = require('../commands/case.js');
60
+ return mod.cmdCase(flags, argv, quiet);
61
+ }
62
+
63
+ export function cmdHook(flags) {
64
+ const mod = require('../commands/hook.js');
65
+ return mod.cmdHook(flags);
66
+ }
67
+
68
+ export async function cmdGraph(flags, quiet) {
69
+ const mod = require('../commands/graph.js');
70
+ return mod.cmdGraph(flags, quiet);
71
+ }
72
+
73
+ export async function cmdMutate(flags, argv) {
74
+ const mod = require('../commands/mutate.js');
75
+ return mod.cmdMutate(flags, argv);
76
+ }
77
+
78
+ export function cmdContext(flags, argv) {
79
+ const mod = require('../commands/context.js');
80
+ return mod.cmdContext(flags, argv);
81
+ }
82
+
83
+ export async function cmdSync() {
84
+ const mod = require('../commands/sync.js');
85
+ return mod.cmdSync();
86
+ }
87
+
88
+ export async function cmdAlign(flags, argv, quiet) {
89
+ const mod = require('../commands/align.js');
90
+ return mod.cmdAlign(flags, argv, quiet);
91
+ }
92
+
93
+ export async function cmdMarathon(flags, argv, quiet) {
94
+ const mod = require('../commands/marathon.js');
95
+ return mod.cmdMarathon(flags, argv, quiet);
96
+ }
97
+
98
+ export async function cmdCompile(flags, quiet) {
99
+ const mod = require('../commands/compile.js');
100
+ return mod.cmdCompile(flags, quiet);
101
+ }
102
+
103
+ export async function cmdMemory(flags, argv, quiet) {
104
+ const mod = require('../commands/memory.js');
105
+ return mod.cmdMemory(flags, argv, quiet);
106
+ }
107
+
108
+ export function cmdUninstall(flags, quiet) {
109
+ const mod = require('../commands/uninstall.js');
110
+ return mod.cmdUninstall(flags, quiet);
111
+ }
112
+
113
+ export async function generateIDEBridges(cwd, agentDest, quiet) {
114
+ const mod = require('../commands/init.js');
115
+ return mod.generateIDEBridges(cwd, agentDest, quiet);
116
+ }