@oracle-agent/oracle 0.35.21 → 0.35.22
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.
- package/README.md +24 -1
- package/dist/agent-lifecycle.mjs +3 -0
- package/dist/assets/skills/oracle-desk-product/SKILL.md +1 -1
- package/dist/bin/desk-server.mjs +36 -36
- package/dist/bin/oracle-mev-arb-shadow.mjs +4 -4
- package/dist/bin/oracle-mev-shadow.mjs +6 -6
- package/dist/bin/oracle-route.mjs +11 -11
- package/dist/bin/oracle-scan.mjs +15 -15
- package/dist/bin/oracle.mjs +19 -10
- package/dist/cli/commands/chat.mjs +1 -1
- package/dist/cli/commands/context.mjs +16 -0
- package/dist/cli/commands/doctor.mjs +5 -5
- package/dist/cli/commands/eval.mjs +89 -89
- package/dist/cli/commands/lifecycle.mjs +17 -0
- package/dist/cli/commands/model.mjs +1 -1
- package/dist/cli/commands/quickstart.mjs +5 -5
- package/dist/cli/commands/sign.mjs +1 -1
- package/dist/cli/commands/signer.mjs +22 -22
- package/dist/cli/commands/snipe.mjs +4 -4
- package/dist/cli/commands/swap.mjs +4 -4
- package/dist/cli/commands/venues.mjs +2 -2
- package/dist/context-graph.mjs +3 -0
- package/dist/data/desk-data.mjs +34 -34
- package/dist/data/providers/lp-destination-discovery.mjs +6 -0
- package/dist/data/providers/lp-liquidity-ranker.mjs +1 -0
- package/dist/index.mjs +50 -48
- package/dist/local-signer/anvil-attestation-worker.mjs +1 -1
- package/dist/local-signer/runtime.mjs +1 -1
- package/dist/router/index.mjs +3 -3
- package/dist/router/prepare-bridge.mjs +2 -2
- package/dist/scanner/index.mjs +4 -4
- package/dist/tenant-rbac.mjs +1 -1
- package/dist/workflow-telemetry.mjs +1 -1
- package/package.json +5 -1
- package/public/eval-report.json +1 -1
- package/public/oracle-splash/brand/liquidlaunch.webp +0 -0
- package/public/oracle-splash/brand/markets.webp +0 -0
- package/public/oracle-splash/brand/motion.webp +0 -0
- package/public/oracle-splash/brand/nest.webp +0 -0
- package/public/oracle-splash/brand/outcome.webp +0 -0
- package/public/oracle-splash/brand/silhouette.webp +0 -0
- package/public/oracle-splash/brand/tradexyz.webp +0 -0
- package/public/oracle-splash/index.html +9 -9
- package/server.json +2 -2
package/README.md
CHANGED
|
@@ -122,6 +122,29 @@ Three properties define it:
|
|
|
122
122
|
|
|
123
123
|
Default posture is `DISARMED`.
|
|
124
124
|
|
|
125
|
+
### Context and lifecycle governance
|
|
126
|
+
|
|
127
|
+
Oracle includes the two organization-scale governance layers directly in the
|
|
128
|
+
public self-hosted package:
|
|
129
|
+
|
|
130
|
+
- `@oracle-agent/oracle/context-graph`: tenant/domain-scoped nodes and edges with
|
|
131
|
+
mandatory caller-asserted provenance explicitly marked `unverified`, evidence
|
|
132
|
+
hashes, freshness TTLs, stale exclusion, trusted domain assignments and RBAC,
|
|
133
|
+
immutable revision history, private atomic storage, and a hash chain that
|
|
134
|
+
detects corruption and un-rehashed edits. The local hash chain is not an
|
|
135
|
+
external anti-rollback anchor against a same-UID writer.
|
|
136
|
+
- `@oracle-agent/oracle/agent-lifecycle`: inventory for agents, tools, workflows,
|
|
137
|
+
first-class expiring credentials, and external credential references, with
|
|
138
|
+
last-use/eval health, credential expiry,
|
|
139
|
+
inactivity retirement, regression quarantine, and owner-reviewed reactivation.
|
|
140
|
+
|
|
141
|
+
Use `oracle context --help` and `oracle lifecycle --help`, or import the APIs.
|
|
142
|
+
These are local governance surfaces: they add no public HTTP endpoint, expose no
|
|
143
|
+
credential-value field, reject recognized secret-shaped input, and grant no signing authority. Public self-hosted and
|
|
144
|
+
operator/admin installations use the same capabilities, safety checks, and
|
|
145
|
+
execution flow; operator fee configuration is the product-rate difference, not
|
|
146
|
+
a capability fork.
|
|
147
|
+
|
|
125
148
|
## Why it's different
|
|
126
149
|
|
|
127
150
|
The differentiators are **policy, custody, and receipts** — not a smarter chat
|
|
@@ -252,7 +275,7 @@ known answer. This matters: the canonical QuoterV2 address also has bytecode on
|
|
|
252
275
|
Base, but does not price that chain's pairs. A codesize check would have
|
|
253
276
|
allowlisted the wrong contract.
|
|
254
277
|
|
|
255
|
-
**
|
|
278
|
+
**125 provider modules** and **537 operations** in the read/quote catalog, covering **220 unique
|
|
256
279
|
protocols/venues** across EVM, Solana, and Bitcoin (115 EVM + cross-chain, 98
|
|
257
280
|
Solana venues backed by 101 verified Jupiter program IDs, 6 Bitcoin surfaces).
|
|
258
281
|
One module can cover many protocols: the Jupiter module alone routes 98 Solana
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{createHash as je}from"node:crypto";var ze=1,Le=1,$e=1;var qe=Object.freeze(["owner","operator","agent","viewer"]),Me=Object.freeze(["tenant","config","policy","grant","workflow","trade","receipt","audit","telemetry","context","lifecycle"]),de=Object.freeze({read:"read",create:"create",update:"update",delete:"delete",manage:"manage",prepare:"prepare",cancel:"cancel",export:"export",approve:"approve"}),Ye=Object.freeze(["owner"]),O=Object.freeze({ALLOW_ROLE_PERMISSION:"allow.role_permission",DENY_MISSING_CONTEXT:"deny.missing_context",DENY_INVALID_CONTEXT:"deny.invalid_context",DENY_INVALID_REQUEST:"deny.invalid_request",DENY_UNKNOWN_RESOURCE:"deny.unknown_resource",DENY_UNKNOWN_ACTION:"deny.unknown_action",DENY_UNBOUND_OBJECT:"deny.unbound_object",DENY_TENANT_MISMATCH:"deny.tenant_mismatch",DENY_RESOURCE_MISMATCH:"deny.resource_mismatch",DENY_ROLE_PERMISSION:"deny.role_permission",DENY_POLICY_NOT_APPROVER:"deny.policy_not_approver"}),Pe=new Set(qe),Z=new Set(Me),He=new Set(Object.values(de)),Ue=new Set(["user","service","local-owner"]),Ve=new Set(["verified-session","service-credential","desktop-session","owner-arm-token","local-owner"]),B=/^[A-Za-z0-9][A-Za-z0-9._:@-]{0,127}$/,le="tob1",Fe=new WeakSet;var ue=Object.freeze({owner:Object.freeze(["tenant:read","tenant:manage","config:read","config:manage","policy:read","policy:manage","grant:read","grant:create","grant:update","grant:delete","grant:manage","workflow:read","workflow:create","workflow:update","workflow:delete","workflow:cancel","workflow:approve","trade:read","trade:prepare","receipt:read","receipt:export","audit:read","audit:export","telemetry:read","telemetry:create","telemetry:export","context:read","context:create","context:update","context:delete","context:manage","context:export","lifecycle:read","lifecycle:create","lifecycle:update","lifecycle:delete","lifecycle:manage","lifecycle:approve","lifecycle:export"]),operator:Object.freeze(["tenant:read","config:read","policy:read","grant:read","workflow:read","workflow:create","workflow:update","workflow:cancel","trade:read","trade:prepare","receipt:read","audit:read","telemetry:read","telemetry:create","context:read","context:create","context:update","context:delete","lifecycle:read","lifecycle:create","lifecycle:update","lifecycle:manage"]),agent:Object.freeze(["tenant:read","config:read","policy:read","grant:read","workflow:read","workflow:create","workflow:update","trade:read","trade:prepare","receipt:read","telemetry:create","context:read","context:create","context:update","lifecycle:read"]),viewer:Object.freeze(["tenant:read","config:read","grant:read","workflow:read","trade:read","receipt:read","audit:read","telemetry:read","context:read","lifecycle:read"])}),Ot=Object.freeze(Object.fromEntries(Object.entries(ue).map(([e,t])=>[e,Object.freeze([...t])]))),T=class extends Error{constructor(t,n="invalid-context"){super(t),this.name="TenantContextError",this.code=n}};function se(e){return!!e&&typeof e=="object"&&!Array.isArray(e)&&Object.getPrototypeOf(e)===Object.prototype}function W(e){if(e&&typeof e=="object"&&!Object.isFrozen(e)){Object.freeze(e);for(let t of Object.values(e))W(t)}return e}function G(e){return e===null||typeof e!="object"?JSON.stringify(e):Array.isArray(e)?`[${e.map(G).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${G(e[t])}`).join(",")}}`}function fe(e){return je("sha256").update(G(e)).digest("hex")}function Je(e,t){return e.length===t.length&&e.every((n,r)=>n===t[r])}function Be(e){if(!se(e)||e.schemaVersion!==ze||!B.test(e.tenantId||"")||typeof e.localCompatibility!="boolean")return!1;let t=e.actor;if(!se(t)||t.schemaVersion!==Le||!B.test(t.actorId||"")||!Ue.has(t.actorType)||!Ve.has(t.authSource)||!Array.isArray(t.roles)||t.roles.length===0)return!1;let n=[...new Set(t.roles)].sort();return n.every(r=>Pe.has(r))&&Je(n,t.roles)}function M(e){return Fe.has(e)&&Be(e)}function Ge(e){if(!M(e))throw new T("a resolved tenant context is required","unresolved-context");return e}function Y(e){return Buffer.from(e,"utf8").toString("base64url")}function J(e,t){if(!e||!/^[A-Za-z0-9_-]+$/.test(e))throw new T(`${t} binding is invalid`,"invalid-object-binding");let n=Buffer.from(e,"base64url").toString("utf8");if(!n||Y(n)!==e)throw new T(`${t} binding is non-canonical`,"invalid-object-binding");return n}function pe(e){let t=String(e??"").trim();if(!t||t.length>256||/[\u0000-\u001f\u007f]/.test(t))throw new T("objectId is invalid","invalid-object-id");return t}function ye(e,t,n){Ge(e);let r=String(t??"").trim();if(!Z.has(r))throw new T("resource is unknown","unknown-resource");let i=pe(n);return`${le}.${Y(e.tenantId)}.${Y(r)}.${Y(i)}`}function Ze(e){let t=String(e??""),n=t.split(".");if(n.length!==4||n[0]!==le)throw new T("tenant-bound object id required","unbound-object");let r=J(n[1],"tenant"),i=J(n[2],"resource"),s=J(n[3],"object");if(!B.test(r)||!Z.has(i))throw new T("tenant-bound object id is invalid","invalid-object-binding");return pe(s),W({schemaVersion:1,tenantId:r,resource:i,objectId:s,boundId:t})}function We(e){if(typeof e!="string"||!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(e))return null;let t=Date.parse(e);return Number.isFinite(t)&&new Date(t).toISOString()===e?e:null}function ce(e){let t={...e,decisionId:fe(e)};return W(t)}function Ke({context:e,resource:t,action:n,objectId:r=null,decidedAt:i}={}){let s=We(i),p={schemaVersion:$e,recordType:"tenant.access-decision",decidedAt:s,tenantId:M(e)?e.tenantId:null,actor:M(e)?{actorId:e.actor.actorId,actorType:e.actor.actorType,authSource:e.actor.authSource,roles:[...e.actor.roles]}:null,request:{resource:typeof t=="string"?t:null,action:typeof n=="string"?n:null,objectRefHash:r==null?null:fe(String(r))}},f=v=>ce({...p,allowed:!1,outcome:"deny",reason:v});if(e==null)return f(O.DENY_MISSING_CONTEXT);if(!M(e))return f(O.DENY_INVALID_CONTEXT);if(!s)return f(O.DENY_INVALID_REQUEST);if(!Z.has(t))return f(O.DENY_UNKNOWN_RESOURCE);if(!He.has(n))return f(O.DENY_UNKNOWN_ACTION);if(r!=null){let v;try{v=Ze(r)}catch{return f(O.DENY_UNBOUND_OBJECT)}if(v.tenantId!==e.tenantId)return f(O.DENY_TENANT_MISMATCH);if(v.resource!==t)return f(O.DENY_RESOURCE_MISMATCH)}if(n===de.approve&&!e.actor.roles.some(S=>Ye.includes(S)))return f(O.DENY_ROLE_PERMISSION);let b=`${t}:${n}`,N=e.actor.roles.some(v=>ue[v]?.includes(b));return ce({...p,allowed:N,outcome:N?"allow":"deny",reason:N?O.ALLOW_ROLE_PERMISSION:O.DENY_ROLE_PERMISSION})}function he(e){let t=Ke(e);if(!t.allowed){let n=new T(`tenant access denied: ${t.reason}`,"access-denied");throw n.decision=t,n}return t}import{createHash as Xe,randomUUID as Qe}from"node:crypto";import{chmodSync as et,closeSync as H,constants as z,existsSync as K,fsyncSync as X,lstatSync as me,mkdirSync as we,openSync as Q,readFileSync as tt,renameSync as nt,unlinkSync as ee,writeFileSync as Ae}from"node:fs";import{dirname as ve,resolve as ge}from"node:path";function te(e){return e===null||typeof e!="object"?JSON.stringify(e):Array.isArray(e)?`[${e.map(te).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${te(e[t])}`).join(",")}}`}function k(e){return Xe("sha256").update(te(e)).digest("hex")}function _(e){if(e&&typeof e=="object"&&!Object.isFrozen(e)){Object.freeze(e);for(let t of Object.values(e))_(t)}return e}function rt(e,t,n){let r=ge(e),i=ve(r);if(we(i,{recursive:!0,mode:448}),K(r)){let p=me(r);if(!p.isFile()||p.isSymbolicLink())throw n("state path must be a regular non-symlink file","unsafe-file")}let s=`${r}.${Qe()}.tmp`;try{Ae(s,`${JSON.stringify(t)}
|
|
2
|
+
`,{encoding:"utf8",mode:384,flag:"wx"});let p=Q(s,z.O_RDONLY);try{X(p)}finally{H(p)}nt(s,r),et(r,384);let f;try{f=Q(i,z.O_RDONLY),X(f)}finally{f!==void 0&&H(f)}}catch(p){try{K(s)&&ee(s)}catch{}throw p}}function ot(e,t,n){if(!e||typeof e!="object"||Array.isArray(e))throw n("state must be an object","integrity-failed");if(e.schemaVersion!==t||!Array.isArray(e.events))throw n("state schema is invalid","integrity-failed");let r=null;for(let p=0;p<e.events.length;p+=1){let f=e.events[p];if(!f||typeof f!="object"||Array.isArray(f))throw n("event is invalid","integrity-failed");if(f.record&&typeof f.record.recordHash=="string"){let{recordHash:v,...S}=f.record;if(k(S)!==v)throw n("record hash integrity failed; state may be tampered","integrity-failed")}let{eventHash:b,...N}=f;if(f.sequence!==p+1||f.previousEventHash!==r||k(N)!==b)throw n("event hash chain integrity failed; state may be tampered","integrity-failed");r=b}let{stateHash:i,...s}=e;if(k(s)!==i)throw n("state hash integrity failed; state may be tampered","integrity-failed");return e}function P(e,t,n){if(!K(e)){let s={schemaVersion:t,events:[]};return{...s,stateHash:k(s)}}let r=me(e);if(!r.isFile()||r.isSymbolicLink())throw n("state path must be a regular non-symlink file","unsafe-file");if((r.mode&511)!==384)throw n("state file permissions must be 0600","unsafe-permissions");let i;try{i=JSON.parse(tt(e,"utf8"))}catch{throw n("state JSON is malformed","integrity-failed")}return ot(i,t,n)}function it(e,t,n){let r=`${e}.lock`,i;try{i=Q(r,z.O_CREAT|z.O_EXCL|z.O_WRONLY,384),Ae(i,`${JSON.stringify({pid:process.pid,createdAt:new Date().toISOString()})}
|
|
3
|
+
`,"utf8"),X(i)}catch(s){if(i!==void 0){H(i);try{ee(r)}catch{}}throw s?.code==="EEXIST"?t("state is locked by another writer","state-locked"):s}try{return n()}finally{try{H(i)}finally{ee(r)}}}function Se({path:e,schemaVersion:t,fail:n}){if(typeof e!="string"||e.length<1||e.length>4096)throw n("bounded state path required","invalid-path");if(typeof n!="function")throw new TypeError("fail factory required");let r=ge(e);we(ve(r),{recursive:!0,mode:448});let i=P(r,t,n);function s(){let f={schemaVersion:t,events:i.events};i={...f,stateHash:k(f)},rt(r,i,n)}function p({tenantId:f,recordType:b,recordId:N,operation:v,occurredAt:S,record:C,expectedRecordHash:V=null}){return it(r,n,()=>{if(i=P(r,t,n),(([...i.events].reverse().find(x=>x.record?.boundId===C?.boundId)??null)?.record?.recordHash??null)!==V)throw n("record changed concurrently; retry from current state","state-conflict");if(C&&typeof C.recordHash=="string"){let{recordHash:x,...F}=C;if(k(F)!==x)throw n("record hash is inconsistent","integrity-failed")}let $={sequence:i.events.length+1,previousEventHash:i.events.at(-1)?.eventHash??null,tenantId:f,recordType:b,recordId:N,operation:v,occurredAt:S,record:C},q=_({...$,eventHash:k($)});return i={...i,events:[...i.events,q]},s(),q})}return Object.freeze({append:p,events:()=>(i=P(r,t,n),i.events.map(f=>structuredClone(f))),verify:()=>{try{return i=P(r,t,n),{ok:!0,count:i.events.length,stateHash:i.stateHash}}catch(f){return{ok:!1,reason:f?.code||"integrity-failed"}}},path:r})}var at=Object.freeze([/(?:^|\s)Bearer\s+\S+/i,/-----BEGIN [A-Z ]*PRIVATE KEY-----/i,/\b(?:sk-|xprv|gh[pousr]_|github_pat_|AKIA|ASIA)[A-Za-z0-9_/-]{12,}\b/i,/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/,/\b(?:0x)?[0-9a-f]{64}\b/i,/(?<![1-9A-HJ-NP-Za-km-z])[59KLc][1-9A-HJ-NP-Za-km-z]{50,51}(?![1-9A-HJ-NP-Za-km-z])/,/(?<![1-9A-HJ-NP-Za-km-z])[1-9A-HJ-NP-Za-km-z]{64,88}(?![1-9A-HJ-NP-Za-km-z])/]),st=new Set(["apikey","key","token","accesstoken","secret","password","passwd","auth","authorization","bearer","signertoken","credential","credentials","clientsecret","privatekey","xapikey","accesskey","refreshtoken"]),ct=Object.freeze(["apikey","accesskey","privatekey","clientsecret","accesstoken","refreshtoken","signertoken","credential","password","passwd","authorization","bearer","secret","token"]);function dt(e){return String(e??"").replace(/[^a-z0-9]/gi,"").toLowerCase()}function lt(e){let t;try{t=new URL(e)}catch{return!1}if(t.username||t.password)return!0;for(let n of t.searchParams.keys()){let r=dt(n);if(st.has(r)||ct.some(i=>r.includes(i)))return!0}return!1}function Ee(e){try{let t=decodeURIComponent(e);return t===e?null:t}catch{return null}}var ut=/[a-z][a-z0-9+.-]{1,15}(?::\/\/|%3a%2f%2f)\S+/gi;function ft(e){return e.replace(/[),.;:!?'"\]}]+$/,"")}function pt(e){let t=e.match(ut)||[];for(let n of t){let r=ft(n),i=Ee(r),s=i?Ee(i):null;for(let p of[r,i,s])if(p&<(p))return!0}return!1}function ne(e){return typeof e!="string"||e.length===0?!1:at.some(t=>t.test(e))?!0:pt(e)}var yt="oracle.agent-lifecycle/1",ht="oracle.agent-lifecycle-state/1",mt=Object.freeze(["agent","tool","workflow","credential"]),wt=Object.freeze(["active","quarantined","retired","pending_reactivation"]),U=Object.freeze({inactivityMs:2160*60*60*1e3,maxEvalAgeMs:720*60*60*1e3}),At=50,Ie=100,be=new Set(mt),Re=/^[A-Za-z0-9][A-Za-z0-9._:@/-]{0,127}$/,vt=512,Oe=300*1e3,gt=["authorization","apikey","accesskey","cookie","password","passphrase","secret","token","privatekey","seed","mnemonic","keystore","signature"],re=class extends Error{constructor(t,n="invalid-agent-lifecycle"){super(`agent-lifecycle: ${t}`),this.name="AgentLifecycleError",this.code=n}};function l(e,t){return new re(e,t)}function R(e,t){if(typeof e!="string")throw l(`${t} must be an ISO timestamp`,"invalid-time");let n=Date.parse(e);if(!Number.isFinite(n)||new Date(n).toISOString()!==e)throw l(`${t} must be an ISO timestamp`,"invalid-time");return e}function E(e,t){let n=String(e??"").trim();if(ne(n))throw l(`${t} contains secret-shaped material`,"secret-material");if(!Re.test(n))throw l(`${t} is invalid`,"invalid-id");return n}function L(e,t,{required:n=!0}={}){let r=String(e??"").trim();if(n&&!r||r.length>vt||/[\u0000-\u001f\u007f]/.test(r)||ne(r))throw l(`${t} is invalid or contains secret-shaped material`,"invalid-text");return r}function St(e={}){if(!e||typeof e!="object"||Array.isArray(e)||Object.getPrototypeOf(e)!==Object.prototype)throw l("metadata must be a plain object","invalid-metadata");let t=Object.keys(e).sort();if(t.length>24)throw l("metadata field limit exceeded","metadata-limit");let n={};for(let r of t){if(!/^[A-Za-z][A-Za-z0-9_.-]{0,47}$/.test(r))throw l(`metadata key ${r} is invalid`,"invalid-metadata");let i=r.replace(/[^a-z0-9]/gi,"").toLowerCase();if(gt.some(p=>i.includes(p)))throw l(`metadata key ${r} is forbidden because it may contain a secret`,"secret-material");let s=e[r];if(typeof s=="string")n[r]=L(s,`metadata.${r}`,{required:!1});else if(typeof s=="boolean"||s===null)n[r]=s;else if(typeof s=="number"&&Number.isFinite(s))n[r]=s;else throw l(`metadata.${r} must be a scalar`,"invalid-metadata")}return n}function _e(e=[]){if(!Array.isArray(e)||e.length>32)throw l("credentialRefs must be a bounded array","invalid-credentials");let t=new Set;return e.map(n=>{if(!n||typeof n!="object"||Array.isArray(n))throw l("credential reference is invalid","invalid-credentials");let r=Object.keys(n).filter(s=>!["ref","expiresAt"].includes(s));if(r.length)throw l(`credential reference has unknown fields: ${r.sort().join(", ")}`,"invalid-credentials");let i=E(L(n.ref,"credential ref"),"credential ref");if(t.has(i))throw l("credential references must be unique","invalid-credentials");return t.add(i),{ref:i,expiresAt:R(n.expiresAt,"credential expiresAt")}}).sort((n,r)=>n.ref.localeCompare(r.ref))}function Et(e={}){let t=e.inactivityMs??U.inactivityMs,n=e.maxEvalAgeMs??U.maxEvalAgeMs;if(!Number.isSafeInteger(t)||t<1440*60*1e3||t>3660*24*60*60*1e3)throw l("policy.inactivityMs is invalid","invalid-policy");if(!Number.isSafeInteger(n)||n<1||n>3660*24*60*60*1e3)throw l("policy.maxEvalAgeMs is invalid","invalid-policy");return{inactivityMs:t,maxEvalAgeMs:n}}function Ne(e){let t=e==null||e===""?At:Number(e);if(!Number.isSafeInteger(t)||t<1||t>Ie)throw l(`limit must be an integer from 1 to ${Ie}`,"invalid-limit");return t}function Ce(e){return Buffer.from(JSON.stringify(e),"utf8").toString("base64url")}function It(e,t){if(typeof e!="string"||e.length<1||e.length>2048||!/^[A-Za-z0-9_-]+$/.test(e))throw l("cursor is invalid","invalid-cursor");let n;try{n=JSON.parse(Buffer.from(e,"base64url").toString("utf8"))}catch{throw l("cursor is invalid","invalid-cursor")}let r=n&&typeof n=="object"&&!Array.isArray(n)?Object.keys(n).sort():[],i=["after","checkedAt","entityType","kind","sequence","status","tenantId","version"].sort();if(JSON.stringify(r)!==JSON.stringify(i)||n.version!==1||n.kind!==t.kind||n.tenantId!==t.tenantId||n.entityType!==t.entityType||n.status!==t.status||!Number.isSafeInteger(n.sequence)||n.sequence<0||n.sequence>t.headSequence||typeof n.after!="string"||!Re.test(n.after)||Ce(n)!==e)throw l("cursor does not match this lifecycle query","invalid-cursor");try{R(n.checkedAt,"cursor checkedAt")}catch{throw l("cursor is invalid","invalid-cursor")}if(Date.parse(n.checkedAt)>Date.parse(t.authorizedAt))throw l("cursor timestamp is in the future","invalid-cursor");return n}function Te(e){let t=new Map;for(let n of e)t.set(`${n.tenantId}\0${n.recordId}`,n.record);return t}function ke(e,{at:t=new Date().toISOString(),inactivityMs:n=U.inactivityMs,maxEvalAgeMs:r=U.maxEvalAgeMs}={}){let i=R(t,"at"),s=Date.parse(i),p=[];if(e.latestEval&&(e.latestEval.passed===!1||e.latestEval.score<e.latestEval.threshold)&&p.push("eval-below-threshold"),e.latestEval?.passed===!0&&s-Date.parse(e.latestEval.evaluatedAt)>r&&p.push("eval-stale"),(e.credentialRefs||[]).some(b=>Date.parse(b.expiresAt)<=s)&&p.push("credential-expired"),e.entityType==="credential"&&e.expiresAt&&Date.parse(e.expiresAt)<=s&&p.push("credential-expired"),p.length)return _({status:"quarantined",reasons:p.sort(),evaluatedAt:i});let f=e.lastUsedAt??e.registeredAt;return s-Date.parse(f)>=n?_({status:"retired",reasons:["inactive"],evaluatedAt:i}):_({status:"active",reasons:[],evaluatedAt:i})}function zt({path:e,now:t=()=>new Date().toISOString(),policy:n={}}={}){let r=Et(n),i=Se({path:e,schemaVersion:ht,fail:l});function s(){return R(t(),"now")}function p(o,y,u=s()){return he({context:o,resource:"lifecycle",action:y,decidedAt:u})}function f(o,y){return Te(i.events()).get(`${o.tenantId}\0${y}`)??null}function b({context:o,kind:y,cursor:u,checkedAt:c,entityType:d=null,status:a=null}){let h=i.events(),m=h.at(-1)?.sequence??0,A=u==null?null:It(u,{kind:y,tenantId:o.tenantId,entityType:d,status:a,headSequence:m,authorizedAt:c}),w=A?.sequence??m,g=A?.checkedAt??c,D=A?.after??null;return{records:[...Te(h.filter(I=>I.sequence<=w)).values()].filter(I=>I.tenantId===o.tenantId).filter(I=>d==null||I.entityType===d).sort((I,j)=>I.entityId.localeCompare(j.entityId)).filter(I=>D==null||I.entityId.localeCompare(D)>0),sequence:w,checkedAt:g}}function N({items:o,hasMore:y,lastEntityId:u,kind:c,context:d,entityType:a=null,status:h=null,sequence:m,checkedAt:A}){let w=y?Ce({version:1,kind:c,tenantId:d.tenantId,entityType:a,status:h,sequence:m,checkedAt:A,after:u}):null;return _({items:o,nextCursor:w,sequence:m})}function v(o,y){let u=ke(o,{at:y,...r}),c=["quarantined","retired","pending_reactivation"].includes(o.status)&&u.status==="active",d=c?o.status:u.status,a=c?[...o.reasons||[]]:[...u.reasons];return _({...structuredClone(o),status:d,reasons:a,evaluatedAt:u.evaluatedAt})}function S(o,y,u,c=s()){let d=u.recordHash??null,a={...u};delete a.recordHash;let h=_({...a,recordHash:k(a)});return i.append({tenantId:o.tenantId,recordType:"lifecycle",recordId:h.entityId,operation:y,occurredAt:c,record:h,expectedRecordHash:d}),h}function C({context:o,input:y}={}){let u=s();p(o,"create",u);let c=E(y?.entityId,"entityId");if(f(o,c))throw l("entity already exists","duplicate-entity");let d=String(y?.entityType??"").trim();if(!be.has(d))throw l("entityType is invalid","invalid-entity-type");let a=_e(y?.credentialRefs);if(d==="credential"&&a.length)throw l("credential entities cannot contain credentialRefs","invalid-credentials");let h=d==="credential"?R(y?.expiresAt,"expiresAt"):null,m=a.some(g=>Date.parse(g.expiresAt)<=Date.parse(u))||h!=null&&Date.parse(h)<=Date.parse(u),A=E(y?.ownerActorId,"ownerActorId"),w=E(o.actor.actorId,"registering actorId");if(!o.actor.roles.includes("owner")&&A!==w)throw l("only an owner may assign lifecycle ownership to another actor","owner-assignment-required");return S(o,"register",{schemaVersion:yt,tenantId:o.tenantId,boundId:ye(o,"lifecycle",c),entityId:c,entityType:d,label:L(y?.label,"label"),ownerActorId:A,registeredBy:w,credentialRefs:a,expiresAt:h,metadata:St(y?.metadata),status:m?"quarantined":"active",reasons:m?["credential-expired"]:[],registeredAt:u,updatedAt:u,lastUsedAt:null,latestEval:null,reactivation:null,revision:1},u)}function V({context:o,entityId:y}={}){let u=s();p(o,"read",u);let c=f(o,E(y,"entityId"));return c?v(c,u):null}function oe({context:o,entityType:y=null,status:u=null,limit:c=null,cursor:d=null}={}){let a=s();if(p(o,"read",a),y!=null&&!be.has(y))throw l("entityType is invalid","invalid-entity-type");if(u!=null&&!wt.includes(u))throw l("status is invalid","invalid-status");let h=Ne(c),m=b({context:o,kind:"list",cursor:d,checkedAt:a,entityType:y,status:u}),A=m.records.map(g=>v(g,m.checkedAt)).filter(g=>u==null||g.status===u),w=A.slice(0,h).map(g=>_(structuredClone(g)));return N({items:w,hasMore:A.length>h,lastEntityId:w.at(-1)?.entityId??null,kind:"list",context:o,entityType:y,status:u,sequence:m.sequence,checkedAt:m.checkedAt})}function ie({context:o,entityId:y,outcome:u,occurredAt:c=null}={}){let d=s();p(o,"update",d);let a=f(o,E(y,"entityId"));if(!a)throw l("entity not found","not-found");let h=new Set(["succeeded","failed","denied","cancelled","skipped"]),m=String(u??"").trim();if(!h.has(m))throw l("usage outcome is invalid","invalid-outcome");let A=R(c??d,"occurredAt"),w=v(a,d);if(w.status!=="active")throw(w.status!==a.status||JSON.stringify(w.reasons)!==JSON.stringify(a.reasons||[]))&&S(o,"usage-denied",{...a,status:w.status,reasons:[...w.reasons],evaluatedAt:w.evaluatedAt,updatedAt:d,revision:a.revision+1},d),l(`entity is not active: ${w.status}`,"entity-not-active");if(Date.parse(A)>Date.parse(d)+Oe)throw l("occurredAt is too far in the future","future-usage");if(a.lastUsedAt&&Date.parse(A)<Date.parse(a.lastUsedAt))throw l("occurredAt must be monotonic","non-monotonic-usage");return S(o,"usage",{...a,lastUsedAt:A,lastOutcome:m,updatedAt:d,revision:a.revision+1},d)}function $({context:o,entityId:y,suite:u,score:c,threshold:d,evaluatedAt:a=null}={}){let h=s();p(o,"update",h);let m=f(o,E(y,"entityId"));if(!m)throw l("entity not found","not-found");let A=Number(c),w=Number(d);if(![A,w].every(j=>Number.isFinite(j)&&j>=0&&j<=1))throw l("eval score and threshold must be from 0 to 1","invalid-eval");let g=R(a??h,"evaluatedAt");if(Date.parse(g)>Date.parse(h)+Oe)throw l("evaluatedAt is too far in the future","future-eval");if(m.latestEval&&Date.parse(g)<Date.parse(m.latestEval.evaluatedAt))throw l("evaluatedAt must be monotonic","non-monotonic-eval");let D={suite:E(u,"eval suite"),score:A,threshold:w,evaluatedAt:g,evaluatorActorId:E(o.actor.actorId,"evaluatorActorId"),passed:A>=w},ae={...m,latestEval:D},I=v(ae,h);return S(o,"eval",{...m,latestEval:D,status:I.status,reasons:[...I.reasons],evaluatedAt:I.evaluatedAt,updatedAt:h,revision:m.revision+1},h)}function q({context:o,entityId:y,refs:u}={}){let c=s();p(o,"update",c);let d=f(o,E(y,"entityId"));if(!d)throw l("entity not found","not-found");let a=v(d,c);if(a.entityType==="credential")throw l("credential entities use updateCredentialExpiry","invalid-credentials");let h=_e(u),m=h.some(A=>Date.parse(A.expiresAt)<=Date.parse(c));return S(o,"credential-refs",{...a,credentialRefs:h,status:m?"quarantined":a.status,reasons:m?[...new Set([...a.reasons||[],"credential-expired"])].sort():a.reasons,updatedAt:c,revision:a.revision+1},c)}function x({context:o,entityId:y,expiresAt:u}={}){let c=s();p(o,"update",c);let d=f(o,E(y,"entityId"));if(!d)throw l("entity not found","not-found");let a=v(d,c);if(a.entityType!=="credential")throw l("entity is not a credential","invalid-entity-type");let h=R(u,"expiresAt"),m=Date.parse(h)<=Date.parse(c);return S(o,"credential-expiry",{...a,expiresAt:h,status:m?"quarantined":a.status,reasons:m?[...new Set([...a.reasons||[],"credential-expired"])].sort():a.reasons,updatedAt:c,revision:a.revision+1},c)}function F({context:o,limit:y=null,cursor:u=null}={}){let c=s();p(o,"manage",c);let d=Ne(y),a=b({context:o,kind:"sweep",cursor:u,checkedAt:c}),h=a.checkedAt,m=[],A=a.records.slice(0,d);for(let w of A){let g=v(w,h);(g.status!==w.status||JSON.stringify(g.reasons)!==JSON.stringify(w.reasons||[]))&&S(o,"sweep",{...w,status:g.status,reasons:[...g.reasons],evaluatedAt:h,updatedAt:h,revision:w.revision+1},h),m.push({entityId:w.entityId,status:g.status,reasons:[...g.reasons],evaluatedAt:h})}return N({items:m.map(w=>_(w)),hasMore:a.records.length>d,lastEntityId:A.at(-1)?.entityId??null,kind:"sweep",context:o,sequence:a.sequence,checkedAt:h})}function xe({context:o,entityId:y,reason:u}={}){let c=s();p(o,"update",c);let d=f(o,E(y,"entityId"));if(!d)throw l("entity not found","not-found");let a=v(d,c);if(!["quarantined","retired"].includes(a.status))throw l("only quarantined or retired entities may request reactivation","invalid-transition");return S(o,"reactivation-requested",{...a,status:"pending_reactivation",reactivation:{requestedAt:c,requestedBy:E(o.actor.actorId,"requestedBy"),reason:L(u,"reactivation reason"),reviewedAt:null,reviewedBy:null,review:null},updatedAt:c,revision:a.revision+1},c)}function De({context:o,entityId:y,review:u}={}){let c=s();p(o,"approve",c);let d=f(o,E(y,"entityId"));if(!d)throw l("entity not found","not-found");if(d.status!=="pending_reactivation"||!d.reactivation)throw l("reactivation request is required","invalid-transition");let a=ke(d,{at:c,...r});if(a.status!=="active")throw l(`reactivation remediation incomplete: ${a.reasons.join(", ")}`,"remediation-required");let h=c;return S(o,"reactivation-approved",{...d,status:"active",reasons:[],reactivation:{...d.reactivation,reviewedAt:h,reviewedBy:E(o.actor.actorId,"reviewedBy"),review:L(u,"reactivation review")},updatedAt:h,revision:d.revision+1},c)}return Object.freeze({register:C,get:V,list:oe,recordUsage:ie,recordEval:$,updateCredentialRefs:q,updateCredentialExpiry:x,sweep:F,requestReactivation:xe,approveReactivation:De,verify:i.verify})}export{mt as AGENT_LIFECYCLE_ENTITY_TYPES,yt as AGENT_LIFECYCLE_SCHEMA_VERSION,ht as AGENT_LIFECYCLE_STATE_VERSION,wt as AGENT_LIFECYCLE_STATUSES,re as AgentLifecycleError,At as DEFAULT_AGENT_LIFECYCLE_PAGE_LIMIT,U as DEFAULT_AGENT_LIFECYCLE_POLICY,Ie as MAX_AGENT_LIFECYCLE_PAGE_LIMIT,zt as createAgentLifecycleController,ke as evaluateLifecycleRecord};
|
|
@@ -97,7 +97,7 @@ does not prove npm users receive it. A locally hosted model/data/policy loop doe
|
|
|
97
97
|
a bundled signer. A merged feature is not public until the npm artifact containing it is
|
|
98
98
|
published and inspected.
|
|
99
99
|
|
|
100
|
-
**Candidate release in this source tree:** public package `@oracle-agent/oracle@0.35.
|
|
100
|
+
**Candidate release in this source tree:** public package `@oracle-agent/oracle@0.35.22`
|
|
101
101
|
ships the encrypted local vault + short-lived loopback signer. Hosted/keyless
|
|
102
102
|
Oracle cannot hold keys or move funds. Self-hosting with `oracle sign init` or
|
|
103
103
|
`oracle sign import --kind evm --key-file <0600 file>` writes an encrypted vault and marks
|