2026-07-05 21:10:14 +02:00
import { TerminalToolRegistry } from './terminal-agent.mjs' ;
export function createTerminalToolRegistry ( {
getData ,
getHealth ,
getDelta ,
buildBrief ,
intelligenceStore ,
2026-07-05 21:39:55 +02:00
securityProfileStore ,
2026-07-05 21:10:14 +02:00
triggerSweep ,
isSweepInProgress ,
telegramAlerter ,
} = { } ) {
const dataFor = runtime => runtime ? . data || getData ? . ( ) || null ;
const deltaFor = runtime => runtime ? . delta || getDelta ? . ( ) || null ;
return new TerminalToolRegistry ( [
tool ( 'get_system_status' , 'Get server, sweep, LLM, Telegram, source, and memory health.' , { } , async ( ) => getHealth ? . ( ) || { } ) ,
2026-07-05 21:39:55 +02:00
tool ( 'get_security_profile' , 'Get the operator-approved Security Manager profile for personal risk relevance, location, dependencies, mobility, alert preferences, and response language.' , { } , async ( ) => ( {
available : Boolean ( securityProfileStore ? . exists ) ,
profile : securityProfileStore ? . getAgentProfile ( ) || null ,
} ) ) ,
2026-07-05 21:10:14 +02:00
tool ( 'get_latest_brief' , 'Build the latest operator intelligence brief.' , { } , async ( _args , runtime ) => {
const data = dataFor ( runtime ) ;
return { brief : data && buildBrief ? buildBrief ( data ) : 'No completed sweep.' } ;
} ) ,
tool ( 'get_sweep_delta' , 'Inspect changes, escalations, de-escalations, and direction from the latest sweep.' , { } , async ( _args , runtime ) => compactDelta ( deltaFor ( runtime ) ) ) ,
tool ( 'get_market_snapshot' , 'Get key rates, volatility, energy, metals, and current generated ideas.' , { } , async ( _args , runtime ) => compactMarkets ( dataFor ( runtime ) ) ) ,
tool ( 'get_source_health' , 'Inspect healthy, degraded, or failed sources. Optional arguments: status, name, limit.' , { status : 'string' , name : 'string' , limit : 'number' } , async ( args , runtime ) => {
const data = dataFor ( runtime ) ;
const status = clean ( args . status , 30 ) . toLowerCase ( ) ;
const name = clean ( args . name , 80 ) . toLowerCase ( ) ;
const limit = bounded ( args . limit , 1 , 25 , 12 ) ;
return ( data ? . sourceHealth || data ? . health || [ ] )
. filter ( item => ! status || String ( item . status || '' ) . toLowerCase ( ) === status )
. filter ( item => ! name || String ( item . name || item . n || '' ) . toLowerCase ( ) . includes ( name ) )
. slice ( 0 , limit )
. map ( item => ( { name : item . name || item . n , status : item . status , ms : item . ms , error : clean ( item . error || item . message , 240 ) || null } ) ) ;
} ) ,
tool ( 'get_evidence' , 'Search recent news, feed items, and urgent OSINT. Arguments: query, limit.' , { query : 'string' , limit : 'number' } , async ( args , runtime ) => {
const data = dataFor ( runtime ) ;
const query = clean ( args . query , 120 ) . toLowerCase ( ) ;
const limit = bounded ( args . limit , 1 , 20 , 8 ) ;
const rows = [
... ( data ? . news || [ ] ) ,
... ( data ? . newsFeed || [ ] ) ,
... ( data ? . tg ? . urgent || [ ] ) . map ( item => ( { ... item , title : item . text , source : item . source || 'Telegram OSINT' } ) ) ,
] ;
return rows . filter ( item => ! query || ` ${ item . headline || item . title || item . text || '' } ${ item . source || '' } ` . toLowerCase ( ) . includes ( query ) )
. slice ( 0 , limit )
. map ( item => ( { title : clean ( item . headline || item . title || item . text , 400 ) , source : clean ( item . source , 100 ) , url : clean ( item . url , 500 ) || null , timestamp : item . timestamp || item . date || null } ) ) ;
} ) ,
tool ( 'search_memory' , 'Search persisted cross-sweep events. Arguments: query, limit.' , { query : 'string' , limit : 'number' } , async args => intelligenceStore ? . queryMemory ( { q : clean ( args . query , 120 ) , limit : bounded ( args . limit , 1 , 25 , 8 ) } ) || { available : false } ) ,
tool ( 'list_predictions' , 'List persisted predictions and their current outcome states. Arguments: state, limit.' , { state : 'string' , limit : 'number' } , async args => intelligenceStore ? . listPredictions ( { state : clean ( args . state , 30 ) || null , limit : bounded ( args . limit , 1 , 25 , 8 ) } ) || { available : false } ) ,
tool ( 'get_scenarios' , 'Inspect current scenario watchlist states and confidence.' , { } , async ( _args , runtime ) => {
const scenarios = dataFor ( runtime ) ? . scenarios || { } ;
return { summary : scenarios . summary || null , items : ( scenarios . items || scenarios . scenarios || [ ] ) . slice ( 0 , 20 ) , changed : ( scenarios . changed || [ ] ) . slice ( 0 , 10 ) } ;
} ) ,
tool ( 'get_trade_ideas' , 'Inspect current LLM-generated ideas. Optional argument: ticker.' , { ticker : 'string' } , async ( args , runtime ) => {
const ticker = clean ( args . ticker , 30 ) . toLowerCase ( ) ;
return ( dataFor ( runtime ) ? . ideas || [ ] ) . filter ( item => ! ticker || String ( item . ticker || '' ) . toLowerCase ( ) . includes ( ticker ) ) . slice ( 0 , 10 ) ;
} ) ,
tool ( 'trigger_sweep' , 'Start a new full intelligence sweep.' , { } , async ( _args , runtime ) => {
if ( ! runtime . confirmed ) throw new Error ( 'Operator confirmation required' ) ;
if ( isSweepInProgress ? . ( ) ) return { accepted : false , status : 'already_running' } ;
triggerSweep ? . ( ) ;
return { accepted : true , status : 'started' } ;
} , true ) ,
tool ( 'mute_alerts' , 'Mute proactive Telegram alerts for a bounded number of hours.' , { hours : 'number' } , async ( args , runtime ) => {
if ( ! runtime . confirmed ) throw new Error ( 'Operator confirmation required' ) ;
const hours = Math . max ( 0.25 , Math . min ( 24 , Number ( args . hours ) || 1 ) ) ;
telegramAlerter ? . muteAlerts ( hours ) ;
return { muted : true , hours } ;
} , true ) ,
tool ( 'unmute_alerts' , 'Resume proactive Telegram alerts.' , { } , async ( _args , runtime ) => {
if ( ! runtime . confirmed ) throw new Error ( 'Operator confirmation required' ) ;
telegramAlerter ? . unmuteAlerts ( ) ;
return { muted : false } ;
} , true ) ,
] ) ;
}
function tool ( name , description , parameters , handler , mutating = false ) {
return { name , description , parameters , handler , mutating } ;
}
function compactDelta ( delta ) {
return {
summary : delta ? . summary || null ,
new : ( delta ? . signals ? . new || [ ] ) . slice ( 0 , 15 ) ,
escalated : ( delta ? . signals ? . escalated || [ ] ) . slice ( 0 , 15 ) ,
deescalated : ( delta ? . signals ? . deescalated || [ ] ) . slice ( 0 , 15 ) ,
} ;
}
function compactMarkets ( data ) {
if ( ! data ) return { available : false } ;
const fred = Object . fromEntries ( ( data . fred || [ ] ) . filter ( item => [ 'VIXCLS' , 'DFF' , 'DGS10' , 'DGS2' , 'T10Y2Y' , 'BAMLH0A0HYM2' ] . includes ( item . id ) ) . map ( item => [ item . id , item . value ] ) ) ;
return { available : true , generatedAt : data . meta ? . generatedAt || data . meta ? . timestamp , fred , energy : data . energy || null , metals : data . metals || null , ideasSource : data . ideasSource , ideas : ( data . ideas || [ ] ) . slice ( 0 , 8 ) } ;
}
function clean ( value , maxLength ) {
return String ( value || '' ) . replace ( /[\u0000-\u001f]/g , ' ' ) . trim ( ) . slice ( 0 , maxLength ) ;
}
function bounded ( value , min , max , fallback ) {
const parsed = Number . parseInt ( value , 10 ) ;
return Number . isFinite ( parsed ) ? Math . max ( min , Math . min ( max , parsed ) ) : fallback ;
}