@burdenoff/fe-libs 2026.910.7 → 2026.911.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 (32) hide show
  1. package/dist/shared/assistant/index.d.ts +7 -0
  2. package/dist/shared/assistant/index.d.ts.map +1 -1
  3. package/dist/shared/assistant/preview/AssistantPreviewOverlay.d.ts +5 -0
  4. package/dist/shared/assistant/preview/AssistantPreviewOverlay.d.ts.map +1 -0
  5. package/dist/shared/assistant/preview/AssistantPreviewOverlay.js +68 -0
  6. package/dist/shared/assistant/preview/context.d.ts +9 -0
  7. package/dist/shared/assistant/preview/context.d.ts.map +1 -0
  8. package/dist/shared/assistant/preview/context.js +12 -0
  9. package/dist/shared/assistant/preview/previewTransitions.d.ts +78 -0
  10. package/dist/shared/assistant/preview/previewTransitions.d.ts.map +1 -0
  11. package/dist/shared/assistant/preview/previewTransitions.js +96 -0
  12. package/dist/shared/assistant/preview/types.d.ts +121 -0
  13. package/dist/shared/assistant/preview/types.d.ts.map +1 -0
  14. package/dist/shared/assistant/preview/useAssistantPreviewBridge.d.ts +3 -0
  15. package/dist/shared/assistant/preview/useAssistantPreviewBridge.d.ts.map +1 -0
  16. package/dist/shared/assistant/preview/useAssistantPreviewBridge.js +71 -0
  17. package/dist/shared/assistant/ui/AIAssistantPanel.d.ts +8 -0
  18. package/dist/shared/assistant/ui/AIAssistantPanel.d.ts.map +1 -1
  19. package/dist/shared/assistant/ui/AIAssistantPanel.js +82 -45
  20. package/dist/shared/assistant/ui/AssistantConversationList.d.ts.map +1 -1
  21. package/dist/shared/assistant/ui/AssistantConversationList.js +81 -76
  22. package/dist/shared/assistant/ui/AssistantHeader.d.ts +10 -0
  23. package/dist/shared/assistant/ui/AssistantHeader.d.ts.map +1 -1
  24. package/dist/shared/assistant/ui/AssistantHeader.js +46 -36
  25. package/dist/shared/assistant/ui/panelOverlays.d.ts +48 -0
  26. package/dist/shared/assistant/ui/panelOverlays.d.ts.map +1 -0
  27. package/dist/shared/assistant/ui/panelOverlays.js +16 -0
  28. package/dist/shared/assistant/ui/useOverlayFocus.d.ts +4 -0
  29. package/dist/shared/assistant/ui/useOverlayFocus.d.ts.map +1 -0
  30. package/dist/shared/assistant/ui/useOverlayFocus.js +17 -0
  31. package/dist/shared-assistant.js +41 -35
  32. package/package.json +1 -1
@@ -91,6 +91,13 @@ export * from './ui/composer/AssistantAttachmentButton';
91
91
  export * from './ui/composer/AssistantAttachmentChips';
92
92
  export * from './ui/composer/AssistantConnectSourceItem';
93
93
  export * from './ui/composer/connectSource';
94
+ export * from './preview/types';
95
+ export * from './preview/context';
96
+ export * from './preview/previewTransitions';
97
+ export * from './ui/panelOverlays';
98
+ export * from './ui/useOverlayFocus';
99
+ export * from './preview/useAssistantPreviewBridge';
100
+ export * from './preview/AssistantPreviewOverlay';
94
101
  export * from './ui/composer/AssistantLanguageSelector';
95
102
  export * from './ui/composer/AssistantModeSelector';
96
103
  export * from './ui/composer/AssistantVoiceButton';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { FC } from 'react';
