Initial release — Crucix Intelligence Engine v2.0.0

26-source OSINT intelligence engine with live Jarvis dashboard,
auto-refresh via SSE, optional LLM layer (4 providers), delta/memory
system, and Telegram breaking news alerts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
calesthio
2026-03-12 23:45:46 -07:00
commit ef2c6470fb
53 changed files with 8709 additions and 0 deletions

49
lib/llm/anthropic.mjs Normal file
View File

@@ -0,0 +1,49 @@
// Anthropic Claude Provider — raw fetch, no SDK
import { LLMProvider } from './provider.mjs';
export class AnthropicProvider extends LLMProvider {
constructor(config) {
super(config);
this.name = 'anthropic';
this.apiKey = config.apiKey;
this.model = config.model || 'claude-sonnet-4-20250514';
}
get isConfigured() { return !!this.apiKey; }
async complete(systemPrompt, userMessage, opts = {}) {
const res = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': this.apiKey,
'anthropic-version': '2023-06-01',
},
body: JSON.stringify({
model: this.model,
max_tokens: opts.maxTokens || 4096,
system: systemPrompt,
messages: [{ role: 'user', content: userMessage }],
}),
signal: AbortSignal.timeout(opts.timeout || 60000),
});
if (!res.ok) {
const err = await res.text().catch(() => '');
throw new Error(`Anthropic API ${res.status}: ${err.substring(0, 200)}`);
}
const data = await res.json();
const text = data.content?.[0]?.text || '';
return {
text,
usage: {
inputTokens: data.usage?.input_tokens || 0,
outputTokens: data.usage?.output_tokens || 0,
},
model: data.model || this.model,
};
}
}

147
lib/llm/codex.mjs Normal file
View File

@@ -0,0 +1,147 @@
// OpenAI Codex Provider — uses ChatGPT subscription via chatgpt.com/backend-api/codex/responses
// Auth: reads ~/.codex/auth.json (created by `npx @openai/codex login`)
// SSE streaming, codex-specific models only (gpt-5.2-codex, gpt-5.3-codex)
import { readFileSync } from 'fs';
import { join } from 'path';
import { homedir } from 'os';
import { LLMProvider } from './provider.mjs';
const CODEX_ENDPOINT = 'https://chatgpt.com/backend-api/codex/responses';
const AUTH_PATH = join(homedir(), '.codex', 'auth.json');
export class CodexProvider extends LLMProvider {
constructor(config) {
super(config);
this.name = 'codex';
this.model = config.model || 'gpt-5.2-codex';
this._creds = null;
}
get isConfigured() {
return !!this._getCredentials();
}
_getCredentials() {
if (this._creds) return this._creds;
// Try env vars first
const token = process.env.CODEX_ACCESS_TOKEN || process.env.OPENAI_OAUTH_TOKEN;
const accountId = process.env.CODEX_ACCOUNT_ID;
if (token && accountId) {
this._creds = { accessToken: token, accountId };
return this._creds;
}
// Try ~/.codex/auth.json
try {
const auth = JSON.parse(readFileSync(AUTH_PATH, 'utf8'));
// Tokens may be nested under auth.tokens (newer format) or top-level
const tokens = auth.tokens || auth;
const accessToken = tokens.access_token || tokens.token || auth.access_token || auth.token;
if (accessToken) {
this._creds = {
accessToken,
accountId: tokens.account_id || auth.account_id || accountId || '',
};
return this._creds;
}
} catch { /* no auth file */ }
return null;
}
_clearCredentials() {
this._creds = null;
}
async complete(systemPrompt, userMessage, opts = {}) {
const creds = this._getCredentials();
if (!creds) throw new Error('Codex: No credentials found. Run `npx @openai/codex login`');
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${creds.accessToken}`,
};
if (creds.accountId) headers['ChatGPT-Account-Id'] = creds.accountId;
const body = {
model: this.model,
instructions: systemPrompt || '',
input: [{ type: 'message', role: 'user', content: userMessage }],
stream: true,
store: false,
};
const res = await fetch(CODEX_ENDPOINT, {
method: 'POST',
headers,
body: JSON.stringify(body),
signal: AbortSignal.timeout(opts.timeout || 90000),
});
if (res.status === 401 || res.status === 403) {
this._clearCredentials();
throw new Error(`Codex auth failed (${res.status}). Run \`npx @openai/codex login\` to refresh.`);
}
if (!res.ok) {
const err = await res.text().catch(() => '');
throw new Error(`Codex API ${res.status}: ${err.substring(0, 200)}`);
}
// Parse SSE stream
const text = await this._parseSSE(res);
return {
text,
usage: { inputTokens: 0, outputTokens: 0 }, // Codex doesn't always return usage
model: this.model,
};
}
async _parseSSE(res) {
const reader = res.body.getReader();
const decoder = new TextDecoder();
let text = '';
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';
for (const line of lines) {
if (!line.startsWith('data: ')) continue;
const payload = line.slice(6).trim();
if (payload === '[DONE]') return text;
try {
const event = JSON.parse(payload);
// Handle text deltas
if (event.type === 'response.output_text.delta') {
text += event.delta || '';
}
// Handle completed response
if (event.type === 'response.completed') {
const output = event.response?.output;
if (output && Array.isArray(output)) {
for (const item of output) {
if (item.type === 'message' && item.content) {
for (const part of item.content) {
if (part.type === 'output_text') text = part.text || text;
}
}
}
}
}
} catch { /* skip malformed events */ }
}
}
return text;
}
}

