@burdenoff/fe-libs 2026.1004.4 → 2026.1004.6
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/chrome/ContextSwitcher.d.ts.map +1 -1
- package/dist/chrome/ContextSwitcher.js +73 -50
- package/dist/chrome/GlobalSearch.d.ts.map +1 -1
- package/dist/chrome/GlobalSearch.js +76 -72
- package/dist/chrome/LanguageSwitcher.d.ts.map +1 -1
- package/dist/chrome/LanguageSwitcher.js +61 -40
- package/dist/chrome/NotificationCenter.d.ts.map +1 -1
- package/dist/chrome/NotificationCenter.js +71 -68
- package/dist/chrome/ProfileSwitcher.d.ts.map +1 -1
- package/dist/chrome/ProfileSwitcher.js +87 -81
- package/dist/chrome/SideNavigation.d.ts.map +1 -1
- package/dist/chrome/SideNavigation.js +120 -76
- package/dist/shared/assistant/appControls/copy.d.ts +12 -0
- package/dist/shared/assistant/appControls/copy.d.ts.map +1 -0
- package/dist/shared/assistant/appControls/copy.js +98 -0
- package/dist/shared/assistant/appControls/grammar.d.ts +102 -0
- package/dist/shared/assistant/appControls/grammar.d.ts.map +1 -0
- package/dist/shared/assistant/appControls/grammar.js +236 -0
- package/dist/shared/assistant/appControls/languages.d.ts +6 -0
- package/dist/shared/assistant/appControls/languages.d.ts.map +1 -0
- package/dist/shared/assistant/appControls/languages.js +52 -0
- package/dist/shared/assistant/appControls/names.d.ts +22 -0
- package/dist/shared/assistant/appControls/names.d.ts.map +1 -0
- package/dist/shared/assistant/appControls/names.js +29 -0
- package/dist/shared/assistant/appControls/pageAdapters.d.ts +59 -0
- package/dist/shared/assistant/appControls/pageAdapters.d.ts.map +1 -0
- package/dist/shared/assistant/appControls/pageAdapters.js +87 -0
- package/dist/shared/assistant/appControls/plan.d.ts +148 -0
- package/dist/shared/assistant/appControls/plan.d.ts.map +1 -0
- package/dist/shared/assistant/appControls/plan.js +511 -0
- package/dist/shared/assistant/appControls/registry.d.ts +9 -0
- package/dist/shared/assistant/appControls/registry.d.ts.map +1 -0
- package/dist/shared/assistant/appControls/registry.js +38 -0
- package/dist/shared/assistant/appControls/snapshot.d.ts +42 -0
- package/dist/shared/assistant/appControls/snapshot.d.ts.map +1 -0
- package/dist/shared/assistant/appControls/snapshot.js +40 -0
- package/dist/shared/assistant/appControls/text.d.ts +7 -0
- package/dist/shared/assistant/appControls/text.d.ts.map +1 -0
- package/dist/shared/assistant/appControls/text.js +6 -0
- package/dist/shared/assistant/appControls/types.d.ts +183 -0
- package/dist/shared/assistant/appControls/types.d.ts.map +1 -0
- package/dist/shared/assistant/appControls/types.js +25 -0
- package/dist/shared/assistant/appControls/useAssistantControl.d.ts +24 -0
- package/dist/shared/assistant/appControls/useAssistantControl.d.ts.map +1 -0
- package/dist/shared/assistant/appControls/useAssistantControl.js +13 -0
- package/dist/shared/assistant/conversation.d.ts +12 -1
- package/dist/shared/assistant/conversation.d.ts.map +1 -1
- package/dist/shared/assistant/history/historyMapping.d.ts.map +1 -1
- package/dist/shared/assistant/history/historyMapping.js +130 -114
- package/dist/shared/assistant/i18nManifest.d.ts +74 -0
- package/dist/shared/assistant/i18nManifest.d.ts.map +1 -1
- package/dist/shared/assistant/i18nManifest.js +86 -12
- package/dist/shared/assistant/index.d.ts +16 -0
- package/dist/shared/assistant/index.d.ts.map +1 -1
- package/dist/shared/assistant/localUiCommandCopy.d.ts +7 -0
- package/dist/shared/assistant/localUiCommandCopy.d.ts.map +1 -1
- package/dist/shared/assistant/localUiCommandCopy.js +1 -1
- package/dist/shared/assistant/localUiCommands.d.ts +16 -0
- package/dist/shared/assistant/localUiCommands.d.ts.map +1 -1
- package/dist/shared/assistant/localUiCommands.js +92 -84
- package/dist/shared/assistant/store.d.ts +10 -0
- package/dist/shared/assistant/store.d.ts.map +1 -1
- package/dist/shared/assistant/store.js +52 -44
- package/dist/shared/assistant/ui/AIAssistantPanel.d.ts.map +1 -1
- package/dist/shared/assistant/ui/AIAssistantPanel.js +57 -49
- package/dist/shared/assistant/ui/AssistantChatArea.d.ts.map +1 -1
- package/dist/shared/assistant/ui/AssistantChatArea.js +1085 -1016
- package/dist/shared/assistant/ui/AssistantControlConfirmDialog.d.ts +38 -0
- package/dist/shared/assistant/ui/AssistantControlConfirmDialog.d.ts.map +1 -0
- package/dist/shared/assistant/ui/AssistantControlConfirmDialog.js +65 -0
- package/dist/shared/assistant/ui/AssistantMoreMenu.d.ts.map +1 -1
- package/dist/shared/assistant/ui/AssistantMoreMenu.js +58 -56
- package/dist/shared/assistant/ui/AssistantSpeechProvider.d.ts.map +1 -1
- package/dist/shared/assistant/ui/AssistantSpeechProvider.js +106 -105
- package/dist/shared/assistant/ui/composer/AssistantVoiceGraceSelector.d.ts +20 -0
- package/dist/shared/assistant/ui/composer/AssistantVoiceGraceSelector.d.ts.map +1 -0
- package/dist/shared/assistant/ui/composer/AssistantVoiceGraceSelector.js +39 -0
- package/dist/shared/assistant/ui/controlConfirmDialog.d.ts +30 -0
- package/dist/shared/assistant/ui/controlConfirmDialog.d.ts.map +1 -0
- package/dist/shared/assistant/ui/controlConfirmDialog.js +46 -0
- package/dist/shared/assistant/ui/useVoiceSession.d.ts +35 -2
- package/dist/shared/assistant/ui/useVoiceSession.d.ts.map +1 -1
- package/dist/shared/assistant/ui/useVoiceSession.js +232 -171
- package/dist/shared/assistant/ui/voice/AssistantVoiceSession.d.ts +15 -1
- package/dist/shared/assistant/ui/voice/AssistantVoiceSession.d.ts.map +1 -1
- package/dist/shared/assistant/ui/voice/AssistantVoiceSession.js +173 -150
- package/dist/shared/assistant/voice/handsFree.d.ts +160 -0
- package/dist/shared/assistant/voice/handsFree.d.ts.map +1 -0
- package/dist/shared/assistant/voice/handsFree.js +104 -0
- package/dist/shared/assistant/voice/supersededTurns.d.ts +29 -0
- package/dist/shared/assistant/voice/supersededTurns.d.ts.map +1 -0
- package/dist/shared/assistant/voice/supersededTurns.js +17 -0
- package/dist/shared/assistant/voice/useVoiceInput.d.ts +7 -0
- package/dist/shared/assistant/voice/useVoiceInput.d.ts.map +1 -1
- package/dist/shared/assistant/voice/useVoiceInput.js +13 -10
- package/dist/shared/assistant/voice/voiceSession.d.ts +64 -20
- package/dist/shared/assistant/voice/voiceSession.d.ts.map +1 -1
- package/dist/shared/assistant/voice/voiceSession.js +120 -67
- package/dist/shared/components/KeyboardHelpDialogWrapper.d.ts.map +1 -1
- package/dist/shared/components/KeyboardHelpDialogWrapper.js +11 -9
- package/dist/shared/providers/shell/GlobalUiProvider.d.ts +2 -0
- package/dist/shared/providers/shell/GlobalUiProvider.d.ts.map +1 -1
- package/dist/shared/providers/shell/GlobalUiProvider.js +4 -1
- package/dist/shared-assistant.js +219 -203
- package/package.json +1 -1
|
@@ -1,233 +1,256 @@
|
|
|
1
1
|
import { useReturnFocus as e } from "../../../hooks/useReturnFocus.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
2
|
+
import { useAssistantControl as t } from "../../appControls/useAssistantControl.js";
|
|
3
|
+
import { useAssistantTr as n } from "../../i18n.js";
|
|
4
|
+
import { micIsInterrupt as r, showsAssistantCaption as ee, voiceStageState as i } from "../../voice/voiceStageState.js";
|
|
5
|
+
import { VOICE_THINKING_LABEL as a, composeVoiceStatus as te, voiceStatusSuffix as ne } from "../../voice/voiceStatus.js";
|
|
6
|
+
import { spokenSoFar as o } from "../../voice/voiceSession.js";
|
|
7
|
+
import { ASSISTANT_PANEL_ATTR as re, ASSISTANT_VOICE_SESSION_ATTR as ie } from "../panelOverlays.js";
|
|
8
|
+
import { AssistantAttachmentButton as ae } from "../composer/AssistantAttachmentButton.js";
|
|
9
|
+
import { AssistantAttachmentChips as oe } from "../composer/AssistantAttachmentChips.js";
|
|
10
|
+
import { AssistantVoiceOrb as se } from "./AssistantVoiceOrb.js";
|
|
11
|
+
import { VoiceMiniController as ce } from "./VoiceMiniController.js";
|
|
12
|
+
import { VoiceStage as le } from "./VoiceStage.js";
|
|
13
|
+
import { VoiceTranscriptDrawer as ue } from "./VoiceTranscriptDrawer.js";
|
|
14
|
+
import { escapeBelongsToLayerAbove as de, voiceSessionEscapeAction as fe } from "./voiceSessionEscape.js";
|
|
15
|
+
import { useCallback as s, useEffect as c, useMemo as pe, useRef as l, useState as u } from "react";
|
|
16
|
+
import { Maximize2 as me, Minimize2 as he, ScrollText as ge, X as d } from "lucide-react";
|
|
17
|
+
import { jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
17
18
|
//#region src/shared/assistant/ui/voice/AssistantVoiceSession.tsx
|
|
18
|
-
var
|
|
19
|
-
let
|
|
20
|
-
|
|
21
|
-
let
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}, []),
|
|
26
|
-
|
|
19
|
+
var m = ({ session: m, turns: ye = [], onSaveTranscript: be, onContinueInChat: xe, notice: h = null, spoken: g, onInterrupt: Se, onToggleMute: _, attachments: v = [], onAttachFiles: y, onRemoveAttachment: Ce, onRetryAttachment: we, canAttachMore: Te = !0, preparingAttachments: b = 0, spokenChunks: x = null, onEnd: S, capturing: Ee = !0, interrupting: De = !1, awaitingEndpoint: Oe = !1, holding: C = !1, correcting: ke = !1, onLetMeFinish: w, onImDone: T, proposalChip: E = null, proposalTray: D = null }) => {
|
|
20
|
+
let O = n(), { muted: k, error: A } = m, j = l(null), M = l(null), [N, P] = u("mini"), F = N === "full", I = N === "mini", L = N === "mini" ? "panel" : N === "panel" ? "full" : "mini", [R, z] = u(!1);
|
|
21
|
+
t("assistant.transcript", pe(() => ({ run: () => R ? { status: "already" } : (z(!0), { status: "done" }) }), [R]));
|
|
22
|
+
let B = D !== null && !I, V = l(!1), H = l(_);
|
|
23
|
+
H.current = _;
|
|
24
|
+
let U = s(() => {
|
|
25
|
+
m.phase !== "listening" && m.phase !== "thinking" || k || V.current || o(m) || (V.current = !0, H.current());
|
|
26
|
+
}, [k, m]), W = s(() => {
|
|
27
|
+
V.current && (V.current = !1, H.current());
|
|
28
|
+
}, []), Ae = U;
|
|
29
|
+
c(() => {
|
|
27
30
|
let e = () => {
|
|
28
|
-
document.visibilityState === "hidden" ?
|
|
31
|
+
document.visibilityState === "hidden" ? U() : W();
|
|
29
32
|
};
|
|
30
33
|
return document.addEventListener("visibilitychange", e), () => document.removeEventListener("visibilitychange", e);
|
|
31
|
-
}, [
|
|
32
|
-
let e =
|
|
34
|
+
}, [U, W]), c(() => {
|
|
35
|
+
let e = W;
|
|
33
36
|
return window.addEventListener("focus", e), () => {
|
|
34
|
-
window.removeEventListener("focus", e),
|
|
37
|
+
window.removeEventListener("focus", e), V.current = !1;
|
|
35
38
|
};
|
|
36
|
-
}, []),
|
|
37
|
-
|
|
38
|
-
}, []), e(
|
|
39
|
+
}, []), c(() => {
|
|
40
|
+
j.current?.focus();
|
|
41
|
+
}, []), e(M, { fallbackSelector: `[${re}]` }), c(() => {
|
|
39
42
|
let e = (e) => {
|
|
40
43
|
if (e.key === "Escape") {
|
|
41
|
-
let t =
|
|
44
|
+
let t = fe({
|
|
42
45
|
defaultPrevented: e.defaultPrevented,
|
|
43
|
-
layerAbove:
|
|
46
|
+
layerAbove: de({
|
|
44
47
|
target: e.target,
|
|
45
|
-
session:
|
|
48
|
+
session: M.current,
|
|
46
49
|
doc: document
|
|
47
50
|
}),
|
|
48
|
-
transcriptOpen:
|
|
51
|
+
transcriptOpen: R
|
|
49
52
|
});
|
|
50
53
|
if (t === "ignore") return;
|
|
51
|
-
e.preventDefault(), t === "close-transcript" ?
|
|
54
|
+
e.preventDefault(), t === "close-transcript" ? z(!1) : B ? D?.onClose() : S();
|
|
52
55
|
return;
|
|
53
56
|
}
|
|
54
|
-
if (e.key !== "Tab" || !
|
|
55
|
-
let t = (
|
|
57
|
+
if (e.key !== "Tab" || !F) return;
|
|
58
|
+
let t = (R ? M.current?.querySelector("[data-testid=\"assistant-voice-transcript\"]") : M.current)?.querySelectorAll("button:not([disabled])");
|
|
56
59
|
if (!t || t.length === 0) return;
|
|
57
60
|
let n = t[0], r = t[t.length - 1];
|
|
58
61
|
!n || !r || (e.shiftKey && document.activeElement === n ? (e.preventDefault(), r.focus()) : !e.shiftKey && document.activeElement === r && (e.preventDefault(), n.focus()));
|
|
59
62
|
};
|
|
60
63
|
return window.addEventListener("keydown", e), () => window.removeEventListener("keydown", e);
|
|
61
64
|
}, [
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
S,
|
|
66
|
+
F,
|
|
67
|
+
R,
|
|
68
|
+
B,
|
|
69
|
+
D
|
|
67
70
|
]);
|
|
68
|
-
let
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
let G = h !== null && A === null, K = o(m), q = w && T && m.phase === "listening" && !k && A === null ? {
|
|
72
|
+
letMeFinish: w,
|
|
73
|
+
imDone: T
|
|
74
|
+
} : null, J = q !== null;
|
|
75
|
+
c(() => {
|
|
76
|
+
if (J) return;
|
|
77
|
+
let e = document.activeElement;
|
|
78
|
+
(!e || e === document.body) && j.current?.focus();
|
|
79
|
+
}, [J]);
|
|
80
|
+
let Y = i({
|
|
81
|
+
snapshot: m,
|
|
82
|
+
capturing: Ee,
|
|
83
|
+
interrupting: De,
|
|
84
|
+
awaitingEndpoint: Oe
|
|
85
|
+
}), je = (() => {
|
|
74
86
|
switch (Y) {
|
|
75
|
-
case "connecting": return
|
|
76
|
-
case "endpoint-grace": return
|
|
77
|
-
case "interrupting": return
|
|
78
|
-
case "thinking": return
|
|
79
|
-
case "speaking": return
|
|
87
|
+
case "connecting": return O("voiceSession.connecting", "Starting the microphone…");
|
|
88
|
+
case "endpoint-grace": return O("voiceSession.endpointGrace", "Still listening — take your time");
|
|
89
|
+
case "interrupting": return O("voiceSession.interrupting", "Stopped — go ahead");
|
|
90
|
+
case "thinking": return O(a.key, a.fallback);
|
|
91
|
+
case "speaking": return O("voiceSession.speaking", "Speaking — tap to stop");
|
|
80
92
|
case "mic-error":
|
|
81
93
|
case "ended": return "";
|
|
82
|
-
case "listening": return
|
|
94
|
+
case "listening": return k ? O("voiceSession.muted", "Microphone off") : O("voiceSession.listening", "Listening…");
|
|
83
95
|
default: return Y;
|
|
84
96
|
}
|
|
85
|
-
})(), Z =
|
|
86
|
-
tr:
|
|
97
|
+
})(), X = !k && (Y === "listening" || Y === "endpoint-grace"), Z = X && C ? O("voiceSession.holding", "Take your time — tap “I’m done” when you finish") : X && ke ? O("voiceSession.correcting", "Stopped that answer — listening to your correction") : je, Q = ne({
|
|
98
|
+
tr: O,
|
|
87
99
|
stage: Y,
|
|
88
|
-
muted:
|
|
89
|
-
label:
|
|
90
|
-
}),
|
|
91
|
-
return /* @__PURE__ */
|
|
92
|
-
ref:
|
|
93
|
-
className: `flex flex-col items-center justify-between bg-bg-sunken ${
|
|
100
|
+
muted: k,
|
|
101
|
+
label: Z
|
|
102
|
+
}), $ = te(Z, Q), Me = Y === "thinking";
|
|
103
|
+
return /* @__PURE__ */ p("div", {
|
|
104
|
+
ref: M,
|
|
105
|
+
className: `flex flex-col items-center justify-between bg-bg-sunken ${N === "full" ? "fixed inset-x-0 bottom-0 top-14 z-[60] px-6 py-8" : N === "panel" ? "absolute inset-0 z-20 px-4 py-6" : "absolute inset-x-0 bottom-0 z-20 h-[11.25rem] border-t border-border-subtle px-3 py-3 shadow-lg"}`,
|
|
94
106
|
role: "dialog",
|
|
95
|
-
"aria-modal":
|
|
96
|
-
"aria-label":
|
|
107
|
+
"aria-modal": F || void 0,
|
|
108
|
+
"aria-label": O("voiceSession.title", "Voice conversation"),
|
|
97
109
|
"data-testid": "assistant-voice-session",
|
|
98
|
-
[
|
|
110
|
+
[ie]: "",
|
|
99
111
|
children: [
|
|
100
|
-
/* @__PURE__ */
|
|
101
|
-
ref:
|
|
112
|
+
/* @__PURE__ */ p("button", {
|
|
113
|
+
ref: j,
|
|
102
114
|
type: "button",
|
|
103
|
-
onClick:
|
|
104
|
-
className: `absolute ${
|
|
105
|
-
title:
|
|
115
|
+
onClick: S,
|
|
116
|
+
className: `absolute ${F ? "right-6 top-6 h-14 gap-2 px-5 text-base" : I ? "right-12 top-2 h-8 gap-1.5 px-2.5 text-xs" : "right-3 top-3 h-11 gap-2 px-4 text-sm"} flex items-center justify-center rounded-full border border-border-default bg-bg-elevated text-text-secondary hover:bg-bg-sunken transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong`,
|
|
117
|
+
title: O("voiceSession.end", "End the voice conversation"),
|
|
106
118
|
"data-testid": "assistant-voice-end",
|
|
107
|
-
children: [/* @__PURE__ */
|
|
108
|
-
className:
|
|
119
|
+
children: [/* @__PURE__ */ f(d, {
|
|
120
|
+
className: F ? "size-6" : I ? "size-4" : "size-5",
|
|
109
121
|
"aria-hidden": "true"
|
|
110
|
-
}), /* @__PURE__ */
|
|
111
|
-
className: `truncate whitespace-nowrap font-medium ${
|
|
112
|
-
children:
|
|
122
|
+
}), /* @__PURE__ */ f("span", {
|
|
123
|
+
className: `truncate whitespace-nowrap font-medium ${I ? "max-w-[3.5rem] text-xs" : "max-w-[7rem]"}`,
|
|
124
|
+
children: O("voiceSession.endShort", "End")
|
|
113
125
|
})]
|
|
114
126
|
}),
|
|
115
|
-
/* @__PURE__ */
|
|
116
|
-
className: `flex flex-col items-center ${
|
|
117
|
-
children:
|
|
127
|
+
/* @__PURE__ */ f("div", {
|
|
128
|
+
className: `flex flex-col items-center ${I ? "px-3" : `min-h-[1.5rem] ${G ? F ? "pt-14" : "pt-10" : ""}`}`,
|
|
129
|
+
children: G ? /* @__PURE__ */ f("p", {
|
|
118
130
|
className: "max-w-xs text-center text-xs text-status-warning",
|
|
119
131
|
"data-testid": "assistant-voice-notice",
|
|
120
|
-
children:
|
|
132
|
+
children: _e(h, O)
|
|
121
133
|
}) : null
|
|
122
134
|
}),
|
|
123
135
|
(() => {
|
|
124
|
-
let e = /* @__PURE__ */
|
|
125
|
-
session:
|
|
126
|
-
compact:
|
|
136
|
+
let e = /* @__PURE__ */ f(se, {
|
|
137
|
+
session: m,
|
|
138
|
+
compact: I,
|
|
127
139
|
connecting: Y === "connecting",
|
|
128
|
-
onPress:
|
|
129
|
-
label:
|
|
130
|
-
}), t =
|
|
131
|
-
|
|
132
|
-
|
|
140
|
+
onPress: r(Y) ? Se : _,
|
|
141
|
+
label: r(Y) ? O("voiceSession.interrupt", "Stop the assistant and speak") : k ? O("voiceSession.unmute", "Turn the microphone on") : O("voiceSession.mute", "Turn the microphone off")
|
|
142
|
+
}), t = q ? /* @__PURE__ */ f("button", {
|
|
143
|
+
type: "button",
|
|
144
|
+
onClick: C ? q.imDone : q.letMeFinish,
|
|
145
|
+
className: `flex items-center justify-center rounded-full border font-medium transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong ${I ? "h-7 px-3 text-xs" : F ? "h-11 px-6 text-base" : "h-9 px-4 text-sm"} ${C ? "border-transparent bg-action-primary-bg text-action-primary-text hover:opacity-90" : "border-border-default bg-bg-elevated text-text-secondary hover:bg-bg-sunken"}`,
|
|
146
|
+
title: C ? O("voiceSession.imDoneHint", "Send what you said now") : O("voiceSession.letMeFinishHint", "Pause sending until you tap “I’m done”"),
|
|
147
|
+
"data-testid": "assistant-voice-hold",
|
|
148
|
+
"data-holding": C ? "true" : "false",
|
|
149
|
+
children: C ? O("voiceSession.imDone", "I’m done") : O("voiceSession.letMeFinish", "Let me finish")
|
|
150
|
+
}) : null, n = t ? /* @__PURE__ */ p("div", {
|
|
151
|
+
className: "flex flex-col items-center gap-2",
|
|
152
|
+
children: [e, t]
|
|
153
|
+
}) : e, i = ee(Y) ? g : K || null, a = A === null ? null : ve(A, O);
|
|
154
|
+
return I ? /* @__PURE__ */ f(ce, {
|
|
155
|
+
spokenChunks: x,
|
|
133
156
|
state: Y,
|
|
134
|
-
caption:
|
|
135
|
-
statusText:
|
|
136
|
-
statusSuffix:
|
|
137
|
-
rotateStatus:
|
|
138
|
-
errorText:
|
|
139
|
-
control:
|
|
140
|
-
}) : /* @__PURE__ */
|
|
157
|
+
caption: i,
|
|
158
|
+
statusText: $,
|
|
159
|
+
statusSuffix: Q,
|
|
160
|
+
rotateStatus: Me,
|
|
161
|
+
errorText: a,
|
|
162
|
+
control: n
|
|
163
|
+
}) : /* @__PURE__ */ f(le, {
|
|
141
164
|
state: Y,
|
|
142
|
-
userCaption:
|
|
143
|
-
spokenChunks:
|
|
144
|
-
assistantCaption:
|
|
145
|
-
expanded:
|
|
146
|
-
statusText:
|
|
147
|
-
statusSuffix:
|
|
148
|
-
rotateStatus:
|
|
149
|
-
errorText:
|
|
150
|
-
control:
|
|
165
|
+
userCaption: K || null,
|
|
166
|
+
spokenChunks: x,
|
|
167
|
+
assistantCaption: g,
|
|
168
|
+
expanded: F,
|
|
169
|
+
statusText: $,
|
|
170
|
+
statusSuffix: Q,
|
|
171
|
+
rotateStatus: Me,
|
|
172
|
+
errorText: a,
|
|
173
|
+
control: n
|
|
151
174
|
});
|
|
152
175
|
})(),
|
|
153
|
-
|
|
154
|
-
className:
|
|
155
|
-
children: /* @__PURE__ */
|
|
176
|
+
E && !B ? /* @__PURE__ */ f("div", {
|
|
177
|
+
className: I ? "absolute left-20 right-36 top-2 flex justify-center" : `flex w-full justify-center ${F ? "max-w-[calc(100%-12rem)]" : "max-w-[calc(100%-8rem)]"}`,
|
|
178
|
+
children: /* @__PURE__ */ f("button", {
|
|
156
179
|
type: "button",
|
|
157
180
|
onClick: () => {
|
|
158
|
-
|
|
181
|
+
P("panel"), E.onOpen();
|
|
159
182
|
},
|
|
160
|
-
className: `max-w-full truncate rounded-full border border-border-default bg-bg-elevated font-medium text-text-primary transition-colors hover:bg-bg-raised focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong ${
|
|
183
|
+
className: `max-w-full truncate rounded-full border border-border-default bg-bg-elevated font-medium text-text-primary transition-colors hover:bg-bg-raised focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong ${I ? "h-8 px-3 text-xs" : "h-10 px-4 text-sm"}`,
|
|
161
184
|
"data-testid": "assistant-voice-proposal-chip",
|
|
162
|
-
children:
|
|
185
|
+
children: E.label
|
|
163
186
|
})
|
|
164
187
|
}) : null,
|
|
165
|
-
|
|
166
|
-
className: `absolute z-10 flex flex-col gap-2 overflow-y-auto rounded-lg border border-border-subtle bg-bg-elevated shadow-lg ${
|
|
188
|
+
D && B ? /* @__PURE__ */ p("div", {
|
|
189
|
+
className: `absolute z-10 flex flex-col gap-2 overflow-y-auto rounded-lg border border-border-subtle bg-bg-elevated shadow-lg ${F ? "inset-x-6 bottom-24 top-24 mx-auto max-w-xl p-4" : "inset-x-3 bottom-16 top-16 p-3"}`,
|
|
167
190
|
"data-testid": "assistant-voice-proposal-tray",
|
|
168
|
-
children: [/* @__PURE__ */
|
|
191
|
+
children: [/* @__PURE__ */ f("div", {
|
|
169
192
|
className: "flex justify-end",
|
|
170
|
-
children: /* @__PURE__ */
|
|
193
|
+
children: /* @__PURE__ */ f("button", {
|
|
171
194
|
type: "button",
|
|
172
|
-
onClick:
|
|
195
|
+
onClick: D.onClose,
|
|
173
196
|
className: "flex size-8 items-center justify-center rounded-full text-text-secondary transition-colors hover:bg-bg-raised hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong",
|
|
174
|
-
"aria-label":
|
|
197
|
+
"aria-label": D.closeLabel,
|
|
175
198
|
"data-testid": "assistant-voice-proposal-tray-close",
|
|
176
|
-
children: /* @__PURE__ */
|
|
199
|
+
children: /* @__PURE__ */ f(d, {
|
|
177
200
|
className: "size-4",
|
|
178
201
|
"aria-hidden": "true"
|
|
179
202
|
})
|
|
180
203
|
})
|
|
181
|
-
}),
|
|
204
|
+
}), D.content]
|
|
182
205
|
}) : null,
|
|
183
|
-
|
|
184
|
-
turns:
|
|
185
|
-
onClose: () =>
|
|
186
|
-
onSave:
|
|
187
|
-
onContinueInChat:
|
|
206
|
+
R ? /* @__PURE__ */ f(ue, {
|
|
207
|
+
turns: ye,
|
|
208
|
+
onClose: () => z(!1),
|
|
209
|
+
onSave: be,
|
|
210
|
+
onContinueInChat: xe
|
|
188
211
|
}) : null,
|
|
189
|
-
|
|
190
|
-
className: `absolute ${
|
|
191
|
-
children: /* @__PURE__ */
|
|
212
|
+
y ? /* @__PURE__ */ f("div", {
|
|
213
|
+
className: `absolute ${F ? "left-6 top-6" : I ? "left-11 top-2" : "left-3 top-3"}`,
|
|
214
|
+
children: /* @__PURE__ */ f(ae, {
|
|
192
215
|
onFiles: (e) => {
|
|
193
|
-
|
|
216
|
+
y(e), P((e) => e === "mini" ? "panel" : e);
|
|
194
217
|
},
|
|
195
|
-
onPickerOpen:
|
|
218
|
+
onPickerOpen: Ae,
|
|
196
219
|
direction: "down",
|
|
197
|
-
canAddMore:
|
|
220
|
+
canAddMore: Te
|
|
198
221
|
})
|
|
199
222
|
}) : null,
|
|
200
|
-
(
|
|
201
|
-
className: `absolute ${
|
|
223
|
+
(v.length > 0 || b > 0) && !I ? /* @__PURE__ */ f("div", {
|
|
224
|
+
className: `absolute ${F ? "bottom-24 left-24 right-24" : "bottom-16 left-16 right-16"}`,
|
|
202
225
|
"data-testid": "assistant-voice-attachments",
|
|
203
|
-
children: /* @__PURE__ */
|
|
204
|
-
attachments:
|
|
205
|
-
onRemove:
|
|
206
|
-
onRetry:
|
|
207
|
-
preparingCount:
|
|
226
|
+
children: /* @__PURE__ */ f(oe, {
|
|
227
|
+
attachments: v,
|
|
228
|
+
onRemove: Ce ?? (() => void 0),
|
|
229
|
+
onRetry: we ?? (() => void 0),
|
|
230
|
+
preparingCount: b
|
|
208
231
|
})
|
|
209
232
|
}) : null,
|
|
210
|
-
/* @__PURE__ */
|
|
233
|
+
/* @__PURE__ */ f("button", {
|
|
211
234
|
type: "button",
|
|
212
|
-
onClick: () =>
|
|
213
|
-
className: `absolute ${
|
|
214
|
-
"aria-pressed":
|
|
215
|
-
"aria-label":
|
|
235
|
+
onClick: () => z((e) => !e),
|
|
236
|
+
className: `absolute ${F ? "bottom-6 right-6 size-14" : I ? "right-2 top-2 size-8" : "bottom-3 right-3 size-11"} flex items-center justify-center rounded-full bg-bg-elevated text-text-secondary transition-colors hover:bg-bg-raised hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong`,
|
|
237
|
+
"aria-pressed": R,
|
|
238
|
+
"aria-label": O("voiceSession.transcriptTitle", "Voice transcript"),
|
|
216
239
|
"data-testid": "assistant-voice-transcript-toggle",
|
|
217
|
-
children: /* @__PURE__ */
|
|
240
|
+
children: /* @__PURE__ */ f(ge, { className: F ? "size-6" : I ? "size-4" : "size-5" })
|
|
218
241
|
}),
|
|
219
|
-
/* @__PURE__ */
|
|
242
|
+
/* @__PURE__ */ f("button", {
|
|
220
243
|
type: "button",
|
|
221
|
-
onClick: () =>
|
|
222
|
-
className: `absolute ${
|
|
223
|
-
"aria-label":
|
|
244
|
+
onClick: () => P(L),
|
|
245
|
+
className: `absolute ${F ? "bottom-6 left-6 size-14" : I ? "left-2 top-2 size-8" : "bottom-3 left-3 size-11"} flex items-center justify-center rounded-full bg-bg-elevated text-text-secondary transition-colors hover:bg-bg-raised hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong`,
|
|
246
|
+
"aria-label": L === "panel" ? O("voiceSession.expandPanel", "Show the conversation in the panel") : L === "full" ? O("voiceSession.expand", "Expand the conversation to full screen") : O("voiceSession.collapse", "Shrink to the compact controller"),
|
|
224
247
|
"data-testid": "assistant-voice-expand",
|
|
225
|
-
children:
|
|
248
|
+
children: F ? /* @__PURE__ */ f(he, { className: "size-5" }) : /* @__PURE__ */ f(me, { className: I ? "size-4" : "size-5" })
|
|
226
249
|
})
|
|
227
250
|
]
|
|
228
251
|
});
|
|
229
252
|
};
|
|
230
|
-
function
|
|
253
|
+
function _e(e, t) {
|
|
231
254
|
switch (e) {
|
|
232
255
|
case "network": return t("voiceSession.noticeNetwork", "Speech recognition lost its connection. Check your network — it will retry.");
|
|
233
256
|
case "not-capturing": return t("voiceSession.noticeNotCapturing", "The microphone did not start. Check that this site is allowed to use it, then try again.");
|
|
@@ -236,7 +259,7 @@ function de(e, t) {
|
|
|
236
259
|
default: return e;
|
|
237
260
|
}
|
|
238
261
|
}
|
|
239
|
-
function
|
|
262
|
+
function ve(e, t) {
|
|
240
263
|
switch (e) {
|
|
241
264
|
case "mic-denied": return t("voiceSession.micDenied", "Microphone access is blocked. Allow it in your browser settings to talk.");
|
|
242
265
|
case "no-speech-support": return t("voiceSession.noSpeechSupport", "This browser cannot listen. Try a different browser, or type instead.");
|
|
@@ -245,4 +268,4 @@ function fe(e, t) {
|
|
|
245
268
|
}
|
|
246
269
|
}
|
|
247
270
|
//#endregion
|
|
248
|
-
export {
|
|
271
|
+
export { m as AssistantVoiceSession };
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hands-free voice, steps H1 and H2 — the pure rules (BOFF hands-free slice).
|
|
3
|
+
*
|
|
4
|
+
* Everything here is data in, decision out: no DOM, no timers, no React, for
|
|
5
|
+
* the reason `voiceSession.ts` gives (this repo's unit runner has no browser).
|
|
6
|
+
* The hook (`useVoiceSession`) owns the clock and the recogniser; this file
|
|
7
|
+
* owns what the words and the preference MEAN.
|
|
8
|
+
*
|
|
9
|
+
* ★ H1 — the end-of-speech grace is a USER PREFERENCE (2 s default, 3 s, 5 s),
|
|
10
|
+
* and there is exactly ONE timing owner: `planSubmitTimer`. The old
|
|
11
|
+
* `SILENCE_SUBMIT_MS` constant is gone; the value the timer waits is the
|
|
12
|
+
* preference, resolved by `resolveVoiceGraceMs`. Nothing else in the package
|
|
13
|
+
* waits before submitting a spoken turn (`ENDPOINT_GRACE_MS` only decides when
|
|
14
|
+
* the stage SHOWS the pause, and is clamped inside the grace).
|
|
15
|
+
*
|
|
16
|
+
* ★ H2 — corrections while the assistant is still PREPARING an answer. The
|
|
17
|
+
* microphone stays open in `thinking`, so a recogniser can deliver three kinds
|
|
18
|
+
* of result there, and telling them apart is the whole difficulty:
|
|
19
|
+
* 1. a trailing result of the turn JUST submitted (Chrome finalises late;
|
|
20
|
+
* Chrome Android re-sends the whole utterance, sometimes revised) — must
|
|
21
|
+
* be ignored, or every spoken question is aborted and sent twice;
|
|
22
|
+
* 2. noise and fillers ("uh", "hmm") — must not abort a model turn;
|
|
23
|
+
* 3. a person speaking — a correction: the turn is superseded.
|
|
24
|
+
* `planThinkingSpeech` is that classification.
|
|
25
|
+
*
|
|
26
|
+
* A spoken "yes" never commits a business write. In `thinking` a bare
|
|
27
|
+
* affirmation is therefore NOT a correction at all: it neither aborts the turn
|
|
28
|
+
* nor withdraws anything (`classifyWriteReply` is the same classifier the 5a
|
|
29
|
+
* binder uses). The binder, and the card's button, stay the only way a change
|
|
30
|
+
* is confirmed.
|
|
31
|
+
*/
|
|
32
|
+
/** The choices offered in the voice settings, shortest first. */
|
|
33
|
+
export declare const VOICE_GRACE_CHOICES_MS: readonly [2000, 3000, 5000];
|
|
34
|
+
export type VoiceGraceMs = (typeof VOICE_GRACE_CHOICES_MS)[number];
|
|
35
|
+
/**
|
|
36
|
+
* How long the user must stop talking before the turn is submitted, until they
|
|
37
|
+
* choose otherwise.
|
|
38
|
+
*
|
|
39
|
+
* ★ 2000, not 1200: 1.2 s does not survive an ordinary pause. Once a turn is
|
|
40
|
+
* submitted the reducer discards the rest of the sentence, so cutting someone
|
|
41
|
+
* off costs the whole round trip AND makes them repeat themselves — waiting
|
|
42
|
+
* 800 ms longer costs only a moment of silence. The asymmetry is what settled
|
|
43
|
+
* the number, and it is why the longer choices exist for people who pause more.
|
|
44
|
+
*/
|
|
45
|
+
export declare const DEFAULT_VOICE_GRACE_MS: VoiceGraceMs;
|
|
46
|
+
/**
|
|
47
|
+
* Read a stored or passed value as one of the offered choices.
|
|
48
|
+
*
|
|
49
|
+
* Anything else — a stale number from an older build, a string, `null`, a value
|
|
50
|
+
* hand-edited into storage — is the default, never a nearby choice: a grace of
|
|
51
|
+
* 0 or 600000 ms read back from storage would either submit mid-word or never
|
|
52
|
+
* submit at all.
|
|
53
|
+
*/
|
|
54
|
+
export declare function resolveVoiceGraceMs(value: unknown): VoiceGraceMs;
|
|
55
|
+
/**
|
|
56
|
+
* The ONE decision about the submit timer.
|
|
57
|
+
*
|
|
58
|
+
* `arm` is true only for a listening, unmuted session with something worth
|
|
59
|
+
* sending, and NOT while the person asked to finish in their own time
|
|
60
|
+
* ("Let me finish", `holding`). `delayMs` is the preference. The hook re-asks
|
|
61
|
+
* on every change of the session, so new speech cancels a pending submit and
|
|
62
|
+
* the turn continues — there is no second timer to forget.
|
|
63
|
+
*/
|
|
64
|
+
export declare function planSubmitTimer(input: {
|
|
65
|
+
phase: string;
|
|
66
|
+
muted: boolean;
|
|
67
|
+
/** Everything heard this turn (`spokenSoFar`). */
|
|
68
|
+
spoken: string;
|
|
69
|
+
/** "Let me finish" is on: nothing is submitted until the person says done. */
|
|
70
|
+
holding: boolean;
|
|
71
|
+
/** The preference, in ms. */
|
|
72
|
+
graceMs: number;
|
|
73
|
+
}): {
|
|
74
|
+
arm: boolean;
|
|
75
|
+
delayMs: number;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* The comparable words of a transcript: letters, marks and digits only (marks
|
|
79
|
+
* kept — Tamil and Hindi vowel signs are marks), lower-cased. Punctuation and
|
|
80
|
+
* capitals a final adds are not speech.
|
|
81
|
+
*/
|
|
82
|
+
export declare function speechWords(text: string): string[];
|
|
83
|
+
/**
|
|
84
|
+
* Add a newly finalised phrase to the turn heard so far.
|
|
85
|
+
*
|
|
86
|
+
* ★ Chrome Android duplicates finals. With `continuous` on, a restarted
|
|
87
|
+
* recogniser can re-send the phrase it just finalised, and it often re-sends
|
|
88
|
+
* the WHOLE utterance so far with a few words added. Plain concatenation turned
|
|
89
|
+
* "when should I sow" into "when should I sow when should I sow ragi" and sent
|
|
90
|
+
* that. So:
|
|
91
|
+
* - a phrase that STARTS WITH everything heard is the same utterance, longer
|
|
92
|
+
* or equal: it replaces what was heard;
|
|
93
|
+
* - a phrase of two or more words that the turn already ENDS with is a
|
|
94
|
+
* repeat: dropped;
|
|
95
|
+
* - anything else is new speech: appended.
|
|
96
|
+
* A single repeated word is kept unless it is the whole turn — "no no" is
|
|
97
|
+
* emphasis, but a lone "hello" arriving twice is the recogniser.
|
|
98
|
+
*/
|
|
99
|
+
export declare function mergeFinalPhrase(pending: string, phrase: string): string;
|
|
100
|
+
/**
|
|
101
|
+
* A transcript without the words of the turn it follows, when it starts with
|
|
102
|
+
* them (a cumulative result: "when should I sow ragi" after "when should I
|
|
103
|
+
* sow"). Anything else is returned unchanged.
|
|
104
|
+
*/
|
|
105
|
+
export declare function stripSubmittedPrefix(transcript: string, submitted: string): string;
|
|
106
|
+
/**
|
|
107
|
+
* How long after a turn is submitted its OWN trailing results may still arrive.
|
|
108
|
+
*
|
|
109
|
+
* The person was silent for the whole grace (2 s at least), so anything
|
|
110
|
+
* arriving this soon after the submit and resembling what was sent is the
|
|
111
|
+
* recogniser finishing the sentence, not a correction. Past it, only an exact
|
|
112
|
+
* repeat is ignored — a person correcting "plant ragi in June" with "no plant
|
|
113
|
+
* ragi in July" is speaking, however alike the words are.
|
|
114
|
+
*/
|
|
115
|
+
export declare const TRAILING_RESULT_WINDOW_MS = 1500;
|
|
116
|
+
/**
|
|
117
|
+
* Is this transcript the recogniser finishing, repeating or revising the turn
|
|
118
|
+
* that was just submitted?
|
|
119
|
+
*
|
|
120
|
+
* `sinceSubmitMs` is null when unknown (no clock): then only an exact repeat
|
|
121
|
+
* counts, which can only ever err towards treating speech as speech.
|
|
122
|
+
*/
|
|
123
|
+
export declare function isTrailingResultOfSubmitted(transcript: string, submitted: string, sinceSubmitMs: number | null): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Is this a person speaking, rather than noise?
|
|
126
|
+
*
|
|
127
|
+
* Aborting a model turn costs the turn, so the bar is two letters or digits
|
|
128
|
+
* that are not all filler. "no" and "ok" pass; "a", "uh" and "hmm" do not. A
|
|
129
|
+
* single Han, kana or Hangul character passes — "不" is a whole word.
|
|
130
|
+
*/
|
|
131
|
+
export declare function isGenuineUserSpeech(text: string): boolean;
|
|
132
|
+
/** What a result heard while the answer is being prepared amounts to. */
|
|
133
|
+
export type ThinkingSpeechPlan = {
|
|
134
|
+
kind: "ignore";
|
|
135
|
+
reason: "empty" | "trailing" | "noise" | "affirmation";
|
|
136
|
+
} | {
|
|
137
|
+
kind: "supersede";
|
|
138
|
+
/** What the person said, without the words of the turn it corrects. */
|
|
139
|
+
text: string;
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Classify a result that arrives while the assistant is PREPARING an answer.
|
|
143
|
+
*
|
|
144
|
+
* Ignored: nothing; the recogniser finishing, repeating or revising the turn
|
|
145
|
+
* just submitted; noise; and a bare affirmation (a spoken "yes" is never a
|
|
146
|
+
* correction, and never commits a write — see the header). Everything else is
|
|
147
|
+
* a correction.
|
|
148
|
+
*
|
|
149
|
+
* Echo is not checked here: nothing plays during `thinking`. The caller still
|
|
150
|
+
* passes the previous reply through `isEcho` first, because its tail can sound
|
|
151
|
+
* for a moment after playback ends.
|
|
152
|
+
*/
|
|
153
|
+
export declare function planThinkingSpeech(input: {
|
|
154
|
+
transcript: string;
|
|
155
|
+
/** The turn in flight, as it was sent. */
|
|
156
|
+
submitted: string;
|
|
157
|
+
/** Milliseconds since it was sent, or null when no clock was given. */
|
|
158
|
+
sinceSubmitMs: number | null;
|
|
159
|
+
}): ThinkingSpeechPlan;
|
|
160
|
+
//# sourceMappingURL=handsFree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handsFree.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/voice/handsFree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAQH,iEAAiE;AACjE,eAAO,MAAM,sBAAsB,6BAA8B,CAAC;AAElE,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnE;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,EAAE,YAAmB,CAAC;AAEzD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,CAEhE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,OAAO,EAAE,OAAO,CAAC;IACjB,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;CACjB,GAAG;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAIpC;AAMD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAMlD;AA6BD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAQxE;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAelF;AAMD;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,OAAO,CAAC;AAK9C;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GAAG,IAAI,GAC3B,OAAO,CAYT;AAyBD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOzD;AAED,yEAAyE;AACzE,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,OAAO,GAAG,UAAU,GAAG,OAAO,GAAG,aAAa,CAAA;CAAE,GAC1E;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEN;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B,GAAG,kBAAkB,CASrB"}
|