2
+ export declare const AssistantPreviewOverlay: FC<{
3
+ onClose: () => void;
4
+ }>;
5
+ //# sourceMappingURL=AssistantPreviewOverlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssistantPreviewOverlay.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/preview/AssistantPreviewOverlay.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAA6B,KAAK,EAAE,EAAkB,MAAM,OAAO,CAAC;AA2E3E,eAAO,MAAM,uBAAuB,EAAE,EAAE,CAAC;IAAE,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,CAwF/D,CAAC"}
@@ -0,0 +1,68 @@
1
+ import { useAssistantTr as e } from "../i18n.js";
2
+ import { useAssistantStore as t } from "../store.js";
3
+ import { useAssistantPreview as n } from "./context.js";
4
+ import { useOverlayFocus as r } from "../ui/useOverlayFocus.js";
5
+ import { Component as i } from "react";
6
+ import { Fragment as a, jsx as o, jsxs as s } from "react/jsx-runtime";
7
+ //#region src/shared/assistant/preview/AssistantPreviewOverlay.tsx
8
+ var c = class extends i {
9
+ state = {
10
+ failed: !1,
11
+ shownFor: this.props.resetKey
12
+ };
13
+ static getDerivedStateFromProps(e, t) {
14
+ return e.resetKey === t.shownFor ? null : {
15
+ failed: !1,
16
+ shownFor: e.resetKey
17
+ };
18
+ }
19
+ static getDerivedStateFromError() {
20
+ return { failed: !0 };
21
+ }
22
+ componentDidCatch(e, t) {
23
+ console.error("[assistant] preview surface threw", e, t.componentStack);
24
+ }
25
+ render() {
26
+ return this.state.failed ? this.props.fallback : this.props.children;
27
+ }
28
+ }, l = ({ controller: e }) => /* @__PURE__ */ o(a, { children: e.render() }), u = ({ onClose: i }) => {
29
+ let a = n(), u = e(), d = t((e) => {
30
+ let t = e.activeConversationId, n = t ? e.processingByConversationId[t]?.messageId : null;
31
+ return !t || !n ? "idle" : `${t}:${n}#${e.conversations.find((e) => e.id === t)?.updatedAt ?? ""}`;
32
+ }), f = r("assistant-toggle-preview");
33
+ return a ? /* @__PURE__ */ s("div", {
34
+ ref: f,
35
+ tabIndex: -1,
36
+ className: "absolute inset-0 z-10 flex flex-col bg-bg-surface outline-none animate-in slide-in-from-right-2 fade-in duration-200",
37
+ role: "region",
38
+ "aria-label": a.label ?? u("preview.title", "Preview"),
39
+ "data-testid": "assistant-preview",
40
+ children: [/* @__PURE__ */ s("div", {
41
+ className: "flex items-center justify-between border-b border-border-default px-3 py-2",
42
+ children: [/* @__PURE__ */ o("span", {
43
+ className: "text-sm font-medium text-text-primary",
44
+ children: a.label ?? u("preview.title", "Preview")
45
+ }), /* @__PURE__ */ o("button", {
46
+ type: "button",
47
+ onClick: i,
48
+ className: "rounded-md px-2 py-1 text-xs text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary focus:outline-none focus-visible:ring-2 focus-visible:ring-border-strong",
49
+ "aria-label": u("preview.close", "Close preview"),
50
+ "data-testid": "assistant-preview-close",
51
+ children: u("preview.close", "Close preview")
52
+ })]
53
+ }), /* @__PURE__ */ o("div", {
54
+ className: "min-h-0 flex-1 overflow-y-auto",
55
+ children: /* @__PURE__ */ o(c, {
56
+ resetKey: d,
57
+ fallback: /* @__PURE__ */ o("p", {
58
+ className: "p-4 text-sm text-text-muted",
59
+ "data-testid": "assistant-preview-failed",
60
+ children: u("preview.failed", "The preview could not be displayed.")
61
+ }),
62
+ children: /* @__PURE__ */ o(l, { controller: a })
63
+ })
64
+ })]
65
+ }) : null;
66
+ };
67
+ //#endregion
68
+ export { u as AssistantPreviewOverlay };
@@ -0,0 +1,9 @@
1
+ import { FC, ReactNode } from 'react';
2
+ import { AssistantPreviewController } from './types';
3
+ export declare const AssistantPreviewProvider: FC<{
4
+ value?: AssistantPreviewController;
5
+ children: ReactNode;
6
+ }>;
7
+ /** The product's controller, or null when the product supplied none. */
8
+ export declare function useAssistantPreview(): AssistantPreviewController | null;
9
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/preview/context.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAA6B,KAAK,EAAE,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE3E,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AAM1D,eAAO,MAAM,wBAAwB,EAAE,EAAE,CAAC;IACxC,KAAK,CAAC,EAAE,0BAA0B,CAAC;IACnC,QAAQ,EAAE,SAAS,CAAC;CACrB,CAIA,CAAC;AAEF,wEAAwE;AACxE,wBAAgB,mBAAmB,IAAI,0BAA0B,GAAG,IAAI,CAEvE"}
@@ -0,0 +1,12 @@
1
+ import { createContext as e, useContext as t } from "react";
2
+ import { jsx as n } from "react/jsx-runtime";
3
+ //#region src/shared/assistant/preview/context.tsx
4
+ var r = e(null), i = ({ value: e, children: t }) => /* @__PURE__ */ n(r.Provider, {
5
+ value: e ?? null,
6
+ children: t
7
+ });
8
+ function a() {
9
+ return t(r);
10
+ }
11
+ //#endregion
12
+ export { i as AssistantPreviewProvider, a as useAssistantPreview };
@@ -0,0 +1,78 @@
1
+ import { AssistantConversationStatus } from '../conversation';
2
+ import { AssistantPreviewEvent, AssistantPreviewRun } from './types';
3
+ export interface PreviewBridgeState {
4
+ /**
5
+ * ★★ The conversation whose baseline has been established.
6
+ *
7
+ * It exists to tell two indistinguishable-looking situations apart. Mounting
8
+ * onto a conversation whose LAST turn already settled must NOT replay that
9
+ * turn — the entry commonly still holds a `complete` status long after the
10
+ * answer was read. But a turn that fails SYNCHRONOUSLY is the same shape: the
11
+ * no-workspace path throws inside the same block as the `provisioning` write
12
+ * (AssistantChatArea.tsx:1024 then :1492), React batches them, and the bridge
13
+ * sees only `error`. Requiring a prior `start` suppressed every event for
14
+ * that whole class of failure — the user saw an error in the transcript and
15
+ * the preview showed nothing at all.
16
+ *
17
+ * ★★ PER CONVERSATION, not a single flag. Terminal processing entries
18
+ * deliberately persist, so with one global flag, selecting a History row
19
+ * whose entry still held `complete` re-announced that OLD settled turn and
20
+ * replaced the product's preview with stale output — the very replay this
21
+ * guard exists to prevent, reached by switching conversation instead of by
22
+ * mounting. The first observation of EACH conversation is a baseline.
23
+ */
24
+ readonly observedConversationId: string | null;
25
+ /**
26
+ * The run announced with `start` and not yet finished.
27
+ *
28
+ * ★ Clearing this IS the idempotence mechanism — a settled run is no longer
29
+ * anybody's started run, so no second `end` can be derived for it. An earlier
30
+ * draft also carried an `endedRunId`; a mutation test showed nothing could
31
+ * distinguish its presence from its absence, because this null already did
32
+ * the work. Two mechanisms for one guarantee is how they drift apart.
33
+ */
34
+ readonly startedRun: AssistantPreviewRun | null;
35
+ /**
36
+ * ★★ The last run finished. NOT redundant with `startedRun` being null: a
37
+ * settled status can be written more than once, and since a terminal run
38
+ * first seen already-terminal now gets a lifecycle, "no started run" alone
39
+ * cannot tell a REPEATED `complete` from a genuinely new failed run. Without
40
+ * this the second `complete` tick re-announced the same run and ended it
41
+ * twice.
42
+ *
43
+ * (An earlier revision carried this field, found nothing could distinguish
44
+ * its presence from its absence, and removed it. That was correct then and is
45
+ * wrong now — the terminal-first case is what gives it work to do.)
46
+ */
47
+ readonly lastEndedRunId: string | null;
48
+ /** The last content emitted, so an unchanged tick is not re-emitted. */
49
+ readonly lastSnapshot: string | null;
50
+ }
51
+ export declare const IDLE_PREVIEW_STATE: PreviewBridgeState;
52
+ export interface PreviewInput {
53
+ /**
54
+ * The turn the store currently describes, or null when the entry is gone.
55
+ * ★ null is NOT "nothing to do" — it is how an interrupted run ends.
56
+ */
57
+ readonly run: AssistantPreviewRun | null;
58
+ /**
59
+ * ★★ The ACTIVE conversation, independent of whether it has a run.
60
+ *
61
+ * The baseline used to be derivable only from a run — so a panel opened on an
62
+ * IDLE conversation recorded nothing, and when that conversation's first turn
63
+ * then failed synchronously the terminal render was still "unbaselined" and
64
+ * emitted no events at all. The very case the baseline exists to permit,
65
+ * defeated by the baseline needing a run to establish itself.
66
+ */
67
+ readonly conversationId: string | null;
68
+ readonly status: AssistantConversationStatus;
69
+ readonly content: string | null;
70
+ readonly error?: string | null;
71
+ /** `isStageCopy`, injected so this stays pure and testable without i18n. */
72
+ readonly isFiller: (content: string) => boolean;
73
+ }
74
+ export declare function nextPreviewEvents(state: PreviewBridgeState, input: PreviewInput): {
75
+ events: AssistantPreviewEvent[];
76
+ state: PreviewBridgeState;
77
+ };
78
+ //# sourceMappingURL=previewTransitions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"previewTransitions.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/preview/previewTransitions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,KAAK,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAS1E,MAAM,WAAW,kBAAkB;IACjC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,QAAQ,CAAC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/C;;;;;;;;OAQG;IACH,QAAQ,CAAC,UAAU,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAChD;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,wEAAwE;IACxE,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;AAED,eAAO,MAAM,kBAAkB,EAAE,kBAKhC,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACzC;;;;;;;;OAQG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAC;IAC7C,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;CACjD;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,kBAAkB,EACzB,KAAK,EAAE,YAAY,GAClB;IAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC;IAAC,KAAK,EAAE,kBAAkB,CAAA;CAAE,CAiIhE"}
@@ -0,0 +1,96 @@
1
+ //#region src/shared/assistant/preview/previewTransitions.ts
2
+ var e = new Set([
3
+ "provisioning",
4
+ "connecting",
5
+ "streaming"
6
+ ]), t = {
7
+ observedConversationId: null,
8
+ startedRun: null,
9
+ lastEndedRunId: null,
10
+ lastSnapshot: null
11
+ };
12
+ function n(t, n) {
13
+ let r = [], i = n.run?.runId ?? null, a = n.conversationId ?? n.run?.conversationId ?? null, o = a !== null && t.observedConversationId === a, s = {
14
+ ...t,
15
+ observedConversationId: a ?? t.observedConversationId
16
+ }, c = s.startedRun;
17
+ if (c && c.runId !== i && (r.push({
18
+ kind: "end",
19
+ run: c,
20
+ outcome: "abandoned",
21
+ error: null
22
+ }), s = {
23
+ ...s,
24
+ startedRun: null,
25
+ lastEndedRunId: c.runId
26
+ }), !n.run) return {
27
+ events: r,
28
+ state: s
29
+ };
30
+ if (e.has(n.status)) {
31
+ s.startedRun?.runId !== n.run.runId && (r.push({
32
+ kind: "start",
33
+ run: n.run
34
+ }), s = {
35
+ ...s,
36
+ startedRun: n.run,
37
+ lastSnapshot: null
38
+ });
39
+ let e = s.startedRun ?? n.run, t = n.content;
40
+ return t && !n.isFiller(t) && t !== s.lastSnapshot && (r.push({
41
+ kind: "snapshot",
42
+ run: e,
43
+ content: t
44
+ }), s = {
45
+ ...s,
46
+ lastSnapshot: t
47
+ }), {
48
+ events: r,
49
+ state: s
50
+ };
51
+ }
52
+ if (!s.startedRun) {
53
+ if (!o || s.lastEndedRunId === n.run.runId) return {
54
+ events: r,
55
+ state: {
56
+ ...s,
57
+ lastEndedRunId: n.run.runId
58
+ }
59
+ };
60
+ r.push({
61
+ kind: "start",
62
+ run: n.run
63
+ }), s = {
64
+ ...s,
65
+ startedRun: n.run,
66
+ lastSnapshot: null
67
+ };
68
+ }
69
+ let l = s.startedRun;
70
+ if (l && l.runId === n.run.runId) {
71
+ let e = n.content;
72
+ e && !n.isFiller(e) && e !== s.lastSnapshot && (r.push({
73
+ kind: "snapshot",
74
+ run: l,
75
+ content: e
76
+ }), s = {
77
+ ...s,
78
+ lastSnapshot: e
79
+ }), r.push({
80
+ kind: "end",
81
+ run: l,
82
+ outcome: n.status === "error" ? "error" : "complete",
83
+ error: n.error ?? null
84
+ }), s = {
85
+ ...s,
86
+ startedRun: null,
87
+ lastEndedRunId: l.runId
88
+ };
89
+ }
90
+ return {
91
+ events: r,
92
+ state: s
93
+ };
94
+ }
95
+ //#endregion
96
+ export { t as IDLE_PREVIEW_STATE, n as nextPreviewEvents };
@@ -0,0 +1,121 @@
1
+ import { ReactNode } from 'react';
2
+ /**
3
+ * One logical run.
4
+ *
5
+ * ★★ `runId` is `${conversationId}:${messageId}`, and that pair is chosen
6
+ * because it is the only identity that SURVIVES THE INTERNAL RETRY. The
7
+ * assistant message id is minted once per turn (AssistantChatArea.tsx:995),
8
+ * outside `sendWithRealBackend` (:1079), which the failure path re-enters as
9
+ * `sendWithRealBackend(2)` (:1477) — and that retry swaps the sandbox id and
10
+ * the session id. A payload keyed on either would split one logical run in two,
11
+ * and a late callback from the first attempt could be mistaken for a new run.
12
+ */
13
+ export interface AssistantPreviewRun {
14
+ readonly runId: string;
15
+ readonly conversationId: string;
16
+ readonly messageId: string;
17
+ /**
18
+ * ★ The workspace as it was when the run STARTED, not as it is now.
19
+ * `getWorkspaceId()` reads the URL live and the panel survives in-app
20
+ * navigation, so re-deriving this per event would file a run's output under a
21
+ * workspace it never ran in.
22
+ */
23
+ readonly workspaceId: string | null;
24
+ }
25
+ /**
26
+ * ★★ SPOKEN TURNS ARE INCLUDED, deliberately. Voice and typed turns share one
27
+ * message array and are separated by `isVoiceTurn`, which every reader of the
28
+ * TRANSCRIPT applies (`turnVisibility.ts:83`, `useConversationTurns.ts:46`,
29
+ * `AssistantConversationList.tsx:13`, `exportConversation.ts:1`) so that spoken
30
+ * turns stay out of the typed thread.
31
+ *
32
+ * The preview is not a transcript. It follows whatever turn the assistant is
33
+ * running, and a spoken turn is a turn — filtering it would leave a product's
34
+ * surface frozen for the whole of a voice answer, which is worse than showing
35
+ * it. Stated here because the omission otherwise reads as an oversight next to
36
+ * four readers that all filter, and because a product wanting to distinguish
37
+ * modality will need a flag on this type: add one when a product actually needs
38
+ * it, rather than guessing the shape before there is a consumer.
39
+ */
40
+ /**
41
+ * ★★ `snapshot` REPLACES, it never appends. The orchestrator's poll loop
42
+ * rewrites the whole message content on every tick
43
+ * (AssistantChatArea.tsx:1329), so a consumer that appended would accumulate
44
+ * duplicates of the same answer. The `kind` says so at the type level rather
45
+ * than in a comment a consumer never reads.
46
+ */
47
+ export type AssistantPreviewEvent = {
48
+ kind: "start";
49
+ run: AssistantPreviewRun;
50
+ } | {
51
+ kind: "snapshot";
52
+ run: AssistantPreviewRun;
53
+ content: string;
54
+ } | {
55
+ kind: "end";
56
+ run: AssistantPreviewRun;
57
+ /**
58
+ * ★★ `abandoned` is not a failure and not a completion — it is a run the
59
+ * bridge can no longer follow. It covers a turn the user cancelled while
60
+ * a correction took over, a turn interrupted with nothing after it, and a
61
+ * conversation switched away from mid-turn. In every one of those the
62
+ * turn writes NO terminal status (`turnState.ts:70`), so without this
63
+ * outcome the run would simply never end and a preview would sit showing
64
+ * progress forever. The turn may or may not still be executing.
65
+ */
66
+ outcome: "complete" | "error" | "abandoned";
67
+ /**
68
+ * ★ NON-optional. Every terminal branch sets this — `complete` and
69
+ * `error` from the store, `abandoned` explicitly as null — so leaving it
70
+ * optional let a future branch omit it and hand a consumer `undefined`
71
+ * where it had been promised `null`. The type now enforces at compile
72
+ * time what the tests pin at runtime.
73
+ */
74
+ error: string | null;
75
+ };
76
+ /**
77
+ * ★★ KEEP THIS OBJECT STABLE across renders — memoise it, or hold it in a ref.
78
+ *
79
+ * Two things depend on it, and both fail quietly rather than loudly:
80
+ *
81
+ * - The bridge's effect depends on the controller. It deliberately does NOT
82
+ * reset its run state when the identity changes, precisely so that the
83
+ * natural `preview={{ render, onEvent }}` — a new object every render — does
84
+ * not re-announce `start` on every poll tick. The cost of that choice is that
85
+ * REPLACING one working controller with another mid-run leaves the newcomer
86
+ * without a `start` for the run already in flight. Swap controllers between
87
+ * runs, not during one.
88
+ *
89
+ * - `render()` is invoked inside a single `PreviewSurface` component, so its
90
+ * hooks belong to that component's fiber. Swapping in a renderer with a
91
+ * DIFFERENT hook layout while the overlay is open is the classic
92
+ * "rendered more hooks than during the previous render" error. Keep one
93
+ * renderer per mounted preview, and branch inside it rather than swapping it.
94
+ *
95
+ * Neither is enforced by the type system: a named function passed as a callback
96
+ * satisfies the hooks lint, so nothing warns.
97
+ */
98
+ export interface AssistantPreviewController {
99
+ /**
100
+ * The product's own preview surface. Returns JSX and is called during render,
101
+ * so it may use hooks like any component body.
102
+ *
103
+ * ★ It is rendered as an OVERLAY over a still-mounted chat area — never as an
104
+ * alternate view. Swapping the panel's body would unmount `AssistantChatArea`
105
+ * and take the voice session, the in-flight turn, draft attachments and the
106
+ * composer draft with it, while turn status lives on in the zustand store:
107
+ * split-brain rather than a clean stop.
108
+ */
109
+ render: () => ReactNode;
110
+ /**
111
+ * Run-scoped progress. Optional: a product may want the surface without the
112
+ * stream.
113
+ *
114
+ * ★ Non-blocking and error-contained by the bridge — a throwing observer must
115
+ * never disturb the assistant, and must never cause a retry.
116
+ */
117
+ onEvent?: (event: AssistantPreviewEvent) => void;
118
+ /** Toggle label. Product-neutral English fallback if omitted. */
119
+ label?: string;
120
+ }
121
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/preview/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC;;;;;;;;;;GAUG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED;;;;;;;;;;;;;;GAcG;AAEH;;;;;;GAMG;AACH,MAAM,MAAM,qBAAqB,GAC7B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,mBAAmB,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,GAAG,EAAE,mBAAmB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC/D;IACE,IAAI,EAAE,KAAK,CAAC;IACZ,GAAG,EAAE,mBAAmB,CAAC;IACzB;;;;;;;;OAQG;IACH,OAAO,EAAE,UAAU,GAAG,OAAO,GAAG,WAAW,CAAC;IAC5C;;;;;;OAMG;IACH,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAEN;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;;;;;;;OASG;IACH,MAAM,EAAE,MAAM,SAAS,CAAC;IAExB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAEjD,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
@@ -0,0 +1,3 @@
1
+ import { AssistantPreviewController } from './types';
2
+ export declare function useAssistantPreviewBridge(controller: AssistantPreviewController | null): void;
3
+ //# sourceMappingURL=useAssistantPreviewBridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAssistantPreviewBridge.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/preview/useAssistantPreviewBridge.ts"],"names":[],"mappings":"AAyCA,OAAO,KAAK,EAAE,0BAA0B,EAAyB,MAAM,SAAS,CAAC;AAyCjF,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,0BAA0B,GAAG,IAAI,GAC5C,IAAI,CAoKN"}
@@ -0,0 +1,71 @@
1
+ import { useAssistantTr as e } from "../i18n.js";
2
+ import { useAssistantStore as t } from "../store.js";
3
+ import { isStageCopy as n } from "../stageCopy.js";
4
+ import { getWorkspaceId as r } from "../context.js";
5
+ import { IDLE_PREVIEW_STATE as i, nextPreviewEvents as a } from "./previewTransitions.js";
6
+ import { useEffect as o, useRef as s } from "react";
7
+ //#region src/shared/assistant/preview/useAssistantPreviewBridge.ts
8
+ function c(e, t) {
9
+ try {
10
+ let n = e?.onEvent?.(t);
11
+ n && typeof n.then == "function" && Promise.resolve(n).catch((e) => {
12
+ console.error("[assistant] preview observer rejected", e);
13
+ });
14
+ } catch (e) {
15
+ console.error("[assistant] preview observer threw", e);
16
+ }
17
+ }
18
+ function l(l) {
19
+ let u = e(), d = t((e) => e.activeConversationId), f = t((e) => e.activeConversationId ? e.processingByConversationId[e.activeConversationId] : void 0), p = t((e) => {
20
+ let t = e.activeConversationId, n = t ? e.processingByConversationId[t]?.messageId : null;
21
+ return !t || !n ? null : e.conversations.find((e) => e.id === t)?.messages.find((e) => e.id === n)?.content ?? null;
22
+ }), m = s(i), h = s(null), g = s(null);
23
+ o(() => {
24
+ h.current = l;
25
+ }, [l]), o(() => () => {
26
+ let { events: e, state: t } = a(m.current, {
27
+ run: null,
28
+ conversationId: null,
29
+ status: "idle",
30
+ content: null,
31
+ isFiller: () => !1
32
+ });
33
+ m.current = t;
34
+ for (let t of e) c(h.current, t);
35
+ }, []), o(() => {
36
+ if (!l?.onEvent) {
37
+ m.current = i;
38
+ return;
39
+ }
40
+ let e = (e) => {
41
+ c(l, e);
42
+ }, t = f?.messageId ?? null, o = d && t ? {
43
+ runId: `${d}:${t}`,
44
+ conversationId: d,
45
+ messageId: t,
46
+ workspaceId: r() || null
47
+ } : null;
48
+ o && g.current?.runId !== o.runId && (g.current = {
49
+ runId: o.runId,
50
+ tr: u
51
+ });
52
+ let s = o ? g.current?.tr ?? u : u, { events: h, state: _ } = a(m.current, {
53
+ run: o,
54
+ conversationId: d,
55
+ status: f?.status ?? "idle",
56
+ content: p,
57
+ error: f?.error ?? null,
58
+ isFiller: (e) => n(s, e)
59
+ });
60
+ m.current = _;
61
+ for (let t of h) e(t);
62
+ }, [
63
+ l,
64
+ d,
65
+ f,
66
+ p,
67
+ u
68
+ ]);
69
+ }
70
+ //#endregion
71
+ export { l as useAssistantPreviewBridge };
@@ -2,6 +2,7 @@ import { FC } from 'react';
2
2
  import { PanelProps } from '../../plugins/types';