48
lib/llm/gemini.mjs Normal file
View File

@@ -0,0 +1,48 @@
// Google Gemini Provider — raw fetch, no SDK
import { LLMProvider } from './provider.mjs';
export class GeminiProvider extends LLMProvider {
constructor(config) {
super(config);
this.name = 'gemini';
this.apiKey = config.apiKey;
this.model = config.model || 'gemini-2.0-flash';
}
get isConfigured() { return !!this.apiKey; }
async complete(systemPrompt, userMessage, opts = {}) {
const url = `https://generativelanguage.googleapis.com/v1beta/models/${this.model}:generateContent?key=${this.apiKey}`;
const res = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
systemInstruction: { parts: [{ text: systemPrompt }] },
contents: [{ parts: [{ text: userMessage }] }],
generationConfig: {
maxOutputTokens: opts.maxTokens || 4096,
},
}),
signal: AbortSignal.timeout(opts.timeout || 60000),
});
if (!res.ok) {
const err = await res.text().catch(() => '');
throw new Error(`Gemini API ${res.status}: ${err.substring(0, 200)}`);
}
const data = await res.json();
const text = data.candidates?.[0]?.content?.parts?.[0]?.text || '';
return {
text,
usage: {
inputTokens: data.usageMetadata?.promptTokenCount || 0,
outputTokens: data.usageMetadata?.candidatesTokenCount || 0,
},
model: this.model,
};
}
}

189
lib/llm/ideas.mjs Normal file
View File

