glassbox 0.4.2 → 0.4.3

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 CHANGED
@@ -1403,9 +1403,9 @@ function createNewFileDiff(filePath, repoRoot) {
1403
1403
  isBinary: false
1404
1404
  };
1405
1405
  }
1406
- function parseDiff(raw2) {
1406
+ function parseDiff(raw) {
1407
1407
  const files = [];
1408
- const fileChunks = raw2.split(/^diff --git /m).filter(Boolean);
1408
+ const fileChunks = raw.split(/^diff --git /m).filter(Boolean);
1409
1409
  for (const chunk of fileChunks) {
1410
1410
  const headerEnd = chunk.indexOf("@@");
1411
1411
  const header = headerEnd === -1 ? chunk : chunk.slice(0, headerEnd);
@@ -1441,12 +1441,12 @@ function parseDiff(raw2) {
1441
1441
  }
1442
1442
  return files;
1443
1443
  }
1444
- function parseHunks(raw2) {
1444
+ function parseHunks(raw) {
1445
1445
  const hunks = [];
1446
1446
  const hunkRegex = /^@@\s+-(\d+)(?:,(\d+))?\s+\+(\d+)(?:,(\d+))?\s+@@(.*)/gm;
1447
1447
  let match;
1448
1448
  const hunkStarts = [];
1449
- while ((match = hunkRegex.exec(raw2)) !== null) {
1449
+ while ((match = hunkRegex.exec(raw)) !== null) {
1450
1450
  const groups = match;
1451
1451
  hunkStarts.push({
1452
1452
  index: match.index + match[0].length,
@@ -1458,8 +1458,8 @@ function parseHunks(raw2) {
1458
1458
  }
1459
1459
  for (let i = 0; i < hunkStarts.length; i++) {
1460
1460
  const start = hunkStarts[i];
1461
- const end = i + 1 < hunkStarts.length ? raw2.lastIndexOf("\n@@", hunkStarts[i + 1].index) : raw2.length;
1462
- const body = raw2.slice(start.index, end);
1461
+ const end = i + 1 < hunkStarts.length ? raw.lastIndexOf("\n@@", hunkStarts[i + 1].index) : raw.length;
1462
+ const body = raw.slice(start.index, end);
1463
1463
  const lines = [];
1464
1464
  let oldNum = start.oldStart;
1465
1465
  let newNum = start.newStart;
@@ -4175,24 +4175,7 @@ var SafeHtml = class {
4175
4175
  return this.__html;
4176
4176
  }
4177
4177
  };
4178
- function raw(html) {
4179
- return new SafeHtml(html);
4180
- }
4181
- var VOID_TAGS = /* @__PURE__ */ new Set([
4182
- "area",
4183
- "base",
4184
- "br",
4185
- "col",
4186
- "embed",
4187
- "hr",
4188
- "img",
4189
- "input",
4190
- "link",
4191
- "meta",
4192
- "source",
4193
- "track",
4194
- "wbr"
4195
- ]);
4178
+ var VOID_TAGS = /* @__PURE__ */ new Set(["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "source", "track", "wbr"]);
4196
4179
  function renderChildren(children) {
4197
4180
  if (children == null || typeof children === "boolean") return "";
4198
4181
  if (children instanceof SafeHtml) return children.__html;
@@ -4201,10 +4184,134 @@ function renderChildren(children) {
4201
4184
  if (Array.isArray(children)) return children.map(renderChildren).join("");
4202
4185
  return "";
4203
4186
  }
4187
+ var ATTR_ALIASES = {
4188
+ // HTML attributes
4189
+ className: "class",
4190
+ htmlFor: "for",
4191
+ httpEquiv: "http-equiv",
4192
+ acceptCharset: "accept-charset",
4193
+ accessKey: "accesskey",
4194
+ autoCapitalize: "autocapitalize",
4195
+ autoComplete: "autocomplete",
4196
+ autoFocus: "autofocus",
4197
+ autoPlay: "autoplay",
4198
+ colSpan: "colspan",
4199
+ contentEditable: "contenteditable",
4200
+ crossOrigin: "crossorigin",
4201
+ dateTime: "datetime",
4202
+ defaultChecked: "checked",
4203
+ defaultValue: "value",
4204
+ encType: "enctype",
4205
+ formAction: "formaction",
4206
+ formEncType: "formenctype",
4207
+ formMethod: "formmethod",
4208
+ formNoValidate: "formnovalidate",
4209
+ formTarget: "formtarget",
4210
+ hrefLang: "hreflang",
4211
+ inputMode: "inputmode",
4212
+ maxLength: "maxlength",
4213
+ minLength: "minlength",
4214
+ noModule: "nomodule",
4215
+ noValidate: "novalidate",
4216
+ readOnly: "readonly",
4217
+ referrerPolicy: "referrerpolicy",
4218
+ rowSpan: "rowspan",
4219
+ spellCheck: "spellcheck",
4220
+ srcDoc: "srcdoc",
4221
+ srcLang: "srclang",
4222
+ srcSet: "srcset",
4223
+ tabIndex: "tabindex",
4224
+ useMap: "usemap",
4225
+ // SVG presentation attributes (camelCase → kebab-case)
4226
+ strokeWidth: "stroke-width",
4227
+ strokeLinecap: "stroke-linecap",
4228
+ strokeLinejoin: "stroke-linejoin",
4229
+ strokeDasharray: "stroke-dasharray",
4230
+ strokeDashoffset: "stroke-dashoffset",
4231
+ strokeMiterlimit: "stroke-miterlimit",
4232
+ strokeOpacity: "stroke-opacity",
4233
+ fillOpacity: "fill-opacity",
4234
+ fillRule: "fill-rule",
4235
+ clipPath: "clip-path",
4236
+ clipRule: "clip-rule",
4237
+ colorInterpolation: "color-interpolation",
4238
+ colorInterpolationFilters: "color-interpolation-filters",
4239
+ floodColor: "flood-color",
4240
+ floodOpacity: "flood-opacity",
4241
+ lightingColor: "lighting-color",
4242
+ stopColor: "stop-color",
4243
+ stopOpacity: "stop-opacity",
4244
+ shapeRendering: "shape-rendering",
4245
+ imageRendering: "image-rendering",
4246
+ textRendering: "text-rendering",
4247
+ pointerEvents: "pointer-events",
4248
+ vectorEffect: "vector-effect",
4249
+ paintOrder: "paint-order",
4250
+ // SVG text/font attributes
4251
+ fontFamily: "font-family",
4252
+ fontSize: "font-size",
4253
+ fontStyle: "font-style",
4254
+ fontVariant: "font-variant",
4255
+ fontWeight: "font-weight",
4256
+ fontStretch: "font-stretch",
4257
+ textAnchor: "text-anchor",
4258
+ textDecoration: "text-decoration",
4259
+ dominantBaseline: "dominant-baseline",
4260
+ alignmentBaseline: "alignment-baseline",
4261
+ baselineShift: "baseline-shift",
4262
+ letterSpacing: "letter-spacing",
4263
+ wordSpacing: "word-spacing",
4264
+ writingMode: "writing-mode",
4265
+ glyphOrientationHorizontal: "glyph-orientation-horizontal",
4266
+ glyphOrientationVertical: "glyph-orientation-vertical",
4267
+ // SVG marker/gradient/filter attributes
4268
+ markerStart: "marker-start",
4269
+ markerMid: "marker-mid",
4270
+ markerEnd: "marker-end",
4271
+ gradientUnits: "gradientUnits",
4272
+ gradientTransform: "gradientTransform",
4273
+ spreadMethod: "spreadMethod",
4274
+ patternUnits: "patternUnits",
4275
+ patternContentUnits: "patternContentUnits",
4276
+ patternTransform: "patternTransform",
4277
+ maskUnits: "maskUnits",
4278
+ maskContentUnits: "maskContentUnits",
4279
+ filterUnits: "filterUnits",
4280
+ primitiveUnits: "primitiveUnits",
4281
+ clipPathUnits: "clipPathUnits",
4282
+ // SVG xlink (legacy but still used)
4283
+ xlinkHref: "xlink:href",
4284
+ xlinkShow: "xlink:show",
4285
+ xlinkActuate: "xlink:actuate",
4286
+ xlinkType: "xlink:type",
4287
+ xlinkRole: "xlink:role",
4288
+ xlinkTitle: "xlink:title",
4289
+ xlinkArcrole: "xlink:arcrole",
4290
+ xmlBase: "xml:base",
4291
+ xmlLang: "xml:lang",
4292
+ xmlSpace: "xml:space",
4293
+ xmlns: "xmlns",
4294
+ xmlnsXlink: "xmlns:xlink",
4295
+ // SVG filter primitive attributes
4296
+ stdDeviation: "stdDeviation",
4297
+ baseFrequency: "baseFrequency",
4298
+ numOctaves: "numOctaves",
4299
+ kernelMatrix: "kernelMatrix",
4300
+ surfaceScale: "surfaceScale",
4301
+ specularConstant: "specularConstant",
4302
+ specularExponent: "specularExponent",
4303
+ diffuseConstant: "diffuseConstant",
4304
+ pointsAtX: "pointsAtX",
4305
+ pointsAtY: "pointsAtY",
4306
+ pointsAtZ: "pointsAtZ",
4307
+ limitingConeAngle: "limitingConeAngle",
4308
+ tableValues: "tableValues"
4309
+ // viewBox, preserveAspectRatio stay as-is (already correct casing)
4310
+ };
4204
4311
  function renderAttr(key, value) {
4312
+ const name = ATTR_ALIASES[key] ?? key;
4205
4313
  if (value == null || value === false) return "";
4206
- if (value === true) return ` ${key}`;
4207
- const name = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
4314
+ if (value === true) return ` ${name}`;
4208
4315
  let strValue;
4209
4316
  if (value instanceof SafeHtml) {
4210
4317
  strValue = value.__html;
@@ -4226,6 +4333,65 @@ function jsx(tag, props) {
4226
4333
  return new SafeHtml(`<${tag}${attrStr}>${childStr}</${tag}>`);
4227
4334
  }
4228
4335
 
4336
+ // src/icons.tsx
4337
+ var S14 = { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" };
4338
+ var S12 = { ...S14, width: "12", height: "12" };
4339
+ var S16 = { ...S14, width: "16", height: "16" };
4340
+ function IconEdit() {
4341
+ return /* @__PURE__ */ jsx("svg", { ...S14, children: [
4342
+ /* @__PURE__ */ jsx("path", { d: "M17 3a2.85 2.85 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z" }),
4343
+ /* @__PURE__ */ jsx("path", { d: "m15 5 4 4" })
4344
+ ] });
4345
+ }
4346
+ function IconTrash() {
4347
+ return /* @__PURE__ */ jsx("svg", { ...S14, children: [
4348
+ /* @__PURE__ */ jsx("path", { d: "M3 6h18" }),
4349
+ /* @__PURE__ */ jsx("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }),
4350
+ /* @__PURE__ */ jsx("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" }),
4351
+ /* @__PURE__ */ jsx("line", { x1: "10", y1: "11", x2: "10", y2: "17" }),
4352
+ /* @__PURE__ */ jsx("line", { x1: "14", y1: "11", x2: "14", y2: "17" })
4353
+ ] });
4354
+ }
4355
+ function IconTrash16() {
4356
+ return /* @__PURE__ */ jsx("svg", { ...S16, children: [
4357
+ /* @__PURE__ */ jsx("path", { d: "M3 6h18" }),
4358
+ /* @__PURE__ */ jsx("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }),
4359
+ /* @__PURE__ */ jsx("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" }),
4360
+ /* @__PURE__ */ jsx("line", { x1: "10", y1: "11", x2: "10", y2: "17" }),
4361
+ /* @__PURE__ */ jsx("line", { x1: "14", y1: "11", x2: "14", y2: "17" })
4362
+ ] });
4363
+ }
4364
+ function IconReveal() {
4365
+ return /* @__PURE__ */ jsx("svg", { ...S12, children: [
4366
+ /* @__PURE__ */ jsx("path", { d: "M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" }),
4367
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "11", x2: "12", y2: "17" }),
4368
+ /* @__PURE__ */ jsx("polyline", { points: "9 14 12 11 15 14" })
4369
+ ] });
4370
+ }
4371
+ function IconZoomOut() {
4372
+ return /* @__PURE__ */ jsx("svg", { ...S14, children: /* @__PURE__ */ jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" }) });
4373
+ }
4374
+ function IconZoomIn() {
4375
+ return /* @__PURE__ */ jsx("svg", { ...S14, children: [
4376
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
4377
+ /* @__PURE__ */ jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
4378
+ ] });
4379
+ }
4380
+ function IconFit() {
4381
+ return /* @__PURE__ */ jsx("svg", { ...S14, children: [
4382
+ /* @__PURE__ */ jsx("path", { d: "M15 3h6v6" }),
4383
+ /* @__PURE__ */ jsx("path", { d: "M9 21H3v-6" }),
4384
+ /* @__PURE__ */ jsx("path", { d: "M21 3l-7 7" }),
4385
+ /* @__PURE__ */ jsx("path", { d: "M3 21l7-7" })
4386
+ ] });
4387
+ }
4388
+ function IconActualSize() {
4389
+ return /* @__PURE__ */ jsx("svg", { ...S14, children: [
4390
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
4391
+ /* @__PURE__ */ jsx("text", { x: "12", y: "15.5", textAnchor: "middle", fontSize: "9", fontWeight: "bold", fill: "currentColor", stroke: "none", children: "1:1" })
4392
+ ] });
4393
+ }
4394
+
4229
4395
  // src/components/imageDiff.tsx
4230
4396
  function ImageDiff({ file, diff, fontWarning, baseWidth, baseHeight }) {
4231
4397
  const fileId = file.id;
@@ -4274,7 +4440,6 @@ function ImageDiff({ file, diff, fontWarning, baseWidth, baseHeight }) {
4274
4440
  }
4275
4441
 
4276
4442
  // src/components/diffView.tsx
4277
- var revealSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/><line x1="12" y1="11" x2="12" y2="17"/><polyline points="9 14 12 11 15 14"/></svg>';
4278
4443
  function DiffView({ file, diff, annotations, mode }) {
4279
4444
  const annotationsByLine = {};
4280
4445
  for (const a of annotations) {
@@ -4293,7 +4458,7 @@ function DiffView({ file, diff, annotations, mode }) {
4293
4458
  /* @__PURE__ */ jsx("div", { className: "diff-header", children: [
4294
4459
  /* @__PURE__ */ jsx("div", { className: "diff-header-file", children: [
4295
4460
  /* @__PURE__ */ jsx("span", { className: "file-path", children: diff.filePath }),
4296
- /* @__PURE__ */ jsx("button", { className: "reveal-btn", "data-file-id": file.id, title: "Reveal in file manager", children: raw(revealSvg) })
4461
+ /* @__PURE__ */ jsx("button", { className: "reveal-btn", "data-file-id": file.id, title: "Reveal in file manager", children: /* @__PURE__ */ jsx(IconReveal, {}) })
4297
4462
  ] }),
4298
4463
  /* @__PURE__ */ jsx("div", { className: "diff-header-actions", children: /* @__PURE__ */ jsx("span", { className: `file-status ${diff.status}`, children: diff.status }) })
4299
4464
  ] }),
@@ -4354,7 +4519,7 @@ function SplitDiff({ hunks, annotationsByLine }) {
4354
4519
  "data-new-line": group.pair.left?.newNum ?? group.pair.right?.newNum ?? "",
4355
4520
  children: [
4356
4521
  /* @__PURE__ */ jsx("span", { className: "gutter", "data-line-number": group.pair.left?.oldNum ?? "" }),
4357
- /* @__PURE__ */ jsx("span", { className: "code", children: group.pair.left ? raw(escapeHtml(group.pair.left.content)) : "" })
4522
+ /* @__PURE__ */ jsx("span", { className: "code", children: group.pair.left?.content ?? "" })
4358
4523
  ]
4359
4524
  }
4360
4525
  ),
@@ -4366,7 +4531,7 @@ function SplitDiff({ hunks, annotationsByLine }) {
4366
4531
  "data-side": "new",
4367
4532
  children: [
4368
4533
  /* @__PURE__ */ jsx("span", { className: "gutter", "data-line-number": group.pair.right?.newNum ?? "" }),
4369
- /* @__PURE__ */ jsx("span", { className: "code", children: group.pair.right ? raw(escapeHtml(group.pair.right.content)) : "" })
4534
+ /* @__PURE__ */ jsx("span", { className: "code", children: group.pair.right?.content ?? "" })
4370
4535
  ]
4371
4536
  }
4372
4537
  )
@@ -4416,7 +4581,7 @@ function SplitDiff({ hunks, annotationsByLine }) {
4416
4581
  "data-new-line": pair.left?.newNum ?? pair.right?.newNum ?? "",
4417
4582
  children: [
4418
4583
  /* @__PURE__ */ jsx("span", { className: "gutter", "data-line-number": pair.left?.oldNum ?? "" }),
4419
- /* @__PURE__ */ jsx("span", { className: "code", children: pair.left ? raw(escapeHtml(pair.left.content)) : "" })
4584
+ /* @__PURE__ */ jsx("span", { className: "code", children: pair.left?.content ?? "" })
4420
4585
  ]
4421
4586
  }
4422
4587
  );
@@ -4461,7 +4626,7 @@ function SplitDiff({ hunks, annotationsByLine }) {
4461
4626
  "data-side": "new",
4462
4627
  children: [
4463
4628
  /* @__PURE__ */ jsx("span", { className: "gutter", "data-line-number": pair.right?.newNum ?? "" }),
4464
- /* @__PURE__ */ jsx("span", { className: "code", children: pair.right ? raw(escapeHtml(pair.right.content)) : "" })
4629
+ /* @__PURE__ */ jsx("span", { className: "code", children: pair.right?.content ?? "" })
4465
4630
  ]
4466
4631
  }
4467
4632
  );
@@ -4543,7 +4708,7 @@ function UnifiedDiff({ hunks, annotationsByLine }) {
4543
4708
  children: [
4544
4709
  /* @__PURE__ */ jsx("span", { className: "gutter-old", "data-line-number": line.oldNum ?? "" }),
4545
4710
  /* @__PURE__ */ jsx("span", { className: "gutter-new", "data-line-number": line.newNum ?? "" }),
4546
- /* @__PURE__ */ jsx("span", { className: "code", children: raw(escapeHtml(line.content)) })
4711
+ /* @__PURE__ */ jsx("span", { className: "code", children: line.content })
4547
4712
  ]
4548
4713
  }
4549
4714
  ),
@@ -4567,8 +4732,8 @@ function AnnotationRows({ annotations }) {
4567
4732
  /* @__PURE__ */ jsx("span", { className: "annotation-text", children: a.content }),
4568
4733
  /* @__PURE__ */ jsx("div", { className: "annotation-actions", children: [
4569
4734
  a.is_stale ? /* @__PURE__ */ jsx("button", { className: "btn btn-xs btn-keep", "data-action": "keep", children: "Keep" }) : null,
4570
- /* @__PURE__ */ jsx("button", { className: "btn btn-xs btn-icon", "data-action": "edit", title: "Edit", children: raw('<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.85 2.85 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/><path d="m15 5 4 4"/></svg>') }),
4571
- /* @__PURE__ */ jsx("button", { className: "btn btn-xs btn-icon btn-danger", "data-action": "delete", title: "Delete", children: raw('<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/><line x1="10" y1="11" x2="10" y2="17"/><line x1="14" y1="11" x2="14" y2="17"/></svg>') })
4735
+ /* @__PURE__ */ jsx("button", { className: "btn btn-xs btn-icon", "data-action": "edit", title: "Edit", children: /* @__PURE__ */ jsx(IconEdit, {}) }),
4736
+ /* @__PURE__ */ jsx("button", { className: "btn btn-xs btn-icon btn-danger", "data-action": "delete", title: "Delete", children: /* @__PURE__ */ jsx(IconTrash, {}) })
4572
4737
  ] })
4573
4738
  ]
4574
4739
  }
@@ -4678,7 +4843,6 @@ function Layout({ title, reviewId, children }) {
4678
4843
  function titleCase(s) {
4679
4844
  return s.replace(/[_-]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
4680
4845
  }
4681
- var trashIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/><line x1="10" y1="11" x2="10" y2="17"/><line x1="14" y1="11" x2="14" y2="17"/></svg>';
4682
4846
  function shortenArgs(args) {
4683
4847
  const shaPattern = /\b([0-9a-f]{7,40})\b/gi;
4684
4848
  const result = { hasLong: false };
@@ -4726,7 +4890,7 @@ function ReviewHistory({ reviews, currentReviewId }) {
4726
4890
  " | Created: ",
4727
4891
  r.created_at
4728
4892
  ] }),
4729
- !isCurrent ? /* @__PURE__ */ jsx("button", { className: "delete-review-btn", "data-delete-id": r.id, title: "Delete review", children: raw(trashIcon) }) : null
4893
+ !isCurrent ? /* @__PURE__ */ jsx("button", { className: "delete-review-btn", "data-delete-id": r.id, title: "Delete review", children: /* @__PURE__ */ jsx(IconTrash16, {}) }) : null
4730
4894
  ] }) }),
4731
4895
  isCurrent && hasOtherReviews ? /* @__PURE__ */ jsx("div", { className: "bulk-actions", children: [
4732
4896
  /* @__PURE__ */ jsx("span", { children: "Bulk actions:" }),
@@ -4736,94 +4900,12 @@ function ReviewHistory({ reviews, currentReviewId }) {
4736
4900
  ] });
4737
4901
  }) }),
4738
4902
  /* @__PURE__ */ jsx("a", { href: "/", className: "btn btn-link", style: "margin-top:16px;display:inline-block", children: "Back to current review" }),
4739
- /* @__PURE__ */ jsx("script", { children: raw(getHistoryScript()) })
4903
+ /* @__PURE__ */ jsx("script", { src: "/static/history.js" })
4740
4904
  ] });
4741
4905
  }
4742
- function getHistoryScript() {
4743
- return `
4744
- (function() {
4745
- function esc(s) {
4746
- var d = document.createElement('div');
4747
- d.textContent = s;
4748
- return d.innerHTML;
4749
- }
4750
-
4751
- function updateBulkVisibility() {
4752
- var bulk = document.querySelector('.bulk-actions');
4753
- if (bulk && !document.querySelector('.delete-review-btn')) {
4754
- bulk.remove();
4755
- }
4756
- }
4757
-
4758
- // Single review delete
4759
- document.querySelectorAll('.delete-review-btn').forEach(function(btn) {
4760
- btn.addEventListener('click', function(e) {
4761
- e.preventDefault();
4762
- e.stopPropagation();
4763
- var id = btn.dataset.deleteId;
4764
- showConfirm('Delete this review? This cannot be undone.', function() {
4765
- fetch('/api/review/' + encodeURIComponent(id), { method: 'DELETE' })
4766
- .then(function(r) { return r.json(); })
4767
- .then(function() {
4768
- btn.closest('.history-item-link').parentElement.remove();
4769
- updateBulkVisibility();
4770
- });
4771
- });
4772
- });
4773
- });
4774
-
4775
- // Bulk delete completed
4776
- var delCompletedBtn = document.getElementById('delete-completed-btn');
4777
- if (delCompletedBtn) {
4778
- delCompletedBtn.addEventListener('click', function() {
4779
- showConfirm('Delete all completed reviews (except current)? This cannot be undone.', function() {
4780
- fetch('/api/reviews/delete-completed', { method: 'POST', headers: { 'Content-Type': 'application/json' } })
4781
- .then(function(r) { return r.json(); })
4782
- .then(function() { location.reload(); });
4783
- });
4784
- });
4785
- }
4786
-
4787
- // Bulk delete all
4788
- var delAllBtn = document.getElementById('delete-all-btn');
4789
- if (delAllBtn) {
4790
- delAllBtn.addEventListener('click', function() {
4791
- showConfirm('Delete ALL reviews except the current one? This cannot be undone.', function() {
4792
- fetch('/api/reviews/delete-all', { method: 'POST', headers: { 'Content-Type': 'application/json' } })
4793
- .then(function(r) { return r.json(); })
4794
- .then(function() { location.reload(); });
4795
- });
4796
- });
4797
- }
4798
-
4799
- function showConfirm(message, onConfirm) {
4800
- var overlay = document.createElement('div');
4801
- overlay.className = 'modal-overlay';
4802
- overlay.innerHTML =
4803
- '<div class="modal">' +
4804
- '<h3>Confirm</h3>' +
4805
- '<p>' + esc(message) + '</p>' +
4806
- '<div class="modal-actions">' +
4807
- '<button class="btn btn-sm modal-cancel">Cancel</button>' +
4808
- '<button class="btn btn-sm btn-danger modal-confirm">Delete</button>' +
4809
- '</div>' +
4810
- '</div>';
4811
- overlay.querySelector('.modal-cancel').addEventListener('click', function() { overlay.remove(); });
4812
- overlay.querySelector('.modal-confirm').addEventListener('click', function() { overlay.remove(); onConfirm(); });
4813
- overlay.addEventListener('click', function(e) { if (e.target === overlay) overlay.remove(); });
4814
- document.body.appendChild(overlay);
4815
- }
4816
- })();
4817
- `;
4818
- }
4819
4906
 
4820
4907
  // src/routes/pages.tsx
4821
4908
  init_queries();
4822
- var zoomOutSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/></svg>';
4823
- var zoomInSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>';
4824
- var actualSizeSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><text x="12" y="15.5" text-anchor="middle" font-size="9" font-weight="bold" fill="currentColor" stroke="none">1:1</text></svg>';
4825
- var fitSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M9 21H3v-6"/><path d="M21 3l-7 7"/><path d="M3 21l7-7"/></svg>';
4826
- var revealSvgIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/><line x1="12" y1="11" x2="12" y2="17"/><polyline points="9 14 12 11 15 14"/></svg>';
4827
4909
  var pageRoutes = new Hono3();
4828
4910
  pageRoutes.get("/", async (c) => {
4829
4911
  const reviewId = c.get("reviewId");
@@ -4894,10 +4976,10 @@ pageRoutes.get("/", async (c) => {
4894
4976
  /* @__PURE__ */ jsx("button", { className: "segment", "data-image-mode": "image", style: "display:none", children: "Image" })
4895
4977
  ] }) }),
