@burdenoff/fe-libs 2026.1014.3 → 2026.1014.5

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.
@@ -3,282 +3,288 @@ import { useAssistantControl as t } from "../../appControls/useAssistantControl.
3
3
  import { useAssistantTr as n } from "../../i18n.js";
4
4
  import { micIsInterrupt as r, showsAssistantCaption as ee, voiceStageState as i } from "../../voice/voiceStageState.js";
5
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 { AssistantAttachmentButton as re } from "../composer/AssistantAttachmentButton.js";
8
- import { AssistantAttachmentChips as ie } from "../composer/AssistantAttachmentChips.js";
6
+ import { spokenSoFar as re } from "../../voice/voiceSession.js";
7
+ import { useAvatarCopy as ie } from "../../avatar/useAvatarCopy.js";
9
8
  import { ASSISTANT_PANEL_ATTR as ae, ASSISTANT_VOICE_SESSION_ATTR as oe } from "../panelOverlays.js";
10
- import { AssistantVoiceOrb as se } from "./AssistantVoiceOrb.js";
11
- import { useLiveAvatarVoiceView as ce } from "../assistantLiveAvatarSeam.js";
12
- import { VoiceMiniController as le } from "./VoiceMiniController.js";
13
- import { VoiceStage as ue } from "./VoiceStage.js";
14
- import { VoiceTranscriptDrawer as de } from "./VoiceTranscriptDrawer.js";
15
- import { escapeBelongsToLayerAbove as fe, voiceSessionEscapeAction as pe } from "./voiceSessionEscape.js";
16
- import { HandsFreePrivacyNotice as me } from "./HandsFreePrivacyNotice.js";
17
- import { useCallback as s, useEffect as c, useMemo as he, useRef as l, useState as u } from "react";
18
- import { Maximize2 as ge, Minimize2 as _e, ScrollText as ve, X as d } from "lucide-react";
19
- import { jsx as f, jsxs as p } from "react/jsx-runtime";
9
+ import { useLiveAvatarHandsFreeGuard as se, useLiveAvatarVoiceView as ce } from "../assistantLiveAvatarSeam.js";
10
+ import { AssistantAttachmentButton as le } from "../composer/AssistantAttachmentButton.js";
11
+ import { AssistantAttachmentChips as ue } from "../composer/AssistantAttachmentChips.js";
12
+ import { AssistantVoiceOrb as de } from "./AssistantVoiceOrb.js";
13
+ import { VoiceMiniController as fe } from "./VoiceMiniController.js";
14
+ import { VoiceStage as pe } from "./VoiceStage.js";
15
+ import { VoiceTranscriptDrawer as me } from "./VoiceTranscriptDrawer.js";
16
+ import { escapeBelongsToLayerAbove as he, voiceSessionEscapeAction as ge } from "./voiceSessionEscape.js";
17
+ import { HandsFreePrivacyNotice as _e } from "./HandsFreePrivacyNotice.js";
18
+ import { useCallback as o, useEffect as s, useMemo as ve, useRef as c, useState as l } from "react";
19
+ import { Maximize2 as ye, Minimize2 as be, ScrollText as xe, X as u } from "lucide-react";
20
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
20
21
  //#region src/shared/assistant/ui/voice/AssistantVoiceSession.tsx
