@letterblack/lbe-core 1.3.3 → 1.3.4
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/LICENSE +1 -1
- package/README.md +130 -442
- package/assets/runtime-boundary.svg +36 -36
- package/dist/cli.js +141 -0
- package/dist/index.js +52 -0
- package/{release-exec/dist → dist}/wasm.lock.json +5 -4
- package/package.json +23 -54
- package/types.d.ts +2 -175
- package/.githooks/pre-commit +0 -2
- package/.githooks/pre-push +0 -2
- package/CHANGELOG.md +0 -75
- package/Release-README.md +0 -65
- package/WORKSPACE.md +0 -422
- package/_proof.mjs +0 -246
- package/bin/lbe.js +0 -12
- package/config/identity.config.json +0 -3
- package/config/policy.default.json +0 -24
- package/dist/cli/lbe.js +0 -4274
- package/dist/hooks/register.cjs +0 -505
- package/dist/state/appendCentral.cjs +0 -87
- package/dist/state/index.cjs +0 -101
- package/exec/cli.js +0 -472
- package/exec/index.js +0 -2
- package/index.js +0 -24
- package/lbe.audit.jsonl +0 -46
- package/release/README.md +0 -216
- package/release/TRUST.md +0 -90
- package/release/exec-README.md +0 -215
- package/release/exec-types.d.ts +0 -50
- package/release-exec/LICENSE +0 -1
- package/release-exec/README.md +0 -215
- package/release-exec/assets/lbe-gates.jpg +0 -0
- package/release-exec/assets/lbe-gates.png +0 -0
- package/release-exec/assets/runtime-boundary.svg +0 -36
- package/release-exec/assets/story-allow.jpg +0 -0
- package/release-exec/assets/story-allow.png +0 -0
- package/release-exec/assets/story-deny.jpg +0 -0
- package/release-exec/assets/story-deny.png +0 -0
- package/release-exec/dist/cli.js +0 -2841
- package/release-exec/dist/index.js +0 -1835
- package/release-exec/hooks/register.cjs +0 -473
- package/release-exec/package.json +0 -35
- package/release-exec/types.d.ts +0 -50
- package/runtime/engine.js +0 -322
- package/runtime/lbe_engine.wasm +0 -0
- package/src/cli/commands/auditVerify.js +0 -36
- package/src/cli/commands/dryrun.js +0 -175
- package/src/cli/commands/health.js +0 -153
- package/src/cli/commands/init.js +0 -306
- package/src/cli/commands/integrityCheck.js +0 -57
- package/src/cli/commands/logs.js +0 -53
- package/src/cli/commands/openState.js +0 -44
- package/src/cli/commands/policyAdd.js +0 -8
- package/src/cli/commands/policyMode.js +0 -7
- package/src/cli/commands/policySign.js +0 -72
- package/src/cli/commands/proof.js +0 -122
- package/src/cli/commands/run.js +0 -342
- package/src/cli/commands/status.js +0 -73
- package/src/cli/commands/verify.js +0 -144
- package/src/cli/main.js +0 -176
- package/src/cli/parseArgs.js +0 -114
- package/src/exec/localExecutor.js +0 -289
- package/src/hooks/register.cjs +0 -505
- package/src/state/appendCentral.cjs +0 -87
- package/src/state/fileIndex.js +0 -140
- package/src/state/index.cjs +0 -101
- package/src/state/index.js +0 -65
- package/src/state/intentRegistry.js +0 -83
- package/src/state/migration.js +0 -112
- package/src/state/proofRunner.js +0 -246
- package/src/state/stateRoot.js +0 -40
- package/src/state/targetRegistry.js +0 -108
- package/src/state/workspaceId.js +0 -40
- package/src/state/workspaceRegistry.js +0 -65
- /package/{release-exec/dist → dist}/lbe_engine.wasm +0 -0
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="960" height="440" viewBox="0 0 960 440" role="img" aria-labelledby="title desc">
|
|
2
|
-
<title id="title">LetterBlack LBE runtime boundary</title>
|
|
3
|
-
<desc id="desc">An application sends a serialized request to the local LBE WASM validation runtime, which returns a structured allow, deny, or error decision to the application.</desc>
|
|
4
|
-
<defs>
|
|
5
|
-
<linearGradient id="panel" x1="0" x2="1"><stop stop-color="#172033"/><stop offset="1" stop-color="#202d47"/></linearGradient>
|
|
6
|
-
<linearGradient id="runtime" x1="0" x2="1"><stop stop-color="#3756d6"/><stop offset="1" stop-color="#7356d6"/></linearGradient>
|
|
7
|
-
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#8fa3c9"/></marker>
|
|
8
|
-
</defs>
|
|
9
|
-
<rect width="960" height="440" rx="24" fill="#0e1524"/>
|
|
10
|
-
<text x="56" y="65" fill="#f5f8ff" font-family="Arial, sans-serif" font-size="28" font-weight="700">Local validation boundary</text>
|
|
11
|
-
<text x="56" y="98" fill="#aab9d4" font-family="Arial, sans-serif" font-size="17">The host owns execution. LBE returns a deterministic decision before the host accepts an action.</text>
|
|
12
|
-
|
|
13
|
-
<rect x="55" y="165" width="220" height="170" rx="16" fill="url(#panel)" stroke="#405273"/>
|
|
14
|
-
<text x="165" y="220" text-anchor="middle" fill="#fff" font-family="Arial, sans-serif" font-size="21" font-weight="700">Host application</text>
|
|
15
|
-
<text x="165" y="254" text-anchor="middle" fill="#b9c7df" font-family="Arial, sans-serif" font-size="15">agent, tool, or service</text>
|
|
16
|
-
<text x="165" y="286" text-anchor="middle" fill="#7fe1c3" font-family="Arial, sans-serif" font-size="15">serializes request</text>
|
|
17
|
-
|
|
18
|
-
<line x1="285" y1="250" x2="402" y2="250" stroke="#8fa3c9" stroke-width="4" marker-end="url(#arrow)"/>
|
|
19
|
-
<text x="343" y="229" text-anchor="middle" fill="#aab9d4" font-family="Arial, sans-serif" font-size="14">JSON request</text>
|
|
20
|
-
|
|
21
|
-
<rect x="415" y="132" width="290" height="236" rx="18" fill="url(#runtime)" stroke="#9a8cff" stroke-width="2"/>
|
|
22
|
-
<text x="560" y="183" text-anchor="middle" fill="#fff" font-family="Arial, sans-serif" font-size="23" font-weight="700">LBE WASM runtime</text>
|
|
23
|
-
<line x1="453" y1="205" x2="667" y2="205" stroke="#bfc8ff" opacity=".55"/>
|
|
24
|
-
<text x="560" y="242" text-anchor="middle" fill="#f0efff" font-family="Arial, sans-serif" font-size="16">schema · timestamp · key lifecycle</text>
|
|
25
|
-
<text x="560" y="271" text-anchor="middle" fill="#f0efff" font-family="Arial, sans-serif" font-size="16">signature · rate limit · nonce · policy</text>
|
|
26
|
-
<text x="560" y="319" text-anchor="middle" fill="#d7d1ff" font-family="Arial, sans-serif" font-size="14">local, deterministic validation</text>
|
|
27
|
-
|
|
28
|
-
<line x1="718" y1="250" x2="825" y2="250" stroke="#8fa3c9" stroke-width="4" marker-end="url(#arrow)"/>
|
|
29
|
-
<text x="770" y="229" text-anchor="middle" fill="#aab9d4" font-family="Arial, sans-serif" font-size="14">structured result</text>
|
|
30
|
-
|
|
31
|
-
<rect x="838" y="165" width="80" height="170" rx="16" fill="url(#panel)" stroke="#405273"/>
|
|
32
|
-
<text x="878" y="215" text-anchor="middle" fill="#fff" font-family="Arial, sans-serif" font-size="16" font-weight="700">Host</text>
|
|
33
|
-
<text x="878" y="249" text-anchor="middle" fill="#7fe1c3" font-family="Arial, sans-serif" font-size="14">allow</text>
|
|
34
|
-
<text x="878" y="275" text-anchor="middle" fill="#ffadad" font-family="Arial, sans-serif" font-size="14">deny</text>
|
|
35
|
-
<text x="878" y="301" text-anchor="middle" fill="#ffd28a" font-family="Arial, sans-serif" font-size="14">error</text>
|
|
36
|
-
</svg>
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="960" height="440" viewBox="0 0 960 440" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">LetterBlack LBE runtime boundary</title>
|
|
3
|
+
<desc id="desc">An application sends a serialized request to the local LBE WASM validation runtime, which returns a structured allow, deny, or error decision to the application.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<linearGradient id="panel" x1="0" x2="1"><stop stop-color="#172033"/><stop offset="1" stop-color="#202d47"/></linearGradient>
|
|
6
|
+
<linearGradient id="runtime" x1="0" x2="1"><stop stop-color="#3756d6"/><stop offset="1" stop-color="#7356d6"/></linearGradient>
|
|
7
|
+
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#8fa3c9"/></marker>
|
|
8
|
+
</defs>
|
|
9
|
+
<rect width="960" height="440" rx="24" fill="#0e1524"/>
|
|
10
|
+
<text x="56" y="65" fill="#f5f8ff" font-family="Arial, sans-serif" font-size="28" font-weight="700">Local validation boundary</text>
|
|
11
|
+
<text x="56" y="98" fill="#aab9d4" font-family="Arial, sans-serif" font-size="17">The host owns execution. LBE returns a deterministic decision before the host accepts an action.</text>
|
|
12
|
+
|
|
13
|
+
<rect x="55" y="165" width="220" height="170" rx="16" fill="url(#panel)" stroke="#405273"/>
|
|
14
|
+
<text x="165" y="220" text-anchor="middle" fill="#fff" font-family="Arial, sans-serif" font-size="21" font-weight="700">Host application</text>
|
|
15
|
+
<text x="165" y="254" text-anchor="middle" fill="#b9c7df" font-family="Arial, sans-serif" font-size="15">agent, tool, or service</text>
|
|
16
|
+
<text x="165" y="286" text-anchor="middle" fill="#7fe1c3" font-family="Arial, sans-serif" font-size="15">serializes request</text>
|
|
17
|
+
|
|
18
|
+
<line x1="285" y1="250" x2="402" y2="250" stroke="#8fa3c9" stroke-width="4" marker-end="url(#arrow)"/>
|
|
19
|
+
<text x="343" y="229" text-anchor="middle" fill="#aab9d4" font-family="Arial, sans-serif" font-size="14">JSON request</text>
|
|
20
|
+
|
|
21
|
+
<rect x="415" y="132" width="290" height="236" rx="18" fill="url(#runtime)" stroke="#9a8cff" stroke-width="2"/>
|
|
22
|
+
<text x="560" y="183" text-anchor="middle" fill="#fff" font-family="Arial, sans-serif" font-size="23" font-weight="700">LBE WASM runtime</text>
|
|
23
|
+
<line x1="453" y1="205" x2="667" y2="205" stroke="#bfc8ff" opacity=".55"/>
|
|
24
|
+
<text x="560" y="242" text-anchor="middle" fill="#f0efff" font-family="Arial, sans-serif" font-size="16">schema · timestamp · key lifecycle</text>
|
|
25
|
+
<text x="560" y="271" text-anchor="middle" fill="#f0efff" font-family="Arial, sans-serif" font-size="16">signature · rate limit · nonce · policy</text>
|
|
26
|
+
<text x="560" y="319" text-anchor="middle" fill="#d7d1ff" font-family="Arial, sans-serif" font-size="14">local, deterministic validation</text>
|
|
27
|
+
|
|
28
|
+
<line x1="718" y1="250" x2="825" y2="250" stroke="#8fa3c9" stroke-width="4" marker-end="url(#arrow)"/>
|
|
29
|
+
<text x="770" y="229" text-anchor="middle" fill="#aab9d4" font-family="Arial, sans-serif" font-size="14">structured result</text>
|
|
30
|
+
|
|
31
|
+
<rect x="838" y="165" width="80" height="170" rx="16" fill="url(#panel)" stroke="#405273"/>
|
|
32
|
+
<text x="878" y="215" text-anchor="middle" fill="#fff" font-family="Arial, sans-serif" font-size="16" font-weight="700">Host</text>
|
|
33
|
+
<text x="878" y="249" text-anchor="middle" fill="#7fe1c3" font-family="Arial, sans-serif" font-size="14">allow</text>
|
|
34
|
+
<text x="878" y="275" text-anchor="middle" fill="#ffadad" font-family="Arial, sans-serif" font-size="14">deny</text>
|
|
35
|
+
<text x="878" y="301" text-anchor="middle" fill="#ffd28a" font-family="Arial, sans-serif" font-size="14">error</text>
|
|
36
|
+
</svg>
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @letterblack/lbe-sdk v1.3.3
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { execute } from './index.js';
|
|
6
|
+
|
|
7
|
+
const cmd = process.argv[2];
|
|
8
|
+
const cwd = process.cwd();
|
|
9
|
+
const policyFile = path.join(cwd, 'lbe.policy.json');
|
|
10
|
+
const lbeDir = path.join(cwd, '.lbe');
|
|
11
|
+
|
|
12
|
+
function readPolicy() {
|
|
13
|
+
if (!fs.existsSync(policyFile)) return null;
|
|
14
|
+
return JSON.parse(fs.readFileSync(policyFile, 'utf8'));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function writePolicy(p) {
|
|
18
|
+
fs.writeFileSync(policyFile, JSON.stringify(p, null, 2) + '\n', 'utf8');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function ensurePolicy() {
|
|
22
|
+
if (fs.existsSync(policyFile)) return readPolicy();
|
|
23
|
+
const p = { version: 1, mode: 'observe', workspace: cwd, rules: [] };
|
|
24
|
+
writePolicy(p);
|
|
25
|
+
return p;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ── lbe init ──────────────────────────────────────────────────────────────
|
|
29
|
+
if (cmd === 'init') {
|
|
30
|
+
fs.mkdirSync(lbeDir, { recursive: true });
|
|
31
|
+
const policy = ensurePolicy();
|
|
32
|
+
const isNew = policy.rules.length === 0 && policy.mode === 'observe';
|
|
33
|
+
|
|
34
|
+
process.stdout.write('\n LBE initialised.\n\n');
|
|
35
|
+
process.stdout.write(' mode: ' + policy.mode + '\n');
|
|
36
|
+
process.stdout.write(' policy: lbe.policy.json\n');
|
|
37
|
+
process.stdout.write(' audit log: .lbe/audit.jsonl\n\n');
|
|
38
|
+
if (isNew) {
|
|
39
|
+
process.stdout.write(' Observer mode is on — LBE is watching but not blocking.\n');
|
|
40
|
+
process.stdout.write(' Run \'npx lbe enforce\' when you are ready to block actions.\n\n');
|
|
41
|
+
}
|
|
42
|
+
process.exit(0);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ── lbe observe ───────────────────────────────────────────────────────────
|
|
46
|
+
if (cmd === 'observe') {
|
|
47
|
+
const policy = ensurePolicy();
|
|
48
|
+
policy.mode = 'observe';
|
|
49
|
+
writePolicy(policy);
|
|
50
|
+
process.stdout.write('Observer mode on — LBE is watching silently. Nothing is blocked.\n');
|
|
51
|
+
process.exit(0);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ── lbe enforce ───────────────────────────────────────────────────────────
|
|
55
|
+
if (cmd === 'enforce') {
|
|
56
|
+
const policy = ensurePolicy();
|
|
57
|
+
policy.mode = 'enforce';
|
|
58
|
+
writePolicy(policy);
|
|
59
|
+
process.stdout.write('Enforcement on — LBE will now block actions that violate policy.\n');
|
|
60
|
+
process.exit(0);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ── lbe policy ────────────────────────────────────────────────────────────
|
|
64
|
+
if (cmd === 'policy') {
|
|
65
|
+
const policy = readPolicy();
|
|
66
|
+
if (!policy) {
|
|
67
|
+
process.stdout.write('No policy yet. Run \'npx lbe init\' first.\n');
|
|
68
|
+
process.exit(0);
|
|
69
|
+
}
|
|
70
|
+
process.stdout.write('\n mode: ' + policy.mode + '\n');
|
|
71
|
+
process.stdout.write(' rules (' + policy.rules.length + '):\n\n');
|
|
72
|
+
if (policy.rules.length === 0) {
|
|
73
|
+
process.stdout.write(' No rules yet. LBE learns from your conversation.\n');
|
|
74
|
+
}
|
|
75
|
+
for (const r of policy.rules) {
|
|
76
|
+
const label = r.effect === 'deny' ? ' block' : ' allow';
|
|
77
|
+
process.stdout.write(label + ' ' + r.pattern + '\n');
|
|
78
|
+
process.stdout.write(' from: ' + r.from + '\n\n');
|
|
79
|
+
}
|
|
80
|
+
process.exit(0);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ── lbe status ────────────────────────────────────────────────────────────
|
|
84
|
+
if (cmd === 'status') {
|
|
85
|
+
const policy = readPolicy();
|
|
86
|
+
process.stdout.write('runtime: ok\n');
|
|
87
|
+
process.stdout.write('mode: ' + (policy?.mode ?? 'not initialised') + '\n');
|
|
88
|
+
process.stdout.write('rules: ' + (policy?.rules?.length ?? 0) + '\n');
|
|
89
|
+
const auditLog = path.join(lbeDir, 'audit.jsonl');
|
|
90
|
+
if (fs.existsSync(auditLog)) {
|
|
91
|
+
const lines = fs.readFileSync(auditLog, 'utf8').trim().split('\n').filter(Boolean);
|
|
92
|
+
process.stdout.write('audit: ' + lines.length + ' entries\n');
|
|
93
|
+
} else {
|
|
94
|
+
process.stdout.write('audit: no entries yet\n');
|
|
95
|
+
}
|
|
96
|
+
process.exit(0);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ── lbe execute ───────────────────────────────────────────────────────────
|
|
100
|
+
if (cmd === 'execute') {
|
|
101
|
+
async function readStdin() {
|
|
102
|
+
const chunks = [];
|
|
103
|
+
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
104
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
105
|
+
}
|
|
106
|
+
let input = '';
|
|
107
|
+
const inputFlag = process.argv.indexOf('--input');
|
|
108
|
+
if (inputFlag >= 0) {
|
|
109
|
+
const file = process.argv[inputFlag + 1];
|
|
110
|
+
if (!file) { process.stderr.write('--input requires a file path\n'); process.exit(2); }
|
|
111
|
+
input = fs.readFileSync(file, 'utf8');
|
|
112
|
+
} else {
|
|
113
|
+
input = await readStdin();
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
const output = execute(input);
|
|
117
|
+
process.stdout.write(output + '\n');
|
|
118
|
+
const parsed = JSON.parse(output);
|
|
119
|
+
if (parsed?.result?.type === 'allowed') process.exit(0);
|
|
120
|
+
if (parsed?.result?.type === 'denied') process.exit(1);
|
|
121
|
+
process.exit(2);
|
|
122
|
+
} catch (err) {
|
|
123
|
+
process.stderr.write(String(err?.message || err) + '\n');
|
|
124
|
+
process.exit(2);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ── usage ─────────────────────────────────────────────────────────────────
|
|
129
|
+
if (!cmd) {
|
|
130
|
+
process.stdout.write('\nUsage:\n');
|
|
131
|
+
process.stdout.write(' npx lbe init Set up LBE in this project\n');
|
|
132
|
+
process.stdout.write(' npx lbe status Show current mode and rule count\n');
|
|
133
|
+
process.stdout.write(' npx lbe policy List all rules\n');
|
|
134
|
+
process.stdout.write(' npx lbe observe Switch to observer mode (watch, never block)\n');
|
|
135
|
+
process.stdout.write(' npx lbe enforce Switch to enforcement mode (block violations)\n');
|
|
136
|
+
process.stdout.write(' npx lbe execute Run a raw JSON request (advanced)\n\n');
|
|
137
|
+
process.exit(0);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
process.stderr.write('Unknown command: ' + cmd + '\nRun \'npx lbe\' for usage.\n');
|
|
141
|
+
process.exit(2);
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// @letterblack/lbe-sdk v1.3.3
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import crypto from 'node:crypto';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
|
|
7
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const wasmPath = path.join(here, 'lbe_engine.wasm');
|
|
9
|
+
const lockPath = path.join(here, 'wasm.lock.json');
|
|
10
|
+
let instance;
|
|
11
|
+
|
|
12
|
+
function hashFile(file) {
|
|
13
|
+
return crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function load() {
|
|
17
|
+
if (instance) return instance;
|
|
18
|
+
const lock = JSON.parse(fs.readFileSync(lockPath, 'utf8'));
|
|
19
|
+
const actual = hashFile(wasmPath);
|
|
20
|
+
if (actual !== lock.wasm_sha256) throw new Error('LBE WASM integrity check failed');
|
|
21
|
+
const wasm = new WebAssembly.Instance(new WebAssembly.Module(fs.readFileSync(wasmPath)), {});
|
|
22
|
+
if (typeof wasm.exports.lbe_execute !== 'function') throw new Error('LBE WASM missing execute entrypoint');
|
|
23
|
+
instance = wasm;
|
|
24
|
+
return instance;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function memory(wasm) {
|
|
28
|
+
return new Uint8Array(wasm.exports.memory.buffer);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function readOut(wasm) {
|
|
32
|
+
const mem = memory(wasm);
|
|
33
|
+
const ptr = wasm.exports.lbe_out_ptr();
|
|
34
|
+
const max = wasm.exports.lbe_buf_size();
|
|
35
|
+
let end = ptr;
|
|
36
|
+
while (mem[end] !== 0 && end - ptr < max) end++;
|
|
37
|
+
return new TextDecoder().decode(mem.slice(ptr, end));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function execute(input) {
|
|
41
|
+
if (typeof input !== 'string') throw new TypeError('execute input must be a string');
|
|
42
|
+
const wasm = load();
|
|
43
|
+
const bytes = new TextEncoder().encode(input);
|
|
44
|
+
const max = wasm.exports.lbe_buf_size();
|
|
45
|
+
if (bytes.length + 1 > max) throw new Error('execute input exceeds WASM buffer');
|
|
46
|
+
const mem = memory(wasm);
|
|
47
|
+
const ptr = wasm.exports.lbe_in_ptr();
|
|
48
|
+
mem.set(bytes, ptr);
|
|
49
|
+
mem[ptr + bytes.length] = 0;
|
|
50
|
+
wasm.exports.lbe_execute();
|
|
51
|
+
return readOut(wasm);
|
|
52
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
{
|
|
2
|
-
"wasm_sha256": "feb93a2ea76a02584048a588305ba0a192683fd58c1da8f539aeb49b41d0a254",
|
|
3
|
-
"entrypoint": "lbe_execute"
|
|
4
|
-
|
|
1
|
+
{
|
|
2
|
+
"wasm_sha256": "feb93a2ea76a02584048a588305ba0a192683fd58c1da8f539aeb49b41d0a254",
|
|
3
|
+
"entrypoint": "lbe_execute",
|
|
4
|
+
"contract": "execute(input:string)->string"
|
|
5
|
+
}
|
package/package.json
CHANGED
|
@@ -1,52 +1,31 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "@letterblack/lbe-core",
|
|
3
|
-
"version": "1.3.
|
|
4
|
-
"description": "Local-first execution governance SDK for AI agents.
|
|
2
|
+
"name": "@letterblack/lbe-core",
|
|
3
|
+
"version": "1.3.4",
|
|
4
|
+
"description": "Local-first execution governance SDK for AI agents.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "index.js",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
7
|
"types": "types.d.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": {
|
|
10
|
-
"types": "./types.d.ts",
|
|
11
|
-
"default": "./index.js"
|
|
12
|
-
},
|
|
13
|
-
"./
|
|
14
|
-
|
|
15
|
-
"./exec": "./exec/index.js",
|
|
16
|
-
"./hooks/register.cjs": "./dist/hooks/register.cjs"
|
|
17
|
-
},
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./types.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./cli": "./dist/cli.js"
|
|
14
|
+
},
|
|
18
15
|
"bin": {
|
|
19
|
-
"lbe": "
|
|
16
|
+
"lbe": "dist/cli.js"
|
|
20
17
|
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist/",
|
|
20
|
+
"assets/",
|
|
21
|
+
"types.d.ts",
|
|
22
|
+
"README.md",
|
|
23
|
+
"LICENSE"
|
|
24
|
+
],
|
|
21
25
|
"scripts": {
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
"verify": "node bin/lbe.js verify",
|
|
26
|
-
"dryrun": "node bin/lbe.js dryrun",
|
|
27
|
-
"run": "node bin/lbe.js run",
|
|
28
|
-
"policy:sign": "node bin/lbe.js policy-sign",
|
|
29
|
-
"health": "node bin/lbe.js health --json true",
|
|
30
|
-
"integrity:generate": "node bin/lbe.js integrity-generate",
|
|
31
|
-
"integrity:check": "node bin/lbe.js integrity-check",
|
|
32
|
-
"build:engine": "node scripts/build-engine.js",
|
|
33
|
-
"build:public-sdk": "node scripts/build-public-sdk.mjs",
|
|
34
|
-
"build:public-exec": "node scripts/build-public-exec.mjs",
|
|
35
|
-
"build:package-runtime": "node scripts/build-package-runtime.mjs",
|
|
36
|
-
"proof": "node _proof.mjs",
|
|
37
|
-
"audit:public-docs": "node scripts/audit-public-docs.mjs",
|
|
38
|
-
"verify:package-runtime": "node scripts/verify-package-runtime.mjs",
|
|
39
|
-
"verify:public-exec": "npm run proof && npm run build:public-exec && node scripts/check-public-exec.mjs && cd release-exec && npm pack --dry-run",
|
|
40
|
-
"verify:public-sdk": "npm run build:public-sdk && node scripts/check-public-artifact.mjs && cd release-public && npm pack --dry-run",
|
|
41
|
-
"engine:check": "node scripts/check-engine.js",
|
|
42
|
-
"pack:check": "npm pack --dry-run",
|
|
43
|
-
"audit:verify": "node bin/lbe.js audit-verify",
|
|
44
|
-
"guard:mainhead": "node scripts/mainhead-guard.mjs",
|
|
45
|
-
"hooks:install": "node scripts/install-git-hooks.mjs",
|
|
46
|
-
"prepack": "npm run build:package-runtime",
|
|
47
|
-
"validate:all": "npm run guard:mainhead && npm run engine:check && npm run lint && npm run test",
|
|
48
|
-
"publish:release": "node scripts/publish.mjs"
|
|
49
|
-
},
|
|
26
|
+
"pack": "npm pack",
|
|
27
|
+
"pack:check": "npm pack --dry-run"
|
|
28
|
+
},
|
|
50
29
|
"keywords": [
|
|
51
30
|
"ai-governance",
|
|
52
31
|
"execution-governance",
|
|
@@ -59,18 +38,8 @@
|
|
|
59
38
|
],
|
|
60
39
|
"author": "LetterBlack",
|
|
61
40
|
"license": "SEE LICENSE IN LICENSE",
|
|
62
|
-
"dependencies": {
|
|
63
|
-
"tweetnacl": "^1.0.3",
|
|
64
|
-
"json-canonicalize": "^1.0.4"
|
|
65
|
-
},
|
|
66
|
-
"devDependencies": {
|
|
67
|
-
"esbuild": "^0.25.11",
|
|
68
|
-
"eslint": "^8.52.0"
|
|
69
|
-
},
|
|
41
|
+
"dependencies": {},
|
|
70
42
|
"engines": {
|
|
71
43
|
"node": ">=20.9.0"
|
|
72
|
-
},
|
|
73
|
-
"directories": {
|
|
74
|
-
"doc": "docs"
|
|
75
44
|
}
|
|
76
45
|
}
|
package/types.d.ts
CHANGED
|
@@ -1,175 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
role: 'user' | 'system' | 'agent';
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export interface LBEIntent {
|
|
7
|
-
type: 'command' | 'query' | 'task';
|
|
8
|
-
name: string;
|
|
9
|
-
payload: Record<string, unknown>;
|
|
10
|
-
}
|
|
11
|
-
|
|
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
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
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
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function execute(input: string): string;
|
|
57
|
-
|
|
58
|
-
export type LBEExecutionIntent = 'read_file' | 'write_file' | 'patch_file' | 'delete_file' | 'run_shell';
|
|
59
|
-
|
|
60
|
-
export interface LBERequest {
|
|
61
|
-
id?: string;
|
|
62
|
-
actor?: string;
|
|
63
|
-
intent: LBEExecutionIntent;
|
|
64
|
-
target?: string;
|
|
65
|
-
content?: string;
|
|
66
|
-
patch?: unknown;
|
|
67
|
-
command?: { cmd: string; args: string[]; cwd?: string; timeoutMs?: number; maxOutputBytes?: number };
|
|
68
|
-
reason?: string;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export interface LBEResult {
|
|
72
|
-
ok: boolean;
|
|
73
|
-
decision: 'allow' | 'deny' | 'observe';
|
|
74
|
-
executed: boolean;
|
|
75
|
-
dryRun: boolean;
|
|
76
|
-
error?: { code: string; message: string; recoverable: boolean };
|
|
77
|
-
matchedRules?: string[];
|
|
78
|
-
auditId?: string;
|
|
79
|
-
rollback?: { available: boolean; performed: boolean; backupId?: string };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// ── Policy file types ─────────────────────────────────────────────────────
|
|
83
|
-
|
|
84
|
-
export type LBEMode = 'observe' | 'enforce';
|
|
85
|
-
export type LBERuleEffect = 'deny' | 'allow';
|
|
86
|
-
export type LBERuleType = 'path' | 'command';
|
|
87
|
-
|
|
88
|
-
export interface LBEPolicyRule {
|
|
89
|
-
id: string;
|
|
90
|
-
effect: LBERuleEffect;
|
|
91
|
-
type: LBERuleType;
|
|
92
|
-
pattern: string;
|
|
93
|
-
from: string;
|
|
94
|
-
at: string;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export interface LBEPolicy {
|
|
98
|
-
version: number;
|
|
99
|
-
mode: LBEMode;
|
|
100
|
-
workspace: string;
|
|
101
|
-
rules: LBEPolicyRule[];
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// ── High-level ergonomic API ──────────────────────────────────────────────
|
|
105
|
-
|
|
106
|
-
export interface LBEResult {
|
|
107
|
-
ok: boolean;
|
|
108
|
-
denied: boolean;
|
|
109
|
-
reason: string | null;
|
|
110
|
-
commandId: string | null;
|
|
111
|
-
stage?: string;
|
|
112
|
-
risk?: string | null;
|
|
113
|
-
output?: unknown;
|
|
114
|
-
error: string | null;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export interface LBEObservedResult {
|
|
118
|
-
ok: true;
|
|
119
|
-
observed: true;
|
|
120
|
-
intent: string;
|
|
121
|
-
actor: string;
|
|
122
|
-
commandId: string | null;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export interface LBEToolDef {
|
|
126
|
-
name: string;
|
|
127
|
-
description?: string;
|
|
128
|
-
parameters?: Record<string, unknown>;
|
|
129
|
-
[key: string]: unknown;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export interface LBEDispatchContext {
|
|
133
|
-
agentId?: string;
|
|
134
|
-
actor?: string;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export interface LBEWrappedTools {
|
|
138
|
-
definitions: LBEToolDef[];
|
|
139
|
-
dispatch(
|
|
140
|
-
toolName: string,
|
|
141
|
-
args?: Record<string, unknown>,
|
|
142
|
-
context?: LBEDispatchContext,
|
|
143
|
-
): Promise<LBEResult | LBEObservedResult>;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export interface LBEAddedRule {
|
|
147
|
-
id: string;
|
|
148
|
-
added: true;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export interface LBEInstance {
|
|
152
|
-
mode: LBEMode;
|
|
153
|
-
rootDir: string;
|
|
154
|
-
execute(opts: { actor?: string; intent: string; [key: string]: unknown }): Promise<LBEResult | LBEObservedResult>;
|
|
155
|
-
wrapTools(toolDefs: LBEToolDef[]): LBEWrappedTools;
|
|
156
|
-
/** Advisory only; never writes lbe.policy.json. */
|
|
157
|
-
proposePolicyRule(rule: { effect: LBERuleEffect; type: LBERuleType; pattern: string; from: string }): { proposed: true; at: string };
|
|
158
|
-
/**
|
|
159
|
-
* Detect if a user message expresses a permanent block instruction.
|
|
160
|
-
* Returns a rule object to pass to addRule(), or null if not a policy intent.
|
|
161
|
-
* llmCall receives a ready-made prompt and must return the LLM's text response.
|
|
162
|
-
*/
|
|
163
|
-
detectPolicyIntent(
|
|
164
|
-
userMessage: string,
|
|
165
|
-
llmCall: (prompt: string) => Promise<string>,
|
|
166
|
-
): Promise<{ effect: LBERuleEffect; type: LBERuleType; pattern: string } | null>;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
export interface LBEOptions {
|
|
170
|
-
rootDir?: string;
|
|
171
|
-
actor?: string;
|
|
172
|
-
mode?: LBEMode;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
export function createLBE(opts?: LBEOptions): LBEInstance;
|
|
1
|
+
// @letterblack/lbe-sdk v1.3.3
|
|
2
|
+
export function execute(input: string): string;
|
package/.githooks/pre-commit
DELETED
package/.githooks/pre-push
DELETED
package/CHANGELOG.md
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## 1.3.3 — 2026-06-23
|
|
4
|
-
|
|
5
|
-
### Fixed
|
|
6
|
-
- Rebuilt the docs-aligned release from a committed tree so the npm artifact
|
|
7
|
-
gitHead matches the release commit.
|
|
8
|
-
|
|
9
|
-
## 1.3.2 — 2026-06-23
|
|
10
|
-
|
|
11
|
-
### Fixed
|
|
12
|
-
- Aligned the public README surfaces and release docs with the shipped
|
|
13
|
-
`@letterblack/lbe-core` package and current CLI commands.
|
|
14
|
-
|
|
15
|
-
## 1.3.1 — 2026-06-23
|
|
16
|
-
|
|
17
|
-
### Fixed
|
|
18
|
-
- Re-aligned the release branch and published package lineage after the 1.3.0
|
|
19
|
-
tag/artifact mismatch was detected.
|
|
20
|
-
|
|
21
|
-
## 1.3.0 — 2026-06-23
|
|
22
|
-
|
|
23
|
-
### Added
|
|
24
|
-
- Central local workspace state, proof summaries, and one-time import of legacy
|
|
25
|
-
`.lbe/events.jsonl` entries while preserving the original local log.
|
|
26
|
-
|
|
27
|
-
## 1.2.0 — 2026-06-20
|
|
28
|
-
|
|
29
|
-
### Added
|
|
30
|
-
- **Real JS governance engine** — `createLBE()` now uses the full 7-gate validation pipeline (schema → key lifecycle → timestamp skew → rate limit → nonce replay → policy) with backup, rollback, and audit. Previously backed by a thin WASM wrapper.
|
|
31
|
-
- **Observer mode** — `createLBE({ mode: 'observe' })` or `npx lbe observe`. All gates run silently, audit log is written, nothing is blocked. Default for new and half-built projects.
|
|
32
|
-
- **Policy file** (`lbe.policy.json`) — human-readable rule store per project. Records `effect`, `type`, `pattern`, the original user message (`from`), and timestamp (`at`). Deny always wins over allow.
|
|
33
|
-
- **New CLI commands:**
|
|
34
|
-
- `npx lbe observe` — switch to observer mode
|
|
35
|
-
- `npx lbe enforce` — switch to enforcement mode
|
|
36
|
-
- `npx lbe policy` — list all rules with source context
|
|
37
|
-
- **Universal CLI interface** — non-JS projects (Python, Rust, Go, any language) can pipe JSON to `npx lbe execute`. Exit 0 = allowed, exit 1 = denied, exit 2 = error.
|
|
38
|
-
- **Language-agnostic design** — WASM runtime path documented as the path to non-JS bindings. JS engine is the current production runtime.
|
|
39
|
-
|
|
40
|
-
### Changed
|
|
41
|
-
- `LBEResult` now includes `commandId`, `stage`, `risk`, `output` fields.
|
|
42
|
-
- `LBEOptions` removes `policy_mode` / `timeout_ms` — these are managed by the governance engine internally.
|
|
43
|
-
- `wrapTools().dispatch()` now returns `Promise<LBEResult>` (async) to match the real engine contract.
|
|
44
|
-
- Types updated throughout to reflect observer mode result shape (`LBEObservedResult`).
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
## 1.0.4 — 2026-06-19
|
|
49
|
-
|
|
50
|
-
### Removed
|
|
51
|
-
- MCP execution surface — `lbe-mcp` command, MCP adapter, and configuration examples removed.
|
|
52
|
-
An MCP server only offers LBE as one optional tool; agent hosts with native tools can act outside that boundary, so it cannot enforce the governance boundary. See `docs/decisions/ADR-001-remove-mcp-execution-surface.md`.
|
|
53
|
-
- HTTP server surface — `lbe-serve` command and HTTP adapter removed.
|
|
54
|
-
An HTTP endpoint replicates governance in a separate process and creates a second attack surface without guaranteeing the calling agent routes through it. See `docs/decisions/ADR-002-remove-http-server-surface.md`.
|
|
55
|
-
|
|
56
|
-
### Changed
|
|
57
|
-
- Established SDK-only product boundary: LBE ships as one local SDK and CLI embedded in the caller's application. No daemon, host platform, Docker deployment, or companion system. See `docs/decisions/ADR-003-sdk-only-product-boundary.md`.
|
|
58
|
-
- Workspace pruned to SDK-only source; all optional execution surfaces removed from `src/`, `bin/`, and CI config.
|
|
59
|
-
- Public package identity (`LBE_PUBLIC_PACKAGE_NAME`, `LBE_PUBLIC_PACKAGE_VERSION`) is now parameterised via environment variables in the build script.
|
|
60
|
-
- Test command made portable across Node.js versions (no `--experimental-vm-modules` flag needed).
|
|
61
|
-
|
|
62
|
-
### Public surface
|
|
63
|
-
The public package (`@letterblack/lbe-sdk`) exports exactly one function:
|
|
64
|
-
|
|
65
|
-
```ts
|
|
66
|
-
export function execute(input: string): string;
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
No server, daemon, MCP surface, or optional execution layer ships in the public package.
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
73
|
-
## 1.0.3 and earlier
|
|
74
|
-
|
|
75
|
-
Pre-release development. No public changelog maintained.
|