@tangle-network/agent-app 0.45.63 → 0.45.64
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/assistant/index.js +2 -2
- package/dist/{chunk-PC2WYTK7.js → chunk-EDTWGSQT.js} +118 -1
- package/dist/chunk-EDTWGSQT.js.map +1 -0
- package/dist/{chunk-FOXGPGXF.js → chunk-OMGV3CX2.js} +1252 -534
- package/dist/chunk-OMGV3CX2.js.map +1 -0
- package/dist/session-shell/command-palette.d.ts +88 -0
- package/dist/session-shell/index.d.ts +1 -0
- package/dist/session-shell/index.js +13 -1
- package/dist/web-react/chat-composer.d.ts +29 -1
- package/dist/web-react/command-palette.d.ts +44 -0
- package/dist/web-react/index.d.ts +2 -0
- package/dist/web-react/index.js +14 -2
- package/dist/web-react/insight-card.d.ts +5 -1
- package/dist/web-react/record-grid-model.d.ts +45 -0
- package/dist/web-react/record-grid.d.ts +28 -2
- package/dist/web-react/use-dictation.d.ts +67 -0
- package/dist/workspace-react/index.js +1 -1
- package/package.json +3 -3
- package/dist/chunk-FOXGPGXF.js.map +0 -1
- package/dist/chunk-PC2WYTK7.js.map +0 -1
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
ChevronDown,
|
|
11
11
|
OVERLAY_SHADOW,
|
|
12
12
|
POPOVER_OPTION_FOCUS,
|
|
13
|
+
POPOVER_SURFACE_ATTR,
|
|
13
14
|
PopoverSurface,
|
|
14
15
|
usePending,
|
|
15
16
|
usePopover
|
|
@@ -19,9 +20,11 @@ import {
|
|
|
19
20
|
} from "./chunk-3UBAO3N5.js";
|
|
20
21
|
import {
|
|
21
22
|
UNTITLED_SESSION_LABEL,
|
|
23
|
+
filterCommandPaletteItems,
|
|
24
|
+
groupCommandPaletteItems,
|
|
22
25
|
mergeSessionPages,
|
|
23
26
|
sessionLabel
|
|
24
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-EDTWGSQT.js";
|
|
25
28
|
import {
|
|
26
29
|
attachmentPartsFromMessageParts
|
|
27
30
|
} from "./chunk-5ZTFZBS6.js";
|
|
@@ -41,7 +44,7 @@ import {
|
|
|
41
44
|
} from "./chunk-YJMCRXQQ.js";
|
|
42
45
|
|
|
43
46
|
// src/web-react/index.tsx
|
|
44
|
-
import { useEffect as
|
|
47
|
+
import { useEffect as useEffect14, useMemo as useMemo9, useRef as useRef14, useState as useState18, memo } from "react";
|
|
45
48
|
import { InlineToolItem, RunRowShell } from "@tangle-network/ui/run";
|
|
46
49
|
|
|
47
50
|
// src/web-react/smooth-text.ts
|
|
@@ -1408,11 +1411,147 @@ async function streamChatTurn(opts) {
|
|
|
1408
1411
|
|
|
1409
1412
|
// src/web-react/chat-composer.tsx
|
|
1410
1413
|
import {
|
|
1411
|
-
useCallback as
|
|
1412
|
-
useEffect as
|
|
1413
|
-
|
|
1414
|
-
|
|
1414
|
+
useCallback as useCallback3,
|
|
1415
|
+
useEffect as useEffect6,
|
|
1416
|
+
useMemo as useMemo3,
|
|
1417
|
+
useId,
|
|
1418
|
+
useRef as useRef6,
|
|
1419
|
+
useState as useState8
|
|
1415
1420
|
} from "react";
|
|
1421
|
+
|
|
1422
|
+
// src/web-react/use-dictation.ts
|
|
1423
|
+
import { useCallback as useCallback2, useEffect as useEffect5, useRef as useRef5, useState as useState7 } from "react";
|
|
1424
|
+
var PREFERRED_MIME_TYPES = ["audio/webm;codecs=opus", "audio/webm", "audio/mp4"];
|
|
1425
|
+
function pickDictationMimeType() {
|
|
1426
|
+
if (typeof MediaRecorder === "undefined" || typeof MediaRecorder.isTypeSupported !== "function") {
|
|
1427
|
+
return void 0;
|
|
1428
|
+
}
|
|
1429
|
+
for (const type of PREFERRED_MIME_TYPES) {
|
|
1430
|
+
if (MediaRecorder.isTypeSupported(type)) return type;
|
|
1431
|
+
}
|
|
1432
|
+
return void 0;
|
|
1433
|
+
}
|
|
1434
|
+
function detectDictationSupport() {
|
|
1435
|
+
return typeof navigator !== "undefined" && typeof navigator.mediaDevices?.getUserMedia === "function" && typeof MediaRecorder !== "undefined";
|
|
1436
|
+
}
|
|
1437
|
+
function dictationErrorMessage(error) {
|
|
1438
|
+
if (error instanceof DOMException) {
|
|
1439
|
+
if (error.name === "NotAllowedError") return "Microphone access was denied \u2014 allow it in the browser to dictate.";
|
|
1440
|
+
if (error.name === "NotFoundError") return "No microphone found on this device.";
|
|
1441
|
+
}
|
|
1442
|
+
return "Could not start recording.";
|
|
1443
|
+
}
|
|
1444
|
+
function formatDictationElapsed(totalSeconds) {
|
|
1445
|
+
const safe = Number.isFinite(totalSeconds) && totalSeconds > 0 ? Math.floor(totalSeconds) : 0;
|
|
1446
|
+
const minutes = Math.floor(safe / 60);
|
|
1447
|
+
const seconds = safe % 60;
|
|
1448
|
+
return `${minutes}:${String(seconds).padStart(2, "0")}`;
|
|
1449
|
+
}
|
|
1450
|
+
function releaseStream(stream) {
|
|
1451
|
+
for (const track of stream.getTracks()) track.stop();
|
|
1452
|
+
}
|
|
1453
|
+
function useDictation({ onDictate, onError }) {
|
|
1454
|
+
const [supported] = useState7(detectDictationSupport);
|
|
1455
|
+
const [recording, setRecording] = useState7(false);
|
|
1456
|
+
const [elapsedSeconds, setElapsedSeconds] = useState7(0);
|
|
1457
|
+
const sessionRef = useRef5(null);
|
|
1458
|
+
const cancelPendingStartRef = useRef5(null);
|
|
1459
|
+
const callbacksRef = useRef5({ onDictate, onError });
|
|
1460
|
+
callbacksRef.current = { onDictate, onError };
|
|
1461
|
+
useEffect5(() => {
|
|
1462
|
+
if (!recording) return;
|
|
1463
|
+
setElapsedSeconds(0);
|
|
1464
|
+
const id = setInterval(() => setElapsedSeconds((s) => s + 1), 1e3);
|
|
1465
|
+
return () => clearInterval(id);
|
|
1466
|
+
}, [recording]);
|
|
1467
|
+
const teardown = useCallback2((cancelled) => {
|
|
1468
|
+
const session = sessionRef.current;
|
|
1469
|
+
if (session === null) return;
|
|
1470
|
+
session.cancelled = session.cancelled || cancelled;
|
|
1471
|
+
sessionRef.current = null;
|
|
1472
|
+
releaseStream(session.stream);
|
|
1473
|
+
setRecording(false);
|
|
1474
|
+
}, []);
|
|
1475
|
+
const stop = useCallback2(() => {
|
|
1476
|
+
cancelPendingStartRef.current?.();
|
|
1477
|
+
cancelPendingStartRef.current = null;
|
|
1478
|
+
const session = sessionRef.current;
|
|
1479
|
+
if (session === null || session.cancelled) return;
|
|
1480
|
+
if (session.recorder.state !== "inactive") session.recorder.stop();
|
|
1481
|
+
}, []);
|
|
1482
|
+
const start = useCallback2(() => {
|
|
1483
|
+
if (!supported) return;
|
|
1484
|
+
if (sessionRef.current !== null || cancelPendingStartRef.current !== null) return;
|
|
1485
|
+
let pendingCancelled = false;
|
|
1486
|
+
cancelPendingStartRef.current = () => {
|
|
1487
|
+
pendingCancelled = true;
|
|
1488
|
+
};
|
|
1489
|
+
navigator.mediaDevices.getUserMedia({ audio: true }).then(
|
|
1490
|
+
(stream) => {
|
|
1491
|
+
cancelPendingStartRef.current = null;
|
|
1492
|
+
if (pendingCancelled) {
|
|
1493
|
+
releaseStream(stream);
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
const mimeType = pickDictationMimeType();
|
|
1497
|
+
const recorder = new MediaRecorder(stream, mimeType === void 0 ? void 0 : { mimeType });
|
|
1498
|
+
const session = {
|
|
1499
|
+
stream,
|
|
1500
|
+
recorder,
|
|
1501
|
+
chunks: [],
|
|
1502
|
+
mimeType: recorder.mimeType || mimeType || "",
|
|
1503
|
+
startedAt: Date.now(),
|
|
1504
|
+
cancelled: false
|
|
1505
|
+
};
|
|
1506
|
+
sessionRef.current = session;
|
|
1507
|
+
recorder.ondataavailable = (event) => {
|
|
1508
|
+
if (event.data.size > 0) session.chunks.push(event.data);
|
|
1509
|
+
};
|
|
1510
|
+
recorder.onstop = () => {
|
|
1511
|
+
teardown(session.cancelled);
|
|
1512
|
+
if (session.cancelled) return;
|
|
1513
|
+
const blob = new Blob(session.chunks, { type: session.mimeType });
|
|
1514
|
+
if (blob.size === 0) {
|
|
1515
|
+
callbacksRef.current.onError?.("Nothing was recorded.");
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1518
|
+
const durationSeconds = Math.max(0, Math.round((Date.now() - session.startedAt) / 1e3));
|
|
1519
|
+
callbacksRef.current.onDictate({ blob, mimeType: session.mimeType, durationSeconds });
|
|
1520
|
+
};
|
|
1521
|
+
recorder.onerror = () => {
|
|
1522
|
+
teardown(true);
|
|
1523
|
+
callbacksRef.current.onError?.("Recording stopped unexpectedly.");
|
|
1524
|
+
};
|
|
1525
|
+
recorder.start();
|
|
1526
|
+
setRecording(true);
|
|
1527
|
+
},
|
|
1528
|
+
(error) => {
|
|
1529
|
+
cancelPendingStartRef.current = null;
|
|
1530
|
+
if (pendingCancelled) return;
|
|
1531
|
+
callbacksRef.current.onError?.(dictationErrorMessage(error));
|
|
1532
|
+
}
|
|
1533
|
+
);
|
|
1534
|
+
}, [supported, teardown]);
|
|
1535
|
+
useEffect5(
|
|
1536
|
+
() => () => {
|
|
1537
|
+
cancelPendingStartRef.current?.();
|
|
1538
|
+
cancelPendingStartRef.current = null;
|
|
1539
|
+
const session = sessionRef.current;
|
|
1540
|
+
if (session === null) return;
|
|
1541
|
+
session.cancelled = true;
|
|
1542
|
+
sessionRef.current = null;
|
|
1543
|
+
try {
|
|
1544
|
+
if (session.recorder.state !== "inactive") session.recorder.stop();
|
|
1545
|
+
} finally {
|
|
1546
|
+
releaseStream(session.stream);
|
|
1547
|
+
}
|
|
1548
|
+
},
|
|
1549
|
+
[]
|
|
1550
|
+
);
|
|
1551
|
+
return { supported, recording, elapsedSeconds, start, stop };
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
// src/web-react/chat-composer.tsx
|
|
1416
1555
|
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1417
1556
|
var IS_APPLE_PLATFORM = typeof navigator !== "undefined" && /Mac|iPhone|iPad|iPod/i.test(navigator.platform);
|
|
1418
1557
|
function SendGlyph({ className }) {
|
|
@@ -1439,6 +1578,12 @@ function CloseGlyph({ className }) {
|
|
|
1439
1578
|
function UploadGlyph({ className }) {
|
|
1440
1579
|
return /* @__PURE__ */ jsx7("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx7("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M17 8l-5-5-5 5M12 3v12" }) });
|
|
1441
1580
|
}
|
|
1581
|
+
function MicGlyph({ className }) {
|
|
1582
|
+
return /* @__PURE__ */ jsxs5("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
1583
|
+
/* @__PURE__ */ jsx7("rect", { x: "9", y: "2", width: "6", height: "12", rx: "3" }),
|
|
1584
|
+
/* @__PURE__ */ jsx7("path", { d: "M5 10v1a7 7 0 0 0 14 0v-1M12 18v4" })
|
|
1585
|
+
] });
|
|
1586
|
+
}
|
|
1442
1587
|
var MAX_HEIGHT = 168;
|
|
1443
1588
|
var DEFAULT_SEND_FAILURE = "Message not sent. Your draft is still here \u2014 try again.";
|
|
1444
1589
|
function isRejectedOutcome(outcome) {
|
|
@@ -1480,6 +1625,9 @@ function ChatComposer({
|
|
|
1480
1625
|
accept,
|
|
1481
1626
|
dropTitle = "Drop files to add context",
|
|
1482
1627
|
dropDescription = "They attach to your next message.",
|
|
1628
|
+
slashCommands,
|
|
1629
|
+
onDictate,
|
|
1630
|
+
onDictateError,
|
|
1483
1631
|
focusShortcut = true,
|
|
1484
1632
|
floating = false,
|
|
1485
1633
|
sendLabel = "Send",
|
|
@@ -1487,31 +1635,47 @@ function ChatComposer({
|
|
|
1487
1635
|
className
|
|
1488
1636
|
}) {
|
|
1489
1637
|
const isControlled = value !== void 0;
|
|
1490
|
-
const [internal, setInternal] =
|
|
1638
|
+
const [internal, setInternal] = useState8(initialValue ?? "");
|
|
1491
1639
|
const text = isControlled ? value : internal;
|
|
1492
|
-
const textRef =
|
|
1640
|
+
const textRef = useRef6(text);
|
|
1493
1641
|
textRef.current = text;
|
|
1494
|
-
const textareaRef =
|
|
1495
|
-
const fileInputRef =
|
|
1496
|
-
const folderInputRef =
|
|
1497
|
-
const [dragOver, setDragOver] =
|
|
1498
|
-
const dragDepth =
|
|
1499
|
-
const setText =
|
|
1642
|
+
const textareaRef = useRef6(null);
|
|
1643
|
+
const fileInputRef = useRef6(null);
|
|
1644
|
+
const folderInputRef = useRef6(null);
|
|
1645
|
+
const [dragOver, setDragOver] = useState8(false);
|
|
1646
|
+
const dragDepth = useRef6(0);
|
|
1647
|
+
const setText = useCallback3(
|
|
1500
1648
|
(next) => {
|
|
1501
1649
|
if (!isControlled) setInternal(next);
|
|
1502
1650
|
onValueChange?.(next);
|
|
1503
1651
|
},
|
|
1504
1652
|
[isControlled, onValueChange]
|
|
1505
1653
|
);
|
|
1506
|
-
|
|
1654
|
+
const [dictateError, setDictateError] = useState8(null);
|
|
1655
|
+
const handleDictated = useCallback3(
|
|
1656
|
+
(audio) => {
|
|
1657
|
+
setDictateError(null);
|
|
1658
|
+
onDictate?.(audio);
|
|
1659
|
+
},
|
|
1660
|
+
[onDictate]
|
|
1661
|
+
);
|
|
1662
|
+
const handleDictateError = useCallback3(
|
|
1663
|
+
(message) => {
|
|
1664
|
+
setDictateError(message);
|
|
1665
|
+
onDictateError?.(message);
|
|
1666
|
+
},
|
|
1667
|
+
[onDictateError]
|
|
1668
|
+
);
|
|
1669
|
+
const dictation = useDictation({ onDictate: handleDictated, onError: handleDictateError });
|
|
1670
|
+
useEffect6(() => {
|
|
1507
1671
|
const el = textareaRef.current;
|
|
1508
1672
|
if (!el) return;
|
|
1509
1673
|
el.style.height = "auto";
|
|
1510
1674
|
el.style.height = `${Math.min(el.scrollHeight, MAX_HEIGHT)}px`;
|
|
1511
1675
|
}, [text]);
|
|
1512
|
-
const prevSeedRef =
|
|
1513
|
-
const pendingCaretRef =
|
|
1514
|
-
|
|
1676
|
+
const prevSeedRef = useRef6(null);
|
|
1677
|
+
const pendingCaretRef = useRef6(null);
|
|
1678
|
+
useEffect6(() => {
|
|
1515
1679
|
const prev = prevSeedRef.current;
|
|
1516
1680
|
prevSeedRef.current = seed ?? null;
|
|
1517
1681
|
if (seed == null || seed === prev || isControlled) return;
|
|
@@ -1525,7 +1689,7 @@ function ChatComposer({
|
|
|
1525
1689
|
pendingCaretRef.current = seed;
|
|
1526
1690
|
}
|
|
1527
1691
|
}, [seed, setText, onSeedApplied, isControlled]);
|
|
1528
|
-
|
|
1692
|
+
useEffect6(() => {
|
|
1529
1693
|
if (pendingCaretRef.current == null || pendingCaretRef.current !== text)
|
|
1530
1694
|
return;
|
|
1531
1695
|
pendingCaretRef.current = null;
|
|
@@ -1534,8 +1698,8 @@ function ChatComposer({
|
|
|
1534
1698
|
el.focus();
|
|
1535
1699
|
el.setSelectionRange(text.length, text.length);
|
|
1536
1700
|
}, [text]);
|
|
1537
|
-
const restoreCaretRef =
|
|
1538
|
-
|
|
1701
|
+
const restoreCaretRef = useRef6(null);
|
|
1702
|
+
useEffect6(() => {
|
|
1539
1703
|
const pending = restoreCaretRef.current;
|
|
1540
1704
|
if (!pending || pending.text !== text) return;
|
|
1541
1705
|
restoreCaretRef.current = null;
|
|
@@ -1546,7 +1710,7 @@ function ChatComposer({
|
|
|
1546
1710
|
const end = Math.min(pending.end, text.length);
|
|
1547
1711
|
el.setSelectionRange(start, end);
|
|
1548
1712
|
}, [text]);
|
|
1549
|
-
|
|
1713
|
+
useEffect6(() => {
|
|
1550
1714
|
if (!focusShortcut || disabled) return;
|
|
1551
1715
|
function onKeyDown(e) {
|
|
1552
1716
|
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "l") {
|
|
@@ -1560,8 +1724,8 @@ function ChatComposer({
|
|
|
1560
1724
|
const readyFileCount = pendingFiles.filter((f) => f.status === "ready").length;
|
|
1561
1725
|
const hasSendable = text.trim().length > 0 || readyFileCount > 0;
|
|
1562
1726
|
const canSend = hasSendable && !isStreaming && !disabled;
|
|
1563
|
-
const [failedSend, setFailedSend] =
|
|
1564
|
-
const failSend =
|
|
1727
|
+
const [failedSend, setFailedSend] = useState8(null);
|
|
1728
|
+
const failSend = useCallback3(
|
|
1565
1729
|
(error, draft, trimmed, parts, caret) => {
|
|
1566
1730
|
const message = sendFailureText(error, sendFailureMessage);
|
|
1567
1731
|
const restored = textRef.current === "";
|
|
@@ -1580,7 +1744,7 @@ function ChatComposer({
|
|
|
1580
1744
|
},
|
|
1581
1745
|
[onSendFailed, sendFailureMessage, setText]
|
|
1582
1746
|
);
|
|
1583
|
-
const dispatchSend =
|
|
1747
|
+
const dispatchSend = useCallback3(
|
|
1584
1748
|
(draft, trimmed, parts, caret) => {
|
|
1585
1749
|
let outcome;
|
|
1586
1750
|
try {
|
|
@@ -1602,7 +1766,7 @@ function ChatComposer({
|
|
|
1602
1766
|
},
|
|
1603
1767
|
[onSend, onSendParts, failSend]
|
|
1604
1768
|
);
|
|
1605
|
-
const send =
|
|
1769
|
+
const send = useCallback3(() => {
|
|
1606
1770
|
const trimmed = text.trim();
|
|
1607
1771
|
if (isStreaming || disabled) return;
|
|
1608
1772
|
const readyFiles = pendingFiles.filter((f) => f.status === "ready");
|
|
@@ -1615,15 +1779,90 @@ function ChatComposer({
|
|
|
1615
1779
|
textRef.current = "";
|
|
1616
1780
|
dispatchSend(text, trimmed, parts, caret);
|
|
1617
1781
|
}, [text, isStreaming, disabled, onSendParts, pendingFiles, setText, dispatchSend]);
|
|
1618
|
-
const retryFailedSend =
|
|
1782
|
+
const retryFailedSend = useCallback3(() => {
|
|
1619
1783
|
const failure = failedSend;
|
|
1620
1784
|
if (!failure || isStreaming || disabled) return;
|
|
1621
1785
|
setFailedSend(null);
|
|
1622
1786
|
const caret = { start: failure.text.length, end: failure.text.length };
|
|
1623
1787
|
dispatchSend(failure.text, failure.trimmed, failure.parts, caret);
|
|
1624
1788
|
}, [failedSend, isStreaming, disabled, dispatchSend]);
|
|
1789
|
+
const slashPanelRef = useRef6(null);
|
|
1790
|
+
const cardRef = useRef6(null);
|
|
1791
|
+
const slashListId = useId();
|
|
1792
|
+
const [slashActive, setSlashActive] = useState8(0);
|
|
1793
|
+
const [slashDismissedFor, setSlashDismissedFor] = useState8(null);
|
|
1794
|
+
const slashToken = slashCommands && slashCommands.length > 0 ? /^\/(\S*)$/.exec(text)?.[1] : void 0;
|
|
1795
|
+
const slashOpen = slashToken !== void 0 && text !== slashDismissedFor;
|
|
1796
|
+
const slashItems = useMemo3(
|
|
1797
|
+
() => (slashCommands ?? []).map((command) => ({
|
|
1798
|
+
id: command.name,
|
|
1799
|
+
group: "Commands",
|
|
1800
|
+
label: `/${command.name}`,
|
|
1801
|
+
description: command.description,
|
|
1802
|
+
keywords: [command.name, command.description]
|
|
1803
|
+
})),
|
|
1804
|
+
[slashCommands]
|
|
1805
|
+
);
|
|
1806
|
+
const slashFiltered = useMemo3(
|
|
1807
|
+
() => slashToken === void 0 ? [] : filterCommandPaletteItems(slashItems, slashToken),
|
|
1808
|
+
[slashItems, slashToken]
|
|
1809
|
+
);
|
|
1810
|
+
const slashActiveIndex = slashFiltered.length === 0 ? 0 : Math.min(slashActive, slashFiltered.length - 1);
|
|
1811
|
+
useEffect6(() => {
|
|
1812
|
+
setSlashActive(0);
|
|
1813
|
+
}, [slashToken]);
|
|
1814
|
+
useEffect6(() => {
|
|
1815
|
+
if (!slashOpen) return;
|
|
1816
|
+
document.getElementById(`${slashListId}-${slashActiveIndex}`)?.scrollIntoView?.({ block: "nearest" });
|
|
1817
|
+
}, [slashOpen, slashActiveIndex, slashListId]);
|
|
1818
|
+
useEffect6(() => {
|
|
1819
|
+
if (!slashOpen) return;
|
|
1820
|
+
function onMouseDown(e) {
|
|
1821
|
+
const target = e.target;
|
|
1822
|
+
if (cardRef.current?.contains(target)) return;
|
|
1823
|
+
if (slashPanelRef.current?.contains(target)) return;
|
|
1824
|
+
setSlashDismissedFor(textRef.current);
|
|
1825
|
+
}
|
|
1826
|
+
document.addEventListener("mousedown", onMouseDown);
|
|
1827
|
+
return () => document.removeEventListener("mousedown", onMouseDown);
|
|
1828
|
+
}, [slashOpen]);
|
|
1829
|
+
const pickSlash = useCallback3(
|
|
1830
|
+
(name) => {
|
|
1831
|
+
const command = slashCommands?.find((c) => c.name === name);
|
|
1832
|
+
setText("");
|
|
1833
|
+
setSlashDismissedFor(null);
|
|
1834
|
+
command?.run();
|
|
1835
|
+
},
|
|
1836
|
+
[slashCommands, setText]
|
|
1837
|
+
);
|
|
1625
1838
|
const handleKeyDown = (e) => {
|
|
1626
1839
|
if (e.nativeEvent.isComposing) return;
|
|
1840
|
+
if (slashOpen) {
|
|
1841
|
+
if (e.key === "ArrowDown") {
|
|
1842
|
+
e.preventDefault();
|
|
1843
|
+
if (slashFiltered.length > 0) setSlashActive((slashActiveIndex + 1) % slashFiltered.length);
|
|
1844
|
+
return;
|
|
1845
|
+
}
|
|
1846
|
+
if (e.key === "ArrowUp") {
|
|
1847
|
+
e.preventDefault();
|
|
1848
|
+
if (slashFiltered.length > 0)
|
|
1849
|
+
setSlashActive((slashActiveIndex - 1 + slashFiltered.length) % slashFiltered.length);
|
|
1850
|
+
return;
|
|
1851
|
+
}
|
|
1852
|
+
if (e.key === "Enter" && !e.shiftKey || e.key === "Tab") {
|
|
1853
|
+
const item = slashFiltered[slashActiveIndex];
|
|
1854
|
+
if (item) {
|
|
1855
|
+
e.preventDefault();
|
|
1856
|
+
pickSlash(item.id);
|
|
1857
|
+
return;
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
if (e.key === "Escape") {
|
|
1861
|
+
e.preventDefault();
|
|
1862
|
+
setSlashDismissedFor(text);
|
|
1863
|
+
return;
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1627
1866
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
1628
1867
|
e.preventDefault();
|
|
1629
1868
|
send();
|
|
@@ -1637,13 +1876,13 @@ function ChatComposer({
|
|
|
1637
1876
|
if (e.target.files?.length) (onAttachFolder ?? onAttach)?.(e.target.files);
|
|
1638
1877
|
e.target.value = "";
|
|
1639
1878
|
};
|
|
1640
|
-
const handleDragEnter =
|
|
1879
|
+
const handleDragEnter = useCallback3((e) => {
|
|
1641
1880
|
e.preventDefault();
|
|
1642
1881
|
e.stopPropagation();
|
|
1643
1882
|
dragDepth.current++;
|
|
1644
1883
|
if (e.dataTransfer?.types.includes("Files")) setDragOver(true);
|
|
1645
1884
|
}, []);
|
|
1646
|
-
const handleDragLeave =
|
|
1885
|
+
const handleDragLeave = useCallback3((e) => {
|
|
1647
1886
|
e.preventDefault();
|
|
1648
1887
|
e.stopPropagation();
|
|
1649
1888
|
dragDepth.current--;
|
|
@@ -1652,12 +1891,12 @@ function ChatComposer({
|
|
|
1652
1891
|
setDragOver(false);
|
|
1653
1892
|
}
|
|
1654
1893
|
}, []);
|
|
1655
|
-
const handleDragOver =
|
|
1894
|
+
const handleDragOver = useCallback3((e) => {
|
|
1656
1895
|
e.preventDefault();
|
|
1657
1896
|
e.stopPropagation();
|
|
1658
1897
|
if (e.dataTransfer) e.dataTransfer.dropEffect = "copy";
|
|
1659
1898
|
}, []);
|
|
1660
|
-
const handleDrop =
|
|
1899
|
+
const handleDrop = useCallback3(
|
|
1661
1900
|
(e) => {
|
|
1662
1901
|
e.preventDefault();
|
|
1663
1902
|
e.stopPropagation();
|
|
@@ -1687,6 +1926,27 @@ function ChatComposer({
|
|
|
1687
1926
|
/* @__PURE__ */ jsx7("p", { className: "mt-0.5 text-xs text-muted-foreground", children: dropDescription })
|
|
1688
1927
|
] }) }),
|
|
1689
1928
|
showAbove && /* @__PURE__ */ jsx7("div", { className: "mb-1.5 flex flex-wrap items-center gap-1.5 px-1", children: controls }),
|
|
1929
|
+
dictateError && /* @__PURE__ */ jsxs5(
|
|
1930
|
+
"div",
|
|
1931
|
+
{
|
|
1932
|
+
role: "alert",
|
|
1933
|
+
"data-testid": "composer-dictate-error",
|
|
1934
|
+
className: "mb-2 flex items-start gap-2 rounded-xl border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",
|
|
1935
|
+
children: [
|
|
1936
|
+
/* @__PURE__ */ jsx7("span", { className: "min-w-0 flex-1", children: dictateError }),
|
|
1937
|
+
/* @__PURE__ */ jsx7(
|
|
1938
|
+
"button",
|
|
1939
|
+
{
|
|
1940
|
+
type: "button",
|
|
1941
|
+
"aria-label": "Dismiss dictation error",
|
|
1942
|
+
onClick: () => setDictateError(null),
|
|
1943
|
+
className: "shrink-0 font-medium underline-offset-2 hover:underline focus:outline-none focus-visible:ring-2 focus-visible:ring-destructive/50",
|
|
1944
|
+
children: "Dismiss"
|
|
1945
|
+
}
|
|
1946
|
+
)
|
|
1947
|
+
]
|
|
1948
|
+
}
|
|
1949
|
+
),
|
|
1690
1950
|
failedSend && /* @__PURE__ */ jsxs5(
|
|
1691
1951
|
"div",
|
|
1692
1952
|
{
|
|
@@ -1761,6 +2021,7 @@ function ChatComposer({
|
|
|
1761
2021
|
/* @__PURE__ */ jsxs5(
|
|
1762
2022
|
"div",
|
|
1763
2023
|
{
|
|
2024
|
+
ref: cardRef,
|
|
1764
2025
|
"data-testid": "composer-card",
|
|
1765
2026
|
className: `flex flex-col gap-1.5 rounded-2xl border border-card-edge bg-card px-3 py-2.5 transition focus-within:border-primary/40 focus-within:ring-2 focus-within:ring-primary/15 ${floating ? "shadow-raised" : ""}`,
|
|
1766
2027
|
children: [
|
|
@@ -1827,6 +2088,41 @@ function ChatComposer({
|
|
|
1827
2088
|
children: showInline && controls
|
|
1828
2089
|
}
|
|
1829
2090
|
),
|
|
2091
|
+
onDictate && dictation.supported ? dictation.recording ? /* @__PURE__ */ jsxs5("div", { className: "flex shrink-0 items-center gap-1.5", children: [
|
|
2092
|
+
/* @__PURE__ */ jsx7("span", { "aria-hidden": "true", className: "h-2 w-2 animate-pulse rounded-full bg-destructive" }),
|
|
2093
|
+
/* @__PURE__ */ jsx7(
|
|
2094
|
+
"span",
|
|
2095
|
+
{
|
|
2096
|
+
"aria-hidden": "true",
|
|
2097
|
+
"data-testid": "composer-dictate-elapsed",
|
|
2098
|
+
className: "text-xs tabular-nums text-muted-foreground",
|
|
2099
|
+
children: formatDictationElapsed(dictation.elapsedSeconds)
|
|
2100
|
+
}
|
|
2101
|
+
),
|
|
2102
|
+
/* @__PURE__ */ jsx7("span", { role: "status", className: "sr-only", children: "Recording" }),
|
|
2103
|
+
/* @__PURE__ */ jsx7(
|
|
2104
|
+
"button",
|
|
2105
|
+
{
|
|
2106
|
+
type: "button",
|
|
2107
|
+
onClick: dictation.stop,
|
|
2108
|
+
"aria-label": "Stop dictation",
|
|
2109
|
+
title: "Stop dictation",
|
|
2110
|
+
className: "shrink-0 rounded-lg p-2 text-destructive transition hover:bg-accent focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
2111
|
+
children: /* @__PURE__ */ jsx7(StopGlyph, { className: "h-4 w-4" })
|
|
2112
|
+
}
|
|
2113
|
+
)
|
|
2114
|
+
] }) : /* @__PURE__ */ jsx7(
|
|
2115
|
+
"button",
|
|
2116
|
+
{
|
|
2117
|
+
type: "button",
|
|
2118
|
+
onClick: dictation.start,
|
|
2119
|
+
disabled,
|
|
2120
|
+
"aria-label": "Dictate message",
|
|
2121
|
+
title: "Dictate message",
|
|
2122
|
+
className: "shrink-0 rounded-lg p-2 text-muted-foreground transition hover:bg-accent hover:text-foreground disabled:opacity-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
2123
|
+
children: /* @__PURE__ */ jsx7(MicGlyph, { className: "h-4 w-4" })
|
|
2124
|
+
}
|
|
2125
|
+
) : null,
|
|
1830
2126
|
isStreaming ? sendVariant === "icon" ? /* @__PURE__ */ jsx7(
|
|
1831
2127
|
"button",
|
|
1832
2128
|
{
|
|
@@ -1878,6 +2174,38 @@ function ChatComposer({
|
|
|
1878
2174
|
]
|
|
1879
2175
|
}
|
|
1880
2176
|
),
|
|
2177
|
+
/* @__PURE__ */ jsxs5(
|
|
2178
|
+
PopoverSurface,
|
|
2179
|
+
{
|
|
2180
|
+
open: slashOpen,
|
|
2181
|
+
id: slashListId,
|
|
2182
|
+
role: "listbox",
|
|
2183
|
+
triggerRef: textareaRef,
|
|
2184
|
+
panelRef: slashPanelRef,
|
|
2185
|
+
className: `w-80 overflow-y-auto rounded-xl border border-card-edge bg-popover p-1 ${OVERLAY_SHADOW}`,
|
|
2186
|
+
children: [
|
|
2187
|
+
slashFiltered.length === 0 && /* @__PURE__ */ jsx7("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "No matching commands" }),
|
|
2188
|
+
slashFiltered.map((item, index) => /* @__PURE__ */ jsxs5(
|
|
2189
|
+
"button",
|
|
2190
|
+
{
|
|
2191
|
+
type: "button",
|
|
2192
|
+
role: "option",
|
|
2193
|
+
"aria-selected": index === slashActiveIndex,
|
|
2194
|
+
id: `${slashListId}-${index}`,
|
|
2195
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
2196
|
+
onMouseMove: () => setSlashActive(index),
|
|
2197
|
+
onClick: () => pickSlash(item.id),
|
|
2198
|
+
className: `flex w-full items-center gap-2.5 rounded-md px-3 py-2.5 text-left text-sm transition ${POPOVER_OPTION_FOCUS} ${index === slashActiveIndex ? "bg-accent" : "hover:bg-accent"}`,
|
|
2199
|
+
children: [
|
|
2200
|
+
/* @__PURE__ */ jsx7("span", { className: "shrink-0 font-medium text-foreground", children: item.label }),
|
|
2201
|
+
/* @__PURE__ */ jsx7("span", { className: "truncate text-xs text-muted-foreground", children: item.description })
|
|
2202
|
+
]
|
|
2203
|
+
},
|
|
2204
|
+
item.id
|
|
2205
|
+
))
|
|
2206
|
+
]
|
|
2207
|
+
}
|
|
2208
|
+
),
|
|
1881
2209
|
focusShortcut && /* @__PURE__ */ jsx7("div", { className: "mt-1.5 flex justify-end px-1", children: /* @__PURE__ */ jsxs5("span", { className: "text-xs text-muted-foreground", children: [
|
|
1882
2210
|
/* @__PURE__ */ jsx7("kbd", { className: "rounded border border-border bg-background px-1 py-0.5 text-xs", children: IS_APPLE_PLATFORM ? "Cmd" : "Ctrl" }),
|
|
1883
2211
|
/* @__PURE__ */ jsx7("kbd", { className: "ml-0.5 rounded border border-border bg-background px-1 py-0.5 text-xs", children: "L" }),
|
|
@@ -1889,7 +2217,7 @@ function ChatComposer({
|
|
|
1889
2217
|
}
|
|
1890
2218
|
|
|
1891
2219
|
// src/web-react/durable-plan-flow.ts
|
|
1892
|
-
import { useCallback as
|
|
2220
|
+
import { useCallback as useCallback4, useEffect as useEffect7, useRef as useRef7, useState as useState9 } from "react";
|
|
1893
2221
|
var DurablePlanClientError = class extends Error {
|
|
1894
2222
|
constructor(message, status, code, currentPlan) {
|
|
1895
2223
|
super(message);
|
|
@@ -1976,14 +2304,14 @@ function createDurablePlanDecisionClient(options) {
|
|
|
1976
2304
|
};
|
|
1977
2305
|
}
|
|
1978
2306
|
function useDurablePlanFlow(options) {
|
|
1979
|
-
const [plan, setPlan] =
|
|
1980
|
-
const [deciding, setDeciding] =
|
|
1981
|
-
const [restoring, setRestoring] =
|
|
1982
|
-
const [error, setError] =
|
|
1983
|
-
const attachments =
|
|
1984
|
-
const decisionInFlight =
|
|
1985
|
-
|
|
1986
|
-
const apply =
|
|
2307
|
+
const [plan, setPlan] = useState9(options.plan);
|
|
2308
|
+
const [deciding, setDeciding] = useState9(null);
|
|
2309
|
+
const [restoring, setRestoring] = useState9(false);
|
|
2310
|
+
const [error, setError] = useState9(null);
|
|
2311
|
+
const attachments = useRef7(/* @__PURE__ */ new Map());
|
|
2312
|
+
const decisionInFlight = useRef7(false);
|
|
2313
|
+
useEffect7(() => setPlan(options.plan), [options.plan]);
|
|
2314
|
+
const apply = useCallback4(async (result) => {
|
|
1987
2315
|
setPlan(result.plan);
|
|
1988
2316
|
options.onUpdated?.(result.plan);
|
|
1989
2317
|
const receipt = result.followUp;
|
|
@@ -1996,7 +2324,7 @@ function useDurablePlanFlow(options) {
|
|
|
1996
2324
|
}
|
|
1997
2325
|
await pending;
|
|
1998
2326
|
}, [options.attachFollowUp, options.onUpdated]);
|
|
1999
|
-
const decide =
|
|
2327
|
+
const decide = useCallback4(async (decision, feedback) => {
|
|
2000
2328
|
if (decisionInFlight.current) return null;
|
|
2001
2329
|
decisionInFlight.current = true;
|
|
2002
2330
|
setDeciding(decision);
|
|
@@ -2022,7 +2350,7 @@ function useDurablePlanFlow(options) {
|
|
|
2022
2350
|
setDeciding(null);
|
|
2023
2351
|
}
|
|
2024
2352
|
}, [apply, options.client, options.onUpdated, plan.planId, plan.revision]);
|
|
2025
|
-
const restore =
|
|
2353
|
+
const restore = useCallback4(async () => {
|
|
2026
2354
|
setRestoring(true);
|
|
2027
2355
|
setError(null);
|
|
2028
2356
|
try {
|
|
@@ -2151,7 +2479,7 @@ function createDurableInteractionAnswerSubmitter(options) {
|
|
|
2151
2479
|
}
|
|
2152
2480
|
|
|
2153
2481
|
// src/web-react/use-chat-interactions.ts
|
|
2154
|
-
import { useCallback as
|
|
2482
|
+
import { useCallback as useCallback5, useMemo as useMemo4, useState as useState10 } from "react";
|
|
2155
2483
|
function hasPendingContentDuplicate(list, interaction) {
|
|
2156
2484
|
if (interaction.status !== "pending") return false;
|
|
2157
2485
|
const signature = questionInteractionContentSignature(interaction);
|
|
@@ -2230,34 +2558,34 @@ function hydrateChatInteractions(list, persisted) {
|
|
|
2230
2558
|
return persisted.reduce(upsertChatInteraction, list);
|
|
2231
2559
|
}
|
|
2232
2560
|
function useChatInteractions(options = {}) {
|
|
2233
|
-
const [interactions, setInteractions] =
|
|
2234
|
-
const upsert =
|
|
2561
|
+
const [interactions, setInteractions] = useState10([]);
|
|
2562
|
+
const upsert = useCallback5((interaction) => {
|
|
2235
2563
|
setInteractions((prev) => upsertChatInteraction(prev, interaction));
|
|
2236
2564
|
}, []);
|
|
2237
|
-
const applyCancel =
|
|
2565
|
+
const applyCancel = useCallback5((cancel) => {
|
|
2238
2566
|
setInteractions((prev) => cancelChatInteraction(prev, cancel));
|
|
2239
2567
|
}, []);
|
|
2240
|
-
const markResolved =
|
|
2568
|
+
const markResolved = useCallback5((id, status, answers) => {
|
|
2241
2569
|
setInteractions((prev) => resolveChatInteraction(prev, id, status, answers));
|
|
2242
2570
|
}, []);
|
|
2243
|
-
const restore =
|
|
2571
|
+
const restore = useCallback5((outstanding, restoreOptions) => {
|
|
2244
2572
|
setInteractions((prev) => restoreChatInteractions(prev, outstanding, {
|
|
2245
2573
|
mode: restoreOptions?.mode ?? options.mode
|
|
2246
2574
|
}));
|
|
2247
2575
|
}, [options.mode]);
|
|
2248
|
-
const hydrate =
|
|
2576
|
+
const hydrate = useCallback5((persisted) => {
|
|
2249
2577
|
setInteractions((prev) => hydrateChatInteractions(prev, persisted));
|
|
2250
2578
|
}, []);
|
|
2251
|
-
const terminalizePending =
|
|
2579
|
+
const terminalizePending = useCallback5((status) => {
|
|
2252
2580
|
setInteractions((prev) => terminalizePendingChatInteractions(prev, status));
|
|
2253
2581
|
}, []);
|
|
2254
|
-
const reset =
|
|
2255
|
-
const pending =
|
|
2582
|
+
const reset = useCallback5(() => setInteractions([]), []);
|
|
2583
|
+
const pending = useMemo4(() => interactions.filter((item) => item.status === "pending"), [interactions]);
|
|
2256
2584
|
return { interactions, pending, upsert, applyCancel, markResolved, restore, hydrate, terminalizePending, reset };
|
|
2257
2585
|
}
|
|
2258
2586
|
|
|
2259
2587
|
// src/web-react/use-file-mentions.ts
|
|
2260
|
-
import { useCallback as
|
|
2588
|
+
import { useCallback as useCallback6, useMemo as useMemo5, useRef as useRef8, useState as useState11 } from "react";
|
|
2261
2589
|
var FILE_MENTION_KIND = "file";
|
|
2262
2590
|
function toMentionItem(file) {
|
|
2263
2591
|
return { id: file.path, label: file.name, detail: file.path, kind: FILE_MENTION_KIND };
|
|
@@ -2315,12 +2643,12 @@ function useFileMentions(options) {
|
|
|
2315
2643
|
emptyText = DEFAULT_MENTION_EMPTY_TEXT
|
|
2316
2644
|
} = options;
|
|
2317
2645
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
2318
|
-
const [state, setState] =
|
|
2319
|
-
const stateRef =
|
|
2646
|
+
const [state, setState] = useState11({ kind: "idle" });
|
|
2647
|
+
const stateRef = useRef8(state);
|
|
2320
2648
|
stateRef.current = state;
|
|
2321
|
-
const inFlightRef =
|
|
2322
|
-
const [mentions, setMentions] =
|
|
2323
|
-
const load =
|
|
2649
|
+
const inFlightRef = useRef8(null);
|
|
2650
|
+
const [mentions, setMentions] = useState11([]);
|
|
2651
|
+
const load = useCallback6(() => {
|
|
2324
2652
|
if (inFlightRef.current) return inFlightRef.current;
|
|
2325
2653
|
if (stateRef.current.kind === "idle") {
|
|
2326
2654
|
stateRef.current = { kind: "loading" };
|
|
@@ -2352,10 +2680,10 @@ function useFileMentions(options) {
|
|
|
2352
2680
|
inFlightRef.current = attempt;
|
|
2353
2681
|
return attempt;
|
|
2354
2682
|
}, [fetchImpl, indexUrl]);
|
|
2355
|
-
const refresh =
|
|
2683
|
+
const refresh = useCallback6(async () => {
|
|
2356
2684
|
await load();
|
|
2357
2685
|
}, [load]);
|
|
2358
|
-
const fetchItems =
|
|
2686
|
+
const fetchItems = useCallback6(
|
|
2359
2687
|
async (query) => {
|
|
2360
2688
|
let current = stateRef.current;
|
|
2361
2689
|
if (current.kind === "idle" || current.kind === "loading") {
|
|
@@ -2370,11 +2698,11 @@ function useFileMentions(options) {
|
|
|
2370
2698
|
},
|
|
2371
2699
|
[load, limit, refreshAfterMs]
|
|
2372
2700
|
);
|
|
2373
|
-
const onMentionsChange =
|
|
2701
|
+
const onMentionsChange = useCallback6((items) => {
|
|
2374
2702
|
setMentions(items.filter((item) => item.kind === void 0 || item.kind === FILE_MENTION_KIND).map(toFileMention));
|
|
2375
2703
|
}, []);
|
|
2376
|
-
const clearMentions =
|
|
2377
|
-
const mention =
|
|
2704
|
+
const clearMentions = useCallback6(() => setMentions([]), []);
|
|
2705
|
+
const mention = useMemo5(
|
|
2378
2706
|
() => ({
|
|
2379
2707
|
fetchItems,
|
|
2380
2708
|
onMentionsChange,
|
|
@@ -2428,7 +2756,7 @@ function segmentMentionContent(content, parts) {
|
|
|
2428
2756
|
}
|
|
2429
2757
|
|
|
2430
2758
|
// src/web-react/mission-activity.tsx
|
|
2431
|
-
import { useCallback as
|
|
2759
|
+
import { useCallback as useCallback7, useEffect as useEffect8, useState as useState12 } from "react";
|
|
2432
2760
|
import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2433
2761
|
var LIVE_STATUSES = /* @__PURE__ */ new Set(["pending", "running"]);
|
|
2434
2762
|
var OK_STATUSES = /* @__PURE__ */ new Set(["completed", "done", "succeeded"]);
|
|
@@ -2488,8 +2816,8 @@ function CopyGlyph({ className }) {
|
|
|
2488
2816
|
] });
|
|
2489
2817
|
}
|
|
2490
2818
|
function TraceIdCopy({ traceId }) {
|
|
2491
|
-
const [copied, setCopied] =
|
|
2492
|
-
const copy =
|
|
2819
|
+
const [copied, setCopied] = useState12(false);
|
|
2820
|
+
const copy = useCallback7(() => {
|
|
2493
2821
|
void navigator.clipboard?.writeText(traceId).then(
|
|
2494
2822
|
() => {
|
|
2495
2823
|
setCopied(true);
|
|
@@ -2581,7 +2909,7 @@ function LaneRow({ run, staggerIndex }) {
|
|
|
2581
2909
|
] });
|
|
2582
2910
|
}
|
|
2583
2911
|
function MissionActivityLane({ activity, startedAt, nowMs }) {
|
|
2584
|
-
const [expanded, setExpanded] =
|
|
2912
|
+
const [expanded, setExpanded] = useState12(false);
|
|
2585
2913
|
if (activity.length === 0) return null;
|
|
2586
2914
|
return /* @__PURE__ */ jsxs6("div", { className: "mt-1 border-l border-border pl-3", children: [
|
|
2587
2915
|
activity.map((run, index) => /* @__PURE__ */ jsx8(LaneRow, { run, staggerIndex: index }, run.taskId)),
|
|
@@ -2614,7 +2942,7 @@ function ActivityRow({
|
|
|
2614
2942
|
staggerIndex
|
|
2615
2943
|
}) {
|
|
2616
2944
|
const arrival = useArrivalStyle(staggerIndex);
|
|
2617
|
-
const [open, setOpen] =
|
|
2945
|
+
const [open, setOpen] = useState12(false);
|
|
2618
2946
|
const tone = activityTone(record.status);
|
|
2619
2947
|
const cost = formatActivityCost(record.costUsd);
|
|
2620
2948
|
const duration = formatActivityDuration(record.durationMs);
|
|
@@ -2654,11 +2982,11 @@ function ActivityRow({
|
|
|
2654
2982
|
] });
|
|
2655
2983
|
}
|
|
2656
2984
|
function AgentActivityPanel({ fetchActivity, renderMissionRef, title = "Agent activity", emptyLabel = "No agent runs yet." }) {
|
|
2657
|
-
const [rows, setRows] =
|
|
2658
|
-
const [cursor, setCursor] =
|
|
2659
|
-
const [status, setStatus] =
|
|
2660
|
-
const [error, setError] =
|
|
2661
|
-
const load =
|
|
2985
|
+
const [rows, setRows] = useState12([]);
|
|
2986
|
+
const [cursor, setCursor] = useState12(void 0);
|
|
2987
|
+
const [status, setStatus] = useState12("loading");
|
|
2988
|
+
const [error, setError] = useState12(null);
|
|
2989
|
+
const load = useCallback7(
|
|
2662
2990
|
async (from) => {
|
|
2663
2991
|
setStatus("loading");
|
|
2664
2992
|
setError(null);
|
|
@@ -2674,7 +3002,7 @@ function AgentActivityPanel({ fetchActivity, renderMissionRef, title = "Agent ac
|
|
|
2674
3002
|
},
|
|
2675
3003
|
[fetchActivity]
|
|
2676
3004
|
);
|
|
2677
|
-
|
|
3005
|
+
useEffect8(() => {
|
|
2678
3006
|
void load();
|
|
2679
3007
|
}, [load]);
|
|
2680
3008
|
const loading = status === "loading";
|
|
@@ -2711,7 +3039,7 @@ function AgentActivityPanel({ fetchActivity, renderMissionRef, title = "Agent ac
|
|
|
2711
3039
|
}
|
|
2712
3040
|
|
|
2713
3041
|
// src/web-react/provenance.tsx
|
|
2714
|
-
import { useCallback as
|
|
3042
|
+
import { useCallback as useCallback8, useEffect as useEffect9, useId as useId2, useRef as useRef9, useState as useState13 } from "react";
|
|
2715
3043
|
|
|
2716
3044
|
// src/web-react/provenance-model.ts
|
|
2717
3045
|
var PROVENANCE_BASES = ["extracted", "entered", "computed", "asserted"];
|
|
@@ -3005,10 +3333,10 @@ function ProvenanceValue({
|
|
|
3005
3333
|
missingValueLabel = DEFAULT_MISSING_VALUE_LABEL,
|
|
3006
3334
|
className
|
|
3007
3335
|
}) {
|
|
3008
|
-
const [open, setOpen] =
|
|
3009
|
-
const triggerRef =
|
|
3010
|
-
const rootRef =
|
|
3011
|
-
const panelId =
|
|
3336
|
+
const [open, setOpen] = useState13(defaultOpen);
|
|
3337
|
+
const triggerRef = useRef9(null);
|
|
3338
|
+
const rootRef = useRef9(null);
|
|
3339
|
+
const panelId = useId2();
|
|
3012
3340
|
const standing = rollUpProvenanceStanding(record, confidencePolicy);
|
|
3013
3341
|
const basisMeta = provenanceBasisMeta(record.basis);
|
|
3014
3342
|
const standingMeta = provenanceStandingMeta(standing);
|
|
@@ -3017,7 +3345,7 @@ function ProvenanceValue({
|
|
|
3017
3345
|
const sources = record.sources ?? [];
|
|
3018
3346
|
const inputs = record.inputs ?? [];
|
|
3019
3347
|
const hasValue = record.display.trim() !== "";
|
|
3020
|
-
const onKeyDown =
|
|
3348
|
+
const onKeyDown = useCallback8(
|
|
3021
3349
|
(event) => {
|
|
3022
3350
|
if (event.key !== "Escape" || !open) return;
|
|
3023
3351
|
event.stopPropagation();
|
|
@@ -3026,11 +3354,11 @@ function ProvenanceValue({
|
|
|
3026
3354
|
},
|
|
3027
3355
|
[open]
|
|
3028
3356
|
);
|
|
3029
|
-
const onToggle =
|
|
3357
|
+
const onToggle = useCallback8(() => {
|
|
3030
3358
|
if (!open) closeTrailsOutside(rootRef.current);
|
|
3031
3359
|
setOpen(!open);
|
|
3032
3360
|
}, [open]);
|
|
3033
|
-
|
|
3361
|
+
useEffect9(() => {
|
|
3034
3362
|
const root = rootRef.current;
|
|
3035
3363
|
if (!open || root === null) return;
|
|
3036
3364
|
const entry = { root, close: () => setOpen(false) };
|
|
@@ -3286,12 +3614,12 @@ function SeatPaywall({
|
|
|
3286
3614
|
|
|
3287
3615
|
// src/web-react/session-history.tsx
|
|
3288
3616
|
import {
|
|
3289
|
-
useCallback as
|
|
3290
|
-
useEffect as
|
|
3291
|
-
useId as
|
|
3292
|
-
useMemo as
|
|
3293
|
-
useRef as
|
|
3294
|
-
useState as
|
|
3617
|
+
useCallback as useCallback9,
|
|
3618
|
+
useEffect as useEffect10,
|
|
3619
|
+
useId as useId3,
|
|
3620
|
+
useMemo as useMemo6,
|
|
3621
|
+
useRef as useRef10,
|
|
3622
|
+
useState as useState14
|
|
3295
3623
|
} from "react";
|
|
3296
3624
|
import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
3297
3625
|
function rethrowAsync(error) {
|
|
@@ -3300,13 +3628,13 @@ function rethrowAsync(error) {
|
|
|
3300
3628
|
});
|
|
3301
3629
|
}
|
|
3302
3630
|
function useInfiniteScroll(onLoadMore, { enabled, root, rootMargin = "300px" }) {
|
|
3303
|
-
const [sentinel, setSentinel] =
|
|
3304
|
-
const sentinelRef =
|
|
3305
|
-
const onLoadMoreRef =
|
|
3306
|
-
|
|
3631
|
+
const [sentinel, setSentinel] = useState14(null);
|
|
3632
|
+
const sentinelRef = useCallback9((node) => setSentinel(node), []);
|
|
3633
|
+
const onLoadMoreRef = useRef10(onLoadMore);
|
|
3634
|
+
useEffect10(() => {
|
|
3307
3635
|
onLoadMoreRef.current = onLoadMore;
|
|
3308
3636
|
}, [onLoadMore]);
|
|
3309
|
-
|
|
3637
|
+
useEffect10(() => {
|
|
3310
3638
|
if (!sentinel || !enabled) return;
|
|
3311
3639
|
if (typeof IntersectionObserver === "undefined") return;
|
|
3312
3640
|
const observer = new IntersectionObserver(
|
|
@@ -3335,24 +3663,24 @@ function useSessionHistory({
|
|
|
3335
3663
|
initialPage,
|
|
3336
3664
|
defaultSort = "newest"
|
|
3337
3665
|
}) {
|
|
3338
|
-
const [items, setItems] =
|
|
3339
|
-
const [nextCursor, setNextCursor] =
|
|
3340
|
-
const [phase, setPhase] =
|
|
3341
|
-
const [reloadKey, setReloadKey] =
|
|
3342
|
-
const seqRef =
|
|
3343
|
-
const resetAbortRef =
|
|
3344
|
-
const loadMoreAbortRef =
|
|
3345
|
-
const loadingMoreRef =
|
|
3346
|
-
const lastOpRef =
|
|
3347
|
-
const nextCursorRef =
|
|
3666
|
+
const [items, setItems] = useState14(initialPage.items);
|
|
3667
|
+
const [nextCursor, setNextCursor] = useState14(initialPage.nextCursor ?? null);
|
|
3668
|
+
const [phase, setPhase] = useState14("idle");
|
|
3669
|
+
const [reloadKey, setReloadKey] = useState14(0);
|
|
3670
|
+
const seqRef = useRef10(0);
|
|
3671
|
+
const resetAbortRef = useRef10(null);
|
|
3672
|
+
const loadMoreAbortRef = useRef10(null);
|
|
3673
|
+
const loadingMoreRef = useRef10(false);
|
|
3674
|
+
const lastOpRef = useRef10("first");
|
|
3675
|
+
const nextCursorRef = useRef10(nextCursor);
|
|
3348
3676
|
nextCursorRef.current = nextCursor;
|
|
3349
|
-
const viewRef =
|
|
3677
|
+
const viewRef = useRef10({ q, sort, fetchPage });
|
|
3350
3678
|
viewRef.current = { q, sort, fetchPage };
|
|
3351
|
-
const seedRef =
|
|
3679
|
+
const seedRef = useRef10(initialPage);
|
|
3352
3680
|
seedRef.current = initialPage;
|
|
3353
3681
|
const isDefaultView = q === "" && sort === defaultSort;
|
|
3354
|
-
const seedKey =
|
|
3355
|
-
|
|
3682
|
+
const seedKey = useMemo6(() => seedSignature(initialPage), [initialPage]);
|
|
3683
|
+
useEffect10(() => {
|
|
3356
3684
|
resetAbortRef.current?.abort();
|
|
3357
3685
|
loadMoreAbortRef.current?.abort();
|
|
3358
3686
|
loadingMoreRef.current = false;
|
|
@@ -3383,7 +3711,7 @@ function useSessionHistory({
|
|
|
3383
3711
|
})();
|
|
3384
3712
|
return () => controller.abort();
|
|
3385
3713
|
}, [q, sort, seedKey, isDefaultView, reloadKey]);
|
|
3386
|
-
const loadMore =
|
|
3714
|
+
const loadMore = useCallback9(() => {
|
|
3387
3715
|
const cursor = nextCursorRef.current;
|
|
3388
3716
|
if (!cursor || loadingMoreRef.current) return;
|
|
3389
3717
|
const { q: currentQ, sort: currentSort, fetchPage: currentFetch } = viewRef.current;
|
|
@@ -3408,14 +3736,14 @@ function useSessionHistory({
|
|
|
3408
3736
|
}
|
|
3409
3737
|
})();
|
|
3410
3738
|
}, []);
|
|
3411
|
-
const retry =
|
|
3739
|
+
const retry = useCallback9(() => {
|
|
3412
3740
|
if (lastOpRef.current === "more") loadMore();
|
|
3413
3741
|
else setReloadKey((key) => key + 1);
|
|
3414
3742
|
}, [loadMore]);
|
|
3415
|
-
const reload =
|
|
3743
|
+
const reload = useCallback9(() => {
|
|
3416
3744
|
setReloadKey((key) => key + 1);
|
|
3417
3745
|
}, []);
|
|
3418
|
-
|
|
3746
|
+
useEffect10(
|
|
3419
3747
|
() => () => {
|
|
3420
3748
|
resetAbortRef.current?.abort();
|
|
3421
3749
|
loadMoreAbortRef.current?.abort();
|
|
@@ -3456,21 +3784,21 @@ function useSessionActions({
|
|
|
3456
3784
|
labels
|
|
3457
3785
|
}) {
|
|
3458
3786
|
const text = { ...DEFAULT_LABELS, ...labels };
|
|
3459
|
-
const [renameTarget, setRenameTarget] =
|
|
3460
|
-
const [renameValue, setRenameValue] =
|
|
3461
|
-
const [deleteTarget, setDeleteTarget] =
|
|
3462
|
-
const [busy, setBusy] =
|
|
3463
|
-
const [error, setError] =
|
|
3464
|
-
const openRename =
|
|
3787
|
+
const [renameTarget, setRenameTarget] = useState14(null);
|
|
3788
|
+
const [renameValue, setRenameValue] = useState14("");
|
|
3789
|
+
const [deleteTarget, setDeleteTarget] = useState14(null);
|
|
3790
|
+
const [busy, setBusy] = useState14(false);
|
|
3791
|
+
const [error, setError] = useState14(null);
|
|
3792
|
+
const openRename = useCallback9((session) => {
|
|
3465
3793
|
setError(null);
|
|
3466
3794
|
setRenameTarget(session);
|
|
3467
3795
|
setRenameValue(session.title ?? "");
|
|
3468
3796
|
}, []);
|
|
3469
|
-
const openDelete =
|
|
3797
|
+
const openDelete = useCallback9((session) => {
|
|
3470
3798
|
setError(null);
|
|
3471
3799
|
setDeleteTarget(session);
|
|
3472
3800
|
}, []);
|
|
3473
|
-
const submitRename =
|
|
3801
|
+
const submitRename = useCallback9(async () => {
|
|
3474
3802
|
if (!renameTarget) return;
|
|
3475
3803
|
const title = renameValue.trim();
|
|
3476
3804
|
if (!title || title === renameTarget.title) {
|
|
@@ -3492,7 +3820,7 @@ function useSessionActions({
|
|
|
3492
3820
|
setBusy(false);
|
|
3493
3821
|
}
|
|
3494
3822
|
}, [renameTarget, renameValue, renameSession, notify, onChanged, text.renamed, text.renameFailed]);
|
|
3495
|
-
const confirmDelete =
|
|
3823
|
+
const confirmDelete = useCallback9(async () => {
|
|
3496
3824
|
if (!deleteTarget) return;
|
|
3497
3825
|
const deletingCurrent = currentSessionId != null && deleteTarget.id === currentSessionId;
|
|
3498
3826
|
setBusy(true);
|
|
@@ -3587,7 +3915,7 @@ function SessionDialog({
|
|
|
3587
3915
|
busy,
|
|
3588
3916
|
error
|
|
3589
3917
|
}) {
|
|
3590
|
-
|
|
3918
|
+
useEffect10(() => {
|
|
3591
3919
|
const onKey = (e) => {
|
|
3592
3920
|
if (e.key === "Escape" && !busy) onClose();
|
|
3593
3921
|
};
|
|
@@ -3677,7 +4005,7 @@ function SessionHistoryPanel({
|
|
|
3677
4005
|
contentWidth = "reading",
|
|
3678
4006
|
className
|
|
3679
4007
|
}) {
|
|
3680
|
-
const scrollRef =
|
|
4008
|
+
const scrollRef = useRef10(null);
|
|
3681
4009
|
const sentinelRef = useInfiniteScroll(history.loadMore, {
|
|
3682
4010
|
enabled: history.hasMore && !history.isLoadingMore && !history.isError,
|
|
3683
4011
|
root: scrollRef,
|
|
@@ -3686,15 +4014,15 @@ function SessionHistoryPanel({
|
|
|
3686
4014
|
const searchTerm = query.trim();
|
|
3687
4015
|
const isSearching = searchTerm.length > 0;
|
|
3688
4016
|
const column = contentWidth === "full" ? "w-full" : "mx-auto w-full max-w-4xl";
|
|
3689
|
-
const [selectedIds, setSelectedIds] =
|
|
3690
|
-
const [ageDays, setAgeDays] =
|
|
3691
|
-
const [bulkTarget, setBulkTarget] =
|
|
3692
|
-
const [bulkBusy, setBulkBusy] =
|
|
3693
|
-
const [bulkError, setBulkError] =
|
|
3694
|
-
|
|
4017
|
+
const [selectedIds, setSelectedIds] = useState14(/* @__PURE__ */ new Set());
|
|
4018
|
+
const [ageDays, setAgeDays] = useState14("30");
|
|
4019
|
+
const [bulkTarget, setBulkTarget] = useState14(null);
|
|
4020
|
+
const [bulkBusy, setBulkBusy] = useState14(false);
|
|
4021
|
+
const [bulkError, setBulkError] = useState14(null);
|
|
4022
|
+
useEffect10(() => {
|
|
3695
4023
|
setSelectedIds(/* @__PURE__ */ new Set());
|
|
3696
4024
|
}, [searchTerm, sort]);
|
|
3697
|
-
|
|
4025
|
+
useEffect10(() => {
|
|
3698
4026
|
const visible = new Set(history.items.map((item) => item.id));
|
|
3699
4027
|
setSelectedIds((current) => {
|
|
3700
4028
|
const next = new Set([...current].filter((id) => visible.has(id)));
|
|
@@ -3705,7 +4033,7 @@ function SessionHistoryPanel({
|
|
|
3705
4033
|
const allVisibleSelected = history.items.length > 0 && history.items.every((item) => selectedIds.has(item.id));
|
|
3706
4034
|
const parsedAgeDays = Number(ageDays);
|
|
3707
4035
|
const validAgeDays = Number.isInteger(parsedAgeDays) && parsedAgeDays >= 1 && parsedAgeDays <= 36500;
|
|
3708
|
-
const openBulkAction =
|
|
4036
|
+
const openBulkAction = useCallback9((action) => {
|
|
3709
4037
|
const verb = deleteLabel.toLowerCase();
|
|
3710
4038
|
if (action.kind === "selected") {
|
|
3711
4039
|
setBulkTarget({
|
|
@@ -3722,7 +4050,7 @@ function SessionHistoryPanel({
|
|
|
3722
4050
|
body: "This applies to every matching session in this workspace, including sessions not currently loaded in this list."
|
|
3723
4051
|
});
|
|
3724
4052
|
}, [deleteLabel]);
|
|
3725
|
-
const confirmBulkAction =
|
|
4053
|
+
const confirmBulkAction = useCallback9(async () => {
|
|
3726
4054
|
if (!bulkTarget || !onBulkAction) return;
|
|
3727
4055
|
setBulkBusy(true);
|
|
3728
4056
|
setBulkError(null);
|
|
@@ -3970,8 +4298,8 @@ function SessionRow({
|
|
|
3970
4298
|
selected,
|
|
3971
4299
|
onSelectedChange
|
|
3972
4300
|
}) {
|
|
3973
|
-
const [menuOpen, setMenuOpen] =
|
|
3974
|
-
const panelId =
|
|
4301
|
+
const [menuOpen, setMenuOpen] = useState14(false);
|
|
4302
|
+
const panelId = useId3();
|
|
3975
4303
|
const { containerRef, triggerRef, panelRef, triggerProps } = usePopover(menuOpen, setMenuOpen);
|
|
3976
4304
|
const extras = extraActions?.(session) ?? [];
|
|
3977
4305
|
const hasMenu = Boolean(onRename) || Boolean(onDelete) || extras.length > 0;
|
|
@@ -4074,12 +4402,12 @@ function SessionRow({
|
|
|
4074
4402
|
import {
|
|
4075
4403
|
Fragment as Fragment6,
|
|
4076
4404
|
isValidElement,
|
|
4077
|
-
useCallback as
|
|
4078
|
-
useEffect as
|
|
4079
|
-
useId as
|
|
4080
|
-
useMemo as
|
|
4081
|
-
useRef as
|
|
4082
|
-
useState as
|
|
4405
|
+
useCallback as useCallback10,
|
|
4406
|
+
useEffect as useEffect11,
|
|
4407
|
+
useId as useId4,
|
|
4408
|
+
useMemo as useMemo7,
|
|
4409
|
+
useRef as useRef11,
|
|
4410
|
+
useState as useState15
|
|
4083
4411
|
} from "react";
|
|
4084
4412
|
|
|
4085
4413
|
// src/web-react/record-grid-model.ts
|
|
@@ -4098,6 +4426,32 @@ function isRecordGridCellApplicable(column, values) {
|
|
|
4098
4426
|
function sameRecordGridValue(a, b) {
|
|
4099
4427
|
return Object.is(a ?? null, b ?? null);
|
|
4100
4428
|
}
|
|
4429
|
+
function diffRecordGridProposal(rows, proposal) {
|
|
4430
|
+
const updates = proposal.updates ?? {};
|
|
4431
|
+
const removals = new Set(proposal.removals ?? []);
|
|
4432
|
+
const additions = proposal.additions ?? [];
|
|
4433
|
+
const liveIds = new Set(rows.map((row) => row.id));
|
|
4434
|
+
const diffs = [];
|
|
4435
|
+
for (const row of rows) {
|
|
4436
|
+
if (removals.has(row.id)) {
|
|
4437
|
+
diffs.push({ rowId: row.id, kind: "removed", cells: [], row });
|
|
4438
|
+
continue;
|
|
4439
|
+
}
|
|
4440
|
+
const patch = updates[row.id];
|
|
4441
|
+
if (patch === void 0) continue;
|
|
4442
|
+
const cells = [];
|
|
4443
|
+
for (const [columnId, after] of Object.entries(patch)) {
|
|
4444
|
+
const before = row.values[columnId] ?? null;
|
|
4445
|
+
if (!sameRecordGridValue(before, after)) cells.push({ columnId, before, after });
|
|
4446
|
+
}
|
|
4447
|
+
if (cells.length > 0) diffs.push({ rowId: row.id, kind: "changed", cells, row });
|
|
4448
|
+
}
|
|
4449
|
+
for (const row of additions) {
|
|
4450
|
+
if (liveIds.has(row.id)) continue;
|
|
4451
|
+
diffs.push({ rowId: row.id, kind: "added", cells: [], row });
|
|
4452
|
+
}
|
|
4453
|
+
return diffs;
|
|
4454
|
+
}
|
|
4101
4455
|
var NUMERIC = /^[+-]?(?:\d+(?:\.\d+)?|\.\d+)$/;
|
|
4102
4456
|
var ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
4103
4457
|
function parseNumericText(raw) {
|
|
@@ -4456,6 +4810,11 @@ function RecordGrid({
|
|
|
4456
4810
|
onCreate,
|
|
4457
4811
|
onUpdate,
|
|
4458
4812
|
onDelete,
|
|
4813
|
+
proposed,
|
|
4814
|
+
onAcceptRow,
|
|
4815
|
+
onRejectRow,
|
|
4816
|
+
onAcceptAll,
|
|
4817
|
+
onRejectAll,
|
|
4459
4818
|
newRowDefaults,
|
|
4460
4819
|
addLabel = "Add row",
|
|
4461
4820
|
locale,
|
|
@@ -4463,40 +4822,57 @@ function RecordGrid({
|
|
|
4463
4822
|
loadingRowCount = 3,
|
|
4464
4823
|
className
|
|
4465
4824
|
}) {
|
|
4466
|
-
const fieldPrefix =
|
|
4467
|
-
const [overlay, setOverlay] =
|
|
4468
|
-
const [editing, setEditingState] =
|
|
4469
|
-
const [cellErrors, setCellErrors] =
|
|
4470
|
-
const [rowErrors, setRowErrors] =
|
|
4471
|
-
const [pendingRows, setPendingRows] =
|
|
4472
|
-
const [focus, setFocus] =
|
|
4473
|
-
const [openSource, setOpenSource] =
|
|
4474
|
-
const [confirmDelete, setConfirmDelete] =
|
|
4475
|
-
const [adding, setAdding] =
|
|
4476
|
-
const [draft, setDraft] =
|
|
4477
|
-
const [draftErrors, setDraftErrors] =
|
|
4478
|
-
const [draftError, setDraftError] =
|
|
4479
|
-
const [creating, setCreating] =
|
|
4480
|
-
const cellRefs =
|
|
4481
|
-
const settling =
|
|
4482
|
-
const draftCounter =
|
|
4483
|
-
const editingRef =
|
|
4484
|
-
const setEditing =
|
|
4825
|
+
const fieldPrefix = useId4();
|
|
4826
|
+
const [overlay, setOverlay] = useState15(EMPTY_RECORD_GRID_OVERLAY);
|
|
4827
|
+
const [editing, setEditingState] = useState15(null);
|
|
4828
|
+
const [cellErrors, setCellErrors] = useState15({});
|
|
4829
|
+
const [rowErrors, setRowErrors] = useState15({});
|
|
4830
|
+
const [pendingRows, setPendingRows] = useState15({});
|
|
4831
|
+
const [focus, setFocus] = useState15(null);
|
|
4832
|
+
const [openSource, setOpenSource] = useState15(null);
|
|
4833
|
+
const [confirmDelete, setConfirmDelete] = useState15(null);
|
|
4834
|
+
const [adding, setAdding] = useState15(false);
|
|
4835
|
+
const [draft, setDraft] = useState15({ ...newRowDefaults ?? {} });
|
|
4836
|
+
const [draftErrors, setDraftErrors] = useState15({});
|
|
4837
|
+
const [draftError, setDraftError] = useState15(null);
|
|
4838
|
+
const [creating, setCreating] = useState15(false);
|
|
4839
|
+
const cellRefs = useRef11(/* @__PURE__ */ new Map());
|
|
4840
|
+
const settling = useRef11(false);
|
|
4841
|
+
const draftCounter = useRef11(0);
|
|
4842
|
+
const editingRef = useRef11(null);
|
|
4843
|
+
const setEditing = useCallback10((next) => {
|
|
4485
4844
|
editingRef.current = next;
|
|
4486
4845
|
setEditingState(next);
|
|
4487
4846
|
}, []);
|
|
4488
4847
|
const callerRows = state.status === "ready" || state.status === "empty" ? state.value : EMPTY_RECORD_GRID_ROWS;
|
|
4489
|
-
|
|
4848
|
+
useEffect11(() => {
|
|
4490
4849
|
setOverlay((current) => pruneRecordGridOverlay(callerRows, current));
|
|
4491
4850
|
}, [callerRows]);
|
|
4492
|
-
const visibleRows =
|
|
4493
|
-
const
|
|
4851
|
+
const visibleRows = useMemo7(() => projectRecordGridRows(callerRows, overlay), [callerRows, overlay]);
|
|
4852
|
+
const diffs = useMemo7(
|
|
4853
|
+
() => proposed === void 0 ? null : diffRecordGridProposal(visibleRows, proposed),
|
|
4854
|
+
[proposed, visibleRows]
|
|
4855
|
+
);
|
|
4856
|
+
const reviewing = diffs !== null && diffs.length > 0;
|
|
4857
|
+
const diffByRow = useMemo7(() => new Map((diffs ?? []).map((diff) => [diff.rowId, diff])), [diffs]);
|
|
4858
|
+
const diffCellByKey = useMemo7(() => {
|
|
4859
|
+
const map = /* @__PURE__ */ new Map();
|
|
4860
|
+
for (const diff of diffs ?? []) {
|
|
4861
|
+
for (const cell of diff.cells) map.set(cellKey(diff.rowId, cell.columnId), cell);
|
|
4862
|
+
}
|
|
4863
|
+
return map;
|
|
4864
|
+
}, [diffs]);
|
|
4865
|
+
const addedRows = useMemo7(
|
|
4866
|
+
() => (diffs ?? []).filter((diff) => diff.kind === "added").map((diff) => diff.row),
|
|
4867
|
+
[diffs]
|
|
4868
|
+
);
|
|
4869
|
+
const activeFocus = useMemo7(() => {
|
|
4494
4870
|
if (focus === null) return null;
|
|
4495
4871
|
if (!visibleRows.some((row) => row.id === focus.rowId)) return null;
|
|
4496
4872
|
if (!columns.some((column) => column.id === focus.columnId)) return null;
|
|
4497
4873
|
return focus;
|
|
4498
4874
|
}, [columns, focus, visibleRows]);
|
|
4499
|
-
const setCellError =
|
|
4875
|
+
const setCellError = useCallback10((key, message) => {
|
|
4500
4876
|
setCellErrors((current) => {
|
|
4501
4877
|
if (message === null) {
|
|
4502
4878
|
if (!(key in current)) return current;
|
|
@@ -4508,7 +4884,7 @@ function RecordGrid({
|
|
|
4508
4884
|
return { ...current, [key]: message };
|
|
4509
4885
|
});
|
|
4510
4886
|
}, []);
|
|
4511
|
-
const setRowError =
|
|
4887
|
+
const setRowError = useCallback10((rowId, message) => {
|
|
4512
4888
|
setRowErrors((current) => {
|
|
4513
4889
|
if (message === null) {
|
|
4514
4890
|
if (!(rowId in current)) return current;
|
|
@@ -4519,7 +4895,7 @@ function RecordGrid({
|
|
|
4519
4895
|
return { ...current, [rowId]: message };
|
|
4520
4896
|
});
|
|
4521
4897
|
}, []);
|
|
4522
|
-
const setRowPending =
|
|
4898
|
+
const setRowPending = useCallback10((rowId, pending) => {
|
|
4523
4899
|
setPendingRows((current) => {
|
|
4524
4900
|
if (pending) return rowId in current ? current : { ...current, [rowId]: true };
|
|
4525
4901
|
if (!(rowId in current)) return current;
|
|
@@ -4528,11 +4904,11 @@ function RecordGrid({
|
|
|
4528
4904
|
return next;
|
|
4529
4905
|
});
|
|
4530
4906
|
}, []);
|
|
4531
|
-
const focusCell =
|
|
4907
|
+
const focusCell = useCallback10((rowId, columnId) => {
|
|
4532
4908
|
setFocus({ rowId, columnId });
|
|
4533
4909
|
cellRefs.current.get(cellKey(rowId, columnId))?.focus();
|
|
4534
4910
|
}, []);
|
|
4535
|
-
const beginEdit =
|
|
4911
|
+
const beginEdit = useCallback10(
|
|
4536
4912
|
(row, column) => {
|
|
4537
4913
|
setCellError(cellKey(row.id, column.id), null);
|
|
4538
4914
|
setEditing({
|
|
@@ -4543,7 +4919,7 @@ function RecordGrid({
|
|
|
4543
4919
|
},
|
|
4544
4920
|
[setCellError, setEditing]
|
|
4545
4921
|
);
|
|
4546
|
-
const applyCellWrite =
|
|
4922
|
+
const applyCellWrite = useCallback10(
|
|
4547
4923
|
async (row, column, value) => {
|
|
4548
4924
|
if (!onUpdate) return;
|
|
4549
4925
|
const values = { ...row.values, [column.id]: value };
|
|
@@ -4571,7 +4947,7 @@ function RecordGrid({
|
|
|
4571
4947
|
},
|
|
4572
4948
|
[locale, onUpdate, setRowError, setRowPending]
|
|
4573
4949
|
);
|
|
4574
|
-
const commitEdit =
|
|
4950
|
+
const commitEdit = useCallback10(
|
|
4575
4951
|
async (row, column, text) => {
|
|
4576
4952
|
const open = editingRef.current;
|
|
4577
4953
|
if (open === null || open.rowId !== row.id || open.columnId !== column.id) return;
|
|
@@ -4595,7 +4971,7 @@ function RecordGrid({
|
|
|
4595
4971
|
},
|
|
4596
4972
|
[applyCellWrite, setCellError, setEditing]
|
|
4597
4973
|
);
|
|
4598
|
-
const cancelEdit =
|
|
4974
|
+
const cancelEdit = useCallback10(
|
|
4599
4975
|
(row, column) => {
|
|
4600
4976
|
setCellError(cellKey(row.id, column.id), null);
|
|
4601
4977
|
setEditing(null);
|
|
@@ -4603,7 +4979,7 @@ function RecordGrid({
|
|
|
4603
4979
|
},
|
|
4604
4980
|
[focusCell, setCellError, setEditing]
|
|
4605
4981
|
);
|
|
4606
|
-
const performDelete =
|
|
4982
|
+
const performDelete = useCallback10(
|
|
4607
4983
|
async (row) => {
|
|
4608
4984
|
if (!onDelete) return;
|
|
4609
4985
|
setConfirmDelete(null);
|
|
@@ -4621,16 +4997,16 @@ function RecordGrid({
|
|
|
4621
4997
|
},
|
|
4622
4998
|
[columns, onDelete, setRowError]
|
|
4623
4999
|
);
|
|
4624
|
-
const resetDraft =
|
|
5000
|
+
const resetDraft = useCallback10(() => {
|
|
4625
5001
|
setDraft({ ...newRowDefaults ?? {} });
|
|
4626
5002
|
setDraftErrors({});
|
|
4627
5003
|
setDraftError(null);
|
|
4628
5004
|
}, [newRowDefaults]);
|
|
4629
|
-
const openAdd =
|
|
5005
|
+
const openAdd = useCallback10(() => {
|
|
4630
5006
|
resetDraft();
|
|
4631
5007
|
setAdding(true);
|
|
4632
5008
|
}, [resetDraft]);
|
|
4633
|
-
const submitDraft =
|
|
5009
|
+
const submitDraft = useCallback10(async () => {
|
|
4634
5010
|
if (!onCreate) return;
|
|
4635
5011
|
const validated = validateRecordGridRow(columns, draft);
|
|
4636
5012
|
if (!validated.succeeded) {
|
|
@@ -4660,7 +5036,7 @@ function RecordGrid({
|
|
|
4660
5036
|
setOverlay((current) => withoutRecordGridCreated(current, draftId));
|
|
4661
5037
|
setDraftError(outcome.error);
|
|
4662
5038
|
}, [columns, draft, fieldPrefix, onCreate, resetDraft]);
|
|
4663
|
-
const handleGridKeyDown =
|
|
5039
|
+
const handleGridKeyDown = useCallback10(
|
|
4664
5040
|
(event) => {
|
|
4665
5041
|
if (editing !== null) return;
|
|
4666
5042
|
const target = event.target;
|
|
@@ -4674,7 +5050,7 @@ function RecordGrid({
|
|
|
4674
5050
|
const row = visibleRows[rowIndex];
|
|
4675
5051
|
const column = columns[columnIndex];
|
|
4676
5052
|
if (!row || !column) return;
|
|
4677
|
-
if (!onUpdate || column.editable === false || row.readOnly === true) return;
|
|
5053
|
+
if (reviewing || !onUpdate || column.editable === false || row.readOnly === true) return;
|
|
4678
5054
|
if (column.kind === "boolean") return;
|
|
4679
5055
|
if (!isRecordGridCellApplicable(column, row.values)) return;
|
|
4680
5056
|
event.preventDefault();
|
|
@@ -4696,7 +5072,7 @@ function RecordGrid({
|
|
|
4696
5072
|
if (!destinationRow || !destinationColumn) return;
|
|
4697
5073
|
focusCell(destinationRow.id, destinationColumn.id);
|
|
4698
5074
|
},
|
|
4699
|
-
[beginEdit, columns, editing, focusCell, onUpdate, visibleRows]
|
|
5075
|
+
[beginEdit, columns, editing, focusCell, onUpdate, reviewing, visibleRows]
|
|
4700
5076
|
);
|
|
4701
5077
|
if (state.status === "idle" || state.status === "loading") {
|
|
4702
5078
|
return /* @__PURE__ */ jsxs10("div", { className: `space-y-3 ${className ?? ""}`, children: [
|
|
@@ -4736,7 +5112,7 @@ function RecordGrid({
|
|
|
4736
5112
|
] })
|
|
4737
5113
|
] });
|
|
4738
5114
|
}
|
|
4739
|
-
const addForm = adding && onCreate ? /* @__PURE__ */ jsx12(
|
|
5115
|
+
const addForm = adding && onCreate && !reviewing ? /* @__PURE__ */ jsx12(
|
|
4740
5116
|
AddRecordForm,
|
|
4741
5117
|
{
|
|
4742
5118
|
columns,
|
|
@@ -4754,7 +5130,7 @@ function RecordGrid({
|
|
|
4754
5130
|
}
|
|
4755
5131
|
}
|
|
4756
5132
|
) : null;
|
|
4757
|
-
if (visibleRows.length === 0) {
|
|
5133
|
+
if (visibleRows.length === 0 && !reviewing) {
|
|
4758
5134
|
return /* @__PURE__ */ jsxs10("div", { className: `space-y-3 ${className ?? ""}`, children: [
|
|
4759
5135
|
toolbar,
|
|
4760
5136
|
addForm ?? /* @__PURE__ */ jsxs10("div", { className: "rounded-xl border border-dashed border-border px-6 py-10 text-center", children: [
|
|
@@ -4784,9 +5160,55 @@ function RecordGrid({
|
|
|
4784
5160
|
] });
|
|
4785
5161
|
}
|
|
4786
5162
|
const hasFooter = columns.some((column) => column.footerValue !== void 0);
|
|
4787
|
-
const
|
|
5163
|
+
const showActionsColumn = reviewing || onDelete !== void 0;
|
|
5164
|
+
const columnSpan = columns.length + (showActionsColumn ? 1 : 0);
|
|
5165
|
+
const changedCount = (diffs ?? []).filter((diff) => diff.kind === "changed").length;
|
|
5166
|
+
const addedCount = addedRows.length;
|
|
5167
|
+
const removedCount = (diffs ?? []).filter((diff) => diff.kind === "removed").length;
|
|
5168
|
+
const changedCellCount = (diffs ?? []).reduce((total, diff) => total + diff.cells.length, 0);
|
|
5169
|
+
const reviewSummary = [
|
|
5170
|
+
changedCount > 0 ? `${changedCount} changed (${changedCellCount} ${changedCellCount === 1 ? "cell" : "cells"})` : null,
|
|
5171
|
+
addedCount > 0 ? `${addedCount} added` : null,
|
|
5172
|
+
removedCount > 0 ? `${removedCount} removed` : null
|
|
5173
|
+
].filter((part) => part !== null).join(" \xB7 ");
|
|
5174
|
+
const reviewBar = reviewing ? /* @__PURE__ */ jsxs10(
|
|
5175
|
+
"div",
|
|
5176
|
+
{
|
|
5177
|
+
"data-record-grid-review": "",
|
|
5178
|
+
className: "flex flex-wrap items-center justify-between gap-3 rounded-xl border border-card-edge bg-card px-4 py-2.5",
|
|
5179
|
+
children: [
|
|
5180
|
+
/* @__PURE__ */ jsxs10("div", { className: "min-w-0", children: [
|
|
5181
|
+
/* @__PURE__ */ jsx12("p", { className: "text-[11px] font-semibold uppercase tracking-[0.05em] text-muted-foreground", children: "Proposed changes" }),
|
|
5182
|
+
/* @__PURE__ */ jsx12("p", { className: "mt-0.5 text-xs tabular-nums text-muted-foreground", children: reviewSummary })
|
|
5183
|
+
] }),
|
|
5184
|
+
(onAcceptAll || onRejectAll) && /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2", children: [
|
|
5185
|
+
onRejectAll && /* @__PURE__ */ jsx12(
|
|
5186
|
+
"button",
|
|
5187
|
+
{
|
|
5188
|
+
type: "button",
|
|
5189
|
+
"aria-label": `Reject all proposed changes to ${caption}`,
|
|
5190
|
+
onClick: onRejectAll,
|
|
5191
|
+
className: "rounded-md border border-border px-3 py-1.5 text-xs font-medium text-muted-foreground transition hover:bg-accent",
|
|
5192
|
+
children: "Reject all"
|
|
5193
|
+
}
|
|
5194
|
+
),
|
|
5195
|
+
onAcceptAll && /* @__PURE__ */ jsx12(
|
|
5196
|
+
"button",
|
|
5197
|
+
{
|
|
5198
|
+
type: "button",
|
|
5199
|
+
"aria-label": `Accept all proposed changes to ${caption}`,
|
|
5200
|
+
onClick: onAcceptAll,
|
|
5201
|
+
className: "rounded-md bg-success/10 px-3 py-1.5 text-xs font-medium text-success transition hover:bg-success/20",
|
|
5202
|
+
children: "Accept all"
|
|
5203
|
+
}
|
|
5204
|
+
)
|
|
5205
|
+
] })
|
|
5206
|
+
]
|
|
5207
|
+
}
|
|
5208
|
+
) : null;
|
|
4788
5209
|
return /* @__PURE__ */ jsxs10("div", { className: `space-y-3 ${className ?? ""}`, children: [
|
|
4789
5210
|
toolbar,
|
|
5211
|
+
reviewBar,
|
|
4790
5212
|
/* @__PURE__ */ jsx12("div", { className: "overflow-x-auto rounded-xl border border-card-edge bg-card", children: /* @__PURE__ */ jsxs10(
|
|
4791
5213
|
"table",
|
|
4792
5214
|
{
|
|
@@ -4806,149 +5228,222 @@ function RecordGrid({
|
|
|
4806
5228
|
},
|
|
4807
5229
|
column.id
|
|
4808
5230
|
)),
|
|
4809
|
-
|
|
5231
|
+
showActionsColumn && /* @__PURE__ */ jsx12("th", { role: "columnheader", scope: "col", className: "w-px px-3 py-2 font-medium", children: /* @__PURE__ */ jsx12("span", { className: "sr-only", children: reviewing ? "Review" : "Row actions" }) })
|
|
4810
5232
|
] }) }),
|
|
4811
|
-
/* @__PURE__ */
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
5233
|
+
/* @__PURE__ */ jsxs10("tbody", { children: [
|
|
5234
|
+
visibleRows.map((row) => {
|
|
5235
|
+
const rowLabel = recordGridRowLabel(columns, row);
|
|
5236
|
+
const pending = row.id in pendingRows;
|
|
5237
|
+
const rowError = rowErrors[row.id];
|
|
5238
|
+
const rowDiff = reviewing ? diffByRow.get(row.id) : void 0;
|
|
5239
|
+
const removedRow = rowDiff?.kind === "removed";
|
|
5240
|
+
return /* @__PURE__ */ jsxs10(Fragment6, { children: [
|
|
5241
|
+
/* @__PURE__ */ jsxs10(
|
|
5242
|
+
"tr",
|
|
5243
|
+
{
|
|
5244
|
+
role: "row",
|
|
5245
|
+
"aria-busy": pending,
|
|
5246
|
+
"data-record-grid-diff": rowDiff?.kind,
|
|
5247
|
+
className: `border-b border-border ${pending ? "opacity-60" : ""} ${removedRow ? "bg-destructive/[0.06]" : ""}`,
|
|
5248
|
+
children: [
|
|
5249
|
+
columns.map((column) => {
|
|
5250
|
+
const key = cellKey(row.id, column.id);
|
|
5251
|
+
const applicable = isRecordGridCellApplicable(column, row.values);
|
|
5252
|
+
const editable = !reviewing && onUpdate !== void 0 && column.editable !== false && row.readOnly !== true && applicable;
|
|
5253
|
+
const value = row.values[column.id] ?? null;
|
|
5254
|
+
const isEditing = editing?.rowId === row.id && editing.columnId === column.id;
|
|
5255
|
+
const cellError = cellErrors[key];
|
|
5256
|
+
const active = activeFocus === null ? row.id === visibleRows[0]?.id && column.id === columns[0]?.id : activeFocus.rowId === row.id && activeFocus.columnId === column.id;
|
|
5257
|
+
const source = row.sources?.[column.id];
|
|
5258
|
+
const errorId = `${fieldPrefix}-cell-error-${row.id}-${column.id}`;
|
|
5259
|
+
const cellDiff = rowDiff?.kind === "changed" ? diffCellByKey.get(key) : void 0;
|
|
5260
|
+
if (isEditing && editable) {
|
|
5261
|
+
return /* @__PURE__ */ jsxs10("td", { role: "gridcell", className: `px-3 py-1.5 ${alignmentClass(column)}`, children: [
|
|
5262
|
+
/* @__PURE__ */ jsx12(
|
|
5263
|
+
CellEditor,
|
|
5264
|
+
{
|
|
5265
|
+
column,
|
|
5266
|
+
rowLabel,
|
|
5267
|
+
text: editing.text,
|
|
5268
|
+
invalid: cellError !== void 0,
|
|
5269
|
+
describedBy: cellError === void 0 ? void 0 : errorId,
|
|
5270
|
+
onText: (text) => setEditing({ rowId: row.id, columnId: column.id, text }),
|
|
5271
|
+
onCommit: (text) => void commitEdit(row, column, text),
|
|
5272
|
+
onCancel: () => cancelEdit(row, column)
|
|
5273
|
+
}
|
|
5274
|
+
),
|
|
5275
|
+
cellError !== void 0 && /* @__PURE__ */ jsx12("p", { id: errorId, role: "alert", className: "mt-1 text-xs leading-snug text-destructive", children: cellError })
|
|
5276
|
+
] }, column.id);
|
|
5277
|
+
}
|
|
5278
|
+
if (column.kind === "boolean" && editable) {
|
|
5279
|
+
return /* @__PURE__ */ jsx12("td", { role: "gridcell", className: `px-3 py-2 ${alignmentClass(column)}`, children: /* @__PURE__ */ jsx12(
|
|
5280
|
+
"input",
|
|
5281
|
+
{
|
|
5282
|
+
type: "checkbox",
|
|
5283
|
+
checked: value === true,
|
|
5284
|
+
"aria-label": `${column.header}, ${rowLabel}`,
|
|
5285
|
+
"data-record-grid-row": row.id,
|
|
5286
|
+
"data-record-grid-column": column.id,
|
|
5287
|
+
tabIndex: active ? 0 : -1,
|
|
5288
|
+
ref: (node) => {
|
|
5289
|
+
cellRefs.current.set(key, node);
|
|
5290
|
+
},
|
|
5291
|
+
onFocus: () => setFocus({ rowId: row.id, columnId: column.id }),
|
|
5292
|
+
onChange: (event) => void applyCellWrite(row, column, event.target.checked),
|
|
5293
|
+
className: "h-4 w-4 rounded border-border accent-primary"
|
|
5294
|
+
}
|
|
5295
|
+
) }, column.id);
|
|
5296
|
+
}
|
|
5297
|
+
const display = applicable ? formatRecordGridValue(column, value, locale) : "";
|
|
5298
|
+
return /* @__PURE__ */ jsx12(
|
|
5299
|
+
"td",
|
|
5300
|
+
{
|
|
5301
|
+
role: "gridcell",
|
|
5302
|
+
"aria-readonly": editable ? void 0 : true,
|
|
5303
|
+
"data-record-grid-row": row.id,
|
|
5304
|
+
"data-record-grid-column": column.id,
|
|
5305
|
+
tabIndex: active ? 0 : -1,
|
|
5306
|
+
ref: (node) => {
|
|
5307
|
+
cellRefs.current.set(key, node);
|
|
5308
|
+
},
|
|
5309
|
+
onFocus: () => setFocus({ rowId: row.id, columnId: column.id }),
|
|
5310
|
+
onClick: () => {
|
|
5311
|
+
if (editable) beginEdit(row, column);
|
|
5312
|
+
},
|
|
5313
|
+
className: `px-3 py-2 outline-none focus:ring-2 focus:ring-inset focus:ring-primary/50 ${alignmentClass(
|
|
5314
|
+
column
|
|
5315
|
+
)} ${editable ? "cursor-text" : ""}`,
|
|
5316
|
+
children: /* @__PURE__ */ jsxs10("span", { className: "inline-flex max-w-full items-center gap-1.5", children: [
|
|
5317
|
+
column.id === columns[0]?.id && removedRow && /* @__PURE__ */ jsx12("span", { className: "inline-flex shrink-0 rounded border border-destructive/60 px-1 py-px text-[11px] font-semibold uppercase tracking-[0.05em] text-destructive", children: "Remove" }),
|
|
5318
|
+
cellDiff ? /* @__PURE__ */ jsxs10("span", { className: "inline-flex max-w-full flex-wrap items-baseline gap-x-1.5", children: [
|
|
5319
|
+
/* @__PURE__ */ jsx12("span", { className: "tabular-nums text-destructive line-through decoration-destructive/60", children: formatRecordGridValue(column, cellDiff.before, locale) || "\u2014" }),
|
|
5320
|
+
/* @__PURE__ */ jsx12("span", { "aria-hidden": "true", className: "text-muted-foreground", children: "\u2192" }),
|
|
5321
|
+
/* @__PURE__ */ jsx12("span", { className: "tabular-nums font-medium text-success", children: formatRecordGridValue(column, cellDiff.after, locale) || "\u2014" })
|
|
5322
|
+
] }) : /* @__PURE__ */ jsx12(
|
|
5323
|
+
"span",
|
|
5324
|
+
{
|
|
5325
|
+
className: removedRow ? "truncate text-destructive line-through decoration-destructive/60" : display === "" ? "text-muted-foreground" : "truncate text-foreground",
|
|
5326
|
+
children: display === "" ? applicable ? "\u2014" : "n/a" : display
|
|
5327
|
+
}
|
|
5328
|
+
),
|
|
5329
|
+
source && /* @__PURE__ */ jsx12(
|
|
5330
|
+
SourceMarker,
|
|
5331
|
+
{
|
|
5332
|
+
panelId: `${fieldPrefix}-source-${row.id}-${column.id}`,
|
|
5333
|
+
columnHeader: column.header,
|
|
5334
|
+
rowLabel,
|
|
5335
|
+
source,
|
|
5336
|
+
open: openSource === key,
|
|
5337
|
+
onToggle: () => setOpenSource((current) => current === key ? null : key)
|
|
5338
|
+
}
|
|
5339
|
+
)
|
|
5340
|
+
] })
|
|
5341
|
+
},
|
|
5342
|
+
column.id
|
|
5343
|
+
);
|
|
5344
|
+
}),
|
|
5345
|
+
showActionsColumn && /* @__PURE__ */ jsx12("td", { role: "gridcell", className: "px-3 py-2 text-right", children: reviewing ? rowDiff && /* @__PURE__ */ jsx12(
|
|
5346
|
+
ReviewActions,
|
|
4831
5347
|
{
|
|
4832
|
-
|
|
5348
|
+
rowId: row.id,
|
|
5349
|
+
kind: rowDiff.kind,
|
|
4833
5350
|
rowLabel,
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
describedBy: cellError === void 0 ? void 0 : errorId,
|
|
4837
|
-
onText: (text) => setEditing({ rowId: row.id, columnId: column.id, text }),
|
|
4838
|
-
onCommit: (text) => void commitEdit(row, column, text),
|
|
4839
|
-
onCancel: () => cancelEdit(row, column)
|
|
5351
|
+
onAccept: onAcceptRow,
|
|
5352
|
+
onReject: onRejectRow
|
|
4840
5353
|
}
|
|
4841
|
-
),
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
5354
|
+
) : row.readOnly === true ? null : confirmDelete === row.id ? /* @__PURE__ */ jsxs10("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
5355
|
+
/* @__PURE__ */ jsx12(
|
|
5356
|
+
"button",
|
|
5357
|
+
{
|
|
5358
|
+
type: "button",
|
|
5359
|
+
"aria-label": `Confirm delete ${rowLabel}`,
|
|
5360
|
+
onClick: () => void performDelete(row),
|
|
5361
|
+
className: "rounded-md bg-destructive/10 px-2 py-1 text-xs font-medium text-destructive transition hover:bg-destructive/20",
|
|
5362
|
+
children: "Delete"
|
|
5363
|
+
}
|
|
5364
|
+
),
|
|
5365
|
+
/* @__PURE__ */ jsx12(
|
|
5366
|
+
"button",
|
|
5367
|
+
{
|
|
5368
|
+
type: "button",
|
|
5369
|
+
"aria-label": `Keep ${rowLabel}`,
|
|
5370
|
+
onClick: () => setConfirmDelete(null),
|
|
5371
|
+
className: "rounded-md border border-border px-2 py-1 text-xs font-medium text-muted-foreground transition hover:bg-accent",
|
|
5372
|
+
children: "Cancel"
|
|
5373
|
+
}
|
|
5374
|
+
)
|
|
5375
|
+
] }) : /* @__PURE__ */ jsx12(
|
|
5376
|
+
"button",
|
|
5377
|
+
{
|
|
5378
|
+
type: "button",
|
|
5379
|
+
"aria-label": `Delete ${rowLabel}`,
|
|
5380
|
+
onClick: () => setConfirmDelete(row.id),
|
|
5381
|
+
className: "rounded-md p-1.5 text-muted-foreground transition hover:bg-destructive/10 hover:text-destructive",
|
|
5382
|
+
children: /* @__PURE__ */ jsxs10(
|
|
5383
|
+
"svg",
|
|
5384
|
+
{
|
|
5385
|
+
viewBox: "0 0 24 24",
|
|
5386
|
+
className: "h-3.5 w-3.5",
|
|
5387
|
+
fill: "none",
|
|
5388
|
+
stroke: "currentColor",
|
|
5389
|
+
strokeWidth: "2",
|
|
5390
|
+
strokeLinecap: "round",
|
|
5391
|
+
strokeLinejoin: "round",
|
|
5392
|
+
"aria-hidden": true,
|
|
5393
|
+
children: [
|
|
5394
|
+
/* @__PURE__ */ jsx12("polyline", { points: "3 6 5 6 21 6" }),
|
|
5395
|
+
/* @__PURE__ */ jsx12("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
|
|
5396
|
+
]
|
|
5397
|
+
}
|
|
5398
|
+
)
|
|
5399
|
+
}
|
|
5400
|
+
) })
|
|
5401
|
+
]
|
|
4863
5402
|
}
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
source && /* @__PURE__ */ jsx12(
|
|
4886
|
-
SourceMarker,
|
|
5403
|
+
),
|
|
5404
|
+
rowError !== void 0 && /* @__PURE__ */ jsx12("tr", { role: "row", className: "border-b border-border", children: /* @__PURE__ */ jsx12("td", { role: "gridcell", colSpan: columnSpan, className: "px-3 pb-2", children: /* @__PURE__ */ jsx12("p", { role: "alert", className: "rounded-md bg-destructive/10 px-2.5 py-1.5 text-xs text-destructive", children: rowError }) }) })
|
|
5405
|
+
] }, row.id);
|
|
5406
|
+
}),
|
|
5407
|
+
reviewing && addedRows.map((row) => {
|
|
5408
|
+
const rowLabel = recordGridRowLabel(columns, row);
|
|
5409
|
+
return /* @__PURE__ */ jsxs10(
|
|
5410
|
+
"tr",
|
|
5411
|
+
{
|
|
5412
|
+
role: "row",
|
|
5413
|
+
"data-record-grid-diff": "added",
|
|
5414
|
+
className: "border-b border-border bg-success/[0.06]",
|
|
5415
|
+
children: [
|
|
5416
|
+
columns.map((column, columnIndex) => {
|
|
5417
|
+
const applicable = isRecordGridCellApplicable(column, row.values);
|
|
5418
|
+
const value = row.values[column.id] ?? null;
|
|
5419
|
+
const display = applicable ? formatRecordGridValue(column, value, locale) : "";
|
|
5420
|
+
return /* @__PURE__ */ jsx12("td", { role: "gridcell", className: `px-3 py-2 ${alignmentClass(column)}`, children: /* @__PURE__ */ jsxs10("span", { className: "inline-flex max-w-full items-center gap-1.5", children: [
|
|
5421
|
+
columnIndex === 0 && /* @__PURE__ */ jsx12("span", { className: "inline-flex shrink-0 rounded border border-success/60 px-1 py-px text-[11px] font-semibold uppercase tracking-[0.05em] text-success", children: "New" }),
|
|
5422
|
+
/* @__PURE__ */ jsx12(
|
|
5423
|
+
"span",
|
|
4887
5424
|
{
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
rowLabel,
|
|
4891
|
-
source,
|
|
4892
|
-
open: openSource === key,
|
|
4893
|
-
onToggle: () => setOpenSource((current) => current === key ? null : key)
|
|
5425
|
+
className: `tabular-nums ${display === "" ? "text-muted-foreground" : "truncate text-foreground"}`,
|
|
5426
|
+
children: display === "" ? applicable ? "\u2014" : "n/a" : display
|
|
4894
5427
|
}
|
|
4895
5428
|
)
|
|
4896
|
-
] })
|
|
4897
|
-
},
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
}),
|
|
4901
|
-
onDelete && /* @__PURE__ */ jsx12("td", { role: "gridcell", className: "px-3 py-2 text-right", children: row.readOnly === true ? null : confirmDelete === row.id ? /* @__PURE__ */ jsxs10("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
4902
|
-
/* @__PURE__ */ jsx12(
|
|
4903
|
-
"button",
|
|
4904
|
-
{
|
|
4905
|
-
type: "button",
|
|
4906
|
-
"aria-label": `Confirm delete ${rowLabel}`,
|
|
4907
|
-
onClick: () => void performDelete(row),
|
|
4908
|
-
className: "rounded-md bg-destructive/10 px-2 py-1 text-xs font-medium text-destructive transition hover:bg-destructive/20",
|
|
4909
|
-
children: "Delete"
|
|
4910
|
-
}
|
|
4911
|
-
),
|
|
4912
|
-
/* @__PURE__ */ jsx12(
|
|
4913
|
-
"button",
|
|
4914
|
-
{
|
|
4915
|
-
type: "button",
|
|
4916
|
-
"aria-label": `Keep ${rowLabel}`,
|
|
4917
|
-
onClick: () => setConfirmDelete(null),
|
|
4918
|
-
className: "rounded-md border border-border px-2 py-1 text-xs font-medium text-muted-foreground transition hover:bg-accent",
|
|
4919
|
-
children: "Cancel"
|
|
4920
|
-
}
|
|
4921
|
-
)
|
|
4922
|
-
] }) : /* @__PURE__ */ jsx12(
|
|
4923
|
-
"button",
|
|
4924
|
-
{
|
|
4925
|
-
type: "button",
|
|
4926
|
-
"aria-label": `Delete ${rowLabel}`,
|
|
4927
|
-
onClick: () => setConfirmDelete(row.id),
|
|
4928
|
-
className: "rounded-md p-1.5 text-muted-foreground transition hover:bg-destructive/10 hover:text-destructive",
|
|
4929
|
-
children: /* @__PURE__ */ jsxs10(
|
|
4930
|
-
"svg",
|
|
5429
|
+
] }) }, column.id);
|
|
5430
|
+
}),
|
|
5431
|
+
/* @__PURE__ */ jsx12("td", { role: "gridcell", className: "px-3 py-2 text-right", children: /* @__PURE__ */ jsx12(
|
|
5432
|
+
ReviewActions,
|
|
4931
5433
|
{
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
strokeLinecap: "round",
|
|
4938
|
-
strokeLinejoin: "round",
|
|
4939
|
-
"aria-hidden": true,
|
|
4940
|
-
children: [
|
|
4941
|
-
/* @__PURE__ */ jsx12("polyline", { points: "3 6 5 6 21 6" }),
|
|
4942
|
-
/* @__PURE__ */ jsx12("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" })
|
|
4943
|
-
]
|
|
5434
|
+
rowId: row.id,
|
|
5435
|
+
kind: "added",
|
|
5436
|
+
rowLabel,
|
|
5437
|
+
onAccept: onAcceptRow,
|
|
5438
|
+
onReject: onRejectRow
|
|
4944
5439
|
}
|
|
4945
|
-
)
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
5440
|
+
) })
|
|
5441
|
+
]
|
|
5442
|
+
},
|
|
5443
|
+
row.id
|
|
5444
|
+
);
|
|
5445
|
+
})
|
|
5446
|
+
] }),
|
|
4952
5447
|
hasFooter && /* @__PURE__ */ jsx12("tfoot", { children: /* @__PURE__ */ jsxs10("tr", { role: "row", className: "border-t-2 border-border", children: [
|
|
4953
5448
|
columns.map((column) => /* @__PURE__ */ jsx12(
|
|
4954
5449
|
"td",
|
|
@@ -4959,12 +5454,12 @@ function RecordGrid({
|
|
|
4959
5454
|
},
|
|
4960
5455
|
column.id
|
|
4961
5456
|
)),
|
|
4962
|
-
|
|
5457
|
+
showActionsColumn && /* @__PURE__ */ jsx12("td", { role: "gridcell" })
|
|
4963
5458
|
] }) })
|
|
4964
5459
|
]
|
|
4965
5460
|
}
|
|
4966
5461
|
) }),
|
|
4967
|
-
onCreate && (addForm ?? /* @__PURE__ */ jsxs10(
|
|
5462
|
+
onCreate && !reviewing && (addForm ?? /* @__PURE__ */ jsxs10(
|
|
4968
5463
|
"button",
|
|
4969
5464
|
{
|
|
4970
5465
|
type: "button",
|
|
@@ -4994,6 +5489,31 @@ function RecordGrid({
|
|
|
4994
5489
|
))
|
|
4995
5490
|
] });
|
|
4996
5491
|
}
|
|
5492
|
+
function ReviewActions({ rowId, kind, rowLabel, onAccept, onReject }) {
|
|
5493
|
+
const noun = kind === "changed" ? `proposed change to ${rowLabel}` : kind === "added" ? `new row ${rowLabel}` : `removal of ${rowLabel}`;
|
|
5494
|
+
return /* @__PURE__ */ jsxs10("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
5495
|
+
onReject && /* @__PURE__ */ jsx12(
|
|
5496
|
+
"button",
|
|
5497
|
+
{
|
|
5498
|
+
type: "button",
|
|
5499
|
+
"aria-label": `Reject ${noun}`,
|
|
5500
|
+
onClick: () => onReject(rowId),
|
|
5501
|
+
className: "rounded-md border border-border px-2 py-1 text-xs font-medium text-muted-foreground transition hover:bg-accent",
|
|
5502
|
+
children: "Reject"
|
|
5503
|
+
}
|
|
5504
|
+
),
|
|
5505
|
+
onAccept && /* @__PURE__ */ jsx12(
|
|
5506
|
+
"button",
|
|
5507
|
+
{
|
|
5508
|
+
type: "button",
|
|
5509
|
+
"aria-label": `Accept ${noun}`,
|
|
5510
|
+
onClick: () => onAccept(rowId),
|
|
5511
|
+
className: "rounded-md bg-success/10 px-2 py-1 text-xs font-medium text-success transition hover:bg-success/20",
|
|
5512
|
+
children: "Accept"
|
|
5513
|
+
}
|
|
5514
|
+
)
|
|
5515
|
+
] });
|
|
5516
|
+
}
|
|
4997
5517
|
function CellEditor({ column, rowLabel, text, invalid, describedBy, onText, onCommit, onCancel }) {
|
|
4998
5518
|
const shared = {
|
|
4999
5519
|
"aria-label": `${column.header}, ${rowLabel}`,
|
|
@@ -5066,7 +5586,7 @@ function CellEditor({ column, rowLabel, text, invalid, describedBy, onText, onCo
|
|
|
5066
5586
|
}
|
|
5067
5587
|
function SourceMarker({ panelId, columnHeader, rowLabel, source, open, onToggle }) {
|
|
5068
5588
|
const basis = source.basis ?? "asserted";
|
|
5069
|
-
const setOpen =
|
|
5589
|
+
const setOpen = useCallback10(
|
|
5070
5590
|
(next) => {
|
|
5071
5591
|
if (!next) onToggle();
|
|
5072
5592
|
},
|
|
@@ -5150,7 +5670,7 @@ function AddRecordForm({
|
|
|
5150
5670
|
onSubmit,
|
|
5151
5671
|
onCancel
|
|
5152
5672
|
}) {
|
|
5153
|
-
const groups =
|
|
5673
|
+
const groups = useMemo7(() => groupColumns(columns), [columns]);
|
|
5154
5674
|
return /* @__PURE__ */ jsxs10(
|
|
5155
5675
|
"form",
|
|
5156
5676
|
{
|
|
@@ -5311,6 +5831,196 @@ function DraftField({ column, id, value, invalid, describedBy, onValue }) {
|
|
|
5311
5831
|
);
|
|
5312
5832
|
}
|
|
5313
5833
|
|
|
5834
|
+
// src/web-react/command-palette.tsx
|
|
5835
|
+
import {
|
|
5836
|
+
useCallback as useCallback11,
|
|
5837
|
+
useEffect as useEffect12,
|
|
5838
|
+
useId as useId5,
|
|
5839
|
+
useMemo as useMemo8,
|
|
5840
|
+
useRef as useRef12,
|
|
5841
|
+
useState as useState16
|
|
5842
|
+
} from "react";
|
|
5843
|
+
import { createPortal } from "react-dom";
|
|
5844
|
+
import { Fragment as Fragment7, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
5845
|
+
function SearchGlyph({ className }) {
|
|
5846
|
+
return /* @__PURE__ */ jsxs11("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
5847
|
+
/* @__PURE__ */ jsx13("circle", { cx: "11", cy: "11", r: "8" }),
|
|
5848
|
+
/* @__PURE__ */ jsx13("path", { d: "m21 21-4.3-4.3" })
|
|
5849
|
+
] });
|
|
5850
|
+
}
|
|
5851
|
+
function CommandPalette({
|
|
5852
|
+
items,
|
|
5853
|
+
onSelect,
|
|
5854
|
+
open: controlledOpen,
|
|
5855
|
+
onOpenChange,
|
|
5856
|
+
hotkey = true,
|
|
5857
|
+
loading = false,
|
|
5858
|
+
initialQuery,
|
|
5859
|
+
placeholder = "Search sessions and commands\u2026",
|
|
5860
|
+
emptyMessage,
|
|
5861
|
+
label = "Command palette"
|
|
5862
|
+
}) {
|
|
5863
|
+
const [internalOpen, setInternalOpen] = useState16(false);
|
|
5864
|
+
const open = controlledOpen ?? internalOpen;
|
|
5865
|
+
const setOpen = useCallback11(
|
|
5866
|
+
(next) => {
|
|
5867
|
+
if (controlledOpen === void 0) setInternalOpen(next);
|
|
5868
|
+
onOpenChange?.(next);
|
|
5869
|
+
},
|
|
5870
|
+
[controlledOpen, onOpenChange]
|
|
5871
|
+
);
|
|
5872
|
+
const [query, setQuery] = useState16(initialQuery ?? "");
|
|
5873
|
+
const [active, setActive] = useState16(0);
|
|
5874
|
+
const inputRef = useRef12(null);
|
|
5875
|
+
const surfaceId = useId5();
|
|
5876
|
+
const listId = `${surfaceId}-list`;
|
|
5877
|
+
const flat = useMemo8(() => filterCommandPaletteItems(items, query), [items, query]);
|
|
5878
|
+
const sections = useMemo8(() => groupCommandPaletteItems(flat), [flat]);
|
|
5879
|
+
const activeIndex = flat.length === 0 ? 0 : Math.min(active, flat.length - 1);
|
|
5880
|
+
const activeId = flat.length > 0 ? `${listId}-${activeIndex}` : void 0;
|
|
5881
|
+
useEffect12(() => {
|
|
5882
|
+
if (!hotkey) return;
|
|
5883
|
+
function onKeyDown(e) {
|
|
5884
|
+
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
|
|
5885
|
+
e.preventDefault();
|
|
5886
|
+
setOpen(!open);
|
|
5887
|
+
}
|
|
5888
|
+
}
|
|
5889
|
+
document.addEventListener("keydown", onKeyDown);
|
|
5890
|
+
return () => document.removeEventListener("keydown", onKeyDown);
|
|
5891
|
+
}, [hotkey, open, setOpen]);
|
|
5892
|
+
const restoreFocusRef = useRef12(null);
|
|
5893
|
+
useEffect12(() => {
|
|
5894
|
+
if (open) {
|
|
5895
|
+
restoreFocusRef.current = document.activeElement;
|
|
5896
|
+
inputRef.current?.focus();
|
|
5897
|
+
return;
|
|
5898
|
+
}
|
|
5899
|
+
setQuery(initialQuery ?? "");
|
|
5900
|
+
setActive(0);
|
|
5901
|
+
const restore = restoreFocusRef.current;
|
|
5902
|
+
restoreFocusRef.current = null;
|
|
5903
|
+
if (restore instanceof HTMLElement) restore.focus();
|
|
5904
|
+
}, [open]);
|
|
5905
|
+
useEffect12(() => {
|
|
5906
|
+
if (!open || !activeId) return;
|
|
5907
|
+
document.getElementById(activeId)?.scrollIntoView?.({ block: "nearest" });
|
|
5908
|
+
}, [open, activeId]);
|
|
5909
|
+
const choose = useCallback11(
|
|
5910
|
+
(item) => {
|
|
5911
|
+
onSelect(item);
|
|
5912
|
+
setOpen(false);
|
|
5913
|
+
},
|
|
5914
|
+
[onSelect, setOpen]
|
|
5915
|
+
);
|
|
5916
|
+
const handleKeyDown = (e) => {
|
|
5917
|
+
if (e.key === "ArrowDown") {
|
|
5918
|
+
e.preventDefault();
|
|
5919
|
+
if (flat.length > 0) setActive((activeIndex + 1) % flat.length);
|
|
5920
|
+
} else if (e.key === "ArrowUp") {
|
|
5921
|
+
e.preventDefault();
|
|
5922
|
+
if (flat.length > 0) setActive((activeIndex - 1 + flat.length) % flat.length);
|
|
5923
|
+
} else if (e.key === "Enter") {
|
|
5924
|
+
e.preventDefault();
|
|
5925
|
+
const item = flat[activeIndex];
|
|
5926
|
+
if (item) choose(item);
|
|
5927
|
+
} else if (e.key === "Escape") {
|
|
5928
|
+
e.preventDefault();
|
|
5929
|
+
setOpen(false);
|
|
5930
|
+
}
|
|
5931
|
+
};
|
|
5932
|
+
if (!open || typeof document === "undefined") return null;
|
|
5933
|
+
let rowIndex = -1;
|
|
5934
|
+
return createPortal(
|
|
5935
|
+
/* @__PURE__ */ jsxs11(Fragment7, { children: [
|
|
5936
|
+
/* @__PURE__ */ jsx13(
|
|
5937
|
+
"div",
|
|
5938
|
+
{
|
|
5939
|
+
"aria-hidden": true,
|
|
5940
|
+
"data-testid": "command-palette-backdrop",
|
|
5941
|
+
onMouseDown: () => setOpen(false),
|
|
5942
|
+
className: "fixed inset-0 z-[999] bg-background/80"
|
|
5943
|
+
}
|
|
5944
|
+
),
|
|
5945
|
+
/* @__PURE__ */ jsx13("div", { className: "pointer-events-none fixed inset-x-0 top-[15%] z-[1000] flex justify-center px-4", children: /* @__PURE__ */ jsxs11(
|
|
5946
|
+
"div",
|
|
5947
|
+
{
|
|
5948
|
+
role: "dialog",
|
|
5949
|
+
"aria-modal": "true",
|
|
5950
|
+
"aria-label": label,
|
|
5951
|
+
...{ [POPOVER_SURFACE_ATTR]: surfaceId },
|
|
5952
|
+
className: `agent-pop-in pointer-events-auto flex max-h-[70vh] w-[560px] max-w-full flex-col overflow-hidden rounded-xl border border-card-edge bg-popover ${OVERLAY_SHADOW}`,
|
|
5953
|
+
children: [
|
|
5954
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex shrink-0 items-center gap-2 border-b border-border px-3 py-2.5", children: [
|
|
5955
|
+
/* @__PURE__ */ jsx13(SearchGlyph, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
|
|
5956
|
+
/* @__PURE__ */ jsx13(
|
|
5957
|
+
"input",
|
|
5958
|
+
{
|
|
5959
|
+
ref: inputRef,
|
|
5960
|
+
type: "text",
|
|
5961
|
+
role: "combobox",
|
|
5962
|
+
"aria-expanded": true,
|
|
5963
|
+
"aria-controls": listId,
|
|
5964
|
+
"aria-activedescendant": activeId,
|
|
5965
|
+
"aria-label": label,
|
|
5966
|
+
value: query,
|
|
5967
|
+
onChange: (e) => {
|
|
5968
|
+
setQuery(e.target.value);
|
|
5969
|
+
setActive(0);
|
|
5970
|
+
},
|
|
5971
|
+
onKeyDown: handleKeyDown,
|
|
5972
|
+
placeholder,
|
|
5973
|
+
className: "flex-1 bg-transparent text-sm text-foreground placeholder:text-muted-foreground"
|
|
5974
|
+
}
|
|
5975
|
+
)
|
|
5976
|
+
] }),
|
|
5977
|
+
/* @__PURE__ */ jsxs11("div", { role: "listbox", id: listId, className: "min-h-0 flex-1 overflow-y-auto p-1 pb-2", children: [
|
|
5978
|
+
loading && /* @__PURE__ */ jsx13("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: "Loading\u2026" }),
|
|
5979
|
+
!loading && flat.length === 0 && /* @__PURE__ */ jsx13("div", { className: "px-3 py-4 text-center text-sm text-muted-foreground", children: emptyMessage ?? (query.trim() ? `No results for \u201C${query.trim()}\u201D` : "Nothing here yet") }),
|
|
5980
|
+
!loading && sections.map((section) => /* @__PURE__ */ jsxs11("div", { children: [
|
|
5981
|
+
/* @__PURE__ */ jsx13("div", { className: "px-3 pb-1 pt-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: section.group }),
|
|
5982
|
+
section.items.map((item) => {
|
|
5983
|
+
rowIndex += 1;
|
|
5984
|
+
const index = rowIndex;
|
|
5985
|
+
return /* @__PURE__ */ jsxs11(
|
|
5986
|
+
"div",
|
|
5987
|
+
{
|
|
5988
|
+
id: `${listId}-${index}`,
|
|
5989
|
+
role: "option",
|
|
5990
|
+
"aria-selected": index === activeIndex,
|
|
5991
|
+
onMouseMove: () => setActive(index),
|
|
5992
|
+
onClick: () => choose(item),
|
|
5993
|
+
className: `flex w-full cursor-pointer items-center gap-2.5 rounded-md px-3 py-2.5 text-left text-sm ${index === activeIndex ? "bg-accent" : ""}`,
|
|
5994
|
+
children: [
|
|
5995
|
+
/* @__PURE__ */ jsx13("span", { className: "truncate text-foreground", children: item.label }),
|
|
5996
|
+
item.description && /* @__PURE__ */ jsx13("span", { className: "truncate text-xs text-muted-foreground", children: item.description }),
|
|
5997
|
+
item.hint && /* @__PURE__ */ jsx13("span", { className: "ml-auto shrink-0 text-xs tabular-nums text-muted-foreground", children: item.hint })
|
|
5998
|
+
]
|
|
5999
|
+
},
|
|
6000
|
+
item.id
|
|
6001
|
+
);
|
|
6002
|
+
})
|
|
6003
|
+
] }, section.group))
|
|
6004
|
+
] }),
|
|
6005
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex shrink-0 items-center justify-between border-t border-border px-3 py-2 text-xs text-muted-foreground", children: [
|
|
6006
|
+
/* @__PURE__ */ jsx13("span", { className: "tabular-nums", children: query.trim() ? `${flat.length} of ${items.length}` : `${items.length} items` }),
|
|
6007
|
+
/* @__PURE__ */ jsxs11("span", { className: "flex items-center gap-1.5", children: [
|
|
6008
|
+
/* @__PURE__ */ jsx13("kbd", { className: "rounded border border-border bg-background px-1 py-0.5", children: "\u2191\u2193" }),
|
|
6009
|
+
/* @__PURE__ */ jsx13("span", { children: "navigate" }),
|
|
6010
|
+
/* @__PURE__ */ jsx13("kbd", { className: "ml-1.5 rounded border border-border bg-background px-1 py-0.5", children: "\u21B5" }),
|
|
6011
|
+
/* @__PURE__ */ jsx13("span", { children: "select" }),
|
|
6012
|
+
/* @__PURE__ */ jsx13("kbd", { className: "ml-1.5 rounded border border-border bg-background px-1 py-0.5", children: "esc" }),
|
|
6013
|
+
/* @__PURE__ */ jsx13("span", { children: "close" })
|
|
6014
|
+
] })
|
|
6015
|
+
] })
|
|
6016
|
+
]
|
|
6017
|
+
}
|
|
6018
|
+
) })
|
|
6019
|
+
] }),
|
|
6020
|
+
document.body
|
|
6021
|
+
);
|
|
6022
|
+
}
|
|
6023
|
+
|
|
5314
6024
|
// src/web-react/class-names.ts
|
|
5315
6025
|
function joinClasses(...parts) {
|
|
5316
6026
|
const kept = [];
|
|
@@ -5323,7 +6033,7 @@ function joinClasses(...parts) {
|
|
|
5323
6033
|
}
|
|
5324
6034
|
|
|
5325
6035
|
// src/web-react/sparkline.tsx
|
|
5326
|
-
import { jsx as
|
|
6036
|
+
import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
5327
6037
|
var DEFAULT_SPARKLINE_WIDTH = 96;
|
|
5328
6038
|
var DEFAULT_SPARKLINE_HEIGHT = 24;
|
|
5329
6039
|
var DEFAULT_INSET = 2.5;
|
|
@@ -5429,21 +6139,21 @@ function Sparkline({
|
|
|
5429
6139
|
const geometry = sparklineGeometry(values, { width, height });
|
|
5430
6140
|
const accessibleName = sparklineLabel(values, { label, format });
|
|
5431
6141
|
if (geometry.points.length === 0) {
|
|
5432
|
-
return /* @__PURE__ */
|
|
6142
|
+
return /* @__PURE__ */ jsxs12(
|
|
5433
6143
|
"span",
|
|
5434
6144
|
{
|
|
5435
6145
|
"data-sparkline": geometry.gaps > 0 ? "unavailable" : "empty",
|
|
5436
6146
|
className: joinClasses("text-[11px] text-muted-foreground", className),
|
|
5437
6147
|
children: [
|
|
5438
|
-
/* @__PURE__ */
|
|
5439
|
-
/* @__PURE__ */
|
|
6148
|
+
/* @__PURE__ */ jsx14("span", { className: "sr-only", children: accessibleName }),
|
|
6149
|
+
/* @__PURE__ */ jsx14("span", { "aria-hidden": "true", children: geometry.gaps > 0 ? unavailableLabel : emptyLabel })
|
|
5440
6150
|
]
|
|
5441
6151
|
}
|
|
5442
6152
|
);
|
|
5443
6153
|
}
|
|
5444
6154
|
const drawsLine = geometry.segments.some((segment) => segment.length > 1);
|
|
5445
6155
|
const end = geometry.points[geometry.points.length - 1];
|
|
5446
|
-
return /* @__PURE__ */
|
|
6156
|
+
return /* @__PURE__ */ jsxs12(
|
|
5447
6157
|
"svg",
|
|
5448
6158
|
{
|
|
5449
6159
|
role: "img",
|
|
@@ -5460,7 +6170,7 @@ function Sparkline({
|
|
|
5460
6170
|
geometry.segments.map((segment, index) => {
|
|
5461
6171
|
const key = `segment-${index}`;
|
|
5462
6172
|
if (segment.length > 1) {
|
|
5463
|
-
return /* @__PURE__ */
|
|
6173
|
+
return /* @__PURE__ */ jsx14(
|
|
5464
6174
|
"polyline",
|
|
5465
6175
|
{
|
|
5466
6176
|
points: sparklinePointsAttribute(segment),
|
|
@@ -5476,9 +6186,9 @@ function Sparkline({
|
|
|
5476
6186
|
}
|
|
5477
6187
|
const only = segment[0];
|
|
5478
6188
|
if (only.x === end.x && only.y === end.y) return null;
|
|
5479
|
-
return /* @__PURE__ */
|
|
6189
|
+
return /* @__PURE__ */ jsx14("circle", { cx: only.x, cy: only.y, r: DOT_RADIUS, fill: "currentColor" }, key);
|
|
5480
6190
|
}),
|
|
5481
|
-
/* @__PURE__ */
|
|
6191
|
+
/* @__PURE__ */ jsx14("circle", { cx: end.x, cy: end.y, r: DOT_RADIUS, fill: "currentColor" })
|
|
5482
6192
|
]
|
|
5483
6193
|
}
|
|
5484
6194
|
);
|
|
@@ -5487,12 +6197,12 @@ function Sparkline({
|
|
|
5487
6197
|
// src/web-react/insight-card.tsx
|
|
5488
6198
|
import {
|
|
5489
6199
|
isValidElement as isValidElement2,
|
|
5490
|
-
useCallback as
|
|
5491
|
-
useEffect as
|
|
5492
|
-
useRef as
|
|
5493
|
-
useState as
|
|
6200
|
+
useCallback as useCallback12,
|
|
6201
|
+
useEffect as useEffect13,
|
|
6202
|
+
useRef as useRef13,
|
|
6203
|
+
useState as useState17
|
|
5494
6204
|
} from "react";
|
|
5495
|
-
import { Fragment as
|
|
6205
|
+
import { Fragment as Fragment8, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
5496
6206
|
function insightDelta(value, previous) {
|
|
5497
6207
|
if (typeof value !== "number" || !Number.isFinite(value)) return null;
|
|
5498
6208
|
if (typeof previous !== "number" || !Number.isFinite(previous)) return null;
|
|
@@ -5525,6 +6235,7 @@ var DIRECTION_GLYPH = { up: "\u2191", down: "\u2193", flat: "\u2192" };
|
|
|
5525
6235
|
var INSIGHT_UNAVAILABLE_GLYPH = "\u2014";
|
|
5526
6236
|
var INSIGHT_UNAVAILABLE_LABEL = "Not available";
|
|
5527
6237
|
function InsightCard({
|
|
6238
|
+
eyebrow,
|
|
5528
6239
|
title,
|
|
5529
6240
|
value,
|
|
5530
6241
|
unit,
|
|
@@ -5544,7 +6255,7 @@ function InsightCard({
|
|
|
5544
6255
|
const tone = delta ? insightDeltaTone(delta.direction, polarity) : "neutral";
|
|
5545
6256
|
const unavailable = typeof value === "number" && !Number.isFinite(value);
|
|
5546
6257
|
const shown = typeof value === "number" ? format(value) : value;
|
|
5547
|
-
return /* @__PURE__ */
|
|
6258
|
+
return /* @__PURE__ */ jsxs13(
|
|
5548
6259
|
"article",
|
|
5549
6260
|
{
|
|
5550
6261
|
"data-insight-card": "",
|
|
@@ -5552,39 +6263,40 @@ function InsightCard({
|
|
|
5552
6263
|
className: joinClasses("agent-arrive flex h-full flex-col rounded-xl border border-card-edge bg-card p-4", className),
|
|
5553
6264
|
style,
|
|
5554
6265
|
children: [
|
|
5555
|
-
/* @__PURE__ */
|
|
5556
|
-
|
|
6266
|
+
eyebrow ? /* @__PURE__ */ jsx15("p", { "data-insight-eyebrow": "", className: "mb-0.5 text-[11px] font-semibold uppercase tracking-[0.05em] text-muted-foreground", children: eyebrow }) : null,
|
|
6267
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex items-baseline justify-between gap-2", children: [
|
|
6268
|
+
/* @__PURE__ */ jsx15("h3", { className: "text-[13px] font-medium text-muted-foreground", children: title }),
|
|
5557
6269
|
live ? (
|
|
5558
6270
|
// No `data-motion` opt-out: the word is the signal and the sweep is
|
|
5559
6271
|
// emphasis, so the reduced-motion floor reaches this like everything
|
|
5560
6272
|
// else and leaves a static, legible label.
|
|
5561
|
-
/* @__PURE__ */
|
|
6273
|
+
/* @__PURE__ */ jsx15("span", { className: "agent-shimmer shrink-0 text-[11px] font-medium", "data-insight-live": "", children: liveLabel })
|
|
5562
6274
|
) : null
|
|
5563
6275
|
] }),
|
|
5564
|
-
/* @__PURE__ */
|
|
5565
|
-
/* @__PURE__ */
|
|
5566
|
-
/* @__PURE__ */
|
|
5567
|
-
] }) : /* @__PURE__ */
|
|
5568
|
-
/* @__PURE__ */
|
|
5569
|
-
unit ? /* @__PURE__ */
|
|
6276
|
+
/* @__PURE__ */ jsx15("p", { className: "mt-1 flex items-baseline gap-1", children: unavailable ? /* @__PURE__ */ jsxs13("span", { "data-insight-value": "unavailable", className: "text-xl font-semibold text-muted-foreground", children: [
|
|
6277
|
+
/* @__PURE__ */ jsx15("span", { "aria-hidden": "true", children: INSIGHT_UNAVAILABLE_GLYPH }),
|
|
6278
|
+
/* @__PURE__ */ jsx15("span", { className: "sr-only", children: INSIGHT_UNAVAILABLE_LABEL })
|
|
6279
|
+
] }) : /* @__PURE__ */ jsxs13(Fragment8, { children: [
|
|
6280
|
+
/* @__PURE__ */ jsx15("span", { className: "text-xl font-semibold tabular-nums text-foreground", children: shown }),
|
|
6281
|
+
unit ? /* @__PURE__ */ jsx15("span", { className: "text-[11px] text-muted-foreground", children: unit }) : null
|
|
5570
6282
|
] }) }),
|
|
5571
|
-
delta ? /* @__PURE__ */
|
|
5572
|
-
/* @__PURE__ */
|
|
6283
|
+
delta ? /* @__PURE__ */ jsxs13("p", { "data-insight-delta": delta.direction, className: `mt-0.5 text-[11px] font-medium ${TONE_CLASS[tone]}`, children: [
|
|
6284
|
+
/* @__PURE__ */ jsxs13("span", { "aria-hidden": "true", children: [
|
|
5573
6285
|
DIRECTION_GLYPH[delta.direction],
|
|
5574
6286
|
" "
|
|
5575
6287
|
] }),
|
|
5576
6288
|
formatInsightDelta(delta, format)
|
|
5577
6289
|
] }) : null,
|
|
5578
|
-
description ? /* @__PURE__ */
|
|
5579
|
-
series ? /* @__PURE__ */
|
|
5580
|
-
action ? /* @__PURE__ */
|
|
6290
|
+
description ? /* @__PURE__ */ jsx15("p", { className: "mt-1 text-[11px] text-muted-foreground", children: description }) : null,
|
|
6291
|
+
series ? /* @__PURE__ */ jsx15("div", { className: "mt-2 text-muted-foreground", children: /* @__PURE__ */ jsx15(Sparkline, { values: series, label: seriesLabel ?? title, format }) }) : null,
|
|
6292
|
+
action ? /* @__PURE__ */ jsx15("div", { className: "mt-3", children: renderInsightAction(action) }) : null
|
|
5581
6293
|
]
|
|
5582
6294
|
}
|
|
5583
6295
|
);
|
|
5584
6296
|
}
|
|
5585
6297
|
function renderInsightAction(action) {
|
|
5586
6298
|
if (isValidElement2(action)) return action;
|
|
5587
|
-
return /* @__PURE__ */
|
|
6299
|
+
return /* @__PURE__ */ jsx15(
|
|
5588
6300
|
"button",
|
|
5589
6301
|
{
|
|
5590
6302
|
type: "button",
|
|
@@ -5653,15 +6365,15 @@ function InsightDeck({
|
|
|
5653
6365
|
className,
|
|
5654
6366
|
onPageChange
|
|
5655
6367
|
}) {
|
|
5656
|
-
const [page, setPage] =
|
|
5657
|
-
const [held, setHeld] =
|
|
6368
|
+
const [page, setPage] = useState17(0);
|
|
6369
|
+
const [held, setHeld] = useState17(null);
|
|
5658
6370
|
const answered = state.status === "error" || state.status === "empty";
|
|
5659
6371
|
const carried = state.status === "ready" ? state.value : answered ? null : held;
|
|
5660
6372
|
if (carried !== held) setHeld(carried);
|
|
5661
6373
|
const shown = carried !== null && state.status !== "ready" ? { status: "ready", value: carried, retry: state.retry } : state;
|
|
5662
6374
|
const refreshing = shown !== state;
|
|
5663
|
-
const reported =
|
|
5664
|
-
const settlePage =
|
|
6375
|
+
const reported = useRef13(0);
|
|
6376
|
+
const settlePage = useCallback12(
|
|
5665
6377
|
(next) => {
|
|
5666
6378
|
if (reported.current === next) return;
|
|
5667
6379
|
reported.current = next;
|
|
@@ -5669,7 +6381,7 @@ function InsightDeck({
|
|
|
5669
6381
|
},
|
|
5670
6382
|
[onPageChange]
|
|
5671
6383
|
);
|
|
5672
|
-
return /* @__PURE__ */
|
|
6384
|
+
return /* @__PURE__ */ jsx15(
|
|
5673
6385
|
AsyncView,
|
|
5674
6386
|
{
|
|
5675
6387
|
state: shown,
|
|
@@ -5677,7 +6389,7 @@ function InsightDeck({
|
|
|
5677
6389
|
loadingLabel,
|
|
5678
6390
|
retryLabel,
|
|
5679
6391
|
className,
|
|
5680
|
-
children: (insights) => /* @__PURE__ */
|
|
6392
|
+
children: (insights) => /* @__PURE__ */ jsx15(
|
|
5681
6393
|
InsightPages,
|
|
5682
6394
|
{
|
|
5683
6395
|
insights,
|
|
@@ -5744,18 +6456,18 @@ function InsightPages({
|
|
|
5744
6456
|
const pageCount = insightPageCount(insights.length, size);
|
|
5745
6457
|
const current = Math.min(Math.max(page, 0), pageCount - 1);
|
|
5746
6458
|
const visible = insightPageSlice(insights, current, size);
|
|
5747
|
-
const sectionRef =
|
|
5748
|
-
const listRef =
|
|
5749
|
-
const recoverFocus =
|
|
5750
|
-
|
|
6459
|
+
const sectionRef = useRef13(null);
|
|
6460
|
+
const listRef = useRef13(null);
|
|
6461
|
+
const recoverFocus = useRef13(false);
|
|
6462
|
+
useEffect13(() => {
|
|
5751
6463
|
onPageSettled(current);
|
|
5752
6464
|
}, [current, onPageSettled]);
|
|
5753
|
-
|
|
6465
|
+
useEffect13(() => {
|
|
5754
6466
|
if (!recoverFocus.current) return;
|
|
5755
6467
|
recoverFocus.current = false;
|
|
5756
6468
|
sectionRef.current?.focus();
|
|
5757
6469
|
}, [current]);
|
|
5758
|
-
const goTo =
|
|
6470
|
+
const goTo = useCallback12(
|
|
5759
6471
|
(next) => {
|
|
5760
6472
|
const clamped = Math.min(Math.max(next, 0), pageCount - 1);
|
|
5761
6473
|
if (clamped === current) return false;
|
|
@@ -5790,7 +6502,7 @@ function InsightPages({
|
|
|
5790
6502
|
}
|
|
5791
6503
|
if (moved) event.preventDefault();
|
|
5792
6504
|
};
|
|
5793
|
-
return /* @__PURE__ */
|
|
6505
|
+
return /* @__PURE__ */ jsxs13(
|
|
5794
6506
|
"section",
|
|
5795
6507
|
{
|
|
5796
6508
|
ref: sectionRef,
|
|
@@ -5802,7 +6514,7 @@ function InsightPages({
|
|
|
5802
6514
|
tabIndex: pageCount > 1 ? 0 : void 0,
|
|
5803
6515
|
"aria-keyshortcuts": pageCount > 1 ? "ArrowLeft ArrowRight PageUp PageDown Home End" : void 0,
|
|
5804
6516
|
children: [
|
|
5805
|
-
/* @__PURE__ */
|
|
6517
|
+
/* @__PURE__ */ jsx15("ul", { ref: listRef, className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-3", children: visible.map(({ id, style, ...card }, index) => (
|
|
5806
6518
|
// The page index is in the key on purpose: a page turn is an arrival,
|
|
5807
6519
|
// and reusing the node would swap the text under a card that never
|
|
5808
6520
|
// moved. Remounting replays `.agent-arrive` with the new stagger.
|
|
@@ -5813,10 +6525,10 @@ function InsightPages({
|
|
|
5813
6525
|
// does not arrive a second time. The key does BOTH jobs — but only
|
|
5814
6526
|
// because the deck now keeps this subtree mounted across a reload
|
|
5815
6527
|
// (see `InsightDeck`); a key is never compared across a teardown.
|
|
5816
|
-
/* @__PURE__ */
|
|
6528
|
+
/* @__PURE__ */ jsx15("li", { children: /* @__PURE__ */ jsx15(InsightCard, { ...card, style: staggerStyle(index, style) }) }, `${current}:${id}`)
|
|
5817
6529
|
)) }),
|
|
5818
|
-
/* @__PURE__ */
|
|
5819
|
-
/* @__PURE__ */
|
|
6530
|
+
/* @__PURE__ */ jsxs13("div", { className: pageCount > 1 ? "flex items-center justify-between gap-2" : void 0, children: [
|
|
6531
|
+
/* @__PURE__ */ jsxs13(
|
|
5820
6532
|
"p",
|
|
5821
6533
|
{
|
|
5822
6534
|
role: "status",
|
|
@@ -5830,8 +6542,8 @@ function InsightPages({
|
|
|
5830
6542
|
]
|
|
5831
6543
|
}
|
|
5832
6544
|
),
|
|
5833
|
-
pageCount > 1 ? /* @__PURE__ */
|
|
5834
|
-
/* @__PURE__ */
|
|
6545
|
+
pageCount > 1 ? /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-1", children: [
|
|
6546
|
+
/* @__PURE__ */ jsx15(PagerButton, { label: "Previous insights", glyph: "\u2039", atEnd: current === 0, onClick: () => goTo(current - 1) }),
|
|
5835
6547
|
pageCount <= MAX_PAGE_DOTS ? Array.from({ length: pageCount }, (_, index) => (
|
|
5836
6548
|
// WCAG 2.2 SC 2.5.8 wants a 24x24 CSS px target. The dot stays
|
|
5837
6549
|
// 8px because a 24px dot is a different control; the BUTTON
|
|
@@ -5839,7 +6551,7 @@ function InsightPages({
|
|
|
5839
6551
|
// and the span is the graphic. The Spacing exception cannot
|
|
5840
6552
|
// rescue the bare dot — at a 12px pitch the 24px circle around
|
|
5841
6553
|
// each centre overlaps its neighbour's.
|
|
5842
|
-
/* @__PURE__ */
|
|
6554
|
+
/* @__PURE__ */ jsx15(
|
|
5843
6555
|
"button",
|
|
5844
6556
|
{
|
|
5845
6557
|
type: "button",
|
|
@@ -5847,7 +6559,7 @@ function InsightPages({
|
|
|
5847
6559
|
"aria-current": index === current ? "page" : void 0,
|
|
5848
6560
|
onClick: () => goTo(index),
|
|
5849
6561
|
className: "group flex h-6 w-6 shrink-0 items-center justify-center rounded-full",
|
|
5850
|
-
children: /* @__PURE__ */
|
|
6562
|
+
children: /* @__PURE__ */ jsx15(
|
|
5851
6563
|
"span",
|
|
5852
6564
|
{
|
|
5853
6565
|
"aria-hidden": "true",
|
|
@@ -5861,7 +6573,7 @@ function InsightPages({
|
|
|
5861
6573
|
index
|
|
5862
6574
|
)
|
|
5863
6575
|
)) : null,
|
|
5864
|
-
/* @__PURE__ */
|
|
6576
|
+
/* @__PURE__ */ jsx15(
|
|
5865
6577
|
PagerButton,
|
|
5866
6578
|
{
|
|
5867
6579
|
label: "Next insights",
|
|
@@ -5882,7 +6594,7 @@ function PagerButton({
|
|
|
5882
6594
|
atEnd,
|
|
5883
6595
|
onClick
|
|
5884
6596
|
}) {
|
|
5885
|
-
return /* @__PURE__ */
|
|
6597
|
+
return /* @__PURE__ */ jsx15(
|
|
5886
6598
|
"button",
|
|
5887
6599
|
{
|
|
5888
6600
|
type: "button",
|
|
@@ -5892,13 +6604,13 @@ function PagerButton({
|
|
|
5892
6604
|
if (!atEnd) onClick();
|
|
5893
6605
|
},
|
|
5894
6606
|
className: `flex h-6 w-6 items-center justify-center rounded-md border border-border text-xs text-muted-foreground transition ${atEnd ? "opacity-40" : "hover:bg-accent hover:text-foreground"}`,
|
|
5895
|
-
children: /* @__PURE__ */
|
|
6607
|
+
children: /* @__PURE__ */ jsx15("span", { "aria-hidden": "true", children: glyph })
|
|
5896
6608
|
}
|
|
5897
6609
|
);
|
|
5898
6610
|
}
|
|
5899
6611
|
|
|
5900
6612
|
// src/web-react/index.tsx
|
|
5901
|
-
import { Fragment as
|
|
6613
|
+
import { Fragment as Fragment9, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
5902
6614
|
function formatModelCost(msg, models) {
|
|
5903
6615
|
if (msg.promptTokens == null && msg.completionTokens == null) return null;
|
|
5904
6616
|
const pricing = models.find((m) => m.id === msg.modelUsed)?.pricing;
|
|
@@ -5917,41 +6629,41 @@ function formatTokensPerSecond(msg) {
|
|
|
5917
6629
|
return `${Math.round(msg.completionTokens / (msg.durationMs / 1e3))} tok/s`;
|
|
5918
6630
|
}
|
|
5919
6631
|
function RunDrillIn({ run, onClose }) {
|
|
5920
|
-
return /* @__PURE__ */
|
|
5921
|
-
/* @__PURE__ */
|
|
5922
|
-
/* @__PURE__ */
|
|
6632
|
+
return /* @__PURE__ */ jsxs14("div", { className: `fixed inset-y-0 right-0 z-50 flex w-[480px] max-w-full flex-col border-l border-card-edge bg-popover ${OVERLAY_SHADOW}`, children: [
|
|
6633
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2 border-b border-border px-4 py-3", children: [
|
|
6634
|
+
/* @__PURE__ */ jsx16(
|
|
5923
6635
|
"span",
|
|
5924
6636
|
{
|
|
5925
6637
|
className: `h-2 w-2 shrink-0 rounded-full ${run.status === "running" ? "bg-warning" : run.status === "error" ? "bg-destructive" : "bg-success"}`
|
|
5926
6638
|
}
|
|
5927
6639
|
),
|
|
5928
|
-
/* @__PURE__ */
|
|
5929
|
-
/* @__PURE__ */
|
|
5930
|
-
/* @__PURE__ */
|
|
6640
|
+
/* @__PURE__ */ jsxs14("div", { className: "min-w-0 flex-1", children: [
|
|
6641
|
+
/* @__PURE__ */ jsx16("p", { className: "truncate text-[15px] font-semibold", children: run.title }),
|
|
6642
|
+
/* @__PURE__ */ jsx16("p", { className: "truncate font-mono text-xs text-muted-foreground", children: run.toolName })
|
|
5931
6643
|
] }),
|
|
5932
|
-
/* @__PURE__ */
|
|
6644
|
+
/* @__PURE__ */ jsx16(
|
|
5933
6645
|
"button",
|
|
5934
6646
|
{
|
|
5935
6647
|
type: "button",
|
|
5936
6648
|
onClick: onClose,
|
|
5937
6649
|
"aria-label": "Close",
|
|
5938
6650
|
className: "rounded-md p-1.5 text-muted-foreground transition hover:bg-accent hover:text-foreground",
|
|
5939
|
-
children: /* @__PURE__ */
|
|
6651
|
+
children: /* @__PURE__ */ jsx16("svg", { className: "h-4 w-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx16("path", { d: "M18 6 6 18M6 6l12 12" }) })
|
|
5940
6652
|
}
|
|
5941
6653
|
)
|
|
5942
6654
|
] }),
|
|
5943
|
-
/* @__PURE__ */
|
|
5944
|
-
run.steps.length === 0 && /* @__PURE__ */
|
|
5945
|
-
run.steps.map((step, i) => /* @__PURE__ */
|
|
5946
|
-
/* @__PURE__ */
|
|
5947
|
-
/* @__PURE__ */
|
|
5948
|
-
/* @__PURE__ */
|
|
5949
|
-
/* @__PURE__ */
|
|
6655
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex-1 space-y-3 overflow-y-auto p-4", children: [
|
|
6656
|
+
run.steps.length === 0 && /* @__PURE__ */ jsx16("p", { className: "text-sm text-muted-foreground", children: "No steps recorded yet." }),
|
|
6657
|
+
run.steps.map((step, i) => /* @__PURE__ */ jsxs14("div", { className: "rounded-lg border border-card-edge bg-card", children: [
|
|
6658
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex items-baseline gap-2 border-b border-border px-3 py-1.5", children: [
|
|
6659
|
+
/* @__PURE__ */ jsx16("span", { className: `font-mono text-xs ${step.status === "error" ? "text-destructive" : "text-muted-foreground"}`, children: step.status === "error" ? "\u2717" : "$" }),
|
|
6660
|
+
/* @__PURE__ */ jsx16("code", { className: "min-w-0 flex-1 truncate font-mono text-xs", children: step.label }),
|
|
6661
|
+
/* @__PURE__ */ jsx16("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", children: new Date(step.at).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) })
|
|
5950
6662
|
] }),
|
|
5951
|
-
step.detail && /* @__PURE__ */
|
|
6663
|
+
step.detail && /* @__PURE__ */ jsx16("pre", { className: "max-h-48 overflow-auto whitespace-pre-wrap px-3 py-2 font-mono text-xs leading-relaxed text-muted-foreground", children: step.detail })
|
|
5952
6664
|
] }, i))
|
|
5953
6665
|
] }),
|
|
5954
|
-
/* @__PURE__ */
|
|
6666
|
+
/* @__PURE__ */ jsx16("p", { className: "border-t border-border px-4 py-2 text-xs text-muted-foreground", children: "Read-only transcript \u2014 reply in the main chat." })
|
|
5955
6667
|
] });
|
|
5956
6668
|
}
|
|
5957
6669
|
function pendingApprovalOf(call) {
|
|
@@ -5967,23 +6679,23 @@ function ChatEmptyState({
|
|
|
5967
6679
|
}) {
|
|
5968
6680
|
const doorCount = Math.min(doors?.length ?? 0, 3);
|
|
5969
6681
|
const doorsGridClass = doorCount === 1 ? "mx-auto max-w-sm sm:grid-cols-1" : doorCount === 2 ? "sm:grid-cols-2" : "sm:grid-cols-3";
|
|
5970
|
-
return /* @__PURE__ */
|
|
5971
|
-
/* @__PURE__ */
|
|
5972
|
-
/* @__PURE__ */
|
|
5973
|
-
/* @__PURE__ */
|
|
5974
|
-
subline && /* @__PURE__ */
|
|
5975
|
-
doors && doors.length > 0 && /* @__PURE__ */
|
|
6682
|
+
return /* @__PURE__ */ jsxs14("div", { className: "mx-auto flex w-full max-w-2xl flex-col items-center px-6 py-12 text-center sm:py-20", children: [
|
|
6683
|
+
/* @__PURE__ */ jsx16("span", { className: "mb-5 inline-flex h-14 w-14 items-center justify-center rounded-2xl bg-primary/10 ring-1 ring-primary/15", children: /* @__PURE__ */ jsx16(BrandMark, { size: 32, className: "shrink-0" }) }),
|
|
6684
|
+
/* @__PURE__ */ jsx16("p", { className: "text-xs font-semibold uppercase tracking-[0.05em] text-muted-foreground", children: productName }),
|
|
6685
|
+
/* @__PURE__ */ jsx16("h2", { className: "mt-1.5 text-balance text-2xl font-semibold leading-tight text-foreground", children: headline }),
|
|
6686
|
+
subline && /* @__PURE__ */ jsx16("p", { className: "mt-3 max-w-md text-[15px] leading-relaxed text-muted-foreground", children: subline }),
|
|
6687
|
+
doors && doors.length > 0 && /* @__PURE__ */ jsx16("div", { className: `mt-7 grid w-full gap-2.5 ${doorsGridClass}`, children: doors.slice(0, 3).map((door, i) => /* @__PURE__ */ jsxs14(
|
|
5976
6688
|
"button",
|
|
5977
6689
|
{
|
|
5978
6690
|
type: "button",
|
|
5979
6691
|
onClick: door.onSelect,
|
|
5980
6692
|
className: "group flex min-h-[44px] flex-col items-start rounded-xl border border-border bg-card px-4 py-3 text-left transition hover:border-primary/40 hover:bg-accent",
|
|
5981
6693
|
children: [
|
|
5982
|
-
/* @__PURE__ */
|
|
6694
|
+
/* @__PURE__ */ jsxs14("span", { className: "flex items-center gap-2 text-sm font-semibold text-foreground", children: [
|
|
5983
6695
|
door.icon,
|
|
5984
6696
|
door.label
|
|
5985
6697
|
] }),
|
|
5986
|
-
door.description && /* @__PURE__ */
|
|
6698
|
+
door.description && /* @__PURE__ */ jsx16("span", { className: "mt-0.5 text-[12px] leading-snug text-muted-foreground", children: door.description })
|
|
5987
6699
|
]
|
|
5988
6700
|
},
|
|
5989
6701
|
i
|
|
@@ -5992,26 +6704,26 @@ function ChatEmptyState({
|
|
|
5992
6704
|
}
|
|
5993
6705
|
function ToolGlyph({ name, className }) {
|
|
5994
6706
|
if (name.startsWith("sandbox_")) {
|
|
5995
|
-
return /* @__PURE__ */
|
|
5996
|
-
/* @__PURE__ */
|
|
5997
|
-
/* @__PURE__ */
|
|
6707
|
+
return /* @__PURE__ */ jsxs14("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
6708
|
+
/* @__PURE__ */ jsx16("polyline", { points: "4 17 10 11 4 5" }),
|
|
6709
|
+
/* @__PURE__ */ jsx16("line", { x1: "12", y1: "19", x2: "20", y2: "19" })
|
|
5998
6710
|
] });
|
|
5999
6711
|
}
|
|
6000
6712
|
if (name === "submit_proposal") {
|
|
6001
|
-
return /* @__PURE__ */
|
|
6002
|
-
/* @__PURE__ */
|
|
6003
|
-
/* @__PURE__ */
|
|
6713
|
+
return /* @__PURE__ */ jsxs14("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
6714
|
+
/* @__PURE__ */ jsx16("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
|
|
6715
|
+
/* @__PURE__ */ jsx16("path", { d: "M14 2v6h6M9 15l2 2 4-4" })
|
|
6004
6716
|
] });
|
|
6005
6717
|
}
|
|
6006
6718
|
if (name === "schedule_followup") {
|
|
6007
|
-
return /* @__PURE__ */
|
|
6008
|
-
/* @__PURE__ */
|
|
6009
|
-
/* @__PURE__ */
|
|
6719
|
+
return /* @__PURE__ */ jsxs14("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": true, children: [
|
|
6720
|
+
/* @__PURE__ */ jsx16("circle", { cx: "12", cy: "12", r: "9" }),
|
|
6721
|
+
/* @__PURE__ */ jsx16("path", { d: "M12 7v5l3 3" })
|
|
6010
6722
|
] });
|
|
6011
6723
|
}
|
|
6012
|
-
return /* @__PURE__ */
|
|
6013
|
-
/* @__PURE__ */
|
|
6014
|
-
/* @__PURE__ */
|
|
6724
|
+
return /* @__PURE__ */ jsxs14("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
6725
|
+
/* @__PURE__ */ jsx16("path", { d: "M12 3v3m0 12v3M3 12h3m12 0h3" }),
|
|
6726
|
+
/* @__PURE__ */ jsx16("circle", { cx: "12", cy: "12", r: "4" })
|
|
6015
6727
|
] });
|
|
6016
6728
|
}
|
|
6017
6729
|
function toolOutcomeOf(call) {
|
|
@@ -6097,40 +6809,40 @@ function truncate(v, max = 240) {
|
|
|
6097
6809
|
function KvRows({ data }) {
|
|
6098
6810
|
const entries = Object.entries(data).filter(([, v]) => v !== void 0 && v !== null && v !== "");
|
|
6099
6811
|
if (!entries.length) return null;
|
|
6100
|
-
return /* @__PURE__ */
|
|
6101
|
-
/* @__PURE__ */
|
|
6102
|
-
/* @__PURE__ */
|
|
6812
|
+
return /* @__PURE__ */ jsx16("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1", children: entries.map(([k, v]) => /* @__PURE__ */ jsxs14("div", { className: "contents", children: [
|
|
6813
|
+
/* @__PURE__ */ jsx16("dt", { className: "font-mono text-xs text-muted-foreground", children: k }),
|
|
6814
|
+
/* @__PURE__ */ jsx16("dd", { className: "min-w-0 whitespace-pre-wrap break-words font-mono text-xs text-muted-foreground", children: truncate(v) })
|
|
6103
6815
|
] }, k)) });
|
|
6104
6816
|
}
|
|
6105
6817
|
function ShellDetail({ call }) {
|
|
6106
6818
|
const outcome = toolOutcomeOf(call);
|
|
6107
6819
|
const r = outcome?.result ?? {};
|
|
6108
|
-
return /* @__PURE__ */
|
|
6109
|
-
/* @__PURE__ */
|
|
6110
|
-
/* @__PURE__ */
|
|
6111
|
-
/* @__PURE__ */
|
|
6112
|
-
r.exitCode != null && /* @__PURE__ */
|
|
6820
|
+
return /* @__PURE__ */ jsxs14("div", { className: "overflow-hidden rounded-md bg-zinc-900 font-mono text-xs leading-relaxed", children: [
|
|
6821
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2 px-3 pt-2 text-zinc-400", children: [
|
|
6822
|
+
/* @__PURE__ */ jsx16("span", { className: "select-none text-zinc-500", children: "$" }),
|
|
6823
|
+
/* @__PURE__ */ jsx16("span", { className: "min-w-0 flex-1 truncate text-zinc-200", children: String(call.args?.command ?? "") }),
|
|
6824
|
+
r.exitCode != null && /* @__PURE__ */ jsxs14("span", { className: r.exitCode === 0 ? "text-success" : "text-destructive", children: [
|
|
6113
6825
|
"exit ",
|
|
6114
6826
|
r.exitCode
|
|
6115
6827
|
] })
|
|
6116
6828
|
] }),
|
|
6117
|
-
/* @__PURE__ */
|
|
6829
|
+
/* @__PURE__ */ jsx16("pre", { className: "max-h-56 overflow-auto whitespace-pre-wrap px-3 pb-2.5 pt-1.5 text-zinc-300", children: outcome?.ok === false ? outcome.message ?? "failed" : [r.stdout, r.stderr].filter(Boolean).join("\n") || "(no output)" })
|
|
6118
6830
|
] });
|
|
6119
6831
|
}
|
|
6120
6832
|
function DefaultToolDetail({ call }) {
|
|
6121
6833
|
const result = call.result;
|
|
6122
6834
|
const envelope = typeof result === "object" && result !== null ? result : null;
|
|
6123
|
-
return /* @__PURE__ */
|
|
6124
|
-
call.args && Object.keys(call.args).length > 0 && /* @__PURE__ */
|
|
6125
|
-
/* @__PURE__ */
|
|
6126
|
-
/* @__PURE__ */
|
|
6835
|
+
return /* @__PURE__ */ jsxs14("div", { className: "space-y-2", children: [
|
|
6836
|
+
call.args && Object.keys(call.args).length > 0 && /* @__PURE__ */ jsxs14("div", { children: [
|
|
6837
|
+
/* @__PURE__ */ jsx16("p", { className: "mb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Called with" }),
|
|
6838
|
+
/* @__PURE__ */ jsx16(KvRows, { data: call.args })
|
|
6127
6839
|
] }),
|
|
6128
|
-
envelope ? /* @__PURE__ */
|
|
6129
|
-
/* @__PURE__ */
|
|
6130
|
-
envelope.ok === false ? /* @__PURE__ */
|
|
6131
|
-
] }) : result != null ? /* @__PURE__ */
|
|
6132
|
-
/* @__PURE__ */
|
|
6133
|
-
/* @__PURE__ */
|
|
6840
|
+
envelope ? /* @__PURE__ */ jsxs14("div", { children: [
|
|
6841
|
+
/* @__PURE__ */ jsx16("p", { className: "mb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: envelope.ok === false ? "Failed" : "Result" }),
|
|
6842
|
+
envelope.ok === false ? /* @__PURE__ */ jsx16("p", { className: "text-xs text-destructive", children: envelope.message ?? "Tool failed" }) : envelope.result && typeof envelope.result === "object" ? /* @__PURE__ */ jsx16(KvRows, { data: envelope.result }) : envelope.result != null ? /* @__PURE__ */ jsx16("p", { className: "font-mono text-xs text-muted-foreground", children: truncate(envelope.result) }) : null
|
|
6843
|
+
] }) : result != null ? /* @__PURE__ */ jsxs14("div", { children: [
|
|
6844
|
+
/* @__PURE__ */ jsx16("p", { className: "mb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Result" }),
|
|
6845
|
+
/* @__PURE__ */ jsx16("p", { className: "font-mono text-xs text-muted-foreground", children: truncate(result) })
|
|
6134
6846
|
] }) : null
|
|
6135
6847
|
] });
|
|
6136
6848
|
}
|
|
@@ -6141,24 +6853,24 @@ function ProposalCard({
|
|
|
6141
6853
|
approval,
|
|
6142
6854
|
renderers
|
|
6143
6855
|
}) {
|
|
6144
|
-
const [expanded, setExpanded] =
|
|
6856
|
+
const [expanded, setExpanded] = useState18(false);
|
|
6145
6857
|
const { summary, meta, typeSlug } = proposalPreview(call);
|
|
6146
6858
|
const custom = renderers?.[call.name]?.(call, message);
|
|
6147
6859
|
const { pending: deciding, run: decide } = usePending();
|
|
6148
|
-
return /* @__PURE__ */
|
|
6149
|
-
/* @__PURE__ */
|
|
6150
|
-
/* @__PURE__ */
|
|
6151
|
-
/* @__PURE__ */
|
|
6152
|
-
/* @__PURE__ */
|
|
6153
|
-
/* @__PURE__ */
|
|
6154
|
-
summary && /* @__PURE__ */
|
|
6155
|
-
typeSlug && /* @__PURE__ */
|
|
6156
|
-
meta.length > 0 && /* @__PURE__ */
|
|
6860
|
+
return /* @__PURE__ */ jsxs14("div", { className: "w-full max-w-full rounded-xl border border-warning/50 bg-warning/[0.06] text-sm shadow-sm ring-1 ring-warning/10", children: [
|
|
6861
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex items-start gap-2.5 px-4 pt-3.5", children: [
|
|
6862
|
+
/* @__PURE__ */ jsx16("span", { className: "mt-0.5 inline-flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-warning/15 text-warning", children: /* @__PURE__ */ jsx16(ToolGlyph, { name: call.name, className: "h-3.5 w-3.5" }) }),
|
|
6863
|
+
/* @__PURE__ */ jsxs14("div", { className: "min-w-0 flex-1", children: [
|
|
6864
|
+
/* @__PURE__ */ jsx16("p", { className: "text-xs font-semibold uppercase tracking-[0.05em] text-warning-strong", children: approval ? "Needs your approval" : "Awaiting approval" }),
|
|
6865
|
+
/* @__PURE__ */ jsx16("p", { className: "mt-0.5 text-[15px] font-semibold leading-snug text-foreground", children: friendlyToolTitle(call) }),
|
|
6866
|
+
summary && /* @__PURE__ */ jsx16("p", { className: "mt-1 text-xs leading-relaxed text-muted-foreground", children: summary }),
|
|
6867
|
+
typeSlug && /* @__PURE__ */ jsx16("p", { className: "mt-1 font-mono text-xs text-muted-foreground", children: typeSlug }),
|
|
6868
|
+
meta.length > 0 && /* @__PURE__ */ jsx16("div", { className: "mt-1.5 flex flex-wrap items-center gap-1.5", children: meta.map((m, i) => /* @__PURE__ */ jsx16("span", { className: "rounded-full bg-secondary px-2 py-0.5 text-xs font-medium text-muted-foreground", children: m }, i)) })
|
|
6157
6869
|
] })
|
|
6158
6870
|
] }),
|
|
6159
|
-
/* @__PURE__ */
|
|
6160
|
-
approval && /* @__PURE__ */
|
|
6161
|
-
/* @__PURE__ */
|
|
6871
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex flex-wrap items-center gap-2 px-4 pb-3.5 pt-3", children: [
|
|
6872
|
+
approval && /* @__PURE__ */ jsxs14(Fragment9, { children: [
|
|
6873
|
+
/* @__PURE__ */ jsx16(
|
|
6162
6874
|
"button",
|
|
6163
6875
|
{
|
|
6164
6876
|
type: "button",
|
|
@@ -6168,7 +6880,7 @@ function ProposalCard({
|
|
|
6168
6880
|
children: "Approve & run"
|
|
6169
6881
|
}
|
|
6170
6882
|
),
|
|
6171
|
-
/* @__PURE__ */
|
|
6883
|
+
/* @__PURE__ */ jsx16(
|
|
6172
6884
|
"button",
|
|
6173
6885
|
{
|
|
6174
6886
|
type: "button",
|
|
@@ -6179,7 +6891,7 @@ function ProposalCard({
|
|
|
6179
6891
|
}
|
|
6180
6892
|
)
|
|
6181
6893
|
] }),
|
|
6182
|
-
/* @__PURE__ */
|
|
6894
|
+
/* @__PURE__ */ jsxs14(
|
|
6183
6895
|
"button",
|
|
6184
6896
|
{
|
|
6185
6897
|
type: "button",
|
|
@@ -6188,12 +6900,12 @@ function ProposalCard({
|
|
|
6188
6900
|
className: "ml-auto inline-flex items-center gap-1 rounded text-[12px] font-medium text-muted-foreground transition hover:text-foreground",
|
|
6189
6901
|
children: [
|
|
6190
6902
|
expanded ? "Hide details" : "View details",
|
|
6191
|
-
/* @__PURE__ */
|
|
6903
|
+
/* @__PURE__ */ jsx16(ChevronDown, { className: `h-3 w-3 transition-transform ${expanded ? "rotate-180" : ""}` })
|
|
6192
6904
|
]
|
|
6193
6905
|
}
|
|
6194
6906
|
)
|
|
6195
6907
|
] }),
|
|
6196
|
-
expanded && /* @__PURE__ */
|
|
6908
|
+
expanded && /* @__PURE__ */ jsx16("div", { className: "border-t border-warning/20 px-4 py-3 text-xs", children: custom ?? /* @__PURE__ */ jsx16(DefaultToolDetail, { call }) })
|
|
6197
6909
|
] });
|
|
6198
6910
|
}
|
|
6199
6911
|
function formatFollowupWhen(when) {
|
|
@@ -6208,14 +6920,14 @@ function FollowupCard({ call }) {
|
|
|
6208
6920
|
const when = typeof a.when === "string" ? a.when : typeof a.at === "string" ? a.at : typeof a.schedule === "string" ? a.schedule : null;
|
|
6209
6921
|
const failed = toolCallFailed(call);
|
|
6210
6922
|
const errorText = failed ? toolOutcomeOf(call)?.message ?? "Scheduling failed" : null;
|
|
6211
|
-
return /* @__PURE__ */
|
|
6212
|
-
/* @__PURE__ */
|
|
6213
|
-
/* @__PURE__ */
|
|
6214
|
-
/* @__PURE__ */
|
|
6215
|
-
when && /* @__PURE__ */
|
|
6216
|
-
/* @__PURE__ */
|
|
6923
|
+
return /* @__PURE__ */ jsx16("div", { className: "flex items-start gap-2", children: /* @__PURE__ */ jsxs14("div", { className: "min-w-0 flex-1 overflow-hidden rounded-[var(--radius-lg)] border border-[var(--border-subtle)] bg-[var(--md3-surface-container)]", children: [
|
|
6924
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex w-full items-center gap-2.5 px-3 py-2", children: [
|
|
6925
|
+
/* @__PURE__ */ jsx16("span", { className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-[var(--radius-sm)] border border-border bg-muted text-muted-foreground", children: /* @__PURE__ */ jsx16(ToolGlyph, { name: call.name, className: "h-3.5 w-3.5" }) }),
|
|
6926
|
+
/* @__PURE__ */ jsx16("span", { className: "shrink-0 whitespace-nowrap text-xs font-medium text-foreground", children: friendlyToolTitle(call) }),
|
|
6927
|
+
when && /* @__PURE__ */ jsx16("span", { title: when, className: "hidden min-w-0 flex-1 truncate font-mono text-xs tabular-nums text-muted-foreground sm:inline", children: formatFollowupWhen(when) }),
|
|
6928
|
+
/* @__PURE__ */ jsx16("span", { className: "ml-auto flex shrink-0 items-center gap-1.5", children: call.status === "running" ? /* @__PURE__ */ jsx16("svg", { className: "h-3 w-3 shrink-0 animate-spin text-[var(--accent-text)]", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": true, children: /* @__PURE__ */ jsx16("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", strokeLinecap: "round" }) }) : /* @__PURE__ */ jsx16("span", { className: `h-1.5 w-1.5 shrink-0 rounded-full ${failed ? "bg-[var(--surface-danger-text)]" : "bg-[var(--surface-success-text)]"}` }) })
|
|
6217
6929
|
] }),
|
|
6218
|
-
errorText && /* @__PURE__ */
|
|
6930
|
+
errorText && /* @__PURE__ */ jsx16("div", { className: "border-t border-border px-3 py-2 text-xs text-[var(--surface-danger-text)]", children: errorText })
|
|
6219
6931
|
] }) });
|
|
6220
6932
|
}
|
|
6221
6933
|
function toolRowTitle(call) {
|
|
@@ -6238,10 +6950,10 @@ function ToolCallCard({
|
|
|
6238
6950
|
const arrival = useArrivalStyle(staggerIndex ?? 0);
|
|
6239
6951
|
const pending = call.status === "done" ? pendingApprovalOf(call) : null;
|
|
6240
6952
|
const kind = blockKindOf(call);
|
|
6241
|
-
const arrive = (row) => /* @__PURE__ */
|
|
6953
|
+
const arrive = (row) => /* @__PURE__ */ jsx16("div", { className: "agent-arrive", style: arrival, children: row });
|
|
6242
6954
|
if (pending) {
|
|
6243
6955
|
return arrive(
|
|
6244
|
-
/* @__PURE__ */
|
|
6956
|
+
/* @__PURE__ */ jsx16(
|
|
6245
6957
|
ProposalCard,
|
|
6246
6958
|
{
|
|
6247
6959
|
call,
|
|
@@ -6254,18 +6966,18 @@ function ToolCallCard({
|
|
|
6254
6966
|
);
|
|
6255
6967
|
}
|
|
6256
6968
|
if (kind === "followup") {
|
|
6257
|
-
return arrive(/* @__PURE__ */
|
|
6969
|
+
return arrive(/* @__PURE__ */ jsx16(FollowupCard, { call }));
|
|
6258
6970
|
}
|
|
6259
6971
|
const custom = renderers?.[call.name]?.(call, message);
|
|
6260
6972
|
return arrive(
|
|
6261
|
-
/* @__PURE__ */
|
|
6973
|
+
/* @__PURE__ */ jsx16(
|
|
6262
6974
|
InlineToolItem,
|
|
6263
6975
|
{
|
|
6264
6976
|
part: chatToolCallPart(call),
|
|
6265
6977
|
title: toolRowTitle(call),
|
|
6266
6978
|
description: toolRowDescription(call),
|
|
6267
|
-
renderToolDetail: () => custom ?? (call.name === "sandbox_run_command" ? /* @__PURE__ */
|
|
6268
|
-
actions: onOpenRun && call.name.startsWith("sandbox_") ? /* @__PURE__ */
|
|
6979
|
+
renderToolDetail: () => custom ?? (call.name === "sandbox_run_command" ? /* @__PURE__ */ jsx16(ShellDetail, { call }) : /* @__PURE__ */ jsx16(DefaultToolDetail, { call })),
|
|
6980
|
+
actions: onOpenRun && call.name.startsWith("sandbox_") ? /* @__PURE__ */ jsx16(
|
|
6269
6981
|
"button",
|
|
6270
6982
|
{
|
|
6271
6983
|
type: "button",
|
|
@@ -6273,9 +6985,9 @@ function ToolCallCard({
|
|
|
6273
6985
|
"aria-label": "Open full transcript",
|
|
6274
6986
|
title: "Open full transcript",
|
|
6275
6987
|
className: "rounded-md p-1.5 text-muted-foreground transition hover:bg-accent hover:text-foreground",
|
|
6276
|
-
children: /* @__PURE__ */
|
|
6277
|
-
/* @__PURE__ */
|
|
6278
|
-
/* @__PURE__ */
|
|
6988
|
+
children: /* @__PURE__ */ jsxs14("svg", { className: "h-3.5 w-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
6989
|
+
/* @__PURE__ */ jsx16("path", { d: "M7 17 17 7" }),
|
|
6990
|
+
/* @__PURE__ */ jsx16("path", { d: "M7 7h10v10" })
|
|
6279
6991
|
] })
|
|
6280
6992
|
}
|
|
6281
6993
|
) : void 0
|
|
@@ -6284,7 +6996,7 @@ function ToolCallCard({
|
|
|
6284
6996
|
);
|
|
6285
6997
|
}
|
|
6286
6998
|
function StreamingCaret() {
|
|
6287
|
-
return /* @__PURE__ */
|
|
6999
|
+
return /* @__PURE__ */ jsx16(
|
|
6288
7000
|
"span",
|
|
6289
7001
|
{
|
|
6290
7002
|
className: "ml-0.5 inline-block h-[1.1em] w-[3px] translate-y-[2px] animate-[agent-caret_1s_step-end_infinite] rounded-sm bg-foreground/70",
|
|
@@ -6301,7 +7013,7 @@ function SegmentText({
|
|
|
6301
7013
|
messageClassName
|
|
6302
7014
|
}) {
|
|
6303
7015
|
const text = useSmoothText(content, streaming);
|
|
6304
|
-
const body =
|
|
7016
|
+
const body = useMemo9(() => renderBody(text), [renderBody, text]);
|
|
6305
7017
|
if (!content.trim() && !showCaret) return null;
|
|
6306
7018
|
return (
|
|
6307
7019
|
// A settled run arrives from a short blur; the LIVE run does not, because
|
|
@@ -6309,9 +7021,9 @@ function SegmentText({
|
|
|
6309
7021
|
// the container on top of that makes the paragraph shimmer while it types.
|
|
6310
7022
|
// The distinction is what separates "the answer materialised" from "the
|
|
6311
7023
|
// log was appended to".
|
|
6312
|
-
/* @__PURE__ */
|
|
7024
|
+
/* @__PURE__ */ jsxs14("div", { className: `${messageClassName}${streaming ? "" : " agent-stream-in"}`, children: [
|
|
6313
7025
|
body,
|
|
6314
|
-
showCaret && /* @__PURE__ */
|
|
7026
|
+
showCaret && /* @__PURE__ */ jsx16(StreamingCaret, {})
|
|
6315
7027
|
] })
|
|
6316
7028
|
);
|
|
6317
7029
|
}
|
|
@@ -6336,7 +7048,7 @@ function SegmentedBody({
|
|
|
6336
7048
|
const leftoverToolCalls = (msg.toolCalls ?? []).filter(
|
|
6337
7049
|
(tc) => !segmentToolIds.has(tc.id)
|
|
6338
7050
|
);
|
|
6339
|
-
const renderToolCard = (call, index) => /* @__PURE__ */
|
|
7051
|
+
const renderToolCard = (call, index) => /* @__PURE__ */ jsx16(
|
|
6340
7052
|
ToolCallCard,
|
|
6341
7053
|
{
|
|
6342
7054
|
call,
|
|
@@ -6364,7 +7076,7 @@ function SegmentedBody({
|
|
|
6364
7076
|
for (const g of groups) {
|
|
6365
7077
|
if (g.kind === "text") {
|
|
6366
7078
|
children.push(
|
|
6367
|
-
/* @__PURE__ */
|
|
7079
|
+
/* @__PURE__ */ jsx16(
|
|
6368
7080
|
SegmentText,
|
|
6369
7081
|
{
|
|
6370
7082
|
content: g.content,
|
|
@@ -6380,13 +7092,13 @@ function SegmentedBody({
|
|
|
6380
7092
|
}
|
|
6381
7093
|
if (!streaming && g.calls.length >= COLLAPSE_TOOL_RUN_AT && !g.calls.some(isImportantTool)) {
|
|
6382
7094
|
children.push(
|
|
6383
|
-
/* @__PURE__ */
|
|
6384
|
-
/* @__PURE__ */
|
|
7095
|
+
/* @__PURE__ */ jsxs14("details", { children: [
|
|
7096
|
+
/* @__PURE__ */ jsxs14("summary", { className: "cursor-pointer select-none rounded-md py-0.5 text-xs font-medium text-muted-foreground [transition:color_var(--motion-control)] hover:text-foreground", children: [
|
|
6385
7097
|
"Worked through ",
|
|
6386
7098
|
g.calls.length,
|
|
6387
7099
|
" steps"
|
|
6388
7100
|
] }),
|
|
6389
|
-
/* @__PURE__ */
|
|
7101
|
+
/* @__PURE__ */ jsx16("div", { className: "mt-1.5 flex flex-col gap-1.5", children: g.calls.map(renderToolCard) })
|
|
6390
7102
|
] }, `tools-fold-${g.index}`)
|
|
6391
7103
|
);
|
|
6392
7104
|
continue;
|
|
@@ -6395,9 +7107,9 @@ function SegmentedBody({
|
|
|
6395
7107
|
}
|
|
6396
7108
|
leftoverToolCalls.forEach((call, index) => children.push(renderToolCard(call, index)));
|
|
6397
7109
|
if (streaming && segments[lastIndex]?.kind === "tool") {
|
|
6398
|
-
children.push(/* @__PURE__ */
|
|
7110
|
+
children.push(/* @__PURE__ */ jsx16(StreamingCaret, {}, "streaming-caret"));
|
|
6399
7111
|
}
|
|
6400
|
-
return /* @__PURE__ */
|
|
7112
|
+
return /* @__PURE__ */ jsx16("div", { className: "flex flex-col gap-2", children });
|
|
6401
7113
|
}
|
|
6402
7114
|
var QUIET_META_LANE_CLASS = "mt-1 flex h-[18px] items-center gap-2 text-xs tabular-nums text-muted-foreground opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-within:opacity-100 motion-reduce:transition-none [@media(hover:none)]:opacity-100";
|
|
6403
7115
|
function copyTextOf(msg) {
|
|
@@ -6406,9 +7118,9 @@ function copyTextOf(msg) {
|
|
|
6406
7118
|
return msg.content;
|
|
6407
7119
|
}
|
|
6408
7120
|
function CopyMessageButton({ text }) {
|
|
6409
|
-
const [copied, setCopied] =
|
|
6410
|
-
const timerRef =
|
|
6411
|
-
|
|
7121
|
+
const [copied, setCopied] = useState18(false);
|
|
7122
|
+
const timerRef = useRef14(null);
|
|
7123
|
+
useEffect14(
|
|
6412
7124
|
() => () => {
|
|
6413
7125
|
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
6414
7126
|
},
|
|
@@ -6427,7 +7139,7 @@ function CopyMessageButton({ text }) {
|
|
|
6427
7139
|
}
|
|
6428
7140
|
);
|
|
6429
7141
|
};
|
|
6430
|
-
return /* @__PURE__ */
|
|
7142
|
+
return /* @__PURE__ */ jsx16(
|
|
6431
7143
|
"button",
|
|
6432
7144
|
{
|
|
6433
7145
|
type: "button",
|
|
@@ -6435,9 +7147,9 @@ function CopyMessageButton({ text }) {
|
|
|
6435
7147
|
"aria-label": "Copy message",
|
|
6436
7148
|
title: "Copy message",
|
|
6437
7149
|
className: "rounded p-0.5 text-muted-foreground transition hover:bg-accent hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
6438
|
-
children: copied ? /* @__PURE__ */
|
|
6439
|
-
/* @__PURE__ */
|
|
6440
|
-
/* @__PURE__ */
|
|
7150
|
+
children: copied ? /* @__PURE__ */ jsx16("svg", { className: "h-3.5 w-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx16("polyline", { points: "20 6 9 17 4 12" }) }) : /* @__PURE__ */ jsxs14("svg", { className: "h-3.5 w-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
7151
|
+
/* @__PURE__ */ jsx16("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2" }),
|
|
7152
|
+
/* @__PURE__ */ jsx16("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
|
|
6441
7153
|
] })
|
|
6442
7154
|
}
|
|
6443
7155
|
);
|
|
@@ -6460,34 +7172,34 @@ function AssistantMessageImpl({
|
|
|
6460
7172
|
}) {
|
|
6461
7173
|
const content = useSmoothText(msg.content, streaming);
|
|
6462
7174
|
const reasoning = useSmoothText(msg.reasoning ?? "", streaming);
|
|
6463
|
-
const body =
|
|
7175
|
+
const body = useMemo9(() => renderBody(content), [renderBody, content]);
|
|
6464
7176
|
const segments = msg.segments;
|
|
6465
7177
|
const hasAnswerText = content !== "" || (segments?.some((s) => s.kind === "text" && s.content.trim() !== "") ?? false);
|
|
6466
|
-
const reasoningScrollRef =
|
|
6467
|
-
const thinkStartRef =
|
|
6468
|
-
const thinkMsRef =
|
|
7178
|
+
const reasoningScrollRef = useRef14(null);
|
|
7179
|
+
const thinkStartRef = useRef14(null);
|
|
7180
|
+
const thinkMsRef = useRef14(null);
|
|
6469
7181
|
if (streaming && reasoning && !hasAnswerText && thinkStartRef.current === null) {
|
|
6470
7182
|
thinkStartRef.current = performance.now();
|
|
6471
7183
|
}
|
|
6472
7184
|
if (hasAnswerText && thinkStartRef.current !== null && thinkMsRef.current === null) {
|
|
6473
7185
|
thinkMsRef.current = performance.now() - thinkStartRef.current;
|
|
6474
7186
|
}
|
|
6475
|
-
|
|
7187
|
+
useEffect14(() => {
|
|
6476
7188
|
const el = reasoningScrollRef.current;
|
|
6477
7189
|
if (el && streaming && !hasAnswerText) el.scrollTop = el.scrollHeight;
|
|
6478
7190
|
}, [reasoning, streaming, hasAnswerText]);
|
|
6479
7191
|
const thinkingSeconds = useThinkingSeconds(
|
|
6480
7192
|
streaming && !!reasoning && !hasAnswerText
|
|
6481
7193
|
);
|
|
6482
|
-
const [reasoningToggled, setReasoningToggled] =
|
|
7194
|
+
const [reasoningToggled, setReasoningToggled] = useState18(null);
|
|
6483
7195
|
const reasoningOpen = reasoningToggled ?? !hasAnswerText;
|
|
6484
7196
|
const quiet = chrome === "quiet";
|
|
6485
|
-
return /* @__PURE__ */
|
|
6486
|
-
!quiet && /* @__PURE__ */
|
|
6487
|
-
/* @__PURE__ */
|
|
6488
|
-
msg.modelUsed && /* @__PURE__ */
|
|
6489
|
-
formatTokensPerSecond(msg) && /* @__PURE__ */
|
|
6490
|
-
formatModelCost(msg, models) && /* @__PURE__ */
|
|
7197
|
+
return /* @__PURE__ */ jsxs14("div", { className: `mx-auto w-full max-w-3xl px-6 ${quiet ? "group pb-1 pt-3" : "py-3"}`, children: [
|
|
7198
|
+
!quiet && /* @__PURE__ */ jsxs14("div", { className: "mb-1 flex items-baseline gap-2 text-xs tabular-nums text-muted-foreground", children: [
|
|
7199
|
+
/* @__PURE__ */ jsx16("span", { className: "font-semibold uppercase tracking-[0.05em]", children: agentLabel }),
|
|
7200
|
+
msg.modelUsed && /* @__PURE__ */ jsx16("span", { className: "font-mono normal-case", children: msg.modelUsed }),
|
|
7201
|
+
formatTokensPerSecond(msg) && /* @__PURE__ */ jsx16("span", { children: formatTokensPerSecond(msg) }),
|
|
7202
|
+
formatModelCost(msg, models) && /* @__PURE__ */ jsx16("span", { children: formatModelCost(msg, models) })
|
|
6491
7203
|
] }),
|
|
6492
7204
|
reasoning && // The canonical run-row grammar (RunRowShell — the same shell the tool
|
|
6493
7205
|
// rows compose): one family of rows instead of a bespoke disclosure per
|
|
@@ -6497,12 +7209,12 @@ function AssistantMessageImpl({
|
|
|
6497
7209
|
// and a click outranks the default from then on — the contract the old
|
|
6498
7210
|
// hand-rolled disclosure had, now enforced through the shell's
|
|
6499
7211
|
// controlled `open`.
|
|
6500
|
-
/* @__PURE__ */
|
|
7212
|
+
/* @__PURE__ */ jsx16(
|
|
6501
7213
|
RunRowShell,
|
|
6502
7214
|
{
|
|
6503
7215
|
className: "mb-2",
|
|
6504
|
-
icon: /* @__PURE__ */
|
|
6505
|
-
title: !hasAnswerText ? /* @__PURE__ */
|
|
7216
|
+
icon: /* @__PURE__ */ jsx16(BrainGlyph, { className: "h-3.5 w-3.5" }),
|
|
7217
|
+
title: !hasAnswerText ? /* @__PURE__ */ jsxs14("span", { className: "agent-shimmer", "data-motion": "essential", children: [
|
|
6506
7218
|
"Thinking",
|
|
6507
7219
|
thinkingSeconds >= 1 ? ` \xB7 ${thinkingSeconds}s` : "\u2026"
|
|
6508
7220
|
] }) : thinkMsRef.current != null ? (
|
|
@@ -6517,7 +7229,7 @@ function AssistantMessageImpl({
|
|
|
6517
7229
|
status: hasAnswerText ? "idle" : "running",
|
|
6518
7230
|
open: reasoningOpen,
|
|
6519
7231
|
onOpenChange: (next) => setReasoningToggled(next),
|
|
6520
|
-
children: /* @__PURE__ */
|
|
7232
|
+
children: /* @__PURE__ */ jsx16(
|
|
6521
7233
|
"div",
|
|
6522
7234
|
{
|
|
6523
7235
|
ref: reasoningScrollRef,
|
|
@@ -6527,7 +7239,7 @@ function AssistantMessageImpl({
|
|
|
6527
7239
|
)
|
|
6528
7240
|
}
|
|
6529
7241
|
),
|
|
6530
|
-
segments && segments.length > 0 ? /* @__PURE__ */
|
|
7242
|
+
segments && segments.length > 0 ? /* @__PURE__ */ jsx16(
|
|
6531
7243
|
SegmentedBody,
|
|
6532
7244
|
{
|
|
6533
7245
|
segments,
|
|
@@ -6539,12 +7251,12 @@ function AssistantMessageImpl({
|
|
|
6539
7251
|
toolRenderers,
|
|
6540
7252
|
messageClassName
|
|
6541
7253
|
}
|
|
6542
|
-
) : /* @__PURE__ */
|
|
6543
|
-
/* @__PURE__ */
|
|
7254
|
+
) : /* @__PURE__ */ jsxs14(Fragment9, { children: [
|
|
7255
|
+
/* @__PURE__ */ jsxs14("div", { className: messageClassName, children: [
|
|
6544
7256
|
body,
|
|
6545
|
-
streaming && content && !msg.toolCalls?.length && /* @__PURE__ */
|
|
7257
|
+
streaming && content && !msg.toolCalls?.length && /* @__PURE__ */ jsx16(StreamingCaret, {})
|
|
6546
7258
|
] }),
|
|
6547
|
-
msg.toolCalls && msg.toolCalls.length > 0 && /* @__PURE__ */
|
|
7259
|
+
msg.toolCalls && msg.toolCalls.length > 0 && /* @__PURE__ */ jsx16("div", { className: "mt-2 flex flex-col gap-1.5", children: msg.toolCalls.map((tc, index) => /* @__PURE__ */ jsx16(
|
|
6548
7260
|
ToolCallCard,
|
|
6549
7261
|
{
|
|
6550
7262
|
call: tc,
|
|
@@ -6557,7 +7269,7 @@ function AssistantMessageImpl({
|
|
|
6557
7269
|
tc.id
|
|
6558
7270
|
)) })
|
|
6559
7271
|
] }),
|
|
6560
|
-
durableCards && msg.parts && /* @__PURE__ */
|
|
7272
|
+
durableCards && msg.parts && /* @__PURE__ */ jsx16(
|
|
6561
7273
|
DurableChatCards,
|
|
6562
7274
|
{
|
|
6563
7275
|
...durableCards,
|
|
@@ -6566,7 +7278,7 @@ function AssistantMessageImpl({
|
|
|
6566
7278
|
className: "mt-3"
|
|
6567
7279
|
}
|
|
6568
7280
|
),
|
|
6569
|
-
workProductCards && workProductPartsFromMessageParts(msg.parts).map((part) => /* @__PURE__ */
|
|
7281
|
+
workProductCards && workProductPartsFromMessageParts(msg.parts).map((part) => /* @__PURE__ */ jsx16(
|
|
6570
7282
|
WorkProductCard,
|
|
6571
7283
|
{
|
|
6572
7284
|
part,
|
|
@@ -6576,7 +7288,7 @@ function AssistantMessageImpl({
|
|
|
6576
7288
|
`${part.ref.id}:${part.ref.version}`
|
|
6577
7289
|
)),
|
|
6578
7290
|
renderExtras?.(msg),
|
|
6579
|
-
resolveAttachmentUrl && attachmentPartsFromMessageParts(msg.parts).length > 0 && /* @__PURE__ */
|
|
7291
|
+
resolveAttachmentUrl && attachmentPartsFromMessageParts(msg.parts).length > 0 && /* @__PURE__ */ jsx16("div", { className: "mt-2", children: /* @__PURE__ */ jsx16(
|
|
6580
7292
|
MessageAttachments,
|
|
6581
7293
|
{
|
|
6582
7294
|
parts: attachmentPartsFromMessageParts(msg.parts),
|
|
@@ -6584,18 +7296,18 @@ function AssistantMessageImpl({
|
|
|
6584
7296
|
justify: "start"
|
|
6585
7297
|
}
|
|
6586
7298
|
) }),
|
|
6587
|
-
quiet && /* @__PURE__ */
|
|
6588
|
-
/* @__PURE__ */
|
|
6589
|
-
msg.modelUsed && /* @__PURE__ */
|
|
6590
|
-
formatTokensPerSecond(msg) && /* @__PURE__ */
|
|
6591
|
-
formatModelCost(msg, models) && /* @__PURE__ */
|
|
7299
|
+
quiet && /* @__PURE__ */ jsxs14("div", { "data-testid": "message-meta-lane", className: QUIET_META_LANE_CLASS, children: [
|
|
7300
|
+
/* @__PURE__ */ jsx16(CopyMessageButton, { text: copyTextOf(msg) }),
|
|
7301
|
+
msg.modelUsed && /* @__PURE__ */ jsx16("span", { className: "font-mono", children: msg.modelUsed }),
|
|
7302
|
+
formatTokensPerSecond(msg) && /* @__PURE__ */ jsx16("span", { children: formatTokensPerSecond(msg) }),
|
|
7303
|
+
formatModelCost(msg, models) && /* @__PURE__ */ jsx16("span", { children: formatModelCost(msg, models) })
|
|
6592
7304
|
] })
|
|
6593
7305
|
] });
|
|
6594
7306
|
}
|
|
6595
7307
|
var AssistantMessage = memo(AssistantMessageImpl);
|
|
6596
7308
|
function useThinkingSeconds(active) {
|
|
6597
|
-
const [seconds, setSeconds] =
|
|
6598
|
-
|
|
7309
|
+
const [seconds, setSeconds] = useState18(0);
|
|
7310
|
+
useEffect14(() => {
|
|
6599
7311
|
if (!active) return;
|
|
6600
7312
|
setSeconds(0);
|
|
6601
7313
|
const id = setInterval(() => setSeconds((s) => s + 1), 1e3);
|
|
@@ -6605,23 +7317,23 @@ function useThinkingSeconds(active) {
|
|
|
6605
7317
|
}
|
|
6606
7318
|
function ThinkingRow({ agentLabel, chrome = "labeled" }) {
|
|
6607
7319
|
const seconds = useThinkingSeconds(true);
|
|
6608
|
-
return /* @__PURE__ */
|
|
6609
|
-
chrome !== "quiet" && /* @__PURE__ */
|
|
6610
|
-
/* @__PURE__ */
|
|
6611
|
-
/* @__PURE__ */
|
|
7320
|
+
return /* @__PURE__ */ jsxs14("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
|
|
7321
|
+
chrome !== "quiet" && /* @__PURE__ */ jsx16("p", { className: "mb-1 text-xs font-semibold uppercase tracking-[0.05em] text-muted-foreground", children: agentLabel }),
|
|
7322
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2 text-[15px] text-muted-foreground", children: [
|
|
7323
|
+
/* @__PURE__ */ jsx16("svg", { className: "h-4 w-4 animate-spin", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": true, children: /* @__PURE__ */ jsx16("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", strokeLinecap: "round" }) }),
|
|
6612
7324
|
"Thinking",
|
|
6613
7325
|
seconds >= 3 ? ` \xB7 ${seconds}s` : "..."
|
|
6614
7326
|
] })
|
|
6615
7327
|
] });
|
|
6616
7328
|
}
|
|
6617
7329
|
function StreamErrorRow({ message, onRetry }) {
|
|
6618
|
-
return /* @__PURE__ */
|
|
6619
|
-
/* @__PURE__ */
|
|
6620
|
-
/* @__PURE__ */
|
|
6621
|
-
/* @__PURE__ */
|
|
7330
|
+
return /* @__PURE__ */ jsx16("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: /* @__PURE__ */ jsxs14("div", { role: "alert", className: "flex items-start gap-2.5 rounded-lg border border-destructive/40 bg-destructive/5 px-3 py-2.5 text-sm text-destructive", children: [
|
|
7331
|
+
/* @__PURE__ */ jsxs14("svg", { className: "mt-0.5 h-4 w-4 shrink-0", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
|
|
7332
|
+
/* @__PURE__ */ jsx16("circle", { cx: "12", cy: "12", r: "9" }),
|
|
7333
|
+
/* @__PURE__ */ jsx16("path", { d: "M12 8v4m0 4h.01" })
|
|
6622
7334
|
] }),
|
|
6623
|
-
/* @__PURE__ */
|
|
6624
|
-
onRetry && /* @__PURE__ */
|
|
7335
|
+
/* @__PURE__ */ jsx16("span", { className: "min-w-0 flex-1 break-words", children: message }),
|
|
7336
|
+
onRetry && /* @__PURE__ */ jsx16(
|
|
6625
7337
|
"button",
|
|
6626
7338
|
{
|
|
6627
7339
|
type: "button",
|
|
@@ -6655,33 +7367,33 @@ function ChatMessages({
|
|
|
6655
7367
|
workProductCards
|
|
6656
7368
|
}) {
|
|
6657
7369
|
const messageClassName = messageSize === "large" ? "agent-app-message-copy text-[17px] leading-[1.6]" : "agent-app-message-copy text-base leading-[1.6]";
|
|
6658
|
-
const renderBody =
|
|
6659
|
-
() => renderMarkdown ?? ((content) => /* @__PURE__ */
|
|
7370
|
+
const renderBody = useMemo9(
|
|
7371
|
+
() => renderMarkdown ?? ((content) => /* @__PURE__ */ jsx16("p", { className: "whitespace-pre-wrap", children: content })),
|
|
6660
7372
|
[renderMarkdown]
|
|
6661
7373
|
);
|
|
6662
7374
|
const lastIsUser = messages[messages.length - 1]?.role === "user";
|
|
6663
7375
|
const quiet = chrome === "quiet";
|
|
6664
7376
|
if (messages.length === 0 && !loading && !error) {
|
|
6665
|
-
const empty = renderEmpty ? renderEmpty() : /* @__PURE__ */
|
|
6666
|
-
return /* @__PURE__ */
|
|
7377
|
+
const empty = renderEmpty ? renderEmpty() : /* @__PURE__ */ jsx16(ChatEmptyState, { ...emptyState });
|
|
7378
|
+
return /* @__PURE__ */ jsxs14(Fragment9, { children: [
|
|
6667
7379
|
header,
|
|
6668
7380
|
empty
|
|
6669
7381
|
] });
|
|
6670
7382
|
}
|
|
6671
|
-
return /* @__PURE__ */
|
|
7383
|
+
return /* @__PURE__ */ jsxs14(Fragment9, { children: [
|
|
6672
7384
|
header,
|
|
6673
7385
|
messages.map(
|
|
6674
|
-
(msg) => msg.role === "user" ? /* @__PURE__ */
|
|
6675
|
-
/* @__PURE__ */
|
|
6676
|
-
!quiet && /* @__PURE__ */
|
|
6677
|
-
/* @__PURE__ */
|
|
7386
|
+
(msg) => msg.role === "user" ? /* @__PURE__ */ jsxs14("div", { className: `mx-auto w-full max-w-3xl px-6 ${quiet ? "group pb-1 pt-3" : "py-3"}`, children: [
|
|
7387
|
+
/* @__PURE__ */ jsxs14("div", { className: `ml-auto w-fit ${quiet ? "max-w-[72%]" : "max-w-[85%]"}`, children: [
|
|
7388
|
+
!quiet && /* @__PURE__ */ jsx16("p", { className: "mb-1 text-right text-xs font-semibold uppercase tracking-[0.05em] text-muted-foreground", children: userLabel }),
|
|
7389
|
+
/* @__PURE__ */ jsx16(
|
|
6678
7390
|
"div",
|
|
6679
7391
|
{
|
|
6680
7392
|
className: quiet ? `rounded-2xl bg-[color-mix(in_srgb,hsl(var(--secondary))_65%,hsl(var(--background)))] px-4 py-2.5 ${messageClassName}` : `rounded-2xl rounded-tr-md bg-primary/10 px-4 py-2.5 ${messageClassName}`,
|
|
6681
|
-
children: /* @__PURE__ */
|
|
7393
|
+
children: /* @__PURE__ */ jsx16("p", { className: "whitespace-pre-wrap", children: msg.content })
|
|
6682
7394
|
}
|
|
6683
7395
|
),
|
|
6684
|
-
resolveAttachmentUrl && attachmentPartsFromMessageParts(msg.parts).length > 0 && /* @__PURE__ */
|
|
7396
|
+
resolveAttachmentUrl && attachmentPartsFromMessageParts(msg.parts).length > 0 && /* @__PURE__ */ jsx16("div", { className: "mt-1.5", children: /* @__PURE__ */ jsx16(
|
|
6685
7397
|
MessageAttachments,
|
|
6686
7398
|
{
|
|
6687
7399
|
parts: attachmentPartsFromMessageParts(msg.parts),
|
|
@@ -6690,8 +7402,8 @@ function ChatMessages({
|
|
|
6690
7402
|
}
|
|
6691
7403
|
) })
|
|
6692
7404
|
] }),
|
|
6693
|
-
quiet && /* @__PURE__ */
|
|
6694
|
-
] }, msg.id) : /* @__PURE__ */
|
|
7405
|
+
quiet && /* @__PURE__ */ jsx16("div", { "data-testid": "message-meta-lane", className: `${QUIET_META_LANE_CLASS} justify-end`, children: /* @__PURE__ */ jsx16(CopyMessageButton, { text: msg.content }) })
|
|
7406
|
+
] }, msg.id) : /* @__PURE__ */ jsx16(
|
|
6695
7407
|
AssistantMessage,
|
|
6696
7408
|
{
|
|
6697
7409
|
msg,
|
|
@@ -6712,8 +7424,8 @@ function ChatMessages({
|
|
|
6712
7424
|
msg.id
|
|
6713
7425
|
)
|
|
6714
7426
|
),
|
|
6715
|
-
loading && lastIsUser && /* @__PURE__ */
|
|
6716
|
-
error && !loading && /* @__PURE__ */
|
|
7427
|
+
loading && lastIsUser && /* @__PURE__ */ jsx16(ThinkingRow, { agentLabel, chrome }),
|
|
7428
|
+
error && !loading && /* @__PURE__ */ jsx16(StreamErrorRow, { message: error, onRetry })
|
|
6717
7429
|
] });
|
|
6718
7430
|
}
|
|
6719
7431
|
|
|
@@ -6748,6 +7460,10 @@ export {
|
|
|
6748
7460
|
dispatchChatStreamLine,
|
|
6749
7461
|
consumeChatStream,
|
|
6750
7462
|
streamChatTurn,
|
|
7463
|
+
pickDictationMimeType,
|
|
7464
|
+
dictationErrorMessage,
|
|
7465
|
+
formatDictationElapsed,
|
|
7466
|
+
useDictation,
|
|
6751
7467
|
ChatComposer,
|
|
6752
7468
|
DurablePlanClientError,
|
|
6753
7469
|
createDurablePlanDecisionClient,
|
|
@@ -6803,6 +7519,7 @@ export {
|
|
|
6803
7519
|
recordGridFail,
|
|
6804
7520
|
isRecordGridCellApplicable,
|
|
6805
7521
|
sameRecordGridValue,
|
|
7522
|
+
diffRecordGridProposal,
|
|
6806
7523
|
parseRecordGridInput,
|
|
6807
7524
|
validateRecordGridCell,
|
|
6808
7525
|
readRecordGridCell,
|
|
@@ -6822,6 +7539,7 @@ export {
|
|
|
6822
7539
|
withoutRecordGridRemoved,
|
|
6823
7540
|
pruneRecordGridOverlay,
|
|
6824
7541
|
RecordGrid,
|
|
7542
|
+
CommandPalette,
|
|
6825
7543
|
DEFAULT_SPARKLINE_WIDTH,
|
|
6826
7544
|
DEFAULT_SPARKLINE_HEIGHT,
|
|
6827
7545
|
DEFAULT_SPARKLINE_LABEL,
|
|
@@ -6851,4 +7569,4 @@ export {
|
|
|
6851
7569
|
useThinkingSeconds,
|
|
6852
7570
|
ChatMessages
|
|
6853
7571
|
};
|
|
6854
|
-
//# sourceMappingURL=chunk-
|
|
7572
|
+
//# sourceMappingURL=chunk-OMGV3CX2.js.map
|