glitchgrab 1.35.0 → 1.37.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
@@ -647,7 +647,7 @@ async function enhanceText(text, token, baseUrl, screenshot, context) {
647
647
  }
648
648
  }
649
649
  async function assistTurn(params, token, baseUrl) {
650
- var _a, _b, _c, _d, _e, _f, _g;
650
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
651
651
  const offline = {
652
652
  conversationId: null,
653
653
  question: null,
@@ -676,7 +676,10 @@ async function assistTurn(params, token, baseUrl) {
676
676
  return {
677
677
  conversationId: (_c = (_b = envelope.data) == null ? void 0 : _b.conversationId) != null ? _c : null,
678
678
  question: (_e = (_d = envelope.data) == null ? void 0 : _d.question) != null ? _e : null,
679
- report: (_g = (_f = envelope.data) == null ? void 0 : _f.report) != null ? _g : null,
679
+ options: (_g = (_f = envelope.data) == null ? void 0 : _f.options) != null ? _g : [],
680
+ report: (_i = (_h = envelope.data) == null ? void 0 : _h.report) != null ? _i : null,
681
+ duplicate: (_k = (_j = envelope.data) == null ? void 0 : _j.duplicate) != null ? _k : null,
682
+ solved: (_m = (_l = envelope.data) == null ? void 0 : _l.solved) != null ? _m : null,
680
683
  degraded: null
681
684
  };
682
685
  } catch (e) {
@@ -1203,6 +1206,26 @@ function AnnotationCanvas({ imageSrc, onSave, onCancel }) {
1203
1206
  }
1204
1207
  );
1205
1208
  }
1209
+ function getTypeLabel(type) {
1210
+ switch (type) {
1211
+ case "RATING":
1212
+ return "Rating";
1213
+ case "BUG":
1214
+ return "Bug Report";
1215
+ case "FEATURE_REQUEST":
1216
+ return "Feature Request";
1217
+ case "UI_IMPROVEMENT":
1218
+ return "UI Improvement";
1219
+ case "PERFORMANCE":
1220
+ return "Performance";
1221
+ case "SECURITY":
1222
+ return "Security";
1223
+ case "QUESTION":
1224
+ return "Question";
1225
+ case "OTHER":
1226
+ return "Other";
1227
+ }
1228
+ }
1206
1229
  var STARTERS = [
1207
1230
  "Something on this page is broken",
1208
1231
  "It did the wrong thing",
@@ -1281,6 +1304,12 @@ function AssistSheet({
1281
1304
  attachmentCount,
1282
1305
  context,
1283
1306
  reportTypeLabel,
1307
+ typePicked,
1308
+ currentTile,
1309
+ tiles,
1310
+ onPickType,
1311
+ rating,
1312
+ onRatingChange,
1284
1313
  projectSlot,
1285
1314
  reporterName,
1286
1315
  description,
@@ -1288,18 +1317,27 @@ function AssistSheet({
1288
1317
  severity,
1289
1318
  onSeverityChange,
1290
1319
  showSeverity,
1320
+ onDuplicateChange,
1321
+ onConversationChange,
1291
1322
  isSubmitting,
1292
1323
  submitted,
1293
1324
  onSend,
1294
1325
  onDegrade,
1295
- onClose
1326
+ onClose,
1327
+ onFinish
1296
1328
  }) {
1297
1329
  const narrow = useIsNarrow();
1298
1330
  const [messages, setMessages] = (0, import_react3.useState)([]);
1299
1331
  const [input, setInput] = (0, import_react3.useState)("");
1300
1332
  const [busy, setBusy] = (0, import_react3.useState)(false);
1301
1333
  const [conversationId, setConversationId] = (0, import_react3.useState)(null);
1302
- const [phase, setPhase] = (0, import_react3.useState)("chat");
1334
+ const [hoveredStar, setHoveredStar] = (0, import_react3.useState)(0);
1335
+ const [options, setOptions] = (0, import_react3.useState)([]);
1336
+ const [duplicate, setDuplicate] = (0, import_react3.useState)(null);
1337
+ const [solved, setSolved] = (0, import_react3.useState)(null);
1338
+ const [phase, setPhase] = (0, import_react3.useState)(
1339
+ !typePicked ? "type" : currentTile === "RATING" ? "rating" : "chat"
1340
+ );
1303
1341
  const scrollRef = (0, import_react3.useRef)(null);
1304
1342
  const inputRef = (0, import_react3.useRef)(null);
1305
1343
  const draftRef = (0, import_react3.useRef)(null);
@@ -1313,6 +1351,7 @@ function AssistSheet({
1313
1351
  if (phase === "draft") (_a = draftRef.current) == null ? void 0 : _a.focus();
1314
1352
  }, [phase]);
1315
1353
  async function runTurn(history2) {
1354
+ var _a, _b, _c, _d;
1316
1355
  setBusy(true);
1317
1356
  let result;
1318
1357
  try {
@@ -1327,15 +1366,28 @@ function AssistSheet({
1327
1366
  onDegrade(result.degraded);
1328
1367
  return;
1329
1368
  }
1330
- if (result.conversationId) setConversationId(result.conversationId);
1369
+ if (result.conversationId) {
1370
+ setConversationId(result.conversationId);
1371
+ onConversationChange == null ? void 0 : onConversationChange(result.conversationId);
1372
+ }
1373
+ setDuplicate((_a = result.duplicate) != null ? _a : null);
1374
+ onDuplicateChange == null ? void 0 : onDuplicateChange((_c = (_b = result.duplicate) == null ? void 0 : _b.number) != null ? _c : null);
1375
+ if (result.solved) {
1376
+ setSolved(result.solved);
1377
+ setOptions([]);
1378
+ setPhase("solved");
1379
+ return;
1380
+ }
1331
1381
  if (result.report) {
1332
1382
  onDescriptionChange(result.report);
1333
1383
  setMessages([...history2, { role: "assistant", content: "Here's your report \u2014 have a read." }]);
1384
+ setOptions([]);
1334
1385
  setPhase("draft");
1335
1386
  return;
1336
1387
  }
1337
1388
  if (result.question) {
1338
1389
  setMessages([...history2, { role: "assistant", content: result.question }]);
1390
+ setOptions((_d = result.options) != null ? _d : []);
1339
1391
  return;
1340
1392
  }
1341
1393
  onDegrade("The assistant had nothing to add \u2014 write your report below and send it as normal.");
@@ -1343,6 +1395,7 @@ function AssistSheet({
1343
1395
  (0, import_react3.useEffect)(() => {
1344
1396
  if (seededRef.current) return;
1345
1397
  seededRef.current = true;
1398
+ if (!typePicked || currentTile === "RATING") return;
1346
1399
  const seed = description.trim();
1347
1400
  if (!seed) return;
1348
1401
  const history2 = [{ role: "user", content: seed }];
@@ -1352,12 +1405,17 @@ function AssistSheet({
1352
1405
  function send(text) {
1353
1406
  const value = text.trim();
1354
1407
  if (!value || busy) return;
1408
+ setOptions([]);
1355
1409
  const history2 = [...messages, { role: "user", content: value }];
1356
1410
  setMessages(history2);
1357
1411
  setInput("");
1358
1412
  void runTurn(history2);
1359
1413
  }
1360
- const empty = messages.length === 0 && !busy;
1414
+ function pickType(tile) {
1415
+ onPickType(tile);
1416
+ setPhase(tile === "RATING" ? "rating" : "chat");
1417
+ }
1418
+ const empty = phase === "chat" && messages.length === 0 && !busy;
1361
1419
  const initials = (reporterName != null ? reporterName : "").split(/\s+/).filter(Boolean).slice(0, 2).map((w) => {
1362
1420
  var _a, _b;
1363
1421
  return (_b = (_a = w[0]) == null ? void 0 : _a.toUpperCase()) != null ? _b : "";
@@ -1473,7 +1531,7 @@ function AssistSheet({
1473
1531
  }
1474
1532
  ),
1475
1533
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { fontSize: "11.5px", color: t2.textMuted, marginTop: "3px" }, children: [
1476
- reportTypeLabel,
1534
+ phase === "type" ? null : reportTypeLabel,
1477
1535
  projectSlot ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { marginLeft: "6px" }, children: projectSlot }) : null
1478
1536
  ] })
1479
1537
  ] }),
@@ -1481,20 +1539,24 @@ function AssistSheet({
1481
1539
  "button",
1482
1540
  {
1483
1541
  type: "button",
1542
+ "data-gg-write-myself": "",
1484
1543
  onClick: onClose,
1485
- "aria-label": "Close and write it myself",
1544
+ "aria-label": "Write it myself instead",
1486
1545
  style: {
1487
1546
  flexShrink: 0,
1488
- border: "none",
1547
+ border: `1px solid ${t2.inputBorder}`,
1548
+ borderRadius: "999px",
1489
1549
  background: "transparent",
1490
1550
  color: t2.textMuted,
1491
1551
  cursor: "pointer",
1492
- fontSize: narrow ? "18px" : "12px",
1552
+ fontSize: "11.5px",
1493
1553
  lineHeight: 1,
1494
1554
  fontFamily: "inherit",
1495
- padding: narrow ? "4px 6px" : "6px 4px"
1555
+ whiteSpace: "nowrap",
1556
+ // ~32px tall either way — this is the escape hatch, not a hint.
1557
+ padding: "9px 11px"
1496
1558
  },
1497
- children: narrow ? "\xD7" : "Write it myself"
1559
+ children: "Write it myself"
1498
1560
  }
1499
1561
  )
1500
1562
  ]
@@ -1523,6 +1585,182 @@ function AssistSheet({
1523
1585
  minWidth: 0
1524
1586
  },
1525
1587
  children: [
1588
+ phase === "type" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
1589
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
1590
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Avatar, { who: "assistant", theme: t2 }),
1591
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1592
+ "div",
1593
+ {
1594
+ style: {
1595
+ padding: "9px 12px",
1596
+ borderRadius: "12px 12px 12px 4px",
1597
+ backgroundColor: t2.bgSecondary,
1598
+ fontSize: "13px",
1599
+ lineHeight: 1.55,
1600
+ maxWidth: "88%"
1601
+ },
1602
+ children: [
1603
+ reporterName ? `Hi ${reporterName.split(" ")[0]} \u2014 w` : "W",
1604
+ "hat do you want to do? Pick one and I'll take it from there."
1605
+ ]
1606
+ }
1607
+ )
1608
+ ] }),
1609
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1610
+ "div",
1611
+ {
1612
+ style: {
1613
+ display: "flex",
1614
+ flexWrap: "wrap",
1615
+ gap: "6px",
1616
+ paddingLeft: "32px"
1617
+ },
1618
+ children: tiles.map((tile) => {
1619
+ const rate = tile === "RATING";
1620
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1621
+ "button",
1622
+ {
1623
+ type: "button",
1624
+ "data-gg-chip": "",
1625
+ "data-gg-tile": tile,
1626
+ onClick: () => pickType(tile),
1627
+ style: {
1628
+ display: "inline-flex",
1629
+ alignItems: "center",
1630
+ gap: "5px",
1631
+ // The rating is the only tile that isn't a report, so
1632
+ // it wears the star colour the dialog's hero row uses
1633
+ // rather than hiding among the report types.
1634
+ border: `1px solid ${rate ? "rgba(245,158,11,0.5)" : t2.inputBorder}`,
1635
+ background: rate ? "rgba(245,158,11,0.08)" : "transparent",
1636
+ color: rate ? "#f59e0b" : t2.textMuted,
1637
+ borderRadius: "999px",
1638
+ // 8px vertical keeps the tap target at ~32px.
1639
+ padding: "8px 12px",
1640
+ fontSize: "12px",
1641
+ fontWeight: rate ? 600 : 400,
1642
+ fontFamily: "inherit",
1643
+ cursor: "pointer"
1644
+ },
1645
+ children: rate ? "\u2605 Rate us" : getTypeLabel(tile)
1646
+ },
1647
+ tile
1648
+ );
1649
+ })
1650
+ }
1651
+ )
1652
+ ] }),
1653
+ phase === "rating" && !submitted && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
1654
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
1655
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Avatar, { who: "assistant", theme: t2 }),
1656
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1657
+ "div",
1658
+ {
1659
+ style: {
1660
+ padding: "9px 12px",
1661
+ borderRadius: "12px 12px 12px 4px",
1662
+ backgroundColor: t2.bgSecondary,
1663
+ fontSize: "13px",
1664
+ lineHeight: 1.55,
1665
+ maxWidth: "88%"
1666
+ },
1667
+ children: "How are we doing? Tap a star \u2014 the words are optional."
1668
+ }
1669
+ )
1670
+ ] }),
1671
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1672
+ "div",
1673
+ {
1674
+ style: {
1675
+ display: "flex",
1676
+ flexDirection: "column",
1677
+ gap: "10px",
1678
+ marginLeft: "32px",
1679
+ padding: "12px",
1680
+ borderRadius: "12px",
1681
+ border: "1px solid rgba(245,158,11,0.4)",
1682
+ backgroundColor: "rgba(245,158,11,0.06)"
1683
+ },
1684
+ children: [
1685
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", gap: "4px" }, role: "group", "aria-label": "Rating", children: [1, 2, 3, 4, 5].map((star) => {
1686
+ const filled = star <= (hoveredStar || rating);
1687
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1688
+ "button",
1689
+ {
1690
+ type: "button",
1691
+ "aria-label": `${star} star${star > 1 ? "s" : ""}`,
1692
+ "aria-pressed": star <= rating,
1693
+ onClick: () => onRatingChange(star),
1694
+ onMouseEnter: () => setHoveredStar(star),
1695
+ onMouseLeave: () => setHoveredStar(0),
1696
+ style: {
1697
+ border: "none",
1698
+ background: "transparent",
1699
+ padding: 0,
1700
+ cursor: "pointer",
1701
+ lineHeight: 0
1702
+ },
1703
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "30", height: "30", viewBox: "0 0 24 24", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1704
+ "path",
1705
+ {
1706
+ d: "M12 3l2.6 5.3 5.9.9-4.3 4.1 1 5.8L12 16.4 6.8 19.1l1-5.8L3.5 9.2l5.9-.9L12 3z",
1707
+ fill: filled ? "#f59e0b" : "transparent",
1708
+ stroke: filled ? "#f59e0b" : t2.inputBorder,
1709
+ strokeWidth: "1.5",
1710
+ strokeLinejoin: "round"
1711
+ }
1712
+ ) })
1713
+ },
1714
+ star
1715
+ );
1716
+ }) }),
1717
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1718
+ "textarea",
1719
+ {
1720
+ value: description,
1721
+ onChange: (e) => onDescriptionChange(e.target.value),
1722
+ rows: 3,
1723
+ placeholder: "What made it good \u2014 or what let you down? (optional)",
1724
+ style: {
1725
+ width: "100%",
1726
+ padding: "10px",
1727
+ borderRadius: "8px",
1728
+ border: `1px solid ${t2.inputBorder}`,
1729
+ backgroundColor: t2.inputBg,
1730
+ color: t2.text,
1731
+ fontSize: "13px",
1732
+ lineHeight: 1.5,
1733
+ fontFamily: "inherit",
1734
+ resize: "vertical",
1735
+ outline: "none",
1736
+ boxSizing: "border-box"
1737
+ }
1738
+ }
1739
+ ),
1740
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1741
+ "button",
1742
+ {
1743
+ type: "button",
1744
+ onClick: () => setPhase("type"),
1745
+ style: {
1746
+ alignSelf: "flex-start",
1747
+ border: "none",
1748
+ background: "transparent",
1749
+ color: t2.textMuted,
1750
+ fontSize: "12px",
1751
+ fontFamily: "inherit",
1752
+ // A bare text link is ~14px tall — half a thumb.
1753
+ padding: "9px 0",
1754
+ cursor: "pointer",
1755
+ textDecoration: "underline"
1756
+ },
1757
+ children: "Report something instead"
1758
+ }
1759
+ )
1760
+ ]
1761
+ }
1762
+ )
1763
+ ] }),
1526
1764
  empty && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