3
3
  import { WorkspaceWriteAccess } from '../useWorkspaceWriteAccess';
4
4
  import { AssistantNavigate } from './AssistantMarkdownRenderer';
5
+ import { AssistantPreviewController } from '../preview/types';
5
6
  export type AIAssistantPanelProps = PanelProps & {
6
7
  /** When provided, renders a dock/float toggle in the header. */
7
8
  docked?: boolean;
@@ -35,6 +36,13 @@ export type AIAssistantPanelProps = PanelProps & {
35
36
  * opens in a new tab.
36
37
  */
37
38
  connectSourceHref?: string;
39
+ /**
40
+ * An optional product preview surface, shown as an overlay over the chat.
41
+ *
42
+ * ★ Absence is the off-switch — no controller, no toggle, no overlay and no
43
+ * events. There is deliberately no second flag that could disagree with it.
44
+ */
45
+ preview?: AssistantPreviewController;
38
46
  };
39
47
  /**
40
48
  * The panel.
@@ -1 +1 @@
1
- {"version":3,"file":"AIAssistantPanel.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/ui/AIAssistantPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAU,KAAK,EAAE,EAAE,MAAM,OAAO,CAAC;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAMtD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAIvE,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,6BAA6B,CAAC;AAMrC,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG;IAC/C,gEAAgE;IAChE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,oBAAoB,CAAC;IACnC;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B;;;;;;;;;OASG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC,qBAAqB,CAgHtD,CAAC"}
1
+ {"version":3,"file":"AIAssistantPanel.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/ui/AIAssistantPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAU,KAAK,EAAE,EAAY,MAAM,OAAO,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAMtD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAIvE,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,6BAA6B,CAAC;AAQrC,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAGnE,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG;IAC/C,gEAAgE;IAChE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,oBAAoB,CAAC;IACnC;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B;;;;;;;;;OASG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,0BAA0B,CAAC;CACtC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC,qBAAqB,CAyMtD,CAAC"}