@@ -0,0 +1,189 @@
// LLM-Powered Trade Ideas — generates actionable ideas from sweep data + delta context
/**
* Generate LLM-enhanced trade ideas from sweep data.
* @param {LLMProvider} provider - configured LLM provider
* @param {object} sweepData - synthesized dashboard data
* @param {object|null} delta - delta from last sweep
* @param {Array} previousIdeas - ideas from previous runs (for dedup)
* @returns {Promise<Array>} - array of idea objects
*/
export async function generateLLMIdeas(provider, sweepData, delta, previousIdeas = []) {
if (!provider?.isConfigured) return null;
let context;
try {
context = compactSweepForLLM(sweepData, delta, previousIdeas);
} catch (err) {
console.error('[LLM Ideas] Failed to compact sweep data:', err.message);
return null;
}
const systemPrompt = `You are a quantitative analyst at a macro intelligence firm. You receive structured OSINT + economic data from 25 sources and produce 5-8 actionable trade ideas.
Rules:
- Each idea must cite specific data points from the input
- Include entry rationale, risk factors, and time horizon
- Blend geopolitical, economic, and market signals — cross-correlate across domains
- Be specific: name instruments (tickers, futures, ETFs), not vague sectors
- If delta shows significant changes, lead with those
- Do NOT repeat ideas from the "previous ideas" list unless conditions have materially changed
- Rate confidence: HIGH (multiple confirming signals), MEDIUM (thesis supported), LOW (speculative)
Output ONLY valid JSON array. Each object:
{
"title": "Short title (max 10 words)",
"type": "LONG|SHORT|HEDGE|WATCH|AVOID",
"ticker": "Primary instrument",
"confidence": "HIGH|MEDIUM|LOW",
"rationale": "2-3 sentence explanation citing specific data",
"risk": "Key risk factor",
"horizon": "Intraday|Days|Weeks|Months",
"signals": ["signal1", "signal2"]
}`;
try {
const result = await provider.complete(systemPrompt, context, { maxTokens: 4096, timeout: 90000 });
const ideas = parseIdeasResponse(result.text);
if (ideas && ideas.length > 0) {
return ideas;
}
console.warn('[LLM Ideas] No valid ideas parsed from response');
return null;
} catch (err) {
console.error('[LLM Ideas] Generation failed:', err.message);
return null;
}
}
/**
* Compact sweep data to ~8KB for token efficiency.
*/
function compactSweepForLLM(data, delta, previousIdeas) {
const sections = [];
// Economic indicators
if (data.fred?.length) {
const key = data.fred.filter(f => ['VIXCLS', 'DFF', 'DGS10', 'DGS2', 'T10Y2Y', 'BAMLH0A0HYM2', 'DTWEXBGS', 'MORTGAGE30US'].includes(f.id));
sections.push(`ECONOMIC: ${key.map(f => `${f.id}=${f.value}${f.momChange ? ` (${f.momChange > 0 ? '+' : ''}${f.momChange})` : ''}`).join(', ')}`);
}
// Energy
if (data.energy) {
sections.push(`ENERGY: WTI=$${data.energy.wti}, Brent=$${data.energy.brent}, NatGas=$${data.energy.natgas}, CrudeStocks=${data.energy.crudeStocks}bbl`);
}
// BLS
if (data.bls?.length) {
sections.push(`LABOR: ${data.bls.map(b => `${b.id}=${b.value}`).join(', ')}`);
}
// Treasury
if (data.treasury) {
sections.push(`TREASURY: totalDebt=$${data.treasury}T`);
}
// Supply chain
if (data.gscpi) {
sections.push(`SUPPLY_CHAIN: GSCPI=${data.gscpi.value} (${data.gscpi.interpretation})`);
}
// Geopolitical signals
const urgentPosts = (data.tg?.urgent || []).slice(0, 5);
if (urgentPosts.length) {
sections.push(`URGENT_OSINT:\n${urgentPosts.map(p => `- ${(p.text || '').substring(0, 120)}`).join('\n')}`);
}
// Thermal / fire detections
if (data.thermal?.length) {
const hotRegions = data.thermal.filter(t => t.det > 10).map(t => `${t.region}: ${t.det} detections (${t.hc} high-conf)`);
if (hotRegions.length) sections.push(`THERMAL: ${hotRegions.join(', ')}`);
}
// Air activity
if (data.air?.length) {
const airSum = data.air.map(a => `${a.region}: ${a.total} aircraft`);
sections.push(`AIR_ACTIVITY: ${airSum.join(', ')}`);
}
// Nuclear
if (data.nuke?.length) {
const anomalies = data.nuke.filter(n => n.anom);
if (anomalies.length) sections.push(`NUCLEAR_ANOMALY: ${anomalies.map(n => `${n.site}: ${n.cpm}cpm`).join(', ')}`);
}
// WHO alerts
if (data.who?.length) {
sections.push(`WHO_ALERTS: ${data.who.slice(0, 3).map(w => w.title).join('; ')}`);
}
// Defense spending
if (data.defense?.length) {
const topContracts = data.defense.slice(0, 3).map(d => `$${((d.amount || 0) / 1e6).toFixed(0)}M to ${d.recipient}`);
sections.push(`DEFENSE_CONTRACTS: ${topContracts.join(', ')}`);
}
// Delta context
if (delta?.summary) {
sections.push(`\nDELTA_SINCE_LAST_SWEEP: direction=${delta.summary.direction}, changes=${delta.summary.totalChanges}, critical=${delta.summary.criticalChanges}`);
if (delta.signals?.escalated?.length) {
sections.push(`ESCALATED: ${delta.signals.escalated.map(s => `${s.label}: ${s.previous}${s.current} (${(s.changePct||0) > 0 ? '+' : ''}${(s.changePct||0).toFixed(1)}%)`).join(', ')}`);
}
if (delta.signals?.new?.length) {
sections.push(`NEW_SIGNALS: ${delta.signals.new.map(s => s.label || s.text?.substring(0, 60)).join('; ')}`);
}
}
// Previous ideas (for dedup)
if (previousIdeas.length) {
sections.push(`\nPREVIOUS_IDEAS (avoid repeating):\n${previousIdeas.map(i => `- ${i.title} [${i.type}]`).join('\n')}`);
}
return sections.join('\n');
}
/**
* Parse LLM response into ideas array. Handles markdown code blocks.
*/
function parseIdeasResponse(text) {
if (!text) return null;
// Strip markdown code block wrappers
let cleaned = text.trim();
if (cleaned.startsWith('```')) {
cleaned = cleaned.replace(/^```(?:json)?\n?/, '').replace(/\n?```$/, '');
}
try {
const parsed = JSON.parse(cleaned);
if (!Array.isArray(parsed)) return null;
// Validate each idea has required fields
return parsed.filter(idea =>
idea.title && idea.type && idea.confidence
).map(idea => ({
title: idea.title,
type: idea.type,
ticker: idea.ticker || '',
confidence: idea.confidence,
rationale: idea.rationale || '',
risk: idea.risk || '',
horizon: idea.horizon || '',
signals: idea.signals || [],
source: 'llm',
}));
} catch {
// Try to extract JSON array from mixed text
const match = cleaned.match(/\[[\s\S]*\]/);
if (match) {
try {
const arr = JSON.parse(match[0]);
return arr.filter(i => i.title && i.type).map(idea => ({
...idea,
source: 'llm',
}));
} catch { /* give up */ }
}
return null;
}
}