21
- var m = ({ session: m, turns: be = [], onSaveTranscript: xe, onContinueInChat: Se, notice: g = null, privacyNotice: _ = null, spoken: v, onInterrupt: Ce, onToggleMute: y, attachments: b = [], onAttachFiles: x, onRemoveAttachment: we, onRetryAttachment: Te, canAttachMore: Ee = !0, preparingAttachments: S = 0, attachmentsLocked: C = !1, attachmentNotice: w = null, spokenChunks: T = null, onEnd: E, capturing: De = !0, interrupting: Oe = !1, awaitingEndpoint: ke = !1, holding: D = !1, correcting: Ae = !1, onLetMeFinish: O, onImDone: k, proposalChip: A = null, proposalTray: j = null, renderAfterTurn: je }) => {
22
- let M = n(), { muted: N, error: P } = m, F = l(null), I = l(null), [Me, L] = u("mini"), R = ce(Me, m.phase === "ended"), z = R === "full", B = R === "mini", V = R === "mini" ? "panel" : R === "panel" ? "full" : "mini", [H, U] = u(!1);
23
- t("assistant.transcript", he(() => ({ run: () => H ? { status: "already" } : (U(!0), { status: "done" }) }), [H]));
24
- let W = j !== null && !B, G = l(!1), K = l(y);
25
- K.current = y;
26
- let q = s(() => {
27
- m.phase !== "listening" && m.phase !== "thinking" || N || G.current || o(m) || (G.current = !0, K.current());
28
- }, [N, m]), J = s(() => {
29
- G.current && (G.current = !1, K.current());
30
- }, []), Ne = q;
31
- c(() => {
22
+ var p = ({ session: p, turns: we = [], onSaveTranscript: Te, onContinueInChat: Ee, notice: m = null, privacyNotice: h = null, spoken: g, onInterrupt: De, onToggleMute: _, attachments: v = [], onAttachFiles: y, onRemoveAttachment: Oe, onRetryAttachment: ke, canAttachMore: Ae = !0, preparingAttachments: b = 0, attachmentsLocked: x = !1, attachmentNotice: S = null, spokenChunks: C = null, onEnd: w, capturing: je = !0, interrupting: Me = !1, awaitingEndpoint: Ne = !1, holding: T = !1, correcting: Pe = !1, onLetMeFinish: E, onImDone: D, proposalChip: O = null, proposalTray: k = null, renderAfterTurn: Fe }) => {
23
+ let A = n(), { muted: j, error: M } = p, N = c(null), P = c(null), [Ie, F] = l("mini"), I = ce(Ie, p.phase === "ended"), Le = se(), L = ie(), R = I === "full", z = I === "mini", B = I === "mini" ? "panel" : I === "panel" ? "full" : "mini", [V, H] = l(!1);
24
+ t("assistant.transcript", ve(() => ({ run: () => V ? { status: "already" } : (H(!0), { status: "done" }) }), [V]));
25
+ let U = k !== null && !z, W = c(!1), G = c(_);
26
+ G.current = _;
27
+ let K = o(() => {
28
+ p.phase !== "listening" && p.phase !== "thinking" || j || W.current || re(p) || (W.current = !0, G.current());
29
+ }, [j, p]), q = o(() => {
30
+ W.current && (W.current = !1, G.current());
31
+ }, []), Re = K;
32
+ s(() => {
32
33
  let e = () => {
33
- document.visibilityState === "hidden" ? q() : J();
34
+ document.visibilityState === "hidden" ? K() : q();
34
35
  };
35
36
  return document.addEventListener("visibilitychange", e), () => document.removeEventListener("visibilitychange", e);
36
- }, [q, J]), c(() => {
37
- let e = J;
37
+ }, [K, q]), s(() => {
38
+ let e = q;
38
39
  return window.addEventListener("focus", e), () => {
39
- window.removeEventListener("focus", e), G.current = !1;
40
+ window.removeEventListener("focus", e), W.current = !1;
40
41
  };
41
- }, []), c(() => {
42
- document.activeElement?.closest("[data-hands-free-notice]") || F.current?.focus();
43
- }, []), e(I, { fallbackSelector: `[${ae}]` }), c(() => {
42
+ }, []), s(() => {
43
+ document.activeElement?.closest("[data-hands-free-notice]") || N.current?.focus();
44
+ }, []), e(P, { fallbackSelector: `[${ae}]` }), s(() => {
44
45
  let e = (e) => {
45
46
  if (e.key === "Escape") {
46
- let t = pe({
47
+ let t = ge({
47
48
  defaultPrevented: e.defaultPrevented,
48
- layerAbove: fe({
49
+ layerAbove: he({
49
50
  target: e.target,
50
- session: I.current,
51
+ session: P.current,
51
52
  doc: document
52
53
  }),
53
- transcriptOpen: H
54
+ transcriptOpen: V
54
55
  });
55
56
  if (t === "ignore") return;
56
- e.preventDefault(), t === "close-transcript" ? U(!1) : _ ? _.decline() : W ? j?.onClose() : E();
57
+ e.preventDefault(), t === "close-transcript" ? H(!1) : h ? h.decline() : U ? k?.onClose() : w();
57
58
  return;
58
59
  }
59
- if (e.key !== "Tab" || !z) return;
60
- let t = (H ? I.current?.querySelector("[data-testid=\"assistant-voice-transcript\"]") : I.current)?.querySelectorAll("button:not([disabled])");
60
+ if (e.key !== "Tab" || !R) return;
61
+ let t = (V ? P.current?.querySelector("[data-testid=\"assistant-voice-transcript\"]") : P.current)?.querySelectorAll("button:not([disabled])");
61
62
  if (!t || t.length === 0) return;
62
63
  let n = t[0], r = t[t.length - 1];
63
64
  !n || !r || (e.shiftKey && document.activeElement === n ? (e.preventDefault(), r.focus()) : !e.shiftKey && document.activeElement === r && (e.preventDefault(), n.focus()));
64
65
  };
65
66
  return window.addEventListener("keydown", e), () => window.removeEventListener("keydown", e);
66
67
  }, [
67
- E,
68
- z,
69
- H,
70
- W,
71
- j,
72
- _
68
+ w,
69
+ R,
70
+ V,
71
+ U,
72
+ k,
73
+ h
73
74
  ]);
74
- let Y = g !== null && P === null, X = o(m), Z = O && k && m.phase === "listening" && !N && P === null ? {
75
- letMeFinish: O,
76
- imDone: k
77
- } : null, Pe = Z !== null;
78
- c(() => {
79
- if (Pe) return;
75
+ let J = m !== null && M === null, Y = Le && m === null && M === null, ze = re(p), X = E && D && p.phase === "listening" && !j && M === null ? {
76
+ letMeFinish: E,
77
+ imDone: D
78
+ } : null, Be = X !== null;
79
+ s(() => {
80
+ if (Be) return;
80
81
  let e = document.activeElement;
81
- (!e || e === document.body) && F.current?.focus();
82
- }, [Pe]);
83
- let Q = i({
84
- snapshot: m,
85
- capturing: De,
86
- interrupting: Oe,
87
- awaitingEndpoint: ke
88
- }), Fe = (() => {
89
- switch (Q) {
90
- case "connecting": return M("voiceSession.connecting", "Starting the microphone…");
91
- case "endpoint-grace": return M("voiceSession.endpointGrace", "Still listening — take your time");
92
- case "interrupting": return M("voiceSession.interrupting", "Stopped — go ahead");
93
- case "thinking": return M(a.key, a.fallback);
94
- case "speaking": return M("voiceSession.speaking", "Speaking — tap to stop");
82
+ (!e || e === document.body) && N.current?.focus();
83
+ }, [Be]);
84
+ let Z = i({
85
+ snapshot: p,
86
+ capturing: je,
87
+ interrupting: Me,
88
+ awaitingEndpoint: Ne
89
+ }), Ve = (() => {
90
+ switch (Z) {
91
+ case "connecting": return A("voiceSession.connecting", "Starting the microphone…");
92
+ case "endpoint-grace": return A("voiceSession.endpointGrace", "Still listening — take your time");
93
+ case "interrupting": return A("voiceSession.interrupting", "Stopped — go ahead");
94
+ case "thinking": return A(a.key, a.fallback);
95
+ case "speaking": return A("voiceSession.speaking", "Speaking — tap to stop");
95
96
  case "mic-error":
96
97
  case "ended": return "";
97
- case "listening": return N ? M("voiceSession.muted", "Microphone off") : M("voiceSession.listening", "Listening…");
98
- default: return Q;
98
+ case "listening": return j ? A("voiceSession.muted", "Microphone off") : A("voiceSession.listening", "Listening…");
99
+ default: return Z;
99
100
  }
100
- })(), Ie = !N && (Q === "listening" || Q === "endpoint-grace"), Le = Ie && D ? M("voiceSession.holding", "Take your time — tap “I’m done” when you finish") : Ie && Ae ? M("voiceSession.correcting", "Stopped that answer — listening to your correction") : Fe, $ = ne({
101
- tr: M,
102
- stage: Q,
103
- muted: N,
104
- label: Le
105
- }), Re = te(Le, $), ze = Q === "thinking";
106
- return /* @__PURE__ */ p("div", {
107
- ref: I,
108
- className: `flex flex-col items-center justify-between bg-bg-sunken ${R === "full" ? "fixed inset-x-0 bottom-0 top-14 z-[60] px-6 py-8" : R === "panel" ? "absolute inset-0 z-20 px-4 py-6" : "absolute inset-x-0 bottom-0 z-20 min-h-[11.25rem] border-t border-border-subtle px-3 py-3 shadow-lg"}`,
101
+ })(), He = !j && (Z === "listening" || Z === "endpoint-grace"), Ue = He && T ? A("voiceSession.holding", "Take your time — tap “I’m done” when you finish") : He && Pe ? A("voiceSession.correcting", "Stopped that answer — listening to your correction") : Ve, Q = ne({
102
+ tr: A,
103
+ stage: Z,
104
+ muted: j,
105
+ label: Ue
106
+ }), We = te(Ue, Q), $ = Z === "thinking";
107
+ return /* @__PURE__ */ f("div", {
108
+ ref: P,
109
+ className: `flex flex-col items-center justify-between bg-bg-sunken ${I === "full" ? "fixed inset-x-0 bottom-0 top-14 z-[60] px-6 py-8" : I === "panel" ? "absolute inset-0 z-20 px-4 py-6" : "absolute inset-x-0 bottom-0 z-20 min-h-[11.25rem] border-t border-border-subtle px-3 py-3 shadow-lg"}`,
109
110
  role: "dialog",
110
- "aria-modal": z || void 0,
111
- "aria-label": M("voiceSession.title", "Voice conversation"),
111
+ "aria-modal": R || void 0,
112
+ "aria-label": A("voiceSession.title", "Voice conversation"),
112
113
  "data-testid": "assistant-voice-session",
113
114
  [oe]: "",
114
115
  children: [
115
- /* @__PURE__ */ p("button", {
116
- ref: F,
116
+ /* @__PURE__ */ f("button", {
117
+ ref: N,
117
118
  type: "button",
118
- onClick: E,
119
- className: `absolute ${z ? "right-6 top-6 h-14 gap-2 px-5 text-base" : B ? "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`,
120
- title: M("voiceSession.end", "End the voice conversation"),
119
+ onClick: w,
120
+ className: `absolute ${R ? "right-6 top-6 h-14 gap-2 px-5 text-base" : z ? "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`,
121
+ title: A("voiceSession.end", "End the voice conversation"),
121
122
  "data-testid": "assistant-voice-end",
122
- children: [/* @__PURE__ */ f(d, {
123
- className: z ? "size-6" : B ? "size-4" : "size-5",
123
+ children: [/* @__PURE__ */ d(u, {
124
+ className: R ? "size-6" : z ? "size-4" : "size-5",
124
125
  "aria-hidden": "true"
125
- }), /* @__PURE__ */ f("span", {
126
- className: `truncate whitespace-nowrap font-medium ${B ? "max-w-[3.5rem] text-xs" : "max-w-[7rem]"}`,
127
- children: M("voiceSession.endShort", "End")
126
+ }), /* @__PURE__ */ d("span", {
127
+ className: `truncate whitespace-nowrap font-medium ${z ? "max-w-[3.5rem] text-xs" : "max-w-[7rem]"}`,
128
+ children: A("voiceSession.endShort", "End")
128
129
  })]
129
130
  }),
130
- /* @__PURE__ */ p("div", {
131
- className: `flex flex-col items-center ${B ? `px-3 ${Y || w ? "pt-9 pb-2" : ""}` : `min-h-[1.5rem] ${Y || w ? z ? "pt-14" : "pt-10" : ""}`}`,
131
+ /* @__PURE__ */ f("div", {
132
+ className: `flex flex-col items-center ${z ? `px-3 ${J || Y || S ? "pt-9 pb-2" : ""}` : `min-h-[1.5rem] ${J || Y || S ? R ? "pt-14" : "pt-10" : ""}`}`,
132
133
  children: [
133
- Y ? /* @__PURE__ */ f("p", {
134
+ J ? /* @__PURE__ */ d("p", {
134
135
  className: "max-w-xs text-center text-xs text-status-warning",
135
136
  "data-testid": "assistant-voice-notice",
136
- children: h(g, M)
137
+ children: Se(m, A)
138
+ }) : null,
139
+ Y ? /* @__PURE__ */ d("p", {
140
+ className: "max-w-xs text-center text-xs text-text-secondary",
141
+ "data-testid": "assistant-voice-avatar-hands-free",
142
+ children: L.handsFreeOff
137
143
  }) : null,
138
- /* @__PURE__ */ f("span", {
144
+ /* @__PURE__ */ d("span", {
139
145
  className: "sr-only start-0 top-0",
140
146
  role: "status",
141
147
  "aria-live": "polite",
142
148
  "aria-atomic": "true",
143
149
  "data-testid": "assistant-voice-notice-announced",
144
- children: Y && g === "reply-not-heard" ? h(g, M) : null
150
+ children: J && m === "reply-not-heard" ? Se(m, A) : Y ? L.handsFreeOff : null
145
151
  }),
146
- w ? /* @__PURE__ */ f("p", {
152
+ S ? /* @__PURE__ */ d("p", {
147
153
  className: "max-w-xs text-center text-xs text-status-warning",
148
154
  role: "status",
149
155
  "aria-live": "polite",
150
156
  "data-testid": "assistant-voice-attachment-notice",
151
- children: w
157
+ children: S
152
158
  }) : null
153
159
  ]
154
160
  }),
155
161
  (() => {
156
- let e = /* @__PURE__ */ f(se, {
157
- session: m,
158
- compact: B,
159
- connecting: Q === "connecting",
160
- onPress: r(Q) ? Ce : y,
161
- label: r(Q) ? M("voiceSession.interrupt", "Stop the assistant and speak") : N ? M("voiceSession.unmute", "Turn the microphone on") : M("voiceSession.mute", "Turn the microphone off")
162
- }), t = Z ? /* @__PURE__ */ f("button", {
162
+ let e = /* @__PURE__ */ d(de, {
163
+ session: p,
164
+ compact: z,
165
+ connecting: Z === "connecting",
166
+ onPress: r(Z) ? De : _,
167
+ label: r(Z) ? A("voiceSession.interrupt", "Stop the assistant and speak") : j ? A("voiceSession.unmute", "Turn the microphone on") : A("voiceSession.mute", "Turn the microphone off")
168
+ }), t = X ? /* @__PURE__ */ d("button", {
163
169
  type: "button",
164
- onClick: D ? Z.imDone : Z.letMeFinish,
165
- 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 ${B ? "h-7 px-3 text-xs" : z ? "h-11 px-6 text-base" : "h-9 px-4 text-sm"} ${D ? "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"}`,
166
- title: D ? M("voiceSession.imDoneHint", "Send what you said now") : M("voiceSession.letMeFinishHint", "Pause sending until you tap “I’m done”"),
170
+ onClick: T ? X.imDone : X.letMeFinish,
171
+ 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 ${z ? "h-7 px-3 text-xs" : R ? "h-11 px-6 text-base" : "h-9 px-4 text-sm"} ${T ? "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"}`,
172
+ title: T ? A("voiceSession.imDoneHint", "Send what you said now") : A("voiceSession.letMeFinishHint", "Pause sending until you tap “I’m done”"),
167
173
  "data-testid": "assistant-voice-hold",
168
- "data-holding": D ? "true" : "false",
169
- children: D ? M("voiceSession.imDone", "I’m done") : M("voiceSession.letMeFinish", "Let me finish")
170
- }) : null, n = t ? /* @__PURE__ */ p("div", {
174
+ "data-holding": T ? "true" : "false",
175
+ children: T ? A("voiceSession.imDone", "I’m done") : A("voiceSession.letMeFinish", "Let me finish")
176
+ }) : null, n = t ? /* @__PURE__ */ f("div", {
171
177
  className: "flex flex-col items-center gap-2",
172
178
  children: [e, t]
173
- }) : e, i = ee(Q) ? v : X || null, a = P === null ? null : ye(P, M);
174
- return B ? /* @__PURE__ */ f(le, {
175
- spokenChunks: T,
176
- state: Q,
179
+ }) : e, i = ee(Z) ? g : ze || null, a = M === null ? null : Ce(M, A);
180
+ return z ? /* @__PURE__ */ d(fe, {
181
+ spokenChunks: C,
182
+ state: Z,
177
183
  caption: i,
178
- statusText: Re,
179
- statusSuffix: $,
180
- rotateStatus: ze,
184
+ statusText: We,
185
+ statusSuffix: Q,
186
+ rotateStatus: $,
181
187
  errorText: a,
182
188
  control: n
183
- }) : /* @__PURE__ */ f(ue, {
184
- state: Q,
185
- userCaption: X || null,
186
- spokenChunks: T,
187
- assistantCaption: v,
188
- expanded: z,
189
- statusText: Re,
190
- statusSuffix: $,
191
- rotateStatus: ze,
189
+ }) : /* @__PURE__ */ d(pe, {
190
+ state: Z,
191
+ userCaption: ze || null,
192
+ spokenChunks: C,
193
+ assistantCaption: g,
194
+ expanded: R,
195
+ statusText: We,
196
+ statusSuffix: Q,
197
+ rotateStatus: $,
192
198
  errorText: a,
193
199
  control: n
194
200
  });
195
201
  })(),
196
- A && !W ? /* @__PURE__ */ f("div", {
197
- className: B ? "absolute left-20 right-36 top-2 flex justify-center" : `flex w-full justify-center ${z ? "max-w-[calc(100%-12rem)]" : "max-w-[calc(100%-8rem)]"}`,
198
- children: /* @__PURE__ */ f("button", {
202
+ O && !U ? /* @__PURE__ */ d("div", {
203
+ className: z ? "absolute left-20 right-36 top-2 flex justify-center" : `flex w-full justify-center ${R ? "max-w-[calc(100%-12rem)]" : "max-w-[calc(100%-8rem)]"}`,
204
+ children: /* @__PURE__ */ d("button", {
199
205
  type: "button",
200
206
  onClick: () => {
201
- L("panel"), A.onOpen();
207
+ F("panel"), O.onOpen();
202
208
  },
203
- 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 ${B ? "h-8 px-3 text-xs" : "h-10 px-4 text-sm"}`,
209
+ 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 ${z ? "h-8 px-3 text-xs" : "h-10 px-4 text-sm"}`,
204
210
  "data-testid": "assistant-voice-proposal-chip",
205
- children: A.label
211
+ children: O.label
206
212
  })
207
213
  }) : null,
208
- j && W ? /* @__PURE__ */ p("div", {
209
- className: `absolute z-10 flex flex-col gap-2 overflow-y-auto rounded-lg border border-border-subtle bg-bg-elevated shadow-lg ${z ? "inset-x-6 bottom-24 top-24 mx-auto max-w-xl p-4" : "inset-x-3 bottom-16 top-16 p-3"}`,
214
+ k && U ? /* @__PURE__ */ f("div", {
215
+ className: `absolute z-10 flex flex-col gap-2 overflow-y-auto rounded-lg border border-border-subtle bg-bg-elevated shadow-lg ${R ? "inset-x-6 bottom-24 top-24 mx-auto max-w-xl p-4" : "inset-x-3 bottom-16 top-16 p-3"}`,
210
216
  "data-testid": "assistant-voice-proposal-tray",
211
- children: [/* @__PURE__ */ f("div", {
217
+ children: [/* @__PURE__ */ d("div", {
212
218
  className: "flex justify-end",
213
- children: /* @__PURE__ */ f("button", {
219
+ children: /* @__PURE__ */ d("button", {
214
220
  type: "button",
215
- onClick: j.onClose,
221
+ onClick: k.onClose,
216
222
  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",
217
- "aria-label": j.closeLabel,
223
+ "aria-label": k.closeLabel,
218
224
  "data-testid": "assistant-voice-proposal-tray-close",
219
- children: /* @__PURE__ */ f(d, {
225
+ children: /* @__PURE__ */ d(u, {
220
226
  className: "size-4",
221
227
  "aria-hidden": "true"
222
228
  })
223
229
  })
224
- }), j.content]
230
+ }), k.content]
225
231
  }) : null,
226
- _ ? /* @__PURE__ */ f(me, {
227
- view: R,
228
- onContinue: _.accept,
229
- onNotNow: _.decline
232
+ h ? /* @__PURE__ */ d(_e, {
233
+ view: I,
234
+ onContinue: h.accept,
235
+ onNotNow: h.decline
230
236
  }) : null,
231
- H ? /* @__PURE__ */ f(de, {
232
- turns: be,
233
- onClose: () => U(!1),
234
- onSave: xe,
235
- onContinueInChat: Se,
236
- renderAfterTurn: je
237
+ V ? /* @__PURE__ */ d(me, {
238
+ turns: we,
239
+ onClose: () => H(!1),
240
+ onSave: Te,
241
+ onContinueInChat: Ee,
242
+ renderAfterTurn: Fe
237
243
  }) : null,
238
- x ? /* @__PURE__ */ f("div", {
239
- className: `absolute ${z ? "left-6 top-6" : B ? "left-11 top-2" : "left-3 top-3"}`,
240
- children: /* @__PURE__ */ f(re, {
244
+ y ? /* @__PURE__ */ d("div", {
245
+ className: `absolute ${R ? "left-6 top-6" : z ? "left-11 top-2" : "left-3 top-3"}`,
246
+ children: /* @__PURE__ */ d(le, {
241
247
  onFiles: (e) => {
242
- x(e), L((e) => e === "mini" ? "panel" : e);
248
+ y(e), F((e) => e === "mini" ? "panel" : e);
243
249
  },
244
- onPickerOpen: Ne,
250
+ onPickerOpen: Re,
245
251
  direction: "down",
246
- canAddMore: Ee,
247
- disabled: C
252
+ canAddMore: Ae,
253
+ disabled: x
248
254
  })
249
255
  }) : null,
250
- (b.length > 0 || S > 0) && !B ? /* @__PURE__ */ f("div", {
251
- className: `absolute ${z ? "bottom-24 left-24 right-24" : "bottom-16 left-16 right-16"}`,
256
+ (v.length > 0 || b > 0) && !z ? /* @__PURE__ */ d("div", {
257
+ className: `absolute ${R ? "bottom-24 left-24 right-24" : "bottom-16 left-16 right-16"}`,
252
258
  "data-testid": "assistant-voice-attachments",
253
- children: /* @__PURE__ */ f(ie, {
254
- attachments: b,
255
- onRemove: we ?? (() => void 0),
256
- onRetry: Te ?? (() => void 0),
257
- preparingCount: S,
258
- disabled: C
259
+ children: /* @__PURE__ */ d(ue, {
260
+ attachments: v,
261
+ onRemove: Oe ?? (() => void 0),
262
+ onRetry: ke ?? (() => void 0),
263
+ preparingCount: b,
264
+ disabled: x
259
265
  })
260
266
  }) : null,
261
- /* @__PURE__ */ f("button", {
267
+ /* @__PURE__ */ d("button", {
262
268
  type: "button",
263
- onClick: () => U((e) => !e),
264
- className: `absolute ${z ? "bottom-6 right-6 size-14" : B ? "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`,
265
- "aria-pressed": H,
266
- "aria-label": M("voiceSession.transcriptTitle", "Voice transcript"),
269
+ onClick: () => H((e) => !e),
270
+ className: `absolute ${R ? "bottom-6 right-6 size-14" : z ? "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`,
271
+ "aria-pressed": V,
272
+ "aria-label": A("voiceSession.transcriptTitle", "Voice transcript"),
267
273
  "data-testid": "assistant-voice-transcript-toggle",
268
- children: /* @__PURE__ */ f(ve, { className: z ? "size-6" : B ? "size-4" : "size-5" })
274
+ children: /* @__PURE__ */ d(xe, { className: R ? "size-6" : z ? "size-4" : "size-5" })
269
275
  }),
270
- /* @__PURE__ */ f("button", {
276
+ /* @__PURE__ */ d("button", {
271
277
  type: "button",
272
- onClick: () => L(V),
273
- className: `absolute ${z ? "bottom-6 left-6 size-14" : B ? "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`,
274
- "aria-label": V === "panel" ? M("voiceSession.expandPanel", "Show the conversation in the panel") : V === "full" ? M("voiceSession.expand", "Expand the conversation to full screen") : M("voiceSession.collapse", "Shrink to the compact controller"),
278
+ onClick: () => F(B),
279
+ className: `absolute ${R ? "bottom-6 left-6 size-14" : z ? "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`,
280
+ "aria-label": B === "panel" ? A("voiceSession.expandPanel", "Show the conversation in the panel") : B === "full" ? A("voiceSession.expand", "Expand the conversation to full screen") : A("voiceSession.collapse", "Shrink to the compact controller"),
275
281
  "data-testid": "assistant-voice-expand",
276
- children: z ? /* @__PURE__ */ f(_e, { className: "size-5" }) : /* @__PURE__ */ f(ge, { className: B ? "size-4" : "size-5" })
282
+ children: R ? /* @__PURE__ */ d(be, { className: "size-5" }) : /* @__PURE__ */ d(ye, { className: z ? "size-4" : "size-5" })
277
283
  })
278
284
  ]
279
285
  });
280
286
  };
281
- function h(e, t) {
287
+ function Se(e, t) {
282
288
  switch (e) {
283
289
  case "network": return t("voiceSession.noticeNetwork", "Speech recognition lost its connection. Check your network — it will retry.");
284
290
  case "not-capturing": return t("voiceSession.noticeNotCapturing", "The microphone did not start. Check that this site is allowed to use it, then try again.");
@@ -290,7 +296,7 @@ function h(e, t) {
290
296
  default: return e;
291
297
  }
292
298
  }
293
- function ye(e, t) {
299
+ function Ce(e, t) {
294
300
  switch (e) {
295
301
  case "mic-denied": return t("voiceSession.micDenied", "Microphone access is blocked. Allow it in your browser settings to talk.");
296
302
  case "no-speech-support": return t("voiceSession.noSpeechSupport", "This browser cannot listen. Try a different browser, or type instead.");
@@ -299,4 +305,4 @@ function ye(e, t) {
299
305
  }
300
306
  }
301
307
  //#endregion
302
- export { m as AssistantVoiceSession };
308
+ export { p as AssistantVoiceSession };
@@ -1,9 +1,9 @@
1
1
  import { showsAssistantCaption as e, waveformIsActive as t, waveformIsSettled as n } from "../../voice/voiceStageState.js";
2
2
  import { showPreviousChunk as r } from "../../voice/miniCaptionBudget.js";
3
3
  import { isAwaitingFirstChunk as i } from "../../voice/speechPlayback.js";
4
- import { VoiceWaveform as a } from "./VoiceWaveform.js";
5
- import { VoiceStatusText as o } from "./VoiceStatusText.js";
6
- import { LiveAvatarMiniIndicator as s, useLiveAvatarMiniIndicatorShown as c } from "../assistantLiveAvatarSeam.js";
4
+ import { LiveAvatarMiniIndicator as a, useLiveAvatarMiniIndicatorShown as o } from "../assistantLiveAvatarSeam.js";
5
+ import { VoiceWaveform as s } from "./VoiceWaveform.js";
6
+ import { VoiceStatusText as c } from "./VoiceStatusText.js";
7
7
  import { Fragment as l, jsx as u, jsxs as d } from "react/jsx-runtime";
8
8
  //#region src/shared/assistant/ui/voice/VoiceMiniController.tsx
9
9
  var f = " self-stretch justify-end pb-8.5 [container-type:size] [@container_(min-height:4.0312rem)_and_(max-height:5.2343rem)]:[&>p[role=status]]:line-clamp-2 [@container_(max-height:4.0312rem)]:[&>p[role=status]]:line-clamp-1 [@container_(max-height:4.0312rem)]:[&>p[role=status]]:min-h-5 [@container_(max-height:5.2343rem)]:[&>p[role=status]>span:not(:last-child)]:sr-only", p = ({ state: p, caption: m, spokenChunks: h = null, statusText: g, statusSuffix: _, rotateStatus: v, control: y, errorText: b = null }) => {
@@ -14,14 +14,14 @@ var f = " self-stretch justify-end pb-8.5 [container-type:size] [@container_(min
14
14
  "data-state": p,
15
15
  children: [
16
16
  /* @__PURE__ */ d("div", {
17
- className: `flex min-w-0 flex-1 flex-col gap-1.5${c() ? f : ""}`,
17
+ className: `flex min-w-0 flex-1 flex-col gap-1.5${o() ? f : ""}`,
18
18
  children: [/* @__PURE__ */ d("div", {
19
19
  className: "flex items-center gap-2",
20
- children: [/* @__PURE__ */ u(a, {
20
+ children: [/* @__PURE__ */ u(s, {
21
21
  active: t(p),
22
22
  settled: n(p),
23
23
  tone: p === "speaking" ? "speaking" : "listening"
24
- }), /* @__PURE__ */ u(o, {
24
+ }), /* @__PURE__ */ u(c, {
25
25
  className: "truncate text-xs text-text-muted",
26
26
  status: g,
27
27
  suffix: _,
@@ -58,7 +58,7 @@ var f = " self-stretch justify-end pb-8.5 [container-type:size] [@container_(min
58
58
  className: "shrink-0",
59
59
  children: y
60
60
  }),
61
- /* @__PURE__ */ u(s, {})
61
+ /* @__PURE__ */ u(a, {})
62
62
  ]
63
63
  });
64
64
  };
@@ -1,13 +1,13 @@
1
1
  import { showsAssistantCaption as e, showsUserCaption as t, waveformIsActive as n, waveformIsSettled as r } from "../../voice/voiceStageState.js";
2
2
  import { isAwaitingFirstChunk as i } from "../../voice/speechPlayback.js";
3
- import { VoiceCaption as a } from "./VoiceCaption.js";
4
- import { VoiceWaveform as o } from "./VoiceWaveform.js";
5
- import { VoiceStatusText as s } from "./VoiceStatusText.js";
6
- import { useLiveAvatarStage as c } from "../assistantLiveAvatarSeam.js";
3
+ import { useLiveAvatarStage as a } from "../assistantLiveAvatarSeam.js";
4
+ import { VoiceCaption as o } from "./VoiceCaption.js";
5
+ import { VoiceWaveform as s } from "./VoiceWaveform.js";
6
+ import { VoiceStatusText as c } from "./VoiceStatusText.js";
7
7
  import { Fragment as l, jsx as u, jsxs as d } from "react/jsx-runtime";
8
8
  //#region src/shared/assistant/ui/voice/VoiceStage.tsx
9
9
  var f = ({ state: f, userCaption: p, assistantCaption: m, expanded: h, statusText: g, statusSuffix: _, rotateStatus: v, control: y, errorText: b = null, spokenChunks: x = null }) => {
10
- let S = c(), C = e(f) && i(x), w = e(f) ? m : t(f) ? p : null, T = /* @__PURE__ */ u(o, {
10
+ let S = a(), C = e(f) && i(x), w = e(f) ? m : t(f) ? p : null, T = /* @__PURE__ */ u(s, {
11
11
  active: n(f),
12
12
  settled: r(f),
13
13
  tone: f === "speaking" ? "speaking" : "listening",
@@ -22,7 +22,7 @@ var f = ({ state: f, userCaption: p, assistantCaption: m, expanded: h, statusTex
22
22
  "data-testid": "assistant-voice-stage",
23
23
  "data-state": f,
24
24
  children: [
25
- /* @__PURE__ */ u(s, {
25
+ /* @__PURE__ */ u(c, {
26
26
  className: [
27
27
  "text-center text-text-muted",
28
28
  h ? "text-base" : "text-sm",
@@ -46,7 +46,7 @@ var f = ({ state: f, userCaption: p, assistantCaption: m, expanded: h, statusTex
46
46
  }), w ? /* @__PURE__ */ u("div", {
47
47
  className: [h ? "mb-12 max-h-[46vh] w-full overflow-y-auto" : "mb-6 max-h-[38vh] w-full overflow-y-auto", C ? h ? "min-h-[4.875rem]" : "min-h-12" : ""].join(" "),
48
48
  "data-caption-scroll": "",
49
- children: /* @__PURE__ */ u(a, {
49
+ children: /* @__PURE__ */ u(o, {
50
50
  text: w,
51
51
  role: e(f) ? "assistant" : "user",
52
52
  spokenChunks: x,
@@ -19,7 +19,13 @@ export declare const HANDS_FREE_OVERRIDE_KEY = "__boffHandsFreeInterrupt";
19
19
  export declare const HANDS_FREE_TRANSPORT_OVERRIDE_KEY = "__boffHandsFreeTransport";
20
20
  /** The stored value is trusted only if it is exactly `true`; anything else is OFF. */
21
21
  export declare function resolveStoredHandsFree(value: unknown): boolean;
22
- export declare function resolveHandsFreeEnabled(stored: unknown, override: unknown): boolean;
22
+ /**
23
+ * ★ BOFF-8822, the avatar pilot: never while a live avatar is ON, the test
24
+ * override included (`useLiveAvatarHandsFreeGuard`). Its voice plays on the
25
+ * speakers, where the microphone hears it, and hands-free would take it for
26
+ * the person speaking over the reply. Without an avatar, as before.
27
+ */
28
+ export declare function resolveHandsFreeEnabled(stored: unknown, override: unknown, avatarOn?: boolean): boolean;
23
29
  export declare function readHandsFreeOverride(): HandsFreeOverride | undefined;
24
30
  export type TransportOverride = "web-speech" | "audio-track" | "backend-stream";
25
31
  export declare function readTransportOverride(): TransportOverride | undefined;
@@ -3,8 +3,8 @@ var e = "__boffHandsFreeInterrupt", t = "__boffHandsFreeTransport";
3
3
  function n(e) {
4
4
  return e === !0;
5
5
  }
6
- function r(e, t) {
7
- return t === "on" ? !0 : t === "off" ? !1 : n(e);
6
+ function r(e, t, r = !1) {
7
+ return r ? !1 : t === "on" ? !0 : t === "off" ? !1 : n(e);
8
8
  }
9
9
  function i(e) {
10
10
  try {