@burdenoff/fe-libs 2026.912.6 → 2026.913.2

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.
Files changed (33) hide show
  1. package/dist/shared/assistant/index.d.ts +4 -0
  2. package/dist/shared/assistant/index.d.ts.map +1 -1
  3. package/dist/shared/assistant/preview/useAssistantPreviewBridge.js +8 -8
  4. package/dist/shared/assistant/ui/AssistantAvatar.d.ts +26 -0
  5. package/dist/shared/assistant/ui/AssistantAvatar.d.ts.map +1 -0
  6. package/dist/shared/assistant/ui/AssistantAvatar.js +12 -0
  7. package/dist/shared/assistant/ui/AssistantChatArea.js +298 -298
  8. package/dist/shared/assistant/ui/AssistantMessageItem.d.ts.map +1 -1
  9. package/dist/shared/assistant/ui/AssistantMessageItem.js +19 -21
  10. package/dist/shared/assistant/ui/AssistantToolActivity.js +1 -1
  11. package/dist/shared/assistant/ui/composer/AssistantAttachmentChips.d.ts.map +1 -1
  12. package/dist/shared/assistant/ui/composer/AssistantAttachmentChips.js +2 -2
  13. package/dist/shared/assistant/ui/composer/AssistantComposer.js +1 -1
  14. package/dist/shared/assistant/ui/voice/AssistantVoiceSession.d.ts.map +1 -1
  15. package/dist/shared/assistant/ui/voice/AssistantVoiceSession.js +112 -102
  16. package/dist/shared/assistant/ui/voice/VoiceMiniController.d.ts +10 -0
  17. package/dist/shared/assistant/ui/voice/VoiceMiniController.d.ts.map +1 -1
  18. package/dist/shared/assistant/ui/voice/VoiceMiniController.js +29 -28
  19. package/dist/shared/assistant/ui/voice/VoiceStage.d.ts +10 -0
  20. package/dist/shared/assistant/ui/voice/VoiceStage.d.ts.map +1 -1
  21. package/dist/shared/assistant/ui/voice/VoiceStage.js +35 -34
  22. package/dist/shared/assistant/ui/voice/VoiceStatusText.d.ts +51 -0
  23. package/dist/shared/assistant/ui/voice/VoiceStatusText.d.ts.map +1 -0
  24. package/dist/shared/assistant/ui/voice/VoiceStatusText.js +42 -0
  25. package/dist/shared/assistant/ui/voice/VoiceWaveform.js +1 -1
  26. package/dist/shared/assistant/voice/rotationClock.d.ts +31 -0
  27. package/dist/shared/assistant/voice/rotationClock.d.ts.map +1 -0
  28. package/dist/shared/assistant/voice/rotationClock.js +27 -0
  29. package/dist/shared/assistant/voice/voiceStatus.d.ts +81 -0
  30. package/dist/shared/assistant/voice/voiceStatus.d.ts.map +1 -0
  31. package/dist/shared/assistant/voice/voiceStatus.js +33 -0
  32. package/dist/shared-assistant.js +88 -84
  33. package/package.json +1 -1
@@ -1,59 +1,60 @@
1
1
  import { showsAssistantCaption as e, showsUserCaption as t, waveformIsActive as n, waveformIsSettled as r } from "../../voice/voiceStageState.js";
2
2
  import { VoiceCaption as i } from "./VoiceCaption.js";
3
3
  import { VoiceWaveform as a } from "./VoiceWaveform.js";
4
- import { Fragment as o, jsx as s, jsxs as c } from "react/jsx-runtime";
4
+ import { VoiceStatusText as o } from "./VoiceStatusText.js";
5
+ import { Fragment as s, jsx as c, jsxs as l } from "react/jsx-runtime";
5
6
  //#region src/shared/assistant/ui/voice/VoiceStage.tsx
