@letterblack/lbe-sdk 0.4.2 → 0.4.3

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.
@@ -1,29 +1,20 @@
1
1
  #!/usr/bin/env node
2
- if (process.argv.includes("--help") || process.argv.includes("-h")) {
3
- console.log(`LBE SDK MCP Server
4
-
5
- Usage:
6
- npx lbe-mcp
7
-
8
- Setup:
9
- npx lbe init
10
-
11
- Tools:
12
- lbe_workspace_context Read local workspace context
13
- lbe_write_file Governed file write
14
- lbe_read_file Governed file read
15
- lbe_patch_file Governed file patch
16
- lbe_shell_command Governed command run
17
- lbe_health Check SDK readiness`);
18
- process.exit(0);
19
- }import ze from"fs";import Mt from"path";import _e from"crypto";import Pt from"fs";import Pr from"os";import _ from"path";import Oe from"tweetnacl";import{canonicalize as tt}from"json-canonicalize";function Le(e){return Buffer.from(e,"base64")}function Re(e){return Buffer.from(e).toString("base64")}function Z({payloadObj:e,sigB64:t,pubKeyB64:r}){try{let s=Buffer.from(tt(e),"utf8"),o=Le(t),n=Le(r),i=Oe.sign.detached.verify(new Uint8Array(s),new Uint8Array(o),new Uint8Array(n));return{valid:i,message:i?"Signature verified":"Signature verification failed"}}catch(s){return{valid:!1,message:`Signature verification error: ${s.message}`}}}function Ce(){let e=Oe.sign.keyPair();return{publicKey:Re(e.publicKey),secretKey:Re(e.secretKey)}}function de({payloadObj:e,secretKeyB64:t}){try{let r=Buffer.from(tt(e),"utf8"),s=Le(t),o=Oe.sign.detached(new Uint8Array(r),new Uint8Array(s));return{signature:Re(o),error:null}}catch(r){return{signature:null,error:`Signing failed: ${r.message}`}}}import rt from"fs";import nt from"path";import{fileURLToPath as Xt}from"url";var Qt=nt.dirname(Xt(import.meta.url)),Ne=nt.join(Qt,"../runtime/lbe_engine.wasm"),st={0:{allowed:!0,reason:null,message:"Policy check passed"},1:{allowed:!1,reason:"POLICY_NOT_CONFIGURED",message:"No policy configured"},2:{allowed:!1,reason:"REQUESTER_NOT_ALLOWED",message:"Requester not in policy"},3:{allowed:!1,reason:"COMMAND_NOT_ALLOWED",message:"Command not allowed for requester"},4:{allowed:!1,reason:"ADAPTER_NOT_ALLOWED",message:"Adapter not allowed"},5:{allowed:!1,reason:"NO_FILESYSTEM_ROOTS_DEFINED",message:"No filesystem roots defined for requester"},6:{allowed:!1,reason:"CWD_OUTSIDE_ALLOWED_ROOT",message:"Path not under allowed roots"},7:{allowed:!1,reason:"PATH_DENIED_BY_PATTERN",message:"Path matches deny pattern"},8:{allowed:!1,reason:"SHELL_CMD_DENIED",message:"Shell command not allowed"}},ot={0:{valid:!0,error:null},1:{valid:!1,error:"Missing required field: id"},2:{valid:!1,error:"Missing required field: commandId"},3:{valid:!1,error:"Missing required field: requesterId"},4:{valid:!1,error:"Missing required field: sessionId"},5:{valid:!1,error:"Missing required field: timestamp"},6:{valid:!1,error:"Missing required field: nonce"},7:{valid:!1,error:"Missing required field: requires"},8:{valid:!1,error:"Missing required field: payload"},9:{valid:!1,error:"Missing required field: signature"},10:{valid:!1,error:"Field 'id' is invalid"},11:{valid:!1,error:"Field 'commandId' is invalid"},12:{valid:!1,error:"Field 'requesterId' is invalid"},13:{valid:!1,error:"Field 'sessionId' is invalid"},14:{valid:!1,error:"Field 'timestamp' is invalid"},15:{valid:!1,error:"Field 'nonce' is invalid"},16:{valid:!1,error:"Field 'requires' is invalid"},17:{valid:!1,error:"payload.Missing required field: adapter"},18:{valid:!1,error:"payload.Field 'adapter' is invalid"},19:{valid:!1,error:"signature.Missing required field: alg"},20:{valid:!1,error:"signature.Missing required field: keyId"},21:{valid:!1,error:"signature.Missing required field: sig"},22:{valid:!1,error:"signature.Field 'alg' must be ed25519"},23:{valid:!1,error:"signature.Field 'sig' is invalid"},24:{valid:!1,error:"Field 'risk' is invalid"}},ue=null;function at(){if(ue)return ue;if(!rt.existsSync(Ne))throw new Error(`LBE compiled engine missing: ${Ne}`);let e=rt.readFileSync(Ne),t=new WebAssembly.Module(e);return ue=new WebAssembly.Instance(t,{}),ue}function it(e){let r=at().exports.lbe_policy_decision(e.policyConfigured?1:0,e.requesterConfigured?1:0,e.commandAllowed?1:0,e.adapterAllowed?1:0,e.filesystemRequired?1:0,e.filesystemRootsDefined?1:0,e.filesystemOk?1:0,e.pathDenied?1:0,e.shellRequired?1:0,e.shellCommandOk?1:0);return{...st[r]||st[1],code:r}}function ct(e){let r=at().exports.lbe_schema_decision(e.hasId?1:0,e.idValid?1:0,e.hasCommandId?1:0,e.commandIdValid?1:0,e.hasRequesterId?1:0,e.requesterIdValid?1:0,e.hasSessionId?1:0,e.sessionIdValid?1:0,e.hasTimestamp?1:0,e.timestampValid?1:0,e.hasNonce?1:0,e.nonceValid?1:0,e.hasRequires?1:0,e.requiresValid?1:0,e.hasPayload?1:0,e.hasPayloadAdapter?1:0,e.payloadAdapterValid?1:0,e.hasSignature?1:0,e.hasSignatureAlg?1:0,e.signatureAlgValid?1:0,e.hasSignatureKeyId?1:0,e.hasSignatureSig?1:0,e.signatureSigValid?1:0,e.hasRisk?1:0,e.riskValid?1:0);return{...ot[r]||ot[10],code:r}}var lt={type:"object",required:["id","commandId","requesterId","sessionId","timestamp","nonce","requires","payload","signature"],properties:{id:{type:"string",pattern:"^[A-Z_]+$",minLength:1,maxLength:50},commandId:{type:"string",pattern:"^[a-f0-9\\-]+$",minLength:36,maxLength:36},requesterId:{type:"string",minLength:3,maxLength:100},sessionId:{type:"string",minLength:3},timestamp:{type:"number",minimum:1e9},nonce:{type:"string",minLength:32,maxLength:128},requires:{type:"array",items:{type:"string"},minItems:1},risk:{type:"string",enum:["LOW","MEDIUM","HIGH","CRITICAL"]},payload:{type:"object",required:["adapter"],properties:{adapter:{type:"string"},cmd:{type:"string"},args:{type:"array"},cwd:{type:"string"}}},signature:{type:"object",required:["alg","keyId","sig"],properties:{alg:{type:"string",enum:["ed25519"]},keyId:{type:"string"},sig:{type:"string",minLength:10}}}}};function dt(e,t){let r=l=>e&&Object.prototype.hasOwnProperty.call(e,l),s=l=>typeof l=="string",o=(l,d)=>s(l)&&d.test(l),n=e?.payload,i=e?.signature,a=ct({hasId:r("id"),idValid:o(e?.id,/^[A-Z_]+$/)&&e.id.length>=1&&e.id.length<=50,hasCommandId:r("commandId"),commandIdValid:o(e?.commandId,/^[a-f0-9-]+$/)&&e.commandId.length===36,hasRequesterId:r("requesterId"),requesterIdValid:s(e?.requesterId)&&e.requesterId.length>=3&&e.requesterId.length<=100,hasSessionId:r("sessionId"),sessionIdValid:s(e?.sessionId)&&e.sessionId.length>=3,hasTimestamp:r("timestamp"),timestampValid:typeof e?.timestamp=="number"&&e.timestamp>=1e9,hasNonce:r("nonce"),nonceValid:s(e?.nonce)&&e.nonce.length>=32&&e.nonce.length<=128,hasRequires:r("requires"),requiresValid:Array.isArray(e?.requires)&&e.requires.length>=1&&e.requires.every(s),hasPayload:r("payload")&&typeof n=="object"&&n!==null&&!Array.isArray(n),hasPayloadAdapter:n&&Object.prototype.hasOwnProperty.call(n,"adapter"),payloadAdapterValid:s(n?.adapter),hasSignature:r("signature")&&typeof i=="object"&&i!==null&&!Array.isArray(i),hasSignatureAlg:i&&Object.prototype.hasOwnProperty.call(i,"alg"),signatureAlgValid:i?.alg==="ed25519",hasSignatureKeyId:i&&Object.prototype.hasOwnProperty.call(i,"keyId"),hasSignatureSig:i&&Object.prototype.hasOwnProperty.call(i,"sig"),signatureSigValid:s(i?.sig)&&i.sig.length>=10,hasRisk:r("risk"),riskValid:["LOW","MEDIUM","HIGH","CRITICAL"].includes(e?.risk)}),c=a.valid?[]:[a.error];return{valid:c.length===0,errors:c}}import pe from"fs";import sr from"path";import E from"fs";import De from"path";import Zt from"crypto";var er={timeoutMs:5e3,pollMs:15,staleMs:3e4};function tr(e){return e+".lock"}function ut(e){try{let t=E.openSync(e,"wx");return E.writeSync(t,`pid:${process.pid}:${Date.now()}`),E.closeSync(t),!0}catch(t){if(t.code==="EEXIST"||t.code==="EPERM"||t.code==="EBUSY"||t.code==="EACCES")return!1;throw t}}function pt(e,t){try{let r=E.statSync(e);if(Date.now()-r.mtimeMs>t)try{E.unlinkSync(e)}catch{}}catch{}}function rr(e){let t=Date.now()+e;for(;Date.now()<t;)try{Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,Math.max(1,t-Date.now()))}catch{}}function ft(e,t,r){let s=typeof t=="function"?t:r,o=typeof t=="function"?{}:t||{},{timeoutMs:n,pollMs:i,staleMs:a}={...er,...o},c=De.dirname(e);E.existsSync(c)||E.mkdirSync(c,{recursive:!0});let l=tr(e),d=Date.now()+n,u=!1;for(;!u&&(u=ut(l),!u);){if(Date.now()>=d){if(pt(l,a),u=ut(l),u)break;let p=new Error(`withFileLock: timeout acquiring ${l} after ${n}ms`);throw p.code="ELOCKTIMEOUT",p}pt(l,a);let m=Math.floor(Math.random()*i);rr(i+m)}try{return s()}finally{try{E.unlinkSync(l)}catch{}}}function I(e,t,r={}){let s=De.dirname(e);E.existsSync(s)||E.mkdirSync(s,{recursive:!0});let o=De.join(s,`.tmp-${Date.now()}-${Zt.randomBytes(4).toString("hex")}`);try{E.writeFileSync(o,t,r),E.renameSync(o,e)}catch(n){try{E.existsSync(o)&&E.unlinkSync(o)}catch{}throw n}}function mt(e){try{if(!E.existsSync(e))return null;let t=E.readFileSync(e,"utf8");return JSON.parse(t)}catch(t){return console.error(`[atomicWrite] Failed to read JSON from ${e}:`,t.message),null}}var fe=class{constructor(t,r=3600){this.dbPath=t,this.ttlSec=r,this.db={entries:[]}}async load(){if(!pe.existsSync(this.dbPath)){this.db={entries:[]};return}try{let t=pe.readFileSync(this.dbPath,"utf8");this.db=JSON.parse(t),this.prune()}catch(t){throw new Error(`Nonce DB at ${this.dbPath} is corrupt or unreadable: ${t.message}`)}}async save(){try{let t=sr.dirname(this.dbPath);pe.existsSync(t)||pe.mkdirSync(t,{recursive:!0}),I(this.dbPath,JSON.stringify(this.db,null,2),{encoding:"utf8"})}catch(t){throw new Error(`Failed to save nonce DB: ${t.message}`)}}checkAndRecord({requesterId:t,sessionId:r,nonce:s}){let o=Math.floor(Date.now()/1e3);this.db.entries=this.db.entries.filter(i=>o-i.timestamp<=this.ttlSec);let n=`${t}|${r}|${s}`;return this.db.entries.some(i=>i.key===n)?{ok:!1,reason:"REPLAY_NONCE",message:"Nonce has already been used"}:(this.db.entries.push({key:n,timestamp:o}),{ok:!0,reason:null,message:"Nonce accepted"})}prune(){let t=Math.floor(Date.now()/1e3),r=this.db.entries.length;this.db.entries=this.db.entries.filter(o=>t-o.timestamp<=this.ttlSec);let s=this.db.entries.length;return{prunedCount:r-s,remainingCount:s}}};function yt(e,{requesterId:t,sessionId:r,nonce:s,timestamp:o},n=3600){let i=Math.floor(Date.now()/1e3);e.entries=e.entries.filter(c=>i-c.timestamp<=n);let a=`${t}|${r}|${s}`;return e.entries.some(c=>c.key===a)?{ok:!1,reason:"REPLAY_NONCE",message:"Nonce has already been used"}:(e.entries.push({key:a,timestamp:o}),{ok:!0,reason:null,message:"Nonce accepted"})}import Te from"path";function or(e,t){if(!t||t.length===0)return!1;let r=Te.resolve(e);return t.some(s=>{let o=Te.resolve(s);return r===o||r.startsWith(o+Te.sep)})}function nr(e,t){let r=t.replace(/\./g,"\\.").replace(/\*\*/g,".*").replace(/\*/g,"[^/]*");return new RegExp(`^${r}$`).test(e)}function ht(e,t){let r=!!(e&&!(e.default==="DENY"&&!e.requesters)),s=e?.requesters?.[t.requesterId],o=!!s,n=t.id.toLowerCase(),i=s?.allowCommands?.some(S=>S.toLowerCase()===n)||!1,a=s?.allowAdapters?.includes(t.payload?.adapter)||!1,c=!1,l=!1,d=!0,u=!1,m=null;if(t.payload?.cwd){c=!0;let S=s?.filesystem?.roots||[];l=S.length>0,d=l&&or(t.payload.cwd,S);let k=s?.filesystem?.denyPatterns||[];for(let D of k)if(nr(t.payload.cwd,D)){u=!0,m=D;break}}let p=!1,N=!0,v=!1;if(t.id==="RUN_SHELL"){p=!0;let S=s?.exec?.allowCmds||[],k=s?.exec?.denyCmds||[],D=t.payload?.cmd;v=k.includes(D),N=!v&&(S.length===0||S.includes(D))}let h=it({policyConfigured:r,requesterConfigured:o,commandAllowed:i,adapterAllowed:a,filesystemRequired:c,filesystemRootsDefined:l,filesystemOk:d,pathDenied:u,shellRequired:p,shellCommandOk:N});if(h.allowed)return h;if(h.reason==="REQUESTER_NOT_ALLOWED")return{...h,message:`Requester '${t.requesterId}' not in policy`};if(h.reason==="COMMAND_NOT_ALLOWED")return{...h,message:`Command '${t.id}' not allowed for requester`};if(h.reason==="ADAPTER_NOT_ALLOWED")return{...h,message:`Adapter '${t.payload?.adapter}' not allowed`};if(h.reason==="CWD_OUTSIDE_ALLOWED_ROOT")return{...h,message:`Path '${t.payload.cwd}' not under allowed roots`};if(h.reason==="PATH_DENIED_BY_PATTERN")return{...h,message:`Path '${t.payload.cwd}' matches deny pattern: ${m}`};if(h.reason==="SHELL_CMD_DENIED"){let S=t.payload?.cmd;return{...h,reason:v?"SHELL_CMD_DENIED":"SHELL_CMD_NOT_ALLOWLISTED",message:v?`Shell command '${S}' is explicitly denied`:`Shell command '${S}' not in allowlist`}}return h}function gt(e){return e.payload?.cmd==="rm"?"CRITICAL":["delete","destroy","remove"].some(t=>e.id.toLowerCase().includes(t))?"HIGH":["write","create","update"].some(t=>e.id.toLowerCase().includes(t))?"MEDIUM":"LOW"}import kt from"fs";import ar from"path";var ir=/^[A-Za-z0-9:_-]{3,128}$/;function Pe(e){return typeof e=="string"&&ir.test(e)&&e!=="default"}function St(e){let t=ar.resolve(e);if(!kt.existsSync(t))return{ok:!1,reason:"KEY_STORE_MISSING",message:`Key store not found: ${t}`,store:null};try{let r=kt.readFileSync(t,"utf-8"),s=JSON.parse(r);return!s||typeof s!="object"||typeof s.trustedKeys!="object"?{ok:!1,reason:"KEY_STORE_INVALID",message:`Invalid key store format: ${t}`,store:null}:{ok:!0,reason:null,message:"Key store loaded",store:s}}catch(r){return{ok:!1,reason:"KEY_STORE_INVALID_JSON",message:`Unable to parse key store: ${r.message}`,store:null}}}function me({keyStore:e,keyId:t,requesterId:r,now:s=new Date}){if(!e||typeof e!="object")return{ok:!1,reason:"KEY_STORE_UNAVAILABLE",message:"Trusted key store is not available",publicKey:null};if(!Pe(t))return{ok:!1,reason:"KEY_ID_INVALID",message:`Invalid keyId '${t}'. Use versioned key IDs like 'agent:gpt-v1-2026Q1'`,publicKey:null};let o=e.trustedKeys?.[t];if(!o)return{ok:!1,reason:"KEY_NOT_TRUSTED",message:`Key '${t}' is not in trusted key store`,publicKey:null};if(o.deprecated)return{ok:!1,reason:"KEY_DEPRECATED",message:`Key '${t}' is deprecated`,publicKey:null};if(o.requesterId&&o.requesterId!==r)return{ok:!1,reason:"KEY_REQUESTER_MISMATCH",message:`Key '${t}' is not authorized for requester '${r}'`,publicKey:null};let n=o.notBefore||o.validFrom,i=o.expiresAt||o.validUntil;if(typeof n!="string"||typeof i!="string")return{ok:!1,reason:"KEY_LIFECYCLE_INVALID",message:`Key '${t}' must define lifecycle fields 'notBefore' and 'expiresAt'`,publicKey:null};let a=new Date(n),c=new Date(i);return Number.isNaN(a.getTime())||Number.isNaN(c.getTime())?{ok:!1,reason:"KEY_LIFECYCLE_INVALID",message:`Key '${t}' has invalid lifecycle timestamp(s)`,publicKey:null}:a>=c?{ok:!1,reason:"KEY_LIFECYCLE_INVALID",message:`Key '${t}' has notBefore >= expiresAt`,publicKey:null}:s<a?{ok:!1,reason:"KEY_NOT_YET_VALID",message:`Key '${t}' not valid until ${n}`,publicKey:null}:s>c?{ok:!1,reason:"KEY_EXPIRED",message:`Key '${t}' expired on ${i}`,publicKey:null}:!o.publicKey||typeof o.publicKey!="string"?{ok:!1,reason:"KEY_CONFIG_INVALID",message:`Trusted key '${t}' is missing publicKey`,publicKey:null}:{ok:!0,reason:null,message:"Trusted key resolved",publicKey:o.publicKey}}import Et from"fs";import cr from"path";function It(e){if(typeof e=="number"&&Number.isFinite(e))return{ok:!0,kind:"int",parts:[Math.floor(e)],raw:String(e)};if(typeof e!="string"||!e.trim())return{ok:!1,reason:"POLICY_VERSION_INVALID",message:"Policy version is required"};let t=e.trim();if(/^\d+$/.test(t))return{ok:!0,kind:"int",parts:[Number(t)],raw:t};let r=t.replace(/^v/i,"");if(/^\d+(\.\d+){0,2}$/.test(r)){let s=r.split(".").map(o=>Number(o));for(;s.length<3;)s.push(0);return{ok:!0,kind:"semver",parts:s,raw:t}}return{ok:!1,reason:"POLICY_VERSION_INVALID",message:`Unsupported policy version format '${e}' (use integer or semver)`}}function lr(e,t){let r=Math.max(e.parts.length,t.parts.length);for(let s=0;s<r;s++){let o=e.parts[s]??0,n=t.parts[s]??0;if(o>n)return 1;if(o<n)return-1}return 0}function _t(e){if(typeof e=="number"&&Number.isFinite(e))return{ok:!0,epochSec:e>1e12?Math.floor(e/1e3):Math.floor(e)};if(typeof e!="string"||!e.trim())return{ok:!1,reason:"POLICY_CREATED_AT_INVALID",message:"Policy createdAt is required"};let t=Date.parse(e);return Number.isNaN(t)?{ok:!1,reason:"POLICY_CREATED_AT_INVALID",message:`Invalid policy createdAt '${e}'`}:{ok:!0,epochSec:Math.floor(t/1e3)}}function dr(e){if(!Et.existsSync(e))return{schemaVersion:"1",lastAccepted:null,updatedAt:null};try{let t=JSON.parse(Et.readFileSync(e,"utf8"));if(!t||typeof t!="object")throw new Error("Policy state file has invalid structure");return{schemaVersion:String(t.schemaVersion||"1"),lastAccepted:t.lastAccepted&&typeof t.lastAccepted=="object"?t.lastAccepted:null,updatedAt:t.updatedAt||null}}catch(t){throw new Error(`Policy state at ${e} is corrupt or unreadable: ${t.message}`)}}function ur(e,t){let r=JSON.stringify(t,null,2);I(e,r,{encoding:"utf8"})}function ye({policyObj:e,statePath:t=cr.resolve("data/policy.state.json"),maxCreatedAtSkewSec:r=31536e3,nowSec:s=Math.floor(Date.now()/1e3),persist:o=!0}){let n=It(e?.version);if(!n.ok)return{ok:!1,reason:n.reason,message:n.message,updated:!1};let i=_t(e?.createdAt);if(!i.ok)return{ok:!1,reason:i.reason,message:i.message,updated:!1};let a=Math.abs(s-i.epochSec),c=Number.isFinite(r)&&r>0?Math.floor(r):31536e3;if(a>c)return{ok:!1,reason:"POLICY_CREATED_AT_SKEW_EXCEEDED",message:`Policy createdAt skew ${a}s exceeds allowed ${c}s`,updated:!1};let l;try{l=dr(t)}catch(v){return{ok:!1,reason:"POLICY_STATE_CORRUPT",message:v.message,updated:!1}}let d=l.lastAccepted,u=null,m=null,p=0;if(d&&(u=It(d.version),m=_t(d.createdAt),u.ok&&m.ok)){if(p=lr(n,u),p<0)return{ok:!1,reason:"POLICY_VERSION_REGRESSION",message:`Policy version regression: current '${n.raw}' < last '${u.raw}'`,updated:!1};if(p===0&&i.epochSec<m.epochSec)return{ok:!1,reason:"POLICY_CREATED_AT_REGRESSION",message:`Policy createdAt regression: current '${e.createdAt}' < last '${d.createdAt}'`,updated:!1};if(p>0&&i.epochSec<m.epochSec)return{ok:!1,reason:"POLICY_CREATED_AT_REGRESSION",message:"Policy createdAt must be monotonic when version increases",updated:!1}}let N=!d||!u?.ok||!m?.ok||p>0||p===0&&i.epochSec>m.epochSec;if(o&&N){let v={schemaVersion:"1",lastAccepted:{version:e.version,createdAt:e.createdAt,environment:e.environment||null},updatedAt:new Date().toISOString()};ur(t,v)}return{ok:!0,reason:null,message:"Policy version guard passed",updated:N}}function $e({commandObj:e,pubKeyB64:t,keyStore:r,nonceDb:s,policy:o,rateLimiter:n,policyStatePath:i}){let a={valid:!1,commandId:e?.commandId,checks:{},errors:[]},c=dt(e,lt);if(a.checks.schema=c.valid,!c.valid)return a.errors.push(...c.errors.map(k=>({type:"SCHEMA_ERROR",message:k}))),a;if(i&&o?.version!==void 0)try{let k=ye({policyObj:o,statePath:i});if(a.checks.policyVersion=k.ok,!k.ok)return a.errors.push({type:"POLICY_VERSION_INVALID",message:k.message}),a}catch{a.checks.policyVersion=!0}else a.checks.policyVersion=!0;let l=e.signature?.keyId;if(a.checks.keyId=Pe(l),!a.checks.keyId)return a.errors.push({type:"KEY_ID_INVALID",message:`Invalid keyId '${l}'. Use versioned IDs like 'agent:gpt-v1-2026Q1'`}),a;let d=Math.floor(Date.now()/1e3),u=Number.isFinite(o?.security?.maxClockSkewSec)?o.security.maxClockSkewSec:600,m=Math.abs(d-e.timestamp);if(a.checks.timestamp=m<=u,!a.checks.timestamp)return a.errors.push({type:"TIMESTAMP_SKEW_EXCEEDED",message:`Command timestamp skew ${m}s exceeds allowed ${u}s`}),a;let p=null;if(r){let k=me({keyStore:r,keyId:l,requesterId:e.requesterId});if(!k.ok)return a.checks.signature=!1,a.errors.push({type:k.reason,message:k.message}),a;p=k.publicKey}if(!p&&t&&(p=t),!p)return a.checks.signature=!1,a.errors.push({type:"SIGNATURE_KEY_UNAVAILABLE",message:"No public key available. Provide --pub-key/--pub-key-file or config/keys.json"}),a;let N={...e};delete N.signature;let v=Z({payloadObj:N,sigB64:e.signature.sig,pubKeyB64:p});if(a.checks.signature=v.valid,!v.valid)return a.errors.push({type:"SIGNATURE_INVALID",message:v.message}),a;if(n&&typeof n.checkAndRecord=="function"){let k=o?.requesters?.[e.requesterId]?.rateLimit||{},D=o?.security?.defaultRateLimit||{},T=n.checkAndRecord({requesterId:e.requesterId,nowSec:d,windowSec:k.windowSec??D.windowSec??60,maxRequests:k.maxRequests??D.maxRequests??30});if(a.checks.rateLimit=T.ok,!T.ok)return a.errors.push({type:T.reason,message:`${T.message}. Retry after ${T.retryAfterSec}s`}),a}let h;if(s&&typeof s.checkAndRecord=="function"?h=s.checkAndRecord({requesterId:e.requesterId,sessionId:e.sessionId,nonce:e.nonce}):h=yt(s,{requesterId:e.requesterId,sessionId:e.sessionId,nonce:e.nonce,timestamp:e.timestamp}),a.checks.nonce=h.ok,!h.ok)return a.errors.push({type:h.reason,message:h.message}),a;let S=ht(o,e);return a.checks.policy=S.allowed,a.risk=gt(e),S.allowed?(a.valid=!0,a.message="Command validation successful",a):(a.errors.push({type:S.reason,message:S.message}),a)}import he from"fs";import pr from"path";var ge=class{constructor(t){this.dbPath=t,this.db={entries:[]}}async load(){try{if(!he.existsSync(this.dbPath)){this.db={entries:[]};return}let t=he.readFileSync(this.dbPath,"utf8");this.db=JSON.parse(t),Array.isArray(this.db.entries)||(this.db={entries:[]})}catch{this.db={entries:[]}}}async save(){let t=pr.dirname(this.dbPath);he.existsSync(t)||he.mkdirSync(t,{recursive:!0}),I(this.dbPath,JSON.stringify(this.db,null,2),{encoding:"utf8"})}checkAndRecord({requesterId:t,nowSec:r,windowSec:s,maxRequests:o}){let n=Number.isFinite(r)?r:Math.floor(Date.now()/1e3),i=Number.isFinite(s)&&s>0?s:60,a=Number.isFinite(o)&&o>0?o:30,c=n-i;this.db.entries=this.db.entries.filter(d=>d.timestamp>=c);let l=this.db.entries.filter(d=>d.requesterId===t);if(l.length>=a){let d=l.sort((m,p)=>m.timestamp-p.timestamp)[0],u=Math.max(1,i-(n-d.timestamp));return{ok:!1,reason:"RATE_LIMIT_EXCEEDED",message:`Rate limit exceeded for '${t}' (${a}/${i}s)`,retryAfterSec:u}}return this.db.entries.push({requesterId:t,timestamp:n}),{ok:!0,reason:null,message:"Rate limit check passed",retryAfterSec:0}}};import G from"fs";import fr from"path";import mr from"crypto";function yr(e){return mr.createHash("sha256").update(e).digest("hex")}function hr(e){try{if(!G.existsSync(e))return"GENESIS";let t=G.readFileSync(e,"utf8").trim();if(!t)return"GENESIS";let r=t.split(`
20
- `),s=r[r.length-1];try{return JSON.parse(s).hash||"GENESIS"}catch{return"GENESIS"}}catch{return"GENESIS"}}function ke(e,t){let r=fr.dirname(e);G.existsSync(r)||G.mkdirSync(r,{recursive:!0});let s;return ft(e,()=>{let o=hr(e),n={...t,prevHash:o,timestamp:new Date().toISOString()};delete n.hash;let i=JSON.stringify(n),a=yr(i),c=JSON.stringify({...n,hash:a}),l="";G.existsSync(e)&&(l=G.readFileSync(e,"utf8"));try{I(e,l+c+`
21
- `,{encoding:"utf8"})}catch(d){throw new Error(`Audit log write failed: ${d.message}`)}s={success:!0,hash:a,prevHash:o,message:"Audit entry appended"}}),s}async function vt(e){return{adapter:"noop",commandId:e.commandId||"unknown",command:e.id||"unknown",status:"completed",output:`[NOOP] Would execute: ${e.id||"unknown"} on adapter: ${e.payload?.adapter||"unknown"}`,exitCode:0,timestamp:new Date().toISOString()}}import{spawnSync as gr}from"child_process";import Fe from"path";function kr(e){if(e===void 0)return{ok:!0,args:[]};if(!Array.isArray(e))return{ok:!1,error:"payload.args must be an array"};let t=[];for(let r of e){if(typeof r!="string"&&typeof r!="number"&&typeof r!="boolean")return{ok:!1,error:"payload.args may only contain string, number, or boolean values"};t.push(String(r))}return{ok:!0,args:t}}async function wt(e,t,r){let s=e.payload,o=3e4,n=1024*1024;if(s.adapter!=="shell")return{adapter:"shell",commandId:e.commandId,status:"error",error:"Adapter mismatch",exitCode:1};let i=r?.exec?.allowCmds||[];if((r?.exec?.denyCmds||[]).includes(s.cmd))return{adapter:"shell",commandId:e.commandId,status:"blocked",error:`Command '${s.cmd}' is denied`,exitCode:2};if(i.length>0&&!i.includes(s.cmd))return{adapter:"shell",commandId:e.commandId,status:"blocked",error:`Command '${s.cmd}' not in allowlist`,exitCode:2};if(!(r?.filesystem?.roots||[]).some(u=>{let m=Fe.resolve(u),p=Fe.resolve(s.cwd);return p===m||p.startsWith(m+Fe.sep)}))return{adapter:"shell",commandId:e.commandId,status:"blocked",error:`CWD '${s.cwd}' not authorized`,exitCode:2};let d=kr(s.args);if(!d.ok)return{adapter:"shell",commandId:e.commandId,status:"blocked",error:d.error,exitCode:2};try{let u=gr(s.cmd,d.args,{cwd:s.cwd,timeout:o,encoding:"utf8",maxBuffer:n,stdio:["pipe","pipe","pipe"],shell:!1});if(u.error)throw u.error;let m=`${u.stdout||""}${u.stderr||""}`,p=u.status??1;return p!==0?{adapter:"shell",commandId:e.commandId,command:s.cmd,status:"error",error:m.substring(0,n)||`Command exited with code ${p}`,exitCode:p,timestamp:new Date().toISOString()}:{adapter:"shell",commandId:e.commandId,command:s.cmd,status:"completed",output:m.substring(0,n),exitCode:0,timestamp:new Date().toISOString()}}catch(u){return{adapter:"shell",commandId:e.commandId,command:s.cmd,status:"error",error:u.message,exitCode:u.status||1,timestamp:new Date().toISOString()}}}import te from"fs";import J from"path";import q from"fs";import Se from"path";import Sr from"crypto";function ee(e,t){let r=t||Se.resolve("data/backups");q.existsSync(r)||q.mkdirSync(r,{recursive:!0});let s=Se.resolve(e),o=q.existsSync(s),n=null,i=null;o&&(n=q.readFileSync(s),i=Sr.createHash("sha256").update(n).digest("hex"));let a=Se.basename(s).replace(/[^a-zA-Z0-9._-]/g,"_"),c=`${Date.now()}-${i?i.slice(0,8):"new"}-${a}`,l=o?Se.join(r,c):null;return o&&n!==null&&I(l,n),{originalPath:s,backupPath:l,existed:o,hash:i,createdAt:new Date().toISOString()}}function B(e){if(!e)return{restored:!1,error:"No backup metadata"};let{originalPath:t,backupPath:r,existed:s}=e;if(!s)try{return q.existsSync(t)&&q.unlinkSync(t),{restored:!0,action:"deleted"}}catch(o){return{restored:!1,error:o.message}}if(!r||!q.existsSync(r))return{restored:!1,error:"Backup file not found at: "+r};try{let o=q.readFileSync(r);return I(t,o),{restored:!0,action:"restored"}}catch(o){return{restored:!1,error:o.message}}}var Er=10*1024*1024;function Ir(e,t){return e?J.isAbsolute(e)?J.resolve(e):J.resolve(t||process.cwd(),e):null}function _r(e,t){let r=J.resolve(e);return t.some(s=>{let o=J.resolve(s);return r===o||r.startsWith(o+J.sep)})}function vr(e,t){for(let r of t||[])if(new RegExp("^"+r.replace(/\./g,"\\.").replace(/\*\*/g,".*").replace(/\*/g,"[^/\\\\]*")+"$").test(e))return r;return null}function j(e,t,r,s=2){return{adapter:"file",commandId:e.commandId,status:"blocked",errorCode:t,error:r,exitCode:s}}function $(e,t,r,s=null,o=1){return{adapter:"file",commandId:e.commandId,status:"error",errorCode:t,error:r,backup:s?Ee(s):null,exitCode:o}}function Ee(e){return e?{path:e.backupPath,existed:e.existed,hash:e.hash,createdAt:e.createdAt}:null}async function At(e,t,r){let s=e.payload,o=s.action,n=s.cwd||process.cwd(),i=Ir(s.target,n);if(!o)return j(e,"FILE_NO_ACTION","payload.action is required");if(!i&&o!=="noop")return j(e,"FILE_NO_TARGET","payload.target is required");let a=r?.filesystem?.roots||[];if(a.length===0)return j(e,"FILE_NO_ROOTS","No filesystem roots defined for requester");if(!_r(i,a))return j(e,"FILE_OUTSIDE_ROOT",`'${i}' is outside allowed roots`);let c=vr(i,r?.filesystem?.denyPatterns);if(c)return j(e,"FILE_PATH_DENIED",`'${i}' matches deny pattern: ${c}`);switch(o){case"read":return wr(e,i);case"write":return Ar(e,i,s);case"patch":return br(e,i,s);case"delete":return xr(e,i);default:return j(e,"FILE_UNKNOWN_ACTION",`Unknown action: '${o}'`)}}function wr(e,t){if(!te.existsSync(t))return $(e,"FILE_NOT_FOUND",`Not found: ${t}`);try{let r=te.statSync(t);if(r.size>Er)return $(e,"FILE_TOO_LARGE","File exceeds 10 MB read limit");let s=te.readFileSync(t,"utf8");return{adapter:"file",action:"read",commandId:e.commandId,status:"completed",target:t,output:s,bytesRead:r.size,exitCode:0}}catch(r){return $(e,"FILE_READ_ERROR",r.message)}}function Ar(e,t,r){let s=r.content;if(s==null)return $(e,"FILE_MISSING_CONTENT","payload.content is required for write");let o=qe(t);try{return I(t,s,{encoding:"utf8"}),{adapter:"file",action:"write",commandId:e.commandId,status:"completed",target:t,backup:Ee(o),output:`Wrote ${Buffer.byteLength(s,"utf8")} bytes to ${t}`,exitCode:0}}catch(n){return B(o),$(e,"FILE_WRITE_ERROR",n.message,o)}}function br(e,t,r){let s=r.content;if(s==null)return $(e,"FILE_MISSING_CONTENT","payload.content is required for patch");let o=qe(t);try{return I(t,s,{encoding:"utf8"}),{adapter:"file",action:"patch",commandId:e.commandId,status:"completed",target:t,backup:Ee(o),output:`Patched ${t} (${Buffer.byteLength(s,"utf8")} bytes)`,exitCode:0}}catch(n){return B(o),$(e,"FILE_PATCH_ERROR",n.message,o)}}function xr(e,t){if(!te.existsSync(t))return $(e,"FILE_NOT_FOUND",`Not found: ${t}`);let r=qe(t);try{return te.unlinkSync(t),{adapter:"file",action:"delete",commandId:e.commandId,status:"completed",target:t,backup:Ee(r),output:`Deleted ${t}`,exitCode:0}}catch(s){return B(r),$(e,"FILE_DELETE_ERROR",s.message,r)}}function qe(e){try{return ee(e)}catch{return null}}async function bt(e,t,r){let s=Date.now();try{let o=e.id||"";if(!o.toUpperCase().startsWith("OBSERVE"))return{adapter:"observer",commandId:e.commandId,status:"error",error:`Observer adapter only handles OBSERVE_* commands, got '${o}'`,exitCode:1};let{source:n,context:i,issueType:a,description:c,severity:l,metadata:d}=e.payload||{};if(!a||!c)return{adapter:"observer",commandId:e.commandId,status:"error",error:"Observer payload must include issueType and description",exitCode:1};let u=["low","medium","high","critical"];return l&&!u.includes(l)?{adapter:"observer",commandId:e.commandId,status:"error",error:`Invalid severity '${l}'. Must be one of: ${u.join(", ")}`,exitCode:1}:{adapter:"observer",commandId:e.commandId,status:"recorded",timestamp:new Date().toISOString(),requesterId:e.requesterId,observation:{source:n||"unknown",context:i||"unknown",issueType:a,description:c,severity:l||"info",metadata:d||{}},duration_ms:Date.now()-s,exitCode:0}}catch(o){return{adapter:"observer",commandId:e.commandId,status:"error",error:`Observer execution failed: ${o.message}`,exitCode:9}}}var xt={noop:vt,shell:wt,file:At,observer:bt};function Lr(e){return xt[e]}async function Lt(e,t,r,s){let o=Lr(e);if(!o)return{adapter:e,commandId:t.commandId,status:"error",error:`Adapter '${e}' not found`,exitCode:1};try{return await o(t,r,s)}catch(n){return{adapter:e,commandId:t.commandId,status:"error",error:`Adapter execution failed: ${n.message}`,exitCode:9}}}var Rt=Object.keys(xt);import Ot from"fs";import Rr from"path";function Ct({policyObj:e,keyStore:t,policySigPath:r="./config/policy.sig.json",allowUnsigned:s=!1}){let o=Rr.resolve(r);if(!Ot.existsSync(o))return s?{ok:!0,skipped:!0,reason:"POLICY_SIGNATURE_SKIPPED",message:`Policy signature not found: ${o} (allowed by flag)`}:{ok:!1,skipped:!1,reason:"POLICY_SIGNATURE_MISSING",message:`Policy signature file not found: ${o}`};let n;try{n=JSON.parse(Ot.readFileSync(o,"utf-8"))}catch(c){return{ok:!1,skipped:!1,reason:"POLICY_SIGNATURE_INVALID",message:`Unable to parse policy signature file: ${c.message}`}}if(!n||n.alg!=="ed25519"||typeof n.keyId!="string"||typeof n.sig!="string")return{ok:!1,skipped:!1,reason:"POLICY_SIGNATURE_INVALID",message:"Policy signature envelope must include {alg, keyId, sig}"};if(!t)return{ok:!1,skipped:!1,reason:"POLICY_SIGNER_KEY_STORE_UNAVAILABLE",message:"Trusted key store is required for policy signature verification"};let i=me({keyStore:t,keyId:n.keyId,requesterId:void 0});if(!i.ok)return{ok:!1,skipped:!1,reason:"POLICY_SIGNER_NOT_TRUSTED",message:i.message};let a=Z({payloadObj:e,sigB64:n.sig,pubKeyB64:i.publicKey});return a.valid?{ok:!0,skipped:!1,reason:null,message:"Policy signature verified",keyId:n.keyId}:{ok:!1,skipped:!1,reason:"POLICY_SIGNATURE_INVALID",message:a.message}}import Cr from"crypto";import Or from"path";var Me=class{constructor(t){this.dbPath=t||Or.resolve("data/checkpoints.db.json"),this.store={checkpoints:{},tokens:{}},this._load()}_load(){let t=mt(this.dbPath);t&&(this.store=t,this.store.checkpoints=this.store.checkpoints||{},this.store.tokens=this.store.tokens||{})}_save(){let t=JSON.stringify(this.store,null,2);I(this.dbPath,t,{encoding:"utf8"})}saveCheckpoint(t,r){this.store.checkpoints[t]={jobId:t,...r,updatedAt:Date.now()},this._save()}getCheckpoint(t){return this.store.checkpoints[t]||null}getAllCheckpoints(){return Object.values(this.store.checkpoints)}removeCheckpoint(t){return this.store.checkpoints[t]?(delete this.store.checkpoints[t],this._save(),!0):!1}saveToken(t,r){this.store.tokens[t]={tokenId:t,...r,createdAt:Date.now()},this._save()}getToken(t){return this.store.tokens[t]||null}getAllTokens(){return Object.values(this.store.tokens)}removeToken(t){return this.store.tokens[t]?(delete this.store.tokens[t],this._save(),!0):!1}},Ke=null;function Nt(e){return Ke||(Ke=new Me(e)),Ke}var Ve=class{constructor(t){this.store=Nt(t),this._pendingResolvers=new Map}createToken(t,r={}){let s=Cr.randomBytes(16).toString("hex"),o={jobId:t,context:r,status:"pending",expiresAt:Date.now()+1440*60*1e3};return this.store.saveToken(s,o),s}awaitApproval(t){let r=this.store.getToken(t);return r?r.status!=="pending"?Promise.reject(new Error(`Approval token ${t} is no longer pending (status: ${r.status})`)):Date.now()>r.expiresAt?(this.store.removeToken(t),Promise.reject(new Error(`Approval token ${t} expired`))):new Promise((s,o)=>{this._pendingResolvers.set(t,{resolve:s,reject:o})}):Promise.reject(new Error(`Approval token ${t} not found`))}approve(t,r={}){let s=this.store.getToken(t);if(!s)throw new Error("Token not found");if(s.status!=="pending")throw new Error("Token not pending");this.store.saveToken(t,{...s,status:"approved",approverData:r,resolvedAt:Date.now()});let o=this._pendingResolvers.get(t);return o&&(o.resolve({approved:!0,approverData:r}),this._pendingResolvers.delete(t)),!0}deny(t,r="Manually denied"){let s=this.store.getToken(t);if(!s)throw new Error("Token not found");if(s.status!=="pending")throw new Error("Token not pending");this.store.saveToken(t,{...s,status:"denied",reason:r,resolvedAt:Date.now()});let o=this._pendingResolvers.get(t);return o&&(o.reject(new Error(`Approval denied: ${r}`)),this._pendingResolvers.delete(t)),!0}},Be=null;function Dt(e){return Be||(Be=new Ve(e)),Be}var Ue={DEBUG:0,INFO:1,WARN:2,ERROR:3};function Ie({level:e="INFO",maxHistory:t=500,silent:r=!1}={}){let s=Ue[e]??Ue.INFO,o=[];function n(a,c,l,d){let u={ts:new Date().toISOString(),level:a,scope:c,message:l,...d!==void 0?{meta:d}:{}};if(o.length>=t&&o.shift(),o.push(u),!r&&Ue[a]>=s){let m=d!==void 0?`[${a}] [${c}] ${l} ${JSON.stringify(d)}`:`[${a}] [${c}] ${l}`;process.stderr.write(m+`
22
- `)}}function i(a){return{debug:(c,l)=>n("DEBUG",a,c,l),info:(c,l)=>n("INFO",a,c,l),warn:(c,l)=>n("WARN",a,c,l),error:(c,l)=>n("ERROR",a,c,l)}}return{scope:i,debug:(a,c)=>n("DEBUG","lbe",a,c),info:(a,c)=>n("INFO","lbe",a,c),warn:(a,c)=>n("WARN","lbe",a,c),error:(a,c)=>n("ERROR","lbe",a,c),exportLogs:()=>[...o],clearHistory:()=>{o.length=0},get historyLength(){return o.length}}}var Nr=process.env.LBE_LOG_LEVEL||"INFO",Dr=process.env.LBE_LOG_SILENT==="1",ho=Ie({level:Nr,silent:Dr});function re(e){if(e===null||typeof e!="object"||Object.isFrozen(e))return e;Object.freeze(e);for(let t of Object.getOwnPropertyNames(e)){let r=e[t];typeof r=="object"&&r!==null&&!Object.isFrozen(r)&&re(r)}return e}import Ye from"fs";import He from"path";var z=class extends Error{constructor(t,r,s){super(t),this.name="InvariantGateError",this.checks=r,this.failures=s}};function Tt(e,t,r){let s={},o=[],n=!!(t&&typeof t.version<"u"&&t.requesters&&typeof t.requesters=="object"&&t.default==="DENY");s.policy_structure=n,n||o.push("Policy missing required fields: version, requesters, default=DENY");let i=!!(r&&typeof r=="object"&&Object.keys(r).length>0);s.keys_available=i,i||o.push("No trusted keys loaded \u2014 provide config/keys.json");let a=He.dirname(e.auditLog);s.audit_log_writable=We(a),s.audit_log_writable||o.push(`Audit log directory not writable: ${a}`);let c=He.dirname(e.nonceDb);s.nonce_db_writable=We(c),s.nonce_db_writable||o.push(`Nonce DB directory not writable: ${c}`);let l=He.dirname(e.rateLimit);if(s.rate_limit_writable=We(l),s.rate_limit_writable||o.push(`Rate-limit DB directory not writable: ${l}`),t&&t.requesters){let d=[];for(let[u,m]of Object.entries(t.requesters))for(let p of m.allowAdapters||[])Rt.includes(p)||d.push(`${u}\u2192${p}`);s.adapter_chain_valid=d.length===0,s.adapter_chain_warnings=d.length>0?d:[]}else s.adapter_chain_valid=!0,s.adapter_chain_warnings=[];return s.secret_key_present=!!e.secretKey,s.secret_key_present||o.push("secretKey not provided to createLBE()"),{ok:o.length===0,checks:s,failures:o}}function Ge(e,t,r){let s=Tt(e,t,r);if(!s.ok){let o=s.failures.length;throw new z(`Invariant gate: ${o} violation${o===1?"":"s"} \u2014 ${s.failures.join(" | ")}`,s.checks,s.failures)}return s}function Tr(e){try{return Ye.accessSync(e,Ye.constants.W_OK),!0}catch{return!1}}function We(e){if(Tr(e))return!0;try{return Ye.mkdirSync(e,{recursive:!0}),!0}catch{return!1}}function $r(e,t){let r=_.resolve(e||process.cwd());if(!t||t==="local"){let s=_e.createHash("sha256").update(r).digest("hex").slice(0,16);return _.join(Pr.homedir(),".lbe","workspaces",s)}if(t==="workspace")return _.join(r,".lbe");if(t&&typeof t=="object"&&t.adapter)return null;throw new Error(`createLBE: unknown state option: ${JSON.stringify(t)}`)}var Fr={patch_file:"PATCH_FILE",write_file:"WRITE_FILE",read_file:"READ_FILE",delete_file:"DELETE_FILE",run_shell:"RUN_SHELL",echo:"ECHO"},qr={PATCH_FILE:"file",WRITE_FILE:"file",READ_FILE:"file",DELETE_FILE:"file",RUN_SHELL:"shell",ECHO:"noop"},Kr=new Set(["HIGH","CRITICAL"]);function je(e){return _e.createHash("sha256").update(JSON.stringify(e)).digest("hex")}function Mr(e,t){if(!t?.requireApproval)return!1;let r=t.requireApproval;return r===!0?!0:Array.isArray(r)?r.includes(e)||r.includes("*")||Kr.has(e)&&r.includes("HIGH+"):!1}function $t(e={}){if(e.rootDir&&!e.secretKey){let A=Ce(),g=e.keyId||"sdk-auto-key";e={defaultActor:"agent:sdk",logLevel:"WARN",...e,secretKey:A.secretKey,keyId:g,keyStore:e.keyStore||Br({publicKey:A.publicKey,keyId:g}),policy:e.policy||{version:1,default:"DENY",requesters:{"agent:sdk":{allowCommands:["write_file","read_file","patch_file","delete_file"],allowAdapters:["file"],filesystem:{roots:[e.rootDir],denyPatterns:["*.key","*.env","*.secret"]}}}}}}let{secretKey:t,keyId:r="sdk-key-v1",sessionId:s,defaultActor:o="agent:sdk",policy:n,keyStore:i,policyPath:a,keysStorePath:c,policySigPath:l,policyStatePath:d,nonceDbPath:u,rateLimitDbPath:m,auditLogPath:p,backupDir:N,allowUnsignedPolicy:v=!1,state:h="local",rootDir:S,logLevel:k=process.env.LBE_LOG_LEVEL||"INFO",logSilent:D=process.env.LBE_LOG_SILENT==="1"}=e,T=n&&typeof n=="object"?n:null,Qe=i&&typeof i=="object"?i:null,X=$r(S,h),L={secretKey:t,policy:a||_.resolve("config/policy.default.json"),keys:c||_.resolve("config/keys.json"),policySig:l||_.resolve("config/policy.sig.json"),policyState:d||_.join(X,"policy.state.json"),nonceDb:u||_.join(X,"nonce.db.json"),rateLimit:m||_.join(X,"rate-limit.db.json"),auditLog:p||_.join(X,"audit.log.jsonl"),backupDir:N||_.join(X,"backups")},K=Ie({level:k,silent:D}),w=K.scope("Executor"),V=K.scope("Validator"),U=K.scope("Policy");async function we({actor:A,intent:g,target:y,content:se,args:Yt=[],transaction:Gt={}}){let Q={validate:!0,backup:!0,rollbackOnFailure:!0,audit:!0,...Gt};w.info("execute() called",{actor:A,intent:g,target:y});let oe=Fr[g]||g.toUpperCase().replace(/-/g,"_"),H=qr[oe]||"noop",R;if(T)R=T,U.debug("Using inline policy",{version:R.version});else try{R=JSON.parse(Pt.readFileSync(L.policy,"utf8")),U.debug("Policy loaded from file",{version:R.version})}catch(f){return U.error("Policy load failed",{error:f.message}),{ok:!1,stage:"policy_load",error:"POLICY_LOAD_FAILED",message:f.message}}let M;if(Qe)M=Qe,V.debug("Using inline keyStore");else{let f=St(L.keys);M=f.ok?f.store:null,V.debug("Keys loaded from file",{ok:f.ok})}re(R),M&&re(M);try{let f=Ge(L,R,M);V.debug("Invariant gate passed",f.checks)}catch(f){if(f instanceof z)return V.error("Invariant gate failed",{failures:f.failures}),{ok:!1,stage:"invariant_gate",error:"INVARIANT_GATE_FAILED",message:f.message,checks:f.checks,failures:f.failures};throw f}if(!T){let f=Ct({policyObj:R,keyStore:M,policySigPath:L.policySig,allowUnsigned:v});if(!f.ok)return U.error("Policy signature invalid",{reason:f.reason}),{ok:!1,stage:"policy_sig",error:f.reason,message:f.message};let x=ye({policyObj:R,statePath:L.policyState});if(!x.ok)return U.error("Policy version guard failed",{reason:x.reason}),{ok:!1,stage:"policy_version",error:x.reason,message:x.message};U.debug("Policy signature and version valid")}if(!t)return{ok:!1,stage:"sign",error:"NO_SECRET_KEY",message:"createLBE requires secretKey"};let jt=Math.floor(Date.now()/1e3),Jt=_e.randomBytes(32).toString("hex"),zt=s||`sdk-${Date.now()}`,O=_e.randomUUID();w.debug("Proposal built",{commandId:O,commandId_str:oe,adapter:H});let ne={id:oe,commandId:O,requesterId:A,sessionId:zt,timestamp:jt,nonce:Jt,requires:["policy","signature"],payload:{adapter:H,action:g.includes("_")?g.split("_")[0]:g,target:y?_.resolve(y):null,content:se||null,args:Yt,cwd:y?_.dirname(_.resolve(y)):process.cwd()}},ae=de({payloadObj:ne,secretKeyB64:t});if(ae.error)return w.error("Signing failed",{error:ae.error}),{ok:!1,stage:"sign",commandId:O,error:"SIGN_FAILED",message:ae.error};let ie={...ne,signature:{alg:"ed25519",keyId:r,sig:ae.signature}},Ae=new fe(L.nonceDb);await Ae.load();let be=new ge(L.rateLimit);await be.load();let C=$e({commandObj:ie,keyStore:M,nonceDb:Ae,policy:R,rateLimiter:be,policyStatePath:T?null:L.policyState}),ce=async()=>{await Ae.save().catch(()=>{}),await be.save().catch(()=>{})};if(!C.valid)return V.warn("Validation failed",{error:C.errors[0]?.type,checks:C.checks}),await ce(),Q.audit&&ke(L.auditLog,{commandId:O,status:"rejected",requesterId:A,payloadHash:je(ie),reason:C.errors[0]?.type,intent:g}),{ok:!1,stage:"validate",commandId:O,error:C.errors[0]?.type,message:C.errors[0]?.message,checks:C.checks,operationLog:K.exportLogs()};V.info("Validation passed",{risk:C.risk,checks:C.checks});let F=C.risk||"LOW",Ze=R.requesters?.[A];if(Mr(F,Ze)){w.warn("Approval required",{risk:F,commandId:O}),await ce();let x=Dt(L.policyState).createToken(O,{actor:A,intent:g,target:y,risk:F,commandId:oe});return{ok:!1,stage:"approval_pending",commandId:O,approvalToken:x,risk:F,message:`${F} risk operation requires approval. Token: ${x}`,operationLog:K.exportLogs()}}let P=null;if(Q.backup&&y){let f=["write","patch","delete"].includes(ne?.payload?.action??g.split("_")[0]);try{P=ee(_.resolve(y),L.backupDir),w.debug("Backup created",{existed:P.existed,path:P.backupPath})}catch(x){if(f)return w.error("Backup failed \u2014 aborting write transaction",{error:x.message}),await ce(),{ok:!1,stage:"backup",error:"BACKUP_FAILED",message:x.message};w.warn("Backup failed (non-fatal for read)",{error:x.message})}}w.info("Executing adapter",{adapter:H,target:y});let b;try{b=await Lt(H,ie,R,Ze)}catch(f){b={adapter:H,commandId:O,status:"error",error:f.message,exitCode:1}}w.debug("Adapter returned",{status:b.status,exitCode:b.exitCode});let xe=b.status==="error"||b.exitCode!==0&&b.exitCode!==void 0,W=null;if(Q.validate&&y&&!xe){let f=["write","patch"],x=ne.payload.action;if(f.includes(x)){let et=Pt.existsSync(_.resolve(y));W={ok:et,check:"target_exists",target:y},et?w.debug("Post-execution validation passed"):(w.error("Post-execution validation failed \u2014 target missing after write",{target:y}),b.status="error")}}let Y=null;if((xe||W&&!W.ok)&&Q.rollbackOnFailure&&P)try{Y=B(P),w.warn("Rollback executed",Y)}catch(f){Y={restored:!1,error:f.message},w.error("Rollback failed",{error:f.message})}Q.audit&&ke(L.auditLog,{commandId:O,status:Y?.restored?"rolled_back":b.status||"completed",requesterId:A,payloadHash:je(ie),executionHash:je(b),adapter:H,intent:g,riskLevel:F,exitCode:b.exitCode||0,rolledBack:Y?.restored||!1}),await ce();let le=!xe&&(!W||W.ok);return w.info("execute() complete",{ok:le,stage:le?"executed":"failed",risk:F}),{ok:le,commandId:O,intent:g,actor:A,target:y,risk:F,stage:le?"executed":"failed",status:b.status,output:b.output||null,exitCode:b.exitCode??0,checks:C.checks,backup:P?{path:P.backupPath,existed:P.existed,hash:P.hash}:null,rollback:Y,postValidation:W,operationLog:k==="DEBUG"?K.exportLogs():void 0}}return{execute:we,exportLogs:()=>K.exportLogs(),async writeFile(A,g){let y=await we({actor:o,intent:"write_file",target:A,content:g,transaction:{backup:!0,rollbackOnFailure:!0,audit:!0}});if(!y.ok){let se=new Error(`LBE write failed [${y.error||y.stage}]${y.message?": "+y.message:""}`);throw se.lbeResult=y,se}return y},async readFile(A){let g=await we({actor:o,intent:"read_file",target:A,transaction:{audit:!0}});if(!g.ok){let y=new Error(`LBE read failed [${g.error||g.stage}]${g.message?": "+g.message:""}`);throw y.lbeResult=g,y}return g.output}}}function Br({publicKey:e,keyId:t,validDays:r=365}){let s=new Date,o=new Date(s.getTime()+r*24*3600*1e3);return{defaultKeyId:t,trustedKeys:{[t]:{publicKey:e,notBefore:s.toISOString(),expiresAt:o.toISOString()}}}}import Ft from"fs";import Vr from"path";var qt=[{name:"lbe_workspace_context",description:["Read the workspace contract for this project.","Call this FIRST \u2014 before writing, modifying, or planning any file changes.","Returns the semantics contract: what this project is, where things live,","what must never be touched, and how changes are expected to happen here.","Agents that read this contract before acting produce fewer mistakes and","require fewer corrections. If no contract exists, run: npx lbe init"].join(" "),inputSchema:{type:"object",properties:{include_enforcement:{type:"boolean",description:"Also return allow/approval/deny enforcement rules. Default: false."}},required:[]}},{name:"lbe_write_file",description:["Write content to a file under the governance controller.","The write is validated (schema \u2192 signature \u2192 nonce \u2192 policy), backed up,","and appended to the immutable audit log before any bytes are written.","Requires the actor to be in the policy allowlist."].join(" "),inputSchema:{type:"object",properties:{path:{type:"string",description:"File path to write (must be within policy filesystem.roots)"},content:{type:"string",description:"Content to write"},actor:{type:"string",description:'Actor identifier, e.g. "agent:gpt". Defaults to MCP_DEFAULT_ACTOR env.'}},required:["path","content"]}},{name:"lbe_read_file",description:"Read a file via the governance controller. Audited; policy-checked.",inputSchema:{type:"object",properties:{path:{type:"string",description:"File path to read"},actor:{type:"string",description:"Actor identifier"}},required:["path"]}},{name:"lbe_shell_command",description:["Run a shell command via the governance controller.","Command must be in the actor's policy allowCommands list.","Audited. Does not allow shell expansion beyond the policy."].join(" "),inputSchema:{type:"object",properties:{command:{type:"string",description:"Command name (must be in policy allowlist)"},args:{type:"array",items:{type:"string"},description:"Command arguments"},actor:{type:"string",description:"Actor identifier"}},required:["command"]}},{name:"lbe_patch_file",description:"Append or patch content in an existing file. Backed up before write.",inputSchema:{type:"object",properties:{path:{type:"string",description:"File path to patch"},content:{type:"string",description:"Content to append/patch"},actor:{type:"string",description:"Actor identifier"}},required:["path","content"]}},{name:"lbe_health",description:"Check LBE controller health. Returns ok status and SDK log entry count.",inputSchema:{type:"object",properties:{},required:[]}}];async function Kt(e,t,r,s="mcp:client"){let o=typeof t.actor=="string"&&t.actor?t.actor:s;switch(e){case"lbe_workspace_context":{let n=Vr.resolve(process.cwd(),"lbe.workspace.json");if(!Ft.existsSync(n))return{content:[{type:"text",text:JSON.stringify({ok:!1,error:"NO_WORKSPACE_CONTRACT",message:"No lbe.workspace.json found. Run: npx lbe init"},null,2)}]};let i;try{i=JSON.parse(Ft.readFileSync(n,"utf8"))}catch{return{content:[{type:"text",text:JSON.stringify({ok:!1,error:"CONTRACT_PARSE_ERROR",message:"lbe.workspace.json is malformed. Run: npx lbe init to regenerate."},null,2)}]}}let a={ok:!0,projectTypes:i.projectTypes??null,primaryType:i.primaryType??null,semantics:i.semantics??{}};return t.include_enforcement&&(a.enforcement=i.enforcement??{}),{content:[{type:"text",text:JSON.stringify(a,null,2)}]}}case"lbe_write_file":{let n=await r.execute({actor:o,intent:"write_file",target:t.path,content:t.content,transaction:{backup:!0,rollbackOnFailure:!0,audit:!0}});return ve(n)}case"lbe_read_file":{let n=await r.execute({actor:o,intent:"read_file",target:t.path,transaction:{backup:!1,audit:!0}});return ve(n)}case"lbe_shell_command":{let n=await r.execute({actor:o,intent:"shell_command",target:t.command,content:JSON.stringify({args:Array.isArray(t.args)?t.args:[]}),transaction:{backup:!1,audit:!0}});return ve(n)}case"lbe_patch_file":{let n=await r.execute({actor:o,intent:"patch_file",target:t.path,content:t.content,transaction:{backup:!0,rollbackOnFailure:!0,audit:!0}});return ve(n)}case"lbe_health":{let n=r.exportLogs();return{content:[{type:"text",text:JSON.stringify({ok:!0,sdkLogEntries:n.length},null,2)}]}}default:return{content:[{type:"text",text:`Unknown tool: ${e}`}],isError:!0}}}function ve(e){let t={ok:e.ok,commandId:e.commandId,stage:e.stage,risk:e.risk??void 0,output:e.output??void 0,error:e.error??void 0,message:e.message??void 0};return Object.keys(t).forEach(r=>t[r]===void 0&&delete t[r]),{content:[{type:"text",text:JSON.stringify(t,null,2)}],isError:!e.ok}}(process.argv.includes("--help")||process.argv.includes("-h"))&&(console.log(`
23
- lbe-mcp \u2014 LBE SDK MCP Server v0.4.0
24
-
25
- Wraps LBE SDK as a Model Context Protocol (MCP) server. Every tool call
26
- is handled by the local LBE SDK.
2
+ import Ae from"fs";import jt from"path";import xe from"crypto";import Vt from"fs";import Qr from"os";import x from"path";import De from"tweetnacl";import{canonicalize as nt}from"json-canonicalize";function Ce(e){return Buffer.from(e,"base64")}function Te(e){return Buffer.from(e).toString("base64")}function ee({payloadObj:e,sigB64:t,pubKeyB64:r}){try{let s=Buffer.from(nt(e),"utf8"),o=Ce(t),n=Ce(r),a=De.sign.detached.verify(new Uint8Array(s),new Uint8Array(o),new Uint8Array(n));return{valid:a,message:a?"Signature verified":"Signature verification failed"}}catch(s){return{valid:!1,message:`Signature verification error: ${s.message}`}}}function Pe(){let e=De.sign.keyPair();return{publicKey:Te(e.publicKey),secretKey:Te(e.secretKey)}}function fe({payloadObj:e,secretKeyB64:t}){try{let r=Buffer.from(nt(e),"utf8"),s=Ce(t),o=De.sign.detached(new Uint8Array(r),new Uint8Array(s));return{signature:Te(o),error:null}}catch(r){return{signature:null,error:`Signing failed: ${r.message}`}}}import dt from"fs";import ir from"path";import w from"fs";import $e from"path";import rr from"crypto";var sr={timeoutMs:5e3,pollMs:15,staleMs:3e4};function or(e){return e+".lock"}function it(e){try{let t=w.openSync(e,"wx");return w.writeSync(t,`pid:${process.pid}:${Date.now()}`),w.closeSync(t),!0}catch(t){if(t.code==="EEXIST"||t.code==="EPERM"||t.code==="EBUSY"||t.code==="EACCES")return!1;throw t}}function at(e,t){try{let r=w.statSync(e);if(Date.now()-r.mtimeMs>t)try{w.unlinkSync(e)}catch{}}catch{}}function nr(e){let t=Date.now()+e;for(;Date.now()<t;)try{Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,Math.max(1,t-Date.now()))}catch{}}function ct(e,t,r){let s=typeof t=="function"?t:r,o=typeof t=="function"?{}:t||{},{timeoutMs:n,pollMs:a,staleMs:i}={...sr,...o},c=$e.dirname(e);w.existsSync(c)||w.mkdirSync(c,{recursive:!0});let l=or(e),d=Date.now()+n,u=!1;for(;!u&&(u=it(l),!u);){if(Date.now()>=d){if(at(l,i),u=it(l),u)break;let m=new Error(`withFileLock: timeout acquiring ${l} after ${n}ms`);throw m.code="ELOCKTIMEOUT",m}at(l,i);let p=Math.floor(Math.random()*a);nr(a+p)}try{return s()}finally{try{w.unlinkSync(l)}catch{}}}function v(e,t,r={}){let s=$e.dirname(e);w.existsSync(s)||w.mkdirSync(s,{recursive:!0});let o=$e.join(s,`.tmp-${Date.now()}-${rr.randomBytes(4).toString("hex")}`);try{w.writeFileSync(o,t,r),w.renameSync(o,e)}catch(n){try{w.existsSync(o)&&w.unlinkSync(o)}catch{}throw n}}function lt(e){try{if(!w.existsSync(e))return null;let t=w.readFileSync(e,"utf8");return JSON.parse(t)}catch(t){return console.error(`[atomicWrite] Failed to read JSON from ${e}:`,t.message),null}}function ut(e){if(typeof e=="number"&&Number.isFinite(e))return{ok:!0,kind:"int",parts:[Math.floor(e)],raw:String(e)};if(typeof e!="string"||!e.trim())return{ok:!1,reason:"POLICY_VERSION_INVALID",message:"Policy version is required"};let t=e.trim();if(/^\d+$/.test(t))return{ok:!0,kind:"int",parts:[Number(t)],raw:t};let r=t.replace(/^v/i,"");if(/^\d+(\.\d+){0,2}$/.test(r)){let s=r.split(".").map(o=>Number(o));for(;s.length<3;)s.push(0);return{ok:!0,kind:"semver",parts:s,raw:t}}return{ok:!1,reason:"POLICY_VERSION_INVALID",message:`Unsupported policy version format '${e}' (use integer or semver)`}}function ar(e,t){let r=Math.max(e.parts.length,t.parts.length);for(let s=0;s<r;s++){let o=e.parts[s]??0,n=t.parts[s]??0;if(o>n)return 1;if(o<n)return-1}return 0}function pt(e){if(typeof e=="number"&&Number.isFinite(e))return{ok:!0,epochSec:e>1e12?Math.floor(e/1e3):Math.floor(e)};if(typeof e!="string"||!e.trim())return{ok:!1,reason:"POLICY_CREATED_AT_INVALID",message:"Policy createdAt is required"};let t=Date.parse(e);return Number.isNaN(t)?{ok:!1,reason:"POLICY_CREATED_AT_INVALID",message:`Invalid policy createdAt '${e}'`}:{ok:!0,epochSec:Math.floor(t/1e3)}}function cr(e){if(!dt.existsSync(e))return{schemaVersion:"1",lastAccepted:null,updatedAt:null};try{let t=JSON.parse(dt.readFileSync(e,"utf8"));if(!t||typeof t!="object")throw new Error("Policy state file has invalid structure");return{schemaVersion:String(t.schemaVersion||"1"),lastAccepted:t.lastAccepted&&typeof t.lastAccepted=="object"?t.lastAccepted:null,updatedAt:t.updatedAt||null}}catch(t){throw new Error(`Policy state at ${e} is corrupt or unreadable: ${t.message}`)}}function lr(e,t){let r=JSON.stringify(t,null,2);v(e,r,{encoding:"utf8"})}function me({policyObj:e,statePath:t=ir.resolve("data/policy.state.json"),maxCreatedAtSkewSec:r=31536e3,nowSec:s=Math.floor(Date.now()/1e3),persist:o=!0}){let n=ut(e?.version);if(!n.ok)return{ok:!1,reason:n.reason,message:n.message,updated:!1};let a=pt(e?.createdAt);if(!a.ok)return{ok:!1,reason:a.reason,message:a.message,updated:!1};let i=Math.abs(s-a.epochSec),c=Number.isFinite(r)&&r>0?Math.floor(r):31536e3;if(i>c)return{ok:!1,reason:"POLICY_CREATED_AT_SKEW_EXCEEDED",message:`Policy createdAt skew ${i}s exceeds allowed ${c}s`,updated:!1};let l;try{l=cr(t)}catch(S){return{ok:!1,reason:"POLICY_STATE_CORRUPT",message:S.message,updated:!1}}let d=l.lastAccepted,u=null,p=null,m=0;if(d&&(u=ut(d.version),p=pt(d.createdAt),u.ok&&p.ok)){if(m=ar(n,u),m<0)return{ok:!1,reason:"POLICY_VERSION_REGRESSION",message:`Policy version regression: current '${n.raw}' < last '${u.raw}'`,updated:!1};if(m===0&&a.epochSec<p.epochSec)return{ok:!1,reason:"POLICY_CREATED_AT_REGRESSION",message:`Policy createdAt regression: current '${e.createdAt}' < last '${d.createdAt}'`,updated:!1};if(m>0&&a.epochSec<p.epochSec)return{ok:!1,reason:"POLICY_CREATED_AT_REGRESSION",message:"Policy createdAt must be monotonic when version increases",updated:!1}}let _=!d||!u?.ok||!p?.ok||m>0||m===0&&a.epochSec>p.epochSec;if(o&&_){let S={schemaVersion:"1",lastAccepted:{version:e.version,createdAt:e.createdAt,environment:e.environment||null},updatedAt:new Date().toISOString()};lr(t,S)}return{ok:!0,reason:null,message:"Policy version guard passed",updated:_}}import ft from"fs";import yt from"path";import{fileURLToPath as dr}from"url";var ur=yt.dirname(dr(import.meta.url)),Fe=yt.join(ur,"lbe_engine.wasm"),mt={0:{allowed:!0,reason:null,message:"Policy check passed"},1:{allowed:!1,reason:"POLICY_NOT_CONFIGURED",message:"No policy configured"},2:{allowed:!1,reason:"REQUESTER_NOT_ALLOWED",message:"Requester not in policy"},3:{allowed:!1,reason:"COMMAND_NOT_ALLOWED",message:"Command not allowed for requester"},4:{allowed:!1,reason:"ADAPTER_NOT_ALLOWED",message:"Adapter not allowed"},5:{allowed:!1,reason:"NO_FILESYSTEM_ROOTS_DEFINED",message:"No filesystem roots defined for requester"},6:{allowed:!1,reason:"CWD_OUTSIDE_ALLOWED_ROOT",message:"Path not under allowed roots"},7:{allowed:!1,reason:"PATH_DENIED_BY_PATTERN",message:"Path matches deny pattern"},8:{allowed:!1,reason:"SHELL_CMD_DENIED",message:"Shell command not allowed"}},pr={0:{valid:!0,error:null},1:{valid:!1,error:"Missing required field: id"},2:{valid:!1,error:"Missing required field: commandId"},3:{valid:!1,error:"Missing required field: requesterId"},4:{valid:!1,error:"Missing required field: sessionId"},5:{valid:!1,error:"Missing required field: timestamp"},6:{valid:!1,error:"Missing required field: nonce"},7:{valid:!1,error:"Missing required field: requires"},8:{valid:!1,error:"Missing required field: payload"},9:{valid:!1,error:"Missing required field: signature"},10:{valid:!1,error:"Field 'id' is invalid"},11:{valid:!1,error:"Field 'commandId' is invalid"},12:{valid:!1,error:"Field 'requesterId' is invalid"},13:{valid:!1,error:"Field 'sessionId' is invalid"},14:{valid:!1,error:"Field 'timestamp' is invalid"},15:{valid:!1,error:"Field 'nonce' is invalid"},16:{valid:!1,error:"Field 'requires' is invalid"},17:{valid:!1,error:"payload: missing required field: adapter"},18:{valid:!1,error:"payload: field 'adapter' is invalid"},19:{valid:!1,error:"signature: missing required field: alg"},20:{valid:!1,error:"signature: missing required field: keyId"},21:{valid:!1,error:"signature: missing required field: sig"},22:{valid:!1,error:"signature: field 'alg' must be ed25519"},23:{valid:!1,error:"signature: field 'sig' is invalid"},24:{valid:!1,error:"Field 'risk' is invalid"}},fr={1:"KEY_ID_INVALID",2:"KEY_NOT_TRUSTED",3:"KEY_DEPRECATED",4:"KEY_REQUESTER_MISMATCH",5:"KEY_LIFECYCLE_INVALID",6:"KEY_NOT_YET_VALID",7:"KEY_EXPIRED"},mr={0:"schema",1:"timestamp",2:"key",3:"signature",4:"rate_limit",5:"nonce",6:"policy",255:"ok"},yr=["LOW","MEDIUM","HIGH","CRITICAL"],hr={ECHO:0,READ_FILE:1,WRITE_FILE:2,PATCH_FILE:3,DELETE_FILE:4,RUN_SHELL:5},ye=null;function V(){if(ye)return ye;if(!ft.existsSync(Fe))throw new Error(`LBE engine missing: ${Fe}`);let e=ft.readFileSync(Fe);return ye=new WebAssembly.Instance(new WebAssembly.Module(e),{}),ye}function he(){return new Uint8Array(V().exports.memory.buffer)}function ht(){return V().exports.lbe_in_ptr()}function gt(){return V().exports.lbe_out_ptr()}function gr(){return V().exports.lbe_buf_size()}function kt(e){let t=new TextEncoder().encode(e),r=he(),s=ht();r.set(t,s),r[s+t.length]=0}function Et(){let e=he(),t=gt(),r=t;for(;e[r]!==0&&r-t<gr();)r++;return new TextDecoder().decode(e.slice(t,r))}function kr(e){let t=he(),r=ht(),s=new DataView(t.buffer,r);e.forEach((o,n)=>s.setUint32(n*4,o>>>0,!0))}function Er(){let e=he(),t=gt(),r=new DataView(e.buffer,t);return{stage:r.getUint32(0,!0),code:r.getUint32(4,!0)}}function _t(e){kr([e.hasId?1:0,e.idValid?1:0,e.hasCommandId?1:0,e.commandIdValid?1:0,e.hasRequesterId?1:0,e.requesterIdValid?1:0,e.hasSessionId?1:0,e.sessionIdValid?1:0,e.hasTimestamp?1:0,e.timestampValid?1:0,e.hasNonce?1:0,e.nonceValid?1:0,e.hasRequires?1:0,e.requiresValid?1:0,e.hasPayload?1:0,e.hasPayloadAdapter?1:0,e.payloadAdapterValid?1:0,e.hasSignature?1:0,e.hasSignatureAlg?1:0,e.signatureAlgValid?1:0,e.hasSignatureKeyId?1:0,e.hasSignatureSig?1:0,e.signatureSigValid?1:0,e.hasRisk?1:0,e.riskValid?1:0,e.cmdTimestamp>>>0,e.nowSec>>>0,e.maxClockSkewSec>>>0,e.keyIdFormatValid?1:0,e.keyFound?1:0,e.keyNotDeprecated?1:0,e.keyRequesterMatches?1:0,e.keyNotBeforeOk?1:0,e.keyNotExpired?1:0,e.keyLifecycleFieldsPresent?1:0,e.signatureValid?1:0,e.rateLimitOk?1:0,e.rateLimitRetryAfterSec>>>0,e.nonceOk?1:0,e.policyConfigured?1:0,e.requesterConfigured?1:0,e.commandAllowed?1:0,e.adapterAllowed?1:0,e.filesystemRequired?1:0,e.filesystemRootsDefined?1:0,e.filesystemOk?1:0,e.pathDenied?1:0,e.shellRequired?1:0,e.shellCommandOk?1:0]),V().exports.lbe_validate_pipeline();let{stage:t,code:r}=Er();return{ok:t===255,stage:t,stageLabel:mr[t]||"unknown",code:r,schemaError:t===0?pr[r]?.error||"Schema invalid":null,keyReason:t===2?fr[r]||"KEY_ERROR":null,policyResult:t===6?{...mt[r]||mt[1],code:r}:null,retryAfterSec:t===4?r:0,skewSec:t===1?r:0}}function Ke({ttlSec:e,nowSec:t,newKey:r,existingEntries:s}){let o=[`${e}:${t}`,r,...s].join(`
3
+ `)+`
4
+ `;if(kt(o),V().exports.lbe_nonce_check()!==0)return{ok:!1,updatedEntriesText:null};let a=Et();return{ok:!0,updatedEntriesText:a.startsWith(`OK
5
+ `)?a.slice(3):a}}function St({windowSec:e,maxRequests:t,nowSec:r,requesterId:s,existingEntries:o}){let n=[`${e}:${t}:${r}`,s,...o].join(`
6
+ `)+`
7
+ `;kt(n);let a=V().exports.lbe_rate_check()!==0,i=Et();if(a){let c=parseInt(i.match(/^EXCEEDED:(\d+)/)?.[1]??"1",10),l=i.replace(/^EXCEEDED:\d+\n/,"");return{ok:!1,retryAfterSec:c,updatedEntriesText:l}}return{ok:!0,retryAfterSec:0,updatedEntriesText:i.startsWith(`OK
8
+ `)?i.slice(3):i}}function It(e,t=!1){let r=hr[e]??0,s=V().exports.lbe_classify_risk(r,t?1:0);return yr[s]??"LOW"}import qe from"path";function _r(e){let t=n=>e!=null&&Object.prototype.hasOwnProperty.call(e,n),r=n=>typeof n=="string",s=e?.payload,o=e?.signature;return{hasId:t("id"),idValid:r(e?.id)&&/^[A-Z_]+$/.test(e.id)&&e.id.length>=1&&e.id.length<=50,hasCommandId:t("commandId"),commandIdValid:r(e?.commandId)&&/^[a-f0-9-]+$/.test(e.commandId)&&e.commandId.length===36,hasRequesterId:t("requesterId"),requesterIdValid:r(e?.requesterId)&&e.requesterId.length>=3&&e.requesterId.length<=100,hasSessionId:t("sessionId"),sessionIdValid:r(e?.sessionId)&&e.sessionId.length>=3,hasTimestamp:t("timestamp"),timestampValid:typeof e?.timestamp=="number"&&e.timestamp>=1e9,hasNonce:t("nonce"),nonceValid:r(e?.nonce)&&e.nonce.length>=32&&e.nonce.length<=128,hasRequires:t("requires"),requiresValid:Array.isArray(e?.requires)&&e.requires.length>=1&&e.requires.every(r),hasPayload:t("payload")&&typeof s=="object"&&s!==null&&!Array.isArray(s),hasPayloadAdapter:s!=null&&Object.prototype.hasOwnProperty.call(s,"adapter"),payloadAdapterValid:r(s?.adapter),hasSignature:t("signature")&&typeof o=="object"&&o!==null&&!Array.isArray(o),hasSignatureAlg:o!=null&&Object.prototype.hasOwnProperty.call(o,"alg"),signatureAlgValid:o?.alg==="ed25519",hasSignatureKeyId:o!=null&&Object.prototype.hasOwnProperty.call(o,"keyId"),hasSignatureSig:o!=null&&Object.prototype.hasOwnProperty.call(o,"sig"),signatureSigValid:r(o?.sig)&&o.sig.length>=10,hasRisk:t("risk"),riskValid:["LOW","MEDIUM","HIGH","CRITICAL"].includes(e?.risk)}}function Sr(e,t){let r=!!(e&&e.default==="DENY"&&e.requesters&&typeof e.requesters=="object"),s=e?.requesters?.[t.requesterId],o=t.id?.toLowerCase()??"",n=!!s?.allowCommands?.some(m=>m.toLowerCase()===o),a=!!s?.allowAdapters?.includes(t.payload?.adapter),i=!!t.payload?.cwd,c=!1,l=!1,d=!1;if(i){let m=s?.filesystem?.roots??[];if(c=m.length>0,c){let _=qe.resolve(t.payload.cwd);l=m.some(b=>{let D=qe.resolve(b);return _===D||_.startsWith(D+qe.sep)}),d=(s?.filesystem?.denyPatterns??[]).some(b=>new RegExp("^"+b.replace(/\./g,"\\.").replace(/\*\*/g,".*").replace(/\*/g,"[^/]*")+"$").test(_))}}let u=!1,p=!0;if(t.id==="RUN_SHELL"){u=!0;let m=s?.exec?.allowCmds??[],_=s?.exec?.denyCmds??[],S=t.payload?.cmd;_.includes(S)?p=!1:p=m.length===0||m.includes(S)}return{policyConfigured:r,requesterConfigured:!!s,commandAllowed:n,adapterAllowed:a,filesystemRequired:i,filesystemRootsDefined:c,filesystemOk:l,pathDenied:d,shellRequired:u,shellCommandOk:p}}function Ir(e,t,r,s=new Date){if(!e||!t)return{keyIdFormatValid:!1,keyFound:!1,keyNotDeprecated:!1,keyRequesterMatches:!1,keyNotBeforeOk:!1,keyNotExpired:!1,keyLifecycleFieldsPresent:!1,publicKey:null};let n=/^[A-Za-z0-9:_-]{3,128}$/.test(t)&&t!=="default";if(!n)return{keyIdFormatValid:n,keyFound:!1,keyNotDeprecated:!1,keyRequesterMatches:!1,keyNotBeforeOk:!1,keyNotExpired:!1,keyLifecycleFieldsPresent:!1,publicKey:null};let a=e.trustedKeys?.[t],i=!!a;if(!i)return{keyIdFormatValid:n,keyFound:i,keyNotDeprecated:!1,keyRequesterMatches:!1,keyNotBeforeOk:!1,keyNotExpired:!1,keyLifecycleFieldsPresent:!1,publicKey:null};let c=!a.deprecated,l=!a.requesterId||a.requesterId===r,d=a.notBefore||a.validFrom,u=a.expiresAt||a.validUntil,p=typeof d=="string"&&typeof u=="string",m=!1,_=!1;if(p){let S=new Date(d),b=new Date(u);!isNaN(S.getTime())&&!isNaN(b.getTime())&&S<b&&(m=s>=S,_=s<b)}return{keyIdFormatValid:n,keyFound:i,keyNotDeprecated:c,keyRequesterMatches:l,keyNotBeforeOk:m,keyNotExpired:_,keyLifecycleFieldsPresent:p,publicKey:a.publicKey??null}}function wt(e){return(e?.entries??[]).map(t=>`${t.key}:${t.timestamp}`)}function vt(e){return e.split(`
9
+ `).filter(Boolean).map(t=>{let r=t.lastIndexOf(":");return{key:t.slice(0,r),timestamp:parseInt(t.slice(r+1),10)||0}})}function wr(e){return(e?.entries??[]).map(t=>`${t.requesterId}:${t.timestamp}`)}function vr(e){return e.split(`
10
+ `).filter(Boolean).map(t=>{let r=t.lastIndexOf(":");return{requesterId:t.slice(0,r),timestamp:parseInt(t.slice(r+1),10)||0}})}function Ve({commandObj:e,pubKeyB64:t,keyStore:r,nonceDb:s,policy:o,rateLimiter:n,policyStatePath:a}){let i={valid:!1,commandId:e?.commandId,checks:{},errors:[]},c=Math.floor(Date.now()/1e3),l=new Date,d=Number.isFinite(o?.security?.maxClockSkewSec)?o.security.maxClockSkewSec:600;if(a&&o?.version!==void 0)try{let f=me({policyObj:o,statePath:a});if(i.checks.policyVersion=f.ok,!f.ok)return i.errors.push({type:"POLICY_VERSION_INVALID",message:f.message}),i}catch{i.checks.policyVersion=!0}else i.checks.policyVersion=!0;let u=_r(e),p=e?.signature?.keyId,m=Ir(r,p,e?.requesterId,l),_=!1,S=m.publicKey;if(!S&&t&&(S=t),S){let f={...e};delete f.signature,_=ee({payloadObj:f,sigB64:e?.signature?.sig,pubKeyB64:S}).valid}let b=!0,D=0;if(_&&n&&typeof n.db<"u"){let f=o?.requesters?.[e.requesterId]?.rateLimit||{},g=o?.security?.defaultRateLimit||{},L=f.windowSec??g.windowSec??60,F=f.maxRequests??g.maxRequests??30,K=St({windowSec:L,maxRequests:F,nowSec:c,requesterId:e.requesterId,existingEntries:wr(n.db)});b=K.ok,D=K.retryAfterSec,K.ok&&(n.db.entries=vr(K.updatedEntriesText))}else if(_&&n&&typeof n.checkAndRecord=="function"){let f=o?.requesters?.[e.requesterId]?.rateLimit||{},g=o?.security?.defaultRateLimit||{},L=n.checkAndRecord({requesterId:e.requesterId,nowSec:c,windowSec:f.windowSec??g.windowSec??60,maxRequests:f.maxRequests??g.maxRequests??30});b=L.ok,D=L.retryAfterSec??0}let M=!0,oe=`${e?.requesterId}|${e?.sessionId}|${e?.nonce}`,Y=3600;if(_&&b&&s)if(typeof s.checkAndRecord=="function")if(s.db){let f=Ke({ttlSec:Y,nowSec:c,newKey:oe,existingEntries:wt(s.db)});M=f.ok,f.ok&&(s.db.entries=vt(f.updatedEntriesText))}else M=s.checkAndRecord({requesterId:e.requesterId,sessionId:e.sessionId,nonce:e.nonce}).ok;else{let f=Ke({ttlSec:Y,nowSec:c,newKey:oe,existingEntries:wt(s)});M=f.ok,f.ok&&(s.entries=vt(f.updatedEntriesText))}let ne=Sr(o,e??{}),I=_t({...u,cmdTimestamp:e?.timestamp??0,nowSec:c,maxClockSkewSec:d,...m,signatureValid:_,rateLimitOk:b,rateLimitRetryAfterSec:D,nonceOk:M,...ne}),h=I.stage;if(i.checks.schema=h!==0,h>=1&&(i.checks.timestamp=h!==1),h>=2&&(i.checks.keyId=h!==2),h>=2&&(i.checks.signature=h!==2&&h!==3),h>=4&&(i.checks.rateLimit=h!==4),h>=5&&(i.checks.nonce=h!==5),(h>=6||I.ok)&&(i.checks.policy=h!==6),!I.ok){let f=I.stageLabel;if(f==="schema")i.errors.push({type:"SCHEMA_ERROR",message:I.schemaError||"Schema invalid"});else if(f==="timestamp")i.errors.push({type:"TIMESTAMP_SKEW_EXCEEDED",message:`Command timestamp skew ${I.skewSec}s exceeds allowed ${d}s`});else if(f==="key"){let g=I.keyReason||"KEY_ERROR",L={KEY_ID_INVALID:`Invalid keyId '${p}'`,KEY_NOT_TRUSTED:`Key '${p}' is not in trusted key store`,KEY_DEPRECATED:`Key '${p}' is deprecated`,KEY_REQUESTER_MISMATCH:`Key '${p}' is not authorized for requester '${e?.requesterId}'`,KEY_LIFECYCLE_INVALID:`Key '${p}' must define notBefore and expiresAt`,KEY_NOT_YET_VALID:`Key '${p}' is not yet valid`,KEY_EXPIRED:`Key '${p}' has expired`};i.errors.push({type:g,message:L[g]||g})}else f==="signature"?i.errors.push({type:"SIGNATURE_INVALID",message:S?"Signature verification failed":"No public key available"}):f==="rate_limit"?i.errors.push({type:"RATE_LIMIT_EXCEEDED",message:`Rate limit exceeded. Retry after ${I.retryAfterSec}s`}):f==="nonce"?i.errors.push({type:"REPLAY_NONCE",message:"Nonce has already been used"}):f==="policy"&&I.policyResult?i.errors.push({type:I.policyResult.reason,message:I.policyResult.message}):i.errors.push({type:"VALIDATION_FAILED",message:`Failed at stage: ${f}`});return i}return i.valid=!0,i.risk=It(e.id,e.payload?.cmd==="rm"),i.message="Command validation successful",i}import ge from"fs";import xr from"path";var ke=class{constructor(t,r=3600){this.dbPath=t,this.ttlSec=r,this.db={entries:[]}}async load(){if(!ge.existsSync(this.dbPath)){this.db={entries:[]};return}try{let t=ge.readFileSync(this.dbPath,"utf8");this.db=JSON.parse(t),this.prune()}catch(t){throw new Error(`Nonce DB at ${this.dbPath} is corrupt or unreadable: ${t.message}`)}}async save(){try{let t=xr.dirname(this.dbPath);ge.existsSync(t)||ge.mkdirSync(t,{recursive:!0}),v(this.dbPath,JSON.stringify(this.db,null,2),{encoding:"utf8"})}catch(t){throw new Error(`Failed to save nonce DB: ${t.message}`)}}checkAndRecord({requesterId:t,sessionId:r,nonce:s}){let o=Math.floor(Date.now()/1e3);this.db.entries=this.db.entries.filter(a=>o-a.timestamp<=this.ttlSec);let n=`${t}|${r}|${s}`;return this.db.entries.some(a=>a.key===n)?{ok:!1,reason:"REPLAY_NONCE",message:"Nonce has already been used"}:(this.db.entries.push({key:n,timestamp:o}),{ok:!0,reason:null,message:"Nonce accepted"})}prune(){let t=Math.floor(Date.now()/1e3),r=this.db.entries.length;this.db.entries=this.db.entries.filter(o=>t-o.timestamp<=this.ttlSec);let s=this.db.entries.length;return{prunedCount:r-s,remainingCount:s}}};import Ee from"fs";import br from"path";var _e=class{constructor(t){this.dbPath=t,this.db={entries:[]}}async load(){try{if(!Ee.existsSync(this.dbPath)){this.db={entries:[]};return}let t=Ee.readFileSync(this.dbPath,"utf8");this.db=JSON.parse(t),Array.isArray(this.db.entries)||(this.db={entries:[]})}catch{this.db={entries:[]}}}async save(){let t=br.dirname(this.dbPath);Ee.existsSync(t)||Ee.mkdirSync(t,{recursive:!0}),v(this.dbPath,JSON.stringify(this.db,null,2),{encoding:"utf8"})}checkAndRecord({requesterId:t,nowSec:r,windowSec:s,maxRequests:o}){let n=Number.isFinite(r)?r:Math.floor(Date.now()/1e3),a=Number.isFinite(s)&&s>0?s:60,i=Number.isFinite(o)&&o>0?o:30,c=n-a;this.db.entries=this.db.entries.filter(d=>d.timestamp>=c);let l=this.db.entries.filter(d=>d.requesterId===t);if(l.length>=i){let d=l.sort((p,m)=>p.timestamp-m.timestamp)[0],u=Math.max(1,a-(n-d.timestamp));return{ok:!1,reason:"RATE_LIMIT_EXCEEDED",message:`Rate limit exceeded for '${t}' (${i}/${a}s)`,retryAfterSec:u}}return this.db.entries.push({requesterId:t,timestamp:n}),{ok:!0,reason:null,message:"Rate limit check passed",retryAfterSec:0}}};import J from"fs";import Ar from"path";import Rr from"crypto";function Lr(e){return Rr.createHash("sha256").update(e).digest("hex")}function Nr(e){try{if(!J.existsSync(e))return"GENESIS";let t=J.readFileSync(e,"utf8").trim();if(!t)return"GENESIS";let r=t.split(`
11
+ `),s=r[r.length-1];try{return JSON.parse(s).hash||"GENESIS"}catch{return"GENESIS"}}catch{return"GENESIS"}}function Se(e,t){let r=Ar.dirname(e);J.existsSync(r)||J.mkdirSync(r,{recursive:!0});let s;return ct(e,()=>{let o=Nr(e),n={...t,prevHash:o,timestamp:new Date().toISOString()};delete n.hash;let a=JSON.stringify(n),i=Lr(a),c=JSON.stringify({...n,hash:i}),l="";J.existsSync(e)&&(l=J.readFileSync(e,"utf8"));try{v(e,l+c+`
12
+ `,{encoding:"utf8"})}catch(d){throw new Error(`Audit log write failed: ${d.message}`)}s={success:!0,hash:i,prevHash:o,message:"Audit entry appended"}}),s}async function xt(e){return{adapter:"noop",commandId:e.commandId||"unknown",command:e.id||"unknown",status:"completed",output:`[NOOP] Would execute: ${e.id||"unknown"} on adapter: ${e.payload?.adapter||"unknown"}`,exitCode:0,timestamp:new Date().toISOString()}}import{spawnSync as Or}from"child_process";import Be from"path";function Cr(e){if(e===void 0)return{ok:!0,args:[]};if(!Array.isArray(e))return{ok:!1,error:"payload.args must be an array"};let t=[];for(let r of e){if(typeof r!="string"&&typeof r!="number"&&typeof r!="boolean")return{ok:!1,error:"payload.args may only contain string, number, or boolean values"};t.push(String(r))}return{ok:!0,args:t}}async function bt(e,t,r){let s=e.payload,o=3e4,n=1024*1024;if(s.adapter!=="shell")return{adapter:"shell",commandId:e.commandId,status:"error",error:"Adapter mismatch",exitCode:1};let a=r?.exec?.allowCmds||[];if((r?.exec?.denyCmds||[]).includes(s.cmd))return{adapter:"shell",commandId:e.commandId,status:"blocked",error:`Command '${s.cmd}' is denied`,exitCode:2};if(a.length>0&&!a.includes(s.cmd))return{adapter:"shell",commandId:e.commandId,status:"blocked",error:`Command '${s.cmd}' not in allowlist`,exitCode:2};if(!(r?.filesystem?.roots||[]).some(u=>{let p=Be.resolve(u),m=Be.resolve(s.cwd);return m===p||m.startsWith(p+Be.sep)}))return{adapter:"shell",commandId:e.commandId,status:"blocked",error:`CWD '${s.cwd}' not authorized`,exitCode:2};let d=Cr(s.args);if(!d.ok)return{adapter:"shell",commandId:e.commandId,status:"blocked",error:d.error,exitCode:2};try{let u=Or(s.cmd,d.args,{cwd:s.cwd,timeout:o,encoding:"utf8",maxBuffer:n,stdio:["pipe","pipe","pipe"],shell:!1});if(u.error)throw u.error;let p=`${u.stdout||""}${u.stderr||""}`,m=u.status??1;return m!==0?{adapter:"shell",commandId:e.commandId,command:s.cmd,status:"error",error:p.substring(0,n)||`Command exited with code ${m}`,exitCode:m,timestamp:new Date().toISOString()}:{adapter:"shell",commandId:e.commandId,command:s.cmd,status:"completed",output:p.substring(0,n),exitCode:0,timestamp:new Date().toISOString()}}catch(u){return{adapter:"shell",commandId:e.commandId,command:s.cmd,status:"error",error:u.message,exitCode:u.status||1,timestamp:new Date().toISOString()}}}import re from"fs";import X from"path";import B from"fs";import Ie from"path";import Tr from"crypto";function te(e,t){let r=t||Ie.resolve("data/backups");B.existsSync(r)||B.mkdirSync(r,{recursive:!0});let s=Ie.resolve(e),o=B.existsSync(s),n=null,a=null;o&&(n=B.readFileSync(s),a=Tr.createHash("sha256").update(n).digest("hex"));let i=Ie.basename(s).replace(/[^a-zA-Z0-9._-]/g,"_"),c=`${Date.now()}-${a?a.slice(0,8):"new"}-${i}`,l=o?Ie.join(r,c):null;return o&&n!==null&&v(l,n),{originalPath:s,backupPath:l,existed:o,hash:a,createdAt:new Date().toISOString()}}function j(e){if(!e)return{restored:!1,error:"No backup metadata"};let{originalPath:t,backupPath:r,existed:s}=e;if(!s)try{return B.existsSync(t)&&B.unlinkSync(t),{restored:!0,action:"deleted"}}catch(o){return{restored:!1,error:o.message}}if(!r||!B.existsSync(r))return{restored:!1,error:"Backup file not found at: "+r};try{let o=B.readFileSync(r);return v(t,o),{restored:!0,action:"restored"}}catch(o){return{restored:!1,error:o.message}}}var Dr=10*1024*1024;function Pr(e,t){return e?X.isAbsolute(e)?X.resolve(e):X.resolve(t||process.cwd(),e):null}function $r(e,t){let r=X.resolve(e);return t.some(s=>{let o=X.resolve(s);return r===o||r.startsWith(o+X.sep)})}function Fr(e,t){for(let r of t||[])if(new RegExp("^"+r.replace(/\./g,"\\.").replace(/\*\*/g,".*").replace(/\*/g,"[^/\\\\]*")+"$").test(e))return r;return null}function z(e,t,r,s=2){return{adapter:"file",commandId:e.commandId,status:"blocked",errorCode:t,error:r,exitCode:s}}function $(e,t,r,s=null,o=1){return{adapter:"file",commandId:e.commandId,status:"error",errorCode:t,error:r,backup:s?we(s):null,exitCode:o}}function we(e){return e?{path:e.backupPath,existed:e.existed,hash:e.hash,createdAt:e.createdAt}:null}async function At(e,t,r){let s=e.payload,o=s.action,n=s.cwd||process.cwd(),a=Pr(s.target,n);if(!o)return z(e,"FILE_NO_ACTION","payload.action is required");if(!a&&o!=="noop")return z(e,"FILE_NO_TARGET","payload.target is required");let i=r?.filesystem?.roots||[];if(i.length===0)return z(e,"FILE_NO_ROOTS","No filesystem roots defined for requester");if(!$r(a,i))return z(e,"FILE_OUTSIDE_ROOT",`'${a}' is outside allowed roots`);let c=Fr(a,r?.filesystem?.denyPatterns);if(c)return z(e,"FILE_PATH_DENIED",`'${a}' matches deny pattern: ${c}`);switch(o){case"read":return Kr(e,a);case"write":return qr(e,a,s);case"patch":return Vr(e,a,s);case"delete":return Br(e,a);default:return z(e,"FILE_UNKNOWN_ACTION",`Unknown action: '${o}'`)}}function Kr(e,t){if(!re.existsSync(t))return $(e,"FILE_NOT_FOUND",`Not found: ${t}`);try{let r=re.statSync(t);if(r.size>Dr)return $(e,"FILE_TOO_LARGE","File exceeds 10 MB read limit");let s=re.readFileSync(t,"utf8");return{adapter:"file",action:"read",commandId:e.commandId,status:"completed",target:t,output:s,bytesRead:r.size,exitCode:0}}catch(r){return $(e,"FILE_READ_ERROR",r.message)}}function qr(e,t,r){let s=r.content;if(s==null)return $(e,"FILE_MISSING_CONTENT","payload.content is required for write");let o=Me(t);try{return v(t,s,{encoding:"utf8"}),{adapter:"file",action:"write",commandId:e.commandId,status:"completed",target:t,backup:we(o),output:`Wrote ${Buffer.byteLength(s,"utf8")} bytes to ${t}`,exitCode:0}}catch(n){return j(o),$(e,"FILE_WRITE_ERROR",n.message,o)}}function Vr(e,t,r){let s=r.content;if(s==null)return $(e,"FILE_MISSING_CONTENT","payload.content is required for patch");let o=Me(t);try{return v(t,s,{encoding:"utf8"}),{adapter:"file",action:"patch",commandId:e.commandId,status:"completed",target:t,backup:we(o),output:`Patched ${t} (${Buffer.byteLength(s,"utf8")} bytes)`,exitCode:0}}catch(n){return j(o),$(e,"FILE_PATCH_ERROR",n.message,o)}}function Br(e,t){if(!re.existsSync(t))return $(e,"FILE_NOT_FOUND",`Not found: ${t}`);let r=Me(t);try{return re.unlinkSync(t),{adapter:"file",action:"delete",commandId:e.commandId,status:"completed",target:t,backup:we(r),output:`Deleted ${t}`,exitCode:0}}catch(s){return j(r),$(e,"FILE_DELETE_ERROR",s.message,r)}}function Me(e){try{return te(e)}catch{return null}}async function Rt(e,t,r){let s=Date.now();try{let o=e.id||"";if(!o.toUpperCase().startsWith("OBSERVE"))return{adapter:"observer",commandId:e.commandId,status:"error",error:`Observer adapter only handles OBSERVE_* commands, got '${o}'`,exitCode:1};let{source:n,context:a,issueType:i,description:c,severity:l,metadata:d}=e.payload||{};if(!i||!c)return{adapter:"observer",commandId:e.commandId,status:"error",error:"Observer payload must include issueType and description",exitCode:1};let u=["low","medium","high","critical"];return l&&!u.includes(l)?{adapter:"observer",commandId:e.commandId,status:"error",error:`Invalid severity '${l}'. Must be one of: ${u.join(", ")}`,exitCode:1}:{adapter:"observer",commandId:e.commandId,status:"recorded",timestamp:new Date().toISOString(),requesterId:e.requesterId,observation:{source:n||"unknown",context:a||"unknown",issueType:i,description:c,severity:l||"info",metadata:d||{}},duration_ms:Date.now()-s,exitCode:0}}catch(o){return{adapter:"observer",commandId:e.commandId,status:"error",error:`Observer execution failed: ${o.message}`,exitCode:9}}}var Lt={noop:xt,shell:bt,file:At,observer:Rt};function Mr(e){return Lt[e]}async function Nt(e,t,r,s){let o=Mr(e);if(!o)return{adapter:e,commandId:t.commandId,status:"error",error:`Adapter '${e}' not found`,exitCode:1};try{return await o(t,r,s)}catch(n){return{adapter:e,commandId:t.commandId,status:"error",error:`Adapter execution failed: ${n.message}`,exitCode:9}}}var Ot=Object.keys(Lt);import Pt from"fs";import Wr from"path";import Ct from"fs";import Yr from"path";var Ur=/^[A-Za-z0-9:_-]{3,128}$/;function jr(e){return typeof e=="string"&&Ur.test(e)&&e!=="default"}function Tt(e){let t=Yr.resolve(e);if(!Ct.existsSync(t))return{ok:!1,reason:"KEY_STORE_MISSING",message:`Key store not found: ${t}`,store:null};try{let r=Ct.readFileSync(t,"utf-8"),s=JSON.parse(r);return!s||typeof s!="object"||typeof s.trustedKeys!="object"?{ok:!1,reason:"KEY_STORE_INVALID",message:`Invalid key store format: ${t}`,store:null}:{ok:!0,reason:null,message:"Key store loaded",store:s}}catch(r){return{ok:!1,reason:"KEY_STORE_INVALID_JSON",message:`Unable to parse key store: ${r.message}`,store:null}}}function Dt({keyStore:e,keyId:t,requesterId:r,now:s=new Date}){if(!e||typeof e!="object")return{ok:!1,reason:"KEY_STORE_UNAVAILABLE",message:"Trusted key store is not available",publicKey:null};if(!jr(t))return{ok:!1,reason:"KEY_ID_INVALID",message:`Invalid keyId '${t}'. Use versioned key IDs like 'agent:gpt-v1-2026Q1'`,publicKey:null};let o=e.trustedKeys?.[t];if(!o)return{ok:!1,reason:"KEY_NOT_TRUSTED",message:`Key '${t}' is not in trusted key store`,publicKey:null};if(o.deprecated)return{ok:!1,reason:"KEY_DEPRECATED",message:`Key '${t}' is deprecated`,publicKey:null};if(o.requesterId&&o.requesterId!==r)return{ok:!1,reason:"KEY_REQUESTER_MISMATCH",message:`Key '${t}' is not authorized for requester '${r}'`,publicKey:null};let n=o.notBefore||o.validFrom,a=o.expiresAt||o.validUntil;if(typeof n!="string"||typeof a!="string")return{ok:!1,reason:"KEY_LIFECYCLE_INVALID",message:`Key '${t}' must define lifecycle fields 'notBefore' and 'expiresAt'`,publicKey:null};let i=new Date(n),c=new Date(a);return Number.isNaN(i.getTime())||Number.isNaN(c.getTime())?{ok:!1,reason:"KEY_LIFECYCLE_INVALID",message:`Key '${t}' has invalid lifecycle timestamp(s)`,publicKey:null}:i>=c?{ok:!1,reason:"KEY_LIFECYCLE_INVALID",message:`Key '${t}' has notBefore >= expiresAt`,publicKey:null}:s<i?{ok:!1,reason:"KEY_NOT_YET_VALID",message:`Key '${t}' not valid until ${n}`,publicKey:null}:s>c?{ok:!1,reason:"KEY_EXPIRED",message:`Key '${t}' expired on ${a}`,publicKey:null}:!o.publicKey||typeof o.publicKey!="string"?{ok:!1,reason:"KEY_CONFIG_INVALID",message:`Trusted key '${t}' is missing publicKey`,publicKey:null}:{ok:!0,reason:null,message:"Trusted key resolved",publicKey:o.publicKey}}function $t({policyObj:e,keyStore:t,policySigPath:r="./config/policy.sig.json",allowUnsigned:s=!1}){let o=Wr.resolve(r);if(!Pt.existsSync(o))return s?{ok:!0,skipped:!0,reason:"POLICY_SIGNATURE_SKIPPED",message:`Policy signature not found: ${o} (allowed by flag)`}:{ok:!1,skipped:!1,reason:"POLICY_SIGNATURE_MISSING",message:`Policy signature file not found: ${o}`};let n;try{n=JSON.parse(Pt.readFileSync(o,"utf-8"))}catch(c){return{ok:!1,skipped:!1,reason:"POLICY_SIGNATURE_INVALID",message:`Unable to parse policy signature file: ${c.message}`}}if(!n||n.alg!=="ed25519"||typeof n.keyId!="string"||typeof n.sig!="string")return{ok:!1,skipped:!1,reason:"POLICY_SIGNATURE_INVALID",message:"Policy signature envelope must include {alg, keyId, sig}"};if(!t)return{ok:!1,skipped:!1,reason:"POLICY_SIGNER_KEY_STORE_UNAVAILABLE",message:"Trusted key store is required for policy signature verification"};let a=Dt({keyStore:t,keyId:n.keyId,requesterId:void 0});if(!a.ok)return{ok:!1,skipped:!1,reason:"POLICY_SIGNER_NOT_TRUSTED",message:a.message};let i=ee({payloadObj:e,sigB64:n.sig,pubKeyB64:a.publicKey});return i.valid?{ok:!0,skipped:!1,reason:null,message:"Policy signature verified",keyId:n.keyId}:{ok:!1,skipped:!1,reason:"POLICY_SIGNATURE_INVALID",message:i.message}}import Gr from"crypto";import Hr from"path";var Ue=class{constructor(t){this.dbPath=t||Hr.resolve("data/checkpoints.db.json"),this.store={checkpoints:{},tokens:{}},this._load()}_load(){let t=lt(this.dbPath);t&&(this.store=t,this.store.checkpoints=this.store.checkpoints||{},this.store.tokens=this.store.tokens||{})}_save(){let t=JSON.stringify(this.store,null,2);v(this.dbPath,t,{encoding:"utf8"})}saveCheckpoint(t,r){this.store.checkpoints[t]={jobId:t,...r,updatedAt:Date.now()},this._save()}getCheckpoint(t){return this.store.checkpoints[t]||null}getAllCheckpoints(){return Object.values(this.store.checkpoints)}removeCheckpoint(t){return this.store.checkpoints[t]?(delete this.store.checkpoints[t],this._save(),!0):!1}saveToken(t,r){this.store.tokens[t]={tokenId:t,...r,createdAt:Date.now()},this._save()}getToken(t){return this.store.tokens[t]||null}getAllTokens(){return Object.values(this.store.tokens)}removeToken(t){return this.store.tokens[t]?(delete this.store.tokens[t],this._save(),!0):!1}},Ye=null;function Ft(e){return Ye||(Ye=new Ue(e)),Ye}var We=class{constructor(t){this.store=Ft(t),this._pendingResolvers=new Map}createToken(t,r={}){let s=Gr.randomBytes(16).toString("hex"),o={jobId:t,context:r,status:"pending",expiresAt:Date.now()+1440*60*1e3};return this.store.saveToken(s,o),s}awaitApproval(t){let r=this.store.getToken(t);return r?r.status!=="pending"?Promise.reject(new Error(`Approval token ${t} is no longer pending (status: ${r.status})`)):Date.now()>r.expiresAt?(this.store.removeToken(t),Promise.reject(new Error(`Approval token ${t} expired`))):new Promise((s,o)=>{this._pendingResolvers.set(t,{resolve:s,reject:o})}):Promise.reject(new Error(`Approval token ${t} not found`))}approve(t,r={}){let s=this.store.getToken(t);if(!s)throw new Error("Token not found");if(s.status!=="pending")throw new Error("Token not pending");this.store.saveToken(t,{...s,status:"approved",approverData:r,resolvedAt:Date.now()});let o=this._pendingResolvers.get(t);return o&&(o.resolve({approved:!0,approverData:r}),this._pendingResolvers.delete(t)),!0}deny(t,r="Manually denied"){let s=this.store.getToken(t);if(!s)throw new Error("Token not found");if(s.status!=="pending")throw new Error("Token not pending");this.store.saveToken(t,{...s,status:"denied",reason:r,resolvedAt:Date.now()});let o=this._pendingResolvers.get(t);return o&&(o.reject(new Error(`Approval denied: ${r}`)),this._pendingResolvers.delete(t)),!0}},je=null;function Kt(e){return je||(je=new We(e)),je}var He={DEBUG:0,INFO:1,WARN:2,ERROR:3};function ve({level:e="INFO",maxHistory:t=500,silent:r=!1}={}){let s=He[e]??He.INFO,o=[];function n(i,c,l,d){let u={ts:new Date().toISOString(),level:i,scope:c,message:l,...d!==void 0?{meta:d}:{}};if(o.length>=t&&o.shift(),o.push(u),!r&&He[i]>=s){let p=d!==void 0?`[${i}] [${c}] ${l} ${JSON.stringify(d)}`:`[${i}] [${c}] ${l}`;process.stderr.write(p+`
13
+ `)}}function a(i){return{debug:(c,l)=>n("DEBUG",i,c,l),info:(c,l)=>n("INFO",i,c,l),warn:(c,l)=>n("WARN",i,c,l),error:(c,l)=>n("ERROR",i,c,l)}}return{scope:a,debug:(i,c)=>n("DEBUG","lbe",i,c),info:(i,c)=>n("INFO","lbe",i,c),warn:(i,c)=>n("WARN","lbe",i,c),error:(i,c)=>n("ERROR","lbe",i,c),exportLogs:()=>[...o],clearHistory:()=>{o.length=0},get historyLength(){return o.length}}}var Jr=process.env.LBE_LOG_LEVEL||"INFO",zr=process.env.LBE_LOG_SILENT==="1",Io=ve({level:Jr,silent:zr});function se(e){if(e===null||typeof e!="object"||Object.isFrozen(e))return e;Object.freeze(e);for(let t of Object.getOwnPropertyNames(e)){let r=e[t];typeof r=="object"&&r!==null&&!Object.isFrozen(r)&&se(r)}return e}import ze from"fs";import Ge from"path";var Q=class extends Error{constructor(t,r,s){super(t),this.name="InvariantGateError",this.checks=r,this.failures=s}};function qt(e,t,r){let s={},o=[],n=!!(t&&typeof t.version<"u"&&t.requesters&&typeof t.requesters=="object"&&t.default==="DENY");s.policy_structure=n,n||o.push("Policy missing required fields: version, requesters, default=DENY");let a=!!(r&&typeof r=="object"&&Object.keys(r).length>0);s.keys_available=a,a||o.push("No trusted keys loaded \u2014 provide config/keys.json");let i=Ge.dirname(e.auditLog);s.audit_log_writable=Je(i),s.audit_log_writable||o.push(`Audit log directory not writable: ${i}`);let c=Ge.dirname(e.nonceDb);s.nonce_db_writable=Je(c),s.nonce_db_writable||o.push(`Nonce DB directory not writable: ${c}`);let l=Ge.dirname(e.rateLimit);if(s.rate_limit_writable=Je(l),s.rate_limit_writable||o.push(`Rate-limit DB directory not writable: ${l}`),t&&t.requesters){let d=[];for(let[u,p]of Object.entries(t.requesters))for(let m of p.allowAdapters||[])Ot.includes(m)||d.push(`${u}\u2192${m}`);s.adapter_chain_valid=d.length===0,s.adapter_chain_warnings=d.length>0?d:[]}else s.adapter_chain_valid=!0,s.adapter_chain_warnings=[];return s.secret_key_present=!!e.secretKey,s.secret_key_present||o.push("secretKey not provided to createLBE()"),{ok:o.length===0,checks:s,failures:o}}function Xe(e,t,r){let s=qt(e,t,r);if(!s.ok){let o=s.failures.length;throw new Q(`Invariant gate: ${o} violation${o===1?"":"s"} \u2014 ${s.failures.join(" | ")}`,s.checks,s.failures)}return s}function Xr(e){try{return ze.accessSync(e,ze.constants.W_OK),!0}catch{return!1}}function Je(e){if(Xr(e))return!0;try{return ze.mkdirSync(e,{recursive:!0}),!0}catch{return!1}}function Zr(e,t){let r=x.resolve(e||process.cwd());if(!t||t==="local"){let s=xe.createHash("sha256").update(r).digest("hex").slice(0,16);return x.join(Qr.homedir(),".lbe","workspaces",s)}if(t==="workspace")return x.join(r,".lbe");if(t&&typeof t=="object"&&t.adapter)return null;throw new Error(`createLBE: unknown state option: ${JSON.stringify(t)}`)}var es={patch_file:"PATCH_FILE",write_file:"WRITE_FILE",read_file:"READ_FILE",delete_file:"DELETE_FILE",run_shell:"RUN_SHELL",echo:"ECHO"},ts={PATCH_FILE:"file",WRITE_FILE:"file",READ_FILE:"file",DELETE_FILE:"file",RUN_SHELL:"shell",ECHO:"noop"},rs=new Set(["HIGH","CRITICAL"]);function Qe(e){return xe.createHash("sha256").update(JSON.stringify(e)).digest("hex")}function ss(e,t){if(!t?.requireApproval)return!1;let r=t.requireApproval;return r===!0?!0:Array.isArray(r)?r.includes(e)||r.includes("*")||rs.has(e)&&r.includes("HIGH+"):!1}function Bt(e={}){if(e.rootDir&&!e.secretKey){let A=Pe(),E=e.keyId||"sdk-auto-key";e={defaultActor:"agent:sdk",logLevel:"WARN",...e,secretKey:A.secretKey,keyId:E,keyStore:e.keyStore||os({publicKey:A.publicKey,keyId:E}),policy:e.policy||{version:1,default:"DENY",requesters:{"agent:sdk":{allowCommands:["write_file","read_file","patch_file","delete_file"],allowAdapters:["file"],filesystem:{roots:[e.rootDir],denyPatterns:["*.key","*.env","*.secret"]}}}}}}let{secretKey:t,keyId:r="sdk-key-v1",sessionId:s,defaultActor:o="agent:sdk",policy:n,keyStore:a,policyPath:i,keysStorePath:c,policySigPath:l,policyStatePath:d,nonceDbPath:u,rateLimitDbPath:p,auditLogPath:m,backupDir:_,allowUnsignedPolicy:S=!1,state:b="local",rootDir:D,logLevel:M=process.env.LBE_LOG_LEVEL||"INFO",logSilent:oe=process.env.LBE_LOG_SILENT==="1"}=e,Y=n&&typeof n=="object"?n:null,ne=a&&typeof a=="object"?a:null,I=Zr(D,b),h={secretKey:t,policy:i||x.resolve("config/policy.default.json"),keys:c||x.resolve("config/keys.json"),policySig:l||x.resolve("config/policy.sig.json"),policyState:d||x.join(I,"policy.state.json"),nonceDb:u||x.join(I,"nonce.db.json"),rateLimit:p||x.join(I,"rate-limit.db.json"),auditLog:m||x.join(I,"audit.log.jsonl"),backupDir:_||x.join(I,"backups")},f=ve({level:M,silent:oe}),g=f.scope("Executor"),L=f.scope("Validator"),F=f.scope("Policy");async function K({actor:A,intent:E,target:k,content:ie,args:Xt=[],transaction:Qt={}}){let Z={validate:!0,backup:!0,rollbackOnFailure:!0,audit:!0,...Qt};g.info("execute() called",{actor:A,intent:E,target:k});let ae=es[E]||E.toUpperCase().replace(/-/g,"_"),W=ts[ae]||"noop",O;if(Y)O=Y,F.debug("Using inline policy",{version:O.version});else try{O=JSON.parse(Vt.readFileSync(h.policy,"utf8")),F.debug("Policy loaded from file",{version:O.version})}catch(y){return F.error("Policy load failed",{error:y.message}),{ok:!1,stage:"policy_load",error:"POLICY_LOAD_FAILED",message:y.message}}let U;if(ne)U=ne,L.debug("Using inline keyStore");else{let y=Tt(h.keys);U=y.ok?y.store:null,L.debug("Keys loaded from file",{ok:y.ok})}se(O),U&&se(U);try{let y=Xe(h,O,U);L.debug("Invariant gate passed",y.checks)}catch(y){if(y instanceof Q)return L.error("Invariant gate failed",{failures:y.failures}),{ok:!1,stage:"invariant_gate",error:"INVARIANT_GATE_FAILED",message:y.message,checks:y.checks,failures:y.failures};throw y}if(!Y){let y=$t({policyObj:O,keyStore:U,policySigPath:h.policySig,allowUnsigned:S});if(!y.ok)return F.error("Policy signature invalid",{reason:y.reason}),{ok:!1,stage:"policy_sig",error:y.reason,message:y.message};let N=me({policyObj:O,statePath:h.policyState});if(!N.ok)return F.error("Policy version guard failed",{reason:N.reason}),{ok:!1,stage:"policy_version",error:N.reason,message:N.message};F.debug("Policy signature and version valid")}if(!t)return{ok:!1,stage:"sign",error:"NO_SECRET_KEY",message:"createLBE requires secretKey"};let Zt=Math.floor(Date.now()/1e3),er=xe.randomBytes(32).toString("hex"),tr=s||`sdk-${Date.now()}`,C=xe.randomUUID();g.debug("Proposal built",{commandId:C,commandId_str:ae,adapter:W});let ce={id:ae,commandId:C,requesterId:A,sessionId:tr,timestamp:Zt,nonce:er,requires:["policy","signature"],payload:{adapter:W,action:E.includes("_")?E.split("_")[0]:E,target:k?x.resolve(k):null,content:ie||null,args:Xt,cwd:k?x.dirname(x.resolve(k)):process.cwd()}},le=fe({payloadObj:ce,secretKeyB64:t});if(le.error)return g.error("Signing failed",{error:le.error}),{ok:!1,stage:"sign",commandId:C,error:"SIGN_FAILED",message:le.error};let de={...ce,signature:{alg:"ed25519",keyId:r,sig:le.signature}},Le=new ke(h.nonceDb);await Le.load();let Ne=new _e(h.rateLimit);await Ne.load();let T=Ve({commandObj:de,keyStore:U,nonceDb:Le,policy:O,rateLimiter:Ne,policyStatePath:Y?null:h.policyState}),ue=async()=>{await Le.save().catch(()=>{}),await Ne.save().catch(()=>{})};if(!T.valid)return L.warn("Validation failed",{error:T.errors[0]?.type,checks:T.checks}),await ue(),Z.audit&&Se(h.auditLog,{commandId:C,status:"rejected",requesterId:A,payloadHash:Qe(de),reason:T.errors[0]?.type,intent:E}),{ok:!1,stage:"validate",commandId:C,error:T.errors[0]?.type,message:T.errors[0]?.message,checks:T.checks,operationLog:f.exportLogs()};L.info("Validation passed",{risk:T.risk,checks:T.checks});let q=T.risk||"LOW",st=O.requesters?.[A];if(ss(q,st)){g.warn("Approval required",{risk:q,commandId:C}),await ue();let N=Kt(h.policyState).createToken(C,{actor:A,intent:E,target:k,risk:q,commandId:ae});return{ok:!1,stage:"approval_pending",commandId:C,approvalToken:N,risk:q,message:`${q} risk operation requires approval. Token: ${N}`,operationLog:f.exportLogs()}}let P=null;if(Z.backup&&k){let y=["write","patch","delete"].includes(ce?.payload?.action??E.split("_")[0]);try{P=te(x.resolve(k),h.backupDir),g.debug("Backup created",{existed:P.existed,path:P.backupPath})}catch(N){if(y)return g.error("Backup failed \u2014 aborting write transaction",{error:N.message}),await ue(),{ok:!1,stage:"backup",error:"BACKUP_FAILED",message:N.message};g.warn("Backup failed (non-fatal for read)",{error:N.message})}}g.info("Executing adapter",{adapter:W,target:k});let R;try{R=await Nt(W,de,O,st)}catch(y){R={adapter:W,commandId:C,status:"error",error:y.message,exitCode:1}}g.debug("Adapter returned",{status:R.status,exitCode:R.exitCode});let Oe=R.status==="error"||R.exitCode!==0&&R.exitCode!==void 0,H=null;if(Z.validate&&k&&!Oe){let y=["write","patch"],N=ce.payload.action;if(y.includes(N)){let ot=Vt.existsSync(x.resolve(k));H={ok:ot,check:"target_exists",target:k},ot?g.debug("Post-execution validation passed"):(g.error("Post-execution validation failed \u2014 target missing after write",{target:k}),R.status="error")}}let G=null;if((Oe||H&&!H.ok)&&Z.rollbackOnFailure&&P)try{G=j(P),g.warn("Rollback executed",G)}catch(y){G={restored:!1,error:y.message},g.error("Rollback failed",{error:y.message})}Z.audit&&Se(h.auditLog,{commandId:C,status:G?.restored?"rolled_back":R.status||"completed",requesterId:A,payloadHash:Qe(de),executionHash:Qe(R),adapter:W,intent:E,riskLevel:q,exitCode:R.exitCode||0,rolledBack:G?.restored||!1}),await ue();let pe=!Oe&&(!H||H.ok);return g.info("execute() complete",{ok:pe,stage:pe?"executed":"failed",risk:q}),{ok:pe,commandId:C,intent:E,actor:A,target:k,risk:q,stage:pe?"executed":"failed",status:R.status,output:R.output||null,exitCode:R.exitCode??0,checks:T.checks,backup:P?{path:P.backupPath,existed:P.existed,hash:P.hash}:null,rollback:G,postValidation:H,operationLog:M==="DEBUG"?f.exportLogs():void 0}}return{execute:K,exportLogs:()=>f.exportLogs(),async writeFile(A,E){let k=await K({actor:o,intent:"write_file",target:A,content:E,transaction:{backup:!0,rollbackOnFailure:!0,audit:!0}});if(!k.ok){let ie=new Error(`LBE write failed [${k.error||k.stage}]${k.message?": "+k.message:""}`);throw ie.lbeResult=k,ie}return k},async readFile(A){let E=await K({actor:o,intent:"read_file",target:A,transaction:{audit:!0}});if(!E.ok){let k=new Error(`LBE read failed [${E.error||E.stage}]${E.message?": "+E.message:""}`);throw k.lbeResult=E,k}return E.output}}}function os({publicKey:e,keyId:t,validDays:r=365}){let s=new Date,o=new Date(s.getTime()+r*24*3600*1e3);return{defaultKeyId:t,trustedKeys:{[t]:{publicKey:e,notBefore:s.toISOString(),expiresAt:o.toISOString()}}}}import Mt from"fs";import ns from"path";var Yt=[{name:"lbe_workspace_context",description:["Read the workspace contract for this project.","Call this FIRST \u2014 before writing, modifying, or planning any file changes.","Returns the semantics contract: what this project is, where things live,","what must never be touched, and how changes are expected to happen here.","Agents that read this contract before acting produce fewer mistakes and","require fewer corrections. If no contract exists, run: npx lbe init"].join(" "),inputSchema:{type:"object",properties:{include_enforcement:{type:"boolean",description:"Also return allow/approval/deny enforcement rules. Default: false."}},required:[]}},{name:"lbe_write_file",description:["Write content to a file under the governance controller.","The write is validated (schema \u2192 signature \u2192 nonce \u2192 policy), backed up,","and appended to the immutable audit log before any bytes are written.","Requires the actor to be in the policy allowlist."].join(" "),inputSchema:{type:"object",properties:{path:{type:"string",description:"File path to write (must be within policy filesystem.roots)"},content:{type:"string",description:"Content to write"},actor:{type:"string",description:'Actor identifier, e.g. "agent:gpt". Defaults to MCP_DEFAULT_ACTOR env.'}},required:["path","content"]}},{name:"lbe_read_file",description:"Read a file via the governance controller. Audited; policy-checked.",inputSchema:{type:"object",properties:{path:{type:"string",description:"File path to read"},actor:{type:"string",description:"Actor identifier"}},required:["path"]}},{name:"lbe_shell_command",description:["Run a shell command via the governance controller.","Command must be in the actor's policy allowCommands list.","Audited. Does not allow shell expansion beyond the policy."].join(" "),inputSchema:{type:"object",properties:{command:{type:"string",description:"Command name (must be in policy allowlist)"},args:{type:"array",items:{type:"string"},description:"Command arguments"},actor:{type:"string",description:"Actor identifier"}},required:["command"]}},{name:"lbe_patch_file",description:"Append or patch content in an existing file. Backed up before write.",inputSchema:{type:"object",properties:{path:{type:"string",description:"File path to patch"},content:{type:"string",description:"Content to append/patch"},actor:{type:"string",description:"Actor identifier"}},required:["path","content"]}},{name:"lbe_health",description:"Check LBE controller health. Returns ok status and SDK log entry count.",inputSchema:{type:"object",properties:{},required:[]}}];async function Ut(e,t,r,s="mcp:client"){let o=typeof t.actor=="string"&&t.actor?t.actor:s;switch(e){case"lbe_workspace_context":{let n=ns.resolve(process.cwd(),"lbe.workspace.json");if(!Mt.existsSync(n))return{content:[{type:"text",text:JSON.stringify({ok:!1,error:"NO_WORKSPACE_CONTRACT",message:"No lbe.workspace.json found. Run: npx lbe init"},null,2)}]};let a;try{a=JSON.parse(Mt.readFileSync(n,"utf8"))}catch{return{content:[{type:"text",text:JSON.stringify({ok:!1,error:"CONTRACT_PARSE_ERROR",message:"lbe.workspace.json is malformed. Run: npx lbe init to regenerate."},null,2)}]}}let i={ok:!0,projectTypes:a.projectTypes??null,primaryType:a.primaryType??null,semantics:a.semantics??{}};return t.include_enforcement&&(i.enforcement=a.enforcement??{}),{content:[{type:"text",text:JSON.stringify(i,null,2)}]}}case"lbe_write_file":{let n=await r.execute({actor:o,intent:"write_file",target:t.path,content:t.content,transaction:{backup:!0,rollbackOnFailure:!0,audit:!0}});return be(n)}case"lbe_read_file":{let n=await r.execute({actor:o,intent:"read_file",target:t.path,transaction:{backup:!1,audit:!0}});return be(n)}case"lbe_shell_command":{let n=await r.execute({actor:o,intent:"shell_command",target:t.command,content:JSON.stringify({args:Array.isArray(t.args)?t.args:[]}),transaction:{backup:!1,audit:!0}});return be(n)}case"lbe_patch_file":{let n=await r.execute({actor:o,intent:"patch_file",target:t.path,content:t.content,transaction:{backup:!0,rollbackOnFailure:!0,audit:!0}});return be(n)}case"lbe_health":{let n=r.exportLogs();return{content:[{type:"text",text:JSON.stringify({ok:!0,sdkLogEntries:n.length},null,2)}]}}default:return{content:[{type:"text",text:`Unknown tool: ${e}`}],isError:!0}}}function be(e){let t={ok:e.ok,commandId:e.commandId,stage:e.stage,risk:e.risk??void 0,output:e.output??void 0,error:e.error??void 0,message:e.message??void 0};return Object.keys(t).forEach(r=>t[r]===void 0&&delete t[r]),{content:[{type:"text",text:JSON.stringify(t,null,2)}],isError:!e.ok}}(process.argv.includes("--help")||process.argv.includes("-h"))&&(console.log(`
14
+ lbe-mcp \u2014 LBE-Core MCP Server v0.4.3
15
+
16
+ Wraps LBE-Core as a Model Context Protocol (MCP) server. Every tool call
17
+ passes through the full 7-gate LBE governance pipeline before execution.
27
18
 
28
19
  Usage:
29
20
  node bin/lbe-mcp-server.js Start server on stdio
@@ -31,7 +22,6 @@ Usage:
31
22
  npm run mcp Same via npm script
32
23
 
33
24
  Setup:
34
- npm install @modelcontextprotocol/sdk
35
25
  npm run init Generate keys and policy
36
26
 
37
27
  Environment:
@@ -46,7 +36,7 @@ Tools exposed:
46
36
  lbe_read_file Read a file \u2014 policy-checked, audited
47
37
  lbe_patch_file Append/patch a file \u2014 backed up before write
48
38
  lbe_shell_command Run a command \u2014 must be in policy allowlist
49
- lbe_health Check SDK readiness
39
+ lbe_health Check controller health
50
40
 
51
41
  Claude Desktop config:
52
42
  {
@@ -54,9 +44,9 @@ Claude Desktop config:
54
44
  "lbe": {
55
45
  "command": "npx",
56
46
  "args": ["lbe-mcp"],
57
- "cwd": "/path/to/your/lbe-workspace",
47
+ "cwd": "/path/to/your/letterblack-sentinel",
58
48
  "env": { "LBE_MCP_DEFAULT_ACTOR": "agent:claude" }
59
49
  }
60
50
  }
61
51
  }
62
- `),process.exit(0));var Bt,Vt,Ut,Ht;try{let{Server:e}=await import("@modelcontextprotocol/sdk/server/index.js"),{StdioServerTransport:t}=await import("@modelcontextprotocol/sdk/server/stdio.js"),{CallToolRequestSchema:r,ListToolsRequestSchema:s}=await import("@modelcontextprotocol/sdk/types.js");Bt=e,Vt=t,Ut=r,Ht=s}catch{console.error("[lbe-mcp] @modelcontextprotocol/sdk is not installed."),console.error("[lbe-mcp] Run: npm install @modelcontextprotocol/sdk"),process.exit(1)}var Je=Mt.resolve(process.env.LBE_SECRET_KEY_PATH||"keys/secret.key"),Ur=Mt.resolve(process.env.LBE_KEYS_STORE_PATH||"config/keys.json");ze.existsSync(Je)||(console.error("[lbe-mcp] Secret key not found at:",Je),console.error("[lbe-mcp] Run: npm run init"),process.exit(1));var Hr=ze.readFileSync(Je,"utf8").trim(),Wr=JSON.parse(ze.readFileSync(Ur,"utf8")),Wt=process.env.LBE_MCP_DEFAULT_ACTOR||"mcp:client",Yr=$t({secretKey:Hr,keyId:Wr.defaultKeyId,logLevel:process.env.LBE_LOG_LEVEL||"WARN",logSilent:!1}),Xe=new Bt({name:"lbe-sdk",version:"0.4.0"},{capabilities:{tools:{}}});Xe.setRequestHandler(Ht,async()=>({tools:qt}));Xe.setRequestHandler(Ut,async e=>{let{name:t,arguments:r}=e.params;return Kt(t,r||{},Yr,Wt)});var Gr=new Vt;await Xe.connect(Gr);console.error("[lbe-mcp] LBE SDK MCP server ready \u2014 default actor:",Wt);
52
+ `),process.exit(0));var Wt,Ht,Gt,Jt;try{let{Server:e}=await import("@modelcontextprotocol/sdk/server/index.js"),{StdioServerTransport:t}=await import("@modelcontextprotocol/sdk/server/stdio.js"),{CallToolRequestSchema:r,ListToolsRequestSchema:s}=await import("@modelcontextprotocol/sdk/types.js");Wt=e,Ht=t,Gt=r,Jt=s}catch{console.error("[lbe-mcp] @modelcontextprotocol/sdk is not installed."),console.error("[lbe-mcp] Reinstall LBE dependencies: npm install"),process.exit(1)}var zt=process.env.LBE_MCP_DEFAULT_ACTOR||"mcp:client",Ze=jt.resolve(process.env.LBE_SECRET_KEY_PATH||"keys/secret.key"),et=jt.resolve(process.env.LBE_KEYS_STORE_PATH||"config/keys.json"),Re=null,tt=null;if(!Ae.existsSync(Ze)||!Ae.existsSync(et))tt={error:"LBE_WORKSPACE_NOT_INITIALIZED",message:"LBE workspace keys are missing. Run: npx lbe init",secretKeyPath:Ze,keysStorePath:et},console.error("[lbe-mcp] Workspace not initialized. Run: npx lbe init");else{let e=Ae.readFileSync(Ze,"utf8").trim(),t=JSON.parse(Ae.readFileSync(et,"utf8"));Re=Bt({secretKey:e,keyId:t.defaultKeyId,logLevel:process.env.LBE_LOG_LEVEL||"WARN",logSilent:!1})}var rt=new Wt({name:"lbe-core",version:"0.4.3"},{capabilities:{tools:{}}});rt.setRequestHandler(Jt,async()=>({tools:Yt}));rt.setRequestHandler(Gt,async e=>{let{name:t,arguments:r}=e.params;return!Re&&t!=="lbe_workspace_context"&&t!=="lbe_health"?{content:[{type:"text",text:JSON.stringify(tt,null,2)}],isError:!0}:!Re&&t==="lbe_health"?{content:[{type:"text",text:JSON.stringify({ok:!1,...tt},null,2)}],isError:!0}:Ut(t,r||{},Re,zt)});var is=new Ht;await rt.connect(is);console.error("[lbe-mcp] LBE-Core MCP server ready \u2014 default actor:",zt);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@letterblack/lbe-sdk",
3
- "version": "0.4.2",
4
- "description": "Commercial SDK distribution for the Lockstep Boundary Engine.",
3
+ "version": "0.4.3",
4
+ "description": "Local-first execution governance SDK for AI agents.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "types.d.ts",
@@ -9,25 +9,22 @@
9
9
  ".": {
10
10
  "types": "./types.d.ts",
11
11
  "default": "./dist/index.js"
12
- }
12
+ },
13
+ "./engine": "./dist/index.js"
13
14
  },