1527
1765
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
1528
1766
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Avatar, { who: "assistant", theme: t2 }),
@@ -1611,6 +1849,47 @@ function AssistSheet({
1611
1849
  i
1612
1850
  );
1613
1851
  }),
1852
+ options.length > 0 && !busy && phase === "chat" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1853
+ "div",
1854
+ {
1855
+ style: {
1856
+ display: "flex",
1857
+ // Long labels wrapped into a ragged row that always stranded
1858
+ // the last chip on a line of its own. Past ~24 characters
1859
+ // these stop being chips and become a choice list, so they
1860
+ // stack full width and read like one.
1861
+ flexDirection: options.some((o) => o.length > 24) ? "column" : "row",
1862
+ alignItems: options.some((o) => o.length > 24) ? "stretch" : "flex-start",
1863
+ flexWrap: "wrap",
1864
+ gap: "6px",
1865
+ paddingLeft: "32px"
1866
+ },
1867
+ children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1868
+ "button",
1869
+ {
1870
+ type: "button",
1871
+ "data-gg-chip": "",
1872
+ "data-gg-option": "",
1873
+ onClick: () => send(option),
1874
+ style: {
1875
+ border: `1px solid ${t2.inputBorder}`,
1876
+ background: "transparent",
1877
+ color: t2.textMuted,
1878
+ borderRadius: "999px",
1879
+ // Same 8px as the picker chips — one tap target size in
1880
+ // this sheet, not two.
1881
+ padding: "8px 12px",
1882
+ fontSize: "12px",
1883
+ fontFamily: "inherit",
1884
+ cursor: "pointer",
1885
+ textAlign: "left"
1886
+ },
1887
+ children: option
1888
+ },
1889
+ option
1890
+ ))
1891
+ }
1892
+ ),
1614
1893
  busy && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "8px" }, role: "status", "aria-label": "Thinking", children: [
1615
1894
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Avatar, { who: "assistant", theme: t2 }),
1616
1895
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
@@ -1668,6 +1947,32 @@ function AssistSheet({
1668
1947
  children: "Your report \xB7 edit anything"
1669
1948
  }
1670
1949
  ),
