glitchgrab 1.44.0 → 1.45.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/dist/index.js CHANGED
@@ -770,7 +770,9 @@ async function assistTurn(params, token, baseUrl) {
770
770
  conversationId: null,
771
771
  question: null,
772
772
  report: null,
773
- degraded: (_a = envelope == null ? void 0 : envelope.error) != null ? _a : offline.degraded
773
+ degraded: (_a = envelope == null ? void 0 : envelope.error) != null ? _a : offline.degraded,
774
+ // An hourly limit, not a cap: the dialog keeps the assistant button.
775
+ retryable: (envelope == null ? void 0 : envelope.retryable) === true
774
776
  };
775
777
  }
776
778
  return {
@@ -1367,6 +1369,59 @@ var SEVERITY_LABELS = {
1367
1369
  };
1368
1370
  var MAX_ASSIST_IMAGES = 3;
1369
1371
  var MAX_ASSIST_IMAGE_CHARS = 35e5;
1372
+ var MAX_ASSIST_FILES = 3;
1373
+ var MAX_ASSIST_FILE_CHARS = 3e5;
1374
+ var MAX_ASSIST_FILE_CHARS_EACH = 2e5;
1375
+ var TEXT_ATTACHMENT_EXTENSIONS = [
1376
+ ".html",
1377
+ ".htm",
1378
+ ".txt",
1379
+ ".md",
1380
+ ".json",
1381
+ ".xml",
1382
+ ".log",
1383
+ ".yml",
1384
+ ".yaml",
1385
+ ".csv",
1386
+ ".har",
1387
+ ".js",
1388
+ ".mjs",
1389
+ ".cjs",
1390
+ ".ts",
1391
+ ".tsx",
1392
+ ".jsx",
1393
+ ".css",
1394
+ ".scss",
1395
+ ".py",
1396
+ ".sh"
1397
+ ];
1398
+ var BINARY_ATTACHMENT_EXTENSIONS = [".pdf", ".doc", ".docx", ".xls", ".xlsx", ".zip"];
1399
+ var ATTACHMENT_ACCEPT = [
1400
+ "image/*",
1401
+ ...TEXT_ATTACHMENT_EXTENSIONS,
1402
+ ...BINARY_ATTACHMENT_EXTENSIONS
1403
+ ].join(",");
1404
+ var ASSIST_ATTACHMENT_ACCEPT = ["image/*", ...TEXT_ATTACHMENT_EXTENSIONS].join(",");
1405
+ function isAssistReadableFile(name) {
1406
+ const lower = name.toLowerCase();
1407
+ return TEXT_ATTACHMENT_EXTENSIONS.some((ext) => lower.endsWith(ext));
1408
+ }
1409
+ function decodeTextDataUrl(dataUrl) {
1410
+ try {
1411
+ if (!dataUrl.startsWith("data:")) return null;
1412
+ const comma = dataUrl.indexOf(",");
1413
+ if (comma < 0) return null;
1414
+ const meta = dataUrl.slice(5, comma);
1415
+ const payload = dataUrl.slice(comma + 1);
1416
+ if (!meta.endsWith(";base64")) return decodeURIComponent(payload);
1417
+ const binary = atob(payload);
1418
+ const bytes = new Uint8Array(binary.length);
1419
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
1420
+ return new TextDecoder("utf-8").decode(bytes);
1421
+ } catch (e) {
1422
+ return null;
1423
+ }
1424
+ }
1370
1425
  function getTypeLabel(type) {
1371
1426
  switch (type) {
1372
1427
  case "RATING":
@@ -1398,6 +1453,22 @@ function pickAssistImages(all) {
1398
1453
  }
1399
1454
  return picked;
1400
1455
  }
1456
+ var NO_FILES = [];
1457
+ function pickAssistFiles(files) {
1458
+ const picked = [];
1459
+ let total = 0;
1460
+ for (let i = files.length - 1; i >= 0 && picked.length < MAX_ASSIST_FILES; i--) {
1461
+ const attached = files[i];
1462
+ if (!isAssistReadableFile(attached.name)) continue;
1463
+ const text = decodeTextDataUrl(attached.dataUrl);
1464
+ if (!text || !text.trim()) continue;
1465
+ const content = text.slice(0, MAX_ASSIST_FILE_CHARS_EACH);
1466
+ if (total + content.length > MAX_ASSIST_FILE_CHARS) continue;
1467
+ picked.unshift({ index: i, file: { name: attached.name, content } });
1468
+ total += content.length;
1469
+ }
1470
+ return picked;
1471
+ }
1401
1472
  var STARTERS = [
1402
1473
  "Something on this page is broken",
1403
1474
  "It did the wrong thing",
@@ -1474,7 +1545,9 @@ function AssistSheet({
1474
1545
  theme: t2,
1475
1546
  screenshots,
1476
1547
  pageShot = null,
1477
- onAddImages,
1548
+ onAddFiles,
1549
+ files = NO_FILES,
1550
+ onRemoveFile,
1478
1551
  onRemoveImage,
1479
1552
  attachmentCount,
1480
1553
  context,
@@ -1545,6 +1618,8 @@ function AssistSheet({
1545
1618
  }
1546
1619
  }
1547
1620
  const readShots = new Set(pickAssistImages(screenshots));
1621
+ const sentFiles = (0, import_react3.useMemo)(() => pickAssistFiles(files), [files]);
1622
+ const readFiles = new Set(sentFiles.map((f) => f.index));
1548
1623
  function leave(type, detail) {
1549
1624
  logEvent(type, detail);
1550
1625
  flushEvents();
@@ -1558,10 +1633,10 @@ function AssistSheet({
1558
1633
  var _a;
1559
1634
  if (phase === "draft") (_a = draftRef.current) == null ? void 0 : _a.focus();
1560
1635
  }, [phase]);
1561
- function degradeKeepingEvents(events, message) {
1636
+ function degradeKeepingEvents(events, message, retryable) {
1562
1637
  if (events) eventsRef.current = [...events, ...eventsRef.current];
1563
1638
  flushEvents();
1564
- onDegrade(message);
1639
+ onDegrade(message, retryable);
1565
1640
  }
1566
1641
  async function runTurn(history2) {
1567
1642
  var _a, _b, _c, _d;
@@ -1579,6 +1654,9 @@ function AssistSheet({
1579
1654
  ),
1580
1655
  conversationId,
1581
1656
  screenshots: sent,
1657
+ // Only when there is something: an older server then sees the body
1658
+ // it always did.
1659
+ ...sentFiles.length > 0 ? { files: sentFiles.map((f) => f.file) } : {},
1582
1660
  context: {
1583
1661
  ...context != null ? context : {},
1584
1662
  imageSources: sent.map((shot) => pageShot && shot === pageShot ? "page" : "attached"),
@@ -1598,7 +1676,7 @@ function AssistSheet({
1598
1676
  setBusy(false);
1599
1677
  }
1600
1678
  if (result.degraded) {
1601
- degradeKeepingEvents(events, result.degraded);
1679
+ degradeKeepingEvents(events, result.degraded, result.retryable === true);
1602
1680
  return;
1603
1681
  }
1604
1682
  if (result.conversationId) {
@@ -2586,7 +2664,7 @@ function AssistSheet({
2586
2664
  // instead of remounting, and a draft is something you can
2587
2665
  // still reply to (#360), not a form that replaced the chat.
2588
2666
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
2589
- (screenshots.length > 0 || onAddImages) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2667
+ (screenshots.length > 0 || files.length > 0 || onAddFiles) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2590
2668
  "div",
2591
2669
  {
2592
2670
  style: {
@@ -2690,11 +2768,118 @@ function AssistSheet({
2690
2768
  `${i}-${shot.slice(-16)}`
2691
2769
  );
2692
2770
  }),
2693
- onAddImages && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2771
+ files.map((file, i) => {
2772
+ const read = readFiles.has(i);
2773
+ const why = read ? "the assistant reads this file" : isAssistReadableFile(file.name) ? "attached, but more than one message can carry, so the assistant is not reading it" : "attached to the report \u2014 the assistant can't read this kind of file";
2774
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2775
+ "div",
2776
+ {
2777
+ "data-gg-assist-file": "",
2778
+ "data-gg-assist-file-read": read ? "" : void 0,
2779
+ title: `${file.name} \u2014 ${why}`,
2780
+ style: {
2781
+ position: "relative",
2782
+ height: "40px",
2783
+ maxWidth: "170px",
2784
+ display: "flex",
2785
+ alignItems: "center",
2786
+ gap: "6px",
2787
+ padding: "0 10px",
2788
+ borderRadius: "8px",
2789
+ border: `1px solid ${read ? t2.accent : t2.inputBorder}`,
2790
+ opacity: read ? 1 : 0.55,
2791
+ boxSizing: "border-box",
2792
+ flexShrink: 0
2793
+ },
2794
+ children: [
2795
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", style: { flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2796
+ "path",
2797
+ {
2798
+ d: "M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z M14 2v6h6",
2799
+ stroke: t2.textMuted,
2800
+ strokeWidth: "1.5",
2801
+ strokeLinecap: "round",
2802
+ strokeLinejoin: "round"
2803
+ }
2804
+ ) }),
2805
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2806
+ "span",
2807
+ {
2808
+ style: {
2809
+ fontSize: "11.5px",
2810
+ color: t2.text,
2811
+ overflow: "hidden",
2812
+ textOverflow: "ellipsis",
2813
+ whiteSpace: "nowrap"
2814
+ },
2815
+ children: file.name
2816
+ }
2817
+ ),
2818
+ onRemoveFile && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2819
+ "button",
2820
+ {
2821
+ type: "button",
2822
+ "data-gg-assist-remove-file": "",
2823
+ "aria-label": `Remove file ${file.name}`,
2824
+ title: "Remove this file",
2825
+ onClick: () => {
2826
+ logEvent("file_removed", read ? "read" : "not read");
2827
+ onRemoveFile(i);
2828
+ },
2829
+ style: {
2830
+ position: "absolute",
2831
+ top: "-13px",
2832
+ right: "-13px",
2833
+ width: "32px",
2834
+ height: "32px",
2835
+ border: "none",
2836
+ background: "transparent",
2837
+ padding: 0,
2838
+ cursor: "pointer",
2839
+ display: "flex",
2840
+ alignItems: "center",
2841
+ justifyContent: "center",
2842
+ borderRadius: "50%"
2843
+ },
2844
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2845
+ "span",
2846
+ {
2847
+ "aria-hidden": "true",
2848
+ style: {
2849
+ width: "20px",
2850
+ height: "20px",
2851
+ boxSizing: "border-box",
2852
+ borderRadius: "50%",
2853
+ border: `2px solid ${t2.bg}`,
2854
+ background: "#ef4444",
2855
+ color: "#fff",
2856
+ display: "flex",
2857
+ alignItems: "center",
2858
+ justifyContent: "center"
2859
+ },
2860
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "8", height: "8", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2861
+ "path",
2862
+ {
2863
+ d: "M1 1L9 9M9 1L1 9",
2864
+ stroke: "currentColor",
2865
+ strokeWidth: "1.6",
2866
+ strokeLinecap: "round"
2867
+ }
2868
+ ) })
2869
+ }
2870
+ )
2871
+ }
2872
+ )
2873
+ ]
2874
+ },
2875
+ `file-${i}-${file.name}`
2876
+ );
2877
+ }),
2878
+ onAddFiles && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
2694
2879
  "label",
2695
2880
  {
2696
2881
  "data-gg-assist-attach": "",
2697
- title: "Attach an image \u2014 or just paste one",
2882
+ title: "Attach an image or a file (html, json, log\u2026) \u2014 or paste one",
2698
2883
  style: {
2699
2884
  width: "40px",
2700
2885
  height: "40px",
@@ -2714,14 +2899,18 @@ function AssistSheet({
2714
2899
  "input",
2715
2900
  {
2716
2901
  type: "file",
2717
- accept: "image/*",
2902
+ accept: ASSIST_ATTACHMENT_ACCEPT,
2718
2903
  multiple: true,
2719
2904
  onChange: (e) => {
2720
2905
  var _a;
2721
- const files = Array.from((_a = e.target.files) != null ? _a : []);
2722
- if (files.length) {
2723
- logEvent("image_added", String(files.length));
2724
- onAddImages(files);
2906
+ const picked = Array.from((_a = e.target.files) != null ? _a : []);
2907
+ if (picked.length) {
2908
+ const images = picked.filter((f) => f.type.startsWith("image/")).length;
2909
+ if (images) logEvent("image_added", String(images));
2910
+ if (picked.length > images) {
2911
+ logEvent("file_added", String(picked.length - images));
2912
+ }
2913
+ onAddFiles(picked);
2725
2914
  }
2726
2915
  e.target.value = "";
2727
2916
  },
@@ -2902,6 +3091,7 @@ function AssistSheet({
2902
3091
  }
2903
3092
  var FONT = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
2904
3093
  var FAILED = "Couldn't send it. Try again in a moment.";
3094
+ var MAX_SELF_REPORT_IMAGES = 5;
2905
3095
  function describeSentAlong(hasChat, screenshotCount) {
2906
3096
  const parts = [
2907
3097
  ...hasChat ? ["your AI chat"] : [],
@@ -2925,11 +3115,49 @@ function GlitchgrabProblemPanel({
2925
3115
  const [busy, setBusy] = (0, import_react4.useState)(false);
2926
3116
  const [sent, setSent] = (0, import_react4.useState)(false);
2927
3117
  const [error, setError] = (0, import_react4.useState)(null);
3118
+ const [images, setImages] = (0, import_react4.useState)(
3119
+ () => screenshots.slice(0, MAX_SELF_REPORT_IMAGES)
3120
+ );
2928
3121
  const inputRef = (0, import_react4.useRef)(null);
3122
+ const fileRef = (0, import_react4.useRef)(null);
2929
3123
  (0, import_react4.useEffect)(() => {
2930
3124
  var _a;
2931
3125
  (_a = inputRef.current) == null ? void 0 : _a.focus();
2932
3126
  }, []);
3127
+ const addImages = (0, import_react4.useCallback)((files) => {
3128
+ const picked = files.filter((file) => file.type.startsWith("image/"));
3129
+ if (!picked.length) return;
3130
+ void Promise.all(picked.map((file) => encodeImageFile(file).catch(() => null))).then(
3131
+ (encoded) => {
3132
+ const added = encoded.filter((url) => !!url);
3133
+ if (added.length) {
3134
+ setImages((prev) => [...prev, ...added].slice(0, MAX_SELF_REPORT_IMAGES));
3135
+ }
3136
+ }
3137
+ );
3138
+ }, []);
3139
+ (0, import_react4.useEffect)(() => {
3140
+ const onPaste = (e) => {
3141
+ var _a;
3142
+ try {
3143
+ const items = (_a = e.clipboardData) == null ? void 0 : _a.items;
3144
+ if (!items) return;
3145
+ const files = [];
3146
+ for (let i = 0; i < items.length; i++) {
3147
+ if (items[i].kind !== "file") continue;
3148
+ const file = items[i].getAsFile();
3149
+ if (file) files.push(file);
3150
+ }
3151
+ if (!files.length) return;
3152
+ e.preventDefault();
3153
+ e.stopImmediatePropagation();
3154
+ addImages(files);
3155
+ } catch (e2) {
3156
+ }
3157
+ };
3158
+ window.addEventListener("paste", onPaste, true);
3159
+ return () => window.removeEventListener("paste", onPaste, true);
3160
+ }, [addImages]);
2933
3161
  (0, import_react4.useEffect)(() => {
2934
3162
  const onKey = (e) => {
2935
3163
  if (e.key !== "Escape") return;
@@ -2945,7 +3173,13 @@ function GlitchgrabProblemPanel({
2945
3173
  setBusy(true);
2946
3174
  setError(null);
2947
3175
  try {
2948
- const result = await send({ description, surface, conversationId, reportType, screenshots });
3176
+ const result = await send({
3177
+ description,
3178
+ surface,
3179
+ conversationId,
3180
+ reportType,
3181
+ screenshots: images
3182
+ });
2949
3183
  if (result == null ? void 0 : result.success) setSent(true);
2950
3184
  else setError((result == null ? void 0 : result.message) || FAILED);
2951
3185
  } catch (e) {
@@ -3098,6 +3332,134 @@ function GlitchgrabProblemPanel({
3098
3332
  }
3099
3333
  }
3100
3334
  ),
3335
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
3336
+ "div",
3337
+ {
3338
+ "data-gg-self-report-images": "",
3339
+ style: {
3340
+ display: "flex",
3341
+ flexWrap: "wrap",
3342
+ alignItems: "center",
3343
+ gap: "8px",
3344
+ marginTop: "10px"
3345
+ },
3346
+ children: [
3347
+ images.map((src, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { position: "relative", width: "48px", height: "48px" }, children: [
3348
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3349
+ "img",
3350
+ {
3351
+ src,
3352
+ alt: `Screenshot ${i + 1}`,
3353
+ style: {
3354
+ width: "100%",
3355
+ height: "100%",
3356
+ objectFit: "cover",
3357
+ display: "block",
3358
+ boxSizing: "border-box",
3359
+ borderRadius: "8px",
3360
+ border: `1px solid ${t2.inputBorder}`
3361
+ }
3362
+ }
3363
+ ),
3364
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3365
+ "button",
3366
+ {
3367
+ type: "button",
3368
+ "data-gg-self-report-remove-image": "",
3369
+ "aria-label": `Remove screenshot ${i + 1}`,
3370
+ title: "Don't send this one",
3371
+ onClick: () => setImages((prev) => prev.filter((_, j) => j !== i)),
3372
+ style: {
3373
+ position: "absolute",
3374
+ top: "-13px",
3375
+ right: "-13px",
3376
+ width: "32px",
3377
+ height: "32px",
3378
+ border: "none",
3379
+ background: "transparent",
3380
+ padding: 0,
3381
+ cursor: "pointer",
3382
+ display: "flex",
3383
+ alignItems: "center",
3384
+ justifyContent: "center",
3385
+ borderRadius: "50%"
3386
+ },
3387
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3388
+ "span",
3389
+ {
3390
+ "aria-hidden": "true",
3391
+ style: {
3392
+ width: "20px",
3393
+ height: "20px",
3394
+ boxSizing: "border-box",
3395
+ borderRadius: "50%",
3396
+ border: `2px solid ${t2.bg}`,
3397
+ background: "#ef4444",
3398
+ color: "#fff",
3399
+ display: "flex",
3400
+ alignItems: "center",
3401
+ justifyContent: "center"
3402
+ },
3403
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { width: "8", height: "8", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3404
+ "path",
3405
+ {
3406
+ d: "M1 1L9 9M9 1L1 9",
3407
+ stroke: "currentColor",
3408
+ strokeWidth: "1.6",
3409
+ strokeLinecap: "round"
3410
+ }
3411
+ ) })
3412
+ }
3413
+ )
3414
+ }
3415
+ )
3416
+ ] }, i)),
3417
+ images.length < MAX_SELF_REPORT_IMAGES && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3418
+ "button",
3419
+ {
3420
+ type: "button",
3421
+ "data-gg-self-report-attach": "",
3422
+ "aria-label": "Add screenshot",
3423
+ title: "Add a screenshot \u2014 or paste one",
3424
+ onClick: () => {
3425
+ var _a;
3426
+ return (_a = fileRef.current) == null ? void 0 : _a.click();
3427
+ },
3428
+ style: {
3429
+ height: "48px",
3430
+ padding: "0 12px",
3431
+ boxSizing: "border-box",
3432
+ borderRadius: "8px",
3433
+ border: `1px dashed ${t2.inputBorder}`,
3434
+ background: "transparent",
3435
+ color: t2.textMuted,
3436
+ fontSize: "12.5px",
3437
+ fontWeight: 600,
3438
+ fontFamily: "inherit",
3439
+ cursor: "pointer"
3440
+ },
3441
+ children: images.length >= 3 ? "+ Add" : "+ Add screenshot"
3442
+ }
3443
+ ),
3444
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3445
+ "input",
3446
+ {
3447
+ ref: fileRef,
3448
+ type: "file",
3449
+ accept: "image/*",
3450
+ multiple: true,
3451
+ "data-gg-self-report-file": "",
3452
+ onChange: (e) => {
3453
+ var _a;
3454
+ addImages(Array.from((_a = e.target.files) != null ? _a : []));
3455
+ e.target.value = "";
3456
+ },
3457
+ style: { display: "none" }
3458
+ }
3459
+ )
3460
+ ]
3461
+ }
3462
+ ),
3101
3463
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
3102
3464
  "p",
3103
3465
  {
@@ -3106,7 +3468,7 @@ function GlitchgrabProblemPanel({
3106
3468
  children: [
3107
3469
  "Also sent, so we can see what happened:",
3108
3470
  " ",
3109
- describeSentAlong(conversationId !== null, screenshots.length),
3471
+ describeSentAlong(conversationId !== null, images.length),
3110
3472
  "."
3111
3473
  ]
3112
3474
  }
@@ -3147,38 +3509,6 @@ function isMac() {
3147
3509
  function getShortcutLabel() {
3148
3510
  return isMac() ? GLITCHGRAB_SHORTCUT_MAC : GLITCHGRAB_SHORTCUT;
3149
3511
  }
3150
- var ATTACHMENT_ACCEPT = [
3151
- "image/*",
3152
- // text — inlined into the issue body
3153
- ".html",
3154
- ".htm",
3155
- ".txt",
3156
- ".md",
3157
- ".json",
3158
- ".xml",
3159
- ".log",
3160
- ".yml",
3161
- ".yaml",
3162
- ".csv",
3163
- ".har",
3164
- ".js",
3165
- ".mjs",
3166
- ".cjs",
3167
- ".ts",
3168
- ".tsx",
3169
- ".jsx",
3170
- ".css",
3171
- ".scss",
3172
- ".py",
3173
- ".sh",
3174
- // binary documents
3175
- ".pdf",
3176
- ".doc",
3177
- ".docx",
3178
- ".xls",
3179
- ".xlsx",
3180
- ".zip"
3181
- ].join(",");
3182
3512
  var MAX_SCALE = 2;
3183
3513
  var FRAME_TIMEOUT_MS = 3e3;
3184
3514
  var GRAB_TIMEOUT_MS = FRAME_TIMEOUT_MS + 2e3;
@@ -6408,8 +6738,10 @@ function ReportDialog({
6408
6738
  theme: layerTheme,
6409
6739
  screenshots,
6410
6740
  pageShot,
6411
- onAddImages: addFiles,
6741
+ onAddFiles: addFiles,
6412
6742
  onRemoveImage: (index) => setScreenshots((prev) => prev.filter((_, i) => i !== index)),
6743
+ files: attachments,
6744
+ onRemoveFile: (index) => setAttachments((prev) => prev.filter((_, i) => i !== index)),
6413
6745
  attachmentCount: screenshots.length + attachments.length,
6414
6746
  context: { ...assistContext != null ? assistContext : {}, reportType },
6415
6747
  reportTypeLabel: getTypeLabel(reportType),
@@ -6451,9 +6783,9 @@ function ReportDialog({
6451
6783
  setSelfReportPrefill(prefill != null ? prefill : "");
6452
6784
  setSelfReportFrom("assist");
6453
6785
  } : void 0,
6454
- onDegrade: (message) => {
6786
+ onDegrade: (message, retryable) => {
6455
6787
  setAssistOpen(false);
6456
- setAssistUsed(true);
6788
+ if (!retryable) setAssistUsed(true);
6457
6789
  setAssistNotice(message);
6458
6790
  },
6459
6791
  onClose: () => {