deepbom 0.1.0 → 1.94.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 +198 -12
- package/README.md +19 -103
- package/bin/deepbom.mjs +66 -0
- package/package.json +20 -14
- package/pkg/release-manifest.json +30 -0
- package/{vendor → pkg}/tflite_wasm_audit_bg.wasm +0 -0
- package/bin/deepbom.js +0 -188
- package/vendor/tflite_wasm_audit.js +0 -1222
- package/vendor/tflite_wasm_audit_bg.js +0 -333
package/package.json
CHANGED
|
@@ -1,33 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deepbom",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.94.4",
|
|
4
|
+
"description": "Local multi-format deployment-artifact analysis for on-device AI models",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"deepbom": "bin/deepbom.
|
|
7
|
+
"deepbom": "bin/deepbom.mjs"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"bin/",
|
|
11
|
-
"
|
|
11
|
+
"pkg/",
|
|
12
12
|
"README.md",
|
|
13
13
|
"LICENSE"
|
|
14
14
|
],
|
|
15
|
-
"license": "ISC",
|
|
16
15
|
"engines": {
|
|
17
16
|
"node": ">=20"
|
|
18
17
|
},
|
|
18
|
+
"license": "Apache-2.0",
|
|
19
|
+
"homepage": "https://deepbom.org",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/JunHwan-Kwon/deepbom.git"
|
|
23
|
+
},
|
|
24
|
+
"author": "Jun-Hwan Kwon",
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
},
|
|
19
28
|
"keywords": [
|
|
20
29
|
"tflite",
|
|
21
|
-
"litert",
|
|
22
30
|
"onnx",
|
|
31
|
+
"gguf",
|
|
32
|
+
"safetensors",
|
|
33
|
+
"coreml",
|
|
34
|
+
"tensorrt",
|
|
23
35
|
"quantization",
|
|
24
36
|
"on-device",
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
"ml-bom",
|
|
28
|
-
"cyclonedx",
|
|
29
|
-
"static-analysis"
|
|
30
|
-
],
|
|
31
|
-
"homepage": "https://deepbom.org",
|
|
32
|
-
"author": "Jun-Hwan Kwon"
|
|
37
|
+
"ml-bom"
|
|
38
|
+
]
|
|
33
39
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "deepbom.npm_release.v1",
|
|
3
|
+
"version": "1.94.4",
|
|
4
|
+
"source": {
|
|
5
|
+
"git_commit": "ec751d7a3eb34395f4df0efd1d3fe5a95d2cba4d",
|
|
6
|
+
"git_state": "clean",
|
|
7
|
+
"distribution": "public_channel"
|
|
8
|
+
},
|
|
9
|
+
"runtime": {
|
|
10
|
+
"node": ">=20",
|
|
11
|
+
"tflite_wasm_sha256": "502b847240063853bc473daa36b0d8c15ac3a4071c7ee0d64f2d743342a15bb8"
|
|
12
|
+
},
|
|
13
|
+
"license": {
|
|
14
|
+
"spdx": "Apache-2.0",
|
|
15
|
+
"file": "LICENSE"
|
|
16
|
+
},
|
|
17
|
+
"public_bundle_input_count": 97,
|
|
18
|
+
"supported_inputs": [
|
|
19
|
+
"tflite",
|
|
20
|
+
"onnx",
|
|
21
|
+
"onnx_external_data",
|
|
22
|
+
"gguf",
|
|
23
|
+
"safetensors",
|
|
24
|
+
"safetensors_sharded_repository",
|
|
25
|
+
"coreml_mlmodel",
|
|
26
|
+
"coreml_mlpackage",
|
|
27
|
+
"tensorrt_evidence",
|
|
28
|
+
"tensorrt_llm_contract"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
Binary file
|
package/bin/deepbom.js
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// deepbom — deployment-artifact analysis for on-device neural network models.
|
|
3
|
-
//
|
|
4
|
-
// Runs the browser analyzer's WebAssembly module locally. Model bytes never
|
|
5
|
-
// leave the machine; this command performs no network access.
|
|
6
|
-
|
|
7
|
-
import { readFile } from "node:fs/promises";
|
|
8
|
-
import { fileURLToPath } from "node:url";
|
|
9
|
-
import { dirname, join, basename } from "node:path";
|
|
10
|
-
import { createHash } from "node:crypto";
|
|
11
|
-
|
|
12
|
-
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
13
|
-
const ROOT = join(HERE, "..");
|
|
14
|
-
const pkg = JSON.parse(await readFile(join(ROOT, "package.json"), "utf8"));
|
|
15
|
-
|
|
16
|
-
const argv = process.argv.slice(2);
|
|
17
|
-
|
|
18
|
-
function parseArgs(list) {
|
|
19
|
-
const opts = { _: [] };
|
|
20
|
-
for (let i = 0; i < list.length; i += 1) {
|
|
21
|
-
const a = list[i];
|
|
22
|
-
if (a === "--json") opts.json = true;
|
|
23
|
-
else if (a === "--quiet" || a === "-q") opts.quiet = true;
|
|
24
|
-
else if (a === "--target" || a === "-t") opts.target = list[++i];
|
|
25
|
-
else if (a === "--help" || a === "-h") opts.help = true;
|
|
26
|
-
else if (a === "--version" || a === "-v") opts.version = true;
|
|
27
|
-
else if (a.startsWith("--target=")) opts.target = a.slice(9);
|
|
28
|
-
else if (a.startsWith("-")) { fail(`unknown option: ${a}`); }
|
|
29
|
-
else opts._.push(a);
|
|
30
|
-
}
|
|
31
|
-
return opts;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function fail(message, code = 2) {
|
|
35
|
-
process.stderr.write(`deepbom: ${message}\n`);
|
|
36
|
-
process.exit(code);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const USAGE = `deepbom ${pkg.version} — deployment-artifact analysis for on-device models
|
|
40
|
-
|
|
41
|
-
USAGE
|
|
42
|
-
deepbom audit <file> [--target <id>] [--json]
|
|
43
|
-
deepbom targets
|
|
44
|
-
deepbom --version
|
|
45
|
-
|
|
46
|
-
COMMANDS
|
|
47
|
-
audit Analyse a model artifact and print a summary
|
|
48
|
-
targets List available target profiles
|
|
49
|
-
|
|
50
|
-
OPTIONS
|
|
51
|
-
-t, --target <id> Target profile (default: android_mid_a55)
|
|
52
|
-
--json Emit the full analysis ledger as JSON
|
|
53
|
-
-q, --quiet Suppress the summary header
|
|
54
|
-
-h, --help Show this help
|
|
55
|
-
|
|
56
|
-
FORMATS
|
|
57
|
-
TFLite (.tflite) is supported in this release. ONNX, GGUF, SafeTensors and
|
|
58
|
-
Core ML are available in the browser version at https://deepbom.org
|
|
59
|
-
|
|
60
|
-
PRIVACY
|
|
61
|
-
Analysis runs locally. No model bytes, filenames or results are uploaded.
|
|
62
|
-
`;
|
|
63
|
-
|
|
64
|
-
async function loadEngine() {
|
|
65
|
-
const mod = await import(new URL("../vendor/tflite_wasm_audit.js", import.meta.url));
|
|
66
|
-
const wasm = await readFile(new URL("../vendor/tflite_wasm_audit_bg.wasm", import.meta.url));
|
|
67
|
-
mod.initSync({ module: wasm });
|
|
68
|
-
return mod;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const fmtInt = (n) => Number(n ?? 0).toLocaleString("en-US");
|
|
72
|
-
function fmtBytes(n) {
|
|
73
|
-
const v = Number(n ?? 0);
|
|
74
|
-
if (!Number.isFinite(v) || v <= 0) return "0 B";
|
|
75
|
-
const units = ["B", "KB", "MB", "GB"];
|
|
76
|
-
const i = Math.min(units.length - 1, Math.floor(Math.log(v) / Math.log(1024)));
|
|
77
|
-
return `${(v / 1024 ** i).toFixed(i === 0 ? 0 : 1)} ${units[i]}`;
|
|
78
|
-
}
|
|
79
|
-
const pct = (n, d) => (d > 0 ? `${((n / d) * 100).toFixed(0)}%` : "n/a");
|
|
80
|
-
|
|
81
|
-
async function cmdTargets() {
|
|
82
|
-
const engine = await loadEngine();
|
|
83
|
-
const profiles = engine.target_profiles() || [];
|
|
84
|
-
for (const p of profiles) {
|
|
85
|
-
const id = p?.id ?? p;
|
|
86
|
-
const label = p?.label ? ` — ${p.label}` : "";
|
|
87
|
-
process.stdout.write(`${id}${label}\n`);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
async function cmdAudit(opts) {
|
|
92
|
-
const file = opts._[0];
|
|
93
|
-
if (!file) fail("audit requires a file path\n\n" + USAGE);
|
|
94
|
-
|
|
95
|
-
let bytes;
|
|
96
|
-
try {
|
|
97
|
-
bytes = new Uint8Array(await readFile(file));
|
|
98
|
-
} catch (error) {
|
|
99
|
-
fail(`cannot read ${file}: ${error.code ?? error.message}`);
|
|
100
|
-
}
|
|
101
|
-
if (bytes.length === 0) fail(`${file} is empty`);
|
|
102
|
-
|
|
103
|
-
const engine = await loadEngine();
|
|
104
|
-
const target = opts.target || "android_mid_a55";
|
|
105
|
-
const known = (engine.target_profiles() || []).map((p) => p?.id ?? p);
|
|
106
|
-
if (known.length && !known.includes(target)) {
|
|
107
|
-
fail(`unknown target "${target}". Run: deepbom targets`);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
let analysis;
|
|
111
|
-
try {
|
|
112
|
-
analysis = engine.analyze_tflite_for_target(bytes, basename(file), target);
|
|
113
|
-
} catch (error) {
|
|
114
|
-
fail(`analysis failed: ${error?.message ?? error}\n` +
|
|
115
|
-
`This release supports TFLite FlatBuffer artifacts. ` +
|
|
116
|
-
`For ONNX, GGUF, SafeTensors and Core ML see https://deepbom.org`, 1);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (opts.json) {
|
|
120
|
-
process.stdout.write(`${JSON.stringify(analysis, null, 2)}\n`);
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const sha = analysis.model_sha256 || createHash("sha256").update(bytes).digest("hex");
|
|
125
|
-
const ops = Array.isArray(analysis.ops) ? analysis.ops : [];
|
|
126
|
-
const delegated = ops.filter((o) => o?.xnnpack_supported === true).length;
|
|
127
|
-
const findings = Array.isArray(analysis.findings) ? analysis.findings : [];
|
|
128
|
-
const out = [];
|
|
129
|
-
|
|
130
|
-
if (!opts.quiet) {
|
|
131
|
-
out.push(`${analysis.filename || basename(file)}`);
|
|
132
|
-
out.push(` sha256 ${sha}`);
|
|
133
|
-
out.push(` format ${analysis.format ?? "unknown"} size ${fmtBytes(analysis.file_size ?? bytes.length)}`);
|
|
134
|
-
out.push(` target ${target}`);
|
|
135
|
-
out.push("");
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
out.push("graph");
|
|
139
|
-
out.push(` operators ${fmtInt(analysis.operator_count)}`);
|
|
140
|
-
out.push(` tensors ${fmtInt(analysis.tensor_count)}`);
|
|
141
|
-
if (analysis.total_macs != null) out.push(` total MACs ${fmtInt(analysis.total_macs)}`);
|
|
142
|
-
out.push("");
|
|
143
|
-
|
|
144
|
-
out.push("quantization");
|
|
145
|
-
out.push(` quantized tensors ${fmtInt(analysis.quantized_tensors)} / ${fmtInt(analysis.tensor_count)} (${pct(analysis.quantized_tensors, analysis.tensor_count)})`);
|
|
146
|
-
out.push(` per-axis tensors ${fmtInt(analysis.per_channel_tensors)}`);
|
|
147
|
-
out.push("");
|
|
148
|
-
|
|
149
|
-
if (ops.length) {
|
|
150
|
-
out.push("XNNPACK delegate (predicted)");
|
|
151
|
-
out.push(` delegated ops ${fmtInt(delegated)} / ${fmtInt(ops.length)} (${pct(delegated, ops.length)})`);
|
|
152
|
-
if (analysis.xnnpack_effective_chain_breaks != null) {
|
|
153
|
-
out.push(` chain breaks ${fmtInt(analysis.xnnpack_effective_chain_breaks)} effective / ${fmtInt(analysis.xnnpack_chain_breaks)} total`);
|
|
154
|
-
}
|
|
155
|
-
if (analysis.fallback_estimated_bytes) {
|
|
156
|
-
out.push(` fallback traffic ${fmtBytes(analysis.fallback_estimated_bytes)}`);
|
|
157
|
-
}
|
|
158
|
-
out.push("");
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (findings.length) {
|
|
162
|
-
out.push(`findings (${findings.length})`);
|
|
163
|
-
for (const f of findings.slice(0, 10)) {
|
|
164
|
-
const sev = String(f?.severity ?? f?.priority ?? "info").toUpperCase().padEnd(6);
|
|
165
|
-
const title = f?.title ?? f?.message ?? f?.id ?? "";
|
|
166
|
-
out.push(` ${sev} ${title}`);
|
|
167
|
-
}
|
|
168
|
-
if (findings.length > 10) out.push(` ... ${findings.length - 10} more (use --json)`);
|
|
169
|
-
out.push("");
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
out.push("Predicted delegate placement is a static projection, not observed runtime behaviour.");
|
|
173
|
-
out.push("Full ledger: deepbom audit <file> --json");
|
|
174
|
-
process.stdout.write(`${out.join("\n")}\n`);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const opts = parseArgs(argv);
|
|
178
|
-
if (opts.version) { process.stdout.write(`${pkg.version}\n`); process.exit(0); }
|
|
179
|
-
if (opts.help || argv.length === 0) { process.stdout.write(USAGE); process.exit(argv.length === 0 ? 1 : 0); }
|
|
180
|
-
|
|
181
|
-
const command = opts._.shift();
|
|
182
|
-
try {
|
|
183
|
-
if (command === "audit") await cmdAudit(opts);
|
|
184
|
-
else if (command === "targets") await cmdTargets();
|
|
185
|
-
else fail(`unknown command "${command}"\n\n${USAGE}`);
|
|
186
|
-
} catch (error) {
|
|
187
|
-
fail(error?.stack ?? String(error), 1);
|
|
188
|
-
}
|