6
- var l = ({ state: l, userCaption: u, assistantCaption: d, expanded: f, statusText: p, control: m, errorText: h = null, spokenChunks: g = null }) => {
7
- let _ = e(l) ? d : t(l) ? u : null;
8
- return /* @__PURE__ */ c("div", {
7
+ var u = ({ state: u, userCaption: d, assistantCaption: f, expanded: p, statusText: m, statusSuffix: h, rotateStatus: g, control: _, errorText: v = null, spokenChunks: y = null }) => {
8
+ let b = e(u) ? f : t(u) ? d : null;
9
+ return /* @__PURE__ */ l("div", {
9
10
  className: [
10
11
  "flex min-h-0 w-full flex-1 flex-col items-center",
11
- f ? "px-8" : "px-14",
12
- f ? "justify-start pt-[16vh]" : "justify-center"
12
+ p ? "px-8" : "px-14",
13
+ p ? "justify-start pt-[16vh]" : "justify-center"
13
14
  ].join(" "),
14
15
  "data-testid": "assistant-voice-stage",
15
- "data-state": l,
16
+ "data-state": u,
16
17
  children: [
17
- /* @__PURE__ */ s("p", {
18
+ /* @__PURE__ */ c(o, {
18
19
  className: [
19
20
  "text-center text-text-muted",
20
- f ? "text-base" : "text-sm",
21
- f ? "mb-3" : "mb-2"
21
+ p ? "text-base" : "text-sm",
22
+ p ? "mb-3" : "mb-2"
22
23
  ].join(" "),
23
- "aria-live": "polite",
24
- "data-testid": "assistant-voice-status",
25
- children: p
24
+ status: m,
25
+ suffix: h,
26
+ rotating: g
26
27
  }),
27
- l === "mic-error" ? /* @__PURE__ */ s("p", {
28
- className: `max-w-md text-center text-status-warning ${f ? "text-lg" : "text-sm"}`,
28
+ u === "mic-error" ? /* @__PURE__ */ c("p", {
29
+ className: `max-w-md text-center text-status-warning ${p ? "text-lg" : "text-sm"}`,
29
30
  role: "alert",
30
31
  "data-testid": "assistant-voice-stage-error",
31
- children: h
32
- }) : /* @__PURE__ */ c(o, { children: [/* @__PURE__ */ s("div", {
33
- className: f ? "mb-10" : "mb-5",
34
- children: /* @__PURE__ */ s(a, {
35
- active: n(l),
36
- settled: r(l),
37
- tone: l === "speaking" ? "speaking" : "listening",
38
- expanded: f
32
+ children: v
33
+ }) : /* @__PURE__ */ l(s, { children: [/* @__PURE__ */ c("div", {
34
+ className: p ? "mb-10" : "mb-5",
35
+ children: /* @__PURE__ */ c(a, {
36
+ active: n(u),
37
+ settled: r(u),
38
+ tone: u === "speaking" ? "speaking" : "listening",
39
+ expanded: p
39
40
  })
40
- }), _ ? /* @__PURE__ */ s("div", {
41
- className: f ? "mb-12 max-h-[46vh] w-full overflow-y-auto" : "mb-6 max-h-[38vh] w-full overflow-y-auto",
41
+ }), b ? /* @__PURE__ */ c("div", {
42
+ className: p ? "mb-12 max-h-[46vh] w-full overflow-y-auto" : "mb-6 max-h-[38vh] w-full overflow-y-auto",
42
43
  "data-caption-scroll": "",
43
- children: /* @__PURE__ */ s(i, {
44
- text: _,
45
- role: e(l) ? "assistant" : "user",
46
- spokenChunks: g,
47
- expanded: f,
44
+ children: /* @__PURE__ */ c(i, {
45
+ text: b,
46
+ role: e(u) ? "assistant" : "user",
47
+ spokenChunks: y,
48
+ expanded: p,
48
49
  testId: "assistant-voice-caption"
49
50
  })
50
- }) : /* @__PURE__ */ s("div", {
51
- className: f ? "mb-12 h-[4.875rem]" : "mb-6 h-12",
51
+ }) : /* @__PURE__ */ c("div", {
52
+ className: p ? "mb-12 h-[4.875rem]" : "mb-6 h-12",
52
53
  "aria-hidden": "true"
53
54
  })] }),
54
- m
55
+ _
55
56
  ]
56
57
  });
57
58
  };
58
59
  //#endregion
59
- export { l as VoiceStage };
60
+ export { u as VoiceStage };
@@ -0,0 +1,51 @@
1
+ import { FC } from 'react';
2
+ /**
3
+ * The voice status line's markup: one live region that announces the STATUS,
4
+ * beside visual copy that may differ from it.
5
+ *
6
+ * ★★ Both spans are mounted in EVERY state, and nothing here is keyed. Many
7
+ * screen readers ignore a live region that is inserted at the moment its
8
+ * content changes, so remounting the region — a structure that only split
9
+ * while thinking, or a `key` that changes with the text — would silence the
10
+ * very announcements it exists for. The region stays put; only its text
11
+ * changes, and only when the status does.
12
+ *
13
+ * ★ The shown copy is `aria-hidden`, so a rotation is never read aloud —
14
+ * neither through the live region nor when the line is read with a virtual
15
+ * cursor, where the announced span supplies the text exactly once.
16
+ *
17
+ * ★★ `relative` + `left-0 top-0` CONTAIN the announced span. `sr-only` is
18
+ * `position: absolute`; without a positioned line its containing block is the
19
+ * voice dialog, so it sat after the full untruncated text and pushed scrollable
20
+ * overflow into the chat area. A screen reader scrolling the status into view
21
+ * then shifted the whole docked strip sideways (measured: 34px at 320px wide
22
+ * for a long Spanish status with the microphone off). `left-0`, not the
23
+ * logical `start-0`: the latter is absent from at least one consumer's
24
+ * generated stylesheet, and for a 1px clipped box the side does not matter.
25
+ *
26
+ * ★ `data-testid="assistant-voice-status"` is on the ANNOUNCED span, so reading
27
+ * that id still yields exactly the status, as it always has. The visible copy is
28
+ * `assistant-voice-status-shown`; the line itself is `assistant-voice-status-line`.
29
+ */
30
+ export declare const VoiceStatusLine: FC<{
31
+ announced: string;
32
+ shown: string;
33
+ className: string;
34
+ }>;
35
+ /**
36
+ * The voice session's status line, rotating the SHOWN text while the assistant
37
+ * thinks. What is announced is always `status` — see `voiceStatusParts`.
38
+ *
39
+ * ★ The clock lives HERE, not in `AssistantVoiceSession`: a tick re-renders only
40
+ * this line, and the orchestrators stay free of timers.
41
+ */
42
+ export declare const VoiceStatusText: FC<{
43
+ /** The meaningful status. This is what is announced. */
44
+ status: string;
45
+ /** Kept visible while the shown phrase rotates, e.g. "Microphone off". */
46
+ suffix?: string | null;
47
+ /** Rotate the SHOWN text through the thinking phrases. */
48
+ rotating?: boolean;
49
+ className: string;
50
+ }>;
51
+ //# sourceMappingURL=VoiceStatusText.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VoiceStatusText.d.ts","sourceRoot":"","sources":["../../../../../src/shared/assistant/ui/voice/VoiceStatusText.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AAYrD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,eAAe,EAAE,EAAE,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,CAiBA,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,EAAE,EAAE,CAAC;IAC/B,wDAAwD;IACxD,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB,CAiBA,CAAC"}
@@ -0,0 +1,42 @@
1
+ import { useAssistantTr as e } from "../../i18n.js";
2
+ import { voiceStatusParts as t } from "../../voice/voiceStatus.js";
3
+ import { IDLE_ROTATION_CLOCK as n, advanceRotationClock as r, rotationElapsedMs as i, startRotationTicker as a, syncRotationClock as o } from "../../voice/rotationClock.js";
4
+ import { useEffect as s, useState as c } from "react";
5
+ import { jsx as l, jsxs as u } from "react/jsx-runtime";
6
+ //#region src/shared/assistant/ui/voice/VoiceStatusText.tsx
7
+ var d = ({ announced: e, shown: t, className: n }) => /* @__PURE__ */ u("p", {
8
+ className: `relative ${n}`,
9
+ "data-testid": "assistant-voice-status-line",
10
+ children: [/* @__PURE__ */ l("span", {
11
+ "aria-hidden": "true",
12
+ "data-testid": "assistant-voice-status-shown",
13
+ children: t
14
+ }), /* @__PURE__ */ l("span", {
15
+ className: "sr-only left-0 top-0",
16
+ "aria-live": "polite",
17
+ "aria-atomic": "true",
18
+ "data-testid": "assistant-voice-status",
19
+ children: e
20
+ })]
21
+ }), f = ({ status: n, suffix: r = null, rotating: i = !1, className: a }) => {
22
+ let { announced: o, shown: s } = t({
23
+ tr: e(),
24
+ status: n,
25
+ suffix: r,
26
+ rotating: i,
27
+ elapsedMs: p(i)
28
+ });
29
+ return /* @__PURE__ */ l(d, {
30
+ className: a,
31
+ announced: o,
32
+ shown: s
33
+ });
34
+ };
35
+ function p(e) {
36
+ let [t, l] = c(() => o(n, e)), u = o(t, e);
37
+ return u !== t && l(u), s(() => {
38
+ if (e) return a(() => l((e) => r(e)));
39
+ }, [e]), i(u);
40
+ }
41
+ //#endregion
42
+ export { d as VoiceStatusLine, f as VoiceStatusText };
@@ -17,7 +17,7 @@ var t = [
17
17
  "inline-block rounded-full transition-[height,opacity] duration-300",
18
18
  a ? "w-1.5" : "w-1",
19
19
  r === "speaking" ? "bg-brand-primary" : "bg-text-muted",
20
- n ? i ? "animate-pulse [animation-duration:2.4s] opacity-70" : "animate-pulse" : "opacity-40"
20
+ n ? i ? "motion-safe:animate-pulse [animation-duration:2.4s] opacity-70" : "motion-safe:animate-pulse" : "opacity-40"
21
21
  ].join(" "),
22
22
  style: {
23
23
  height: n ? `${(i ? [
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The clock behind the voice status line's rotating phrase, as plain functions.
3
+ *
4
+ * ★★ Why this is not simply a hook. fe-libs tests run with no DOM and no React
5
+ * renderer, and static rendering runs no effects. A clock written inline in a
6
+ * component is exercised by nothing, so every way of breaking it — never
7
+ * starting, never resetting, never clearing — passes the whole suite (measured:
8
+ * seven such mutations survived before this split). Here the state rules are
9
+ * pure and the ticker runs under fake timers; the hook that joins them is a few
10
+ * lines, pinned by `voiceStatusWiring.test.ts`.
11
+ */
12
+ export interface RotationClock {
13
+ /** Whole rotation steps since the clock last became active. */
14
+ readonly steps: number;
15
+ readonly active: boolean;
16
+ }
17
+ export declare const IDLE_ROTATION_CLOCK: RotationClock;
18
+ /**
19
+ * Follow `active`, restarting from step 0 whenever it changes.
20
+ *
21
+ * ★ Returns the SAME object when nothing changed. The hook adjusts state during
22
+ * render only on a change of identity, so a fresh object here every call would
23
+ * be an infinite render loop.
24
+ */
25
+ export declare function syncRotationClock(clock: RotationClock, active: boolean): RotationClock;
26
+ /** One tick. A tick that lands after the clock went inactive is ignored. */
27
+ export declare function advanceRotationClock(clock: RotationClock): RotationClock;
28
+ export declare function rotationElapsedMs(clock: RotationClock): number;
29
+ /** Call `onTick` every `intervalMs` until the returned stop function runs. */
30
+ export declare function startRotationTicker(onTick: () => void, intervalMs?: number): () => void;
31
+ //# sourceMappingURL=rotationClock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rotationClock.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/voice/rotationClock.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED,eAAO,MAAM,mBAAmB,EAAE,aAA2C,CAAC;AAE9E;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,OAAO,GACd,aAAa,CAEf;AAED,4EAA4E;AAC5E,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,aAAa,GAAG,aAAa,CAExE;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAE9D;AAED,8EAA8E;AAC9E,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,IAAI,EAClB,UAAU,GAAE,MAAyB,GACpC,MAAM,IAAI,CAGZ"}
@@ -0,0 +1,27 @@
1
+ import { PHRASE_ROTATE_MS as e } from "../stageCopy.js";
2
+ //#region src/shared/assistant/voice/rotationClock.ts
3
+ var t = {
4
+ steps: 0,
5
+ active: !1
6
+ };
7
+ function n(e, t) {
8
+ return e.active === t ? e : {
9
+ steps: 0,
10
+ active: t
11
+ };
12
+ }
13
+ function r(e) {
14
+ return e.active ? {
15
+ steps: e.steps + 1,
16
+ active: !0
17
+ } : e;
18
+ }
19
+ function i(t) {
20
+ return t.active ? t.steps * e : 0;
21
+ }
22
+ function a(t, n = e) {
23
+ let r = setInterval(t, n);
24
+ return () => clearInterval(r);
25
+ }
26
+ //#endregion
27
+ export { t as IDLE_ROTATION_CLOCK, r as advanceRotationClock, i as rotationElapsedMs, a as startRotationTicker, n as syncRotationClock };
@@ -0,0 +1,81 @@
1
+ import { AssistantTr } from '../i18n';
2
+ import { StageCopyEntry } from '../stageCopy';
3
+ import { VoiceStageState } from './voiceStageState';
4
+ /** The voice session's own label for `thinking` — one definition for the session and the status line. */
5
+ export declare const VOICE_THINKING_LABEL: StageCopyEntry;
6
+ /** Reported alongside a stage while the microphone is off. */
7
+ export declare const VOICE_MUTED_LABEL: StageCopyEntry;
8
+ /**
9
+ * The muted suffix for the status line, or null.
10
+ *
11
+ * Muted is reported ALONGSIDE the stage, not instead of it: the assistant may
12
+ * still be speaking with the microphone off, and saying only "Microphone off"
13
+ * would misreport that.
14
+ *
15
+ * ★ Gated on the STAGE, not the phase. `connecting`, `endpoint-grace` and
16
+ * `interrupting` are all `phase === 'listening'` underneath, so a phase test
17
+ * dropped the suffix on exactly those three stages — leaving "Stopped — go
18
+ * ahead" inviting someone to speak into a muted microphone.
19
+ *
20
+ * ★ Not while `listening`: that stage's own label already IS "Microphone off"
21
+ * when muted, and a suffix would read "Microphone off · Microphone off".
22
+ *
23
+ * ★ Not for an empty label (ended, mic-error), which would otherwise render a
24
+ * bare " · Microphone off". And no `error !== null` arm: the error belongs to
25
+ * the stage's alert element, and testing it here once printed the whole
26
+ * sentence TWICE — truncated in the status line, repeated below it, and
27
+ * announced twice by a screen reader.
28
+ */
29
+ export declare function voiceStatusSuffix(args: {
30
+ tr: AssistantTr;
31
+ stage: VoiceStageState;
32
+ muted: boolean;
33
+ /** The stage's label, already localised. */
34
+ label: string;
35
+ }): string | null;
36
+ /** The full status: the stage label, then the suffix when there is one. */
37
+ export declare function composeVoiceStatus(label: string, suffix: string | null): string;
38
+ /**
39
+ * The status line, split into what is SHOWN and what is ANNOUNCED.
40
+ *
41
+ * ★★ Why two strings. The status line is a live region: a screen reader reads
42
+ * it aloud whenever its text changes. While the model is thinking, a sighted
43
+ * user is better served by a phrase that moves — a single frozen "Thinking…"
44
+ * for the length of a turn reads as a hang (see `THINKING_PHRASES`). Putting
45
+ * that rotation into the live region would announce a new filler word every
46
+ * `PHRASE_ROTATE_MS`. So the rotation is visual only, and the announced text
47
+ * changes only when the status genuinely does.
48
+ *
49
+ * ★ The first shown phrase is the voice session's OWN label, not the pool's
50
+ * opening entry: on entering `thinking`, sighted and screen-reader users get
51
+ * the same words.
52
+ *
53
+ * ★★ A pool phrase is shown only when it is in the SAME translation state as
54
+ * the voice label. The label (`voiceSession.*`) and the pool (`stage.*`) are
55
+ * separately seeded key families. With the label translated and the pool not,
56
+ * rotating would alternate the user's language with English — so the line holds
57
+ * on the translated label instead. When neither is translated, it rotates in
58
+ * English, like the rest of the untranslated interface.
59
+ *
60
+ * ★ A muted microphone stays on screen through the rotation.
61
+ *
62
+ * Pure in `elapsedMs` — the caller owns the clock — like `thinkingPhrase`.
63
+ */
64
+ export interface VoiceStatusParts {
65
+ /** For the live region. Changes only when the status does. */
66
+ readonly announced: string;
67
+ /** For the eye. Rotates while thinking; otherwise identical to `announced`. */
68
+ readonly shown: string;
69
+ }
70
+ export declare function voiceStatusParts(args: {
71
+ tr: AssistantTr;
72
+ /** The meaningful status, exactly as it should be announced. */
73
+ status: string;
74
+ /** Kept on the shown text while it rotates, e.g. "Microphone off". */
75
+ suffix: string | null;
76
+ /** True only while the assistant is thinking. */
77
+ rotating: boolean;
78
+ /** Time since rotation began. */
79
+ elapsedMs: number;
80
+ }): VoiceStatusParts;
81
+ //# sourceMappingURL=voiceStatus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voiceStatus.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/voice/voiceStatus.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,yGAAyG;AACzG,eAAO,MAAM,oBAAoB,EAAE,cAGlC,CAAC;AAEF,8DAA8D;AAC9D,eAAO,MAAM,iBAAiB,EAAE,cAG/B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,EAAE,EAAE,WAAW,CAAC;IAChB,KAAK,EAAE,eAAe,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC;IACf,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,MAAM,GAAG,IAAI,CAKhB;AAED,2EAA2E;AAC3E,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,MAAM,CAER;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,gBAAgB;IAC/B,8DAA8D;IAC9D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAKD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,EAAE,EAAE,WAAW,CAAC;IAChB,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,iDAAiD;IACjD,QAAQ,EAAE,OAAO,CAAC;IAClB,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,gBAAgB,CAmBnB"}
@@ -0,0 +1,33 @@
1
+ import { THINKING_PHRASES as e, stageText as t, thinkingPhrase as n } from "../stageCopy.js";
2
+ //#region src/shared/assistant/voice/voiceStatus.ts
3
+ var r = {
4
+ key: "voiceSession.thinking",
5
+ fallback: "Thinking…"
6
+ }, i = {
7
+ key: "voiceSession.muted",
8
+ fallback: "Microphone off"
9
+ };
10
+ function a(e) {
11
+ let { tr: n, stage: r, muted: a, label: o } = e;
12
+ return a && r !== "listening" && o !== "" ? t(n, i) : null;
13
+ }
14
+ function o(e, t) {
15
+ return t ? `${e} · ${t}` : e;
16
+ }
17
+ var s = (e, t) => e(t.key, t.fallback) !== t.fallback;
18
+ function c(i) {
19
+ let { tr: a, status: c, suffix: l, rotating: u, elapsedMs: d } = i, f = {
20
+ announced: c,
21
+ shown: c
22
+ };
23
+ if (!u || c === "") return f;
24
+ let p = n(a, d);
25
+ if (p === n(a, 0)) return f;
26
+ let m = e.find((e) => t(a, e) === p);
27
+ return !m || s(a, m) !== s(a, r) ? f : {
28
+ announced: c,
29
+ shown: o(p, l)
30
+ };
31
+ }
32
+ //#endregion
33
+ export { i as VOICE_MUTED_LABEL, r as VOICE_THINKING_LABEL, o as composeVoiceStatus, c as voiceStatusParts, a as voiceStatusSuffix };