1950
+ duplicate && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1951
+ "div",
1952
+ {
1953
+ style: {
1954
+ display: "flex",
1955
+ flexDirection: "column",
1956
+ gap: "3px",
1957
+ padding: "9px 10px",
1958
+ borderRadius: "8px",
1959
+ border: "1px solid rgba(245,158,11,0.4)",
1960
+ backgroundColor: "rgba(245,158,11,0.08)",
1961
+ fontSize: "12px",
1962
+ lineHeight: 1.5
1963
+ },
1964
+ children: [
1965
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#f59e0b", fontWeight: 600 }, children: "Our team is already on this" }),
1966
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { color: t2.textMuted, wordBreak: "break-word" }, children: [
1967
+ "#",
1968
+ duplicate.number,
1969
+ " ",
1970
+ duplicate.title
1971
+ ] }),
1972
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: t2.textMuted }, children: "Your details will be added to it instead of opening a new issue." })
1973
+ ]
1974
+ }
1975
+ ),
1671
1976
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1672
1977
  "textarea",
1673
1978
  {
@@ -1751,7 +2056,7 @@ function AssistSheet({
1751
2056
  color: t2.textMuted,
1752
2057
  fontSize: "12px",
1753
2058
  fontFamily: "inherit",
1754
- padding: 0,
2059
+ padding: "9px 0",
1755
2060
  cursor: "pointer",
1756
2061
  textDecoration: "underline"
1757
2062
  },
@@ -1761,6 +2066,33 @@ function AssistSheet({
1761
2066
  ]
1762
2067
  }
1763
2068
  ),
2069
+ phase === "solved" && solved && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
2070
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
2071
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Avatar, { who: "assistant", theme: t2 }),
2072
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2073
+ "div",
2074
+ {
2075
+ style: {
2076
+ padding: "9px 12px",
2077
+ borderRadius: "12px 12px 12px 4px",
2078
+ backgroundColor: t2.bgSecondary,
2079
+ fontSize: "13px",
2080
+ lineHeight: 1.55,
2081
+ maxWidth: "88%",
2082
+ whiteSpace: "pre-wrap"
2083
+ },
2084
+ children: solved
2085
+ }
2086
+ )
2087
+ ] }),
2088
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2089
+ "span",
2090
+ {
2091
+ style: { fontSize: "11.5px", color: t2.textMuted, paddingLeft: "32px" },
2092
+ children: "Nothing was filed \u2014 you are all set."
2093
+ }
2094
+ )
2095
+ ] }),
1764
2096
  submitted && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1765
