@letterblack/lbe-sdk 0.4.4 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  Local-first execution governance SDK for AI agents.
4
4
 
5
- LBE SDK gives MCP-compatible agents and Node.js tools a governed execution
6
- boundary for local workspace actions: workspace context, policy checks, audit
7
- logging, rollback-aware writes, and controlled shell/file operations.
5
+ LBE SDK exposes a WASM-authoritative execution boundary for local AI agent
6
+ governance. JavaScript is transport only: it verifies the engine hash, passes a
7
+ UTF-8 JSON request into WASM, and returns the UTF-8 JSON response.
8
8
 
9
9
  Everything runs on your machine. No cloud service is required.
10
10
 
@@ -16,100 +16,46 @@ npm install @letterblack/lbe-sdk
16
16
 
17
17
  Requires Node.js >= 20.9.0.
18
18
 
19
- ## Initialize a workspace
19
+ ## Contract
20
20
 
21
- Run this once in each project you want LBE to govern:
21
+ The public boundary is a single function:
22
22
 
23
- ```bash
24
- npx lbe init
25
- ```
26
-
27
- This creates a local workspace contract:
28
-
29
- ```text
30
- lbe.workspace.json
31
- ```
32
-
33
- It also creates local keys and runtime state. Do not commit:
34
-
35
- ```text
36
- keys/
37
- config/keys.json
38
- config/policy.sig.json
39
- data/
23
+ ```ts
24
+ execute(input: string): string
40
25
  ```
41
26
 
42
- ## MCP setup
43
-
44
- Add LBE to any MCP-compatible host:
45
-
46
- ```json
47
- {
48
- "mcpServers": {
49
- "lbe": {
50
- "command": "npx",
51
- "args": ["lbe-mcp"]
52
- }
53
- }
54
- }
55
- ```
56
-
57
- If the workspace has not been initialized yet, the MCP server still starts and
58
- returns a clear `npx lbe init` message from health/action tools instead of
59
- failing the MCP handshake.
60
-
61
- Agents should call `lbe_workspace_context` first, before planning or writing.
62
-
63
- ## MCP tools
64
-
65
- | Tool | Purpose |
66
- |---|---|
67
- | `lbe_workspace_context` | Read the local workspace contract |
68
- | `lbe_write_file` | Write a file with validation, backup, and audit |
69
- | `lbe_read_file` | Read a file through policy checks |
70
- | `lbe_patch_file` | Append/patch a file with backup and audit |
71
- | `lbe_shell_command` | Run an allowlisted shell command |
72
- | `lbe_health` | Report controller/workspace health |
27
+ `input` is a JSON string. `output` is a JSON string. All authoritative
28
+ validation and decisions originate in `dist/lbe_engine.wasm`.
73
29
 
74
30
  ## SDK usage
75
31
 
76
32
  ```js
77
- import { sandbox } from '@letterblack/lbe-sdk';
78
-
79
- const sb = sandbox('./workspace', { audit: true, rollback: true });
80
-
81
- await sb.write('output.txt', 'Hello\n');
82
- const text = await sb.read('output.txt');
83
- ```
84
-
85
- For advanced policy-controlled execution:
86
-
87
- ```js
88
- import { createLBE } from '@letterblack/lbe-sdk';
89
-
90
- const lbe = createLBE({ rootDir: process.cwd() });
91
-
92
- const result = await lbe.execute({
93
- actor: 'agent:writer',
94
- intent: 'write_file',
95
- target: 'output/report.md',
96
- content: '# Report\n',
97
- transaction: { backup: true, rollbackOnFailure: true, audit: true }
98
- });
99
-
100
- console.log(result.ok, result.stage, result.commandId);
33
+ import crypto from 'node:crypto';
34
+ import { execute } from '@letterblack/lbe-sdk';
35
+
36
+ const output = execute(JSON.stringify({
37
+ version: '1.0',
38
+ request_id: crypto.randomUUID(),
39
+ timestamp: Math.floor(Date.now() / 1000),
40
+ actor: { id: 'agent:local', role: 'agent' },
41
+ intent: { type: 'command', name: 'status', payload: {} },
42
+ context: { workspace: process.cwd(), env: {}, history: [] },
43
+ constraints: { policy_mode: 'strict', timeout_ms: 5000 },
44
+ auth: { signature: 'provided-by-host', nonce: crypto.randomUUID() }
45
+ }));
46
+
47
+ console.log(JSON.parse(output));
101
48
  ```
102
49
 
103
50
  ## CLI
104
51
 
105
52
  | Command | Description |
106
53
  |---|---|
107
- | `npx lbe init` | Initialize workspace contract, keys, and policy state |
108
- | `npx lbe health` | Check local workspace health |
109
- | `npx lbe-mcp` | Start the MCP server on stdio |
110
- | `npx lbe verify --in proposal.json` | Validate a proposal without execution |
111
- | `npx lbe run --in proposal.json` | Validate and execute a proposal |
112
- | `npx lbe audit-verify` | Verify audit log hash chain |
54
+ | `npx lbe execute --input input.json` | Execute one JSON request through WASM |
55
+ | `cat input.json \| npx lbe execute` | Execute from stdin |
56
+
57
+ `lbe-mcp` starts a thin MCP stdio bridge exposing one tool: `lbe_execute`.
58
+ It contains no governance logic; it only passes JSON into `execute(input)`.
113
59
 
114
60
  ## What ships
115
61
 
@@ -117,6 +63,7 @@ The npm package contains the public SDK surface only:
117
63
 
118
64
  ```text
119
65
  dist/
66
+ dist/wasm.lock.json
120
67
  types.d.ts
121
68
  README.md
122
69
  LICENSE
@@ -124,14 +71,10 @@ config/policy.default.json
124
71
  package.json
125
72
  ```
126
73
 
127
- Private source files, tests, release scripts, keys, runtime data, and source maps
128
- are not part of the public package.
74
+ Private source files, tests, release scripts, adapter internals, keys, runtime
75
+ data, source maps, and raw governance JS are not part of the public package.
129
76
 
130
77
  ## Security scope
131
78
 
132
- LBE governs actions routed through the SDK. It helps protect against accidental
133
- writes outside allowed roots, replayed proposals, policy drift, audit tampering,
134
- and failed write operations that need rollback.
135
-
136
- It is not a kernel-level sandbox, network egress firewall, or multi-tenant
137
- isolation layer.
79
+ LBE's public JS is not part of the decision boundary. If the WASM hash check or
80
+ WASM entrypoint check fails, execution fails closed.
package/dist/cli.js CHANGED
@@ -1,79 +1,44 @@
1
1
  #!/usr/bin/env node
2
- import Gt from"fs";import xe from"path";import{fileURLToPath as gs}from"url";function Ge(e){if(e.length===0)return{command:"help",opts:{}};let t=e[0],r={};for(let s=1;s<e.length;s++)if(e[s].startsWith("--")){let o=e[s].substring(2);if(o.includes("=")){let[n,i]=o.split("=");r[n]=i}else{let n=e[s+1];!n||n.startsWith("-")?r[o]=!0:(r[o]=n,s++)}}else if(e[s].startsWith("-")){let o=e[s].substring(1),n=e[s+1];!n||n.startsWith("-")?r[o]=!0:(r[o]=n,s++)}return{command:t,opts:r}}function le(e="unknown"){console.log(`
3
- \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
4
- \u2551 LetterBlack Sentinel \u2014 CLI Governance \u2551
5
- \u2551 Local-first execution governance SDK v${e.padEnd(12)}\u2551
6
- \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
2
+ import fs from 'node:fs';
3
+ import { execute } from './index.js';
7
4
 
8
- USAGE:
9
- lbe [command] [options]
5
+ function usage() {
6
+ process.stderr.write('Usage: lbe execute [--input input.json]\n');
7
+ }
10
8
 