37
lib/llm/index.mjs Normal file
View File

@@ -0,0 +1,37 @@
// LLM Factory — creates the configured provider or returns null
import { AnthropicProvider } from './anthropic.mjs';
import { OpenAIProvider } from './openai.mjs';
import { GeminiProvider } from './gemini.mjs';
import { CodexProvider } from './codex.mjs';
export { LLMProvider } from './provider.mjs';
export { AnthropicProvider } from './anthropic.mjs';
export { OpenAIProvider } from './openai.mjs';
export { GeminiProvider } from './gemini.mjs';
export { CodexProvider } from './codex.mjs';
/**
* Create an LLM provider based on config.
* @param {{ provider: string|null, apiKey: string|null, model: string|null }} llmConfig
* @returns {LLMProvider|null}
*/
export function createLLMProvider(llmConfig) {
if (!llmConfig?.provider) return null;
const { provider, apiKey, model } = llmConfig;
switch (provider.toLowerCase()) {
case 'anthropic':
return new AnthropicProvider({ apiKey, model });
case 'openai':
return new OpenAIProvider({ apiKey, model });
case 'gemini':
return new GeminiProvider({ apiKey, model });
case 'codex':
return new CodexProvider({ model });
default:
console.warn(`[LLM] Unknown provider "${provider}". LLM features disabled.`);
return null;
}
}

50
lib/llm/openai.mjs Normal file
View File

@@ -0,0 +1,50 @@
// OpenAI Provider — raw fetch, no SDK
import { LLMProvider } from './provider.mjs';
export class OpenAIProvider extends LLMProvider {
constructor(config) {
super(config);
this.name = 'openai';
this.apiKey = config.apiKey;
this.model = config.model || 'gpt-4o';
}
get isConfigured() { return !!this.apiKey; }
async complete(systemPrompt, userMessage, opts = {}) {
const res = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.apiKey}`,
},
body: JSON.stringify({
model: this.model,
max_tokens: opts.maxTokens || 4096,
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userMessage },
],
}),
signal: AbortSignal.timeout(opts.timeout || 60000),
});
if (!res.ok) {
const err = await res.text().catch(() => '');
throw new Error(`OpenAI API ${res.status}: ${err.substring(0, 200)}`);
}
const data = await res.json();
const text = data.choices?.[0]?.message?.content || '';
return {
text,
usage: {
inputTokens: data.usage?.prompt_tokens || 0,
outputTokens: data.usage?.completion_tokens || 0,
},
model: data.model || this.model,
};
}
}

18
lib/llm/provider.mjs Normal file
View File

@@ -0,0 +1,18 @@
// Base LLM Provider — all providers implement this interface
export class LLMProvider {
constructor(config) {
this.config = config;
this.name = 'base';
}
/**
* Complete a prompt with system + user messages
* @returns {{ text: string, usage: { inputTokens: number, outputTokens: number }, model: string }}
*/
async complete(systemPrompt, userMessage, opts = {}) {
throw new Error(`${this.name}: complete() not implemented`);
}
get isConfigured() { return false; }
}