14
15
  "bin": {
15
16
  "lbe": "dist/cli.js",
16
17
  "lbe-mcp": "dist/mcp-server.js"
17
18
  },
18
19
  "files": [
19
- "dist/index.js",
20
- "dist/engine.js",
21
- "dist/cli.js",
22
- "dist/mcp-server.js",
23
- "runtime/lbe_engine.wasm",
20
+ "dist/",
21
+ "config/policy.default.json",
24
22
  "types.d.ts",
25
23
  "README.md",
26
- "CHANGELOG.md",
27
- "COMMERCIAL_DISTRIBUTION.md",
28
24
  "LICENSE"
29
25
  ],
30
26
  "scripts": {
27
+ "pack": "npm pack",
31
28
  "pack:check": "npm pack --dry-run"
32
29
  },
33
30
  "keywords": [
@@ -43,17 +40,10 @@
43
40
  "author": "LetterBlack",
44
41
  "license": "SEE LICENSE IN LICENSE",
45
42
  "dependencies": {
43
+ "@modelcontextprotocol/sdk": "^1.29.0",
46
44
  "json-canonicalize": "^1.0.4",
47
45
  "tweetnacl": "^1.0.3"
48
46
  },
49
- "peerDependencies": {
50
- "@modelcontextprotocol/sdk": ">=1.0.0"
51
- },
52
- "peerDependenciesMeta": {
53
- "@modelcontextprotocol/sdk": {
54
- "optional": true
55
- }
56
- },
57
47
  "engines": {
58
48
  "node": ">=20.9.0"
59
49
  }
package/types.d.ts CHANGED
@@ -58,6 +58,15 @@ export interface CreateLBEOptions {
58
58
  defaultActor?: string;
59
59
  policy?: Record<string, unknown>;
60
60
  keyStore?: Record<string, unknown>;
61
+ policyPath?: string;
62
+ keysStorePath?: string;
63
+ policySigPath?: string;
64
+ policyStatePath?: string;
65
+ nonceDbPath?: string;
66
+ rateLimitDbPath?: string;
67
+ auditLogPath?: string;
68
+ backupDir?: string;
69
+ allowUnsignedPolicy?: boolean;
61
70
  logLevel?: 'DEBUG' | 'INFO' | 'WARN' | 'ERROR';
62
71
  logSilent?: boolean;
63
72
  }
@@ -70,3 +79,20 @@ export interface SandboxOptions {
70
79
 
71
80
  export function createLBE(options?: CreateLBEOptions): LBEClient;
72
81
  export function sandbox(root: string, opts?: SandboxOptions): SandboxClient;
82
+ export function createKeyStore(options: { publicKey: string; keyId: string; validDays?: number }): Record<string, unknown>;
83
+
84
+ export function validateCommand(options: Record<string, unknown>): Record<string, unknown>;
85
+ export function appendAudit(path: string, entry: Record<string, unknown>): Record<string, unknown>;
86
+ export function createBackup(filePath: string, backupDir?: string): Record<string, unknown>;
87
+ export function restoreBackup(backupMeta: Record<string, unknown>): Record<string, unknown>;
88
+ export function signEd25519(options: { payloadObj: unknown; secretKeyB64: string }): { signature: string | null; error: string | null };
89
+ export function verifyEd25519(options: { payloadObj: unknown; sigB64: string; pubKeyB64: string }): { valid: boolean; message: string };
90
+ export function generateKeyPair(): { publicKey: string; secretKey: string };
91
+ export function createLogger(options?: Record<string, unknown>): Record<string, unknown>;
92
+ export function deepFreeze<T>(obj: T): T;
93
+ export function checkInvariants(cfg: Record<string, unknown>, policy: Record<string, unknown>, keyStore: Record<string, unknown>): Record<string, unknown>;
94
+ export function assertInvariants(cfg: Record<string, unknown>, policy: Record<string, unknown>, keyStore: Record<string, unknown>): Record<string, unknown>;
95
+ export class InvariantGateError extends Error {}
96
+
97
+ export function getRuntimeInfo(): { mode: 'wasm'; available: boolean; wasmPath: string; localFirst: boolean };
98
+ export function loadWasmEngine(): Promise<{ ok: true; mode: 'wasm'; version: number }>;
package/CHANGELOG.md DELETED
@@ -1,47 +0,0 @@
1
- # Changelog
2
-
3
- ## v0.4.0
4
-
5
- ### Engine
6
-
7
- - Governance engine rewritten as a compiled WASM binary (`runtime/lbe_engine.wasm`).
8
- - All validation pipeline decisions (schema, timestamp skew, key lifecycle,
9
- signature, rate-limit, nonce deduplication, policy evaluation) now execute
10
- inside the compiled runtime — no readable JS orchestration of these rules.
11
- - Audit hash chaining (SHA-256 of `prevHash || entry`) computed in WASM.
12
- - Risk classification and rollback decisions computed in WASM.
13
- - JS layer reduced to: field extraction, Ed25519 verification, file IO, adapter
14
- dispatch, and the public `createLBE` / `sandbox` API surface.
15
- - `dist/engine.js` added as the WASM bridge module (internal; not a public export).
16
-
17
- ### Package
18
-
19
- - `dist/engine.js` added to published `files`.
20
- - `"private": true` on source repo hard-blocks accidental source publish.
21
- - Source repository URL removed from release package metadata.
22
- - License aligned: `SEE LICENSE IN LICENSE` (commercial, not MIT).
23
-
24
- ### API
25
-
26
- - Public surface unchanged: `createLBE`, `sandbox`.
27
-
28
- ---
29
-
30
- ## v0.3.0 — SDK Distribution
31
-
32
- ### Added
33
-
34
- - `@letterblack/lbe-sdk` package identity.
35
- - Bundled SDK entry points under `dist/`.
36
- - `lbe` CLI entry point.
37
- - `lbe-mcp` MCP server entry point.
38
- - TypeScript declarations.
39
- - Local SDK package artifact.
40
- - Public package documentation and license terms.
41
-
42
- ### Package Scope
43
-
44
- - Ships SDK distribution artifacts only.
45
- - Excludes source files, tests, demos, and build tooling.
46
- - Supports local-first agent workspace workflows, file operations, command
47
- workflows, audit, rollback, and MCP integration.
@@ -1,29 +0,0 @@
1
- # LBE SDK Distribution
2
-
3
- The LBE SDK is a local-first SDK for governed AI agent file and command
4
- workflows.
5
-
6
- This package is intended for developers and teams that need:
7
-
8
- - Agent workspace setup
9
- - Governed file reads, writes, and patches
10
- - Governed command execution
11
- - Audit and rollback support
12
- - MCP integration through `lbe-mcp`
13
- - Programmatic SDK integration through `sandbox()` and `createLBE()`
14
-
15
- ## Package Contents
16
-
17
- The npm package includes:
18
-
19
- - Bundled JavaScript entry points in `dist/`
20
- - Runtime artifact in `runtime/`
21
- - TypeScript declarations
22
- - README, changelog, and license terms
23
-
24
- It does not include source files, tests, demos, or build tooling.
25
-
26
- ## Licensing
27
-
28
- Commercial usage is governed by the package LICENSE and any separate written
29
- agreement with LetterBlack.
package/dist/engine.js DELETED
@@ -1,78 +0,0 @@
1
- import l from'fs';import t from'path';import{fileURLToPath as f}from'url';
2
- var D=t.dirname(f(import.meta.url)),w=t.join(D,'../runtime/lbe_engine.wasm');
3
- var POLICY_MSGS={0:{allowed:true,reason:null,message:'Policy check passed'},1:{allowed:false,reason:'POLICY_NOT_CONFIGURED',message:'No policy configured'},2:{allowed:false,reason:'REQUESTER_NOT_ALLOWED',message:'Requester not in policy'},3:{allowed:false,reason:'COMMAND_NOT_ALLOWED',message:'Command not allowed for requester'},4:{allowed:false,reason:'ADAPTER_NOT_ALLOWED',message:'Adapter not allowed'},5:{allowed:false,reason:'NO_FILESYSTEM_ROOTS_DEFINED',message:'No filesystem roots defined for requester'},6:{allowed:false,reason:'CWD_OUTSIDE_ALLOWED_ROOT',message:'Path not under allowed roots'},7:{allowed:false,reason:'PATH_DENIED_BY_PATTERN',message:'Path matches deny pattern'},8:{allowed:false,reason:'SHELL_CMD_DENIED',message:'Shell command not allowed'}};
4
- var SCHEMA_MSGS={0:{valid:true,error:null},1:{valid:false,error:'Missing required field: id'},2:{valid:false,error:'Missing required field: commandId'},3:{valid:false,error:'Missing required field: requesterId'},4:{valid:false,error:'Missing required field: sessionId'},5:{valid:false,error:'Missing required field: timestamp'},6:{valid:false,error:'Missing required field: nonce'},7:{valid:false,error:'Missing required field: requires'},8:{valid:false,error:'Missing required field: payload'},9:{valid:false,error:'Missing required field: signature'},10:{valid:false,error:"Field 'id' is invalid"},11:{valid:false,error:"Field 'commandId' is invalid"},12:{valid:false,error:"Field 'requesterId' is invalid"},13:{valid:false,error:"Field 'sessionId' is invalid"},14:{valid:false,error:"Field 'timestamp' is invalid"},15:{valid:false,error:"Field 'nonce' is invalid"},16:{valid:false,error:"Field 'requires' is invalid"},17:{valid:false,error:'payload: missing required field: adapter'},18:{valid:false,error:"payload: field 'adapter' is invalid"},19:{valid:false,error:'signature: missing required field: alg'},20:{valid:false,error:'signature: missing required field: keyId'},21:{valid:false,error:'signature: missing required field: sig'},22:{valid:false,error:"signature: field 'alg' must be ed25519"},23:{valid:false,error:"signature: field 'sig' is invalid"},24:{valid:false,error:"Field 'risk' is invalid"}};
5
- var KEY_REASONS={1:'KEY_ID_INVALID',2:'KEY_NOT_TRUSTED',3:'KEY_DEPRECATED',4:'KEY_REQUESTER_MISMATCH',5:'KEY_LIFECYCLE_INVALID',6:'KEY_NOT_YET_VALID',7:'KEY_EXPIRED'};
6
- var PIPELINE_STAGES={0:'schema',1:'timestamp',2:'key',3:'signature',4:'rate_limit',5:'nonce',6:'policy',255:'ok'};
7
- var RISK_LABELS=['LOW','MEDIUM','HIGH','CRITICAL'];
8
- var CMD_TYPE={ECHO:0,READ_FILE:1,WRITE_FILE:2,PATCH_FILE:3,DELETE_FILE:4,RUN_SHELL:5};
9
- var _inst=null;
10
- function wasm(){if(_inst)return _inst;if(!l.existsSync(w))throw new Error(`LBE engine missing: ${w}`);_inst=new WebAssembly.Instance(new WebAssembly.Module(l.readFileSync(w)),{});return _inst}
11
- function mem(){return new Uint8Array(wasm().exports.memory.buffer)}
12
- function inPtr(){return wasm().exports.lbe_in_ptr()}
13
- function outPtr(){return wasm().exports.lbe_out_ptr()}
14
- function bufSz(){return wasm().exports.lbe_buf_size()}
15
- function writeIn(s){let e=new TextEncoder().encode(s),m=mem(),p=inPtr();m.set(e,p);m[p+e.length]=0}
16
- function readOut(){let m=mem(),p=outPtr(),e=p;while(m[e]!==0&&e-p<bufSz())e++;return new TextDecoder().decode(m.slice(p,e))}
17
- function writeInBin(a,b){let m=mem(),p=inPtr(),i=p;for(let x=0;x<a.length;x++)m[i++]=a[x];m[i++]=0;for(let x=0;x<b.length;x++)m[i++]=b[x];m[i]=0}
18
- function writePipeIn(fields){let m=mem(),p=inPtr(),v=new DataView(m.buffer,p);fields.forEach((f,i)=>v.setUint32(i*4,f>>>0,true))}
19
- function readPipeOut(){let m=mem(),p=outPtr(),v=new DataView(m.buffer,p);return{stage:v.getUint32(0,true),code:v.getUint32(4,true)}}
20
- export function getRuntimeInfo(){return{mode:'wasm',available:l.existsSync(w),wasmPath:w,localFirst:true}}
21
- export async function loadWasmEngine(){return{ok:true,mode:'wasm',version:wasm().exports.lbe_engine_version()}}
22
- export function runValidationPipeline(flags){
23
- writePipeIn([
24
- flags.hasId?1:0,flags.idValid?1:0,flags.hasCommandId?1:0,flags.commandIdValid?1:0,
25
- flags.hasRequesterId?1:0,flags.requesterIdValid?1:0,flags.hasSessionId?1:0,flags.sessionIdValid?1:0,
26
- flags.hasTimestamp?1:0,flags.timestampValid?1:0,flags.hasNonce?1:0,flags.nonceValid?1:0,
27
- flags.hasRequires?1:0,flags.requiresValid?1:0,flags.hasPayload?1:0,
28
- flags.hasPayloadAdapter?1:0,flags.payloadAdapterValid?1:0,flags.hasSignature?1:0,
29
- flags.hasSignatureAlg?1:0,flags.signatureAlgValid?1:0,flags.hasSignatureKeyId?1:0,
30
- flags.hasSignatureSig?1:0,flags.signatureSigValid?1:0,flags.hasRisk?1:0,flags.riskValid?1:0,
31
- flags.cmdTimestamp>>>0,flags.nowSec>>>0,flags.maxClockSkewSec>>>0,
32
- flags.keyIdFormatValid?1:0,flags.keyFound?1:0,flags.keyNotDeprecated?1:0,
33
- flags.keyRequesterMatches?1:0,flags.keyNotBeforeOk?1:0,flags.keyNotExpired?1:0,
34
- flags.keyLifecycleFieldsPresent?1:0,flags.signatureValid?1:0,
35
- flags.rateLimitOk?1:0,flags.rateLimitRetryAfterSec>>>0,flags.nonceOk?1:0,
36
- flags.policyConfigured?1:0,flags.requesterConfigured?1:0,flags.commandAllowed?1:0,
37
- flags.adapterAllowed?1:0,flags.filesystemRequired?1:0,flags.filesystemRootsDefined?1:0,
38
- flags.filesystemOk?1:0,flags.pathDenied?1:0,flags.shellRequired?1:0,flags.shellCommandOk?1:0,
39
- ]);
40
- wasm().exports.lbe_validate_pipeline();
41
- let{stage,code}=readPipeOut(),ok=stage===255;
42
- return{ok,stage,stageLabel:PIPELINE_STAGES[stage]||'unknown',code,
43
- schemaError:stage===0?(SCHEMA_MSGS[code]?.error||'Schema invalid'):null,
44
- keyReason:stage===2?(KEY_REASONS[code]||'KEY_ERROR'):null,
45
- policyResult:stage===6?{...(POLICY_MSGS[code]||POLICY_MSGS[1]),code}:null,
46
- retryAfterSec:stage===4?code:0,skewSec:stage===1?code:0}
47
- }
48
- export function checkNonce({ttlSec,nowSec,newKey,existingEntries}){
49
- writeIn([`${ttlSec}:${nowSec}`,newKey,...existingEntries].join('\n')+'\n');
50
- let isReplay=wasm().exports.lbe_nonce_check()!==0;
51
- if(isReplay)return{ok:false,updatedEntriesText:null};
52
- let out=readOut();
53
- return{ok:true,updatedEntriesText:out.startsWith('OK\n')?out.slice(3):out}
54
- }
55
- export function checkRateLimit({windowSec,maxRequests,nowSec,requesterId,existingEntries}){
56
- writeIn([`${windowSec}:${maxRequests}:${nowSec}`,requesterId,...existingEntries].join('\n')+'\n');
57
- let exceeded=wasm().exports.lbe_rate_check()!==0,out=readOut();
58
- if(exceeded){let r=parseInt(out.match(/^EXCEEDED:(\d+)/)?.[1]??'1',10);return{ok:false,retryAfterSec:r,updatedEntriesText:out.replace(/^EXCEEDED:\d+\n/,'')}}
59
- return{ok:true,retryAfterSec:0,updatedEntriesText:out.startsWith('OK\n')?out.slice(3):out}
60
- }
61
- export function computeAuditHash(prevHash,entryJson){
62
- let enc=new TextEncoder();writeInBin(enc.encode(prevHash),enc.encode(entryJson));
63
- wasm().exports.lbe_audit_hash();return readOut().slice(0,64)
64
- }
65
- export function classifyRisk(commandId,shellCmdIsRm=false){
66
- return RISK_LABELS[wasm().exports.lbe_classify_risk(CMD_TYPE[commandId]??0,shellCmdIsRm?1:0)]??'LOW'
67
- }
68
- export function shouldRollback({execFailed,postCheckFailed,backupExists,rollbackEnabled}){
69
- return wasm().exports.lbe_rollback_decision(execFailed?1:0,postCheckFailed?1:0,backupExists?1:0,rollbackEnabled?1:0)===1
70
- }
71
- export function evaluatePolicyDecision(input){
72
- let c=wasm().exports.lbe_policy_decision(input.policyConfigured?1:0,input.requesterConfigured?1:0,input.commandAllowed?1:0,input.adapterAllowed?1:0,input.filesystemRequired?1:0,input.filesystemRootsDefined?1:0,input.filesystemOk?1:0,input.pathDenied?1:0,input.shellRequired?1:0,input.shellCommandOk?1:0);
73
- return{...(POLICY_MSGS[c]||POLICY_MSGS[1]),code:c}
74
- }
75
- export function evaluateSchemaDecision(input){
76
- let c=wasm().exports.lbe_schema_decision(input.hasId?1:0,input.idValid?1:0,input.hasCommandId?1:0,input.commandIdValid?1:0,input.hasRequesterId?1:0,input.requesterIdValid?1:0,input.hasSessionId?1:0,input.sessionIdValid?1:0,input.hasTimestamp?1:0,input.timestampValid?1:0,input.hasNonce?1:0,input.nonceValid?1:0,input.hasRequires?1:0,input.requiresValid?1:0,input.hasPayload?1:0,input.hasPayloadAdapter?1:0,input.payloadAdapterValid?1:0,input.hasSignature?1:0,input.hasSignatureAlg?1:0,input.signatureAlgValid?1:0,input.hasSignatureKeyId?1:0,input.hasSignatureSig?1:0,input.signatureSigValid?1:0,input.hasRisk?1:0,input.riskValid?1:0);
77
- return{...(SCHEMA_MSGS[c]||SCHEMA_MSGS[10]),code:c}
78
- }
File without changes