11
- COMMANDS:
12
- init Initialize LetterBlack Sentinel environment
13
- verify Verify a proposal (validate, don't execute)
14
- dryrun Validate and simulate execution (no changes)
15
- run Validate and execute a proposal
16
- policy-sign Sign policy and write policy signature envelope
17
- health Run deployment/runtime health checks
18
- integrity-check Verify controller integrity manifest
19
- integrity-generate Generate controller integrity manifest
20
- audit-verify Verify audit log hash-chain integrity
21
- help Show this help message
9
+ async function readStdin() {
10
+ const chunks = [];
11
+ for await (const chunk of process.stdin) chunks.push(chunk);
12
+ return Buffer.concat(chunks).toString('utf8');
13
+ }
22
14
 
23
- OPTIONS:
24
- --in Input file (JSON proposal)
25
- --config Policy config file (default: ./config/policy.default.json)
26
- --policy Alias for --config
27
- --policy-sig Policy signature file (default: ./config/policy.sig.json)
28
- --policy-state Policy monotonic state file (default: ./data/policy.state.json)
29
- --policy-unsigned-ok Allow unsigned policy (dev-only; default: false)
30
- --policy-key-id Signer keyId for policy-sign (default: policy-signer-v1-2026Q1)
31
- --secret-key-file Secret key for policy-sign (default: ./keys/secret.key)
32
- --data-dir Data directory for health checks (default: ./data)
33
- --nonce-db Nonce DB path for health checks
34
- --rate-db Rate-limit DB path for health checks
35
- --keys-store Trusted keys store (default: ./config/keys.json)
36
- --pub-key Public key for verification (Ed25519 base64)
37
- --pub-key-file Legacy single-key file path (fallback mode)
38
- --integrity-strict Fail verify/dryrun/run if integrity check fails
39
- --integrity-manifest Integrity manifest path (default: ./config/integrity.manifest.json)
40
- --manifest Manifest path override for integrity-check
41
- --out Output path for integrity-generate
42
- --audit Audit log file (default: ./data/audit.log.jsonl)
43
- --json JSON output (default: true)
44
- --fail-fast Stop at first audit integrity error (default: true)
45
- --max Max audit entries to process (optional)
46
- --version Show version
47
- --help Show this help message
15
+ const args = process.argv.slice(2);
16
+ if (args[0] !== 'execute') {
17
+ usage();
18
+ process.exit(2);
19
+ }
48
20
 
49
- EXAMPLES:
50
- lbe init
51
- lbe verify --in proposal.json --keys-store ./config/keys.json
52
- lbe dryrun --in proposal.json --keys-store ./config/keys.json
53
- lbe run --in proposal.json --keys-store ./config/keys.json
54
- lbe policy-sign --config ./config/policy.default.json --policy-sig ./config/policy.sig.json
55
- lbe health --json true
56
- lbe integrity-generate --out ./config/integrity.manifest.json
57
- lbe integrity-check --integrity-strict --manifest ./config/integrity.manifest.json
58
- lbe audit-verify --audit ./data/audit.log.jsonl
59
- lbe verify --in proposal.json --pub-key-file ./keys/public.key
21
+ let input = '';
22
+ const inputFlag = args.indexOf('--input');
23
+ if (inputFlag >= 0) {
24
+ const file = args[inputFlag + 1];
25
+ if (!file) {
26
+ usage();
27
+ process.exit(2);
28
+ }
29
+ input = fs.readFileSync(file, 'utf8');
30
+ } else {
31
+ input = await readStdin();
32
+ }
60
33
 
61
- For more info, visit: https://github.com/Letterblack0306/LetterBlack-LBE-Core
62
- `)}import x from"fs";import $ from"path";import kr from"readline";import be from"tweetnacl";import{canonicalize as We}from"json-canonicalize";function we(e){return Buffer.from(e,"base64")}function Ae(e){return Buffer.from(e).toString("base64")}function de({payloadObj:e,sigB64:t,pubKeyB64:r}){try{let s=Buffer.from(We(e),"utf8"),o=we(t),n=we(r),i=be.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 He(){let e=be.sign.keyPair();return{publicKey:Ae(e.publicKey),secretKey:Ae(e.secretKey)}}function ze({payloadObj:e,secretKeyB64:t}){try{let r=Buffer.from(We(e),"utf8"),s=we(t),o=be.sign.detached(new Uint8Array(r),new Uint8Array(s));return{signature:Ae(o),error:null}}catch(r){return{signature:null,error:`Signing failed: ${r.message}`}}}import Ze from"fs";import Zt from"path";import Xe from"fs";import zt from"path";var Xt=/^[A-Za-z0-9:_-]{3,128}$/;function Qt(e){return typeof e=="string"&&Xt.test(e)&&e!=="default"}function Q(e){let t=zt.resolve(e);if(!Xe.existsSync(t))return{ok:!1,reason:"KEY_STORE_MISSING",message:`Key store not found: ${t}`,store:null};try{let r=Xe.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 Qe({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(!Qt(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}}function ue({policyObj:e,secretKeyB64:t,keyId:r}){let s=ze({payloadObj:e,secretKeyB64:t});return s.error?{ok:!1,reason:"POLICY_SIGNATURE_CREATE_FAILED",message:s.error,envelope:null}:{ok:!0,reason:null,message:"Policy signature created",envelope:{alg:"ed25519",keyId:r,sig:s.signature,createdAt:Math.floor(Date.now()/1e3)}}}function Z({policyObj:e,keyStore:t,policySigPath:r="./config/policy.sig.json",allowUnsigned:s=!1}){let o=Zt.resolve(r);if(!Ze.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(Ze.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=Qe({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=de({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 _e from"fs";import L from"path";var er=[{file:"package.json",type:"node"},{file:"pyproject.toml",type:"python"},{file:"requirements.txt",type:"python"},{file:"go.mod",type:"go"},{file:"Cargo.toml",type:"rust"},{file:"pom.xml",type:"java"},{file:"build.gradle",type:"java"},{file:"build.gradle.kts",type:"java"},{file:"Dockerfile",type:"docker"},{file:"docker-compose.yml",type:"docker"},{dir:".github/workflows",type:"ci"},{file:".gitlab-ci.yml",type:"ci"},{dir:".circleci",type:"ci"},{file:"Jenkinsfile",type:"ci"},{file:".travis.yml",type:"ci"}],Ne=["node","python","go","rust","java"],tr={source:["src","lib","app","pages","components","core","api","server","client","pkg","cmd"],generated:["dist","build",".next","out","coverage","target",".cache","__pycache__",".turbo"],tests:["test","tests","__tests__","spec","e2e"],docs:["docs","doc","documentation"]},rt=[".env",".env.*","keys/**","secrets/**","*.key","*.pem","*.p12","*.pfx","*.crt"],rr=["node_modules/**",".git/**"],sr={node:["package-lock.json","yarn.lock","pnpm-lock.yaml"],python:["Pipfile.lock","poetry.lock"],go:["go.sum"],rust:["Cargo.lock"],java:["gradle/wrapper/**"],docker:[],ci:[],generic:[]},et={node:["package.json","tsconfig*.json","jest.config.*","vite.config.*","next.config.*","webpack.config.*",".eslintrc*",".eslint.config.*",".prettierrc*","babel.config.*"],python:["pyproject.toml","setup.py","setup.cfg","tox.ini","pytest.ini","mypy.ini",".flake8",".pylintrc","Pipfile"],go:["go.mod",".golangci.yml",".golangci.yaml"],rust:["Cargo.toml","rust-toolchain.toml","clippy.toml",".rustfmt.toml"],java:["pom.xml","build.gradle","build.gradle.kts","gradle.properties","settings.gradle","settings.gradle.kts"],docker:["Dockerfile","docker-compose.yml",".dockerignore"],ci:[".gitlab-ci.yml","Jenkinsfile",".travis.yml"],generic:["Makefile","CMakeLists.txt","meson.build"]},or=[".editorconfig",".nvmrc",".node-version",".python-version"],nr=["config",".github",".gitlab",".circleci",".vscode"],ir={node:"dependency and build config",python:"package and environment config",go:"module definition",rust:"crate manifest",java:"build definition",docker:"container config",ci:"pipeline definition",generic:"project config"},ar={node:"package manager",python:"dependency resolver",go:"module checksums",rust:"dependency resolver",java:"Gradle wrapper"},cr=["composer.json","Gemfile","mix.exs","pubspec.yaml","Package.swift","project.clj","build.sbt","stack.yaml","deno.json","deno.jsonc","Podfile"],lr=["composer.lock","Gemfile.lock","mix.lock","pubspec.lock","Package.resolved"],dr=[".csproj",".fsproj",".sln",".cabal"];function T(e){return _e.existsSync(e)}function tt(e,t){return t.filter(r=>T(L.join(e,r))).map(r=>`${r}/**`)}function ur(e){let t=L.join(e,".gitignore");return T(t)?_e.readFileSync(t,"utf8").split(`
63
- `).map(r=>r.trim()).filter(r=>r&&!r.startsWith("#")&&!r.startsWith("!")).map(r=>r.endsWith("/")?r+"**":r):[]}function B(e){return e.filter((t,r,s)=>t&&s.indexOf(t)===r)}function fr(e){let t=new Set,r=[];for(let s of er){if(t.has(s.type))continue;let o=L.join(e,s.file||s.dir);T(o)&&(t.add(s.type),r.push(s.type))}return r.length>0?r:["generic"]}function pr(e){return Ne.find(t=>e.includes(t))??"generic"}function mr(e){let t=cr.filter(s=>T(L.join(e,s))),r=lr.filter(s=>T(L.join(e,s)));try{let s=_e.readdirSync(e);for(let o of s)dr.some(n=>o.endsWith(n))&&t.push(o)}catch{}return{manifests:t,lockfiles:r}}function yr(e,t){let r={};for(let[o,n]of Object.entries(tr))r[o]=tt(e,n);r.secrets=rt.filter(o=>{let n=o.split("/")[0].replace(/\*.*/,"");return n.includes("*")||T(L.join(e,n))});let s=B(t.flatMap(o=>et[o]||et.generic).concat(or));if(r.config=B([...s.filter(o=>!o.includes("*")&&!o.endsWith("/**")&&T(L.join(e,o))),...s.filter(o=>o.endsWith("/**")&&T(L.join(e,o.replace("/**","")))),...tt(e,nr)]),r.lockfiles=B(t.flatMap(o=>sr[o]||[]).filter(o=>{let n=o.replace(/\*.*/,"").split("/")[0];return n.includes("*")||T(L.join(e,n))})),!t.some(o=>Ne.includes(o))){let o=mr(e);r.config=B([...r.config,...o.manifests]),r.lockfiles=B([...r.lockfiles,...o.lockfiles])}return r}function gr(e,t,r){let s={};if(s.structure="Preserve the existing folder structure. Add new files within established directories. Do not create top-level directories, reorganize, or rename existing folders.",r.source.length>0&&(s.source=`Source code lives in ${r.source.join(", ")}. Make feature changes and bug fixes here only.`),s.secrets=`Never propose changes to credential or key files (${rt.slice(0,4).join(", ")} \u2026). These are never task targets regardless of the instruction.`,r.generated.length>0&&(s.generated=`${r.generated.join(", ")} contain generated output. Modify the source files that produce them; never write to generated directories directly.`),r.config.length>0){let o=e.filter(c=>Ne.includes(c)),n=o.length===1?ir[o[0]]:"project configuration",i=r.config.slice(0,5).join(", "),a=r.config.length>5?" and related files":"";s.config=`Treat ${i}${a} as ${n} files. Do not modify them unless the task explicitly requires a configuration or dependency change.`}if(r.tests.length>0&&(s.tests=`Test files in ${r.tests.join(", ")} validate behavior. Update them only when the behavior they cover changes.`),r.lockfiles?.length>0){let o=ar[t]||"tooling",n=r.lockfiles.slice(0,3).join(", ");s.lockfiles=`${n} are generated by the ${o}. Never edit them directly.`}if(t==="generic"){let o=r.config.filter(n=>!n.endsWith("/**"));o.length>0?s.unknown=`This project uses an unrecognized toolchain. Treat ${o.slice(0,3).join(", ")} as dependency/manifest files. Do not modify them unless the task explicitly requires a dependency change.`:s.unknown="This project uses an unrecognized toolchain. Do not assume standard source layouts, dependency files, or build conventions apply. Confirm any structural assumption before acting."}return e.includes("docker")&&(s.docker="Dockerfile and docker-compose.yml define the container environment. Treat them as infrastructure config \u2014 only modify when the task explicitly involves container or environment changes."),e.includes("ci")&&(s.ci="CI config files (.github/**, .gitlab-ci.yml, etc.) define the build and deployment pipeline. Do not modify them unless the task explicitly involves CI/CD changes."),s}function hr(e,t){let r=B([...e.source,...e.docs,...e.tests]),s=[...e.config],o=B([...e.secrets,...e.generated,...e.lockfiles||[],...rr,...t.filter(n=>n.endsWith("/**")).slice(0,8)]);return{allow:r.length>0?r:["src/**"],approval:s.length>0?s:[],deny:o}}function st(e){let t=L.resolve(e||process.cwd()),r=fr(t),s=pr(r),o=yr(t,r),n=ur(t),i=gr(r,s,o),a=hr(o,n);return{projectTypes:r,primaryType:s,surfaces:o,semantics:i,enforcement:a}}function ot(e,t,r){let s=[],o=Array.isArray(e)?e.join(" + "):e;s.push(`Detected: ${o}`),s.push(""),s.push("Agent semantics:");for(let[,n]of Object.entries(t))s.push(` - ${n}`);return s.push(""),s.push("Enforcement:"),r.allow.length&&s.push(` allow: ${r.allow.join(", ")}`),r.approval.length&&s.push(` approval: ${r.approval.join(", ")}`),r.deny.length&&s.push(` deny: ${r.deny.slice(0,6).join(", ")}${r.deny.length>6?" \u2026":""}`),s.join(`
64
- `)}function Sr(e){return process.stdin.isTTY?new Promise(t=>{let r=kr.createInterface({input:process.stdin,output:process.stdout});r.question(e,s=>{r.close(),t(s.trim().toLowerCase())})}):Promise.resolve("y")}function Ir(e){return{...e,deny:[...new Set([...e.deny,...e.approval,"*.json","config/**"])],approval:[]}}function Er(e){return{...e,approval:[]}}function vr(e){let t=new Date().toISOString(),r=new Date(Date.now()+4320*60*60*1e3).toISOString(),s="agent:gpt-v1-2026Q1",o="policy-signer-v1-2026Q1";for(let y of["config","keys","data"])x.mkdirSync($.join(e,y),{recursive:!0});let n={"data/nonce.db.json":JSON.stringify({entries:[]},null,2),"data/rate-limit.db.json":JSON.stringify({entries:[]},null,2),"data/policy.state.json":JSON.stringify({schemaVersion:"1",lastAccepted:null,updatedAt:null},null,2),"data/audit.log.jsonl":""};for(let[y,S]of Object.entries(n)){let k=$.join(e,y);x.existsSync(k)||x.writeFileSync(k,S)}let i=$.join(e,"keys"),a=$.join(i,"public.key"),c=$.join(i,"secret.key"),l,u;if(x.existsSync(a)&&x.existsSync(c))l=x.readFileSync(a,"utf8").trim(),u=x.readFileSync(c,"utf8").trim();else{let y=He();l=y.publicKey,u=y.secretKey,x.writeFileSync(a,l),x.writeFileSync(c,u,{mode:384})}let f=$.join(e,"config/keys.json"),d=x.existsSync(f)?JSON.parse(x.readFileSync(f,"utf8")):{schemaVersion:"1",defaultKeyId:s,trustedKeys:{}};for(let y of[s,o])d.trustedKeys[y]||(d.trustedKeys[y]={publicKey:l,notBefore:t,expiresAt:r,validFrom:t,validUntil:r,deprecated:!1});d.defaultKeyId=s,x.writeFileSync(f,JSON.stringify(d,null,2));let p=$.join(e,"config/policy.default.json"),g;x.existsSync(p)?g=JSON.parse(x.readFileSync(p,"utf8")):(g={default:"DENY",version:"1.0.0",createdAt:t,security:{maxClockSkewSec:600,maxPolicyCreatedAtSkewSec:31536e3,defaultRateLimit:{windowSec:60,maxRequests:30}},requesters:{"agent:gpt":{allowAdapters:["noop","shell"],allowCommands:["RUN_SHELL"],rateLimit:{windowSec:60,maxRequests:30},filesystem:{roots:[e],denyPatterns:["**/.git/**","**/secrets/**","**/*.key"]},exec:{allowCmds:["ls","node","python","echo"],denyCmds:["rm","chmod","chown","curl","wget","su","sudo"]}}}},x.writeFileSync(p,JSON.stringify(g,null,2)));let m=ue({policyObj:g,secretKeyB64:u,keyId:o});return m.ok&&x.writeFileSync($.join(e,"config/policy.sig.json"),JSON.stringify(m.envelope,null,2)),{defaultKeyId:s,secretKeyB64:u,publicKeyB64:l}}async function nt(e={}){let t=process.cwd(),r=e.yes||e.y||!process.stdin.isTTY,s=$.join(t,"lbe.workspace.json");console.log(`
65
- Scanning workspace...
66
- `);let{projectTypes:o,primaryType:n,semantics:i,enforcement:a}=st(t);console.log(ot(o,i,a)),console.log("");let c=a;if(!r){let u=await Sr("Accept? [Y = accept / s = strict / r = relaxed / n = cancel] ");if(u==="n")return console.log("Cancelled."),{success:!1};u==="s"&&(c=Ir(a)),u==="r"&&(c=Er(a))}let l={lbe:!0,version:"0.4.0",state:"local",projectTypes:o,primaryType:n,semantics:i,enforcement:c};return x.writeFileSync(s,JSON.stringify(l,null,2)),console.log("\u2713 Wrote lbe.workspace.json"),vr(t),console.log(`\u2713 Keys and policy ready
67
- `),console.log("Done. Agents that detect lbe.workspace.json will operate within these boundaries."),console.log(`Run npx lbe doctor at any time to review or update the contract.
68
- `),{success:!0,contract:l}}import Pe from"fs";import te from"path";import dt from"fs";import _r from"path";import w from"fs";import Oe from"path";import xr from"crypto";var wr={timeoutMs:5e3,pollMs:15,staleMs:3e4};function Ar(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 br(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:i,staleMs:a}={...wr,...o},c=Oe.dirname(e);w.existsSync(c)||w.mkdirSync(c,{recursive:!0});let l=Ar(e),u=Date.now()+n,f=!1;for(;!f&&(f=it(l),!f);){if(Date.now()>=u){if(at(l,a),f=it(l),f)break;let p=new Error(`withFileLock: timeout acquiring ${l} after ${n}ms`);throw p.code="ELOCKTIMEOUT",p}at(l,a);let d=Math.floor(Math.random()*i);br(i+d)}try{return s()}finally{try{w.unlinkSync(l)}catch{}}}function A(e,t,r={}){let s=Oe.dirname(e);w.existsSync(s)||w.mkdirSync(s,{recursive:!0});let o=Oe.join(s,`.tmp-${Date.now()}-${xr.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 Nr(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 ft(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 Or(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 Cr(e,t){let r=JSON.stringify(t,null,2);A(e,r,{encoding:"utf8"})}function q({policyObj:e,statePath:t=_r.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 i=ft(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=Or(t)}catch(m){return{ok:!1,reason:"POLICY_STATE_CORRUPT",message:m.message,updated:!1}}let u=l.lastAccepted,f=null,d=null,p=0;if(u&&(f=ut(u.version),d=ft(u.createdAt),f.ok&&d.ok)){if(p=Nr(n,f),p<0)return{ok:!1,reason:"POLICY_VERSION_REGRESSION",message:`Policy version regression: current '${n.raw}' < last '${f.raw}'`,updated:!1};if(p===0&&i.epochSec<d.epochSec)return{ok:!1,reason:"POLICY_CREATED_AT_REGRESSION",message:`Policy createdAt regression: current '${e.createdAt}' < last '${u.createdAt}'`,updated:!1};if(p>0&&i.epochSec<d.epochSec)return{ok:!1,reason:"POLICY_CREATED_AT_REGRESSION",message:"Policy createdAt must be monotonic when version increases",updated:!1}}let g=!u||!f?.ok||!d?.ok||p>0||p===0&&i.epochSec>d.epochSec;if(o&&g){let m={schemaVersion:"1",lastAccepted:{version:e.version,createdAt:e.createdAt,environment:e.environment||null},updatedAt:new Date().toISOString()};Cr(t,m)}return{ok:!0,reason:null,message:"Policy version guard passed",updated:g}}import pt from"fs";import yt from"path";import{fileURLToPath as Rr}from"url";var Lr=yt.dirname(Rr(import.meta.url)),Ce=yt.join(Lr,"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"}},Dr={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"},Tr={0:"schema",1:"timestamp",2:"key",3:"signature",4:"rate_limit",5:"nonce",6:"policy",255:"ok"},$r=["LOW","MEDIUM","HIGH","CRITICAL"],Fr={ECHO:0,READ_FILE:1,WRITE_FILE:2,PATCH_FILE:3,DELETE_FILE:4,RUN_SHELL:5},fe=null;function M(){if(fe)return fe;if(!pt.existsSync(Ce))throw new Error(`LBE engine missing: ${Ce}`);let e=pt.readFileSync(Ce);return fe=new WebAssembly.Instance(new WebAssembly.Module(e),{}),fe}function pe(){return new Uint8Array(M().exports.memory.buffer)}function gt(){return M().exports.lbe_in_ptr()}function ht(){return M().exports.lbe_out_ptr()}function jr(){return M().exports.lbe_buf_size()}function kt(e){let t=new TextEncoder().encode(e),r=pe(),s=gt();r.set(t,s),r[s+t.length]=0}function St(){let e=pe(),t=ht(),r=t;for(;e[r]!==0&&r-t<jr();)r++;return new TextDecoder().decode(e.slice(t,r))}function Kr(e){let t=pe(),r=gt(),s=new DataView(t.buffer,r);e.forEach((o,n)=>s.setUint32(n*4,o>>>0,!0))}function qr(){let e=pe(),t=ht(),r=new DataView(e.buffer,t);return{stage:r.getUint32(0,!0),code:r.getUint32(4,!0)}}function It(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]),M().exports.lbe_validate_pipeline();let{stage:t,code:r}=qr();return{ok:t===255,stage:t,stageLabel:Tr[t]||"unknown",code:r,schemaError:t===0?Pr[r]?.error||"Schema invalid":null,keyReason:t===2?Dr[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 Re({ttlSec:e,nowSec:t,newKey:r,existingEntries:s}){let o=[`${e}:${t}`,r,...s].join(`
69
- `)+`
70
- `;if(kt(o),M().exports.lbe_nonce_check()!==0)return{ok:!1,updatedEntriesText:null};let i=St();return{ok:!0,updatedEntriesText:i.startsWith(`OK
71
- `)?i.slice(3):i}}function Et({windowSec:e,maxRequests:t,nowSec:r,requesterId:s,existingEntries:o}){let n=[`${e}:${t}:${r}`,s,...o].join(`
72
- `)+`
73
- `;kt(n);let i=M().exports.lbe_rate_check()!==0,a=St();if(i){let c=parseInt(a.match(/^EXCEEDED:(\d+)/)?.[1]??"1",10),l=a.replace(/^EXCEEDED:\d+\n/,"");return{ok:!1,retryAfterSec:c,updatedEntriesText:l}}return{ok:!0,retryAfterSec:0,updatedEntriesText:a.startsWith(`OK
74
- `)?a.slice(3):a}}function vt(e,t=!1){let r=Fr[e]??0,s=M().exports.lbe_classify_risk(r,t?1:0);return $r[s]??"LOW"}import Le from"path";function Mr(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 Vr(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(p=>p.toLowerCase()===o),i=!!s?.allowAdapters?.includes(t.payload?.adapter),a=!!t.payload?.cwd,c=!1,l=!1,u=!1;if(a){let p=s?.filesystem?.roots??[];if(c=p.length>0,c){let g=Le.resolve(t.payload.cwd);l=p.some(y=>{let S=Le.resolve(y);return g===S||g.startsWith(S+Le.sep)}),u=(s?.filesystem?.denyPatterns??[]).some(y=>new RegExp("^"+y.replace(/\./g,"\\.").replace(/\*\*/g,".*").replace(/\*/g,"[^/]*")+"$").test(g))}}let f=!1,d=!0;if(t.id==="RUN_SHELL"){f=!0;let p=s?.exec?.allowCmds??[],g=s?.exec?.denyCmds??[],m=t.payload?.cmd;g.includes(m)?d=!1:d=p.length===0||p.includes(m)}return{policyConfigured:r,requesterConfigured:!!s,commandAllowed:n,adapterAllowed:i,filesystemRequired:a,filesystemRootsDefined:c,filesystemOk:l,pathDenied:u,shellRequired:f,shellCommandOk:d}}function Yr(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 i=e.trustedKeys?.[t],a=!!i;if(!a)return{keyIdFormatValid:n,keyFound:a,keyNotDeprecated:!1,keyRequesterMatches:!1,keyNotBeforeOk:!1,keyNotExpired:!1,keyLifecycleFieldsPresent:!1,publicKey:null};let c=!i.deprecated,l=!i.requesterId||i.requesterId===r,u=i.notBefore||i.validFrom,f=i.expiresAt||i.validUntil,d=typeof u=="string"&&typeof f=="string",p=!1,g=!1;if(d){let m=new Date(u),y=new Date(f);!isNaN(m.getTime())&&!isNaN(y.getTime())&&m<y&&(p=s>=m,g=s<y)}return{keyIdFormatValid:n,keyFound:a,keyNotDeprecated:c,keyRequesterMatches:l,keyNotBeforeOk:p,keyNotExpired:g,keyLifecycleFieldsPresent:d,publicKey:i.publicKey??null}}function xt(e){return(e?.entries??[]).map(t=>`${t.key}:${t.timestamp}`)}function wt(e){return e.split(`
75
- `).filter(Boolean).map(t=>{let r=t.lastIndexOf(":");return{key:t.slice(0,r),timestamp:parseInt(t.slice(r+1),10)||0}})}function Jr(e){return(e?.entries??[]).map(t=>`${t.requesterId}:${t.timestamp}`)}function Br(e){return e.split(`
76
- `).filter(Boolean).map(t=>{let r=t.lastIndexOf(":");return{requesterId:t.slice(0,r),timestamp:parseInt(t.slice(r+1),10)||0}})}function ee({commandObj:e,pubKeyB64:t,keyStore:r,nonceDb:s,policy:o,rateLimiter:n,policyStatePath:i}){let a={valid:!1,commandId:e?.commandId,checks:{},errors:[]},c=Math.floor(Date.now()/1e3),l=new Date,u=Number.isFinite(o?.security?.maxClockSkewSec)?o.security.maxClockSkewSec:600;if(i&&o?.version!==void 0)try{let h=q({policyObj:o,statePath:i});if(a.checks.policyVersion=h.ok,!h.ok)return a.errors.push({type:"POLICY_VERSION_INVALID",message:h.message}),a}catch{a.checks.policyVersion=!0}else a.checks.policyVersion=!0;let f=Mr(e),d=e?.signature?.keyId,p=Yr(r,d,e?.requesterId,l),g=!1,m=p.publicKey;if(!m&&t&&(m=t),m){let h={...e};delete h.signature,g=de({payloadObj:h,sigB64:e?.signature?.sig,pubKeyB64:m}).valid}let y=!0,S=0;if(g&&n&&typeof n.db<"u"){let h=o?.requesters?.[e.requesterId]?.rateLimit||{},_=o?.security?.defaultRateLimit||{},O=h.windowSec??_.windowSec??60,z=h.maxRequests??_.maxRequests??30,X=Et({windowSec:O,maxRequests:z,nowSec:c,requesterId:e.requesterId,existingEntries:Jr(n.db)});y=X.ok,S=X.retryAfterSec,X.ok&&(n.db.entries=Br(X.updatedEntriesText))}else if(g&&n&&typeof n.checkAndRecord=="function"){let h=o?.requesters?.[e.requesterId]?.rateLimit||{},_=o?.security?.defaultRateLimit||{},O=n.checkAndRecord({requesterId:e.requesterId,nowSec:c,windowSec:h.windowSec??_.windowSec??60,maxRequests:h.maxRequests??_.maxRequests??30});y=O.ok,S=O.retryAfterSec??0}let k=!0,D=`${e?.requesterId}|${e?.sessionId}|${e?.nonce}`,K=3600;if(g&&y&&s)if(typeof s.checkAndRecord=="function")if(s.db){let h=Re({ttlSec:K,nowSec:c,newKey:D,existingEntries:xt(s.db)});k=h.ok,h.ok&&(s.db.entries=wt(h.updatedEntriesText))}else k=s.checkAndRecord({requesterId:e.requesterId,sessionId:e.sessionId,nonce:e.nonce}).ok;else{let h=Re({ttlSec:K,nowSec:c,newKey:D,existingEntries:xt(s)});k=h.ok,h.ok&&(s.entries=wt(h.updatedEntriesText))}let Ue=Vr(o,e??{}),I=It({...f,cmdTimestamp:e?.timestamp??0,nowSec:c,maxClockSkewSec:u,...p,signatureValid:g,rateLimitOk:y,rateLimitRetryAfterSec:S,nonceOk:k,...Ue}),b=I.stage;if(a.checks.schema=b!==0,b>=1&&(a.checks.timestamp=b!==1),b>=2&&(a.checks.keyId=b!==2),b>=2&&(a.checks.signature=b!==2&&b!==3),b>=4&&(a.checks.rateLimit=b!==4),b>=5&&(a.checks.nonce=b!==5),(b>=6||I.ok)&&(a.checks.policy=b!==6),!I.ok){let h=I.stageLabel;if(h==="schema")a.errors.push({type:"SCHEMA_ERROR",message:I.schemaError||"Schema invalid"});else if(h==="timestamp")a.errors.push({type:"TIMESTAMP_SKEW_EXCEEDED",message:`Command timestamp skew ${I.skewSec}s exceeds allowed ${u}s`});else if(h==="key"){let _=I.keyReason||"KEY_ERROR",O={KEY_ID_INVALID:`Invalid keyId '${d}'`,KEY_NOT_TRUSTED:`Key '${d}' is not in trusted key store`,KEY_DEPRECATED:`Key '${d}' is deprecated`,KEY_REQUESTER_MISMATCH:`Key '${d}' is not authorized for requester '${e?.requesterId}'`,KEY_LIFECYCLE_INVALID:`Key '${d}' must define notBefore and expiresAt`,KEY_NOT_YET_VALID:`Key '${d}' is not yet valid`,KEY_EXPIRED:`Key '${d}' has expired`};a.errors.push({type:_,message:O[_]||_})}else h==="signature"?a.errors.push({type:"SIGNATURE_INVALID",message:m?"Signature verification failed":"No public key available"}):h==="rate_limit"?a.errors.push({type:"RATE_LIMIT_EXCEEDED",message:`Rate limit exceeded. Retry after ${I.retryAfterSec}s`}):h==="nonce"?a.errors.push({type:"REPLAY_NONCE",message:"Nonce has already been used"}):h==="policy"&&I.policyResult?a.errors.push({type:I.policyResult.reason,message:I.policyResult.message}):a.errors.push({type:"VALIDATION_FAILED",message:`Failed at stage: ${h}`});return a}return a.valid=!0,a.risk=vt(e.id,e.payload?.cmd==="rm"),a.message="Command validation successful",a}import me from"fs";import Ur from"path";var V=class{constructor(t,r=3600){this.dbPath=t,this.ttlSec=r,this.db={entries:[]}}async load(){if(!me.existsSync(this.dbPath)){this.db={entries:[]};return}try{let t=me.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=Ur.dirname(this.dbPath);me.existsSync(t)||me.mkdirSync(t,{recursive:!0}),A(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}}};async function At(e){let{in:t}=e,r=e.config||e.policy,s=e["pub-key"],o=e["keys-store"]||te.resolve("config/keys.json"),n=e["policy-sig"]||te.resolve("config/policy.sig.json"),i=e["policy-state"]||te.resolve("data/policy.state.json"),a=e["policy-unsigned-ok"]===!0||String(e["policy-unsigned-ok"]).toLowerCase()==="true";t||(console.error("Error: --in <file> is required"),process.exit(1));let c;try{let S=te.resolve(t),k=Pe.readFileSync(S,"utf-8");c=JSON.parse(k)}catch(S){console.error(JSON.stringify({status:"error",error:"INVALID_PROPOSAL_FILE",message:S.message})),process.exit(5)}let l;try{let S=r||te.resolve("config/policy.default.json");Pe.existsSync(S)||(console.error(JSON.stringify({status:"error",error:"MISSING_POLICY",message:`Policy file not found: ${S}`})),process.exit(1));let k=Pe.readFileSync(S,"utf-8");l=JSON.parse(k)}catch(S){console.error(JSON.stringify({status:"error",error:"INVALID_POLICY",message:S.message})),process.exit(1)}let u=Q(o),f=u.ok?u.store:null,d=Z({policyObj:l,keyStore:f,policySigPath:n,allowUnsigned:a});d.ok||(console.error(JSON.stringify({status:"error",error:d.reason,message:d.message},null,2)),process.exit(8));let p=q({policyObj:l,statePath:i,maxCreatedAtSkewSec:l?.security?.maxPolicyCreatedAtSkewSec});p.ok||(console.error(JSON.stringify({status:"error",error:p.reason,message:p.message},null,2)),process.exit(8));let g=new V(te.resolve("data/nonce.db.json"));await g.load(),!f&&!s&&(console.error(JSON.stringify({status:"error",error:"MISSING_KEY_MATERIAL",message:`${u.message}. Provide --pub-key/--pub-key-file or create config/keys.json`})),process.exit(1));let m=ee({commandObj:c,pubKeyB64:s,keyStore:f,nonceDb:g,policy:l}),y={status:m.valid?"valid":"invalid",commandId:c.commandId||"N/A",checks:m.checks,errors:m.errors||[],risk:m.risk||"UNKNOWN"};console.log(JSON.stringify(y,null,2)),m.valid||(m.checks.schema===!1&&process.exit(5),m.checks.signature===!1&&process.exit(3),m.checks.nonce===!1&&process.exit(4),m.checks.timestamp===!1&&process.exit(6),m.checks.rateLimit===!1&&process.exit(7),m.checks.policy===!1&&process.exit(2),process.exit(9)),process.exit(0)}import $e from"fs";import oe from"path";async function bt(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 De from"path";function Wr(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 _t(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(f=>{let d=De.resolve(f),p=De.resolve(s.cwd);return p===d||p.startsWith(d+De.sep)}))return{adapter:"shell",commandId:e.commandId,status:"blocked",error:`CWD '${s.cwd}' not authorized`,exitCode:2};let u=Wr(s.args);if(!u.ok)return{adapter:"shell",commandId:e.commandId,status:"blocked",error:u.error,exitCode:2};try{let f=Gr(s.cmd,u.args,{cwd:s.cwd,timeout:o,encoding:"utf8",maxBuffer:n,stdio:["pipe","pipe","pipe"],shell:!1});if(f.error)throw f.error;let d=`${f.stdout||""}${f.stderr||""}`,p=f.status??1;return p!==0?{adapter:"shell",commandId:e.commandId,command:s.cmd,status:"error",error:d.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:d.substring(0,n),exitCode:0,timestamp:new Date().toISOString()}}catch(f){return{adapter:"shell",commandId:e.commandId,command:s.cmd,status:"error",error:f.message,exitCode:f.status||1,timestamp:new Date().toISOString()}}}import ie from"fs";import se from"path";import Y from"fs";import ye from"path";import Hr from"crypto";function ge(e,t){let r=t||ye.resolve("data/backups");Y.existsSync(r)||Y.mkdirSync(r,{recursive:!0});let s=ye.resolve(e),o=Y.existsSync(s),n=null,i=null;o&&(n=Y.readFileSync(s),i=Hr.createHash("sha256").update(n).digest("hex"));let a=ye.basename(s).replace(/[^a-zA-Z0-9._-]/g,"_"),c=`${Date.now()}-${i?i.slice(0,8):"new"}-${a}`,l=o?ye.join(r,c):null;return o&&n!==null&&A(l,n),{originalPath:s,backupPath:l,existed:o,hash:i,createdAt:new Date().toISOString()}}function U(e){if(!e)return{restored:!1,error:"No backup metadata"};let{originalPath:t,backupPath:r,existed:s}=e;if(!s)try{return Y.existsSync(t)&&Y.unlinkSync(t),{restored:!0,action:"deleted"}}catch(o){return{restored:!1,error:o.message}}if(!r||!Y.existsSync(r))return{restored:!1,error:"Backup file not found at: "+r};try{let o=Y.readFileSync(r);return A(t,o),{restored:!0,action:"restored"}}catch(o){return{restored:!1,error:o.message}}}var zr=10*1024*1024;function Xr(e,t){return e?se.isAbsolute(e)?se.resolve(e):se.resolve(t||process.cwd(),e):null}function Qr(e,t){let r=se.resolve(e);return t.some(s=>{let o=se.resolve(s);return r===o||r.startsWith(o+se.sep)})}function Zr(e,t){for(let r of t||[])if(new RegExp("^"+r.replace(/\./g,"\\.").replace(/\*\*/g,".*").replace(/\*/g,"[^/\\\\]*")+"$").test(e))return r;return null}function re(e,t,r,s=2){return{adapter:"file",commandId:e.commandId,status:"blocked",errorCode:t,error:r,exitCode:s}}function F(e,t,r,s=null,o=1){return{adapter:"file",commandId:e.commandId,status:"error",errorCode:t,error:r,backup:s?he(s):null,exitCode:o}}function he(e){return e?{path:e.backupPath,existed:e.existed,hash:e.hash,createdAt:e.createdAt}:null}async function Nt(e,t,r){let s=e.payload,o=s.action,n=s.cwd||process.cwd(),i=Xr(s.target,n);if(!o)return re(e,"FILE_NO_ACTION","payload.action is required");if(!i&&o!=="noop")return re(e,"FILE_NO_TARGET","payload.target is required");let a=r?.filesystem?.roots||[];if(a.length===0)return re(e,"FILE_NO_ROOTS","No filesystem roots defined for requester");if(!Qr(i,a))return re(e,"FILE_OUTSIDE_ROOT",`'${i}' is outside allowed roots`);let c=Zr(i,r?.filesystem?.denyPatterns);if(c)return re(e,"FILE_PATH_DENIED",`'${i}' matches deny pattern: ${c}`);switch(o){case"read":return es(e,i);case"write":return ts(e,i,s);case"patch":return rs(e,i,s);case"delete":return ss(e,i);default:return re(e,"FILE_UNKNOWN_ACTION",`Unknown action: '${o}'`)}}function es(e,t){if(!ie.existsSync(t))return F(e,"FILE_NOT_FOUND",`Not found: ${t}`);try{let r=ie.statSync(t);if(r.size>zr)return F(e,"FILE_TOO_LARGE","File exceeds 10 MB read limit");let s=ie.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 F(e,"FILE_READ_ERROR",r.message)}}function ts(e,t,r){let s=r.content;if(s==null)return F(e,"FILE_MISSING_CONTENT","payload.content is required for write");let o=Te(t);try{return A(t,s,{encoding:"utf8"}),{adapter:"file",action:"write",commandId:e.commandId,status:"completed",target:t,backup:he(o),output:`Wrote ${Buffer.byteLength(s,"utf8")} bytes to ${t}`,exitCode:0}}catch(n){return U(o),F(e,"FILE_WRITE_ERROR",n.message,o)}}function rs(e,t,r){let s=r.content;if(s==null)return F(e,"FILE_MISSING_CONTENT","payload.content is required for patch");let o=Te(t);try{return A(t,s,{encoding:"utf8"}),{adapter:"file",action:"patch",commandId:e.commandId,status:"completed",target:t,backup:he(o),output:`Patched ${t} (${Buffer.byteLength(s,"utf8")} bytes)`,exitCode:0}}catch(n){return U(o),F(e,"FILE_PATCH_ERROR",n.message,o)}}function ss(e,t){if(!ie.existsSync(t))return F(e,"FILE_NOT_FOUND",`Not found: ${t}`);let r=Te(t);try{return ie.unlinkSync(t),{adapter:"file",action:"delete",commandId:e.commandId,status:"completed",target:t,backup:he(r),output:`Deleted ${t}`,exitCode:0}}catch(s){return U(r),F(e,"FILE_DELETE_ERROR",s.message,r)}}function Te(e){try{return ge(e)}catch{return null}}async function Ot(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:u}=e.payload||{};if(!a||!c)return{adapter:"observer",commandId:e.commandId,status:"error",error:"Observer payload must include issueType and description",exitCode:1};let f=["low","medium","high","critical"];return l&&!f.includes(l)?{adapter:"observer",commandId:e.commandId,status:"error",error:`Invalid severity '${l}'. Must be one of: ${f.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:u||{}},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 Ct={noop:bt,shell:_t,file:Nt,observer:Ot};function os(e){return Ct[e]}async function ke(e,t,r,s){let o=os(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 jo=Object.keys(Ct);async function Rt(e){let{in:t}=e,r=e.config||e.policy,s=e["pub-key"],o=e["keys-store"]||oe.resolve("config/keys.json"),n=e["policy-sig"]||oe.resolve("config/policy.sig.json"),i=e["policy-state"]||oe.resolve("data/policy.state.json"),a=e["policy-unsigned-ok"]===!0||String(e["policy-unsigned-ok"]).toLowerCase()==="true";t||(console.error("Error: --in <file> is required"),process.exit(1));let c;try{let k=oe.resolve(t),D=$e.readFileSync(k,"utf-8");c=JSON.parse(D)}catch(k){console.error(JSON.stringify({status:"error",error:"INVALID_PROPOSAL_FILE",message:k.message})),process.exit(5)}let l;try{let k=r||oe.resolve("config/policy.default.json");$e.existsSync(k)||(console.error(JSON.stringify({status:"error",error:"MISSING_POLICY",message:`Policy file not found: ${k}`})),process.exit(1));let D=$e.readFileSync(k,"utf-8");l=JSON.parse(D)}catch(k){console.error(JSON.stringify({status:"error",error:"INVALID_POLICY",message:k.message})),process.exit(1)}let u=Q(o),f=u.ok?u.store:null,d=Z({policyObj:l,keyStore:f,policySigPath:n,allowUnsigned:a});d.ok||(console.error(JSON.stringify({status:"error",error:d.reason,message:d.message},null,2)),process.exit(8));let p=q({policyObj:l,statePath:i,maxCreatedAtSkewSec:l?.security?.maxPolicyCreatedAtSkewSec});p.ok||(console.error(JSON.stringify({status:"error",error:p.reason,message:p.message},null,2)),process.exit(8));let g=new V(oe.resolve("data/nonce.db.json"));await g.load(),!f&&!s&&(console.error(JSON.stringify({status:"error",error:"MISSING_KEY_MATERIAL",message:`${u.message}. Provide --pub-key/--pub-key-file or create config/keys.json`})),process.exit(1));let m=ee({commandObj:c,pubKeyB64:s,keyStore:f,nonceDb:g,policy:l});if(!m.valid){let k={status:"invalid",commandId:c.commandId||"N/A",checks:m.checks,errors:m.errors||[],executionResult:null};console.log(JSON.stringify(k,null,2)),m.checks.schema===!1&&process.exit(5),m.checks.signature===!1&&process.exit(3),m.checks.nonce===!1&&process.exit(4),m.checks.timestamp===!1&&process.exit(6),m.checks.rateLimit===!1&&process.exit(7),m.checks.policy===!1&&process.exit(2),process.exit(9)}let y;try{let k=l.requesters?.[c.requesterId];y=await ke("noop",c,l,k)}catch(k){y={adapter:"noop",status:"error",error:k.message}}let S={status:"valid_simulated",commandId:c.commandId||"N/A",checks:m.checks,risk:m.risk||"UNKNOWN",executionResult:{adapter:y.adapter,status:y.status,output:y.output||y.error||"",exitCode:y.exitCode||0,note:"This is a simulation using noop adapter. No actual execution occurred."}};console.log(JSON.stringify(S,null,2)),process.exit(0)}import Ee from"fs";import R from"path";import ds from"crypto";import J from"fs";import Fe from"path";import ns from"crypto";function Lt(e){return ns.createHash("sha256").update(e).digest("hex")}function is(e){try{if(!J.existsSync(e))return"GENESIS";let t=J.readFileSync(e,"utf8").trim();if(!t)return"GENESIS";let r=t.split(`
77
- `),s=r[r.length-1];try{return JSON.parse(s).hash||"GENESIS"}catch{return"GENESIS"}}catch{return"GENESIS"}}function je(e,t){let r=Fe.dirname(e);J.existsSync(r)||J.mkdirSync(r,{recursive:!0});let s;return ct(e,()=>{let o=is(e),n={...t,prevHash:o,timestamp:new Date().toISOString()};delete n.hash;let i=JSON.stringify(n),a=Lt(i),c=JSON.stringify({...n,hash:a}),l="";J.existsSync(e)&&(l=J.readFileSync(e,"utf8"));try{A(e,l+c+`
78
- `,{encoding:"utf8"})}catch(u){throw new Error(`Audit log write failed: ${u.message}`)}s={success:!0,hash:a,prevHash:o,message:"Audit entry appended"}}),s}function Pt(e,t={}){let r=t.failFast!==!1,s=Number.isFinite(t.maxEntries)&&t.maxEntries>0?Math.floor(t.maxEntries):null,o={ok:!0,file:Fe.resolve(e),entries:0,valid:!0,firstInvalidIndex:null,reason:null,errors:[],message:"Audit log verified"};try{if(!J.existsSync(e))return o.message="Audit log file not found (treated as empty)",o;let n=J.readFileSync(e,"utf8").trim();if(!n)return o.message="Empty audit log",o;let i=n.split(`
79
- `),a=s?i.slice(0,s):i;o.entries=a.length;let c="GENESIS";for(let l=0;l<a.length;l++){let u;try{u=JSON.parse(a[l])}catch{let g={index:l,reason:"INVALID_JSON_LINE",message:`Line ${l} is not valid JSON`};if(o.valid=!1,o.ok=!1,o.firstInvalidIndex??=l,o.reason??=g.reason,o.errors.push(g),r)break;continue}if(u.prevHash!==c){let g={index:l,reason:"PREV_HASH_MISMATCH",message:`Expected prevHash '${c}', got '${u.prevHash}'`};if(o.valid=!1,o.ok=!1,o.firstInvalidIndex??=l,o.reason??=g.reason,o.errors.push(g),r)break}let f={...u},d=f.hash;delete f.hash;let p=Lt(JSON.stringify(f));if(d!==p){let g={index:l,reason:"HASH_MISMATCH",message:`Expected hash '${p}', got '${d}'`};if(o.valid=!1,o.ok=!1,o.firstInvalidIndex??=l,o.reason??=g.reason,o.errors.push(g),r)break}c=d}return o.message=o.valid?`Audit log verified: ${o.entries} entries`:`Audit log integrity failed at index ${o.firstInvalidIndex}`,o}catch(n){return{ok:!1,file:Fe.resolve(e),entries:0,valid:!1,firstInvalidIndex:null,reason:"AUDIT_VERIFY_ERROR",errors:[{index:null,reason:"AUDIT_VERIFY_ERROR",message:n.message}],message:`Integrity check failed: ${n.message}`}}}import Se from"fs";import as from"path";var Ie=class{constructor(t){this.dbPath=t,this.db={entries:[]}}async load(){try{if(!Se.existsSync(this.dbPath)){this.db={entries:[]};return}let t=Se.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=as.dirname(this.dbPath);Se.existsSync(t)||Se.mkdirSync(t,{recursive:!0}),A(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(u=>u.timestamp>=c);let l=this.db.entries.filter(u=>u.requesterId===t);if(l.length>=a){let u=l.sort((d,p)=>d.timestamp-p.timestamp)[0],f=Math.max(1,i-(n-u.timestamp));return{ok:!1,reason:"RATE_LIMIT_EXCEEDED",message:`Rate limit exceeded for '${t}' (${a}/${i}s)`,retryAfterSec:f}}return this.db.entries.push({requesterId:t,timestamp:n}),{ok:!0,reason:null,message:"Rate limit check passed",retryAfterSec:0}}};import ls from"crypto";import cs from"path";var qe=class{constructor(t){this.dbPath=t||cs.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);A(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 Dt(e){return Ke||(Ke=new qe(e)),Ke}var Ve=class{constructor(t){this.store=Dt(t),this._pendingResolvers=new Map}createToken(t,r={}){let s=ls.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}},Me=null;function Tt(e){return Me||(Me=new Ve(e)),Me}function Ye(e){return ds.createHash("sha256").update(JSON.stringify(e)).digest("hex")}async function $t(e){let{in:t}=e,r=e.config||e.policy,s=e["pub-key"],o=e["keys-store"]||R.resolve("config/keys.json"),n=e["policy-sig"]||R.resolve("config/policy.sig.json"),i=e["policy-state"]||R.resolve("data/policy.state.json"),a=e["policy-unsigned-ok"]===!0||String(e["policy-unsigned-ok"]).toLowerCase()==="true";t||(console.error("Error: --in <file> is required"),process.exit(1));let c;try{let E=R.resolve(t),C=Ee.readFileSync(E,"utf-8");c=JSON.parse(C)}catch(E){console.error(JSON.stringify({status:"error",error:"INVALID_PROPOSAL_FILE",message:E.message})),process.exit(5)}let l;try{let E=r||R.resolve("config/policy.default.json");Ee.existsSync(E)||(console.error(JSON.stringify({status:"error",error:"MISSING_POLICY",message:`Policy file not found: ${E}`})),process.exit(1));let C=Ee.readFileSync(E,"utf-8");l=JSON.parse(C)}catch(E){console.error(JSON.stringify({status:"error",error:"INVALID_POLICY",message:E.message})),process.exit(1)}let u=Q(o),f=u.ok?u.store:null,d=Z({policyObj:l,keyStore:f,policySigPath:n,allowUnsigned:a});d.ok||(console.error(JSON.stringify({status:"error",error:d.reason,message:d.message},null,2)),process.exit(8));let p=q({policyObj:l,statePath:i,maxCreatedAtSkewSec:l?.security?.maxPolicyCreatedAtSkewSec});p.ok||(console.error(JSON.stringify({status:"error",error:p.reason,message:p.message},null,2)),process.exit(8));let g=new V(R.resolve("data/nonce.db.json"));await g.load(),!f&&!s&&(console.error(JSON.stringify({status:"error",error:"MISSING_KEY_MATERIAL",message:`${u.message}. Provide --pub-key/--pub-key-file or create config/keys.json`})),process.exit(1));let m=new Ie(R.resolve("data/rate-limit.db.json"));await m.load();let y=ee({commandObj:c,pubKeyB64:s,keyStore:f,nonceDb:g,policy:l,rateLimiter:m});if(!y.valid){try{await g.save(),await m.save()}catch{}let E={status:"invalid",commandId:c.commandId||"N/A",checks:y.checks,errors:y.errors||[],executionResult:null};console.error(JSON.stringify(E,null,2));let C=R.resolve("data/audit.log.jsonl");try{je(C,{commandId:c.commandId||"N/A",status:"rejected",requesterId:c.requesterId||"unknown",payloadHash:Ye(c),reason:y.checks,timestamp:new Date().toISOString()})}catch(Ht){console.error(JSON.stringify({status:"error",error:"AUDIT_WRITE_FAILED",message:Ht.message})),process.exit(10)}y.checks.schema===!1&&process.exit(5),y.checks.signature===!1&&process.exit(3),y.checks.nonce===!1&&process.exit(4),y.checks.timestamp===!1&&process.exit(6),y.checks.rateLimit===!1&&process.exit(7),y.checks.policy===!1&&process.exit(2),process.exit(9)}let S=y.risk||"LOW",k=c.payload.adapter||"shell",D=l.requesters?.[c.requesterId],K=D?.requireApproval;if(K===!0||Array.isArray(K)&&(K.includes(S)||K.includes("*")||["HIGH","CRITICAL"].includes(S)&&K.includes("HIGH+"))){let C=Tt().createToken(c.commandId,{requesterId:c.requesterId,adapter:k,risk:S});await g.save().catch(()=>{}),await m.save().catch(()=>{}),console.log(JSON.stringify({status:"approval_required",commandId:c.commandId||"N/A",risk:S,approvalToken:C,message:`${S} risk operation requires operator approval. Approve with: lbe approve --token ${C}`},null,2)),process.exit(11)}let I=null;if((e.backup===!0||k==="file")&&c.payload.target)try{I=ge(R.resolve(c.payload.target))}catch{}let h;try{h=await ke(k,c,l,D)}catch(E){h={adapter:k,status:"error",error:E.message,exitCode:1}}let _=h.status==="error"||h.exitCode!==0,O=null;if(_&&I&&e["rollback-on-failure"]!==!1)try{O=U(I)}catch(E){O={restored:!1,error:E.message}}let z=null;if(!_&&c.payload.target&&["write","patch"].includes(c.payload.action)){let C=Ee.existsSync(R.resolve(c.payload.target));z={ok:C,check:"target_exists",target:c.payload.target},!C&&I&&(O=U(I),h.status="error")}let X=R.resolve("data/audit.log.jsonl");try{je(X,{commandId:c.commandId||"N/A",status:O?.restored?"rolled_back":h.status||"completed",requesterId:c.requesterId||"unknown",payloadHash:Ye(c),executionHash:Ye(h),adapter:h.adapter,riskLevel:S,exitCode:h.exitCode||0,rolledBack:O?.restored||!1,timestamp:new Date().toISOString()})}catch(E){console.error(JSON.stringify({status:"error",error:"AUDIT_WRITE_FAILED",message:E.message})),process.exit(10)}await g.save(),await m.save();let Wt={status:_||z&&!z.ok?"failed":"executed",commandId:c.commandId||"N/A",risk:S,checks:y.checks,executionResult:{adapter:h.adapter,status:h.status||"completed",output:h.output||h.error||"",exitCode:h.exitCode||0},backup:I?{path:I.backupPath,existed:I.existed,hash:I.hash}:null,rollback:O,postValidation:z};console.log(JSON.stringify(Wt,null,2)),process.exit(h.exitCode||0)}import Ft from"path";function jt(e,t){if(e===void 0)return t;if(e===!0||e===!1)return e;let r=String(e).trim().toLowerCase();return r==="true"||r==="1"||r==="yes"?!0:r==="false"||r==="0"||r==="no"?!1:t}async function Kt(e){let t=e.audit?Ft.resolve(e.audit):Ft.resolve("data/audit.log.jsonl"),r=jt(e["fail-fast"],!0),s=jt(e.json,!0),o=Number.isFinite(Number(e.max))?Number(e.max):void 0,n=Pt(t,{failFast:r,maxEntries:o});s?console.log(JSON.stringify(n,null,2)):n.valid?(console.log(`OK: ${n.file}`),console.log(`Entries: ${n.entries}`)):(console.log(`FAIL: ${n.file}`),console.log(`First invalid index: ${n.firstInvalidIndex}`),console.log(`Reason: ${n.reason}`)),process.exit(n.valid?0:8)}import Be from"path";import G from"fs";import P from"path";import us from"crypto";import{fileURLToPath as fs}from"url";var ae=P.dirname(fs(import.meta.url));function qt(e){try{let t=G.readFileSync(e);return us.createHash("sha256").update(t).digest("hex")}catch{return null}}function ps(e=P.join(ae,"../..")){let t={},r=["src/core/signature.js","src/core/validator.js","src/core/policyEngine.js","src/core/nonceStore.js","src/core/auditLog.js","src/core/schema.js","bin/lbe.js"];for(let s of r){let o=P.join(e,s),n=qt(o);n&&(t[s]=n)}return t}function ms(e,t=P.join(ae,"../..")){let r={valid:!0,mismatches:[],missing:[],checkedFiles:0};for(let[s,o]of Object.entries(e)){let n=P.join(t,s);if(!G.existsSync(n)){r.valid=!1,r.missing.push(s);continue}let i=qt(n);r.checkedFiles++,i!==o&&(r.valid=!1,r.mismatches.push({file:s,expected:o,actual:i}))}return r}async function ne(e={}){let t=typeof e=="string"||e===null?{manifestPath:e}:e,r=t.rootDir||P.join(ae,"../.."),s=t.strict===!0,o=t.manifestPath||P.join(r,"config/integrity.manifest.json");if(!G.existsSync(o))return s?{valid:!1,skipped:!1,reason:"INTEGRITY_MANIFEST_MISSING",message:`Integrity manifest not found: ${o}`,checkedFiles:0,mismatches:[],missing:[]}:{valid:!0,skipped:!0,reason:null,message:"Integrity manifest not found - check skipped",checkedFiles:0,mismatches:[],missing:[]};try{let n=G.readFileSync(o,"utf8"),i=JSON.parse(n),a=ms(i,r);return{...a,skipped:!1,reason:a.valid?null:"INTEGRITY_CHECK_FAILED",message:a.valid?`Integrity check passed (${a.checkedFiles} files verified)`:"Runtime integrity check failed - system may be tampered"}}catch(n){return{valid:!1,skipped:!1,reason:"INTEGRITY_CHECK_ERROR",message:`Integrity check error: ${n.message}`,checkedFiles:0,mismatches:[],missing:[]}}}function Mt({outputPath:e=P.join(ae,"../../config/integrity.manifest.json"),rootDir:t=P.join(ae,"../..")}={}){let r=ps(t),s=JSON.stringify(r,null,2),o=P.dirname(e);return G.existsSync(o)||G.mkdirSync(o,{recursive:!0}),G.writeFileSync(e,s),{outputPath:e,fileCount:Object.keys(r).length,manifest:r}}function Je(e,t=!1){if(e===void 0)return t;if(e===!0||e===!1)return e;let r=String(e).trim().toLowerCase();return r==="true"||r==="1"||r==="yes"?!0:r==="false"||r==="0"||r==="no"?!1:t}async function Vt(e){let t=Je(e.strict,!1)||Je(e["integrity-strict"],!1),r=e.manifest?Be.resolve(e.manifest):Be.resolve(e["integrity-manifest"]||"config/integrity.manifest.json"),s=Je(e.json,!0),o=await ne({manifestPath:r,strict:t});console.log(s?JSON.stringify({ok:o.valid,valid:o.valid,skipped:o.skipped===!0,strict:t,manifestPath:r,checkedFiles:o.checkedFiles,mismatches:o.mismatches||[],missing:o.missing||[],reason:o.reason||null,message:o.message},null,2):o.message),process.exit(o.valid?0:8)}async function Yt(e){let t=Be.resolve(e.out||e.output||e.manifest||"config/integrity.manifest.json"),r=Mt({outputPath:t});console.log(JSON.stringify({ok:!0,outputPath:r.outputPath,fileCount:r.fileCount},null,2)),process.exit(0)}import W from"fs";import ve from"path";async function Jt(e){let t=ve.resolve(e.config||e.policy||"config/policy.default.json"),r=ve.resolve(e["policy-sig"]||"config/policy.sig.json"),s=ve.resolve(e["secret-key-file"]||"keys/secret.key"),o=String(e["policy-key-id"]||"policy-signer-v1-2026Q1");W.existsSync(t)||(console.error(JSON.stringify({status:"error",error:"POLICY_FILE_MISSING",message:`Policy file not found: ${t}`},null,2)),process.exit(1)),W.existsSync(s)||(console.error(JSON.stringify({status:"error",error:"SECRET_KEY_MISSING",message:`Secret key file not found: ${s}`},null,2)),process.exit(1));let n=JSON.parse(W.readFileSync(t,"utf8"));(typeof n.version>"u"||typeof n.createdAt>"u")&&(console.error(JSON.stringify({status:"error",error:"POLICY_VERSION_METADATA_MISSING",message:"Policy must include version and createdAt before signing"},null,2)),process.exit(8));let i=W.readFileSync(s,"utf8").trim(),a=ue({policyObj:n,secretKeyB64:i,keyId:o});a.ok||(console.error(JSON.stringify({status:"error",error:a.reason||"POLICY_SIGN_FAILED",message:a.message},null,2)),process.exit(8));let c=ve.dirname(r);W.existsSync(c)||W.mkdirSync(c,{recursive:!0}),W.writeFileSync(r,JSON.stringify(a.envelope,null,2)),console.log(JSON.stringify({status:"ok",message:"Policy signature written",policy:t,policySig:r,keyId:o},null,2)),process.exit(0)}import v from"fs";import N from"path";function Bt(e,t){if(e===void 0)return t;if(e===!0||e===!1)return e;let r=String(e).trim().toLowerCase();return r==="true"||r==="1"||r==="yes"?!0:r==="false"||r==="0"||r==="no"?!1:t}function j(e,t,r,s){e[t]={ok:r,message:s}}function H(e){try{return v.accessSync(e,v.constants.R_OK),!0}catch{return!1}}function ys(e){let t=N.join(e,`.healthcheck-${Date.now()}`);try{return v.mkdirSync(e,{recursive:!0}),v.writeFileSync(t,"ok","utf8"),v.unlinkSync(t),{ok:!0,message:"Data directory writable"}}catch(r){return{ok:!1,message:`Data directory not writable: ${r.message}`}}}async function Ut(e){let t=Bt(e.json,!0),r=N.resolve(e.config||e.policy||"config/policy.default.json"),s=N.resolve(e["policy-sig"]||"config/policy.sig.json"),o=N.resolve(e["keys-store"]||"config/keys.json"),n=N.resolve(e["data-dir"]||"data"),i=N.resolve(e.audit||N.join(n,"audit.log.jsonl")),a=N.resolve(e["nonce-db"]||N.join(n,"nonce.db.json")),c=N.resolve(e["rate-db"]||N.join(n,"rate-limit.db.json")),l=N.resolve(e["policy-state"]||N.join(n,"policy.state.json")),u=Bt(e["integrity-strict"],!1),f=N.resolve(e["integrity-manifest"]||"config/integrity.manifest.json"),d={};j(d,"policy",v.existsSync(r)&&H(r),v.existsSync(r)?`Policy file readable: ${r}`:`Policy file missing: ${r}`),j(d,"policySignature",v.existsSync(s)&&H(s),v.existsSync(s)?`Policy signature readable: ${s}`:`Policy signature missing: ${s}`),j(d,"trustedKeys",v.existsSync(o)&&H(o),v.existsSync(o)?`Trusted keys readable: ${o}`:`Trusted keys missing: ${o}`),j(d,"auditLog",v.existsSync(i)&&H(i),v.existsSync(i)?`Audit log readable: ${i}`:`Audit log missing: ${i}`),j(d,"nonceDb",v.existsSync(a)&&H(a),v.existsSync(a)?`Nonce DB readable: ${a}`:`Nonce DB missing: ${a}`),j(d,"rateLimitDb",v.existsSync(c)&&H(c),v.existsSync(c)?`Rate-limit DB readable: ${c}`:`Rate-limit DB missing: ${c}`),j(d,"policyState",v.existsSync(l)&&H(l),v.existsSync(l)?`Policy state readable: ${l}`:`Policy state missing: ${l}`);let p=ys(n);if(j(d,"dataWritable",p.ok,p.message),u){let y=await ne({strict:!0,manifestPath:f});j(d,"integrity",y.valid,y.valid?y.message:`${y.reason}: ${y.message}`)}let g=Object.values(d).every(y=>y.ok===!0),m={ok:g,status:g?"healthy":"unhealthy",timestamp:new Date().toISOString(),checks:d};console.log(t?JSON.stringify(m,null,2):`${m.status.toUpperCase()}: ${Object.keys(d).length} checks`),process.exit(g?0:8)}function hs(e,t=!1){if(e===void 0)return t;if(e===!0||e===!1)return e;let r=String(e).trim().toLowerCase();return r==="true"||r==="1"||r==="yes"?!0:r==="false"||r==="0"||r==="no"?!1:t}var ks=xe.dirname(gs(import.meta.url)),Ss=xe.join(ks,"../package.json"),ce=JSON.parse(Gt.readFileSync(Ss,"utf-8"));async function Is(){let e=process.argv.slice(2);e.includes("--version")&&(console.log(`LetterBlack Sentinel v${ce.version}`),process.exit(0)),(e.length===0||e.includes("--help")||e.includes("-h"))&&(le(ce.version),process.exit(0));let{command:t,opts:r}=Ge(e);r.version&&(console.log(`LetterBlack Sentinel v${ce.version}`),process.exit(0)),(r.help||!t||t==="help")&&(le(ce.version),process.exit(0));try{if(r["pub-key-file"])try{r["pub-key"]=Gt.readFileSync(xe.resolve(r["pub-key-file"]),"utf-8").trim()}catch(s){console.error(`Error reading public key file: ${s.message}`),process.exit(1)}if(["verify","dryrun","run"].includes(t)){let s=hs(r["integrity-strict"],!1),o=xe.resolve(r["integrity-manifest"]||"config/integrity.manifest.json"),n=await ne({strict:s,manifestPath:o});n.valid||(console.error(JSON.stringify({status:"error",error:n.reason||"INTEGRITY_CHECK_FAILED",message:n.message},null,2)),process.exit(8))}switch(t){case"init":await nt(r);break;case"verify":await At(r);break;case"dryrun":await Rt(r);break;case"run":await $t(r);break;case"audit-verify":await Kt(r);break;case"integrity-check":await Vt(r);break;case"integrity-generate":await Yt(r);break;case"policy-sign":await Jt(r);break;case"health":await Ut(r);break;default:console.error(`Unknown command: ${t}`),le(ce.version),process.exit(1)}}catch(s){console.error(JSON.stringify({status:"error",error:"INTERNAL_ERROR",message:s.message,stack:process.env.DEBUG?s.stack:void 0})),process.exit(9)}}Is().catch(e=>{console.error(JSON.stringify({status:"error",error:"FATAL_ERROR",message:e.message})),process.exit(9)});
34
+ try {
35
+ const output = execute(input);
36
+ process.stdout.write(output + '\n');
37
+ const parsed = JSON.parse(output);
38
+ if (parsed?.result?.type === 'allowed') process.exit(0);
39
+ if (parsed?.result?.type === 'denied') process.exit(1);
40
+ process.exit(2);
41
+ } catch (error) {
42
+ process.stderr.write(String(error?.message || error) + '\n');
43
+ process.exit(2);
44
+ }
package/dist/index.js CHANGED
@@ -1,12 +1,51 @@
1
- import Le from"crypto";import Ct from"fs";import qr from"os";import _ from"path";import Pe from"tweetnacl";import{canonicalize as et}from"json-canonicalize";function Ce(e){return Buffer.from(e,"base64")}function Te(e){return Buffer.from(e).toString("base64")}function z({payloadObj:e,sigB64:t,pubKeyB64:r}){try{let s=Buffer.from(et(e),"utf8"),o=Ce(t),n=Ce(r),a=Pe.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 ge(){let e=Pe.sign.keyPair();return{publicKey:Te(e.publicKey),secretKey:Te(e.secretKey)}}function se({payloadObj:e,secretKeyB64:t}){try{let r=Buffer.from(et(e),"utf8"),s=Ce(t),o=Pe.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 nt from"fs";import Ht from"path";import v from"fs";import $e from"path";import Bt from"crypto";var Mt={timeoutMs:5e3,pollMs:15,staleMs:3e4};function Yt(e){return e+".lock"}function tt(e){try{let t=v.openSync(e,"wx");return v.writeSync(t,`pid:${process.pid}:${Date.now()}`),v.closeSync(t),!0}catch(t){if(t.code==="EEXIST"||t.code==="EPERM"||t.code==="EBUSY"||t.code==="EACCES")return!1;throw t}}function rt(e,t){try{let r=v.statSync(e);if(Date.now()-r.mtimeMs>t)try{v.unlinkSync(e)}catch{}}catch{}}function Ut(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 st(e,t,r){let s=typeof t=="function"?t:r,o=typeof t=="function"?{}:t||{},{timeoutMs:n,pollMs:a,staleMs:i}={...Mt,...o},c=$e.dirname(e);v.existsSync(c)||v.mkdirSync(c,{recursive:!0});let l=Yt(e),d=Date.now()+n,u=!1;for(;!u&&(u=tt(l),!u);){if(Date.now()>=d){if(rt(l,i),u=tt(l),u)break;let m=new Error(`withFileLock: timeout acquiring ${l} after ${n}ms`);throw m.code="ELOCKTIMEOUT",m}rt(l,i);let f=Math.floor(Math.random()*a);Ut(a+f)}try{return s()}finally{try{v.unlinkSync(l)}catch{}}}function A(e,t,r={}){let s=$e.dirname(e);v.existsSync(s)||v.mkdirSync(s,{recursive:!0});let o=$e.join(s,`.tmp-${Date.now()}-${Bt.randomBytes(4).toString("hex")}`);try{v.writeFileSync(o,t,r),v.renameSync(o,e)}catch(n){try{v.existsSync(o)&&v.unlinkSync(o)}catch{}throw n}}function ot(e){try{if(!v.existsSync(e))return null;let t=v.readFileSync(e,"utf8");return JSON.parse(t)}catch(t){return console.error(`[atomicWrite] Failed to read JSON from ${e}:`,t.message),null}}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 Wt(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 at(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 Gt(e){if(!nt.existsSync(e))return{schemaVersion:"1",lastAccepted:null,updatedAt:null};try{let t=JSON.parse(nt.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 jt(e,t){let r=JSON.stringify(t,null,2);A(e,r,{encoding:"utf8"})}function ke({policyObj:e,statePath:t=Ht.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 a=at(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=Gt(t)}catch(S){return{ok:!1,reason:"POLICY_STATE_CORRUPT",message:S.message,updated:!1}}let d=l.lastAccepted,u=null,f=null,m=0;if(d&&(u=it(d.version),f=at(d.createdAt),u.ok&&f.ok)){if(m=Wt(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<f.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<f.epochSec)return{ok:!1,reason:"POLICY_CREATED_AT_REGRESSION",message:"Policy createdAt must be monotonic when version increases",updated:!1}}let I=!d||!u?.ok||!f?.ok||m>0||m===0&&a.epochSec>f.epochSec;if(o&&I){let S={schemaVersion:"1",lastAccepted:{version:e.version,createdAt:e.createdAt,environment:e.environment||null},updatedAt:new Date().toISOString()};jt(t,S)}return{ok:!0,reason:null,message:"Policy version guard passed",updated:I}}import Fe from"fs";import lt from"path";import{fileURLToPath as Jt}from"url";var zt=lt.dirname(Jt(import.meta.url)),oe=lt.join(zt,"lbe_engine.wasm"),ct={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"}},Xt={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"}},Qt={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"},Zt={0:"schema",1:"timestamp",2:"key",3:"signature",4:"rate_limit",5:"nonce",6:"policy",255:"ok"},er=["LOW","MEDIUM","HIGH","CRITICAL"],tr={ECHO:0,READ_FILE:1,WRITE_FILE:2,PATCH_FILE:3,DELETE_FILE:4,RUN_SHELL:5},Ee=null;function $(){if(Ee)return Ee;if(!Fe.existsSync(oe))throw new Error(`LBE engine missing: ${oe}`);let e=Fe.readFileSync(oe);return Ee=new WebAssembly.Instance(new WebAssembly.Module(e),{}),Ee}function Ie(){return new Uint8Array($().exports.memory.buffer)}function dt(){return $().exports.lbe_in_ptr()}function ut(){return $().exports.lbe_out_ptr()}function rr(){return $().exports.lbe_buf_size()}function ft(e){let t=new TextEncoder().encode(e),r=Ie(),s=dt();r.set(t,s),r[s+t.length]=0}function pt(){let e=Ie(),t=ut(),r=t;for(;e[r]!==0&&r-t<rr();)r++;return new TextDecoder().decode(e.slice(t,r))}function sr(e){let t=Ie(),r=dt(),s=new DataView(t.buffer,r);e.forEach((o,n)=>s.setUint32(n*4,o>>>0,!0))}function or(){let e=Ie(),t=ut(),r=new DataView(e.buffer,t);return{stage:r.getUint32(0,!0),code:r.getUint32(4,!0)}}function nr(){return{mode:"wasm",available:Fe.existsSync(oe),wasmPath:oe,localFirst:!0}}async function ir(){return{ok:!0,mode:"wasm",version:$().exports.lbe_engine_version()}}function mt(e){sr([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]),$().exports.lbe_validate_pipeline();let{stage:t,code:r}=or();return{ok:t===255,stage:t,stageLabel:Zt[t]||"unknown",code:r,schemaError:t===0?Xt[r]?.error||"Schema invalid":null,keyReason:t===2?Qt[r]||"KEY_ERROR":null,policyResult:t===6?{...ct[r]||ct[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(`
2
- `)+`
3
- `;if(ft(o),$().exports.lbe_nonce_check()!==0)return{ok:!1,updatedEntriesText:null};let a=pt();return{ok:!0,updatedEntriesText:a.startsWith(`OK
4
- `)?a.slice(3):a}}function yt({windowSec:e,maxRequests:t,nowSec:r,requesterId:s,existingEntries:o}){let n=[`${e}:${t}:${r}`,s,...o].join(`
5
- `)+`
6
- `;ft(n);let a=$().exports.lbe_rate_check()!==0,i=pt();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
7
- `)?i.slice(3):i}}function ht(e,t=!1){let r=tr[e]??0,s=$().exports.lbe_classify_risk(r,t?1:0);return er[s]??"LOW"}import qe from"path";function ar(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 cr(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 I=qe.resolve(t.payload.cwd);l=m.some(x=>{let T=qe.resolve(x);return I===T||I.startsWith(T+qe.sep)}),d=(s?.filesystem?.denyPatterns??[]).some(x=>new RegExp("^"+x.replace(/\./g,"\\.").replace(/\*\*/g,".*").replace(/\*/g,"[^/]*")+"$").test(I))}}let u=!1,f=!0;if(t.id==="RUN_SHELL"){u=!0;let m=s?.exec?.allowCmds??[],I=s?.exec?.denyCmds??[],S=t.payload?.cmd;I.includes(S)?f=!1:f=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:f}}function lr(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,f=typeof d=="string"&&typeof u=="string",m=!1,I=!1;if(f){let S=new Date(d),x=new Date(u);!isNaN(S.getTime())&&!isNaN(x.getTime())&&S<x&&(m=s>=S,I=s<x)}return{keyIdFormatValid:n,keyFound:i,keyNotDeprecated:c,keyRequesterMatches:l,keyNotBeforeOk:m,keyNotExpired:I,keyLifecycleFieldsPresent:f,publicKey:a.publicKey??null}}function gt(e){return(e?.entries??[]).map(t=>`${t.key}:${t.timestamp}`)}function kt(e){return e.split(`
8
- `).filter(Boolean).map(t=>{let r=t.lastIndexOf(":");return{key:t.slice(0,r),timestamp:parseInt(t.slice(r+1),10)||0}})}function dr(e){return(e?.entries??[]).map(t=>`${t.requesterId}:${t.timestamp}`)}function ur(e){return e.split(`
9
- `).filter(Boolean).map(t=>{let r=t.lastIndexOf(":");return{requesterId:t.slice(0,r),timestamp:parseInt(t.slice(r+1),10)||0}})}function Se({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 p=ke({policyObj:o,statePath:a});if(i.checks.policyVersion=p.ok,!p.ok)return i.errors.push({type:"POLICY_VERSION_INVALID",message:p.message}),i}catch{i.checks.policyVersion=!0}else i.checks.policyVersion=!0;let u=ar(e),f=e?.signature?.keyId,m=lr(r,f,e?.requesterId,l),I=!1,S=m.publicKey;if(!S&&t&&(S=t),S){let p={...e};delete p.signature,I=z({payloadObj:p,sigB64:e?.signature?.sig,pubKeyB64:S}).valid}let x=!0,T=0;if(I&&n&&typeof n.db<"u"){let p=o?.requesters?.[e.requesterId]?.rateLimit||{},g=o?.security?.defaultRateLimit||{},L=p.windowSec??g.windowSec??60,K=p.maxRequests??g.maxRequests??30,q=yt({windowSec:L,maxRequests:K,nowSec:c,requesterId:e.requesterId,existingEntries:dr(n.db)});x=q.ok,T=q.retryAfterSec,q.ok&&(n.db.entries=ur(q.updatedEntriesText))}else if(I&&n&&typeof n.checkAndRecord=="function"){let p=o?.requesters?.[e.requesterId]?.rateLimit||{},g=o?.security?.defaultRateLimit||{},L=n.checkAndRecord({requesterId:e.requesterId,nowSec:c,windowSec:p.windowSec??g.windowSec??60,maxRequests:p.maxRequests??g.maxRequests??30});x=L.ok,T=L.retryAfterSec??0}let Y=!0,ce=`${e?.requesterId}|${e?.sessionId}|${e?.nonce}`,U=3600;if(I&&x&&s)if(typeof s.checkAndRecord=="function")if(s.db){let p=Ke({ttlSec:U,nowSec:c,newKey:ce,existingEntries:gt(s.db)});Y=p.ok,p.ok&&(s.db.entries=kt(p.updatedEntriesText))}else Y=s.checkAndRecord({requesterId:e.requesterId,sessionId:e.sessionId,nonce:e.nonce}).ok;else{let p=Ke({ttlSec:U,nowSec:c,newKey:ce,existingEntries:gt(s)});Y=p.ok,p.ok&&(s.entries=kt(p.updatedEntriesText))}let le=cr(o,e??{}),w=mt({...u,cmdTimestamp:e?.timestamp??0,nowSec:c,maxClockSkewSec:d,...m,signatureValid:I,rateLimitOk:x,rateLimitRetryAfterSec:T,nonceOk:Y,...le}),h=w.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||w.ok)&&(i.checks.policy=h!==6),!w.ok){let p=w.stageLabel;if(p==="schema")i.errors.push({type:"SCHEMA_ERROR",message:w.schemaError||"Schema invalid"});else if(p==="timestamp")i.errors.push({type:"TIMESTAMP_SKEW_EXCEEDED",message:`Command timestamp skew ${w.skewSec}s exceeds allowed ${d}s`});else if(p==="key"){let g=w.keyReason||"KEY_ERROR",L={KEY_ID_INVALID:`Invalid keyId '${f}'`,KEY_NOT_TRUSTED:`Key '${f}' is not in trusted key store`,KEY_DEPRECATED:`Key '${f}' is deprecated`,KEY_REQUESTER_MISMATCH:`Key '${f}' is not authorized for requester '${e?.requesterId}'`,KEY_LIFECYCLE_INVALID:`Key '${f}' must define notBefore and expiresAt`,KEY_NOT_YET_VALID:`Key '${f}' is not yet valid`,KEY_EXPIRED:`Key '${f}' has expired`};i.errors.push({type:g,message:L[g]||g})}else p==="signature"?i.errors.push({type:"SIGNATURE_INVALID",message:S?"Signature verification failed":"No public key available"}):p==="rate_limit"?i.errors.push({type:"RATE_LIMIT_EXCEEDED",message:`Rate limit exceeded. Retry after ${w.retryAfterSec}s`}):p==="nonce"?i.errors.push({type:"REPLAY_NONCE",message:"Nonce has already been used"}):p==="policy"&&w.policyResult?i.errors.push({type:w.policyResult.reason,message:w.policyResult.message}):i.errors.push({type:"VALIDATION_FAILED",message:`Failed at stage: ${p}`});return i}return i.valid=!0,i.risk=ht(e.id,e.payload?.cmd==="rm"),i.message="Command validation successful",i}import _e from"fs";import fr from"path";var we=class{constructor(t,r=3600){this.dbPath=t,this.ttlSec=r,this.db={entries:[]}}async load(){if(!_e.existsSync(this.dbPath)){this.db={entries:[]};return}try{let t=_e.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=fr.dirname(this.dbPath);_e.existsSync(t)||_e.mkdirSync(t,{recursive:!0}),A(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 ve from"fs";import pr from"path";var Ae=class{constructor(t){this.dbPath=t,this.db={entries:[]}}async load(){try{if(!ve.existsSync(this.dbPath)){this.db={entries:[]};return}let t=ve.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);ve.existsSync(t)||ve.mkdirSync(t,{recursive:!0}),A(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((f,m)=>f.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 X from"fs";import mr from"path";import yr from"crypto";function hr(e){return yr.createHash("sha256").update(e).digest("hex")}function gr(e){try{if(!X.existsSync(e))return"GENESIS";let t=X.readFileSync(e,"utf8").trim();if(!t)return"GENESIS";let r=t.split(`
10
- `),s=r[r.length-1];try{return JSON.parse(s).hash||"GENESIS"}catch{return"GENESIS"}}catch{return"GENESIS"}}function ne(e,t){let r=mr.dirname(e);X.existsSync(r)||X.mkdirSync(r,{recursive:!0});let s;return st(e,()=>{let o=gr(e),n={...t,prevHash:o,timestamp:new Date().toISOString()};delete n.hash;let a=JSON.stringify(n),i=hr(a),c=JSON.stringify({...n,hash:i}),l="";X.existsSync(e)&&(l=X.readFileSync(e,"utf8"));try{A(e,l+c+`
11
- `,{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 Et(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 kr}from"child_process";import Ve from"path";function Er(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 It(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 f=Ve.resolve(u),m=Ve.resolve(s.cwd);return m===f||m.startsWith(f+Ve.sep)}))return{adapter:"shell",commandId:e.commandId,status:"blocked",error:`CWD '${s.cwd}' not authorized`,exitCode:2};let d=Er(s.args);if(!d.ok)return{adapter:"shell",commandId:e.commandId,status:"blocked",error:d.error,exitCode:2};try{let u=kr(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 f=`${u.stdout||""}${u.stderr||""}`,m=u.status??1;return m!==0?{adapter:"shell",commandId:e.commandId,command:s.cmd,status:"error",error:f.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:f.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 ie from"fs";import ee from"path";import B from"fs";import xe from"path";import Ir from"crypto";function Q(e,t){let r=t||xe.resolve("data/backups");B.existsSync(r)||B.mkdirSync(r,{recursive:!0});let s=xe.resolve(e),o=B.existsSync(s),n=null,a=null;o&&(n=B.readFileSync(s),a=Ir.createHash("sha256").update(n).digest("hex"));let i=xe.basename(s).replace(/[^a-zA-Z0-9._-]/g,"_"),c=`${Date.now()}-${a?a.slice(0,8):"new"}-${i}`,l=o?xe.join(r,c):null;return o&&n!==null&&A(l,n),{originalPath:s,backupPath:l,existed:o,hash:a,createdAt:new Date().toISOString()}}function M(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 A(t,o),{restored:!0,action:"restored"}}catch(o){return{restored:!1,error:o.message}}}var Sr=10*1024*1024;function _r(e,t){return e?ee.isAbsolute(e)?ee.resolve(e):ee.resolve(t||process.cwd(),e):null}function wr(e,t){let r=ee.resolve(e);return t.some(s=>{let o=ee.resolve(s);return r===o||r.startsWith(o+ee.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 Z(e,t,r,s=2){return{adapter:"file",commandId:e.commandId,status:"blocked",errorCode:t,error:r,exitCode:s}}function F(e,t,r,s=null,o=1){return{adapter:"file",commandId:e.commandId,status:"error",errorCode:t,error:r,backup:s?be(s):null,exitCode:o}}function be(e){return e?{path:e.backupPath,existed:e.existed,hash:e.hash,createdAt:e.createdAt}:null}async function St(e,t,r){let s=e.payload,o=s.action,n=s.cwd||process.cwd(),a=_r(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(!wr(a,i))return Z(e,"FILE_OUTSIDE_ROOT",`'${a}' is outside allowed roots`);let c=vr(a,r?.filesystem?.denyPatterns);if(c)return Z(e,"FILE_PATH_DENIED",`'${a}' matches deny pattern: ${c}`);switch(o){case"read":return Ar(e,a);case"write":return xr(e,a,s);case"patch":return br(e,a,s);case"delete":return Rr(e,a);default:return Z(e,"FILE_UNKNOWN_ACTION",`Unknown action: '${o}'`)}}function Ar(e,t){if(!ie.existsSync(t))return F(e,"FILE_NOT_FOUND",`Not found: ${t}`);try{let r=ie.statSync(t);if(r.size>Sr)return F(e,"FILE_TOO_LARGE","File exceeds 10 MB read limit");let s=ie.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 F(e,"FILE_READ_ERROR",r.message)}}function xr(e,t,r){let s=r.content;if(s==null)return F(e,"FILE_MISSING_CONTENT","payload.content is required for write");let o=Be(t);try{return A(t,s,{encoding:"utf8"}),{adapter:"file",action:"write",commandId:e.commandId,status:"completed",target:t,backup:be(o),output:`Wrote ${Buffer.byteLength(s,"utf8")} bytes to ${t}`,exitCode:0}}catch(n){return M(o),F(e,"FILE_WRITE_ERROR",n.message,o)}}function br(e,t,r){let s=r.content;if(s==null)return F(e,"FILE_MISSING_CONTENT","payload.content is required for patch");let o=Be(t);try{return A(t,s,{encoding:"utf8"}),{adapter:"file",action:"patch",commandId:e.commandId,status:"completed",target:t,backup:be(o),output:`Patched ${t} (${Buffer.byteLength(s,"utf8")} bytes)`,exitCode:0}}catch(n){return M(o),F(e,"FILE_PATCH_ERROR",n.message,o)}}function Rr(e,t){if(!ie.existsSync(t))return F(e,"FILE_NOT_FOUND",`Not found: ${t}`);let r=Be(t);try{return ie.unlinkSync(t),{adapter:"file",action:"delete",commandId:e.commandId,status:"completed",target:t,backup:be(r),output:`Deleted ${t}`,exitCode:0}}catch(s){return M(r),F(e,"FILE_DELETE_ERROR",s.message,r)}}function Be(e){try{return Q(e)}catch{return null}}async function _t(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 wt={noop:Et,shell:It,file:St,observer:_t};function Lr(e){return wt[e]}async function vt(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 At=Object.keys(wt);import Lt from"fs";import Cr from"path";import xt from"fs";import Nr from"path";var Dr=/^[A-Za-z0-9:_-]{3,128}$/;function Or(e){return typeof e=="string"&&Dr.test(e)&&e!=="default"}function bt(e){let t=Nr.resolve(e);if(!xt.existsSync(t))return{ok:!1,reason:"KEY_STORE_MISSING",message:`Key store not found: ${t}`,store:null};try{let r=xt.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 Rt({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(!Or(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 Nt({policyObj:e,keyStore:t,policySigPath:r="./config/policy.sig.json",allowUnsigned:s=!1}){let o=Cr.resolve(r);if(!Lt.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(Lt.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=Rt({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=z({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 Pr from"crypto";import Tr from"path";var Ye=class{constructor(t){this.dbPath=t||Tr.resolve("data/checkpoints.db.json"),this.store={checkpoints:{},tokens:{}},this._load()}_load(){let t=ot(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);A(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}},Me=null;function Dt(e){return Me||(Me=new Ye(e)),Me}var He=class{constructor(t){this.store=Dt(t),this._pendingResolvers=new Map}createToken(t,r={}){let s=Pr.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}},Ue=null;function Ot(e){return Ue||(Ue=new He(e)),Ue}var We={DEBUG:0,INFO:1,WARN:2,ERROR:3};function ae({level:e="INFO",maxHistory:t=500,silent:r=!1}={}){let s=We[e]??We.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&&We[i]>=s){let f=d!==void 0?`[${i}] [${c}] ${l} ${JSON.stringify(d)}`:`[${i}] [${c}] ${l}`;process.stderr.write(f+`
12
- `)}}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 $r=process.env.LBE_LOG_LEVEL||"INFO",Fr=process.env.LBE_LOG_SILENT==="1",io=ae({level:$r,silent:Fr});function te(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)&&te(r)}return e}import Je from"fs";import Ge from"path";var W=class extends Error{constructor(t,r,s){super(t),this.name="InvariantGateError",this.checks=r,this.failures=s}};function ze(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,f]of Object.entries(t.requesters))for(let m of f.allowAdapters||[])At.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 Re(e,t,r){let s=ze(e,t,r);if(!s.ok){let o=s.failures.length;throw new W(`Invariant gate: ${o} violation${o===1?"":"s"} \u2014 ${s.failures.join(" | ")}`,s.checks,s.failures)}return s}function Kr(e){try{return Je.accessSync(e,Je.constants.W_OK),!0}catch{return!1}}function je(e){if(Kr(e))return!0;try{return Je.mkdirSync(e,{recursive:!0}),!0}catch{return!1}}function Vr(e,t){let r=_.resolve(e||process.cwd());if(!t||t==="local"){let s=Le.createHash("sha256").update(r).digest("hex").slice(0,16);return _.join(qr.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 Br={patch_file:"PATCH_FILE",write_file:"WRITE_FILE",read_file:"READ_FILE",delete_file:"DELETE_FILE",run_shell:"RUN_SHELL",echo:"ECHO"},Mr={PATCH_FILE:"file",WRITE_FILE:"file",READ_FILE:"file",DELETE_FILE:"file",RUN_SHELL:"shell",ECHO:"noop"},Yr=new Set(["HIGH","CRITICAL"]);function Xe(e){return Le.createHash("sha256").update(JSON.stringify(e)).digest("hex")}function Ur(e,t){if(!t?.requireApproval)return!1;let r=t.requireApproval;return r===!0?!0:Array.isArray(r)?r.includes(e)||r.includes("*")||Yr.has(e)&&r.includes("HIGH+"):!1}function Tt(e={}){if(e.rootDir&&!e.secretKey){let b=ge(),E=e.keyId||"sdk-auto-key";e={defaultActor:"agent:sdk",logLevel:"WARN",...e,secretKey:b.secretKey,keyId:E,keyStore:e.keyStore||Pt({publicKey:b.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:f,auditLogPath:m,backupDir:I,allowUnsignedPolicy:S=!1,state:x="local",rootDir:T,logLevel:Y=process.env.LBE_LOG_LEVEL||"INFO",logSilent:ce=process.env.LBE_LOG_SILENT==="1"}=e,U=n&&typeof n=="object"?n:null,le=a&&typeof a=="object"?a:null,w=Vr(T,x),h={secretKey:t,policy:i||_.resolve("config/policy.default.json"),keys:c||_.resolve("config/keys.json"),policySig:l||_.resolve("config/policy.sig.json"),policyState:d||_.join(w,"policy.state.json"),nonceDb:u||_.join(w,"nonce.db.json"),rateLimit:f||_.join(w,"rate-limit.db.json"),auditLog:m||_.join(w,"audit.log.jsonl"),backupDir:I||_.join(w,"backups")},p=ae({level:Y,silent:ce}),g=p.scope("Executor"),L=p.scope("Validator"),K=p.scope("Policy");async function q({actor:b,intent:E,target:k,content:de,args:$t=[],transaction:Ft={}}){let re={validate:!0,backup:!0,rollbackOnFailure:!0,audit:!0,...Ft};g.info("execute() called",{actor:b,intent:E,target:k});let ue=Br[E]||E.toUpperCase().replace(/-/g,"_"),G=Mr[ue]||"noop",D;if(U)D=U,K.debug("Using inline policy",{version:D.version});else try{D=JSON.parse(Ct.readFileSync(h.policy,"utf8")),K.debug("Policy loaded from file",{version:D.version})}catch(y){return K.error("Policy load failed",{error:y.message}),{ok:!1,stage:"policy_load",error:"POLICY_LOAD_FAILED",message:y.message}}let H;if(le)H=le,L.debug("Using inline keyStore");else{let y=bt(h.keys);H=y.ok?y.store:null,L.debug("Keys loaded from file",{ok:y.ok})}te(D),H&&te(H);try{let y=Re(h,D,H);L.debug("Invariant gate passed",y.checks)}catch(y){if(y instanceof W)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(!U){let y=Nt({policyObj:D,keyStore:H,policySigPath:h.policySig,allowUnsigned:S});if(!y.ok)return K.error("Policy signature invalid",{reason:y.reason}),{ok:!1,stage:"policy_sig",error:y.reason,message:y.message};let N=ke({policyObj:D,statePath:h.policyState});if(!N.ok)return K.error("Policy version guard failed",{reason:N.reason}),{ok:!1,stage:"policy_version",error:N.reason,message:N.message};K.debug("Policy signature and version valid")}if(!t)return{ok:!1,stage:"sign",error:"NO_SECRET_KEY",message:"createLBE requires secretKey"};let Kt=Math.floor(Date.now()/1e3),qt=Le.randomBytes(32).toString("hex"),Vt=s||`sdk-${Date.now()}`,O=Le.randomUUID();g.debug("Proposal built",{commandId:O,commandId_str:ue,adapter:G});let fe={id:ue,commandId:O,requesterId:b,sessionId:Vt,timestamp:Kt,nonce:qt,requires:["policy","signature"],payload:{adapter:G,action:E.includes("_")?E.split("_")[0]:E,target:k?_.resolve(k):null,content:de||null,args:$t,cwd:k?_.dirname(_.resolve(k)):process.cwd()}},pe=se({payloadObj:fe,secretKeyB64:t});if(pe.error)return g.error("Signing failed",{error:pe.error}),{ok:!1,stage:"sign",commandId:O,error:"SIGN_FAILED",message:pe.error};let me={...fe,signature:{alg:"ed25519",keyId:r,sig:pe.signature}},Ne=new we(h.nonceDb);await Ne.load();let De=new Ae(h.rateLimit);await De.load();let C=Se({commandObj:me,keyStore:H,nonceDb:Ne,policy:D,rateLimiter:De,policyStatePath:U?null:h.policyState}),ye=async()=>{await Ne.save().catch(()=>{}),await De.save().catch(()=>{})};if(!C.valid)return L.warn("Validation failed",{error:C.errors[0]?.type,checks:C.checks}),await ye(),re.audit&&ne(h.auditLog,{commandId:O,status:"rejected",requesterId:b,payloadHash:Xe(me),reason:C.errors[0]?.type,intent:E}),{ok:!1,stage:"validate",commandId:O,error:C.errors[0]?.type,message:C.errors[0]?.message,checks:C.checks,operationLog:p.exportLogs()};L.info("Validation passed",{risk:C.risk,checks:C.checks});let V=C.risk||"LOW",Qe=D.requesters?.[b];if(Ur(V,Qe)){g.warn("Approval required",{risk:V,commandId:O}),await ye();let N=Ot(h.policyState).createToken(O,{actor:b,intent:E,target:k,risk:V,commandId:ue});return{ok:!1,stage:"approval_pending",commandId:O,approvalToken:N,risk:V,message:`${V} risk operation requires approval. Token: ${N}`,operationLog:p.exportLogs()}}let P=null;if(re.backup&&k){let y=["write","patch","delete"].includes(fe?.payload?.action??E.split("_")[0]);try{P=Q(_.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 ye(),{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:G,target:k});let R;try{R=await vt(G,me,D,Qe)}catch(y){R={adapter:G,commandId:O,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,j=null;if(re.validate&&k&&!Oe){let y=["write","patch"],N=fe.payload.action;if(y.includes(N)){let Ze=Ct.existsSync(_.resolve(k));j={ok:Ze,check:"target_exists",target:k},Ze?g.debug("Post-execution validation passed"):(g.error("Post-execution validation failed \u2014 target missing after write",{target:k}),R.status="error")}}let J=null;if((Oe||j&&!j.ok)&&re.rollbackOnFailure&&P)try{J=M(P),g.warn("Rollback executed",J)}catch(y){J={restored:!1,error:y.message},g.error("Rollback failed",{error:y.message})}re.audit&&ne(h.auditLog,{commandId:O,status:J?.restored?"rolled_back":R.status||"completed",requesterId:b,payloadHash:Xe(me),executionHash:Xe(R),adapter:G,intent:E,riskLevel:V,exitCode:R.exitCode||0,rolledBack:J?.restored||!1}),await ye();let he=!Oe&&(!j||j.ok);return g.info("execute() complete",{ok:he,stage:he?"executed":"failed",risk:V}),{ok:he,commandId:O,intent:E,actor:b,target:k,risk:V,stage:he?"executed":"failed",status:R.status,output:R.output||null,exitCode:R.exitCode??0,checks:C.checks,backup:P?{path:P.backupPath,existed:P.existed,hash:P.hash}:null,rollback:J,postValidation:j,operationLog:Y==="DEBUG"?p.exportLogs():void 0}}return{execute:q,exportLogs:()=>p.exportLogs(),async writeFile(b,E){let k=await q({actor:o,intent:"write_file",target:b,content:E,transaction:{backup:!0,rollbackOnFailure:!0,audit:!0}});if(!k.ok){let de=new Error(`LBE write failed [${k.error||k.stage}]${k.message?": "+k.message:""}`);throw de.lbeResult=k,de}return k},async readFile(b){let E=await q({actor:o,intent:"read_file",target:b,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 Hr(e,t={}){let{audit:r=!1,rollback:s=!1}=t,o=_.resolve(e),n=Tt({rootDir:o,state:t.state||"local",logSilent:!0}),a=l=>_.isAbsolute(l)?l:_.join(o,l),i={backup:s,rollbackOnFailure:s,audit:r};function c(l,d){let u=new Error(`sandbox.${l} blocked [${d.error}]${d.message?": "+d.message:""}`);return u.lbeResult=d,u}return{async write(l,d){let u=await n.execute({actor:"agent:sdk",intent:"write_file",target:a(l),content:d,transaction:i});if(!u.ok)throw c("write",u)},async read(l){let d=await n.execute({actor:"agent:sdk",intent:"read_file",target:a(l),transaction:{audit:r}});if(!d.ok)throw c("read",d);return d.output},async patch(l,d){let u=await n.execute({actor:"agent:sdk",intent:"patch_file",target:a(l),content:d,transaction:i});if(!u.ok)throw c("patch",u)},lbe:n}}function Pt({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()}}}}export{W as InvariantGateError,ne as appendAudit,Re as assertInvariants,ze as checkInvariants,Q as createBackup,Pt as createKeyStore,Tt as createLBE,ae as createLogger,te as deepFreeze,ge as generateKeyPair,nr as getRuntimeInfo,ir as loadWasmEngine,M as restoreBackup,Hr as sandbox,se as signEd25519,Se as validateCommand,z as verifyEd25519};
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import crypto from 'node:crypto';
4
+ import { fileURLToPath } from 'node:url';
5
+
6
+ const here = path.dirname(fileURLToPath(import.meta.url));
7
+ const wasmPath = path.join(here, 'lbe_engine.wasm');
8
+ const lockPath = path.join(here, 'wasm.lock.json');
9
+ let instance;
10
+
11
+ function hashFile(file) {
12
+ return crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
13
+ }
14
+
15
+ function load() {
16
+ if (instance) return instance;
17
+ const lock = JSON.parse(fs.readFileSync(lockPath, 'utf8'));
18
+ const actual = hashFile(wasmPath);
19
+ if (actual !== lock.wasm_sha256) throw new Error('LBE WASM integrity check failed');
20
+ const wasm = new WebAssembly.Instance(new WebAssembly.Module(fs.readFileSync(wasmPath)), {});
21
+ if (typeof wasm.exports.lbe_execute !== 'function') throw new Error('LBE WASM missing execute entrypoint');
22
+ instance = wasm;
23
+ return instance;
24
+ }
25
+
26
+ function memory(wasm) {
27
+ return new Uint8Array(wasm.exports.memory.buffer);
28
+ }
29
+
30
+ function readOut(wasm) {
31
+ const mem = memory(wasm);
32
+ const ptr = wasm.exports.lbe_out_ptr();
33
+ const max = wasm.exports.lbe_buf_size();
34
+ let end = ptr;
35
+ while (mem[end] !== 0 && end - ptr < max) end++;
36
+ return new TextDecoder().decode(mem.slice(ptr, end));
37
+ }
38
+
39
+ export function execute(input) {
40
+ if (typeof input !== 'string') throw new TypeError('execute input must be a string');
41
+ const wasm = load();
42
+ const bytes = new TextEncoder().encode(input);
43
+ const max = wasm.exports.lbe_buf_size();
44
+ if (bytes.length + 1 > max) throw new Error('execute input exceeds WASM buffer');
45
+ const mem = memory(wasm);
46
+ const ptr = wasm.exports.lbe_in_ptr();
47
+ mem.set(bytes, ptr);
48
+ mem[ptr + bytes.length] = 0;
49
+ wasm.exports.lbe_execute();
50
+ return readOut(wasm);
51
+ }
Binary file
@@ -1,52 +1,105 @@
1
1
  #!/usr/bin/env node
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.4
2
+ import { execute } from './index.js';
15
3
 
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.
4
+ let buffer = Buffer.alloc(0);
18
5
 
19
- Usage:
20
- node bin/lbe-mcp-server.js Start server on stdio
21
- npx lbe-mcp Same via npx
22
- npm run mcp Same via npm script
6
+ function send(payload) {
7
+ const body = Buffer.from(JSON.stringify(payload), 'utf8');
8
+ process.stdout.write(`Content-Length: ${body.length}\r\n\r\n`);
9
+ process.stdout.write(body);
10
+ }
23
11
 
24
- Setup:
25
- npm run init Generate keys and policy
12
+ function result(id, value) {
13
+ send({ jsonrpc: '2.0', id, result: value });
14
+ }
26
15
 
27
- Environment:
28
- LBE_SECRET_KEY_PATH Path to secret key (default: keys/secret.key)
29
- LBE_KEYS_STORE_PATH Path to keys.json (default: config/keys.json)
30
- LBE_MCP_DEFAULT_ACTOR Default actor id (default: mcp:client)
31
- LBE_LOG_LEVEL DEBUG|INFO|WARN|ERROR (default: WARN)
16
+ function error(id, code, message) {
17
+ send({ jsonrpc: '2.0', id, error: { code, message } });
18
+ }
32
19
 
33
- Tools exposed:
34
- lbe_workspace_context Read the workspace contract \u2014 call this FIRST
35
- lbe_write_file Write a file \u2014 backup, audit, rollback-on-failure
36
- lbe_read_file Read a file \u2014 policy-checked, audited
37
- lbe_patch_file Append/patch a file \u2014 backed up before write
38
- lbe_shell_command Run a command \u2014 must be in policy allowlist
39
- lbe_health Check controller health
40
-
41
- Claude Desktop config:
42
- {
43
- "mcpServers": {
44
- "lbe": {
45
- "command": "npx",
46
- "args": ["lbe-mcp"],
47
- "cwd": "/path/to/your/letterblack-sentinel",
48
- "env": { "LBE_MCP_DEFAULT_ACTOR": "agent:claude" }
20
+ function handle(message) {
21
+ const { id, method, params } = message;
22
+ if (method === 'initialize') {
23
+ result(id, {
24
+ protocolVersion: params?.protocolVersion || '2024-11-05',
25
+ capabilities: { tools: {} },
26
+ serverInfo: { name: 'lbe', version: '1.0.1' }
27
+ });
28
+ return;
29
+ }
30
+ if (method === 'notifications/initialized') return;
31
+ if (method === 'tools/list') {
32
+ result(id, {
33
+ tools: [{
34
+ name: 'lbe_execute',
35
+ description: 'Execute one canonical LBE JSON request through the local WASM boundary.',
36
+ inputSchema: {
37
+ type: 'object',
38
+ properties: {
39
+ input: {
40
+ type: 'object',
41
+ description: 'LBE execute request object. It will be serialized and passed to execute(input).'
42
+ },
43
+ input_json: {
44
+ type: 'string',
45
+ description: 'Raw JSON string to pass to execute(input). Takes precedence over input.'
46
+ }
47
+ }
48
+ }
49
+ }]
50
+ });
51
+ return;
52
+ }
53
+ if (method === 'tools/call') {
54
+ try {
55
+ if (params?.name !== 'lbe_execute') {
56
+ error(id, -32602, 'Unknown tool');
57
+ return;
49
58
  }
59
+ const args = params.arguments || {};
60
+ const input = typeof args.input_json === 'string' ? args.input_json : JSON.stringify(args.input);
61
+ const output = execute(input);
62
+ result(id, {
63
+ content: [{ type: 'text', text: output }],
64
+ structuredContent: JSON.parse(output),
65
+ isError: false
66
+ });
67
+ } catch (err) {
68
+ result(id, {
69
+ content: [{ type: 'text', text: String(err?.message || err) }],
70
+ isError: true
71
+ });
72
+ }
73
+ return;
74
+ }
75
+ if (id !== undefined) error(id, -32601, 'Method not found');
76
+ }
77
+
78
+ function pump() {
79
+ while (true) {
80
+ const headerEnd = buffer.indexOf('\r\n\r\n');
81
+ if (headerEnd < 0) return;
82
+ const header = buffer.slice(0, headerEnd).toString('utf8');
83
+ const match = header.match(/Content-Length:\s*(\d+)/i);
84
+ if (!match) {
85
+ buffer = buffer.slice(headerEnd + 4);
86
+ continue;
87
+ }
88
+ const length = Number(match[1]);
89
+ const bodyStart = headerEnd + 4;
90
+ const bodyEnd = bodyStart + length;
91
+ if (buffer.length < bodyEnd) return;
92
+ const body = buffer.slice(bodyStart, bodyEnd).toString('utf8');
93
+ buffer = buffer.slice(bodyEnd);
94
+ try {
95
+ handle(JSON.parse(body));
96
+ } catch (err) {
97
+ error(null, -32700, String(err?.message || err));
50
98
  }
51
99
  }
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.4"},{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);
100
+ }
101
+
102
+ process.stdin.on('data', (chunk) => {
103
+ buffer = Buffer.concat([buffer, chunk]);
104
+ pump();
105
+ });
@@ -0,0 +1,5 @@
1
+ {
2
+ "wasm_sha256": "feb93a2ea76a02584048a588305ba0a192683fd58c1da8f539aeb49b41d0a254",
3
+ "entrypoint": "lbe_execute",
4
+ "contract": "execute(input:string)->string"
5
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letterblack/lbe-sdk",
3
- "version": "0.4.4",
3
+ "version": "1.0.1",
4
4
  "description": "Local-first execution governance SDK for AI agents.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -10,7 +10,7 @@
10
10
  "types": "./types.d.ts",
11
11
  "default": "./dist/index.js"
12
12
  },
13
- "./engine": "./dist/index.js"
13
+ "./cli": "./dist/cli.js"
14
14
  },
15
15
  "bin": {
16
16
  "lbe": "dist/cli.js",
@@ -39,11 +39,7 @@
39
39
  ],
40
40
  "author": "LetterBlack",
41
41
  "license": "SEE LICENSE IN LICENSE",
42
- "dependencies": {
43
- "@modelcontextprotocol/sdk": "^1.29.0",
44
- "json-canonicalize": "^1.0.4",
45
- "tweetnacl": "^1.0.3"
46
- },
42
+ "dependencies": {},
47
43
  "engines": {
48
44
  "node": ">=20.9.0"
49
45
  }
package/types.d.ts CHANGED
@@ -1,98 +1,56 @@
1
- export type LBERisk = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
2
-
3
- export interface LBEResult {
4
- ok: boolean;
5
- commandId?: string;
6
- intent?: string;
7
- actor?: string;
8
- target?: string;
9
- risk?: LBERisk;
10
- stage?: string;
11
- status?: string;
12
- output?: string | null;
13
- exitCode?: number;
14
- checks?: Record<string, unknown>;
15
- backup?: { path?: string | null; existed?: boolean; hash?: string | null } | null;
16
- rollback?: Record<string, unknown> | null;
17
- postValidation?: Record<string, unknown> | null;
18
- error?: string;
19
- message?: string;
20
- }
21
-
22
- export interface LBETransactionOptions {
23
- validate?: boolean;
24
- backup?: boolean;
25
- rollbackOnFailure?: boolean;
26
- audit?: boolean;
27
- }
28
-
29
- export interface LBEExecuteOptions {
30
- actor?: string;
31
- intent: string;
32
- target?: string;
33
- content?: string;
34
- args?: string[];
35
- transaction?: LBETransactionOptions;
1
+ export interface LBEActor {
2
+ id: string;
3
+ role: 'user' | 'system' | 'agent';
36
4
  }
37
5
 
38
- export interface LBEClient {
39
- execute(options: LBEExecuteOptions): Promise<LBEResult>;
40
- exportLogs(): unknown[];
41
- writeFile(target: string, content: string): Promise<LBEResult>;
42
- readFile(target: string): Promise<string>;
6
+ export interface LBEIntent {
7
+ type: 'command' | 'query' | 'task';
8
+ name: string;
9
+ payload: Record<string, unknown>;
43
10
  }
44
11
 
45
- export interface SandboxClient {
46
- write(target: string, content: string): Promise<void>;
47
- read(target: string): Promise<string>;
48
- patch(target: string, content: string): Promise<void>;
49
- lbe: LBEClient;
12
+ export interface LBEExecuteInput {
13
+ version: '1.0';
14
+ request_id: string;
15
+ timestamp: number;
16
+ actor: LBEActor;
17
+ intent: LBEIntent;
18
+ context: {
19
+ workspace: string;
20
+ env: Record<string, unknown>;
21
+ history: unknown[];
22
+ };
23
+ constraints: {
24
+ policy_mode: 'strict' | 'permissive';
25
+ timeout_ms: number;
26
+ };
27
+ auth: {
28
+ signature: string;
29
+ nonce: string;
30
+ };
50
31
  }
51
32
 
52
- export interface CreateLBEOptions {
53
- rootDir?: string;
54
- state?: 'local' | 'workspace' | { adapter: unknown };
55
- secretKey?: string;
56
- keyId?: string;
57
- sessionId?: string;
58
- defaultActor?: string;
59
- policy?: Record<string, unknown>;
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;
70
- logLevel?: 'DEBUG' | 'INFO' | 'WARN' | 'ERROR';
71
- logSilent?: boolean;
72
- }
73
-
74
- export interface SandboxOptions {
75
- audit?: boolean;
76
- rollback?: boolean;
77
- state?: 'local' | 'workspace' | { adapter: unknown };
33
+ export interface LBEExecuteOutput {
34
+ ok: boolean;
35
+ result: {
36
+ type: 'allowed' | 'denied' | 'error';
37
+ action: string;
38
+ data: Record<string, unknown>;
39
+ };
40
+ policy: {
41
+ decision: 'allow' | 'deny' | 'escalate';
42
+ reason: string;
43
+ rules: string[];
44
+ };
45
+ trace: {
46
+ id: string;
47
+ steps: unknown[];
48
+ hash: string;
49
+ };
50
+ error: null | {
51
+ code: string;
52
+ message: string;
53
+ };
78
54
  }
79
55
 
80
- export function createLBE(options?: CreateLBEOptions): LBEClient;
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 }>;
56
+ export function execute(input: string): string;