glassbox 0.3.0 → 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/README.md +2 -2
- package/dist/cli.js +256 -120
- package/dist/client/app.global.js +7 -7
- package/dist/client/styles.css +1 -1
- package/package.json +3 -4
package/README.md
CHANGED
|
@@ -65,13 +65,13 @@ Glassbox gives you a proper diff viewer with annotation categories designed for
|
|
|
65
65
|
| **Note** | Context for the AI to consider. |
|
|
66
66
|
| **Remember** | A rule to persist to the AI's long-term config. |
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
As you annotate, `.glassbox/latest-review.md` is updated automatically. You can tell your AI tool at any time:
|
|
69
69
|
|
|
70
70
|
```
|
|
71
71
|
Read .glassbox/latest-review.md and apply the feedback.
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
-
The AI gets a structured file with every annotation, organized by file and line number, with clear instructions on how to interpret each category. It fixes the bugs, applies your style preferences, avoids the anti-patterns, and updates its own config with your "remember" items.
|
|
74
|
+
The AI gets a structured file with every annotation, organized by file and line number, with clear instructions on how to interpret each category. It fixes the bugs, applies your style preferences, avoids the anti-patterns, and updates its own config with your "remember" items. You don't need to formally "complete" a review to share feedback — just annotate and switch to your AI tool.
|
|
75
75
|
|
|
76
76
|
Then you run `glassbox` again. Your previous annotations carry forward — matched to the updated diff. Stale comments that no longer apply are flagged so you can keep or discard them. The loop continues until you're satisfied.
|
|
77
77
|
|
package/dist/cli.js
CHANGED
|
@@ -3083,6 +3083,17 @@ async function generateReviewExport(reviewId, repoRoot, isCurrent) {
|
|
|
3083
3083
|
return archivePath;
|
|
3084
3084
|
}
|
|
3085
3085
|
|
|
3086
|
+
// src/export/auto-export.ts
|
|
3087
|
+
var debounceTimer = null;
|
|
3088
|
+
var DEBOUNCE_MS = 2e3;
|
|
3089
|
+
function scheduleAutoExport(reviewId, repoRoot) {
|
|
3090
|
+
if (debounceTimer !== null) clearTimeout(debounceTimer);
|
|
3091
|
+
debounceTimer = setTimeout(() => {
|
|
3092
|
+
debounceTimer = null;
|
|
3093
|
+
void generateReviewExport(reviewId, repoRoot, true);
|
|
3094
|
+
}, DEBOUNCE_MS);
|
|
3095
|
+
}
|
|
3096
|
+
|
|
3086
3097
|
// src/git/image.ts
|
|
3087
3098
|
import { execSync as execSync4 } from "child_process";
|
|
3088
3099
|
import { readFileSync as readFileSync5 } from "fs";
|
|
@@ -3227,27 +3238,10 @@ async function extractMetadata(data, filePath) {
|
|
|
3227
3238
|
exif: null
|
|
3228
3239
|
};
|
|
3229
3240
|
}
|
|
3230
|
-
const
|
|
3231
|
-
const meta = await sharp(data).metadata();
|
|
3232
|
-
let exif = null;
|
|
3233
|
-
if (meta.exif) {
|
|
3234
|
-
try {
|
|
3235
|
-
exif = {};
|
|
3236
|
-
if (meta.orientation) exif["Orientation"] = String(meta.orientation);
|
|
3237
|
-
} catch {
|
|
3238
|
-
}
|
|
3239
|
-
}
|
|
3241
|
+
const parsed = parseImageHeaders(data, ext);
|
|
3240
3242
|
return {
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
height: meta.height ?? null,
|
|
3244
|
-
fileSize: data.length,
|
|
3245
|
-
colorSpace: meta.space ?? null,
|
|
3246
|
-
channels: meta.channels ?? null,
|
|
3247
|
-
depth: meta.depth ?? null,
|
|
3248
|
-
hasAlpha: meta.hasAlpha ?? null,
|
|
3249
|
-
density: meta.density ?? null,
|
|
3250
|
-
exif
|
|
3243
|
+
...parsed,
|
|
3244
|
+
fileSize: data.length
|
|
3251
3245
|
};
|
|
3252
3246
|
}
|
|
3253
3247
|
function formatMetadataLines(meta) {
|
|
@@ -3274,6 +3268,134 @@ function formatBytes(bytes) {
|
|
|
3274
3268
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
3275
3269
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
3276
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
|
+
}
|
|
3277
3399
|
|
|
3278
3400
|
// src/outline/parser.ts
|
|
3279
3401
|
var BRACE_LANGS = /* @__PURE__ */ new Set([
|
|
@@ -3704,6 +3826,9 @@ apiRoutes.patch("/files/:fileId/status", async (c) => {
|
|
|
3704
3826
|
await updateFileStatus(c.req.param("fileId"), status);
|
|
3705
3827
|
return c.json({ ok: true });
|
|
3706
3828
|
});
|
|
3829
|
+
function autoExport(c) {
|
|
3830
|
+
scheduleAutoExport(c.get("reviewId"), c.get("repoRoot"));
|
|
3831
|
+
}
|
|
3707
3832
|
apiRoutes.post("/annotations", async (c) => {
|
|
3708
3833
|
const body = await c.req.json();
|
|
3709
3834
|
const annotation = await addAnnotation(
|
|
@@ -3713,34 +3838,41 @@ apiRoutes.post("/annotations", async (c) => {
|
|
|
3713
3838
|
body.category,
|
|
3714
3839
|
body.content
|
|
3715
3840
|
);
|
|
3841
|
+
autoExport(c);
|
|
3716
3842
|
return c.json(annotation, 201);
|
|
3717
3843
|
});
|
|
3718
3844
|
apiRoutes.patch("/annotations/:id", async (c) => {
|
|
3719
3845
|
const { content, category } = await c.req.json();
|
|
3720
3846
|
await updateAnnotation(c.req.param("id"), content, category);
|
|
3847
|
+
autoExport(c);
|
|
3721
3848
|
return c.json({ ok: true });
|
|
3722
3849
|
});
|
|
3723
3850
|
apiRoutes.delete("/annotations/:id", async (c) => {
|
|
3724
3851
|
await deleteAnnotation(c.req.param("id"));
|
|
3852
|
+
autoExport(c);
|
|
3725
3853
|
return c.json({ ok: true });
|
|
3726
3854
|
});
|
|
3727
3855
|
apiRoutes.patch("/annotations/:id/move", async (c) => {
|
|
3728
3856
|
const { lineNumber, side } = await c.req.json();
|
|
3729
3857
|
await moveAnnotation(c.req.param("id"), lineNumber, side);
|
|
3858
|
+
autoExport(c);
|
|
3730
3859
|
return c.json({ ok: true });
|
|
3731
3860
|
});
|
|
3732
3861
|
apiRoutes.post("/annotations/:id/keep", async (c) => {
|
|
3733
3862
|
await markAnnotationCurrent(c.req.param("id"));
|
|
3863
|
+
autoExport(c);
|
|
3734
3864
|
return c.json({ ok: true });
|
|
3735
3865
|
});
|
|
3736
3866
|
apiRoutes.post("/annotations/stale/delete-all", async (c) => {
|
|
3737
3867
|
const reviewId = resolveReviewId(c);
|
|
3738
3868
|
await deleteStaleAnnotations(reviewId);
|
|
3869
|
+
autoExport(c);
|
|
3739
3870
|
return c.json({ ok: true });
|
|
3740
3871
|
});
|
|
3741
3872
|
apiRoutes.post("/annotations/stale/keep-all", async (c) => {
|
|
3742
3873
|
const reviewId = resolveReviewId(c);
|
|
3743
3874
|
await keepAllStaleAnnotations(reviewId);
|
|
3875
|
+
autoExport(c);
|
|
3744
3876
|
return c.json({ ok: true });
|
|
3745
3877
|
});
|
|
3746
3878
|
apiRoutes.get("/annotations/all", async (c) => {
|
|
@@ -3955,16 +4087,14 @@ function ImageDiff({ file, diff }) {
|
|
|
3955
4087
|
/* @__PURE__ */ jsx("div", { className: "slice-handle slice-handle-a" }),
|
|
3956
4088
|
/* @__PURE__ */ jsx("div", { className: "slice-handle slice-handle-b" })
|
|
3957
4089
|
] }) }),
|
|
3958
|
-
!hasComparison && /* @__PURE__ */ jsx("div", { className: "image-diff-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
/* @__PURE__ */ jsx("p", { className: "image-diff-status", children: isAdded ? "New file" : "Deleted file" })
|
|
3967
|
-
] })
|
|
4090
|
+
!hasComparison && /* @__PURE__ */ jsx("div", { className: "image-diff-panel image-diff-visual", "data-panel": "image", children: /* @__PURE__ */ jsx("div", { className: "image-visual-canvas", "data-zoomable": "true", children: /* @__PURE__ */ jsx("div", { className: "image-zoom-wrap", children: /* @__PURE__ */ jsx(
|
|
4091
|
+
"img",
|
|
4092
|
+
{
|
|
4093
|
+
className: "image-layer image-layer-old",
|
|
4094
|
+
src: `/api/image/${fileId}/${isAdded ? "new" : "old"}`,
|
|
4095
|
+
alt: isAdded ? "New image" : "Deleted image"
|
|
4096
|
+
}
|
|
4097
|
+
) }) }) })
|
|
3968
4098
|
]
|
|
3969
4099
|
}
|
|
3970
4100
|
);
|
|
@@ -4526,55 +4656,58 @@ pageRoutes.get("/", async (c) => {
|
|
|
4526
4656
|
/* @__PURE__ */ jsx("button", { id: "update-banner-dismiss", className: "btn btn-sm", children: "Later" })
|
|
4527
4657
|
] })
|
|
4528
4658
|
] }),
|
|
4529
|
-
/* @__PURE__ */ jsx("
|
|
4530
|
-
/* @__PURE__ */ jsx("
|
|
4531
|
-
/* @__PURE__ */ jsx("
|
|
4532
|
-
|
|
4533
|
-
review
|
|
4534
|
-
|
|
4659
|
+
/* @__PURE__ */ jsx("div", { className: "review-body", children: [
|
|
4660
|
+
/* @__PURE__ */ jsx("aside", { className: "sidebar", children: [
|
|
4661
|
+
/* @__PURE__ */ jsx("div", { className: "sidebar-header", children: [
|
|
4662
|
+
/* @__PURE__ */ jsx("h2", { children: review.repo_name }),
|
|
4663
|
+
/* @__PURE__ */ jsx("span", { className: "review-mode", children: [
|
|
4664
|
+
review.mode,
|
|
4665
|
+
review.mode_args !== null && review.mode_args !== "" ? `: ${review.mode_args}` : ""
|
|
4666
|
+
] })
|
|
4667
|
+
] }),
|
|
4668
|
+
/* @__PURE__ */ jsx("div", { className: "file-filter", children: /* @__PURE__ */ jsx("input", { type: "text", className: "file-filter-input", id: "file-filter", placeholder: "Filter files..." }) }),
|
|
4669
|
+
/* @__PURE__ */ jsx(FileList, { files, annotationCounts, staleCounts: {} }),
|
|
4670
|
+
/* @__PURE__ */ jsx("div", { className: "sidebar-footer", children: [
|
|
4671
|
+
/* @__PURE__ */ jsx("button", { className: "btn btn-primary btn-complete", id: "complete-review", children: "Complete Review" }),
|
|
4672
|
+
/* @__PURE__ */ jsx("a", { href: "/history", className: "btn btn-sm btn-link", children: "Review History" })
|
|
4535
4673
|
] })
|
|
4536
4674
|
] }),
|
|
4537
|
-
/* @__PURE__ */ jsx("div", { className: "
|
|
4538
|
-
/* @__PURE__ */ jsx(
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
/* @__PURE__ */ jsx("div", { className: "welcome-message", children: [
|
|
4547
|
-
/* @__PURE__ */ jsx("h3", { children: "Select a file to begin reviewing" }),
|
|
4548
|
-
/* @__PURE__ */ jsx("p", { children: [
|
|
4549
|
-
files.length,
|
|
4550
|
-
" file(s) to review"
|
|
4675
|
+
/* @__PURE__ */ jsx("div", { className: "sidebar-resize", id: "sidebar-resize" }),
|
|
4676
|
+
/* @__PURE__ */ jsx("main", { className: "main-content", children: [
|
|
4677
|
+
/* @__PURE__ */ jsx("div", { className: "welcome-message", children: [
|
|
4678
|
+
/* @__PURE__ */ jsx("h3", { children: "Select a file to begin reviewing" }),
|
|
4679
|
+
/* @__PURE__ */ jsx("p", { children: [
|
|
4680
|
+
files.length,
|
|
4681
|
+
" file(s) to review"
|
|
4682
|
+
] }),
|
|
4683
|
+
/* @__PURE__ */ jsx("p", { className: "progress-summary", id: "progress-summary" })
|
|
4551
4684
|
] }),
|
|
4552
|
-
/* @__PURE__ */ jsx("
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4559
|
-
|
|
4560
|
-
/* @__PURE__ */ jsx("button", { className: "
|
|
4685
|
+
/* @__PURE__ */ jsx("div", { className: "diff-container", id: "diff-container", style: "display:none" }),
|
|
4686
|
+
/* @__PURE__ */ jsx("div", { className: "diff-toolbar", id: "diff-toolbar", style: "display:none", children: [
|
|
4687
|
+
/* @__PURE__ */ jsx("div", { className: "diff-toolbar-text", children: [
|
|
4688
|
+
/* @__PURE__ */ jsx("div", { className: "diff-toolbar-left", children: [
|
|
4689
|
+
/* @__PURE__ */ jsx("div", { className: "segmented-control", children: [
|
|
4690
|
+
/* @__PURE__ */ jsx("button", { className: "segment active", "data-diff-mode": "split", children: "Split" }),
|
|
4691
|
+
/* @__PURE__ */ jsx("button", { className: "segment", "data-diff-mode": "unified", children: "Unified" })
|
|
4692
|
+
] }),
|
|
4693
|
+
/* @__PURE__ */ jsx("button", { className: "toolbar-btn", id: "wrap-toggle", children: "Wrap" }),
|
|
4694
|
+
/* @__PURE__ */ jsx("button", { className: "toolbar-btn", id: "whitespace-toggle", children: "Ignore Whitespace" })
|
|
4561
4695
|
] }),
|
|
4562
|
-
/* @__PURE__ */ jsx("button", { className: "toolbar-btn", id: "
|
|
4563
|
-
/* @__PURE__ */ jsx("button", { className: "toolbar-btn", id: "whitespace-toggle", children: "Ignore Whitespace" })
|
|
4696
|
+
/* @__PURE__ */ jsx("div", { className: "diff-toolbar-right", children: /* @__PURE__ */ jsx("button", { className: "toolbar-btn", id: "language-btn", children: "Plain Text" }) })
|
|
4564
4697
|
] }),
|
|
4565
|
-
/* @__PURE__ */ jsx("div", { className: "diff-toolbar-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4698
|
+
/* @__PURE__ */ jsx("div", { className: "diff-toolbar-image", style: "display:none", children: [
|
|
4699
|
+
/* @__PURE__ */ jsx("div", { className: "diff-toolbar-left", children: /* @__PURE__ */ jsx("div", { className: "segmented-control", children: [
|
|
4700
|
+
/* @__PURE__ */ jsx("button", { className: "segment active", "data-image-mode": "metadata", children: "Metadata" }),
|
|
4701
|
+
/* @__PURE__ */ jsx("button", { className: "segment", "data-image-mode": "difference", children: "Difference" }),
|
|
4702
|
+
/* @__PURE__ */ jsx("button", { className: "segment", "data-image-mode": "slice", children: "Slice" }),
|
|
4703
|
+
/* @__PURE__ */ jsx("button", { className: "segment", "data-image-mode": "image", style: "display:none", children: "Image" })
|
|
4704
|
+
] }) }),
|
|
4705
|
+
/* @__PURE__ */ jsx("div", { className: "diff-toolbar-right", children: [
|
|
4706
|
+
/* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "out", title: "Zoom out", children: raw(zoomOutSvg) }),
|
|
4707
|
+
/* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "fit", title: "Fit to view", children: raw(fitSvg) }),
|
|
4708
|
+
/* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "actual", title: "Actual size (1:1)", children: raw(actualSizeSvg) }),
|
|
4709
|
+
/* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "in", title: "Zoom in", children: raw(zoomInSvg) })
|
|
4710
|
+
] })
|
|
4578
4711
|
] })
|
|
4579
4712
|
] })
|
|
4580
4713
|
] })
|
|
@@ -4626,56 +4759,59 @@ pageRoutes.get("/review/:reviewId", async (c) => {
|
|
|
4626
4759
|
/* @__PURE__ */ jsx("button", { id: "update-banner-dismiss", className: "btn btn-sm", children: "Later" })
|
|
4627
4760
|
] })
|
|
4628
4761
|
] }),
|
|
4629
|
-
/* @__PURE__ */ jsx("
|
|
4630
|
-
/* @__PURE__ */ jsx("
|
|
4631
|
-
/* @__PURE__ */ jsx("
|
|
4632
|
-
|
|
4633
|
-
review
|
|
4634
|
-
|
|
4762
|
+
/* @__PURE__ */ jsx("div", { className: "review-body", children: [
|
|
4763
|
+
/* @__PURE__ */ jsx("aside", { className: "sidebar", children: [
|
|
4764
|
+
/* @__PURE__ */ jsx("div", { className: "sidebar-header", children: [
|
|
4765
|
+
/* @__PURE__ */ jsx("h2", { children: review.repo_name }),
|
|
4766
|
+
/* @__PURE__ */ jsx("span", { className: "review-mode", children: [
|
|
4767
|
+
review.mode,
|
|
4768
|
+
review.mode_args !== null && review.mode_args !== "" ? `: ${review.mode_args}` : ""
|
|
4769
|
+
] })
|
|
4770
|
+
] }),
|
|
4771
|
+
/* @__PURE__ */ jsx("div", { className: "file-filter", children: /* @__PURE__ */ jsx("input", { type: "text", className: "file-filter-input", id: "file-filter", placeholder: "Filter files..." }) }),
|
|
4772
|
+
/* @__PURE__ */ jsx(FileList, { files, annotationCounts, staleCounts: {} }),
|
|
4773
|
+
/* @__PURE__ */ jsx("div", { className: "sidebar-footer", children: [
|
|
4774
|
+
review.status === "completed" ? /* @__PURE__ */ jsx("button", { className: "btn btn-primary", id: "reopen-review", children: "Reopen Review" }) : /* @__PURE__ */ jsx("button", { className: "btn btn-primary btn-complete", id: "complete-review", children: "Complete Review" }),
|
|
4775
|
+
/* @__PURE__ */ jsx("a", { href: "/history", className: "btn btn-sm btn-link", children: "Review History" }),
|
|
4776
|
+
/* @__PURE__ */ jsx("a", { href: "/", className: "btn btn-sm btn-link", children: "Back to current review" })
|
|
4635
4777
|
] })
|
|
4636
4778
|
] }),
|
|
4637
|
-
/* @__PURE__ */ jsx("div", { className: "
|
|
4638
|
-
/* @__PURE__ */ jsx(
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
/* @__PURE__ */ jsx("main", { className: "main-content", children: [
|
|
4647
|
-
/* @__PURE__ */ jsx("div", { className: "welcome-message", children: [
|
|
4648
|
-
/* @__PURE__ */ jsx("h3", { children: "Select a file to begin reviewing" }),
|
|
4649
|
-
/* @__PURE__ */ jsx("p", { children: [
|
|
4650
|
-
files.length,
|
|
4651
|
-
" file(s) to review"
|
|
4779
|
+
/* @__PURE__ */ jsx("div", { className: "sidebar-resize", id: "sidebar-resize" }),
|
|
4780
|
+
/* @__PURE__ */ jsx("main", { className: "main-content", children: [
|
|
4781
|
+
/* @__PURE__ */ jsx("div", { className: "welcome-message", children: [
|
|
4782
|
+
/* @__PURE__ */ jsx("h3", { children: "Select a file to begin reviewing" }),
|
|
4783
|
+
/* @__PURE__ */ jsx("p", { children: [
|
|
4784
|
+
files.length,
|
|
4785
|
+
" file(s) to review"
|
|
4786
|
+
] }),
|
|
4787
|
+
/* @__PURE__ */ jsx("p", { className: "progress-summary", id: "progress-summary" })
|
|
4652
4788
|
] }),
|
|
4653
|
-
/* @__PURE__ */ jsx("
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
/* @__PURE__ */ jsx("button", { className: "
|
|
4789
|
+
/* @__PURE__ */ jsx("div", { className: "diff-container", id: "diff-container", style: "display:none" }),
|
|
4790
|
+
/* @__PURE__ */ jsx("div", { className: "diff-toolbar", id: "diff-toolbar", style: "display:none", children: [
|
|
4791
|
+
/* @__PURE__ */ jsx("div", { className: "diff-toolbar-text", children: [
|
|
4792
|
+
/* @__PURE__ */ jsx("div", { className: "diff-toolbar-left", children: [
|
|
4793
|
+
/* @__PURE__ */ jsx("div", { className: "segmented-control", children: [
|
|
4794
|
+
/* @__PURE__ */ jsx("button", { className: "segment active", "data-diff-mode": "split", children: "Split" }),
|
|
4795
|
+
/* @__PURE__ */ jsx("button", { className: "segment", "data-diff-mode": "unified", children: "Unified" })
|
|
4796
|
+
] }),
|
|
4797
|
+
/* @__PURE__ */ jsx("button", { className: "toolbar-btn", id: "wrap-toggle", children: "Wrap" }),
|
|
4798
|
+
/* @__PURE__ */ jsx("button", { className: "toolbar-btn", id: "whitespace-toggle", children: "Ignore Whitespace" })
|
|
4662
4799
|
] }),
|
|
4663
|
-
/* @__PURE__ */ jsx("button", { className: "toolbar-btn", id: "
|
|
4664
|
-
/* @__PURE__ */ jsx("button", { className: "toolbar-btn", id: "whitespace-toggle", children: "Ignore Whitespace" })
|
|
4800
|
+
/* @__PURE__ */ jsx("div", { className: "diff-toolbar-right", children: /* @__PURE__ */ jsx("button", { className: "toolbar-btn", id: "language-btn", children: "Plain Text" }) })
|
|
4665
4801
|
] }),
|
|
4666
|
-
/* @__PURE__ */ jsx("div", { className: "diff-toolbar-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4802
|
+
/* @__PURE__ */ jsx("div", { className: "diff-toolbar-image", style: "display:none", children: [
|
|
4803
|
+
/* @__PURE__ */ jsx("div", { className: "diff-toolbar-left", children: /* @__PURE__ */ jsx("div", { className: "segmented-control", children: [
|
|
4804
|
+
/* @__PURE__ */ jsx("button", { className: "segment active", "data-image-mode": "metadata", children: "Metadata" }),
|
|
4805
|
+
/* @__PURE__ */ jsx("button", { className: "segment", "data-image-mode": "difference", children: "Difference" }),
|
|
4806
|
+
/* @__PURE__ */ jsx("button", { className: "segment", "data-image-mode": "slice", children: "Slice" }),
|
|
4807
|
+
/* @__PURE__ */ jsx("button", { className: "segment", "data-image-mode": "image", style: "display:none", children: "Image" })
|
|
4808
|
+
] }) }),
|
|
4809
|
+
/* @__PURE__ */ jsx("div", { className: "diff-toolbar-right", children: [
|
|
4810
|
+
/* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "out", title: "Zoom out", children: raw(zoomOutSvg) }),
|
|
4811
|
+
/* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "fit", title: "Fit to view", children: raw(fitSvg) }),
|
|
4812
|
+
/* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "actual", title: "Actual size (1:1)", children: raw(actualSizeSvg) }),
|
|
4813
|
+
/* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "in", title: "Zoom in", children: raw(zoomInSvg) })
|
|
4814
|
+
] })
|
|
4679
4815
|
] })
|
|
4680
4816
|
] })
|
|
4681
4817
|
] })
|
|
@@ -5129,7 +5265,7 @@ async function main() {
|
|
|
5129
5265
|
console.log("AI service test mode enabled \u2014 using mock AI responses");
|
|
5130
5266
|
}
|
|
5131
5267
|
if (debug) {
|
|
5132
|
-
console.log(`[debug] Build timestamp: ${"2026-03-
|
|
5268
|
+
console.log(`[debug] Build timestamp: ${"2026-03-16T09:50:09.819Z"}`);
|
|
5133
5269
|
}
|
|
5134
5270
|
if (projectDir) {
|
|
5135
5271
|
process.chdir(projectDir);
|