@oracle-agent/oracle 0.32.0 → 0.33.0

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,23 @@
1
+ #!/usr/bin/env node
2
+ import{createInterface as Ae}from"node:readline";var A=Object.freeze({maxRequestBytes:256*1024,maxResponseBytes:2*1024*1024,maxTools:256,maxToolNameLength:64,maxArgumentBytes:128*1024,defaultCallTimeoutMs:3e4,maxCallTimeoutMs:6e4,maxConcurrentCalls:32}),Se=/^[A-Za-z0-9_-]{1,64}$/;function F(t,e){return{jsonrpc:"2.0",id:t??null,result:e}}function g(t,e,r){return{jsonrpc:"2.0",id:t??null,error:{code:e,message:r}}}function Ce(t){return!!(t&&typeof t=="object"&&!Array.isArray(t)&&t.jsonrpc==="2.0"&&typeof t.method=="string"&&t.method.length>0)}function Re(t){if(!Array.isArray(t))return[];let e=[],r=new Set;for(let n of t){if(e.length>=A.maxTools)break;if(!n||typeof n!="object"||Array.isArray(n))continue;let i=typeof n.name=="string"?n.name.trim():"";if(!Se.test(i)||r.has(i))continue;r.add(i);let s=n.inputSchema&&typeof n.inputSchema=="object"&&!Array.isArray(n.inputSchema)?{...n.inputSchema}:{type:"object",properties:{},additionalProperties:!1};s.type==="object"&&s.additionalProperties===void 0&&(s.additionalProperties=!1),e.push({...n,name:i,inputSchema:s})}return e}function _e(t){let e=Number(t)||A.defaultCallTimeoutMs;return Math.min(Math.max(e,1),A.maxCallTimeoutMs)}async function Oe(t,e,r){let n;try{return await Promise.race([t,new Promise((i,s)=>{n=setTimeout(()=>{let o=new Error("tool call timed out");o.code="ORACLE_MCP_TIMEOUT",s(o);try{r?.()}catch{}},e)})])}finally{clearTimeout(n)}}function Ee(t){return t===null?"null":Array.isArray(t)?"array":Number.isInteger(t)?"integer":typeof t}function U(t,e,r="arguments",n=0){if(!e||typeof e!="object"||Array.isArray(e))return null;if(n>12)return`${r} exceeded the nesting limit`;if(Array.isArray(e.oneOf)&&e.oneOf.length&&!e.oneOf.some(s=>U(t,s,r,n+1)===null))return`${r} did not match an allowed shape`;if(Array.isArray(e.anyOf)&&e.anyOf.length&&!e.anyOf.some(s=>U(t,s,r,n+1)===null))return`${r} did not match a required alternative`;if(Array.isArray(e.enum)&&!e.enum.some(i=>Object.is(i,t)))return`${r} must be one of the allowed values`;if(Object.hasOwn(e,"const")&&!Object.is(e.const,t))return`${r} must equal the required constant`;if(e.type){let i=Ee(t);if(!(e.type==="number"?typeof t=="number"&&Number.isFinite(t):e.type==="integer"?Number.isSafeInteger(t):i===e.type))return`${r} must be ${e.type}`}if(typeof t=="string"){let i=Math.min(Number.isSafeInteger(e.maxLength)?e.maxLength:16384,16384);if(t.length>i)return`${r} exceeded the string limit`;if(Number.isSafeInteger(e.minLength)&&t.length<e.minLength)return`${r} is too short`}if(Array.isArray(t)){let i=Math.min(Number.isSafeInteger(e.maxItems)?e.maxItems:1e3,1e3);if(t.length>i)return`${r} exceeded the array limit`;if(Number.isSafeInteger(e.minItems)&&t.length<e.minItems)return`${r} has too few items`;if(e.items)for(let s=0;s<t.length;s+=1){let o=U(t[s],e.items,`${r}[${s}]`,n+1);if(o)return o}}if(t&&typeof t=="object"&&!Array.isArray(t)){let i=Object.keys(t);if(i.length>256)return`${r} exceeded the property limit`;let s=e.properties&&typeof e.properties=="object"?e.properties:{};for(let o of Array.isArray(e.required)?e.required:[])if(!Object.hasOwn(t,o))return`${r}.${o} is required`;if(e.additionalProperties===!1){let o=i.find(l=>!Object.hasOwn(s,l));if(o)return`${r}.${o} is not allowed`}for(let o of i){if(!Object.hasOwn(s,o))continue;let l=U(t[o],s[o],`${r}.${o}`,n+1);if(l)return l}}return null}function Ie(t,e={}){let r=Re(t?.tools),n=new Set(r.map(u=>u.name)),i=new Map(r.map(u=>[u.name,u])),s=typeof t?.name=="string"&&t.name?t.name.slice(0,80):"oracle-mcp",o=typeof t?.version=="string"&&t.version?t.version.slice(0,40):"1",l=_e(e.callTimeoutMs),d=!1;return async function(f){let p=f?.id??null;if(!Ce(f))return g(p,-32600,"invalid request");if(f.method==="initialize")return d=!0,F(p,{protocolVersion:f.params?.protocolVersion??"2025-03-26",capabilities:{tools:{}},serverInfo:{name:s,version:o}});if(f.method==="notifications/initialized")return null;if(f.method==="ping")return F(p,{});if(!d)return g(p,-32002,"server not initialized");if(f.method==="tools/list")return F(p,{tools:r});if(f.method==="tools/call"){let w=f.params?.name,k=f.params?.arguments??{};if(typeof w!="string"||!n.has(w))return g(p,-32602,"unknown tool");if(!k||typeof k!="object"||Array.isArray(k))return g(p,-32602,"tool arguments must be an object");let O;try{O=JSON.stringify(k)}catch{return g(p,-32602,"tool arguments are not serializable")}if(Buffer.byteLength(O)>A.maxArgumentBytes)return g(p,-32602,"tool arguments exceeded the size limit");let M=U(k,i.get(w)?.inputSchema);if(M)return g(p,-32602,M);try{let x=new AbortController,E=await Oe(Promise.resolve(t.call(w,k,{signal:x.signal})),l,()=>x.abort(new Error("tool call timed out")));return F(p,E)}catch(x){if(x?.code==="ORACLE_MCP_TIMEOUT")return g(p,-32001,"tool call timed out");let E=typeof x?.message=="string"?x.message.replace(/\s+/g," ").trim():"",v=/\b(requires?|must be|missing|unknown|invalid|expected|unsupported|out of range|too (?:large|small|long|many)|not a|cannot convert)\b/i.test(E),q=/https?:\/\/|[/~][\w.-]+\/|0x[0-9a-fA-F]{8,}|[A-Za-z0-9+/_-]{24,}={0,2}|\b(?:secret|apikey|api[-_ ]key|private[-_ ]?key|token|password|credential|seed|mnemonic)s?\b/i.test(E.replace(/\btoken(?:In|Out|s\b)/g,"asset"));return v&&!q&&E.length<=200?g(p,-32e3,`tool call failed: ${E}`):g(p,-32e3,"tool call failed")}}return g(p,-32601,"method not found")}}function te(t,e={}){let r=e.input||process.stdin,n=e.output||process.stdout,i=Math.min(Math.max(Number(e.maxRequestBytes)||A.maxRequestBytes,64),A.maxRequestBytes),s=Math.min(Math.max(Number(e.maxResponseBytes)||A.maxResponseBytes,256),A.maxResponseBytes),o=Math.min(Math.max(Number(e.maxConcurrentCalls)||A.maxConcurrentCalls,1),A.maxConcurrentCalls),l=o*8,d=Ie(t,e),u={closed:!1,inflight:0},f=Ae({input:r,terminal:!1,crlfDelay:1/0}),p=0,w=[],k=!1,O=!1;function M(){if(u.closed||u.readerClosed)return;let y=u.inflight>=o||w.length>0||O;y&&!k?(k=!0,f.pause(),typeof r.pause=="function"&&r.pause()):!y&&k&&(k=!1,typeof r.resume=="function"&&r.resume(),f.resume())}function x(y){if(!y||u.closed)return;let $=JSON.stringify(y);Buffer.byteLength($)>s&&($=JSON.stringify(g(y.id,-32003,"response exceeded the size limit"))),n.write(`${$}
3
+ `)===!1&&!O&&(O=!0,M(),n.once("drain",()=>{O=!1,v()}))}function E(y){u.inflight+=1,M(),Promise.resolve(d(y)).then(x).catch(()=>x(g(y?.id,-32603,"internal error"))).finally(()=>{u.inflight-=1,v()})}function v(){for(;!u.closed&&!O&&u.inflight<o&&w.length>0;)E(w.shift());M()}function q(){u.closed||(x(g(null,-32700,"request exceeded the size limit")),u.closed=!0,f.close(),typeof r.destroy=="function"&&r.destroy())}return r.on("data",y=>{if(u.closed)return;let $=String(y).split(`
4
+ `);for(let j=0;j<$.length;j+=1){if(p+=Buffer.byteLength($[j]),p>i){q();return}j<$.length-1&&(p=0)}}),f.on("line",y=>{if(u.closed)return;if(Buffer.byteLength(y)>i){q();return}let $;try{$=JSON.parse(y)}catch{x(g(null,-32700,"parse error"));return}if(w.length>=l){x(g($?.id,-32e3,"server busy"));return}w.push($),v()}),f.on("close",()=>{u.readerClosed=!0,e.exitOnClose!==!1&&(process.exitCode=0)}),u}import{createHash as Je,randomBytes as Ye}from"node:crypto";import{mkdirSync as Xe,readFileSync as Ge,writeFileSync as Qe}from"node:fs";import{homedir as Ze}from"node:os";import{dirname as et,join as oe}from"node:path";var Ne={robinhood:{chainId:4663,name:"Robinhood Chain",rpcEnv:["RH_CHAIN_RPC"],evm:!0},ethereum:{chainId:1,name:"Ethereum",rpcEnv:["ETH_RPC_URL","ETHEREUM_RPC_URL","MAINNET_RPC_URL"],evm:!0},polygon:{chainId:137,name:"Polygon",rpcEnv:["POLYGON_RPC_URL","POLYGON_RPC"],evm:!0},arbitrum:{chainId:42161,name:"Arbitrum One",rpcEnv:["ARBITRUM_RPC_URL","ARB_RPC_URL"],evm:!0},base:{chainId:8453,name:"Base",rpcEnv:["BASE_RPC_URL"],evm:!0},hyperevm:{chainId:999,name:"HyperEVM",rpcEnv:["HYPEREVM_RPC_URL","HYPER_EVM_RPC"],evm:!0},bsc:{chainId:56,name:"BNB Smart Chain",rpcEnv:["BSC_RPC_URL","BNB_RPC_URL"],evm:!0},avalanche:{chainId:43114,name:"Avalanche C-Chain",rpcEnv:["AVALANCHE_RPC_URL","AVAX_RPC_URL"],evm:!0},optimism:{chainId:10,name:"OP Mainnet",rpcEnv:["OPTIMISM_RPC_URL","OP_RPC_URL"],evm:!0},abstract:{chainId:2741,name:"Abstract",rpcEnv:["ABSTRACT_RPC_URL","ABS_RPC_URL"],evm:!0},stable:{chainId:988,name:"Stable Mainnet",rpcEnv:["STABLE_RPC_URL","STABLE_RPC"],evm:!0}},Le=new Map(Object.values(Ne).map(t=>[t.chainId,t]));function re(t){return Le.get(Number(t))||null}var c="UNKNOWN",kt=Object.freeze(["token","launch","hip3","hip4","polymarket","twap","bridge","swap","approve"]),Te=/[_*[\]`]/g;function a(t){return m(t)?String(t).replace(Te,e=>`\\${e}`):c}function m(t){return t==null?!1:typeof t=="number"?Number.isFinite(t):typeof t=="string"?t.trim()!=="":!0}function S(t){if(!m(t))return c;let e=String(t).replace(/`/g,"");return e===""?c:`\`${e}\``}function L(t,{decimals:e=2}={}){if(!m(t))return c;let r=Number(t);return Number.isFinite(r)?r.toLocaleString("en-US",{minimumFractionDigits:0,maximumFractionDigits:e}):c}function h(t,{decimals:e=2}={}){let r=L(t,{decimals:e});return r===c?c:`${r} USD`}function W(t,{decimals:e=2}={}){let r=L(t,{decimals:e});return r===c?c:`${r}%`}function z(t){let e=L(t,{decimals:0});return e===c?c:`${e} bps`}function T(t,e){if(!m(t))return c;let r=Number(e);if(!Number.isInteger(r)||r<0||r>77)return c;let n;try{n=BigInt(typeof t=="string"?t.trim():t)}catch{return c}let i=n<0n,s=i?-n:n,o=10n**BigInt(r),l=(s/o).toString(),d=(s%o).toString().padStart(r,"0").replace(/0+$/,"");return`${i?"-":""}${l}${d?`.${d}`:""}`}function K(t){if(typeof t=="number"&&Number.isFinite(t))return t<0||t>1?c:t>=.75?"HIGH":t>=.4?"MEDIUM":"LOW";if(typeof t=="string"){let e=t.trim().toUpperCase();if(e==="HIGH"||e==="MEDIUM"||e==="LOW")return e}return c}function I(t={}){let e=t.chainId;if(!m(e)||!Number.isFinite(Number(e)))return m(t.chain)?a(t.chain):c;let n=re(e)?.name||(m(t.chain)?String(t.chain):c);return`${a(n)} (chainId ${Number(e)})`}function ne(t={}){return a(t.venue??t.dex??t.pool?.venue)}function Me(t){return t==null?"NONE (text card only)":typeof t=="string"?t.trim()?S(t):"NONE (text card only)":t.error||t.ok===!1||t.available===!1?`UNAVAILABLE${m(t.error)?` \u2014 ${a(t.error)}`:""} (text card stands)`:m(t.url)?S(t.url):"NONE (text card only)"}function D(t={},{now:e=Date.now()}={}){let r=t.grant??t.session??null;if(!r||typeof r!="object")return{allowed:!1,reason:"no local grant/session",actions:[]};if(r.local===!1)return{allowed:!1,reason:"grant is not local",actions:[]};if(r.revoked===!0)return{allowed:!1,reason:"grant revoked",actions:[]};let n=r.expiresAt??r.expiry;if(m(n)){let s=typeof n=="number"?n:Date.parse(n);if(!Number.isFinite(s))return{allowed:!1,reason:"grant expiry unreadable",actions:[]};if(s<=e)return{allowed:!1,reason:"grant expired",actions:[]}}return{allowed:!0,reason:"valid local grant",actions:Array.isArray(r.actions)&&r.actions.length?r.actions.slice():["BUY","SELL"]}}function Pe(t){let e=D(t);return e.allowed?`${e.actions.map(r=>a(r)).join(" / ")} (${a(e.reason)})`:`prepare-only \u2014 ${a(e.reason)}`}function C(t,e,r={}){let n=[`*${t}*`];for(let[i,s]of e)n.push(`${i}: ${s==null||s===""?c:s}`);return n.push(`Chart: ${Me(r.chart)}`),n.push(`Actions: ${Pe(r)}`),Array.isArray(r.warnings)&&r.warnings.length&&n.push(`Warnings: ${r.warnings.map(i=>a(i)).join("; ")}`),(m(r.source)||m(r.fetchedAt))&&n.push(`Source: ${a(r.source)} at ${a(r.fetchedAt)}`),n.join(`
5
+ `)}function R(t){return["Confidence",K(t.confidence)]}function Be(t){let e=t.quote;if(!e||typeof e!="object")return[];let r=m(e.decimals)?T(e.amountOutRaw??e.out??e.raw,e.decimals):c;return[["Quote out (raw)",S(e.amountOutRaw??e.out??e.raw)],["Quote out",r===c?c:`${a(r)} ${a(e.symbol??"")}`.trim()]]}function ie(t){let e=t.autoSlippage;if(!e||typeof e!="object")return["Auto-slippage",c];let r=z(e.selectedBps),n=z(e.capBps);return["Auto-slippage",r===c&&n===c?c:`${r} selected, cap ${n}`]}function ve(t={}){let e=t||{};return C(`ORACLE TOKEN \u2014 ${a(e.symbol??e.token??e.name)}`,[["Chain",I(e)],["Venue",ne(e)],["Name",a(e.name)],["Address",S(e.address??e.mint??e.contract)],["Price",h(e.priceUsd,{decimals:8})],["Market cap",h(e.marketCapUsd)],["Liquidity",h(e.liquidityUsd)],["Volume 24h",h(e.volume24hUsd)],["Change 24h",W(e.priceChange24h)],["Fee tier",m(e.feeTier)?`${z(Number(e.feeTier)/100)} (${L(e.feeTier,{decimals:0})})`:c],["Age",a(e.age)],...Be(e),ie(e),R(e)],e)}function je(t={}){let e=t||{};return C(`ORACLE LAUNCH \u2014 ${a(e.symbol??e.token??e.name)}`,[["Chain",I(e)],["Venue",ne(e)],["Address",S(e.address??e.mint??e.contract)],["Pool",S(e.pool?.address??e.poolAddress??e.pool)],["Liquidity",h(e.liquidityUsd)],["Route ready",a(e.routeReady)],["Sellable",a(e.sellable)],["Sell sim",a(e.sellSimulation??e.sellSim)],["Smart wallets",a(e.smartWalletOverlap)],["Risk",a(e.risk??e.riskStatus)],["Prepared ticket",a(e.preparedTicket??e.ticketStatus)],ie(e),R(e)],e)}function Ue(t={}){let e=t||{};return C(`ORACLE HIP-3 \u2014 ${a(e.market??e.coin??e.name)}`,[["Venue",`Hyperliquid builder-dex ${a(e.dex)}`],["Market",a(e.market??e.coin)],["Mark",h(e.markPx,{decimals:6})],["Oracle",h(e.oraclePx,{decimals:6})],["Funding",W(e.funding,{decimals:6})],["Open interest",h(e.openInterestUsd)],["Depth",a(e.depth)],["Liquidation notes",a(e.liquidationNotes??e.riskNotes)],["Account context",a(e.accountContext)],R(e)],e)}function De(t={}){let e=t||{};return C(`ORACLE HIP-4 \u2014 ${a(e.event??e.market??e.name)}`,[["Venue",`Hyperliquid HIP-4 ${a(e.dex??"outcome")}`],["Event",a(e.event)],["Outcome",a(e.outcome)],["Market id",S(e.marketId??e.market)],["Bid",h(e.bid,{decimals:6})],["Ask",h(e.ask,{decimals:6})],["Depth",a(e.depth)],["Edge",W(e.edge)],["Position",a(e.position)],R(e)],e)}function He(t={}){let e=t||{};return C(`ORACLE POLYMARKET \u2014 ${a(e.event??e.market??e.name)}`,[["Venue","Polymarket CLOB"],["Event",a(e.event)],["Market",a(e.market)],["Market id",S(e.marketId??e.conditionId??e.tokenId)],["Yes",h(e.yesPrice,{decimals:4})],["No",h(e.noPrice,{decimals:4})],["Best bid / ask",`${h(e.bestBid,{decimals:4})} / ${h(e.bestAsk,{decimals:4})}`],["Volume",h(e.volumeUsd)],["Resolution risk",a(e.resolutionRisk)],["Order intent",a(e.orderIntent)],R(e)],e)}function qe(t={}){let e=t||{},r=m(e.completedSplits)&&m(e.totalSplits)?`${L(e.completedSplits,{decimals:0})} / ${L(e.totalSplits,{decimals:0})}`:c;return C(`ORACLE TWAP \u2014 ${a(e.pair??e.symbol??e.name)}`,[["Chain",I(e)],["Side",a(e.side??e.direction)],["Amount",`${a(T(e.amountTotal??e.amount,e.decimals??18))} ${a(e.symbol??"")}`.trim()],["Splits",`${L(e.totalSplits,{decimals:0})} over ${a(e.window)}`],["Progress",r],["Avg price",h(e.averagePrice,{decimals:6})],["Next split",a(e.nextSplitAt)],["Slippage cap",z(e.slippageBps)],["Status",a(e.status)],R(e)],e)}function Fe(t={}){let e=t||{},r=e.approval??e.revokeCheck??{},n=r.needsRevoke&&r.spender?`revoke.cash \u2014 ${a(r.spender)}`:r.needsRevoke===!1?"revoke.cash \u2014 clean":"revoke.cash \u2014 unchecked";return C(`ORACLE BRIDGE \u2014 ${a(e.pair??e.fromSymbol)} \u2192 ${a(e.toSymbol??"")}`.replace(/→ $/,""),[["Bridging","deBridge \xB7 LI.FI \u2014 best route wins"],["From chain",I({chainId:e.fromChainId,chain:e.fromChain})],["To chain",I({chainId:e.toChainId,chain:e.toChain})],["Amount",`${a(T(e.amount,e.fromDecimals??18))} ${a(e.fromSymbol??"")}`.trim()],["Best route",a(e.bestRoute??e.winner)],["Est. received",`${a(T(e.amountOut,e.toDecimals??18))} ${a(e.toSymbol??"")}`.trim()],["Fee",h(e.feeUsd)],["Est. time",a(e.estimatedTime)],["Revoke check",n],["All providers",a(e.providers?.join(", "))],["Preparable",a(e.preparable)],R(e)],e)}function ze(t){let r=(Array.isArray(t)?t:[]).slice(1,4).map(n=>{let i=a(n.source??n.venue??n.name),s=n.improvementBps==null&&n.deltaBps==null?null:Number(n.improvementBps??n.deltaBps),o=Number.isFinite(s)?`${Math.abs(s).toFixed(0)} bps behind`:"spread UNKNOWN";return`${i} (${o})`});return r.length?r.join("; "):c}function Ve(t){let e=t.rankedOn??t.swap?.rankedOn??t.best?.rankedOn;return m(e)?a(e):c}function We(t={}){let e=t||{},r=e.swap&&typeof e.swap=="object"?e.swap:e,n=e.bridge&&typeof e.bridge=="object"?e.bridge:null,i=r.best??r.winner??{},s=`${a(e.tokenInSymbol??e.fromSymbol??"IN")} \u2192 ${a(e.tokenOutSymbol??e.toSymbol??"OUT")}`,o=[["Intent",a(e.intent??"swap")],["Chain",I({chainId:e.chainId??r.chainId,chain:e.chain??r.chain})],["Pair",s],["Amount in",`${a(T(e.amountIn??r.amountIn,e.decimalsIn??18))} ${a(e.tokenInSymbol??"")}`.trim()],["Best swap",a(i.source??i.venue??r.bestRoute??e.bestRoute)],["Net out",`${a(T(i.netOut??i.amountOut??r.amountOut,e.decimalsOut??18))} ${a(e.tokenOutSymbol??"")}`.trim()],["Ranked on",Ve(r)],["Gas accounted",a(i.costAccounted===!0?"yes":i.costAccounted===!1?"no \u2014 gross ranking may flatter this route":null)],["Spread vs next",m(r.improvementBps)?`${a(r.improvementBps)} bps`:c],["Runners-up",ze(r.routes??e.routes)]];if(n){let l=n.best??n.winner??{};o.push(["Best bridge",a(l.source??n.bestRoute??e.bestBridge)],["Bridge out",`${a(T(l.netOut??l.amountOut??n.amountOut,e.bridgeDecimalsOut??e.decimalsOut??18))} ${a(e.bridgeOutSymbol??e.tokenOutSymbol??"")}`.trim()],["Bridge to",I({chainId:n.toChainId??e.toChainId,chain:n.toChain??e.toChain})],["Est. time",a(n.estimatedTime??l.meta?.durationSeconds)])}else o.push(["Best bridge","same-chain \u2014 use Best swap"]);return o.push(["Preparable",a(e.preparable??i.executionReady)],R(e)),C(`ORACLE SWAP \u2014 ${s}`,o,e)}function Ke(t={}){let e=t||{};return C("ORACLE APPROVE \u2014 local signer",[["Pending id",S(e.id??(typeof e.digest=="string"?e.digest.slice(0,8):null))],["Surface",a(e.surface)],["Action",a(e.action)],["Chain",I({chainId:e.chain??e.chainId,chain:e.chainName})],["To",S(e.to??e.destination)],["Value",m(e.value)?a(e.value):c],["Signer",a(e.armed===!0?"running + armed":e.armed===!1?"running, disarmed":"not running")],R({confidence:e.confidence??(e.armed===!0?"high":"low")})],e)}var $t=Object.freeze({token:ve,launch:je,hip3:Ue,hip4:De,polymarket:He,twap:qe,bridge:Fe,swap:We,approve:Ke});var tt=Object.freeze(["deepen","refresh","prepare"]),rt=new Set(tt),Y=/^[a-z0-9-]{4,40}$/i,ae=/^[0-9a-f]{32}$/,se=/^\d+$/;function X(t=process.env){return oe(t.ORACLE_CONFIG_DIR||oe(Ze(),".config","oracle"),"telegram-cards.json")}function P(){return{links:{},artifacts:{},threads:{}}}var H=P();function G(){return H}function ce(t,{readFile:e=Ge}={}){try{let r=JSON.parse(String(e(t)));H={links:r.links&&typeof r.links=="object"?r.links:{},artifacts:r.artifacts&&typeof r.artifacts=="object"?r.artifacts:{},threads:r.threads&&typeof r.threads=="object"?r.threads:{}}}catch{H=P()}return H}function le(t,e=H,{writeFile:r=Qe,mkdir:n=Xe}={}){n(et(t),{recursive:!0,mode:448}),r(t,JSON.stringify(e),{mode:384})}function N(t){return t==null?!1:typeof t=="string"?t.trim()!=="":!0}function ue(t){return Je("sha256").update(String(t)).digest("hex")}function J(t){if(Array.isArray(t))return t.map(J);if(!t||typeof t!="object")return t;let e={};for(let[r,n]of Object.entries(t))/(secret|token|key|seed|private|password|mnemonic|auth)/i.test(r)||(e[r]=J(n));return e}function nt(t){let r=String(t||"").trim().match(/^oracle:card:(deepen|refresh|prepare):([a-z0-9-]{4,40})$/i);return r?{action:r[1].toLowerCase(),artifactId:r[2].toLowerCase()}:null}function de({platform:t="telegram",artifactId:e,openUrl:r,hasGrant:n=!1}={}){let i=String(e||"").trim().toLowerCase();if(!Y.test(i))return{kind:"text_menu",text:"no artifact to continue",cancelHint:""};let s=[];N(r)&&s.push({text:"Open",url:String(r)});let o=[{text:"Deepen",callback_data:`oracle:card:deepen:${i}`},{text:"Refresh",callback_data:`oracle:card:refresh:${i}`}];if(n&&o.push({text:"Prepare",callback_data:`oracle:card:prepare:${i}`}),String(t)==="telegram")return{kind:"inline_keyboard",replyMarkup:{inline_keyboard:[s,o].filter(u=>u.length>0)},cancelHint:n?"Prepare queues an unsigned artifact. Allow/Deny still required to sign.":"prepare-only \u2014 Deepen and Refresh stay read-only."};let l=[],d=0;for(let u of[...s,...o])d+=1,l.push(u.url?`${d}. ${u.text}: ${u.url}`:`${d}. ${u.text} (reply ${d})`);return{kind:"text_menu",text:l.join(`
6
+ `),cancelHint:""}}function fe(t={}){let r=[`*${N(t.title)?a(t.title):"Oracle artifact"}*`,`Kind: ${N(t.kind)?a(t.kind):c}`,`Id: ${N(t.id)?`\`${String(t.id).replace(/`/g,"")}\``:c}`,`Summary: ${N(t.summary)?a(t.summary):c}`,`Confidence: ${K(t.confidence)}`];(N(t.source)||N(t.fetchedAt))&&r.push(`Source: ${a(t.source)} at ${a(t.fetchedAt)}`),Array.isArray(t.warnings)&&t.warnings.length&&r.push(`Warnings: ${t.warnings.map(i=>a(i)).join("; ")}`);let n=D(t);return r.push(n.allowed?"Actions: Deepen / Refresh / Prepare (unsigned)":`Actions: Deepen / Refresh \u2014 ${a(n.reason)}`),r.join(`
7
+ `)}function it(t,e={},{now:r=Date.now()}={}){let n=t||P(),i=String(e.id||"").trim().toLowerCase();if(!Y.test(i))throw new TypeError("artifact id required");let s={id:i,kind:String(e.kind||"thesis"),title:String(e.title||"Oracle artifact"),summary:String(e.summary||""),openUrl:N(e.openUrl)?String(e.openUrl):null,confidence:e.confidence,source:e.source||"oracle",fetchedAt:e.fetchedAt||new Date(r).toISOString(),warnings:Array.isArray(e.warnings)?e.warnings.map(String):[],payload:J(e.payload||{}),createdAt:new Date(r).toISOString()};return n.artifacts[i]=s,s}function Q(t,{chatId:e,artifactId:r,now:n=Date.now()}={}){let i=t||P(),s=String(e||"").trim(),o=String(r||"").trim().toLowerCase();if(!s)throw new TypeError("chat id required");if(!Y.test(o))throw new TypeError("artifact id required");return i.threads[s]={artifactId:o,updatedAt:n},i.threads[s]}function pe(t,{chatId:e,text:r}={}){let n=String(e||"").trim(),i=String(r||"").trim();if(!n||!i||/^\//.test(i))return null;let s=t?.threads?.[n];if(!s?.artifactId)return null;let o=t.artifacts?.[s.artifactId];return o?`Continue artifact ${o.id} (${o.kind}). Prior: ${o.summary||o.title}. User: ${i}`:null}function me(t,{ownerId:e,botUsername:r,now:n=Date.now(),ttlMs:i=600*1e3,token:s,randomBytes:o=Ye}={}){let l=t||P(),d=String(e||"").trim(),u=String(r||"").replace(/^@/,"").trim();if(!se.test(d))throw new TypeError("owner Telegram id required");if(!/^[A-Za-z0-9_]{5,32}$/.test(u))throw new TypeError("bot username required");let f=s||o(16).toString("hex");if(!ae.test(f))throw new TypeError("link token must be 32 hex chars");return l.links[ue(f)]={ownerId:d,expiresAt:n+Number(i)},{token:f,url:`https://t.me/${u}?start=${f}`,expiresAt:n+Number(i)}}function he(t,{token:e,telegramUserId:r,now:n=Date.now()}={}){let i=t||P(),s=String(e||"").trim(),o=String(r||"").trim();if(!ae.test(s))return{ok:!1,error:"invalid start token"};if(!se.test(o))return{ok:!1,error:"invalid telegram user"};let l=ue(s),d=i.links[l];return d?(delete i.links[l],Number(d.expiresAt)<=n?{ok:!1,error:"start token expired"}:String(d.ownerId)!==o?{ok:!1,error:"start token is bound to a different owner"}:{ok:!0,ownerId:o}):{ok:!1,error:"unknown or already used start token"}}function ge(t,{data:e,chatId:r,grant:n=null,now:i=Date.now()}={}){let s=nt(e);if(!s)return null;if(!rt.has(s.action))return{text:"That card action is not available.",buttons:null};let o=t?.artifacts?.[s.artifactId];if(!o)return{text:"That artifact is gone. Ask again and I will issue a new card.",buttons:null};r&&Q(t,{chatId:r,artifactId:o.id,now:i});let l=D({grant:n},{now:i}),d=de({artifactId:o.id,openUrl:o.openUrl,hasGrant:l.allowed});return s.action==="refresh"?{text:fe(o),buttons:d,prompt:null}:s.action==="deepen"?{text:null,buttons:null,prompt:`Deepen artifact ${o.id} (${o.kind}). Prior: ${o.summary||o.title}. Be terse. Do not sign or broadcast.`}:l.allowed?{text:`Queued unsigned prepare for ${o.id}. Nothing signed. Allow/Deny still required.`,buttons:d,prompt:null,prepare:{artifactId:o.id,unsigned:!0,broadcast:!1}}:{text:`Prepare blocked \u2014 ${l.reason}. Deepen and Refresh still work.`,buttons:d,prompt:null}}function ye(t={},{grant:e=null,now:r=Date.now(),state:n}={}){let i=n||G(),s=String(t.id||`art-${Math.abs(Number(r)).toString(36)}`).toLowerCase().slice(0,40),o=it(i,{...t,id:s},{now:r}),l=D({grant:e},{now:r});return{text:fe({...o,grant:e}),replyMarkup:de({artifactId:o.id,openUrl:o.openUrl,hasGrant:l.allowed}).replyMarkup,artifact:o,state:i}}var be=`oracle telegram \u2014 TrueNorth-style interactive cards (native, no Hermes)
8
+
9
+ oracle telegram link --owner <tg-id> --bot <username>
10
+ oracle telegram redeem --token <32hex> --user <tg-id>
11
+ oracle telegram wrap --id <id> --title <t> --summary <s> [--kind thesis] [--grant]
12
+ oracle telegram callback --data oracle:card:<action>:<id> --chat <tg-id> [--grant]
13
+ oracle telegram continue --chat <tg-id> --text <message>
14
+
15
+ Native oracle-gateway uses the same module. Hermes is an optional adapter that
16
+ must call this CLI instead of owning card state. Prepare is unsigned. Execute
17
+ stays on Allow/Deny.`;function b(t,e){let r=t.indexOf(e);return r<0||r+1>=t.length?null:t[r+1]}function xe(t,e){return t.includes(e)}function ot(){return ce(X()),G()}function V(t){le(X(),t)}function B(t,e){t.write(JSON.stringify(e)+`
18
+ `)}async function ke(t=[],e={}){let r=e.out??process.stdout,n=e.err??process.stderr,i=t[0];if(!i||i==="--help"||i==="-h"||i==="help")return r.write(be+`
19
+ `),0;let s=ot();if(i==="link")try{let o=me(s,{ownerId:b(t,"--owner"),botUsername:b(t,"--bot")});return V(s),B(r,{ok:!0,...o}),0}catch(o){return n.write(String(o.message||o)+`
20
+ `),1}if(i==="redeem"){let o=he(s,{token:b(t,"--token"),telegramUserId:b(t,"--user")});return V(s),B(r,o),o.ok?0:1}if(i==="wrap")try{let o=ye({id:b(t,"--id"),kind:b(t,"--kind")||"thesis",title:b(t,"--title")||"Oracle artifact",summary:b(t,"--summary")||"",openUrl:b(t,"--url"),source:"oracle-telegram"},{grant:xe(t,"--grant")?{local:!0}:null,state:s}),l=b(t,"--chat");return l&&Q(s,{chatId:l,artifactId:o.artifact.id}),V(s),B(r,{ok:!0,text:o.text,replyMarkup:o.replyMarkup||null,artifactId:o.artifact.id,fallback:`Reply: deepen ${o.artifact.id} | refresh ${o.artifact.id}`}),0}catch(o){return n.write(String(o.message||o)+`
21
+ `),1}if(i==="callback"){let o=ge(s,{data:b(t,"--data"),chatId:b(t,"--chat"),grant:xe(t,"--grant")?{local:!0}:null});return V(s),o?(B(r,{ok:!0,...o}),0):(B(r,{ok:!1,error:"not an interactive card callback"}),1)}if(i==="continue"){let o=pe(s,{chatId:b(t,"--chat"),text:b(t,"--text")});return B(r,{ok:!0,prompt:o}),0}return n.write(`unknown telegram verb '${i}'
22
+ ${be}
23
+ `),1}var at=40,st=200,ct=4e3,lt=4e3,ut=128,$e=/^[a-z0-9][a-z0-9-]{3,39}$/i,Z=/^\d{1,20}$/,dt=/^oracle:card:(deepen|refresh|prepare):[a-z0-9][a-z0-9-]{3,39}$/i;function ft(t=process.env){return t.ORACLE_TELEGRAM_CARD_GRANT==="1"?{local:!0}:null}function _(t,{field:e,max:r,pattern:n}){if(typeof t!="string")throw new Error(`${e} must be a string`);let i=t.trim();if(!i)throw new Error(`${e} is required`);if(i.length>r)throw new Error(`${e} exceeds ${r} chars`);if(n&&!n.test(i))throw new Error(`${e} is malformed`);return i}function pt(){let t="",e="";return{io:{out:{write(r){return t+=String(r),!0}},err:{write(r){return e+=String(r),!0}}},stdout(){return t},stderr(){return e}}}async function ee(t){let e=pt(),r=await ke(t,e.io),n;try{n=JSON.parse(e.stdout()||"{}")}catch{n={text:e.stdout()}}return r!==0&&!n.error&&(n.error=e.stderr()||"telegram command failed"),{content:[{type:"text",text:JSON.stringify({code:r,...n})}]}}function we(t){return{isError:!0,content:[{type:"text",text:JSON.stringify({error:t})}]}}var mt=[{name:"telegram_wrap",description:"Wrap a scan/quote/thesis as a TrueNorth-style Oracle artifact card. Prepare stays unsigned. No Execute button.",inputSchema:{type:"object",required:["id","title","summary"],properties:{id:{type:"string",description:"artifact id, [a-z0-9-]{4,40}"},title:{type:"string"},summary:{type:"string"},kind:{type:"string"},chat:{type:"string",description:"Telegram chat id, digits only"}}}},{name:"telegram_callback",description:"Handle deepen/refresh/prepare on an Oracle artifact card. Prepare is unsigned. Execute stays on Allow/Deny.",inputSchema:{type:"object",required:["data","chat"],properties:{data:{type:"string",description:"oracle:card:<action>:<id>"},chat:{type:"string"}}}},{name:"telegram_continue",description:"Continue the last artifact thread for this Telegram chat.",inputSchema:{type:"object",required:["chat","text"],properties:{chat:{type:"string"},text:{type:"string"}}}}],ht={name:"oracle-telegram",version:"2",tools:mt,async call(t,e={},{env:r=process.env}={}){let n=ft(r);try{if(t==="telegram_wrap"){let i=["wrap","--id",_(e.id,{field:"id",max:at,pattern:$e}),"--title",_(e.title,{field:"title",max:st}),"--summary",_(e.summary,{field:"summary",max:ct})];return e.kind!==void 0&&i.push("--kind",_(e.kind,{field:"kind",max:40,pattern:$e})),e.chat!==void 0&&i.push("--chat",_(e.chat,{field:"chat",max:20,pattern:Z})),n&&i.push("--grant"),await ee(i)}if(t==="telegram_callback"){let i=["callback","--data",_(e.data,{field:"data",max:ut,pattern:dt}),"--chat",_(e.chat,{field:"chat",max:20,pattern:Z})];return n&&i.push("--grant"),await ee(i)}if(t==="telegram_continue")return await ee(["continue","--chat",_(e.chat,{field:"chat",max:20,pattern:Z}),"--text",_(e.text,{field:"text",max:lt})])}catch(i){return we(i.message)}return we("unknown tool")}};process.argv[1]&&process.argv[1].endsWith("oracle-telegram-mcp.mjs")&&te(ht);export{ft as grantFromEnv,ht as server};
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{realpathSync as T}from"node:fs";import{fileURLToPath as oe}from"node:url";import h from"node:fs";import g from"node:path";import{pathToFileURL as z}from"node:url";import d from"node:fs";import P from"node:os";import i from"node:path";import{fileURLToPath as $}from"node:url";var M=i.dirname($(import.meta.url)),l=i.resolve(M,"../..");function u(){return process.env.ORACLE_FAKE_HOME||P.homedir()}function R(){return process.env.ORACLE_PUBLIC_DESKTOP==="1"}function f(){return R()?process.env.ORACLE_CONFIG_DIR||i.join(u(),".config","oracle"):i.join(u(),".config","oracle")}function I(){return i.join(f(),"exec.env")}function k(){return i.join(f(),"desk.json")}function v(){return i.join(f(),"env")}function p({force:e=!1}={}){if(p._done&&!e)return p._result||null;p._done=!0;let o={},n=(c,t)=>{if(t==null)return;let r=String(t).trim();r&&(process.env[c]!=null&&String(process.env[c]).trim()!==""||(process.env[c]=r,o[c]=r))};try{let c=v();if(d.existsSync(c))for(let t of d.readFileSync(c,"utf8").split(/\r?\n/)){let r=t.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*?)\s*$/);if(!r||r[2].startsWith("#"))continue;let a=r[2];(a.startsWith('"')&&a.endsWith('"')||a.startsWith("'")&&a.endsWith("'"))&&(a=a.slice(1,-1)),n(r[1],a)}}catch{}try{let c=k();if(d.existsSync(c)){let t=JSON.parse(d.readFileSync(c,"utf8"));t&&typeof t=="object"&&(n("ORACLE_DESK_URL",t.deskUrl||t.dataUrl||t.url),n("ORACLE_DATA_URL",t.dataUrl||t.deskUrl||t.url),n("ORACLE_API_URL",t.apiUrl||t.dataUrl||t.deskUrl),n("ORACLE_PUBLIC_URL",t.publicUrl||t.deskUrl||t.dataUrl),n("ORACLE_EXEC_URL",t.execUrl),n("MAD_DESK_URL",t.deskUrl||t.dataUrl))}}catch{}let s=process.env.ORACLE_DESK_URL||process.env.ORACLE_DATA_URL||"";return s&&(n("ORACLE_DESK_URL",s),n("ORACLE_DATA_URL",s),n("ORACLE_API_URL",s),n("ORACLE_PUBLIC_URL",s),n("MAD_DESK_URL",s)),p._result=Object.keys(o).length?o:null,p._result}try{p()}catch{}function H(){return process.env.HERMES_HOME?i.resolve(process.env.HERMES_HOME):i.join(u(),".hermes")}function N(){return i.join(u(),".claude.json")}function F(e=process.cwd()){return i.join(e,".mcp.json")}function q(){return process.platform==="darwin"?i.join(u(),"Library","Application Support","Claude","claude_desktop_config.json"):i.join(u(),".config","Claude","claude_desktop_config.json")}function K(){return i.join(u(),".codex","config.toml")}function C(){return i.join(f(),"connectors")}function B(){return i.join(C(),"chatgpt-openapi.json")}function G(){return i.join(f(),"active-chain.json")}function y(e){let o=[i.join(l,"bin",e),i.join(l,"dist","bin",e),i.join(l,"..","bin",e)];return o.find(n=>d.existsSync(n))||o[0]}function V(e){return d.mkdirSync(e,{recursive:!0}),e}var j={homeDir:u,isPublicDesktop:R,oracleConfigDir:f,oracleExecEnvPath:I,oracleDeskJsonPath:k,oracleEnvFilePath:v,loadDeskRouting:p,hermesRoot:H,activeChainPath:G,claudeCodeUserConfigPath:N,claudeCodeProjectMcpPath:F,claudeDesktopConfigPath:q,codexConfigPath:K,chatgptConnectorDir:C,chatgptOpenApiPath:B,packageBin:y,ensureDir:V,PACKAGE_ROOT:l};import{execFile as J}from"node:child_process";import{existsSync as me,mkdirSync as he,readFileSync as W,realpathSync as ge,writeFileSync as ye}from"node:fs";import w from"node:path";import{promisify as Y}from"node:util";var Ae=Y(J);var _e=1440*60*1e3;function L(e,o){let n=t=>String(t).replace(/^v/,"").split("-")[0].split(".").map(r=>Number.parseInt(r,10)||0),s=n(e),c=n(o);for(let t=0;t<Math.max(s.length,c.length);t+=1){let r=s[t]??0,a=c[t]??0;if(r>a)return 1;if(r<a)return-1}return 0}function X(e){let o=e?.stateDir||w.join(process.env.HOME||".",".oracle");return w.join(o,"update-check.json")}function O(e){try{return JSON.parse(W(X(e),"utf8"))}catch{return null}}var Q="\u25C7 ORACLE // self-custody multichain agent control plane",Z=`START
2
+ import{realpathSync as T}from"node:fs";import{fileURLToPath as oe}from"node:url";import h from"node:fs";import g from"node:path";import{pathToFileURL as z}from"node:url";import d from"node:fs";import P from"node:os";import i from"node:path";import{fileURLToPath as $}from"node:url";var M=i.dirname($(import.meta.url)),l=i.resolve(M,"../..");function u(){return process.env.ORACLE_FAKE_HOME||P.homedir()}function v(){return process.env.ORACLE_PUBLIC_DESKTOP==="1"}function f(){return v()?process.env.ORACLE_CONFIG_DIR||i.join(u(),".config","oracle"):i.join(u(),".config","oracle")}function I(){return i.join(f(),"exec.env")}function R(){return i.join(f(),"desk.json")}function k(){return i.join(f(),"env")}function p({force:e=!1}={}){if(p._done&&!e)return p._result||null;p._done=!0;let o={},n=(c,t)=>{if(t==null)return;let r=String(t).trim();r&&(process.env[c]!=null&&String(process.env[c]).trim()!==""||(process.env[c]=r,o[c]=r))};try{let c=k();if(d.existsSync(c))for(let t of d.readFileSync(c,"utf8").split(/\r?\n/)){let r=t.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*?)\s*$/);if(!r||r[2].startsWith("#"))continue;let a=r[2];(a.startsWith('"')&&a.endsWith('"')||a.startsWith("'")&&a.endsWith("'"))&&(a=a.slice(1,-1)),n(r[1],a)}}catch{}try{let c=R();if(d.existsSync(c)){let t=JSON.parse(d.readFileSync(c,"utf8"));t&&typeof t=="object"&&(n("ORACLE_DESK_URL",t.deskUrl||t.dataUrl||t.url),n("ORACLE_DATA_URL",t.dataUrl||t.deskUrl||t.url),n("ORACLE_API_URL",t.apiUrl||t.dataUrl||t.deskUrl),n("ORACLE_PUBLIC_URL",t.publicUrl||t.deskUrl||t.dataUrl),n("ORACLE_EXEC_URL",t.execUrl),n("MAD_DESK_URL",t.deskUrl||t.dataUrl))}}catch{}let s=process.env.ORACLE_DESK_URL||process.env.ORACLE_DATA_URL||"";return s&&(n("ORACLE_DESK_URL",s),n("ORACLE_DATA_URL",s),n("ORACLE_API_URL",s),n("ORACLE_PUBLIC_URL",s),n("MAD_DESK_URL",s)),p._result=Object.keys(o).length?o:null,p._result}try{p()}catch{}function H(){return process.env.HERMES_HOME?i.resolve(process.env.HERMES_HOME):i.join(u(),".hermes")}function N(){return i.join(u(),".claude.json")}function F(e=process.cwd()){return i.join(e,".mcp.json")}function q(){return process.platform==="darwin"?i.join(u(),"Library","Application Support","Claude","claude_desktop_config.json"):i.join(u(),".config","Claude","claude_desktop_config.json")}function K(){return i.join(u(),".codex","config.toml")}function C(){return i.join(f(),"connectors")}function B(){return i.join(C(),"chatgpt-openapi.json")}function G(){return i.join(f(),"active-chain.json")}function y(e){let o=[i.join(l,"bin",e),i.join(l,"dist","bin",e),i.join(l,"..","bin",e)];return o.find(n=>d.existsSync(n))||o[0]}function V(e){return d.mkdirSync(e,{recursive:!0}),e}var j={homeDir:u,isPublicDesktop:v,oracleConfigDir:f,oracleExecEnvPath:I,oracleDeskJsonPath:R,oracleEnvFilePath:k,loadDeskRouting:p,hermesRoot:H,activeChainPath:G,claudeCodeUserConfigPath:N,claudeCodeProjectMcpPath:F,claudeDesktopConfigPath:q,codexConfigPath:K,chatgptConnectorDir:C,chatgptOpenApiPath:B,packageBin:y,ensureDir:V,PACKAGE_ROOT:l};import{execFile as J}from"node:child_process";import{existsSync as me,mkdirSync as he,readFileSync as W,realpathSync as ge,writeFileSync as ye}from"node:fs";import w from"node:path";import{promisify as Y}from"node:util";var Ae=Y(J);var _e=1440*60*1e3;function L(e,o){let n=t=>String(t).replace(/^v/,"").split("-")[0].split(".").map(r=>Number.parseInt(r,10)||0),s=n(e),c=n(o);for(let t=0;t<Math.max(s.length,c.length);t+=1){let r=s[t]??0,a=c[t]??0;if(r>a)return 1;if(r<a)return-1}return 0}function X(e){let o=e?.stateDir||w.join(process.env.HOME||".",".oracle");return w.join(o,"update-check.json")}function O(e){try{return JSON.parse(W(X(e),"utf8"))}catch{return null}}var Q="\u25C7 ORACLE // self-custody multichain agent control plane",Z=`START
3
3
  oracle open the native Oracle chat (TTY)
4
4
  oracle chat open chat explicitly
5
5
  oracle setup connect a model and optional messaging
@@ -36,6 +36,7 @@ SYSTEM
36
36
  oracle init optional Hermes lane install (dry-run by default)
37
37
  oracle bootstrap optional Hermes installation
38
38
  oracle public serve secret-free public HTTP surface
39
+ oracle telegram native interactive Telegram cards (no Hermes)
39
40
  oracle fees status \xB7 check
40
41
  oracle eval desk \xB7 fidelity \xB7 hybrid \xB7 guards \xB7 contracts \xB7 all
41
42
  oracle upgrade update installed agent lanes
@@ -1,16 +1,16 @@
1
- import T from"node:fs";import F from"node:path";import j from"node:fs";import pe from"node:os";import O from"node:path";import{fileURLToPath as le}from"node:url";var fe=O.dirname(le(import.meta.url)),Ve=O.resolve(fe,"../..");function X(){return process.env.ORACLE_FAKE_HOME||pe.homedir()}function he(){return process.env.ORACLE_PUBLIC_DESKTOP==="1"}function b(){return he()?process.env.ORACLE_CONFIG_DIR||O.join(X(),".config","oracle"):O.join(X(),".config","oracle")}function me(){return O.join(b(),"desk.json")}function we(){return O.join(b(),"env")}function E({force:e=!1}={}){if(E._done&&!e)return E._result||null;E._done=!0;let t={},r=(n,i)=>{if(i==null)return;let s=String(i).trim();s&&(process.env[n]!=null&&String(process.env[n]).trim()!==""||(process.env[n]=s,t[n]=s))};try{let n=we();if(j.existsSync(n))for(let i of j.readFileSync(n,"utf8").split(/\r?\n/)){let s=i.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*?)\s*$/);if(!s||s[2].startsWith("#"))continue;let p=s[2];(p.startsWith('"')&&p.endsWith('"')||p.startsWith("'")&&p.endsWith("'"))&&(p=p.slice(1,-1)),r(s[1],p)}}catch{}try{let n=me();if(j.existsSync(n)){let i=JSON.parse(j.readFileSync(n,"utf8"));i&&typeof i=="object"&&(r("ORACLE_DESK_URL",i.deskUrl||i.dataUrl||i.url),r("ORACLE_DATA_URL",i.dataUrl||i.deskUrl||i.url),r("ORACLE_API_URL",i.apiUrl||i.dataUrl||i.deskUrl),r("ORACLE_PUBLIC_URL",i.publicUrl||i.deskUrl||i.dataUrl),r("ORACLE_EXEC_URL",i.execUrl),r("MAD_DESK_URL",i.deskUrl||i.dataUrl))}}catch{}let o=process.env.ORACLE_DESK_URL||process.env.ORACLE_DATA_URL||"";return o&&(r("ORACLE_DESK_URL",o),r("ORACLE_DATA_URL",o),r("ORACLE_API_URL",o),r("ORACLE_PUBLIC_URL",o),r("MAD_DESK_URL",o)),E._result=Object.keys(t).length?t:null,E._result}try{E()}catch{}function $(e){return j.mkdirSync(e,{recursive:!0}),e}var ge=new Set(["openrouter","openai","anthropic","xai","deepseek","gemini","kimi","mistral","nous","qwen","glm","custom","anthropic-oauth","openai-codex","xai-oauth"]);function I(e){return String(e||"").trim()||void 0}function ye(e,{required:t=!1}={}){let r=I(e)?.toLowerCase();if(!r){if(t)throw new Error("model provider is required");return}if(!ge.has(r))throw new Error(`unsupported provider: ${r}`);return r}function ve(e,{required:t=!1}={}){let r=I(e);if(!r){if(t)throw new Error("model is required");return}if(r.includes("..")||r.startsWith("/")||!/^[a-zA-Z0-9._:/-]{1,200}$/.test(r))throw new Error("invalid model id");return r}function ke(e){let t=I(e);if(!t||t.length>2048)throw new Error("invalid custom base URL");let r;try{r=new URL(t)}catch{throw new Error("invalid custom base URL")}let o=r.hostname.toLowerCase().replace(/^\[|\]$/g,""),n=o==="localhost"||o==="127.0.0.1"||o==="::1";if(r.protocol!=="https:"&&!(r.protocol==="http:"&&n)||r.username||r.password||r.search||r.hash)throw new Error("custom base URL must use HTTPS or loopback HTTP without credentials, query, or fragment");return r.toString().replace(/\/+$/,"")}function L({provider:e,model:t,baseUrl:r}={},{requireModel:o=!1}={}){let n=ye(e),i=ve(t,{required:o});if(n==="custom")return{provider:n,...i?{model:i}:{},baseUrl:ke(r)};if(I(r))throw new Error("baseUrl is only supported for the custom provider");return{...n?{provider:n}:{},...i?{model:i}:{}}}var xe=new Set(["auto","standalone","hermes","remote","arch"]);function _e(){return F.join(b(),"model.json")}function P(e){return String(e||"").trim()||void 0}function Ae(e={}){let t=P(e.backend)?.toLowerCase()||"auto",r=L({provider:e.provider,model:e.model,baseUrl:e.baseUrl},{requireModel:t==="standalone"}),o=P(e.apiKeyEnv),n=Number.parseInt(String(e.contextLength||""),10),i=P(e.reasoningEffort),s=P(e.computeHost||e.remoteHost),p=P(e.computeUser||e.remoteUser),u=P(e.computePath||e.remotePath);if(!xe.has(t))throw new Error(`unsupported backend: ${t}`);if(process.env.ORACLE_PUBLIC_DESKTOP==="1"&&["remote","arch"].includes(t))throw new Error("remote compute backends are disabled in the public desktop");if(o&&!/^[A-Z][A-Z0-9_]*$/.test(o))throw new Error("api key env must be an uppercase environment variable name");if(t==="remote"&&!s)throw new Error("remote backend requires computeHost");return{backend:t,...r,...o?{apiKeyEnv:o}:{},...Number.isFinite(n)&&n>0?{contextLength:n}:{},...i?{reasoningEffort:i}:{},...s?{computeHost:s}:{},...p?{computeUser:p}:{},...u?{computePath:u}:{}}}function Z(e){let t=Ae(e),r=_e();$(F.dirname(r)),process.platform!=="win32"&&T.chmodSync(F.dirname(r),448);let o=`${r}.${process.pid}.tmp`;return T.writeFileSync(o,`${JSON.stringify(t,null,2)}
1
+ import T from"node:fs";import F from"node:path";import j from"node:fs";import le from"node:os";import O from"node:path";import{fileURLToPath as pe}from"node:url";var fe=O.dirname(pe(import.meta.url)),Ve=O.resolve(fe,"../..");function X(){return process.env.ORACLE_FAKE_HOME||le.homedir()}function he(){return process.env.ORACLE_PUBLIC_DESKTOP==="1"}function b(){return he()?process.env.ORACLE_CONFIG_DIR||O.join(X(),".config","oracle"):O.join(X(),".config","oracle")}function me(){return O.join(b(),"desk.json")}function we(){return O.join(b(),"env")}function E({force:e=!1}={}){if(E._done&&!e)return E._result||null;E._done=!0;let t={},r=(n,i)=>{if(i==null)return;let s=String(i).trim();s&&(process.env[n]!=null&&String(process.env[n]).trim()!==""||(process.env[n]=s,t[n]=s))};try{let n=we();if(j.existsSync(n))for(let i of j.readFileSync(n,"utf8").split(/\r?\n/)){let s=i.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*?)\s*$/);if(!s||s[2].startsWith("#"))continue;let l=s[2];(l.startsWith('"')&&l.endsWith('"')||l.startsWith("'")&&l.endsWith("'"))&&(l=l.slice(1,-1)),r(s[1],l)}}catch{}try{let n=me();if(j.existsSync(n)){let i=JSON.parse(j.readFileSync(n,"utf8"));i&&typeof i=="object"&&(r("ORACLE_DESK_URL",i.deskUrl||i.dataUrl||i.url),r("ORACLE_DATA_URL",i.dataUrl||i.deskUrl||i.url),r("ORACLE_API_URL",i.apiUrl||i.dataUrl||i.deskUrl),r("ORACLE_PUBLIC_URL",i.publicUrl||i.deskUrl||i.dataUrl),r("ORACLE_EXEC_URL",i.execUrl),r("MAD_DESK_URL",i.deskUrl||i.dataUrl))}}catch{}let o=process.env.ORACLE_DESK_URL||process.env.ORACLE_DATA_URL||"";return o&&(r("ORACLE_DESK_URL",o),r("ORACLE_DATA_URL",o),r("ORACLE_API_URL",o),r("ORACLE_PUBLIC_URL",o),r("MAD_DESK_URL",o)),E._result=Object.keys(t).length?t:null,E._result}try{E()}catch{}function $(e){return j.mkdirSync(e,{recursive:!0}),e}var ge=new Set(["openrouter","openai","anthropic","xai","deepseek","gemini","kimi","mistral","nous","qwen","glm","local","ollama","custom","anthropic-oauth","openai-codex","xai-oauth"]);function I(e){return String(e||"").trim()||void 0}function ye(e,{required:t=!1}={}){let r=I(e)?.toLowerCase();if(!r){if(t)throw new Error("model provider is required");return}if(!ge.has(r))throw new Error(`unsupported provider: ${r}`);return r}function ve(e,{required:t=!1}={}){let r=I(e);if(!r){if(t)throw new Error("model is required");return}if(r.includes("..")||r.startsWith("/")||!/^[a-zA-Z0-9._:/-]{1,200}$/.test(r))throw new Error("invalid model id");return r}function ke(e){let t=I(e);if(!t||t.length>2048)throw new Error("invalid custom base URL");let r;try{r=new URL(t)}catch{throw new Error("invalid custom base URL")}let o=r.hostname.toLowerCase().replace(/^\[|\]$/g,""),n=o==="localhost"||o==="127.0.0.1"||o==="::1";if(r.protocol!=="https:"&&!(r.protocol==="http:"&&n)||r.username||r.password||r.search||r.hash)throw new Error("custom base URL must use HTTPS or loopback HTTP without credentials, query, or fragment");return r.toString().replace(/\/+$/,"")}function L({provider:e,model:t,baseUrl:r}={},{requireModel:o=!1}={}){let n=ye(e),i=ve(t,{required:o});if(n==="custom")return{provider:n,...i?{model:i}:{},baseUrl:ke(r)};if(I(r))throw new Error("baseUrl is only supported for the custom provider");return{...n?{provider:n}:{},...i?{model:i}:{}}}var xe=new Set(["auto","standalone","hermes","remote","arch"]);function _e(){return F.join(b(),"model.json")}function P(e){return String(e||"").trim()||void 0}function Ae(e={}){let t=P(e.backend)?.toLowerCase()||"auto",r=L({provider:e.provider,model:e.model,baseUrl:e.baseUrl},{requireModel:t==="standalone"}),o=P(e.apiKeyEnv),n=Number.parseInt(String(e.contextLength||""),10),i=P(e.reasoningEffort),s=P(e.computeHost||e.remoteHost),l=P(e.computeUser||e.remoteUser),u=P(e.computePath||e.remotePath);if(!xe.has(t))throw new Error(`unsupported backend: ${t}`);if(process.env.ORACLE_PUBLIC_DESKTOP==="1"&&["remote","arch"].includes(t))throw new Error("remote compute backends are disabled in the public desktop");if(o&&!/^[A-Z][A-Z0-9_]*$/.test(o))throw new Error("api key env must be an uppercase environment variable name");if(t==="remote"&&!s)throw new Error("remote backend requires computeHost");return{backend:t,...r,...o?{apiKeyEnv:o}:{},...Number.isFinite(n)&&n>0?{contextLength:n}:{},...i?{reasoningEffort:i}:{},...s?{computeHost:s}:{},...l?{computeUser:l}:{},...u?{computePath:u}:{}}}function Z(e){let t=Ae(e),r=_e();$(F.dirname(r)),process.platform!=="win32"&&T.chmodSync(F.dirname(r),448);let o=`${r}.${process.pid}.tmp`;return T.writeFileSync(o,`${JSON.stringify(t,null,2)}
2
2
  `,{mode:384}),T.renameSync(o,r),process.platform!=="win32"&&T.chmodSync(r,384),t}import{createHash as Se,randomBytes as N,timingSafeEqual as Ee}from"node:crypto";import g from"node:fs";import k from"node:path";import Oe from"node:readline/promises";import{spawn as be,spawnSync as Pe}from"node:child_process";var R=Object.freeze({"anthropic-oauth":{aliases:["anthropic-oauth","anthropic","claude","claude-oauth"],clientId:"9d1c250a-e61b-44d9-88ed-5944d1962f5e",authorizeUrl:"https://claude.ai/oauth/authorize",tokenUrl:"https://platform.claude.com/v1/oauth/token",redirectUri:"https://console.anthropic.com/oauth/code/callback",scope:"org:create_api_key user:profile user:inference",baseUrl:"https://api.anthropic.com/v1",model:"claude-sonnet-4-6",protocol:"anthropic-messages"},"openai-codex":{aliases:["openai-codex","openai-oauth","codex","codex-oauth"],clientId:"app_EMoamEEZ73f0CkXaXp7hrann",issuer:"https://auth.openai.com",tokenUrl:"https://auth.openai.com/oauth/token",baseUrl:"https://chatgpt.com/backend-api/codex",model:"gpt-5.6-sol",protocol:"responses"},"xai-oauth":{aliases:["xai-oauth","xai","grok","grok-oauth"],clientId:"b1a00492-073a-47ea-816f-4c329264a828",issuer:"https://auth.x.ai",discoveryUrl:"https://auth.x.ai/.well-known/openid-configuration",deviceUrl:"https://auth.x.ai/oauth2/device/code",scope:"openid profile email offline_access grok-cli:access api:access",baseUrl:"https://api.x.ai/v1",model:"grok-4.6",protocol:"responses"}}),Ce=12e4;function Re(e={}){return typeof e.now=="function"?Number(e.now()):Date.now()}function _(e){let t=String(e||"").trim().toLowerCase();for(let[r,o]of Object.entries(R))if(o.aliases.includes(t))return r;throw new Error(`unsupported OAuth provider: ${e||"(empty)"}`)}function Y(e){let t=_(e);return{id:t,...R[t]}}function m(e,t={}){if(!g.existsSync(e))return t;try{let r=JSON.parse(g.readFileSync(e,"utf8"));if(!r||typeof r!="object"||Array.isArray(r))throw new Error("invalid object");return r}catch{throw new Error(`credential store is unreadable or corrupt: ${k.basename(e)}`)}}function Q(e){$(e),process.platform!=="win32"&&g.chmodSync(e,448)}function x(e,t){Q(k.dirname(e));let r=`${e}.${process.pid}.${N(4).toString("hex")}.tmp`;g.writeFileSync(r,`${JSON.stringify(t,null,2)}
3
- `,{mode:384}),g.renameSync(r,e),process.platform!=="win32"&&g.chmodSync(e,384)}function Ue(e){if(process.platform!=="linux")return!1;let t=e("secret-tool",["--version"],{encoding:"utf8",stdio:["ignore","pipe","ignore"]});return!t.error&&t.status===0}function D(e){let t=String(e||"").trim().toLowerCase();if(!/^[a-z0-9][a-z0-9._-]*$/.test(t))throw new Error(`invalid API-key provider: ${e||"(empty)"}`);return t}function C(e={}){let t=String(e.accessToken||e.access_token||"").trim(),r=String(e.refreshToken||e.refresh_token||"").trim(),o=Number(e.expiresAt||e.expires_at||0);if(Number.isFinite(o)&&o>=1e9&&o<1e12&&(o=o*1e3),!t)throw new Error("OAuth credential is missing access token");return{accessToken:t,refreshToken:r,expiresAt:Number.isFinite(o)?o:0,tokenType:String(e.tokenType||e.token_type||"Bearer"),source:String(e.source||"oracle"),...e.discovery?{discovery:e.discovery}:{},...e.scope?{scope:e.scope}:{},...e.idToken||e.id_token?{idToken:String(e.idToken||e.id_token)}:{}}}function je(e={}){let t=e.file||k.join(b(),"oauth.json"),r=e.metadataFile||k.join(k.dirname(t),"oauth-meta.json"),o=e.linksFile||k.join(k.dirname(t),"oauth-links.json"),n=()=>typeof e.now=="function"?Number(e.now()):Date.now(),i=e.spawnFn||Pe,s=e.keychain!==!1&&process.env.ORACLE_AUTH_FILE_STORE!=="1"&&Ue(i),p=s?"linux-secret-service":"private-file",u=`${t}.lock`;async function v(f){Q(k.dirname(u));let l;for(let c=0;c<400;c+=1)try{l=g.openSync(u,"wx",384);break}catch(a){if(a?.code!=="EEXIST")throw a;try{Date.now()-g.statSync(u).mtimeMs>3e5&&g.unlinkSync(u)}catch{}await new Promise(d=>setTimeout(d,25))}if(l===void 0)throw new Error("timed out waiting for OAuth credential lock");try{return await f()}finally{try{g.closeSync(l)}catch{}try{g.unlinkSync(u)}catch{}}}function w(f,l="oauth"){return["application","oracle","kind",l,"provider",f]}function U(f){if(!g.existsSync(o))return null;let c=m(o,{providers:{}}).providers?.[f];if(!Array.isArray(c))return null;let a=[];for(let d of c)if(k.isAbsolute(String(d||"")))try{let h=m(d,{});if(f==="anthropic-oauth"&&h.claudeAiOauth){let S=C(h.claudeAiOauth);a.push({...S,refreshToken:"",source:"external-access-only"});continue}let y=h.credential_pool&&typeof h.credential_pool=="object"?h.credential_pool:null;if(y){let S=y[f]||y[f.replace(/-oauth$/,"")]||[],ue=Array.isArray(S)?S:S?[S]:[];for(let z of ue)if(!(!z||typeof z!="object"))try{let de=C(z);a.push({...de,refreshToken:"",source:"external-access-only"})}catch{}}}catch{}return a.length?a.find(d=>!d.expiresAt||d.expiresAt>n()+Ce)||a[0]:null}function W(f){let l=_(f);if(s){let d=i("secret-tool",["lookup",...w(l)],{encoding:"utf8",stdio:["ignore","pipe","ignore"]});if(!d.error&&d.status===0&&String(d.stdout||"").trim())try{return C(JSON.parse(String(d.stdout).trim()))}catch{}return U(l)}let a=m(t,{providers:{}}).providers?.[l];if(a)try{return C(a)}catch{}return U(l)}function ne(f,l){let c=_(f),a=C(l);if(s){let h=i("secret-tool",["store",`--label=Oracle ${c} OAuth`,...w(c)],{input:JSON.stringify(a),encoding:"utf8",stdio:["pipe","ignore","pipe"]});if(h.error||h.status!==0)throw new Error("OS credential store rejected OAuth credential");let y=m(r,{providers:{}});return y.providers||={},y.providers[c]={expiresAt:a.expiresAt,source:a.source},x(r,y),a}let d=m(t,{providers:{}});return d.providers||={},d.providers[c]=a,x(t,d),a}function ie(f){let l=_(f);if(s){let d=i("secret-tool",["clear",...w(l)],{encoding:"utf8",stdio:["ignore","ignore","pipe"]}),h=m(r,{providers:{}});return h.providers&&delete h.providers[l],x(r,h),!d.error&&d.status===0}let c=m(t,{providers:{}}),a=!!c.providers?.[l];return c.providers&&delete c.providers[l],x(t,c),a}function V(f){let l=D(f);if(s){let c=i("secret-tool",["lookup",...w(l,"api-key")],{encoding:"utf8",stdio:["ignore","pipe","ignore"]});return c.error||c.status!==0?"":String(c.stdout||"").trim()}return String(m(t,{apiKeys:{}}).apiKeys?.[l]||"").trim()}function se(f,l){let c=D(f),a=String(l||"").trim();if(!a)throw new Error("API key is empty");if(s){let h=i("secret-tool",["store",`--label=Oracle ${c} API key`,...w(c,"api-key")],{input:a,encoding:"utf8",stdio:["pipe","ignore","pipe"]});if(h.error||h.status!==0)throw new Error("OS credential store rejected API key");let y=m(r,{providers:{},apiKeys:{}});return y.apiKeys||={},y.apiKeys[c]={configured:!0},x(r,y),!0}let d=m(t,{providers:{},apiKeys:{}});return d.apiKeys||={},d.apiKeys[c]=a,x(t,d),!0}function ce(f){let l=D(f);if(s){let d=i("secret-tool",["clear",...w(l,"api-key")],{encoding:"utf8",stdio:["ignore","ignore","pipe"]}),h=m(r,{providers:{},apiKeys:{}});return h.apiKeys&&delete h.apiKeys[l],x(r,h),!d.error&&d.status===0}let c=m(t,{providers:{},apiKeys:{}}),a=!!c.apiKeys?.[l];return c.apiKeys&&delete c.apiKeys[l],x(t,c),a}function ae(){let f={},l={};if(s){let c=m(r,{providers:{},apiKeys:{}});for(let[a,d]of Object.entries(c.providers||{}))f[a]={loggedIn:!!W(a),expiresAt:Number(d.expiresAt||0),source:String(d.source||"oracle"),storage:p};for(let a of Object.keys(c.apiKeys||{}))l[a]={configured:!!V(a),storage:p}}else{let c=m(t,{providers:{},apiKeys:{}});for(let[a,d]of Object.entries(c.providers||{}))f[a]={loggedIn:!!d?.accessToken,expiresAt:Number(d?.expiresAt||0),source:String(d?.source||"oracle"),storage:p};for(let[a,d]of Object.entries(c.apiKeys||{}))l[a]={configured:!!d,storage:p}}for(let c of Object.keys(R)){if(f[c])continue;let a=U(c);a&&(f[c]={loggedIn:!0,expiresAt:a.expiresAt,source:a.source,storage:"external-access-source"})}return{storage:p,providers:f,apiKeys:l}}return Object.freeze({file:t,storage:p,get:W,set:ne,remove:ie,getApiKey:V,setApiKey:se,removeApiKey:ce,status:ae,withLock:v})}var G;function ee(){return G||=je(),G}function M(e){return Buffer.from(e).toString("base64url")}function $e(){let e=M(N(32));return{verifier:e,challenge:M(Se("sha256").update(e).digest()),state:M(N(24))}}function Ie(e,t){let r=Buffer.from(String(e||"")),o=Buffer.from(String(t||""));return r.length===o.length&&Ee(r,o)}function Le(e){let t=String(e),r=process.platform==="darwin"?["open",[t]]:process.platform==="win32"?["cmd.exe",["/d","/s","/c","start","",t]]:["xdg-open",[t]];try{return be(r[0],r[1],{detached:!0,stdio:"ignore"}).unref(),!0}catch{return!1}}function B(e){return new URLSearchParams(e).toString()}async function A(e,t){if(!e?.ok){let o="";try{o=String((await e.json())?.error||"")}catch{}throw new Error(`${t} failed (HTTP ${e?.status||"unknown"}${o?`, ${o}`:""})`)}let r=await e.json();if(!r||typeof r!="object")throw new Error(`${t} returned invalid JSON`);return r}async function Te(e){if(e)return String(await e()).trim();let t=Oe.createInterface({input:process.stdin,output:process.stdout});try{return String(await t.question("Authorization code: ")).trim()}finally{t.close()}}function H(e,t={}){let r=String(e.access_token||"").trim(),o=String(e.refresh_token||t.refreshToken||"").trim();if(!r)throw new Error("OAuth token response is missing access token");let n=Number(e.expires_in||3600);return C({accessToken:r,refreshToken:o,expiresAt:Re(t)+Math.max(1,n)*1e3,tokenType:e.token_type||"Bearer",idToken:e.id_token,source:"oracle",...t.discovery?{discovery:t.discovery}:{},...e.scope?{scope:e.scope}:{}})}async function Ke(e){let t=R["anthropic-oauth"],r=e.pkce||$e(),o=new URLSearchParams({code:"true",client_id:t.clientId,response_type:"code",redirect_uri:t.redirectUri,scope:t.scope,code_challenge:r.challenge,code_challenge_method:"S256",state:r.state}),n=`${t.authorizeUrl}?${o}`;e.output(`Open: ${n}`),e.openFn(n);let i=await Te(e.inputFn),[s,p]=i.split("#",2);if(!s||!Ie(p,r.state))throw new Error("Claude OAuth state mismatch");let u=await e.fetchFn(t.tokenUrl,{method:"POST",headers:{"content-type":"application/json","user-agent":"axios/1.7.9"},body:JSON.stringify({grant_type:"authorization_code",client_id:t.clientId,code:s,state:p,redirect_uri:t.redirectUri,code_verifier:r.verifier})});return H(await A(u,"Claude OAuth token exchange"),e)}async function ze(e){let t=R["openai-codex"],r=await A(await e.fetchFn(`${t.issuer}/api/accounts/deviceauth/usercode`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({client_id:t.clientId})}),"Codex device authorization");if(!r.user_code||!r.device_auth_id)throw new Error("Codex device authorization returned incomplete data");let o=`${t.issuer}/codex/device`;e.output(`Open: ${o}`),e.output(`Code: ${r.user_code}`),e.openFn(o);let n=Math.max(3,Number(r.interval||5)),i;for(let p=0;p<Math.ceil(900/n);p+=1){await e.sleepFn(n*1e3);let u=await e.fetchFn(`${t.issuer}/api/accounts/deviceauth/token`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({device_auth_id:r.device_auth_id,user_code:r.user_code})});if(u.ok){i=await A(u,"Codex device authorization");break}if(![403,404].includes(u.status))throw new Error(`Codex device authorization failed (HTTP ${u.status})`)}if(!i)throw new Error("Codex device authorization timed out");let s=await e.fetchFn(t.tokenUrl,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:B({grant_type:"authorization_code",code:i.authorization_code,redirect_uri:`${t.issuer}/deviceauth/callback`,client_id:t.clientId,code_verifier:i.code_verifier})});return H(await A(s,"Codex OAuth token exchange"),e)}function K(e){let t=new URL(String(e)),r=t.hostname.toLowerCase();if(t.protocol!=="https:"||r!=="x.ai"&&!r.endsWith(".x.ai"))throw new Error("xAI OAuth discovery returned an untrusted endpoint");return t.toString()}async function Fe(e){let t=R["xai-oauth"],r=await A(await e.fetchFn(t.discoveryUrl,{headers:{accept:"application/json"}}),"xAI OAuth discovery");K(r.authorization_endpoint);let o=K(r.token_endpoint),n=await A(await e.fetchFn(t.deviceUrl,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded",accept:"application/json"},body:B({client_id:t.clientId,scope:t.scope})}),"xAI device authorization");if(!n.device_code||!n.user_code||!n.verification_uri)throw new Error("xAI device authorization returned incomplete data");let i=K(n.verification_uri_complete||n.verification_uri);e.output(`Open: ${i}`),e.output(`Code: ${n.user_code}`),e.openFn(i);let s=Math.max(1,Number(n.interval||5)),p=Math.ceil(Math.max(1,Number(n.expires_in||600))/s);for(let u=0;u<p;u+=1){let v=await e.fetchFn(o,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded",accept:"application/json"},body:B({grant_type:"urn:ietf:params:oauth:grant-type:device_code",client_id:t.clientId,device_code:n.device_code})});if(v.ok){let U=await A(v,"xAI OAuth token exchange");return H(U,{...e,discovery:{authorization_endpoint:K(r.authorization_endpoint),token_endpoint:o}})}let w="";try{w=String((await v.json())?.error||"")}catch{}if(w==="slow_down")await e.sleepFn((s+1)*1e3);else if(w==="authorization_pending")await e.sleepFn(s*1e3);else throw new Error(`xAI OAuth token exchange failed (HTTP ${v.status}${w?`, ${w}`:""})`)}throw new Error("xAI device authorization timed out")}async function te(e,t={}){let r=_(e),o={fetchFn:t.fetchFn||globalThis.fetch,inputFn:t.inputFn,sleepFn:t.sleepFn||(n=>new Promise(i=>setTimeout(i,n))),openFn:t.openFn||Le,output:t.output||(n=>process.stdout.write(`${n}
3
+ `,{mode:384}),g.renameSync(r,e),process.platform!=="win32"&&g.chmodSync(e,384)}function Ue(e){if(process.platform!=="linux")return!1;let t=e("secret-tool",["--version"],{encoding:"utf8",stdio:["ignore","pipe","ignore"]});return!t.error&&t.status===0}function D(e){let t=String(e||"").trim().toLowerCase();if(!/^[a-z0-9][a-z0-9._-]*$/.test(t))throw new Error(`invalid API-key provider: ${e||"(empty)"}`);return t}function C(e={}){let t=String(e.accessToken||e.access_token||"").trim(),r=String(e.refreshToken||e.refresh_token||"").trim(),o=Number(e.expiresAt||e.expires_at||0);if(Number.isFinite(o)&&o>=1e9&&o<1e12&&(o=o*1e3),!t)throw new Error("OAuth credential is missing access token");return{accessToken:t,refreshToken:r,expiresAt:Number.isFinite(o)?o:0,tokenType:String(e.tokenType||e.token_type||"Bearer"),source:String(e.source||"oracle"),...e.discovery?{discovery:e.discovery}:{},...e.scope?{scope:e.scope}:{},...e.idToken||e.id_token?{idToken:String(e.idToken||e.id_token)}:{}}}function je(e={}){let t=e.file||k.join(b(),"oauth.json"),r=e.metadataFile||k.join(k.dirname(t),"oauth-meta.json"),o=e.linksFile||k.join(k.dirname(t),"oauth-links.json"),n=()=>typeof e.now=="function"?Number(e.now()):Date.now(),i=e.spawnFn||Pe,s=e.keychain!==!1&&process.env.ORACLE_AUTH_FILE_STORE!=="1"&&Ue(i),l=s?"linux-secret-service":"private-file",u=`${t}.lock`;async function v(f){Q(k.dirname(u));let p;for(let c=0;c<400;c+=1)try{p=g.openSync(u,"wx",384);break}catch(a){if(a?.code!=="EEXIST")throw a;try{Date.now()-g.statSync(u).mtimeMs>3e5&&g.unlinkSync(u)}catch{}await new Promise(d=>setTimeout(d,25))}if(p===void 0)throw new Error("timed out waiting for OAuth credential lock");try{return await f()}finally{try{g.closeSync(p)}catch{}try{g.unlinkSync(u)}catch{}}}function w(f,p="oauth"){return["application","oracle","kind",p,"provider",f]}function U(f){if(!g.existsSync(o))return null;let c=m(o,{providers:{}}).providers?.[f];if(!Array.isArray(c))return null;let a=[];for(let d of c)if(k.isAbsolute(String(d||"")))try{let h=m(d,{});if(f==="anthropic-oauth"&&h.claudeAiOauth){let S=C(h.claudeAiOauth);a.push({...S,refreshToken:"",source:"external-access-only"});continue}let y=h.credential_pool&&typeof h.credential_pool=="object"?h.credential_pool:null;if(y){let S=y[f]||y[f.replace(/-oauth$/,"")]||[],ue=Array.isArray(S)?S:S?[S]:[];for(let z of ue)if(!(!z||typeof z!="object"))try{let de=C(z);a.push({...de,refreshToken:"",source:"external-access-only"})}catch{}}}catch{}return a.length?a.find(d=>!d.expiresAt||d.expiresAt>n()+Ce)||a[0]:null}function W(f){let p=_(f);if(s){let d=i("secret-tool",["lookup",...w(p)],{encoding:"utf8",stdio:["ignore","pipe","ignore"]});if(!d.error&&d.status===0&&String(d.stdout||"").trim())try{return C(JSON.parse(String(d.stdout).trim()))}catch{}return U(p)}let a=m(t,{providers:{}}).providers?.[p];if(a)try{return C(a)}catch{}return U(p)}function ne(f,p){let c=_(f),a=C(p);if(s){let h=i("secret-tool",["store",`--label=Oracle ${c} OAuth`,...w(c)],{input:JSON.stringify(a),encoding:"utf8",stdio:["pipe","ignore","pipe"]});if(h.error||h.status!==0)throw new Error("OS credential store rejected OAuth credential");let y=m(r,{providers:{}});return y.providers||={},y.providers[c]={expiresAt:a.expiresAt,source:a.source},x(r,y),a}let d=m(t,{providers:{}});return d.providers||={},d.providers[c]=a,x(t,d),a}function ie(f){let p=_(f);if(s){let d=i("secret-tool",["clear",...w(p)],{encoding:"utf8",stdio:["ignore","ignore","pipe"]}),h=m(r,{providers:{}});return h.providers&&delete h.providers[p],x(r,h),!d.error&&d.status===0}let c=m(t,{providers:{}}),a=!!c.providers?.[p];return c.providers&&delete c.providers[p],x(t,c),a}function V(f){let p=D(f);if(s){let c=i("secret-tool",["lookup",...w(p,"api-key")],{encoding:"utf8",stdio:["ignore","pipe","ignore"]});return c.error||c.status!==0?"":String(c.stdout||"").trim()}return String(m(t,{apiKeys:{}}).apiKeys?.[p]||"").trim()}function se(f,p){let c=D(f),a=String(p||"").trim();if(!a)throw new Error("API key is empty");if(s){let h=i("secret-tool",["store",`--label=Oracle ${c} API key`,...w(c,"api-key")],{input:a,encoding:"utf8",stdio:["pipe","ignore","pipe"]});if(h.error||h.status!==0)throw new Error("OS credential store rejected API key");let y=m(r,{providers:{},apiKeys:{}});return y.apiKeys||={},y.apiKeys[c]={configured:!0},x(r,y),!0}let d=m(t,{providers:{},apiKeys:{}});return d.apiKeys||={},d.apiKeys[c]=a,x(t,d),!0}function ce(f){let p=D(f);if(s){let d=i("secret-tool",["clear",...w(p,"api-key")],{encoding:"utf8",stdio:["ignore","ignore","pipe"]}),h=m(r,{providers:{},apiKeys:{}});return h.apiKeys&&delete h.apiKeys[p],x(r,h),!d.error&&d.status===0}let c=m(t,{providers:{},apiKeys:{}}),a=!!c.apiKeys?.[p];return c.apiKeys&&delete c.apiKeys[p],x(t,c),a}function ae(){let f={},p={};if(s){let c=m(r,{providers:{},apiKeys:{}});for(let[a,d]of Object.entries(c.providers||{}))f[a]={loggedIn:!!W(a),expiresAt:Number(d.expiresAt||0),source:String(d.source||"oracle"),storage:l};for(let a of Object.keys(c.apiKeys||{}))p[a]={configured:!!V(a),storage:l}}else{let c=m(t,{providers:{},apiKeys:{}});for(let[a,d]of Object.entries(c.providers||{}))f[a]={loggedIn:!!d?.accessToken,expiresAt:Number(d?.expiresAt||0),source:String(d?.source||"oracle"),storage:l};for(let[a,d]of Object.entries(c.apiKeys||{}))p[a]={configured:!!d,storage:l}}for(let c of Object.keys(R)){if(f[c])continue;let a=U(c);a&&(f[c]={loggedIn:!0,expiresAt:a.expiresAt,source:a.source,storage:"external-access-source"})}return{storage:l,providers:f,apiKeys:p}}return Object.freeze({file:t,storage:l,get:W,set:ne,remove:ie,getApiKey:V,setApiKey:se,removeApiKey:ce,status:ae,withLock:v})}var G;function ee(){return G||=je(),G}function M(e){return Buffer.from(e).toString("base64url")}function $e(){let e=M(N(32));return{verifier:e,challenge:M(Se("sha256").update(e).digest()),state:M(N(24))}}function Ie(e,t){let r=Buffer.from(String(e||"")),o=Buffer.from(String(t||""));return r.length===o.length&&Ee(r,o)}function Le(e){let t=String(e),r=process.platform==="darwin"?["open",[t]]:process.platform==="win32"?["cmd.exe",["/d","/s","/c","start","",t]]:["xdg-open",[t]];try{return be(r[0],r[1],{detached:!0,stdio:"ignore"}).unref(),!0}catch{return!1}}function B(e){return new URLSearchParams(e).toString()}async function A(e,t){if(!e?.ok){let o="";try{o=String((await e.json())?.error||"")}catch{}throw new Error(`${t} failed (HTTP ${e?.status||"unknown"}${o?`, ${o}`:""})`)}let r=await e.json();if(!r||typeof r!="object")throw new Error(`${t} returned invalid JSON`);return r}async function Te(e){if(e)return String(await e()).trim();let t=Oe.createInterface({input:process.stdin,output:process.stdout});try{return String(await t.question("Authorization code: ")).trim()}finally{t.close()}}function H(e,t={}){let r=String(e.access_token||"").trim(),o=String(e.refresh_token||t.refreshToken||"").trim();if(!r)throw new Error("OAuth token response is missing access token");let n=Number(e.expires_in||3600);return C({accessToken:r,refreshToken:o,expiresAt:Re(t)+Math.max(1,n)*1e3,tokenType:e.token_type||"Bearer",idToken:e.id_token,source:"oracle",...t.discovery?{discovery:t.discovery}:{},...e.scope?{scope:e.scope}:{}})}async function Ke(e){let t=R["anthropic-oauth"],r=e.pkce||$e(),o=new URLSearchParams({code:"true",client_id:t.clientId,response_type:"code",redirect_uri:t.redirectUri,scope:t.scope,code_challenge:r.challenge,code_challenge_method:"S256",state:r.state}),n=`${t.authorizeUrl}?${o}`;e.output(`Open: ${n}`),e.openFn(n);let i=await Te(e.inputFn),[s,l]=i.split("#",2);if(!s||!Ie(l,r.state))throw new Error("Claude OAuth state mismatch");let u=await e.fetchFn(t.tokenUrl,{method:"POST",headers:{"content-type":"application/json","user-agent":"axios/1.7.9"},body:JSON.stringify({grant_type:"authorization_code",client_id:t.clientId,code:s,state:l,redirect_uri:t.redirectUri,code_verifier:r.verifier})});return H(await A(u,"Claude OAuth token exchange"),e)}async function ze(e){let t=R["openai-codex"],r=await A(await e.fetchFn(`${t.issuer}/api/accounts/deviceauth/usercode`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({client_id:t.clientId})}),"Codex device authorization");if(!r.user_code||!r.device_auth_id)throw new Error("Codex device authorization returned incomplete data");let o=`${t.issuer}/codex/device`;e.output(`Open: ${o}`),e.output(`Code: ${r.user_code}`),e.openFn(o);let n=Math.max(3,Number(r.interval||5)),i;for(let l=0;l<Math.ceil(900/n);l+=1){await e.sleepFn(n*1e3);let u=await e.fetchFn(`${t.issuer}/api/accounts/deviceauth/token`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({device_auth_id:r.device_auth_id,user_code:r.user_code})});if(u.ok){i=await A(u,"Codex device authorization");break}if(![403,404].includes(u.status))throw new Error(`Codex device authorization failed (HTTP ${u.status})`)}if(!i)throw new Error("Codex device authorization timed out");let s=await e.fetchFn(t.tokenUrl,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:B({grant_type:"authorization_code",code:i.authorization_code,redirect_uri:`${t.issuer}/deviceauth/callback`,client_id:t.clientId,code_verifier:i.code_verifier})});return H(await A(s,"Codex OAuth token exchange"),e)}function K(e){let t=new URL(String(e)),r=t.hostname.toLowerCase();if(t.protocol!=="https:"||r!=="x.ai"&&!r.endsWith(".x.ai"))throw new Error("xAI OAuth discovery returned an untrusted endpoint");return t.toString()}async function Fe(e){let t=R["xai-oauth"],r=await A(await e.fetchFn(t.discoveryUrl,{headers:{accept:"application/json"}}),"xAI OAuth discovery");K(r.authorization_endpoint);let o=K(r.token_endpoint),n=await A(await e.fetchFn(t.deviceUrl,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded",accept:"application/json"},body:B({client_id:t.clientId,scope:t.scope})}),"xAI device authorization");if(!n.device_code||!n.user_code||!n.verification_uri)throw new Error("xAI device authorization returned incomplete data");let i=K(n.verification_uri_complete||n.verification_uri);e.output(`Open: ${i}`),e.output(`Code: ${n.user_code}`),e.openFn(i);let s=Math.max(1,Number(n.interval||5)),l=Math.ceil(Math.max(1,Number(n.expires_in||600))/s);for(let u=0;u<l;u+=1){let v=await e.fetchFn(o,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded",accept:"application/json"},body:B({grant_type:"urn:ietf:params:oauth:grant-type:device_code",client_id:t.clientId,device_code:n.device_code})});if(v.ok){let U=await A(v,"xAI OAuth token exchange");return H(U,{...e,discovery:{authorization_endpoint:K(r.authorization_endpoint),token_endpoint:o}})}let w="";try{w=String((await v.json())?.error||"")}catch{}if(w==="slow_down")await e.sleepFn((s+1)*1e3);else if(w==="authorization_pending")await e.sleepFn(s*1e3);else throw new Error(`xAI OAuth token exchange failed (HTTP ${v.status}${w?`, ${w}`:""})`)}throw new Error("xAI device authorization timed out")}async function te(e,t={}){let r=_(e),o={fetchFn:t.fetchFn||globalThis.fetch,inputFn:t.inputFn,sleepFn:t.sleepFn||(n=>new Promise(i=>setTimeout(i,n))),openFn:t.openFn||Le,output:t.output||(n=>process.stdout.write(`${n}
4
4
  `)),now:t.now,pkce:t.pkce};return r==="anthropic-oauth"?Ke(o):r==="openai-codex"?ze(o):Fe(o)}var re=Object.freeze({openrouter:{model:"openrouter/auto"},openai:{model:"gpt-4.1-mini"},anthropic:{model:"claude-sonnet-4-6"},xai:{model:"grok-4.6"},deepseek:{model:"deepseek-chat"},gemini:{model:"gemini-2.5-flash"},kimi:{model:"kimi-k3"},mistral:{model:"mistral-large-latest"},nous:{model:"moonshotai/kimi-k3"},qwen:{model:"qwen-plus"},glm:{model:"glm-4.5"},custom:{model:""}});function q(e,t){let r=e.indexOf(t);return r>=0&&e[r+1]?e[r+1]:""}async function De(){let e="";for await(let t of process.stdin)e+=t;return e.trim()}function Me(e="API key: "){if(!process.stdin.isTTY||!process.stdin.setRawMode)throw new Error("non-interactive API-key input requires --stdin");return process.stdout.write(e),new Promise((t,r)=>{let o="",n=()=>{process.stdin.off("data",i),process.stdin.setRawMode(!1),process.stdin.pause(),process.stdout.write(`
5
- `)},i=s=>{let p=String(s);for(let u of p){if(u==="\r"||u===`
5
+ `)},i=s=>{let l=String(s);for(let u of l){if(u==="\r"||u===`
6
6
  `){n(),t(o.trim());return}if(u===""){n(),r(new Error("cancelled"));return}u==="\x7F"||u==="\b"?o=o.slice(0,-1):o+=u}};process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.on("data",i)})}function J(e,t,{baseUrl:r=""}={}){if(e==="custom"&&!String(r||"").trim())throw new Error("custom provider requires --base-url");return{backend:"standalone",...L({provider:e,model:t,baseUrl:r},{requireModel:!0})}}function oe(e,t,r={}){return Z(J(e,t,r))}function Ne(e){process.stdout.write(`storage: ${e.storage}
7
7
  `);let t=Object.entries(e.providers||{}),r=Object.entries(e.apiKeys||{});if(!t.length&&!r.length){process.stdout.write(`no credentials configured
8
8
  `);return}for(let[o,n]of t){let i=n.expiresAt?new Date(n.expiresAt).toISOString():"unknown";process.stdout.write(`${o}: ${n.loggedIn?"logged in":"missing"}, expires ${i}
9
9
  `)}for(let[o,n]of r)process.stdout.write(`${o}: API key ${n.configured?"configured":"missing"}
10
10
  `)}function Be(){return["oracle auth, configure OAuth or API-key authentication",""," oracle auth login claude|codex|grok [--model MODEL] [--no-browser]"," oracle auth api-key PROVIDER [--model MODEL] [--base-url URL]"," PROVIDER: openrouter|openai|anthropic|xai|deepseek|gemini|kimi|mistral|nous|qwen|glm|custom",` printf '%s\\n' "$KEY" | oracle auth api-key PROVIDER --stdin`," oracle auth status [--json]"," oracle auth logout PROVIDER","","OAuth and API keys are additive. Select any compatible model with oracle model --provider PROVIDER --model MODEL."].join(`
11
- `)}var lt={name:"auth",summary:"login with Claude, Codex, or Grok OAuth; store provider API keys",group:"read",usage:Be(),async run(e){let t=[...e.argv],r=t.shift()||"status",o=ee();try{if(r==="status"){let n=o.status();return t.includes("--json")?process.stdout.write(`${JSON.stringify(n,null,2)}
12
- `):Ne(n),0}if(r==="login"){let n=t.find(u=>!u.startsWith("-"));if(!n)throw new Error("usage: oracle auth login claude|codex|grok");let i=Y(n),s=q(t,"--model")||i.model;J(i.id,s);let p=await te(i.id,{openFn:t.includes("--no-browser")?()=>!1:void 0});return await o.withLock(async()=>{let u=o.get(i.id);o.set(i.id,p);try{oe(i.id,s)}catch(v){throw u?o.set(i.id,u):o.remove(i.id),v}}),process.stdout.write(`${i.id}: logged in, stored in ${o.storage}
13
- `),0}if(r==="api-key"){let n=String(t.find(u=>!u.startsWith("-"))||"").trim().toLowerCase();if(!n)throw new Error("usage: oracle auth api-key PROVIDER [--stdin]");if(!Object.hasOwn(re,n))throw new Error(`unsupported API-key provider: ${n}`);let i=q(t,"--model")||re[n].model,s=q(t,"--base-url");J(n,i,{baseUrl:s});let p=t.includes("--stdin")?await De():await Me();return await o.withLock(async()=>{let u=o.getApiKey(n);o.setApiKey(n,p);try{oe(n,i,{baseUrl:s})}catch(v){throw u?o.setApiKey(n,u):o.removeApiKey(n),v}}),process.stdout.write(`${n}: API key configured in ${o.storage}
14
- `),0}if(r==="logout"){let n=String(t.find(p=>!p.startsWith("-"))||"").trim().toLowerCase();if(!n)throw new Error("usage: oracle auth logout PROVIDER");let i=!1;try{i=o.remove(_(n))}catch{}let s=o.removeApiKey(n);if(!i&&!s)throw new Error(`${n}: no local credential found`);return process.stdout.write(`${n}: local credential removed
11
+ `)}var pt={name:"auth",summary:"login with Claude, Codex, or Grok OAuth; store provider API keys",group:"read",usage:Be(),async run(e){let t=[...e.argv],r=t.shift()||"status",o=ee();try{if(r==="status"){let n=o.status();return t.includes("--json")?process.stdout.write(`${JSON.stringify(n,null,2)}
12
+ `):Ne(n),0}if(r==="login"){let n=t.find(u=>!u.startsWith("-"));if(!n)throw new Error("usage: oracle auth login claude|codex|grok");let i=Y(n),s=q(t,"--model")||i.model;J(i.id,s);let l=await te(i.id,{openFn:t.includes("--no-browser")?()=>!1:void 0});return await o.withLock(async()=>{let u=o.get(i.id);o.set(i.id,l);try{oe(i.id,s)}catch(v){throw u?o.set(i.id,u):o.remove(i.id),v}}),process.stdout.write(`${i.id}: logged in, stored in ${o.storage}
13
+ `),0}if(r==="api-key"){let n=String(t.find(u=>!u.startsWith("-"))||"").trim().toLowerCase();if(!n)throw new Error("usage: oracle auth api-key PROVIDER [--stdin]");if(!Object.hasOwn(re,n))throw new Error(`unsupported API-key provider: ${n}`);let i=q(t,"--model")||re[n].model,s=q(t,"--base-url");J(n,i,{baseUrl:s});let l=t.includes("--stdin")?await De():await Me();return await o.withLock(async()=>{let u=o.getApiKey(n);o.setApiKey(n,l);try{oe(n,i,{baseUrl:s})}catch(v){throw u?o.setApiKey(n,u):o.removeApiKey(n),v}}),process.stdout.write(`${n}: API key configured in ${o.storage}
14
+ `),0}if(r==="logout"){let n=String(t.find(l=>!l.startsWith("-"))||"").trim().toLowerCase();if(!n)throw new Error("usage: oracle auth logout PROVIDER");let i=!1;try{i=o.remove(_(n))}catch{}let s=o.removeApiKey(n);if(!i&&!s)throw new Error(`${n}: no local credential found`);return process.stdout.write(`${n}: local credential removed
15
15
  `),0}throw new Error(`unknown auth action: ${r}`)}catch(n){return process.stderr.write(`oracle auth: ${n.message}
16
- `),1}}};export{lt as default};
16
+ `),1}}};export{pt as default};