4896
4978
  /* @__PURE__ */ jsx("div", { className: "diff-toolbar-right", children: [
4897
- /* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "out", title: "Zoom out", children: raw(zoomOutSvg) }),
4898
- /* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "fit", title: "Fit to view", children: raw(fitSvg) }),
4899
- /* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "actual", title: "Actual size (1:1)", children: raw(actualSizeSvg) }),
4900
- /* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "in", title: "Zoom in", children: raw(zoomInSvg) })
4979
+ /* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "out", title: "Zoom out", children: /* @__PURE__ */ jsx(IconZoomOut, {}) }),
4980
+ /* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "fit", title: "Fit to view", children: /* @__PURE__ */ jsx(IconFit, {}) }),
4981
+ /* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "actual", title: "Actual size (1:1)", children: /* @__PURE__ */ jsx(IconActualSize, {}) }),
4982
+ /* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "in", title: "Zoom in", children: /* @__PURE__ */ jsx(IconZoomIn, {}) })
4901
4983
  ] })
4902
4984
  ] })
4903
4985
  ] })
@@ -4938,7 +5020,7 @@ pageRoutes.get("/file/:fileId", async (c) => {
4938
5020
  /* @__PURE__ */ jsx("div", { className: "diff-header", children: [
4939
5021
  /* @__PURE__ */ jsx("div", { className: "diff-header-file", children: [
4940
5022
  /* @__PURE__ */ jsx("span", { className: "file-path", children: diff.filePath }),
4941
- /* @__PURE__ */ jsx("button", { className: "reveal-btn", "data-file-id": file.id, title: "Reveal in file manager", children: raw(revealSvgIcon) })
5023
+ /* @__PURE__ */ jsx("button", { className: "reveal-btn", "data-file-id": file.id, title: "Reveal in file manager", children: /* @__PURE__ */ jsx(IconReveal, {}) })
4942
5024
  ] }),
4943
5025
  /* @__PURE__ */ jsx("div", { className: "diff-header-actions", children: /* @__PURE__ */ jsx("span", { className: `file-status ${diff.status}`, children: diff.status }) })
4944
5026
  ] }),
@@ -5045,10 +5127,10 @@ pageRoutes.get("/review/:reviewId", async (c) => {
5045
5127
  /* @__PURE__ */ jsx("button", { className: "segment", "data-image-mode": "image", style: "display:none", children: "Image" })
5046
5128
  ] }) }),
