@oracle-agent/oracle 0.23.0 → 0.24.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,4 @@
1
+ import{createCipheriv as X,createDecipheriv as Z,randomBytes as v,scryptSync as K}from"node:crypto";import s from"node:fs";import m from"node:path";var R="ORACLE-LOCAL-VAULT",F=1,x=Object.freeze({N:1<<17,r:8,p:1}),Q=256*1024*1024,ee=16*1024;function O(e,r,n,{max:t=r}={}){if(typeof e!="string"||!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(e))throw new Error(`local-vault: invalid ${n} encoding`);let i=Buffer.from(e,"base64");if(i.toString("base64")!==e||i.length<r||i.length>t)throw new Error(`local-vault: invalid ${n} length`);return i}function j(e,r,n=x){let t=String(e??"");if(t.length<12)throw new Error("local-vault: passphrase must be at least 12 characters");return K(t,r,32,{...n,maxmem:Q})}function Oe(e,r,n={}){let t=Buffer.isBuffer(e)?Buffer.from(e):Buffer.from(String(e));if(!t.length)throw new Error("local-vault: refusing empty key material");let i=v(32),o=v(12),a={magic:R,version:F,kdf:{name:"scrypt",...x,salt:i.toString("base64")},cipher:{name:"aes-256-gcm",iv:o.toString("base64")},meta:{address:n.address?String(n.address).toLowerCase():null,kind:n.kind||"evm",createdAt:new Date().toISOString()}},c=j(r,i);try{let u=X("aes-256-gcm",c,o);u.setAAD(Buffer.from(JSON.stringify(a)));let f=Buffer.concat([u.update(t),u.final()]);return{...a,ciphertext:f.toString("base64"),tag:u.getAuthTag().toString("base64")}}finally{c.fill(0),t.fill(0)}}function ve(e,r){if(e?.magic!==R||e?.version!==F)throw new Error("local-vault: unsupported vault file");if(e?.kdf?.name!=="scrypt"||e?.cipher?.name!=="aes-256-gcm")throw new Error("local-vault: unsupported cryptography");if(e.kdf.N!==x.N||e.kdf.r!==x.r||e.kdf.p!==x.p)throw new Error("local-vault: unsupported KDF parameters");if(Object.keys(e.kdf).sort().join(",")!=="N,name,p,r,salt"||Object.keys(e.cipher).sort().join(",")!=="iv,name")throw new Error("local-vault: unexpected cryptography field");if(!e.meta||Object.keys(e.meta).some(d=>!["address","kind","createdAt"].includes(d))||String(e.meta.kind||"").length>16||String(e.meta.address||"").length>128||!Number.isFinite(Date.parse(e.meta.createdAt)))throw new Error("local-vault: invalid metadata");let n=["magic","version","kdf","cipher","meta","ciphertext","tag"];if(Object.keys(e).some(d=>!n.includes(d)))throw new Error("local-vault: unexpected vault field");let t=O(e.kdf.salt,32,"salt"),i=O(e.cipher.iv,12,"iv"),o=O(e.tag,16,"tag"),a=O(e.ciphertext,1,"ciphertext",{max:ee}),{ciphertext:c,tag:u,...f}=e,l=j(r,t);try{let d=Z("aes-256-gcm",l,i);return d.setAAD(Buffer.from(JSON.stringify(f))),d.setAuthTag(o),Buffer.concat([d.update(a),d.final()])}catch{throw new Error("local-vault: wrong passphrase or tampered vault")}finally{l.fill(0)}}function U(e){let r=s.lstatSync(e);if(r.isSymbolicLink())throw new Error("local-vault: refusing symlink");if(!r.isFile())throw new Error("local-vault: secret source must be a regular file");if(r.uid!==process.getuid?.())throw new Error("local-vault: secret source must be owned by this user");if(r.nlink!==1)throw new Error("local-vault: refusing hard-linked secret source");if((r.mode&63)!==0)throw new Error("local-vault: secret source must be owner-only (0600)")}function $(e){let r=m.dirname(e),n=s.lstatSync(r);if(!n.isDirectory()||n.isSymbolicLink())throw new Error("local-vault: unsafe destination directory");if(n.uid!==process.getuid?.())throw new Error("local-vault: destination directory must be owned by this user");try{let t=s.lstatSync(e);if(t.isSymbolicLink())throw new Error("local-vault: refusing symlink destination");if(!t.isFile()||t.uid!==process.getuid?.()||t.nlink!==1)throw new Error("local-vault: unsafe destination file");if(t.dev!==n.dev)throw new Error("local-vault: destination device mismatch")}catch(t){if(t.code!=="ENOENT")throw t}}function w(e){let r=s.lstatSync(e);U(e);let n=s.openSync(e,s.constants.O_RDONLY|s.constants.O_NOFOLLOW);try{let t=s.fstatSync(n);if(r.dev!==t.dev||r.ino!==t.ino||t.size>1024*1024)throw new Error("local-vault: secret source changed or is too large");return s.readFileSync(n,"utf8").replace(/[\r\n]+$/,"")}finally{s.closeSync(n)}}function be(e){return U(e),JSON.parse(s.readFileSync(e,"utf8"))}function Ne(e,r){s.mkdirSync(m.dirname(e),{recursive:!0,mode:448}),$(e);let n=m.join(m.dirname(e),`.${m.basename(e)}.${process.pid}.${v(6).toString("hex")}.tmp`),t;try{t=s.openSync(n,s.constants.O_CREAT|s.constants.O_EXCL|s.constants.O_WRONLY|s.constants.O_NOFOLLOW,384),s.writeFileSync(t,JSON.stringify(r,null,2)+`
2
+ `),s.fsyncSync(t),s.closeSync(t),t=void 0;let i=s.openSync(n,s.constants.O_RDONLY|s.constants.O_NOFOLLOW),o;try{o=s.fstatSync(i)}finally{s.closeSync(i)}let a=s.lstatSync(m.dirname(e));if(o.nlink!==1||o.dev!==a.dev||o.uid!==process.getuid?.())throw new Error("local-vault: unsafe temporary file");s.renameSync(n,e),s.chmodSync(e,384);let c=s.openSync(m.dirname(e),"r");try{s.fsyncSync(c)}finally{s.closeSync(c)}}catch(i){if(t!==void 0)try{s.closeSync(t)}catch{}try{s.unlinkSync(n)}catch{}throw i}return e}function B(e,r){s.mkdirSync(m.dirname(e),{recursive:!0,mode:448}),$(e);let n=m.join(m.dirname(e),`.${m.basename(e)}.${process.pid}.${v(6).toString("hex")}.tmp`);try{let t=s.openSync(n,s.constants.O_CREAT|s.constants.O_EXCL|s.constants.O_WRONLY|s.constants.O_NOFOLLOW,384);try{s.writeFileSync(t,String(r)),s.fsyncSync(t)}finally{s.closeSync(t)}s.renameSync(n,e),s.chmodSync(e,384);let i=s.openSync(m.dirname(e),"r");try{s.fsyncSync(i)}finally{s.closeSync(i)}}catch(t){try{s.unlinkSync(n)}catch{}throw t}}import{createHash as oe,randomBytes as ie,timingSafeEqual as se}from"node:crypto";var W=new Set(["evm","evm-swap","evm-bridge","btc","sol"]),G=Object.freeze({swap:5,bridge:5,perps:0,nft:0}),b=(e,r,n=256)=>{if(typeof e!="string"||!e||e.length>n)throw new Error(`envelope: bounded ${r} required`);return e},S=(e,r)=>{try{let n=BigInt(e);if(n<0n)throw 0;return n}catch{throw new Error(`envelope: ${r} must be a non-negative integer`)}},re=(e,r)=>{if(!Array.isArray(e)||e.length===0)throw new Error(`policy: ${r} allowlist is empty`);return e},h=(e,r,n)=>{if(!re(r,n).map(t=>String(t).toLowerCase()).includes(String(e).toLowerCase()))throw new Error(`policy: ${n} not allowed`)};function te(e,{localsWaiver:r=!1}={}){if(!(e in G))throw new Error("fee: unknown action");return r?0:G[e]}function C(e,r,{nowMs:n=Date.now()}={}){if(!e||e.version!==1)throw new Error("envelope: version 1 required");let t=b(e.surface,"surface",16);if(!W.has(t))throw new Error("envelope: unsupported public surface");let i=b(e.action,"action",32);if(h(t,r.surfaces,"surface"),h(i,r.actions,"action"),h(e.owner,r.owners,"owner"),h(e.destination,r.destinations,"destination"),!Number.isFinite(e.expiresAtMs)||e.expiresAtMs<=n||e.expiresAtMs-n>Number(r.maxTtlMs))throw new Error("policy: TTL outside bounds");if(!Number.isFinite(e.slippageBps)||e.slippageBps<0||e.slippageBps>Number(r.maxSlippageBps))throw new Error("policy: slippage exceeds cap");let o=e.artifact;if(!o||typeof o!="object"||Array.isArray(o))throw new Error("envelope: structured artifact required");if(t.startsWith("evm")){h(Number(o.chainId),r.chains,"chain");let c=String(o.data||"0x").slice(0,10).toLowerCase();if(h(c,r.selectors,"selector"),String(o.to).toLowerCase()!==String(e.destination).toLowerCase())throw new Error("envelope: destination mismatch");if(S(o.value??0,"value")>S(r.maxValueWei,"maxValueWei"))throw new Error("policy: value exceeds cap");let u=S(o.gasLimit,"gasLimit"),f=S(o.maxFeePerGas??o.gasPrice,"feePerGas");if(u>S(r.maxGasLimit,"maxGasLimit")||u*f>S(r.maxFeeWei,"maxFeeWei"))throw new Error("policy: gas/fee exceeds cap")}else if(t==="btc"){if(b(o.psbt,"PSBT",1e5),h(o.network,r.chains,"chain"),!Array.isArray(o.outputs)||o.outputs.length===0||o.outputs.some(c=>!c.address||S(c.valueSats,"output value")<0n))throw new Error("envelope: bounded BTC outputs required")}else if(t==="sol"){if(b(o.messageBase64,"Solana message",1e5),h(o.cluster,r.chains,"chain"),!Array.isArray(o.programIds)||o.programIds.length===0)throw new Error("envelope: Solana program ids required");for(let c of o.programIds)h(c,r.programs,"program")}else throw new Error("envelope: unsupported public surface");let a=te(i,{localsWaiver:e.fee?.waiver==="locals-only-verified"});if(Number(e.fee?.oracleFeeBps)!==a)throw new Error("fee: final artifact fee mismatch");return!0}var ne=Object.freeze([...W]);function Le(e={}){let r={};for(let n of ne){let t=e[n];if(t){if(typeof t.sign!="function"||typeof t.broadcast!="function")throw new Error(`adapter: ${n} requires sign and broadcast functions`);r[n]=Object.freeze({sign:(i,o)=>t.sign(structuredClone(i),structuredClone(o)),broadcast:(i,o,a)=>t.broadcast(i,structuredClone(o),structuredClone(a))})}}return Object.freeze(r)}function Te(e,r){let n=e?.surface||"evm",t=r?.[n];if(!t)throw new Error(`adapter: ${n} is not configured on this self-host`);return t}var N=e=>String(e||"").toLowerCase(),y=(e,r)=>{try{let n=BigInt(e??0);if(n<0n)throw 0;return n}catch{throw new Error(`policy: ${r} must be a non-negative integer`)}},A=(e,r,n,t=String)=>{if(!Array.isArray(r)||r.length===0)throw new Error(`policy: ${n} allowlist is empty`);if(!r.map(t).includes(t(e)))throw new Error(`policy: ${n} not allowed`)};function g(e){return oe("sha256").update(JSON.stringify(e)).digest("hex")}function ae(e){let r=String(e||"").toLowerCase();return!r.startsWith("0x095ea7b3")||r.length!==138?null:{spender:`0x${r.slice(34,74)}`,amount:BigInt(`0x${r.slice(74)}`)}}function H(e,r,{nowMs:n=Date.now()}={}){if(!e||!r)throw new Error("policy: artifact and policy required");A(Number(e.chainId),r.chains,"chain",Number),A(e.to,r.destinations,"destination",N),A(String(e.data||"0x").slice(0,10),r.selectors,"selector",a=>String(a).toLowerCase()),A(e.from,r.owners,"owner",N);let t=ae(e.data);if(String(e.data||"").slice(0,10).toLowerCase()==="0x095ea7b3"){if(!t)throw new Error("policy: malformed approval calldata");if(A(t.spender,r.spenders,"spender",N),t.amount>y(r.maxApproval,"maxApproval"))throw new Error("policy: approval exceeds cap")}if(y(e.value,"value")>y(r.maxValueWei,"maxValueWei"))throw new Error("policy: value exceeds cap");let i=y(e.gasLimit,"gasLimit");if(i>y(r.maxGasLimit,"maxGasLimit"))throw new Error("policy: gas exceeds cap");if(y(e.maxFeePerGas??e.gasPrice,"feePerGas")*i>y(r.maxFeeWei,"maxFeeWei"))throw new Error("policy: fee exceeds cap");if(!Number.isFinite(e.slippageBps)||e.slippageBps<0||e.slippageBps>Number(r.maxSlippageBps))throw new Error("policy: slippage attestation exceeds cap");if(!Number.isFinite(e.expiresAtMs)||e.expiresAtMs<=n)throw new Error("policy: artifact expired");return!0}var _=class{#e=new Map;constructor({now:r=Date.now}={}){this.now=r}issue({artifact:r,owner:n,ttlMs:t=6e4}){if(t<=0||t>12e4)throw new Error("confirmation: ttl out of range");let i=ie(32).toString("hex");return this.#e.set(i,{digest:g(r),owner:N(n),expiresAtMs:this.now()+t}),i}consume(r,n){let t=this.#e.get(String(r));if(!t)throw new Error("confirmation: used or unknown nonce");if(t.expiresAtMs<=this.now())throw this.#e.delete(String(r)),new Error("confirmation: expired nonce");let i=Buffer.from(t.digest,"hex"),o=Buffer.from(g(n),"hex");if(!se(i,o))throw new Error("confirmation: artifact mismatch");return this.#e.delete(String(r)),t}clear(){this.#e.clear()}};function ce(e={},r={}){let n={};for(let t of new Set([...Object.keys(e),...Object.keys(r)]))n[t]=(BigInt(r[t]??0)-BigInt(e[t]??0)).toString();return n}async function J(e,r,n){if(!n.isArmed())throw new Error("signer: disarmed");let t=e?.version===1&&e?.surface?e:null,i=t?t.artifact:e,o=typeof n.readPolicy=="function"?n.readPolicy():n.policy,a=o?.confirmationMode||"exact-human";if(n.autonomous===!0){if(n.env?.ORACLE_AUTONOMOUS_TRADING!=="1")throw new Error("signer: autonomous execution requires ORACLE_AUTONOMOUS_TRADING=1");if(typeof n.verifyTriggerAttestation!="function"||await n.verifyTriggerAttestation(t?.triggerAttestation,e)!==!0)throw new Error("signer: autonomous trigger attestation required")}else if(a==="exact-human")n.confirmations.consume(r,e);else if(a!=="auto-within-rails")throw new Error("signer: unsupported confirmation mode");let c=g(e),u=()=>typeof n.nowMs=="function"?n.nowMs():n.nowMs??Date.now();t?C(t,o,{nowMs:u()}):H(e,o,{nowMs:u()}),typeof n.reserveLedger=="function"&&n.reserveLedger(t||e,o);let f=await n.sign(i,t);if(!n.isArmed())throw new Error("signer: disarmed before broadcast");if(g(e)!==c)throw new Error("signer: artifact mutated after signing");o=typeof n.readPolicy=="function"?n.readPolicy():n.policy,t?C(t,o,{nowMs:u()}):H(e,o,{nowMs:u()});let l=await n.broadcast(f,i,t),d=l?.status,T=d===1||d==="0x1"?"success":d===0||d==="0x0"?"failed":"pending",k=l?.verifiedBefore??l?.before,I=l?.verifiedAfter??l?.after;return{prepared:e,signed:f,receipt:{transactionHash:l?.hash||l?.transactionHash||null,status:T,balanceDeltaVerified:!!(l?.verifiedBefore&&l?.verifiedAfter),delta:ce(k,I)}}}import ue from"node:http";import{timingSafeEqual as fe}from"node:crypto";var q=new Set(["127.0.0.1","::1","localhost"]),le=(e,r)=>{let n=Buffer.from(String(e)),t=Buffer.from(String(r));return n.length===t.length&&fe(n,t)},p=(e,r,n)=>{let t=JSON.stringify(n);e.writeHead(r,{"content-type":"application/json","cache-control":"no-store","content-length":Buffer.byteLength(t)}),e.end(t)},V=e=>new Promise((r,n)=>{let t=0,i=[],o=!1;e.on("data",a=>{t+=a.length,t>64*1024&&!o?(o=!0,n(new Error("request refused")),e.resume()):o||i.push(a)}),e.on("end",()=>{if(!o)try{r(JSON.parse(Buffer.concat(i).toString()||"{}"))}catch{n(new Error("request refused"))}}),e.on("error",n)});function Re(e={}){let r=e.host||"127.0.0.1";if(!q.has(r))throw new Error("signer: loopback bind required");if(String(e.token||"").length<32)throw new Error("signer: strong auth token required");let n=e.confirmations||new _,t=e.origin||`http://${r}`;return ue.createServer(async(o,a)=>{try{let c=String(o.headers.authorization||"").replace(/^Bearer /i,"");if(!le(c,e.token))return p(a,401,{error:"unauthorized"});let u=String(o.headers.host||"").replace(/^\[|\](?=:|$)/g,"").split(":")[0];if(!q.has(u))return p(a,403,{error:"host refused"});if(o.headers.origin&&o.headers.origin!==t)return p(a,403,{error:"origin refused"});if(o.method==="GET"&&o.url==="/status")return p(a,200,{ok:!0,armed:e.isArmed?.()===!0,sessionExpiresAtMs:e.sessionExpiresAtMs||null});if(o.method==="POST"&&o.url==="/disarm")return e.disarm?.(),n.clear(),p(a,200,{ok:!0,armed:!1});if(!["GET","POST"].includes(o.method))return p(a,405,{error:"request refused"});if(o.method==="POST"&&String(o.headers["content-type"]||"").split(";",1)[0].trim().toLowerCase()!=="application/json")return p(a,415,{error:"request refused"});if(o.method==="POST"&&o.url==="/confirm"){let f=await V(o),l=g(f.artifact);if(e.autonomous!==!0){if(typeof e.confirmArtifact!="function")return p(a,403,{error:"local human confirmation unavailable"});if(await e.confirmArtifact(f.artifact,l)!==!0)return p(a,400,{error:"exact human confirmation refused"})}return p(a,200,{confirmationNonce:n.issue({artifact:f.artifact,owner:f.artifact?.from,ttlMs:f.ttlMs})})}if(o.method==="POST"&&o.url==="/execute"){let f=await V(o),l=await J(f.artifact,f.confirmationNonce,{...e,confirmations:n});return p(a,200,l)}return p(a,404,{error:"not found"})}catch(c){return e.onError?.(String(c?.message||c)),p(a,400,{error:"request refused"})}})}import{createHmac as pe,timingSafeEqual as me}from"node:crypto";import{homedir as D}from"node:os";import{join as M}from"node:path";var z=process.env.ORACLE_PUBLIC_DESKTOP==="1",de=z?process.env.ORACLE_CONFIG_DIR||M(D(),".config","oracle"):M(D(),".config","oracle"),$e=z?de:M(D(),".config","mad-desk");var qe="0".repeat(64),Ve=Object.freeze({PREPARE:"exec.prepare",SIGN:"exec.sign",BROADCAST:"exec.broadcast",POLICY_REJECT:"policy.reject",AUTH_GRANT:"auth.grant",AUTH_OK:"auth.verify.ok",AUTH_FAIL:"auth.verify.fail"});function L(e){return e==null?"null":typeof e!="object"?JSON.stringify(e):Array.isArray(e)?"["+e.map(L).join(",")+"]":"{"+Object.keys(e).sort().map(n=>JSON.stringify(n)+":"+L(e[n])).join(",")+"}"}var ze=Promise.resolve();var he=864e5,E=(e,r)=>pe("sha256",r).update(L(e)).digest("hex"),P=(e,r)=>{let n=Buffer.from(String(e)),t=Buffer.from(String(r));return n.length===t.length&&me(n,t)};function ge(e,r){if(!e||typeof e!="object"||Array.isArray(e))throw new Error("policy: object required");return{policy:e,integrity:{algorithm:"hmac-sha256-canonical-json-v1",mac:E(e,r)}}}function we(e,r){if(e?.integrity?.algorithm!=="hmac-sha256-canonical-json-v1"||!P(e.integrity.mac,E(e.policy,r)))throw new Error("policy: integrity verification failed");return structuredClone(e.policy)}function er(e,r){let n=w(r),t;try{t=JSON.parse(w(e))}catch(i){throw new Error(`policy: cannot read sealed policy: ${i?.message||i}`)}return we(t,n)}function Se(e,r,n){try{let t=JSON.parse(w(e));if(!P(t?.integrity?.mac,E(t.ledger,r)))throw new Error("integrity verification failed");let i=t.ledger;if(!Number.isFinite(i?.windowStartMs)||!Array.isArray(i?.entries))throw new Error("invalid ledger");return n-i.windowStartMs>=he?{windowStartMs:n,entries:[]}:i}catch(t){if(t?.code==="ENOENT")return{windowStartMs:n,entries:[]};throw new Error(`ledger: corrupt or unreadable: ${t?.message||t}`)}}function Y(e,r){return e.reduce((n,t)=>n+BigInt(t[r]??0),0n)}function rr({file:e,keyFile:r,tradeId:n,value:t=0,notional:i=0,policy:o,nowMs:a=Date.now()}){if(!/^[A-Za-z0-9._:-]{1,128}$/.test(String(n||"")))throw new Error("ledger: bounded tradeId required");let c=w(r),u=Se(e,c,a);if(u.entries.some(I=>I.tradeId===n))throw new Error("ledger: replayed tradeId");let f=BigInt(t),l=BigInt(i),d=BigInt(o.maxDailyValueWei),T=BigInt(o.maxDailyNotional??o.maxDailyValueWei),k=BigInt(o.maxPerTrade??o.maxValueWei);if(f<0n||l<0n||l>k)throw new Error("ledger: per-trade cap exceeded");if(Y(u.entries,"value")+f>d||Y(u.entries,"notional")+l>T)throw new Error("ledger: daily cap exceeded");return u.entries.push({tradeId:String(n),value:f.toString(),notional:l.toString(),atMs:a}),B(e,JSON.stringify({ledger:u,integrity:{algorithm:"hmac-sha256-canonical-json-v1",mac:E(u,c)}})+`
3
+ `),structuredClone(u)}function tr(e,r,n){let t=w(r);B(e,JSON.stringify(ge(n,t),null,2)+`
4
+ `)}function nr(e,r,n){let t={triggerId:String(r.triggerId),issuedAtMs:Number(r.issuedAtMs),expiresAtMs:Number(r.expiresAtMs),artifactDigest:g(e)};return{...t,algorithm:"hmac-sha256-canonical-json-v1",mac:E(t,n)}}function or(e,r,n,t=Date.now()){if(e?.algorithm!=="hmac-sha256-canonical-json-v1"||!/^[A-Za-z0-9._:-]{1,128}$/.test(String(e?.triggerId||""))||!Number.isFinite(e.issuedAtMs)||!Number.isFinite(e.expiresAtMs)||e.issuedAtMs>t||e.expiresAtMs<=t||e.expiresAtMs-e.issuedAtMs>12e4)return!1;let i={triggerId:e.triggerId,issuedAtMs:e.issuedAtMs,expiresAtMs:e.expiresAtMs,artifactDigest:g(r)};return P(e.mac,E(i,w(n)))}import{spawnSync as ye}from"node:child_process";function ar(e="oracle-local-signer",r=process.env.USER||process.env.USERNAME||"oracle"){let n,t;if(process.platform==="darwin")n="/usr/bin/security",t=["find-generic-password","-s",e,"-a",r,"-w"];else if(process.platform==="linux")n="secret-tool",t=["lookup","service",e,"account",r];else throw new Error("signer: OS credential lookup is supported on macOS and Linux; use a protected passphrase file on this platform");let i=ye(n,t,{encoding:"utf8",stdio:["ignore","pipe","ignore"],env:{PATH:process.env.PATH,HOME:process.env.HOME,USER:process.env.USER,LOGNAME:process.env.LOGNAME,DBUS_SESSION_BUS_ADDRESS:process.env.DBUS_SESSION_BUS_ADDRESS}}),o=String(i.stdout||"").replace(/[\r\n]+$/,"");if(i.status!==0||o.length<12)throw new Error("signer: OS credential passphrase unavailable");return o}export{_ as ConfirmationStore,ne as PUBLIC_SIGNER_SURFACES,x as SCRYPT,R as VAULT_MAGIC,F as VAULT_VERSION,g as artifactDigest,H as assertExactPolicy,Re as createSignerServer,Le as createSurfaceAdapters,nr as createTriggerAttestation,ve as decryptVault,Oe as encryptVault,J as executeConfirmedArtifact,we as openPolicy,te as publicFeeBps,ar as readCredentialPassphrase,w as readProtectedSecretFile,er as readSealedPolicy,be as readVault,rr as reserveLedger,ge as sealPolicy,Te as surfaceAdapterFor,C as validateSurfaceEnvelope,or as verifyTriggerAttestation,B as writeProtectedTextAtomic,tr as writeSealedPolicy,Ne as writeVaultAtomic};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@oracle-agent/oracle",
3
- "version": "0.23.0",
4
- "description": "Oracle: standalone prepare-only multichain agent control plane. Runs its own agent loop, or plugs into any MCP-compatible harness. Policy-bounded intents for a user-signed wallet; the public package never takes your key.",
3
+ "version": "0.24.0",
4
+ "description": "Oracle: standalone multichain agent control plane with an optional encrypted, loopback-only self-hosted signer.",
5
5
  "license": "BUSL-1.1",
6
6
  "type": "module",
7
7
  "publishConfig": {
@@ -58,7 +58,8 @@
58
58
  "./watch": "./dist/watch-preferences.mjs",
59
59
  "./signals": "./dist/signals/index.mjs",
60
60
  "./strategy": "./dist/strategy/index.mjs",
61
- "./agent-grants": "./dist/public-api/agent-grants.mjs"
61
+ "./agent-grants": "./dist/public-api/agent-grants.mjs",
62
+ "./local-signer": "./dist/local-signer/index.mjs"
62
63
  },
63
64
  "dependencies": {
64
65
  "@msgpack/msgpack": "^3.1.3",
@@ -28,10 +28,10 @@ section{padding-top:72px;scroll-margin-top:90px}.sub{color:var(--muted);line-hei
28
28
  <header><p class="eyebrow">Public release</p><h1>Install Oracle.<br><em>Your wallet signs.</em></h1><p class="lede">The CLI, desktop beta, source, research tools, and unsigned transaction preparation are public to everyone. No wallet connection or NFT is required to download or run Oracle.</p></header>
29
29
  <aside class="policy"><h2>Locals Only means 0% Oracle fees</h2><p>A Locals Only NFT waives the <b>Oracle integrator fee</b>. It does not unlock the product, arm execution, waive provider or network costs, or change the keyless prepare-only custody boundary.</p></aside>
30
30
  <section id="cli"><p class="eyebrow">Oracle CLI</p><h2>Install with curl</h2><p class="sub">One line. Linux and macOS. Requires Node 20.19+ (the script checks and tells you how to get it). Installs into <code>~/.local</code> — no sudo, no global npm.</p><div class="install"><div class="cmd"><code id="cmd">curl -fsSL https://oracle.demi.la/install.sh | bash</code><button class="copy" id="copy" type="button">Copy</button></div><div class="meta"><span>curl install</span><span>keyless</span><span>prepare-only</span><span>user prefix</span></div></div><p class="sub" style="margin-top:18px">npm still works if you prefer: <code>npm i -g @oracle-agent/oracle</code></p></section>
31
- <section id="desktop"><p class="eyebrow">Desktop beta · 0.4.2</p><h2>Native installers</h2><p class="sub">Each installer bundles the same public runtime. Download directly, then verify it against the published SHA-256 manifest.</p><div class="artifacts">
32
- <div class="artifact" data-artifact="Oracle-0.4.2.AppImage"><div><h3>Linux</h3><small>AppImage · x64</small></div><div class="artifact-meta"><span class="build">Oracle 0.4.2 beta</span></div><code class="hash" data-hash>checksum loading</code><a class="dl-btn" href="/downloads/artifacts/Oracle-0.4.2.AppImage" download>Download</a></div>
33
- <div class="artifact" data-artifact="Oracle-0.4.2-arm64.dmg"><div><h3>macOS</h3><small>DMG · Apple silicon</small></div><div class="artifact-meta"><span class="build">Oracle 0.4.2 beta</span></div><code class="hash" data-hash>checksum loading</code><a class="dl-btn" href="/downloads/artifacts/Oracle-0.4.2-arm64.dmg" download>Download</a></div>
34
- <div class="artifact" data-artifact="Oracle-Setup-0.4.2.exe"><div><h3>Windows</h3><small>NSIS installer · x64</small></div><div class="artifact-meta"><span class="build">Oracle 0.4.2 beta</span></div><code class="hash" data-hash>checksum loading</code><a class="dl-btn" href="/downloads/artifacts/Oracle-Setup-0.4.2.exe" download>Download</a></div>
31
+ <section id="desktop"><p class="eyebrow">Desktop beta · 0.4.3</p><h2>Native installers</h2><p class="sub">Each installer bundles the same public runtime. Download directly, then verify it against the published SHA-256 manifest.</p><div class="artifacts">
32
+ <div class="artifact" data-artifact="Oracle-0.4.3.AppImage"><div><h3>Linux</h3><small>AppImage · x64</small></div><div class="artifact-meta"><span class="build">Oracle 0.4.3 beta</span></div><code class="hash" data-hash>checksum loading</code><a class="dl-btn" href="/downloads/artifacts/Oracle-0.4.3.AppImage" download>Download</a></div>
33
+ <div class="artifact" data-artifact="Oracle-0.4.3-arm64.dmg"><div><h3>macOS</h3><small>DMG · Apple silicon</small></div><div class="artifact-meta"><span class="build">Oracle 0.4.3 beta</span></div><code class="hash" data-hash>checksum loading</code><a class="dl-btn" href="/downloads/artifacts/Oracle-0.4.3-arm64.dmg" download>Download</a></div>
34
+ <div class="artifact" data-artifact="Oracle-Setup-0.4.3.exe"><div><h3>Windows</h3><small>NSIS installer · x64</small></div><div class="artifact-meta"><span class="build">Oracle 0.4.3 beta</span></div><code class="hash" data-hash>checksum loading</code><a class="dl-btn" href="/downloads/artifacts/Oracle-Setup-0.4.3.exe" download>Download</a></div>
35
35
  </div><p class="platform-note">Checksums: <a class="checksum" href="/downloads/artifacts/SHA256SUMS.txt">SHA256SUMS.txt</a>. Beta installers may trigger macOS Gatekeeper or Windows SmartScreen when a build is not notarized or CA-signed. Oracle never asks for a private key, seed phrase, or wallet approval.</p></section>
36
36
  </main>
37
37
  <footer><div class="nav-inner"><span>oracle · locals only labs</span><span>public / self-custody / prepare-only</span></div></footer>
@@ -1798,7 +1798,7 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
1798
1798
  <img src="assets/desktop-app.jpg" width="1736" height="959" loading="lazy" decoding="async" alt="Oracle desktop app showing the specialist mesh, with Portfolio, Approvals, Prepare, CLI, Farming Methods, Agent Connect, Receipts, Campaigns and Routes panes.">
1799
1799
  <figcaption>Portfolio, approvals, prepare, farming, receipts and routes in one pane.</figcaption>
1800
1800
  </figure>
1801
- <div class="os-dl"><a class="os-link" href="/downloads/artifacts/Oracle-0.4.2-arm64.dmg">macOS</a><a class="os-link" href="/downloads/artifacts/Oracle-0.4.2.AppImage">Linux</a><a class="os-link" href="/downloads/artifacts/Oracle-Setup-0.4.2.exe">Windows</a></div>
1801
+ <div class="os-dl"><a class="os-link" href="/downloads/artifacts/Oracle-0.4.3-arm64.dmg">macOS</a><a class="os-link" href="/downloads/artifacts/Oracle-0.4.3.AppImage">Linux</a><a class="os-link" href="/downloads/artifacts/Oracle-Setup-0.4.3.exe">Windows</a></div>
1802
1802
  </div>
1803
1803
  </div>
1804
1804
  </section>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0"><dict>
4
+ <key>Label</key><string>la.oracle.local-signer</string>
5
+ <key>ProgramArguments</key><array><string>ORACLE_BIN_PATH</string><string>signer</string><string>--credential-service</string><string>oracle-local-signer</string><string>--session-seconds</string><string>120</string></array>
6
+ <key>RunAtLoad</key><false/><key>KeepAlive</key><false/>
7
+ </dict></plist>
@@ -0,0 +1,5 @@
1
+ # Windows service template. Windows OS-credential retrieval is not currently
2
+ # supported by the public CLI; use an ACL-protected passphrase file owned by the
3
+ # service account. Do not put the passphrase in this script or an environment variable.
4
+ param([Parameter(Mandatory=$true)][string]$PassphraseFile)
5
+ & oracle signer --passphrase-file $PassphraseFile --session-seconds 120
@@ -0,0 +1,16 @@
1
+ [Unit]
2
+ Description=Oracle bounded local signer
3
+ After=network-online.target
4
+
5
+ [Service]
6
+ Type=simple
7
+ ExecStart=%h/.local/bin/oracle signer --credential-service oracle-local-signer --session-seconds 120
8
+ Restart=no
9
+ NoNewPrivileges=true
10
+ PrivateTmp=true
11
+ ProtectSystem=strict
12
+ ProtectHome=read-only
13
+ ReadWritePaths=%h/.config/oracle
14
+
15
+ [Install]
16
+ WantedBy=default.target