glassbox 0.3.1 → 0.3.2
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/dist/cli.js +132 -21
- package/package.json +2 -3
package/dist/cli.js
CHANGED
|
@@ -3238,27 +3238,10 @@ async function extractMetadata(data, filePath) {
|
|
|
3238
3238
|
exif: null
|
|
3239
3239
|
};
|
|
3240
3240
|
}
|
|
3241
|
-
const
|
|
3242
|
-
const meta = await sharp(data).metadata();
|
|
3243
|
-
let exif = null;
|
|
3244
|
-
if (meta.exif) {
|
|
3245
|
-
try {
|
|
3246
|
-
exif = {};
|
|
3247
|
-
if (meta.orientation) exif["Orientation"] = String(meta.orientation);
|
|
3248
|
-
} catch {
|
|
3249
|
-
}
|
|
3250
|
-
}
|
|
3241
|
+
const parsed = parseImageHeaders(data, ext);
|
|
3251
3242
|
return {
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
height: meta.height ?? null,
|
|
3255
|
-
fileSize: data.length,
|
|
3256
|
-
colorSpace: meta.space ?? null,
|
|
3257
|
-
channels: meta.channels ?? null,
|
|
3258
|
-
depth: meta.depth ?? null,
|
|
3259
|
-
hasAlpha: meta.hasAlpha ?? null,
|
|
3260
|
-
density: meta.density ?? null,
|
|
3261
|
-
exif
|
|
3243
|
+
...parsed,
|
|
3244
|
+
fileSize: data.length
|
|
3262
3245
|
};
|
|
3263
3246
|
}
|
|
3264
3247
|
function formatMetadataLines(meta) {
|
|
@@ -3285,6 +3268,134 @@ function formatBytes(bytes) {
|
|
|
3285
3268
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
3286
3269
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
3287
3270
|
}
|
|
3271
|
+
function parseImageHeaders(data, ext) {
|
|
3272
|
+
try {
|
|
3273
|
+
if (ext === ".png") return parsePng(data);
|
|
3274
|
+
if (ext === ".jpg" || ext === ".jpeg") return parseJpeg(data);
|
|
3275
|
+
if (ext === ".gif") return parseGif(data);
|
|
3276
|
+
if (ext === ".webp") return parseWebp(data);
|
|
3277
|
+
} catch {
|
|
3278
|
+
}
|
|
3279
|
+
return emptyMeta(ext.slice(1));
|
|
3280
|
+
}
|
|
3281
|
+
function emptyMeta(format) {
|
|
3282
|
+
return { format, width: null, height: null, colorSpace: null, channels: null, depth: null, hasAlpha: null, density: null, exif: null };
|
|
3283
|
+
}
|
|
3284
|
+
function parsePng(data) {
|
|
3285
|
+
if (data.length < 26) return emptyMeta("png");
|
|
3286
|
+
const width = data.readUInt32BE(16);
|
|
3287
|
+
const height = data.readUInt32BE(20);
|
|
3288
|
+
const bitDepth = data[24];
|
|
3289
|
+
const colorType = data[25];
|
|
3290
|
+
let colorSpace = null;
|
|
3291
|
+
let channels = null;
|
|
3292
|
+
let hasAlpha = null;
|
|
3293
|
+
switch (colorType) {
|
|
3294
|
+
case 0:
|
|
3295
|
+
colorSpace = "grayscale";
|
|
3296
|
+
channels = 1;
|
|
3297
|
+
hasAlpha = false;
|
|
3298
|
+
break;
|
|
3299
|
+
case 2:
|
|
3300
|
+
colorSpace = "srgb";
|
|
3301
|
+
channels = 3;
|
|
3302
|
+
hasAlpha = false;
|
|
3303
|
+
break;
|
|
3304
|
+
case 3:
|
|
3305
|
+
colorSpace = "indexed";
|
|
3306
|
+
channels = 1;
|
|
3307
|
+
hasAlpha = false;
|
|
3308
|
+
break;
|
|
3309
|
+
case 4:
|
|
3310
|
+
colorSpace = "grayscale";
|
|
3311
|
+
channels = 2;
|
|
3312
|
+
hasAlpha = true;
|
|
3313
|
+
break;
|
|
3314
|
+
case 6:
|
|
3315
|
+
colorSpace = "srgb";
|
|
3316
|
+
channels = 4;
|
|
3317
|
+
hasAlpha = true;
|
|
3318
|
+
break;
|
|
3319
|
+
}
|
|
3320
|
+
const density = parsePngDensity(data);
|
|
3321
|
+
return { format: "png", width, height, colorSpace, channels, depth: bitDepth ? String(bitDepth) : null, hasAlpha, density, exif: null };
|
|
3322
|
+
}
|
|
3323
|
+
function parsePngDensity(data) {
|
|
3324
|
+
const marker = Buffer.from("pHYs");
|
|
3325
|
+
const idx = data.indexOf(marker);
|
|
3326
|
+
if (idx === -1 || idx + 13 > data.length) return null;
|
|
3327
|
+
const unit = data[idx + 12];
|
|
3328
|
+
if (unit !== 1) return null;
|
|
3329
|
+
const ppuX = data.readUInt32BE(idx + 4);
|
|
3330
|
+
return Math.round(ppuX / 39.3701);
|
|
3331
|
+
}
|
|
3332
|
+
function parseJpeg(data) {
|
|
3333
|
+
let width = null;
|
|
3334
|
+
let height = null;
|
|
3335
|
+
let channels = null;
|
|
3336
|
+
let depth = null;
|
|
3337
|
+
let density = null;
|
|
3338
|
+
let i = 2;
|
|
3339
|
+
while (i < data.length - 1) {
|
|
3340
|
+
if (data[i] !== 255) {
|
|
3341
|
+
i++;
|
|
3342
|
+
continue;
|
|
3343
|
+
}
|
|
3344
|
+
const marker = data[i + 1];
|
|
3345
|
+
if (marker >= 192 && marker <= 195 || marker >= 197 && marker <= 199 || marker >= 201 && marker <= 203 || marker >= 205 && marker <= 207) {
|
|
3346
|
+
if (i + 9 < data.length) {
|
|
3347
|
+
depth = String(data[i + 4]);
|
|
3348
|
+
height = data.readUInt16BE(i + 5);
|
|
3349
|
+
width = data.readUInt16BE(i + 7);
|
|
3350
|
+
channels = data[i + 9];
|
|
3351
|
+
}
|
|
3352
|
+
break;
|
|
3353
|
+
}
|
|
3354
|
+
if (marker === 224 && i + 14 < data.length) {
|
|
3355
|
+
const units = data[i + 11];
|
|
3356
|
+
const xDensity = data.readUInt16BE(i + 12);
|
|
3357
|
+
if (units === 1) density = xDensity;
|
|
3358
|
+
else if (units === 2) density = Math.round(xDensity * 2.54);
|
|
3359
|
+
}
|
|
3360
|
+
if (i + 3 < data.length) {
|
|
3361
|
+
const len = data.readUInt16BE(i + 2);
|
|
3362
|
+
i += 2 + len;
|
|
3363
|
+
} else {
|
|
3364
|
+
break;
|
|
3365
|
+
}
|
|
3366
|
+
}
|
|
3367
|
+
const colorSpace = channels === 1 ? "grayscale" : channels === 3 ? "srgb" : null;
|
|
3368
|
+
return { format: "jpeg", width, height, colorSpace, channels, depth, hasAlpha: false, density, exif: null };
|
|
3369
|
+
}
|
|
3370
|
+
function parseGif(data) {
|
|
3371
|
+
if (data.length < 10) return emptyMeta("gif");
|
|
3372
|
+
const width = data.readUInt16LE(6);
|
|
3373
|
+
const height = data.readUInt16LE(8);
|
|
3374
|
+
return { format: "gif", width, height, colorSpace: "indexed", channels: null, depth: null, hasAlpha: null, density: null, exif: null };
|
|
3375
|
+
}
|
|
3376
|
+
function parseWebp(data) {
|
|
3377
|
+
if (data.length < 30) return emptyMeta("webp");
|
|
3378
|
+
let width = null;
|
|
3379
|
+
let height = null;
|
|
3380
|
+
let hasAlpha = null;
|
|
3381
|
+
const chunk = data.toString("ascii", 12, 16);
|
|
3382
|
+
if (chunk === "VP8 " && data.length >= 30) {
|
|
3383
|
+
width = data.readUInt16LE(26) & 16383;
|
|
3384
|
+
height = data.readUInt16LE(28) & 16383;
|
|
3385
|
+
hasAlpha = false;
|
|
3386
|
+
} else if (chunk === "VP8L" && data.length >= 25) {
|
|
3387
|
+
const bits = data.readUInt32LE(21);
|
|
3388
|
+
width = (bits & 16383) + 1;
|
|
3389
|
+
height = (bits >> 14 & 16383) + 1;
|
|
3390
|
+
hasAlpha = (bits >> 28 & 1) === 1;
|
|
3391
|
+
} else if (chunk === "VP8X" && data.length >= 30) {
|
|
3392
|
+
const flags = data[20];
|
|
3393
|
+
hasAlpha = (flags & 16) !== 0;
|
|
3394
|
+
width = (data[24] | data[25] << 8 | data[26] << 16) + 1;
|
|
3395
|
+
height = (data[27] | data[28] << 8 | data[29] << 16) + 1;
|
|
3396
|
+
}
|
|
3397
|
+
return { format: "webp", width, height, colorSpace: "srgb", channels: hasAlpha ? 4 : 3, depth: null, hasAlpha, density: null, exif: null };
|
|
3398
|
+
}
|
|
3288
3399
|
|
|
3289
3400
|
// src/outline/parser.ts
|
|
3290
3401
|
var BRACE_LANGS = /* @__PURE__ */ new Set([
|
|
@@ -5154,7 +5265,7 @@ async function main() {
|
|
|
5154
5265
|
console.log("AI service test mode enabled \u2014 using mock AI responses");
|
|
5155
5266
|
}
|
|
5156
5267
|
if (debug) {
|
|
5157
|
-
console.log(`[debug] Build timestamp: ${"2026-03-16T09:
|
|
5268
|
+
console.log(`[debug] Build timestamp: ${"2026-03-16T09:50:09.819Z"}`);
|
|
5158
5269
|
}
|
|
5159
5270
|
if (projectDir) {
|
|
5160
5271
|
process.chdir(projectDir);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "glassbox",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "A local code review tool for AI-generated code. Review diffs, annotate lines, and export structured feedback that AI tools can act on.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -51,8 +51,7 @@
|
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@electric-sql/pglite": "^0.3.15",
|
|
53
53
|
"@hono/node-server": "^1.19.9",
|
|
54
|
-
"hono": "^4.12.2"
|
|
55
|
-
"sharp": "^0.34.5"
|
|
54
|
+
"hono": "^4.12.2"
|
|
56
55
|
},
|
|
57
56
|
"devDependencies": {
|
|
58
57
|
"@eslint/js": "^9.39.3",
|