2097
  "div",
1766
2098
  {
@@ -1782,7 +2114,7 @@ function AssistSheet({
1782
2114
  )
1783
2115
  }
1784
2116
  ),
1785
- !submitted && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2117
+ !submitted && phase !== "type" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1786
2118
  "div",
1787
2119
  {
1788
2120
  style: {
@@ -1792,93 +2124,157 @@ function AssistSheet({
1792
2124
  paddingBottom: narrow ? "max(12px, env(safe-area-inset-bottom))" : "12px",
1793
2125
  backgroundColor: t2.bg
1794
2126
  },
1795
- children: phase === "draft" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1796
- "button",
1797
- {
1798
- type: "button",
1799
- "data-gg-sheet-send": "",
1800
- onClick: onSend,
1801
- disabled: isSubmitting || !description.trim(),
1802
- style: {
1803
- width: "100%",
1804
- padding: "12px",
1805
- borderRadius: "10px",
1806
- border: "none",
1807
- backgroundColor: isSubmitting || !description.trim() ? t2.bgSecondary : t2.accent,
1808
- color: isSubmitting || !description.trim() ? t2.textMuted : t2.accentText,
1809
- fontSize: "14px",
1810
- fontWeight: 700,
1811
- fontFamily: "inherit",
1812
- cursor: isSubmitting || !description.trim() ? "default" : "pointer"
1813
- },
1814
- children: isSubmitting ? "Sending\u2026" : "Send Report"
1815
- }
1816
- ) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "flex-end" }, children: [
1817
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1818
- "textarea",
2127
+ children: [
2128
+ phase === "solved" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2129
+ "button",
1819
2130
  {
1820
- ref: inputRef,
1821
- value: input,
1822
- onChange: (e) => setInput(e.target.value),
1823
- onKeyDown: (e) => {
1824
- if (e.key === "Enter" && !e.shiftKey) {
1825
- e.preventDefault();
1826
- send(input);
1827
- }
2131
+ type: "button",
2132
+ "data-gg-sheet-send": "",
2133
+ onClick: () => (onFinish != null ? onFinish : onClose)(),
2134
+ style: {
2135
+ width: "100%",
2136
+ padding: "12px",
2137
+ borderRadius: "10px",
2138
+ border: "none",
2139
+ backgroundColor: t2.accent,
2140
+ color: t2.accentText,
2141
+ fontSize: "14px",
2142
+ fontWeight: 700,
2143
+ fontFamily: "inherit",
2144
+ cursor: "pointer"
1828
2145
  },
1829
- placeholder: "Type your answer\u2026",
1830
- rows: 1,
1831
- disabled: busy,
1832
- autoFocus: true,
2146
+ children: "Done"
2147
+ }
2148
+ ) : phase === "rating" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2149
+ "button",
2150
+ {
2151
+ type: "button",
2152
+ "data-gg-sheet-send": "",
2153
+ onClick: onSend,
2154
+ disabled: isSubmitting || rating < 1,
1833
2155
  style: {
1834
- flex: 1,
1835
- minHeight: "42px",
1836
- maxHeight: "120px",
1837
- padding: "11px 12px",
2156
+ width: "100%",
2157
+ padding: "12px",
1838
2158
  borderRadius: "10px",
1839
- border: `1px solid ${t2.inputBorder}`,
1840
- backgroundColor: t2.inputBg,
1841
- color: t2.text,
1842
- fontSize: "13px",
1843
- lineHeight: 1.4,
2159
+ border: "none",
2160
+ backgroundColor: isSubmitting || rating < 1 ? t2.bgSecondary : "#f59e0b",
2161
+ color: isSubmitting || rating < 1 ? t2.textMuted : "#1a1a1a",
2162
+ fontSize: "14px",
2163
+ fontWeight: 700,
1844
2164
  fontFamily: "inherit",
1845
- resize: "none",
1846
- outline: "none",
1847
- boxSizing: "border-box"
1848
- }
2165
+ cursor: isSubmitting || rating < 1 ? "default" : "pointer"
2166
+ },
2167
+ children: isSubmitting ? "Sending\u2026" : rating < 1 ? "Pick a star first" : "Send Rating"
1849
2168
  }
1850
- ),
1851
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2169
+ ) : phase === "draft" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1852
2170
  "button",