5047
5129
  /* @__PURE__ */ jsx("div", { className: "diff-toolbar-right", children: [
5048
- /* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "out", title: "Zoom out", children: raw(zoomOutSvg) }),
5049
- /* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "fit", title: "Fit to view", children: raw(fitSvg) }),
5050
- /* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "actual", title: "Actual size (1:1)", children: raw(actualSizeSvg) }),
5051
- /* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "in", title: "Zoom in", children: raw(zoomInSvg) })
5130
+ /* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "out", title: "Zoom out", children: /* @__PURE__ */ jsx(IconZoomOut, {}) }),
5131
+ /* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "fit", title: "Fit to view", children: /* @__PURE__ */ jsx(IconFit, {}) }),
5132
+ /* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "actual", title: "Actual size (1:1)", children: /* @__PURE__ */ jsx(IconActualSize, {}) }),
5133
+ /* @__PURE__ */ jsx("button", { className: "image-zoom-btn", "data-zoom-action": "in", title: "Zoom in", children: /* @__PURE__ */ jsx(IconZoomIn, {}) })
5052
5134
  ] })
5053
5135
  ] })
5054
5136
  ] })
@@ -5099,6 +5181,10 @@ async function startServer(port, reviewId, repoRoot, options) {
5099
5181
  const js = readFileSync8(join7(distDir, "app.global.js"), "utf-8");
5100
5182
  return c.text(js, 200, { "Content-Type": "application/javascript", "Cache-Control": "no-cache" });
5101
5183
  });
5184
+ app.get("/static/history.js", (c) => {
5185
+ const js = readFileSync8(join7(distDir, "history.global.js"), "utf-8");
5186
+ return c.text(js, 200, { "Content-Type": "application/javascript", "Cache-Control": "no-cache" });
5187
+ });
5102
5188
  app.route("/api", apiRoutes);
5103
5189
  app.route("/api/ai", aiApiRoutes);
5104
5190
  app.route("/", pageRoutes);
@@ -5503,7 +5589,7 @@ async function main() {
5503
5589
  console.log("AI service test mode enabled \u2014 using mock AI responses");
5504
5590
  }
5505
5591
  if (debug) {
5506
- console.log(`[debug] Build timestamp: ${"2026-03-20T01:33:08.659Z"}`);
5592
+ console.log(`[debug] Build timestamp: ${"2026-03-21T03:42:45.606Z"}`);
5507
5593
  }
5508
5594
  if (projectDir) {
5509
5595
  process.chdir(projectDir);