export class HunchError extends Error { constructor(message, { status, report } = {}) { super(message); this.name = 'HunchError'; this.status = status; this.report = report; } } export class HunchClient { constructor({ baseUrl = 'https://hunchagents.xyz', profile = 'conservative', timeoutMs = 22000 } = {}) { const url = new URL(baseUrl); if (url.protocol !== 'https:' && !(url.protocol === 'http:' && ['localhost','127.0.0.1'].includes(url.hostname))) throw new Error('Use HTTPS or a loopback development server.'); if (!['conservative','standard'].includes(profile)) throw new Error('Unknown Hunch policy profile.'); this.baseUrl = url; this.profile = profile; this.timeoutMs = timeoutMs; } async request(path, body) { let response; try { response = await fetch(new URL(path,this.baseUrl), { method:'POST', redirect:'error', headers:{'content-type':'application/json'}, body:JSON.stringify(body), signal:AbortSignal.timeout(this.timeoutMs) }); } catch { throw new HunchError('Hunch is unavailable. Stop and request review.'); } let result; try { result = await response.json(); } catch { throw new HunchError('Hunch returned an unreadable result. Stop and request review.', {status:response.status}); } if (!response.ok) throw new HunchError(result.error || 'Hunch could not complete the check.', {status:response.status}); return result; } inspectToken(address) { return this.request('/api/rh/intelligence',{address}); } getDecisionContext({address, tokens = '1', counterAsset, transaction}) { return this.request('/api/rh/context',{address,tokens,...(counterAsset===undefined?{}:{counterAsset}),...(transaction===undefined?{}:{transaction})}); } inspectInstrument(address, tokens = '1') { return this.request('/api/rh/instrument',{address,tokens}); } inspectText(text) { return this.request('/api/text',{text}); } assessAction({ address, amountUsd, slippageBps, text }) { return this.request('/api/rh/assess',{address,amountUsd,slippageBps,...(text !== undefined ? {text}:{}),profile:this.profile}); } simulateTransaction(transaction) { return this.request('/api/rh/simulate',{transaction}); } async requireWithinProfile(action) { const report = await this.assessAction(action); if (report.decision !== 'within_profile') throw new HunchError(`Action requires ${report.decision || 'review'}.`, {report}); return report; } }