1853
2171
  {
1854
2172
  type: "button",
1855
2173
  "data-gg-sheet-send": "",
1856
- onClick: () => send(input),
1857
- disabled: busy || !input.trim(),
1858
- "aria-label": "Send message",
2174
+ onClick: onSend,
2175
+ disabled: isSubmitting || !description.trim(),
1859
2176
  style: {
1860
- flexShrink: 0,
1861
- width: "42px",
1862
- height: "42px",
2177
+ width: "100%",
2178
+ padding: "12px",
1863
2179
  borderRadius: "10px",
1864
2180
  border: "none",
1865
- display: "inline-flex",
1866
- alignItems: "center",
1867
- justifyContent: "center",
1868
- backgroundColor: busy || !input.trim() ? t2.bgSecondary : t2.accent,
1869
- color: busy || !input.trim() ? t2.textMuted : t2.accentText,
1870
- cursor: busy || !input.trim() ? "default" : "pointer"
2181
+ backgroundColor: isSubmitting || !description.trim() ? t2.bgSecondary : t2.accent,
2182
+ color: isSubmitting || !description.trim() ? t2.textMuted : t2.accentText,
2183
+ fontSize: "14px",
2184
+ fontWeight: 700,
2185
+ fontFamily: "inherit",
2186
+ cursor: isSubmitting || !description.trim() ? "default" : "pointer"
1871
2187
  },
1872
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "17", height: "17", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1873
- "path",
1874
- {
1875
- d: "M3 20.5L21.5 12 3 3.5V10l12 2-12 2v6.5z",
1876
- fill: "currentColor"
2188
+ children: isSubmitting ? "Sending\u2026" : duplicate ? `Add to #${duplicate.number}` : "Send Report"
2189
+ }
2190
+ ) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "flex-end" }, children: [
2191
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2192
+ "textarea",
2193
+ {
2194
+ ref: inputRef,
2195
+ value: input,
2196
+ onChange: (e) => setInput(e.target.value),
2197
+ onKeyDown: (e) => {
2198
+ if (e.key === "Enter" && !e.shiftKey) {
2199
+ e.preventDefault();
2200
+ send(input);
2201
+ }
2202
+ },
2203
+ placeholder: "Type your answer\u2026",
2204
+ rows: 1,
2205
+ disabled: busy,
2206
+ autoFocus: true,
2207
+ style: {
2208
+ flex: 1,
2209
+ minHeight: "42px",
2210
+ maxHeight: "120px",
2211
+ padding: "11px 12px",
2212
+ borderRadius: "10px",
2213
+ border: `1px solid ${t2.inputBorder}`,
2214
+ backgroundColor: t2.inputBg,
2215
+ color: t2.text,
2216
+ fontSize: "13px",
2217
+ lineHeight: 1.4,
2218
+ fontFamily: "inherit",
2219
+ resize: "none",
2220
+ outline: "none",
2221
+ boxSizing: "border-box"
1877
2222
  }
1878
- ) })
2223
+ }
2224
+ ),
2225
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2226
+ "button",
2227
+ {
2228
+ type: "button",
2229
+ "data-gg-sheet-send": "",
2230
+ onClick: () => send(input),
2231
+ disabled: busy || !input.trim(),
2232
+ "aria-label": "Send message",
2233
+ "data-gg-send-message": "",
2234
+ style: {
2235
+ flexShrink: 0,
2236
+ width: "42px",
2237
+ height: "42px",
2238
+ borderRadius: "10px",
2239
+ border: "none",
2240
+ display: "inline-flex",
2241
+ alignItems: "center",
2242
+ justifyContent: "center",
2243
+ backgroundColor: busy || !input.trim() ? t2.bgSecondary : t2.accent,
2244
+ color: busy || !input.trim() ? t2.textMuted : t2.accentText,
2245
+ cursor: busy || !input.trim() ? "default" : "pointer"
2246
+ },
2247
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "17", height: "17", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2248
+ "path",
2249
+ {
2250
+ d: "M3 20.5L21.5 12 3 3.5V10l12 2-12 2v6.5z",
2251
+ fill: "currentColor"
2252
+ }
2253
+ ) })
2254
+ }
2255
+ )
2256
+ ] }),
2257
+ phase === "chat" && messages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
2258
+ "button",
2259
+ {
2260
+ type: "button",
2261
+ "data-gg-write-myself": "",
2262
+ onClick: onClose,
2263
+ style: {
2264
+ display: "block",
2265
+ margin: "8px auto 0",
2266
+ border: "none",
2267
+ background: "transparent",
2268
+ color: t2.textMuted,
2269
+ fontSize: "11.5px",
2270
+ fontFamily: "inherit",
2271
+ padding: "6px 8px",
2272
+ cursor: "pointer"
2273
+ },
2274
+ children: "Not getting it? Fill the form yourself \u2192"
1879
2275
  }
1880
2276
  )
1881
- ] })
2277
+ ]
1882
2278
  }
1883
2279
  )
1884
2280
  ]
