brain0 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # brain0 — the black box for AI-written code
2
+
3
+ `git` tells you *what* changed. **brain0** tells you *why* — which prompt wrote it, what the
4
+ agent **read** to write it, and whether you can trust it.
5
+
6
+ ```bash
7
+ npx brain0 up
8
+ ```
9
+
10
+ One command, any repo: brain0 passively indexes your git history (the **facts**) and your
11
+ coding-agent sessions (the **intents** — Codex and Claude Code auto-discovered), then opens
12
+ an explorable decision graph at `http://localhost:8787`. Clicking a commit reveals the
13
+ prompts behind it, per-file diffs, what the agents read, and risk at a glance.
14
+
15
+ - **Drift** — the agent said "I only touched the parser". brain0 fact-checks it against git.
16
+ - **DLP reads** — which files (and which *secrets*) reached the model's context.
17
+ - **Risk that learns** — evidence-driven scoring; "looked safe, proved dangerous" gets flagged.
18
+ - **MCP why-layer** — `claude mcp add brain0 -- brain0 mcp` gives your agent long-term memory
19
+ of why the code is the way it is.
20
+ - **Offline by default** — no hooks, no signup, no telemetry, zero egress without keys.
21
+
22
+ Daily loop:
23
+
24
+ ```bash
25
+ brain0 today # morning triage: what agents did, riskiest first
26
+ brain0 report # the accountability report (add --md to share it)
27
+ brain0 rewind # the agent wrecked your tree? restore any checkpoint
28
+ ```
29
+
30
+ Requirements: Node ≥ 20. Local models via [Ollama](https://ollama.com) are optional and
31
+ make summaries/search better — never required.
32
+
33
+ Full documentation, GUI guide, configuration and troubleshooting:
34
+ **https://github.com/Brain0-ai/brain0**
35
+
36
+ Apache-2.0 · © The brain0 Authors
package/bin/brain0.js ADDED
@@ -0,0 +1,269 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * The `brain0` npm CLI. One product command plus passthrough:
4
+ *
5
+ * brain0 up [--path <dir>] [--repo <id>] [--port 8787] [--encrypt] [--all]
6
+ * [--no-ingest] [--no-observe] [--no-open]
7
+ * Index the repo (git facts + agent transcripts) and serve the GUI — one command,
8
+ * zero config: repo id is inferred from the git remote, data lives in <repo>/.brain0.
9
+ *
10
+ * brain0 <ingest|observe|query|mcp|verify|audit|reembed|purge|watch> …
11
+ * Forwarded verbatim to the Rust core binary.
12
+ *
13
+ * Resolution order (works from the monorepo during development and from the published
14
+ * package): BRAIN0_BIN → @brain0/cli-<platform>-<arch> package → monorepo target/{release,debug}.
15
+ */
16
+
17
+ import { execFileSync, spawn } from "node:child_process";
18
+ import { existsSync } from "node:fs";
19
+ import { basename, dirname, resolve } from "node:path";
20
+ import { fileURLToPath } from "node:url";
21
+ import { inferRepoId, parseArgs, REPO_RE } from "../src/lib.mjs";
22
+
23
+ const PKG_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "..");
24
+ // In the monorepo this is packages/cli → two levels up is the repo root.
25
+ const MONOREPO_ROOT = resolve(PKG_DIR, "../..");
26
+
27
+ // ── component resolution ────────────────────────────────────────────────────
28
+ function resolveRustBin() {
29
+ if (process.env.BRAIN0_BIN && existsSync(process.env.BRAIN0_BIN)) return process.env.BRAIN0_BIN;
30
+ const exe = process.platform === "win32" ? "brain0.exe" : "brain0";
31
+ // Published layout: platform package installed next to us (npm resolves optionalDependencies).
32
+ const platformPkg = `@brain0/cli-${process.platform}-${process.arch}`;
33
+ try {
34
+ const entry = import.meta.resolve(`${platformPkg}/package.json`);
35
+ const p = resolve(dirname(fileURLToPath(entry)), exe);
36
+ if (existsSync(p)) return p;
37
+ } catch {
38
+ /* not installed — fall through to the dev layout */
39
+ }
40
+ for (const rel of [`target/release/${exe}`, `target/debug/${exe}`]) {
41
+ const p = resolve(MONOREPO_ROOT, rel);
42
+ if (existsSync(p)) return p;
43
+ }
44
+ return undefined;
45
+ }
46
+
47
+ function resolveServerEntry() {
48
+ for (const p of [
49
+ resolve(PKG_DIR, "vendor/server/server.js"), // published: bundled at release time
50
+ resolve(MONOREPO_ROOT, "packages/server/dist/server.js"), // monorepo dev
51
+ ]) {
52
+ if (existsSync(p)) return p;
53
+ }
54
+ return undefined;
55
+ }
56
+
57
+ function resolveGuiDir() {
58
+ if (process.env.BRAIN0_GUI_DIR) return process.env.BRAIN0_GUI_DIR;
59
+ for (const p of [
60
+ resolve(PKG_DIR, "vendor/gui"), // published: bundled at release time
61
+ resolve(MONOREPO_ROOT, "packages/gui/build"), // monorepo dev
62
+ ]) {
63
+ if (existsSync(resolve(p, "index.html"))) return p;
64
+ }
65
+ return undefined;
66
+ }
67
+
68
+ // ── small process helpers (mirrors scripts/dev.mjs) ─────────────────────────
69
+ const COLORS = { ingest: 33, observe: 34, server: 35 };
70
+ const prefixer = (label) => {
71
+ const c = COLORS[label] ?? 37;
72
+ return (chunk) => {
73
+ for (const line of chunk.toString().split(/\r?\n/)) {
74
+ if (line.length) process.stdout.write(`\x1b[${c}m[${label}]\x1b[0m ${line}\n`);
75
+ }
76
+ };
77
+ };
78
+
79
+ const longLived = [];
80
+ let shuttingDown = false;
81
+ function shutdown(code = 0) {
82
+ if (shuttingDown) return;
83
+ shuttingDown = true;
84
+ for (const child of longLived) {
85
+ try {
86
+ process.kill(-child.pid, "SIGTERM");
87
+ } catch {
88
+ /* already gone */
89
+ }
90
+ }
91
+ process.exit(code);
92
+ }
93
+ for (const sig of ["SIGINT", "SIGTERM", "exit"]) process.on(sig, () => shutdown());
94
+
95
+ function run(label, cmd, args, cwd, env) {
96
+ return new Promise((res, rej) => {
97
+ const child = spawn(cmd, args, { cwd, env, stdio: ["ignore", "pipe", "pipe"] });
98
+ child.stdout.on("data", prefixer(label));
99
+ child.stderr.on("data", prefixer(label));
100
+ child.on("exit", (c) => (c === 0 ? res() : rej(new Error(`${label} exited with code ${c}`))));
101
+ child.on("error", rej);
102
+ });
103
+ }
104
+
105
+ function runLongLived(label, cmd, args, cwd, env) {
106
+ const child = spawn(cmd, args, { cwd, env, stdio: ["ignore", "pipe", "pipe"], detached: true });
107
+ child.stdout.on("data", prefixer(label));
108
+ child.stderr.on("data", prefixer(label));
109
+ child.on("exit", (c) => {
110
+ if (!shuttingDown) shutdown(c ?? 0);
111
+ });
112
+ longLived.push(child);
113
+ return child;
114
+ }
115
+
116
+ async function poll(url, timeoutMs = 30000) {
117
+ const deadline = Date.now() + timeoutMs;
118
+ while (Date.now() < deadline) {
119
+ try {
120
+ if ((await fetch(url)).ok) return;
121
+ } catch {
122
+ /* not up yet */
123
+ }
124
+ await new Promise((r) => setTimeout(r, 500));
125
+ }
126
+ throw new Error(`timed out waiting for ${url}`);
127
+ }
128
+
129
+ function openBrowser(url) {
130
+ const cmd =
131
+ process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
132
+ try {
133
+ spawn(cmd, [url], { stdio: "ignore", detached: true }).unref();
134
+ } catch {
135
+ /* headless is fine — the URL is printed */
136
+ }
137
+ }
138
+
139
+ // ── `up` ────────────────────────────────────────────────────────────────────
140
+ async function up(argv) {
141
+ const { flags, opts } = parseArgs(argv, ["path", "repo", "port"]);
142
+ const repoPath = resolve(opts.get("path") ?? ".");
143
+ if (!existsSync(repoPath)) {
144
+ console.error(`brain0 up: --path not found: ${repoPath}`);
145
+ process.exit(1);
146
+ }
147
+
148
+ let repo = opts.get("repo") ?? "";
149
+ if (!repo) {
150
+ let remote = "";
151
+ try {
152
+ remote = execFileSync("git", ["-C", repoPath, "remote", "get-url", "origin"], {
153
+ encoding: "utf8",
154
+ stdio: ["ignore", "pipe", "ignore"],
155
+ }).trim();
156
+ } catch {
157
+ /* no git remote — fall back to the directory name */
158
+ }
159
+ repo = inferRepoId(remote, basename(repoPath));
160
+ }
161
+ if (!REPO_RE.test(repo) || repo.startsWith("-")) {
162
+ console.error(`brain0 up: invalid repo id "${repo}" (allowed: letters digits . _ / -)`);
163
+ process.exit(1);
164
+ }
165
+
166
+ const bin = resolveRustBin();
167
+ if (!bin) {
168
+ console.error(
169
+ "brain0 up: core binary not found.\n" +
170
+ ` Expected @brain0/cli-${process.platform}-${process.arch} (npm) or target/release/brain0 (repo).\n` +
171
+ " From the repo: cargo build --release -p brain0-cli",
172
+ );
173
+ process.exit(1);
174
+ }
175
+ const serverEntry = resolveServerEntry();
176
+ if (!serverEntry) {
177
+ console.error(
178
+ "brain0 up: server not found — from the repo run: pnpm --filter @brain0/server build",
179
+ );
180
+ process.exit(1);
181
+ }
182
+ const guiDir = resolveGuiDir(); // optional: API still works without it
183
+
184
+ const port = Number(opts.get("port") ?? process.env.PORT ?? "8787");
185
+ const db = resolve(repoPath, ".brain0/index.db");
186
+ const payload = resolve(repoPath, ".brain0/payload");
187
+ // The GUI must read diffs/summaries, so `up` defaults to a plaintext payload (opt back into
188
+ // at-rest encryption with --encrypt; the GUI then shows an "encrypted" notice instead of text).
189
+ const encArgs = flags.has("encrypt") ? [] : ["--no-encrypt-payload"];
190
+ const common = ["--repo", repo, "--path", repoPath, "--db", db, "--payload", payload, ...encArgs];
191
+
192
+ const env = {
193
+ ...process.env,
194
+ BRAIN0_REPO: repo,
195
+ BRAIN0_DB: db,
196
+ BRAIN0_PAYLOAD: payload,
197
+ BRAIN0_REPO_PATH: repoPath,
198
+ BRAIN0_BIN: bin,
199
+ PORT: String(port),
200
+ ...(guiDir ? { BRAIN0_GUI_DIR: guiDir } : {}),
201
+ };
202
+
203
+ console.log(`brain0 up · repo=${repo} · path=${repoPath}`);
204
+ try {
205
+ if (!flags.has("no-ingest")) await run("ingest", bin, ["ingest", ...common], repoPath, env);
206
+ if (!flags.has("no-observe"))
207
+ await run(
208
+ "observe",
209
+ bin,
210
+ ["observe", ...common, ...(flags.has("all") ? ["--all"] : [])],
211
+ repoPath,
212
+ env,
213
+ );
214
+
215
+ runLongLived(
216
+ "server",
217
+ process.execPath,
218
+ ["--experimental-sqlite", serverEntry],
219
+ repoPath,
220
+ env,
221
+ );
222
+ await poll(`http://localhost:${port}/health`);
223
+
224
+ const url = `http://localhost:${port}/`;
225
+ console.log(
226
+ guiDir
227
+ ? `\n brain0 is up → ${url} (Ctrl-C to stop)\n`
228
+ : `\n brain0 API is up → ${url} (GUI build not bundled — set BRAIN0_GUI_DIR)\n`,
229
+ );
230
+ if (guiDir && !flags.has("no-open")) openBrowser(url);
231
+ } catch (err) {
232
+ console.error(`brain0 up: aborted — ${err.message}`);
233
+ shutdown(1);
234
+ }
235
+ }
236
+
237
+ // ── dispatcher ──────────────────────────────────────────────────────────────
238
+ const HELP = `brain0 — the black box for AI-written code
239
+
240
+ Usage:
241
+ brain0 up [--path <dir>] [--repo <id>] [--port 8787] [--encrypt] [--all]
242
+ [--no-ingest] [--no-observe] [--no-open]
243
+ brain0 <ingest|observe|query|mcp|verify|audit|reembed|purge|watch> [args…]
244
+
245
+ \`up\` indexes the repo (git facts + coding-agent transcripts) and serves the GUI at
246
+ http://localhost:8787. Everything else is forwarded to the brain0 core binary.`;
247
+
248
+ const [cmd, ...rest] = process.argv.slice(2);
249
+ if (!cmd || cmd === "--help" || cmd === "-h" || cmd === "help") {
250
+ console.log(HELP);
251
+ process.exit(0);
252
+ }
253
+ if (cmd === "up") {
254
+ await up(rest);
255
+ } else {
256
+ const bin = resolveRustBin();
257
+ if (!bin) {
258
+ console.error(
259
+ `brain0: core binary not found for "${cmd}" — install @brain0/cli-${process.platform}-${process.arch} or build target/release/brain0`,
260
+ );
261
+ process.exit(1);
262
+ }
263
+ const child = spawn(bin, [cmd, ...rest], { stdio: "inherit" });
264
+ child.on("exit", (code) => process.exit(code ?? 0));
265
+ child.on("error", (err) => {
266
+ console.error(`brain0: ${err.message}`);
267
+ process.exit(1);
268
+ });
269
+ }
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "brain0",
3
+ "version": "0.1.0",
4
+ "description": "brain0 — the black box for AI-written code: `npx brain0 up` on any repo",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "bin": {
8
+ "brain0": "./bin/brain0.js"
9
+ },
10
+ "files": [
11
+ "bin",
12
+ "src",
13
+ "vendor",
14
+ "README.md"
15
+ ],
16
+ "engines": {
17
+ "node": ">=20"
18
+ },
19
+ "scripts": {
20
+ "build": "node -e \"process.exit(0)\"",
21
+ "typecheck": "node --check bin/brain0.js && node --check src/lib.mjs",
22
+ "lint": "node --check bin/brain0.js && node --check src/lib.mjs",
23
+ "test": "node --test test/*.test.mjs"
24
+ },
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/Brain0-ai/brain0.git",
28
+ "directory": "packages/cli"
29
+ },
30
+ "homepage": "https://github.com/Brain0-ai/brain0#readme",
31
+ "bugs": "https://github.com/Brain0-ai/brain0/issues",
32
+ "keywords": [
33
+ "ai",
34
+ "provenance",
35
+ "coding-agents",
36
+ "audit",
37
+ "dlp",
38
+ "drift",
39
+ "git",
40
+ "claude-code",
41
+ "codex",
42
+ "mcp",
43
+ "attestation",
44
+ "code-review",
45
+ "observability"
46
+ ],
47
+ "optionalDependencies": {
48
+ "@brain0/cli-linux-x64": "0.1.0",
49
+ "@brain0/cli-linux-arm64": "0.1.0",
50
+ "@brain0/cli-darwin-x64": "0.1.0",
51
+ "@brain0/cli-darwin-arm64": "0.1.0"
52
+ }
53
+ }
package/src/lib.mjs ADDED
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Pure helpers for the `brain0` npm CLI (no I/O, unit-tested): repo-id inference from a git
3
+ * remote, argument parsing, and the shared repo-id validation mirrored from the server.
4
+ */
5
+
6
+ /** Legal repo id (mirrors the server's refresh validation — keep in sync). */
7
+ export const REPO_RE = /^[A-Za-z0-9._/-]+$/;
8
+
9
+ /** Replace illegal characters and strip leading dashes so the result always passes REPO_RE. */
10
+ export function sanitizeRepoId(raw) {
11
+ const cleaned = String(raw)
12
+ .replace(/[^A-Za-z0-9._/-]+/g, "-")
13
+ .replace(/^-+/, "");
14
+ return cleaned || "repo";
15
+ }
16
+
17
+ /**
18
+ * Infer a stable repo id from the git remote URL, falling back to the directory name.
19
+ * Handles the common shapes:
20
+ * git@github.com:owner/repo.git · ssh://git@host/owner/repo.git
21
+ * https://host/owner/repo(.git) · https://host/group/sub/repo (GitLab nesting)
22
+ */
23
+ export function inferRepoId(remoteUrl, dirName) {
24
+ const url = (remoteUrl ?? "").trim();
25
+ if (url) {
26
+ let path = "";
27
+ const scp = url.match(/^[\w.+-]+@[^:/]+:(.+)$/); // git@host:owner/repo.git
28
+ if (scp) {
29
+ path = scp[1];
30
+ } else {
31
+ try {
32
+ path = new URL(url).pathname; // ssh:// https:// git:// file://
33
+ } catch {
34
+ path = "";
35
+ }
36
+ }
37
+ path = path.replace(/^\/+/, "").replace(/\/+$/, "").replace(/\.git$/, "");
38
+ if (path) {
39
+ // Keep the last two segments (owner/repo) — enough identity without host noise.
40
+ const segs = path.split("/").filter(Boolean);
41
+ const id = segs.slice(-2).join("/");
42
+ if (id && REPO_RE.test(id) && !id.startsWith("-")) return id;
43
+ return sanitizeRepoId(id);
44
+ }
45
+ }
46
+ return sanitizeRepoId(dirName ?? "repo");
47
+ }
48
+
49
+ /**
50
+ * Minimal argv parser: `--flag` booleans, `--opt value` pairs, everything else positional.
51
+ * `optNames` decides which --names consume a value; unknown --names are flags.
52
+ */
53
+ export function parseArgs(argv, optNames) {
54
+ const takesValue = new Set(optNames);
55
+ const flags = new Set();
56
+ const opts = new Map();
57
+ const positional = [];
58
+ for (let i = 0; i < argv.length; i++) {
59
+ const a = argv[i];
60
+ if (a.startsWith("--")) {
61
+ const name = a.slice(2);
62
+ if (takesValue.has(name) && i + 1 < argv.length) {
63
+ opts.set(name, argv[++i]);
64
+ } else {
65
+ flags.add(name);
66
+ }
67
+ } else {
68
+ positional.push(a);
69
+ }
70
+ }
71
+ return { flags, opts, positional };
72
+ }
@@ -0,0 +1,186 @@
1
+ import{w as U,g,c,u as S,B as _,d as m,E as I,e as p}from"./index-QopGLZI_.js";const x={name:"local-uniform-bit",vertex:{header:`
2
+
3
+ struct LocalUniforms {
4
+ uTransformMatrix:mat3x3<f32>,
5
+ uColor:vec4<f32>,
6
+ uRound:f32,
7
+ }
8
+
9
+ @group(1) @binding(0) var<uniform> localUniforms : LocalUniforms;
10
+ `,main:`
11
+ vColor *= localUniforms.uColor;
12
+ modelMatrix *= localUniforms.uTransformMatrix;
13
+ `,end:`
14
+ if(localUniforms.uRound == 1)
15
+ {
16
+ vPosition = vec4(roundPixels(vPosition.xy, globalUniforms.uResolution), vPosition.zw);
17
+ }
18
+ `}},C={...x,vertex:{...x.vertex,header:x.vertex.header.replace("group(1)","group(2)")}},D={name:"local-uniform-bit",vertex:{header:`
19
+
20
+ uniform mat3 uTransformMatrix;
21
+ uniform vec4 uColor;
22
+ uniform float uRound;
23
+ `,main:`
24
+ vColor *= uColor;
25
+ modelMatrix = uTransformMatrix;
26
+ `,end:`
27
+ if(uRound == 1.)
28
+ {
29
+ gl_Position.xy = roundPixels(gl_Position.xy, uResolution);
30
+ }
31
+ `}},O={name:"texture-bit",vertex:{header:`
32
+
33
+ struct TextureUniforms {
34
+ uTextureMatrix:mat3x3<f32>,
35
+ }
36
+
37
+ @group(2) @binding(2) var<uniform> textureUniforms : TextureUniforms;
38
+ `,main:`
39
+ uv = (textureUniforms.uTextureMatrix * vec3(uv, 1.0)).xy;
40
+ `},fragment:{header:`
41
+ @group(2) @binding(0) var uTexture: texture_2d<f32>;
42
+ @group(2) @binding(1) var uSampler: sampler;
43
+
44
+
45
+ `,main:`
46
+ outColor = textureSample(uTexture, uSampler, vUV);
47
+ `}},R={name:"texture-bit",vertex:{header:`
48
+ uniform mat3 uTextureMatrix;
49
+ `,main:`
50
+ uv = (uTextureMatrix * vec3(uv, 1.0)).xy;
51
+ `},fragment:{header:`
52
+ uniform sampler2D uTexture;
53
+
54
+
55
+ `,main:`
56
+ outColor = texture(uTexture, vUV);
57
+ `}};function A(e,t){for(const a in e.attributes){const s=e.attributes[a],r=t[a];r?(s.format??(s.format=r.format),s.offset??(s.offset=r.offset),s.instance??(s.instance=r.instance)):U(`Attribute ${a} is not present in the shader, but is present in the geometry. Unable to infer attribute details.`)}M(e)}function M(e){const{buffers:t,attributes:a}=e,s={},r={};for(const n in t){const o=t[n];s[o.uid]=0,r[o.uid]=0}for(const n in a){const o=a[n];s[o.buffer.uid]+=g(o.format).stride}for(const n in a){const o=a[n];o.stride??(o.stride=s[o.buffer.uid]),o.start??(o.start=r[o.buffer.uid]),r[o.buffer.uid]+=g(o.format).stride}}const d=[];d[c.NONE]=void 0;d[c.DISABLED]={stencilWriteMask:0,stencilReadMask:0};d[c.RENDERING_MASK_ADD]={stencilFront:{compare:"equal",passOp:"increment-clamp"},stencilBack:{compare:"equal",passOp:"increment-clamp"}};d[c.RENDERING_MASK_REMOVE]={stencilFront:{compare:"equal",passOp:"decrement-clamp"},stencilBack:{compare:"equal",passOp:"decrement-clamp"}};d[c.MASK_ACTIVE]={stencilWriteMask:0,stencilFront:{compare:"equal",passOp:"keep"},stencilBack:{compare:"equal",passOp:"keep"}};d[c.INVERSE_MASK_ACTIVE]={stencilWriteMask:0,stencilFront:{compare:"not-equal",passOp:"keep"},stencilBack:{compare:"not-equal",passOp:"keep"}};class B{constructor(t){this._syncFunctionHash=Object.create(null),this._adaptor=t,this._systemCheck()}_systemCheck(){if(!S())throw new Error("Current environment does not allow unsafe-eval, please use pixi.js/unsafe-eval module to enable support.")}ensureUniformGroup(t){const a=this.getUniformGroupData(t);t.buffer||(t.buffer=new _({data:new Float32Array(a.layout.size/4),usage:m.UNIFORM|m.COPY_DST}))}getUniformGroupData(t){return this._syncFunctionHash[t._signature]||this._initUniformGroup(t)}_initUniformGroup(t){const a=t._signature;let s=this._syncFunctionHash[a];if(!s){const r=Object.keys(t.uniformStructures).map(l=>t.uniformStructures[l]),n=this._adaptor.createUboElements(r),o=this._generateUboSync(n.uboElements);s=this._syncFunctionHash[a]={layout:n,syncFunction:o}}return this._syncFunctionHash[a]}_generateUboSync(t){return this._adaptor.generateUboSync(t)}syncUniformGroup(t,a,s){const r=this.getUniformGroupData(t);t.buffer||(t.buffer=new _({data:new Float32Array(r.layout.size/4),usage:m.UNIFORM|m.COPY_DST}));let n=null;return a||(a=t.buffer.data,n=t.buffer.dataInt32),s||(s=0),r.syncFunction(t.uniforms,a,n,s),!0}updateUniformGroup(t){if(t.isStatic&&!t._dirtyId)return!1;t._dirtyId=0;const a=this.syncUniformGroup(t);return t.buffer.update(),a}destroy(){this._syncFunctionHash=null}}const h=[{type:"mat3x3<f32>",test:e=>e.value.a!==void 0,ubo:`
58
+ var matrix = uv[name].toArray(true);
59
+ data[offset] = matrix[0];
60
+ data[offset + 1] = matrix[1];
61
+ data[offset + 2] = matrix[2];
62
+ data[offset + 4] = matrix[3];
63
+ data[offset + 5] = matrix[4];
64
+ data[offset + 6] = matrix[5];
65
+ data[offset + 8] = matrix[6];
66
+ data[offset + 9] = matrix[7];
67
+ data[offset + 10] = matrix[8];
68
+ `,uniform:`
69
+ gl.uniformMatrix3fv(ud[name].location, false, uv[name].toArray(true));
70
+ `},{type:"vec4<f32>",test:e=>e.type==="vec4<f32>"&&e.size===1&&e.value.width!==void 0,ubo:`
71
+ v = uv[name];
72
+ data[offset] = v.x;
73
+ data[offset + 1] = v.y;
74
+ data[offset + 2] = v.width;
75
+ data[offset + 3] = v.height;
76
+ `,uniform:`
77
+ cv = ud[name].value;
78
+ v = uv[name];
79
+ if (cv[0] !== v.x || cv[1] !== v.y || cv[2] !== v.width || cv[3] !== v.height) {
80
+ cv[0] = v.x;
81
+ cv[1] = v.y;
82
+ cv[2] = v.width;
83
+ cv[3] = v.height;
84
+ gl.uniform4f(ud[name].location, v.x, v.y, v.width, v.height);
85
+ }
86
+ `},{type:"vec2<f32>",test:e=>e.type==="vec2<f32>"&&e.size===1&&e.value.x!==void 0,ubo:`
87
+ v = uv[name];
88
+ data[offset] = v.x;
89
+ data[offset + 1] = v.y;
90
+ `,uniform:`
91
+ cv = ud[name].value;
92
+ v = uv[name];
93
+ if (cv[0] !== v.x || cv[1] !== v.y) {
94
+ cv[0] = v.x;
95
+ cv[1] = v.y;
96
+ gl.uniform2f(ud[name].location, v.x, v.y);
97
+ }
98
+ `},{type:"vec4<f32>",test:e=>e.type==="vec4<f32>"&&e.size===1&&e.value.red!==void 0,ubo:`
99
+ v = uv[name];
100
+ data[offset] = v.red;
101
+ data[offset + 1] = v.green;
102
+ data[offset + 2] = v.blue;
103
+ data[offset + 3] = v.alpha;
104
+ `,uniform:`
105
+ cv = ud[name].value;
106
+ v = uv[name];
107
+ if (cv[0] !== v.red || cv[1] !== v.green || cv[2] !== v.blue || cv[3] !== v.alpha) {
108
+ cv[0] = v.red;
109
+ cv[1] = v.green;
110
+ cv[2] = v.blue;
111
+ cv[3] = v.alpha;
112
+ gl.uniform4f(ud[name].location, v.red, v.green, v.blue, v.alpha);
113
+ }
114
+ `},{type:"vec3<f32>",test:e=>e.type==="vec3<f32>"&&e.size===1&&e.value.red!==void 0,ubo:`
115
+ v = uv[name];
116
+ data[offset] = v.red;
117
+ data[offset + 1] = v.green;
118
+ data[offset + 2] = v.blue;
119
+ `,uniform:`
120
+ cv = ud[name].value;
121
+ v = uv[name];
122
+ if (cv[0] !== v.red || cv[1] !== v.green || cv[2] !== v.blue) {
123
+ cv[0] = v.red;
124
+ cv[1] = v.green;
125
+ cv[2] = v.blue;
126
+ gl.uniform3f(ud[name].location, v.red, v.green, v.blue);
127
+ }
128
+ `}];function k(e,t,a,s){const r=[`
129
+ var v = null;
130
+ var v2 = null;
131
+ var t = 0;
132
+ var index = 0;
133
+ var name = null;
134
+ var arrayOffset = null;
135
+ `];let n=0;for(let l=0;l<e.length;l++){const f=e[l],b=f.data.name;let y=!1,i=0;for(let u=0;u<h.length;u++)if(h[u].test(f.data)){i=f.offset/4,r.push(`name = "${b}";`,`offset += ${i-n};`,h[u][t]||h[u].ubo),y=!0;break}if(!y)if(f.data.size>1)i=f.offset/4,r.push(a(f,i-n));else{const u=s[f.data.type];i=f.offset/4,r.push(`
136
+ v = uv.${b};
137
+ offset += ${i-n};
138
+ ${u};
139
+ `)}n=i}const o=r.join(`
140
+ `);return new Function("uv","data","dataInt32","offset",o)}function v(e,t){return`
141
+ for (let i = 0; i < ${e*t}; i++) {
142
+ data[offset + (((i / ${e})|0) * 4) + (i % ${e})] = v[i];
143
+ }
144
+ `}const F={f32:`
145
+ data[offset] = v;`,i32:`
146
+ dataInt32[offset] = v;`,"vec2<f32>":`
147
+ data[offset] = v[0];
148
+ data[offset + 1] = v[1];`,"vec3<f32>":`
149
+ data[offset] = v[0];
150
+ data[offset + 1] = v[1];
151
+ data[offset + 2] = v[2];`,"vec4<f32>":`
152
+ data[offset] = v[0];
153
+ data[offset + 1] = v[1];
154
+ data[offset + 2] = v[2];
155
+ data[offset + 3] = v[3];`,"vec2<i32>":`
156
+ dataInt32[offset] = v[0];
157
+ dataInt32[offset + 1] = v[1];`,"vec3<i32>":`
158
+ dataInt32[offset] = v[0];
159
+ dataInt32[offset + 1] = v[1];
160
+ dataInt32[offset + 2] = v[2];`,"vec4<i32>":`
161
+ dataInt32[offset] = v[0];
162
+ dataInt32[offset + 1] = v[1];
163
+ dataInt32[offset + 2] = v[2];
164
+ dataInt32[offset + 3] = v[3];`,"mat2x2<f32>":`
165
+ data[offset] = v[0];
166
+ data[offset + 1] = v[1];
167
+ data[offset + 4] = v[2];
168
+ data[offset + 5] = v[3];`,"mat3x3<f32>":`
169
+ data[offset] = v[0];
170
+ data[offset + 1] = v[1];
171
+ data[offset + 2] = v[2];
172
+ data[offset + 4] = v[3];
173
+ data[offset + 5] = v[4];
174
+ data[offset + 6] = v[5];
175
+ data[offset + 8] = v[6];
176
+ data[offset + 9] = v[7];
177
+ data[offset + 10] = v[8];`,"mat4x4<f32>":`
178
+ for (let i = 0; i < 16; i++) {
179
+ data[offset + i] = v[i];
180
+ }`,"mat3x2<f32>":v(3,2),"mat4x2<f32>":v(4,2),"mat2x3<f32>":v(2,3),"mat4x3<f32>":v(4,3),"mat2x4<f32>":v(2,4),"mat3x4<f32>":v(3,4)},w={...F,"mat2x2<f32>":`
181
+ data[offset] = v[0];
182
+ data[offset + 1] = v[1];
183
+ data[offset + 2] = v[2];
184
+ data[offset + 3] = v[3];
185
+ `};class P extends I{constructor({buffer:t,offset:a,size:s}){super(),this.uid=p("buffer"),this._resourceType="bufferResource",this._touched=0,this._resourceId=p("resource"),this._bufferResource=!0,this.destroyed=!1,this.buffer=t,this.offset=a|0,this.size=s,this.buffer.on("change",this.onBufferChange,this)}onBufferChange(){this._resourceId=p("resource"),this.emit("change",this)}destroy(t=!1){this.destroyed=!0,t&&this.buffer.destroy(),this.emit("change",this),this.buffer=null,this.removeAllListeners()}}export{P as B,d as G,B as U,x as a,F as b,k as c,h as d,A as e,D as f,R as g,C as l,O as t,w as u};
186
+ //# sourceMappingURL=BufferResource-VGpCfGWQ.js.map