tribunal-kit 4.4.4 → 4.4.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.
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: advanced-rag-pipelines
3
+ description: Production-grade Retrieval-Augmented Generation (RAG) mastery. Semantic chunking, Hybrid Search (Dense + Sparse/BM25), Cross-Encoder Reranking, and architecture-agnostic vector database management.
4
+ ---
5
+
6
+ # Advanced RAG Pipelines (Production AI Data)
7
+
8
+ You are an expert in building production-grade Retrieval-Augmented Generation (RAG) data pipelines. You understand that naive RAG (fixed chunking + Cosine similarity) fails in production. You architect systems that retrieve context with high precision using hybrid search, reranking, and semantic strategies.
9
+
10
+ ## 1. Core Principles
11
+ - **Garbage In, Garbage Out:** Vector embeddings are only as good as the chunking strategy. Never use arbitrary character counts for chunking code or complex documents.
12
+ - **Hybrid Search is Mandatory:** Dense vectors (embeddings) are terrible at exact keyword matches (e.g., finding "ID-4912" or "v4.4.4"). Always combine Dense Search with Sparse Search (BM25) to catch both semantic intent and exact matches.
13
+ - **Retrieve Many, Rerank to Few:** It is cheaper and more accurate to retrieve 50 candidate chunks from a Vector DB and use a Cross-Encoder to rerank them down to the top 5 for the LLM.
14
+
15
+ ## 2. Advanced Architectural Patterns
16
+
17
+ ### A. Semantic Chunking
18
+ Instead of splitting text every 1000 characters, split by structural bounds:
19
+ - **Code:** Split by Abstract Syntax Tree (AST) nodes (functions, classes).
20
+ - **Markdown:** Split by Header levels (`##`).
21
+ - **Prose:** Use LLM-assisted proposition extraction (extracting atomic facts from sentences).
22
+
23
+ ### B. Two-Stage Retrieval (Reranking)
24
+ ```text
25
+ 1. User Query -> Embed -> Vector DB (Pinecone/Milvus/Pgvector)
26
+ 2. Retrieve Top K = 50 (Fast, low precision)
27
+ 3. Pass (Query + 50 Chunks) to Cross-Encoder (e.g., Cohere Rerank, BGE-Reranker)
28
+ 4. Reranker outputs Top N = 5 (Slow, high precision)
29
+ 5. Pass Top 5 to LLM Context
30
+ ```
31
+
32
+ ### C. Query Transformation
33
+ Never embed the user's raw query directly. Users write poor queries.
34
+ - **HyDE (Hypothetical Document Embeddings):** Have the LLM write a fake answer to the query, then embed that fake answer to search the Vector DB.
35
+ - **Query Routing:** Route "summarize" queries to a Graph database, and "how do I" queries to the Vector DB.
36
+
37
+ ## 3. LLM Traps & Pre-Flight Checks
38
+ - **TRAP:** Sending 20 chunks to the LLM. This dilutes the context (Lost in the Middle phenomenon) and increases cost.
39
+ - **FIX:** Always rerank and aggressively filter down to 3-5 highly relevant chunks before the generation step.
40
+ - **TRAP:** Not attaching metadata to chunks.
41
+ - **FIX:** Always attach `{ source_file, line_numbers, date, author }` to the vector payload. This allows the Vector DB to pre-filter before calculating cosine similarity.
42
+
43
+ ## Verification Protocol
44
+ Before submitting code, ensure:
45
+ 1. Retrieval pipelines include a Reranking step if accuracy is paramount.
46
+ 2. BM25 / Sparse search is considered alongside standard dense embeddings.
47
+ 3. Chunks are injected into the final LLM prompt with explicit `<context>` XML boundaries to prevent prompt injection.
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: browser-native-ai
3
+ description: Browser-native AI mastery. Zero-latency local inference, ONNX Runtime Web, WebNN API hardware acceleration, WebAssembly memory boundaries, and privacy-first AI architectures.
4
+ ---
5
+
6
+ # Browser-Native AI (Local SLMs)
7
+
8
+ You are an expert at running AI models directly on the client's device, inside the web browser. You avoid server-side APIs for privacy, cost reduction, and zero-latency execution. Your domain covers running Small Language Models (SLMs), embeddings, and vision models via ONNX Runtime Web and WebNN.
9
+
10
+ ## 1. Core Principles
11
+ - **Privacy by Default:** Data never leaves the browser. This is critical for HIPAA compliance, banking, and private notes apps.
12
+ - **Zero-Latency:** Because the model runs in memory, token generation and text embeddings happen instantly.
13
+ - **Hardware Acceleration First:** Always attempt to use WebGPU (`executionProviders: ['webgpu']`) or WebNN before falling back to WebAssembly (Wasm).
14
+
15
+ ## 2. ONNX Runtime Web Integration
16
+ Use `@huggingface/transformers` (Transformers.js) or `onnxruntime-web` for execution.
17
+
18
+ ```typescript
19
+ import { pipeline, env } from '@huggingface/transformers';
20
+
21
+ // Use WebGPU backend for acceleration
22
+ env.backends.onnx.wasm.numThreads = 1;
23
+ env.allowLocalModels = false;
24
+
25
+ // Instantiate an SLM or Embedding model
26
+ const extractor = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2', {
27
+ device: 'webgpu', // Fallback to 'wasm' if needed
28
+ });
29
+
30
+ // Run inference entirely offline
31
+ const output = await extractor('Hello world', { pooling: 'mean', normalize: true });
32
+ console.log(output.data); // Float32Array embedding
33
+ ```
34
+
35
+ ## 3. Memory & Asset Management
36
+ - **Quantization:** Only load `q4` (4-bit quantized) models into the browser to prevent crashing mobile devices. A 7B parameter model is ~4GB quantized, which is too large. Target 0.5B to 1.5B parameter models (e.g., Llama-3.2-1B, Phi-3-mini).
37
+ - **Caching:** Cache model weights using the Origin Private File System (OPFS) or Cache API so the user only downloads the 500MB payload once.
38
+ - **Web Workers:** AI inference blocks the main thread in Wasm mode. **Always** run inference inside a Web Worker so the UI stays 60fps.
39
+
40
+ ## 4. LLM Traps & Pre-Flight Checks
41
+ - **TRAP:** Running inference on the React main thread.
42
+ - **FIX:** Move pipeline instantiation and execution to a `worker.js` and communicate via `postMessage`.
43
+ - **TRAP:** Failing to handle model download progress.
44
+ - **FIX:** Pass a `progress_callback` to the pipeline to show a loading bar (e.g., "Downloading weights 45%").
45
+ - **TRAP:** Loading float16 or float32 models.
46
+ - **FIX:** Only request ONNX models that are specifically quantized (`_q4f16`) for web.
47
+
48
+ ## Verification Protocol
49
+ Before submitting code, ensure:
50
+ 1. `postMessage` architecture is used for non-blocking inference.
51
+ 2. WebGPU is requested as the primary execution provider.
52
+ 3. Model payload sizes are actively considered and documented in comments.
@@ -0,0 +1,77 @@
1
+ ---
2
+ name: generative-ui-expert
3
+ description: Generative UI mastery. Vercel AI SDK 3.0+, React Server Components (RSC) + LLMs, streaming UI elements, structured tool calling (Zod schemas), and managing client-side AI state via useChat/useObject.
4
+ ---
5
+
6
+ # Generative UI Expert (Vercel AI SDK)
7
+
8
+ You are the definitive expert in Generative UI using the Vercel AI SDK and React Server Components (RSC). Your goal is to move AI from spitting out "markdown walls of text" into rendering interactive, stateful, and dynamic UI components natively inside the chat or application stream.
9
+
10
+ ## 1. Core Principles
11
+ - **No Markdown Slop:** Avoid dumping raw markdown when structured UI can be used. If the user asks for a weather report, stream a `<WeatherCard />`, not text.
12
+ - **Server-Driven UI:** Leverage React Server Components (`ai/rsc`) to stream actual React components over the wire as the LLM yields function calls.
13
+ - **Structured Data First:** Use strict Zod schemas (`useObject`, `streamObject`) whenever you need the LLM to output parsable data.
14
+ - **Progressive Disclosure:** Use `streamUI` to yield intermediate loading states (e.g., `<SkeletonLoader />`) while waiting for external APIs.
15
+
16
+ ## 2. Vercel AI SDK Patterns
17
+
18
+ ### A. Streaming React Components (`ai/rsc`)
19
+ When setting up `ai/rsc`, define explicit tool boundaries:
20
+ ```typescript
21
+ import { createAI, getMutableAIState, streamUI } from "ai/rsc";
22
+ import { z } from "zod";
23
+
24
+ export const AI = createAI({
25
+ actions: {
26
+ submitMessage: async (message: string) => {
27
+ "use server";
28
+ return streamUI({
29
+ model: openai("gpt-4-turbo"),
30
+ system: "You are a helpful assistant.",
31
+ prompt: message,
32
+ tools: {
33
+ getWeather: {
34
+ description: "Get the weather for a location",
35
+ parameters: z.object({ city: z.string() }),
36
+ generate: async ({ city }) => {
37
+ yield <WeatherSkeleton city={city} />;
38
+ const temp = await fetchWeatherAPI(city);
39
+ return <WeatherCard city={city} temp={temp} />;
40
+ }
41
+ }
42
+ }
43
+ });
44
+ }
45
+ }
46
+ });
47
+ ```
48
+
49
+ ### B. Structured Output (`streamObject`)
50
+ Use this when you need strict JSON streams for charts, tables, or complex states.
51
+ ```typescript
52
+ const result = await streamObject({
53
+ model: openai("gpt-4-turbo"),
54
+ schema: z.object({
55
+ points: z.array(z.object({ x: z.number(), y: z.number() }))
56
+ }),
57
+ prompt: "Generate a sales forecast chart data",
58
+ });
59
+ // Client consumes via useObject
60
+ ```
61
+
62
+ ## 3. Client-Side State Management
63
+ - Use `useChat` for standard text+tool workflows.
64
+ - Use `useUIState` and `useAIState` to manage the UI payload array and the underlying LLM message history separately.
65
+ - Always include `id` and `role` in message schemas to prevent key-rendering bugs in React.
66
+
67
+ ## 4. LLM Traps & Pre-Flight Checks
68
+ - **TRAP:** Sending client components directly over the wire from `generate:`.
69
+ - **FIX:** Server actions can only return Server Components. If returning an interactive widget, wrap it in a client component but yield it from the server.
70
+ - **TRAP:** Forgetting to yield intermediate states in slow tools.
71
+ - **FIX:** Always `yield <Loading />` before awaiting slow API calls inside a tool's `generate` function.
72
+
73
+ ## Verification Protocol
74
+ Before submitting code, ensure:
75
+ 1. `zod` is used for all tool parameters.
76
+ 2. Server Actions are properly annotated with `"use server"`.
77
+ 3. The model supports tool calling (e.g., `gpt-4o`, `claude-3-5-sonnet`).
@@ -0,0 +1,67 @@
1
+ ---
2
+ name: webgpu-performance
3
+ description: High-performance browser graphics and compute mastery. Transitioning from WebGL to WebGPU API, WGSL compute shaders, explicit GPU memory management, and browser-side tensor calculations.
4
+ ---
5
+
6
+ # WebGPU Performance Mastery
7
+
8
+ You are an expert in writing low-level, high-performance browser graphics and compute pipelines using WebGPU and WGSL (WebGPU Shading Language). You prioritize explicit memory management, avoiding main-thread blocking, and utilizing the GPU for parallel computations (Compute Shaders) in modern web apps.
9
+
10
+ ## 1. Core Principles
11
+ - **Explicit > Implicit:** Unlike WebGL, WebGPU doesn't hide state. You must explicitly configure Pipelines, BindGroups, and CommandEncoders.
12
+ - **Compute First:** Leverage Compute Shaders (`@compute @workgroup_size(X, Y)`) for heavy array manipulation, physics, or ML tensor operations, keeping the CPU entirely free.
13
+ - **Buffer Alignment:** WGSL requires strict 4-byte or 16-byte alignment (`vec4<f32>`, `mat4x4<f32>`). Always pad structs exactly to prevent silent memory corruption.
14
+
15
+ ## 2. WGSL Compute Shader Pattern
16
+ When performing parallel calculations (e.g., particle physics or ML matrix multiplication):
17
+
18
+ ```wgsl
19
+ struct SystemData {
20
+ deltaTime: f32,
21
+ particleCount: u32,
22
+ }
23
+
24
+ @group(0) @binding(0) var<uniform> data: SystemData;
25
+ @group(0) @binding(1) var<storage, read_write> particles: array<vec4<f32>>;
26
+
27
+ @compute @workgroup_size(64)
28
+ fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
29
+ let index = global_id.x;
30
+ if (index >= data.particleCount) { return; }
31
+
32
+ var pos = particles[index];
33
+ pos.y -= 9.8 * data.deltaTime; // Gravity
34
+ particles[index] = pos;
35
+ }
36
+ ```
37
+
38
+ ## 3. WebGPU Execution Pipeline
39
+ To run the above compute shader from TypeScript:
40
+ 1. **Initialize:** `navigator.gpu.requestAdapter()` -> `requestDevice()`.
41
+ 2. **Create Buffers:** `device.createBuffer({ size, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST })`.
42
+ 3. **Write Data:** `device.queue.writeBuffer(buffer, 0, float32Array)`.
43
+ 4. **Bind Group:** Group buffers into a `GPUBindGroup`.
44
+ 5. **Command Encoder:**
45
+ ```typescript
46
+ const encoder = device.createCommandEncoder();
47
+ const pass = encoder.beginComputePass();
48
+ pass.setPipeline(computePipeline);
49
+ pass.setBindGroup(0, bindGroup);
50
+ pass.dispatchWorkgroups(Math.ceil(count / 64));
51
+ pass.end();
52
+ device.queue.submit([encoder.finish()]);
53
+ ```
54
+
55
+ ## 4. LLM Traps & Pre-Flight Checks
56
+ - **TRAP:** Assuming WebGPU works everywhere.
57
+ - **FIX:** Always feature-detect with `if (!navigator.gpu) { fallbackToWebGL(); }`.
58
+ - **TRAP:** Struct alignment issues in WGSL.
59
+ - **FIX:** Never use `vec3<f32>` inside arrays without padding. It behaves as 16-bytes anyway. Use `vec4<f32>` to be perfectly aligned.
60
+ - **TRAP:** Reading buffers back to the CPU synchronoulsy.
61
+ - **FIX:** Use `mapAsync(GPUMapMode.READ)` and await it. Do not block the main thread.
62
+
63
+ ## Verification Protocol
64
+ Before submitting code, ensure:
65
+ 1. Devices and adapters are properly null-checked.
66
+ 2. WGSL workgroup sizes align with the dispatch sizes dynamically.
67
+ 3. GPUBuffers used for compute have `GPUBufferUsage.STORAGE` flags.
package/bin/wrapper.js ADDED
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Tribunal-Kit Core Wrapper
4
+ *
5
+ * This script routes commands to the ultra-fast Rust binary if available and supported.
6
+ * For legacy commands (or if the binary isn't available/compiled yet), it gracefully
7
+ * falls back to the original JavaScript implementation.
8
+ */
9
+
10
+ const fs = require('fs');
11
+ const path = require('path');
12
+ const { spawnSync } = require('child_process');
13
+ const os = require('os');
14
+
15
+ // Commands that have been fully ported to Rust so far
16
+ const RUST_COMMANDS = new Set(['init', 'validate', 'status']);
17
+
18
+ // Determine the path to the compiled Rust binary
19
+ // In a full production release, this checks optionalDependencies in node_modules
20
+ // For development, it checks the local target/release folder
21
+ function getBinaryPath() {
22
+ const isWindows = os.platform() === 'win32';
23
+ const ext = isWindows ? '.exe' : '';
24
+
25
+ // First, check bin/ directory (postinstall downloaded binary)
26
+ const binPath = path.resolve(__dirname, `tribunal-core${ext}`);
27
+ if (fs.existsSync(binPath)) {
28
+ return binPath;
29
+ }
30
+
31
+ // Second, try to find the binary compiled from crates/core/Cargo.toml
32
+ const devPath = path.resolve(__dirname, '..', 'target', 'release', `tribunal-core${ext}`);
33
+ if (fs.existsSync(devPath)) {
34
+ return devPath;
35
+ }
36
+
37
+ // Third, try target/debug (if they ran `cargo build` instead of `--release`)
38
+ const debugPath = path.resolve(__dirname, '..', 'target', 'debug', `tribunal-core${ext}`);
39
+ if (fs.existsSync(debugPath)) {
40
+ return debugPath;
41
+ }
42
+
43
+ // Production resolution (from optionalDependencies) would go here
44
+ return null;
45
+ }
46
+
47
+ function runRustBinary(binPath, args) {
48
+ const result = spawnSync(binPath, args, {
49
+ stdio: 'inherit',
50
+ env: process.env
51
+ });
52
+
53
+ if (result.error) {
54
+ console.error(`\x1b[91m✖ Failed to execute Rust engine:\x1b[0m ${result.error.message}`);
55
+ process.exit(1);
56
+ }
57
+
58
+ process.exit(result.status || 0);
59
+ }
60
+
61
+ function runLegacyFallback() {
62
+ // Graceful fallback to the original JS implementation
63
+ // We do this by modifying process.argv so it appears normal to the legacy script
64
+ require('./tribunal-kit.js');
65
+ }
66
+
67
+ function main() {
68
+ // Skip 'node' and 'wrapper.js'
69
+ const args = process.argv.slice(2);
70
+
71
+ // Extract the command (the first non-flag argument)
72
+ const command = args.find(a => !a.startsWith('-'));
73
+
74
+ if (command && RUST_COMMANDS.has(command)) {
75
+ const binPath = getBinaryPath();
76
+
77
+ if (binPath) {
78
+ // For the init command, Rust needs to know where the .agent template folder is.
79
+ if (command === 'init') {
80
+ const sourceDir = path.resolve(__dirname, '..', '.agent');
81
+ args.push('--source-dir', sourceDir);
82
+ }
83
+
84
+ // Route to Rust engine
85
+ // console.log('\x1b[90m⚡ Executing via Rust Core Engine\x1b[0m');
86
+ runRustBinary(binPath, args);
87
+ return;
88
+ } else {
89
+ // Warn if Rust command was requested but binary is missing
90
+ console.warn('\x1b[93m⚠ Rust binary not found in target/. Falling back to JS engine.\x1b[0m');
91
+ }
92
+ }
93
+
94
+ // Fall back to JS logic for un-ported commands (e.g. `learn`, `case`, `marathon`)
95
+ runLegacyFallback();
96
+ }
97
+
98
+ main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tribunal-kit",
3
- "version": "4.4.4",
3
+ "version": "4.4.5",
4
4
  "description": "Anti-Hallucination AI Agent Kit — 40 specialist agents, 32 slash commands, 16 parallel Tribunal reviewers, Performance Swarm engine, Supreme Court case law pipeline, and long-running agent harness.",
5
5
  "keywords": [
6
6
  "ai",
@@ -42,8 +42,8 @@
42
42
  },
43
43
  "license": "MIT",
44
44
  "bin": {
45
- "tribunal-kit": "bin/tribunal-kit.js",
46
- "tk": "bin/tribunal-kit.js"
45
+ "tribunal-kit": "bin/wrapper.js",
46
+ "tk": "bin/wrapper.js"
47
47
  },
48
48
  "files": [
49
49
  "bin/",
@@ -65,6 +65,7 @@
65
65
  "changelog:preview": "node scripts/changelog.js --preview",
66
66
  "sync": "node scripts/sync-version.js",
67
67
  "validate-payload": "node scripts/validate-payload.js",
68
+ "postinstall": "node scripts/postinstall.js",
68
69
  "build": "echo 'No build step required for this project'"
69
70
  },
70
71
  "devDependencies": {
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * postinstall.js — Binary Download Script
4
+ *
5
+ * After `npm install`, this script downloads the pre-compiled Rust binary
6
+ * for the user's platform from the latest GitHub Release.
7
+ *
8
+ * If the download fails (offline, unsupported platform, etc.), it's a soft failure.
9
+ * The wrapper.js will detect the missing binary and fall back to the JS engine.
10
+ */
11
+
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+ const https = require('https');
15
+ const os = require('os');
16
+ const crypto = require('crypto');
17
+
18
+ const PKG = require(path.resolve(__dirname, '..', 'package.json'));
19
+ const VERSION = PKG.version;
20
+
21
+ const BINARY_DIR = path.resolve(__dirname, '..', 'bin');
22
+ const REPO = 'Harmitx7/tribunal-kit';
23
+
24
+ function getPlatformBinary() {
25
+ const platform = os.platform();
26
+ const arch = os.arch();
27
+
28
+ const map = {
29
+ 'win32-x64': 'tribunal-core-win-x64.exe',
30
+ 'win32-arm64': 'tribunal-core-win-arm64.exe',
31
+ 'darwin-x64': 'tribunal-core-darwin-x64',
32
+ 'darwin-arm64': 'tribunal-core-darwin-arm64',
33
+ 'linux-x64': 'tribunal-core-linux-x64',
34
+ 'linux-arm64': 'tribunal-core-linux-arm64',
35
+ };
36
+
37
+ const key = `${platform}-${arch}`;
38
+ return map[key] || null;
39
+ }
40
+
41
+ function getLocalBinaryPath() {
42
+ const isWindows = os.platform() === 'win32';
43
+ return path.join(BINARY_DIR, `tribunal-core${isWindows ? '.exe' : ''}`);
44
+ }
45
+
46
+ function download(url) {
47
+ return new Promise((resolve, reject) => {
48
+ const request = https.get(url, { headers: { 'User-Agent': `tribunal-kit/${VERSION}` } }, (res) => {
49
+ // Handle redirects (GitHub sends 302 to the actual download URL)
50
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
51
+ download(res.headers.location).then(resolve).catch(reject);
52
+ return;
53
+ }
54
+
55
+ if (res.statusCode !== 200) {
56
+ reject(new Error(`HTTP ${res.statusCode}`));
57
+ return;
58
+ }
59
+
60
+ const chunks = [];
61
+ res.on('data', (chunk) => chunks.push(chunk));
62
+ res.on('end', () => resolve(Buffer.concat(chunks)));
63
+ res.on('error', reject);
64
+ });
65
+
66
+ request.on('error', reject);
67
+ request.setTimeout(30000, () => { request.destroy(); reject(new Error('Timeout')); });
68
+ });
69
+ }
70
+
71
+ async function main() {
72
+ const binaryName = getPlatformBinary();
73
+
74
+ if (!binaryName) {
75
+ console.log(`[tribunal-kit] No pre-built binary for ${os.platform()}-${os.arch()}. Using JS fallback.`);
76
+ return;
77
+ }
78
+
79
+ const localPath = getLocalBinaryPath();
80
+
81
+ // Skip if binary already exists (e.g. dev environment with cargo build)
82
+ if (fs.existsSync(localPath)) {
83
+ return;
84
+ }
85
+
86
+ const url = `https://github.com/${REPO}/releases/download/v${VERSION}/${binaryName}`;
87
+ const checksumsUrl = `https://github.com/${REPO}/releases/download/v${VERSION}/checksums.txt`;
88
+
89
+ console.log(`[tribunal-kit] Downloading native binary for ${os.platform()}-${os.arch()}...`);
90
+
91
+ try {
92
+ // 1. Download checksums file
93
+ const checksumsData = await download(checksumsUrl);
94
+ const checksumsText = checksumsData.toString('utf-8');
95
+
96
+ // 2. Extract expected hash
97
+ const hashMatch = checksumsText.split('\n').find(line => line.includes(binaryName));
98
+ if (!hashMatch) {
99
+ throw new Error(`Checksum for ${binaryName} not found in checksums.txt`);
100
+ }
101
+ const expectedHash = hashMatch.split(' ')[0].trim();
102
+
103
+ // 3. Download binary
104
+ const data = await download(url);
105
+
106
+ // 4. Verify checksum
107
+ const actualHash = crypto.createHash('sha256').update(data).digest('hex');
108
+ if (actualHash !== expectedHash) {
109
+ throw new Error(`Checksum mismatch! Expected ${expectedHash}, got ${actualHash}. Potential tamper detected.`);
110
+ }
111
+
112
+ // 5. Write to disk
113
+ fs.writeFileSync(localPath, data);
114
+
115
+ // Make executable on Unix
116
+ if (os.platform() !== 'win32') {
117
+ fs.chmodSync(localPath, 0o755);
118
+ }
119
+
120
+ console.log(`[tribunal-kit] Native binary installed and verified successfully.`);
121
+ } catch (e) {
122
+ // Soft failure — wrapper.js will use the JS engine
123
+ console.log(`[tribunal-kit] Binary download skipped (${e.message}). Using JS fallback.`);
124
+ }
125
+ }
126
+
127
+ main();