@@ -2248,6 +2644,9 @@ function ReportDialog({
2248
2644
  const [assistOpen, setAssistOpen] = (0, import_react.useState)(false);
2249
2645
  const [assistNotice, setAssistNotice] = (0, import_react.useState)(null);
2250
2646
  const [assistUsed, setAssistUsed] = (0, import_react.useState)(false);
2647
+ const [typeChosen, setTypeChosen] = (0, import_react.useState)(false);
2648
+ const [duplicateIssueNumber, setDuplicateIssueNumber] = (0, import_react.useState)(null);
2649
+ const [aiConversationId, setAiConversationId] = (0, import_react.useState)(null);
2251
2650
  const [isEnhanced, setIsEnhanced] = (0, import_react.useState)(false);
2252
2651
  const [originalDescription, setOriginalDescription] = (0, import_react.useState)(
2253
2652
  null
@@ -2300,6 +2699,10 @@ function ReportDialog({
2300
2699
  const sarvamChunksRef = (0, import_react.useRef)([]);
2301
2700
  const spaceTimerRef = (0, import_react.useRef)(null);
2302
2701
  const isPushToTalkRef = (0, import_react.useRef)(false);
2702
+ const spaceEditsRef = (0, import_react.useRef)(0);
2703
+ const descriptionRef = (0, import_react.useRef)("");
2704
+ const lastVoiceTextRef = (0, import_react.useRef)(null);
2705
+ const hadWebSpeechRef = (0, import_react.useRef)(false);
2303
2706
  (0, import_react.useEffect)(() => {
2304
2707
  if (!isOpen) return;
2305
2708
  const HOST_LAYERS = '[role="dialog"],[role="alertdialog"],[role="menu"],[role="listbox"]';
@@ -2355,6 +2758,7 @@ function ReportDialog({
2355
2758
  e.preventDefault();
2356
2759
  setRating(Number(e.key));
2357
2760
  setReportType("RATING");
2761
+ setTypeChosen(true);
2358
2762
  setStep(2);
2359
2763
  return;
2360
2764
  }
@@ -2366,6 +2770,7 @@ function ReportDialog({
2366
2770
  if (match) {
2367
2771
  e.preventDefault();
2368
2772
  setReportType(match);
2773
+ setTypeChosen(true);
2369
2774
  setStep(2);
2370
2775
  }
2371
2776
  };
@@ -2419,10 +2824,12 @@ function ReportDialog({
2419
2824
  setAnnotatingIndex(null);
2420
2825
  if (availableTypes.length === 1) {
2421
2826
  setReportType(availableTypes[0]);
2827
+ setTypeChosen(true);
2422
2828
  setStep(2);
2423
2829
  }
2424
2830
  const shot = await captureScreenshot();
2425
2831
  if (shot) setScreenshots([shot]);
2832
+ if (assist && !assistUsed) setAssistOpen(true);
2426
2833
  setIsOpen(true);
2427
2834
  };
2428
2835
  (0, import_react.useEffect)(() => {
@@ -2432,6 +2839,7 @@ function ReportDialog({
2432
2839
  if (detail == null ? void 0 : detail.description) setDescription(detail.description);
2433
2840
  if (detail == null ? void 0 : detail.type) {
2434
2841
  setReportType(detail.type);
2842
+ setTypeChosen(true);
2435
2843
  setStep(2);
2436
2844
  }
2437
2845
  handleOpen();
@@ -2555,6 +2963,22 @@ function ReportDialog({
2555
2963
  }, 3e3);
2556
2964
  return () => clearInterval(id);
2557
2965
  }, [isOpen, transcribeAudio2]);
2966
+ (0, import_react.useEffect)(() => {
2967
+ descriptionRef.current = description;
2968
+ }, [description]);
2969
+ const rebaseVoiceOnUserEdits = () => {
2970
+ var _a2;
2971
+ const live = descriptionRef.current;
2972
+ const baseline = (_a2 = lastVoiceTextRef.current) != null ? _a2 : textBeforeVoiceRef.current;
2973
+ if (live === baseline) return;
2974
+ voiceBaseRef.current = live;
2975
+ textBeforeVoiceRef.current = live;
2976
+ };
2977
+ const setDescriptionFromVoice = (text) => {
2978
+ lastVoiceTextRef.current = text;
2979
+ descriptionRef.current = text;
2980
+ setDescription(text);
2981
+ };
2558
2982
  const stopVoice = () => {
2559
2983
  var _a2, _b2;
2560
2984
  usingWebSpeechRef.current = false;
@@ -2583,7 +3007,7 @@ function ReportDialog({
2583
3007
  } catch (e) {
2584
3008
  }
2585
3009
  };
2586
- const sheetUp = !!assist && assistOpen && !isRating;
3010
+ const sheetUp = !!assist && assistOpen;
2587
3011
  (0, import_react.useEffect)(() => {
2588
3012
  const el = modalRef.current;
2589
3013
  if (!el) return;
@@ -2605,6 +3029,8 @@ function ReportDialog({
2605
3029
  setRating(0);
2606
3030
  setHoveredStar(0);
2607
3031
  setReportType("BUG");
3032
+ setTypeChosen(false);
3033
+ setDuplicateIssueNumber(null);
2608
3034
  setSeverity("medium");
2609
3035
  setValidationError(null);
2610
3036
  setVoiceError(null);
@@ -2619,6 +3045,8 @@ function ReportDialog({
2619
3045
  stopListeningAndTranscribe();
2620
3046
  return;
2621
3047
  }
3048
+ lastVoiceTextRef.current = null;
3049
+ hadWebSpeechRef.current = false;
2622
3050
  const SpeechRec = typeof window !== "undefined" ? window.SpeechRecognition || window.webkitSpeechRecognition : void 0;
2623
3051
  let stream = null;
2624
3052
  try {
@@ -2633,13 +3061,14 @@ function ReportDialog({
2633
3061
  if (stream && transcribeAudio2) {
2634
3062
  streamRef.current = stream;
2635
3063
  sarvamChunksRef.current = [];
2636
- textBeforeVoiceRef.current = description;
3064
+ textBeforeVoiceRef.current = descriptionRef.current;
2637
3065
  const rec = new MediaRecorder(stream);
2638
3066
  mediaRecorderRef.current = rec;
2639
3067
  rec.ondataavailable = (e) => {
2640
3068
  if (e.data.size > 0) sarvamChunksRef.current.push(e.data);
2641
3069
  };
2642
3070
  rec.onstop = async () => {
3071
+ var _a2;
2643
3072
  stream.getTracks().forEach((t22) => t22.stop());
2644
3073
  if (streamRef.current === stream) streamRef.current = null;
2645
3074
  mediaRecorderRef.current = null;
@@ -2651,11 +3080,18 @@ function ReportDialog({
2651
3080
  const blob = new Blob(chunks, { type: rec.mimeType || "audio/webm" });
2652
3081
  const text = await transcribeAudio2(blob);
2653
3082
  if (text.trim()) {
2654
- const sep = textBeforeVoiceRef.current.trim() ? " " : "";
2655
- setDescription(textBeforeVoiceRef.current + sep + text.trim());
2656
- setValidationError(null);
2657
- setIsEnhanced(false);
2658
- setOriginalDescription(null);
3083
+ const live = descriptionRef.current;
3084
+ const baseline = (_a2 = lastVoiceTextRef.current) != null ? _a2 : textBeforeVoiceRef.current;
3085
+ const userEdited = live !== baseline;
3086
+ if (userEdited && hadWebSpeechRef.current) {
3087
+ } else {
3088
+ const base = userEdited ? live : textBeforeVoiceRef.current;
3089
+ const sep = base.trim() ? " " : "";
3090
+ setDescriptionFromVoice(base + sep + text.trim());
3091
+ setValidationError(null);
3092
+ setIsEnhanced(false);
3093
+ setOriginalDescription(null);
3094
+ }
2659
3095
  }
2660
3096
  } catch (e) {
2661
3097
  }
@@ -2666,8 +3102,9 @@ function ReportDialog({
2666
3102
  if (SpeechRec) {
2667
3103
  setVoiceError(null);
2668
3104
  usingWebSpeechRef.current = true;
2669
- voiceBaseRef.current = description;
2670
- textBeforeVoiceRef.current = description;
3105
+ hadWebSpeechRef.current = true;
3106
+ voiceBaseRef.current = descriptionRef.current;
3107
+ textBeforeVoiceRef.current = descriptionRef.current;
2671
3108
  const recognition = new SpeechRec();
2672
3109
  recognition.lang = "en-IN";
2673
3110
  recognition.interimResults = true;
@@ -2682,12 +3119,13 @@ function ReportDialog({
2682
3119
  if (event.results[i].isFinal) finalText += text;
2683
3120
  else interimText += text;
2684
3121
  }
3122
+ rebaseVoiceOnUserEdits();
2685
3123
  if (finalText) {
2686
3124
  const sep = voiceBaseRef.current.trim() ? " " : "";
2687
3125
  voiceBaseRef.current += sep + finalText.trim();
2688
3126
  }
2689
3127
  const liveText = interimText ? voiceBaseRef.current + (voiceBaseRef.current.trim() ? " " : "") + interimText : voiceBaseRef.current;
2690
- setDescription(liveText);
3128
+ setDescriptionFromVoice(liveText);
2691
3129
  setValidationError(null);
2692
3130
  };
2693
3131
  recognition.onend = () => {
@@ -2714,37 +3152,54 @@ function ReportDialog({
2714
3152
  setIsListening(true);
2715
3153
  }
2716
3154
  };
3155
+ const cancelPushToTalkArm = () => {
3156
+ if (!spaceTimerRef.current) return;
3157
+ clearTimeout(spaceTimerRef.current);
3158
+ spaceTimerRef.current = null;
3159
+ };
3160
+ const notePushToTalkEdit = () => {
3161
+ if (!spaceTimerRef.current) return;
3162
+ spaceEditsRef.current += 1;
3163
+ if (spaceEditsRef.current > 1) cancelPushToTalkArm();
3164
+ };
2717
3165
  const handleSpaceDown = (e) => {
2718
- var _a2;
2719
- if (e.code !== "Space") return;
3166
+ if (e.code !== "Space") {
3167
+ if (!e.metaKey && !e.ctrlKey && !e.altKey) cancelPushToTalkArm();
3168
+ return;
3169
+ }
2720
3170
  if (isListening || isPushToTalkRef.current) {
2721
3171
  e.preventDefault();
2722
3172
  return;
2723
3173
  }
2724
3174
  if (e.repeat || !transcribeAudio2 || isTranscribing || spaceTimerRef.current)
2725
3175
  return;
2726
- const pos = (_a2 = e.currentTarget.selectionStart) != null ? _a2 : description.length;
3176
+ if (e.currentTarget.value !== "") return;
3177
+ spaceEditsRef.current = 0;
2727
3178
  spaceTimerRef.current = setTimeout(() => {
3179
+ var _a2;
2728
3180
  spaceTimerRef.current = null;
2729
3181
  isPushToTalkRef.current = true;
2730
- setDescription(
2731
- (prev) => prev[pos] === " " ? prev.slice(0, pos) + prev.slice(pos + 1) : prev
2732
- );
2733
- requestAnimationFrame(() => {
2734
- if (textareaRef.current) {
2735
- textareaRef.current.selectionStart = pos;
2736
- textareaRef.current.selectionEnd = pos;
2737
- }
2738
- });
3182
+ const el = textareaRef.current;
3183
+ const caret = (_a2 = el == null ? void 0 : el.selectionStart) != null ? _a2 : null;
3184
+ if (el && caret !== null && caret === el.selectionEnd && el.value[caret - 1] === " ") {
3185
+ const cut = caret - 1;
3186
+ setDescription(
3187
+ (prev) => prev[cut] === " " ? prev.slice(0, cut) + prev.slice(cut + 1) : prev
3188
+ );
3189
+ descriptionRef.current = descriptionRef.current.slice(0, cut) + descriptionRef.current.slice(cut + 1);
3190
+ requestAnimationFrame(() => {
3191
+ if (textareaRef.current) {
3192
+ textareaRef.current.selectionStart = cut;
3193
+ textareaRef.current.selectionEnd = cut;
3194
+ }
3195
+ });
3196
+ }
2739
3197
  void toggleVoice();
2740
3198
  }, 400);
2741
3199
  };
2742
3200
  const handleSpaceUp = (e) => {
2743
3201
  if (e.code !== "Space") return;
2744
- if (spaceTimerRef.current) {
2745
- clearTimeout(spaceTimerRef.current);
2746
- spaceTimerRef.current = null;
2747
- }
3202
+ cancelPushToTalkArm();
2748
3203
  if (isPushToTalkRef.current) {
2749
3204
  isPushToTalkRef.current = false;
2750
3205
  stopListeningAndTranscribe();
@@ -2789,6 +3244,12 @@ function ReportDialog({
2789
3244
  if (showSeverity && reportType === "BUG") {
2790
3245
  metadata.severity = severity;
2791
3246
  }
3247
+ if (duplicateIssueNumber) {
3248
+ metadata.duplicateIssueNumber = String(duplicateIssueNumber);
3249
+ }
3250
+ if (aiConversationId) {
3251
+ metadata.aiConversationId = aiConversationId;
3252
+ }
2792
3253
  const result = await report(
2793
3254
  // The RATING branch returned above, so anything reaching here is a real
2794
3255
  // ReportType — the widened tile union can't leak into the report API.
@@ -2801,6 +3262,8 @@ function ReportDialog({
2801
3262
  setDescription("");
2802
3263
  setScreenshots([]);
2803
3264
  setAttachments([]);
3265
+ setAiConversationId(null);
3266
+ setDuplicateIssueNumber(null);
2804
3267
  setTimeout(() => {
2805
3268
  setSubmitted(false);
2806
3269
  handleClose();
@@ -3151,6 +3614,7 @@ function ReportDialog({
3151
3614
  onClick: () => {
3152
3615
  setRating(star);
3153
3616
  setReportType("RATING");
3617
+ setTypeChosen(true);
3154
3618
  setStep(2);
3155
3619
  },
3156
3620
  style: {
@@ -3261,6 +3725,7 @@ function ReportDialog({
3261
3725
  "data-gg-type": type,
3262
3726
  onClick: () => {
3263
3727
  setReportType(type);
3728
+ setTypeChosen(true);
3264
3729
  setStep(2);
3265
3730
  },
3266
3731
  style: {
@@ -3380,6 +3845,7 @@ function ReportDialog({
3380
3845
  type: "button",
3381
3846
  onClick: () => {
3382
3847
  setAssistNotice(null);
3848
+ setTypeChosen(true);
3383
3849
  setAssistOpen(true);
3384
3850
  },
3385
3851
  style: {
@@ -3420,6 +3886,7 @@ function ReportDialog({
3420
3886
  ref: textareaRef,
3421
3887
  value: description,
3422
3888
  onChange: (e) => {
3889
+ notePushToTalkEdit();
3423
3890
  setDescription(e.target.value);
3424
3891
  if (validationError) setValidationError(null);
3425
3892
  if (isEnhanced) {
@@ -4528,6 +4995,22 @@ function ReportDialog({
4528
4995
  attachmentCount: screenshots.length + attachments.length,
4529
4996
  context: { ...assistContext != null ? assistContext : {}, reportType },
4530
4997
  reportTypeLabel: getTypeLabel(reportType),
4998
+ typePicked: typeChosen,
4999
+ currentTile: reportType,
5000
+ tiles: sendFeedback2 ? [...availableTypes, "RATING"] : availableTypes,
5001
+ onPickType: (tile) => {
5002
+ setReportType(tile);
5003
+ setTypeChosen(true);
5004
+ setStep(2);
5005
+ },
5006
+ onDuplicateChange: setDuplicateIssueNumber,
5007
+ onConversationChange: setAiConversationId,
5008
+ onFinish: handleClose,
5009
+ rating,
5010
+ onRatingChange: (value) => {
5011
+ setRating(value);
5012
+ if (validationError) setValidationError(null);
5013
+ },
4531
5014
  projectSlot: headerSlot,
4532
5015
  reporterName: (_b = reporter == null ? void 0 : reporter.name) != null ? _b : null,
4533
5016
  description,
@@ -4557,26 +5040,6 @@ function ReportDialog({
4557
5040
  )
4558
5041
  ] });
4559
5042
  }
4560
- function getTypeLabel(type) {
4561
- switch (type) {
4562
- case "RATING":
4563
- return "Rating";
4564
- case "BUG":
4565
- return "Bug Report";
4566
- case "FEATURE_REQUEST":
4567
- return "Feature Request";
4568
- case "UI_IMPROVEMENT":
4569
- return "UI Improvement";
4570
- case "PERFORMANCE":
4571
- return "Performance";
4572
- case "SECURITY":
4573
- return "Security";
4574
- case "QUESTION":
4575
- return "Question";
4576
- case "OTHER":
4577
- return "Other";
4578
- }
4579
- }
4580
5043
  function getPlaceholder(type, idx = 0, hasVoice = false) {
4581
5044
  if (type === "RATING") return "What made it good \u2014 or what let you down? (optional)";
4582
5045
  if (hasVoice && idx === 1) return "Hold Space to speak \u2014 we'll transcribe it";
@@ -5561,6 +6024,12 @@ function GlitchgrabProviderInner({
5561
6024
  return assistTurn(
5562
6025
  {
5563
6026
  ...params,
6027
+ // Same identity the report itself carries, from the same prop.
6028
+ reporter: session ? {
6029
+ key: session.userId,
6030
+ name: session.name ? String(session.name) : null,
6031
+ email: session.email ? String(session.email) : null
6032
+ } : void 0,
5564
6033
  context: {
5565
6034
  ...(_a = params.context) != null ? _a : {},
5566
6035
  url: ctx.url,
@@ -5572,7 +6041,7 @@ function GlitchgrabProviderInner({
5572
6041
  baseUrl
5573
6042
  );
5574
6043
  },
5575
- [token, baseUrl]
6044
+ [token, baseUrl, session]
5576
6045
  );
5577
6046
  const transcribe = (0, import_react5.useCallback)(
5578
6047
  async (blob) => {