react-semaphor 0.1.548 → 0.1.550

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 (51) hide show
  1. package/dist/assistant-context/index.js +1 -1
  2. package/dist/brand-studio/index.js +1 -1
  3. package/dist/briefings/index.js +1 -1
  4. package/dist/chunks/{assistant-chat-DCcWsoGm.js → assistant-chat-ClAvjeNe.js} +1834 -1849
  5. package/dist/chunks/{custom-visual-inputs-BTRnwsfd.js → custom-visual-inputs-CwAcigQS.js} +1 -1
  6. package/dist/chunks/{dashboard-BZHL9a-z.js → dashboard-DDQgKoss.js} +1 -1
  7. package/dist/chunks/dashboard-briefing-launcher-CCYs8E4j.js +3844 -0
  8. package/dist/chunks/{dashboard-controls-BGoBTPS7.js → dashboard-controls-DfSkQBsk.js} +982 -935
  9. package/dist/chunks/{dashboard-json-iHPsdn3j.js → dashboard-json-BPhyn9pl.js} +2 -2
  10. package/dist/chunks/{document-dashboard-inputs-B2AqPfrq.js → document-dashboard-inputs-DPQ_wUGD.js} +2 -2
  11. package/dist/chunks/{edit-dashboard-visual-CLEFFf2T.js → edit-dashboard-visual-G7EmLuR0.js} +280 -280
  12. package/dist/chunks/{filter-reach-copy-ByzGadUk.js → filter-reach-copy-8vnDYToV.js} +95 -93
  13. package/dist/chunks/{global-date-filter-utils-CeeFJ1CP.js → global-date-filter-utils-CnumW4j2.js} +1656 -1651
  14. package/dist/chunks/{index-DeDHr3iz.js → index-DzsdV1o4.js} +3 -3
  15. package/dist/chunks/{raw-temporal-presentation-CrUM2I_o.js → raw-temporal-presentation-CBKeEPYA.js} +1 -1
  16. package/dist/chunks/report-preferences-dialog-D_fEDaS4.js +2261 -0
  17. package/dist/chunks/{resolve-dashboard-input-context-BmWF9hSl.js → resolve-dashboard-input-context-DVWF7p5C.js} +1 -1
  18. package/dist/chunks/{saved-dashboard-context-qtfzl9Eb.js → saved-dashboard-context-BMqMzNAo.js} +4 -4
  19. package/dist/chunks/{semaphor-ready-indicator-Ol6VcaR7.js → semaphor-ready-indicator-Bz5BxITW.js} +25406 -25106
  20. package/dist/chunks/{shelf-drop-preview-context-C2SEC3I9.js → shelf-drop-preview-context-B8kNwpWQ.js} +4 -4
  21. package/dist/chunks/{switch-CEBOR4n7.js → switch-wJP6O7ZT.js} +2 -2
  22. package/dist/chunks/{use-create-flow-overlay-state-CbGIjaVD.js → use-create-flow-overlay-state-RzJa7G8S.js} +3 -3
  23. package/dist/dashboard/index.js +1 -1
  24. package/dist/dashboard-authoring/index.js +7 -7
  25. package/dist/index.js +187 -172
  26. package/dist/live-channel/index.js +124 -0
  27. package/dist/style.css +1 -1
  28. package/dist/surfboard/index.js +1 -1
  29. package/dist/types/components/assistant/assistant-entry-points.d.ts +4 -1
  30. package/dist/types/components/dashboard/favorites/dashboard-favorite-toggle.d.ts +11 -0
  31. package/dist/types/components/dashboard/favorites/favorite-star-button.d.ts +16 -0
  32. package/dist/types/components/index.d.ts +8 -0
  33. package/dist/types/components/sharing-and-management/hooks/use-resource-management.d.ts +16 -0
  34. package/dist/types/components/surfboard/dashboard-plus.d.ts +1 -1
  35. package/dist/types/components/surfboard/toolbar/toolbar-context.d.ts +86 -0
  36. package/dist/types/components/surfboard/toolbar/toolbar-overflow.d.ts +14 -0
  37. package/dist/types/lib/dashboard-viewer/viewer-store-state.d.ts +7 -0
  38. package/dist/types/lib/hooks/use-dashboard-favorite.d.ts +24 -0
  39. package/dist/types/lib/hooks/use-dashboard-query.d.ts +2 -0
  40. package/dist/types/lib/hooks/use-default-dashboard-toggle.d.ts +12 -0
  41. package/dist/types/lib/stores/dashboard-store.d.ts +9 -0
  42. package/dist/types/lib/types/common-types.d.ts +26 -1
  43. package/dist/types/live-channel.d.ts +2 -0
  44. package/dist/types/shared/assistant-protocol/parts.d.ts +11 -0
  45. package/dist/types/shared/dashboard-authoring/changes/dashboard-change.d.ts +14 -44
  46. package/dist/types/shared/dashboard-viewer/viewer-contract.d.ts +18 -0
  47. package/dist/types/shared/live-channel/index.d.ts +1 -0
  48. package/dist/types/shared/live-channel/live-channel-contract.d.ts +126 -0
  49. package/package.json +5 -1
  50. package/dist/chunks/dashboard-briefing-launcher-DML-cAzB.js +0 -3734
  51. package/dist/chunks/report-preferences-dialog-CM7kXmXp.js +0 -1977
@@ -1,4 +1,4 @@
1
- import { a, R as s, D as o } from "../chunks/report-preferences-dialog-CM7kXmXp.js";
1
+ import { a, R as s, D as o } from "../chunks/report-preferences-dialog-D_fEDaS4.js";
2
2
  import { C as f, E as D } from "../chunks/table-settings-WysCBj62.js";
3
3
  export {
4
4
  f as CONTROL_CARD_DEFAULT_VALUE,
@@ -3,7 +3,10 @@ import { AssistantLayout } from '../../shared/assistant-protocol/conversation.js
3
3
  export type AssistantPanelSurface = 'dashboard' | 'none';
4
4
  /** Where the panel shows now: the viewer's layout, or beside the asked-about card (Phase 10, D10-1). */
5
5
  export type AssistantPlacement = AssistantLayout | 'beside-card';
6
- /** Opens and closes the panel. Named after the assistant; no other wording. */
6
+ /**
7
+ * Opens and closes the panel. Named after the assistant; no other wording.
8
+ * Below a wide toolbar it keeps its place as an icon (responsive toolbars).
9
+ */
7
10
  export declare function AssistantToolbarButton(): import("react").JSX.Element | null;
8
11
  /**
9
12
  * The panel. Beside a dashboard (`surface="dashboard"`), the chat mounts on
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The open dashboard's favorite star for a toolbar (dashboard favorites,
3
+ * FAV-D14, FAV-D17). Access and the server's `isFavorite` come from the
4
+ * dashboard's viewer state; this viewer's own writes win over it (the
5
+ * favorites store, ledger R-05). Nothing for a session that saves nothing (no
6
+ * person in the token, or a PDF render), a read-only star while signed in as
7
+ * someone else. Mounted in this package's toolbar and in the app's own toolbar.
8
+ */
9
+ export declare function DashboardFavoriteToggle({ dashboardId }: {
10
+ dashboardId: string;
11
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,16 @@
1
+ /** Shown on a read-only star: the session is signed in as someone else (FAV-D3). */
2
+ export declare const FAVORITES_READ_ONLY_MESSAGE = "Favorites can't be changed while you're signed in as someone else.";
3
+ /**
4
+ * The one favorite star (dashboard favorites, FAV-D13): monochrome, an outline
5
+ * in muted ink when off, filled with foreground ink when on. On rows it shows
6
+ * on hover or keyboard focus and stays visible once on.
7
+ */
8
+ export declare function FavoriteStarButton({ isFavorite, onToggle, readOnly, pending, variant, className, }: {
9
+ isFavorite: boolean;
10
+ onToggle: () => void;
11
+ readOnly?: boolean;
12
+ pending?: boolean;
13
+ /** `row`: hub and list rows, revealed on hover. `toolbar`: always shown. */
14
+ variant?: 'row' | 'toolbar';
15
+ className?: string;
16
+ }): import("react").JSX.Element;
@@ -37,6 +37,14 @@ export { AssistantProvider } from './assistant/assistant-provider.js';
37
37
  export { AssistantPanel, AssistantToolbarButton } from './assistant/assistant-entry-points.js';
38
38
  export { ArrangeLayoutButton } from './surfboard/arrange-layout-button.js';
39
39
  export { ScreenSizePreviewButton } from './surfboard/screen-size-preview-button.js';
40
+ export { DashboardFavoriteToggle } from './dashboard/favorites/dashboard-favorite-toggle.js';
41
+ export { FavoriteStarButton, FAVORITES_READ_ONLY_MESSAGE, } from './dashboard/favorites/favorite-star-button.js';
42
+ export { ToolbarOverflowAnchorSlot, ToolbarProvider } from './surfboard/toolbar/toolbar-overflow.js';
43
+ export { TOOLBAR_LG_MIN, TOOLBAR_MD_MIN, fitsToolbar, toolbarWidthFor, useMeasuredToolbarWidth, useToolbarItem, useToolbarOverflowItems, useToolbarWidth, } from './surfboard/toolbar/toolbar-context.js';
44
+ export type { ToolbarOverflowItem, ToolbarTier, ToolbarWidth, } from './surfboard/toolbar/toolbar-context.js';
45
+ export { useDefaultDashboardToggle } from '../lib/hooks/use-default-dashboard-toggle.js';
46
+ export { useDashboardFavorite } from '../lib/hooks/use-dashboard-favorite.js';
47
+ export type { DashboardFavorites } from '../lib/hooks/use-dashboard-favorite.js';
40
48
  export type { AssistantPanelSurface } from './assistant/assistant-entry-points.js';
41
49
  export { useAssistant } from './assistant/use-assistant.js';
42
50
  export * from '../lib/types/common-types.js';
@@ -1,6 +1,7 @@
1
1
  import { ResourceType, ShareRole, ShareScope } from '../utils/types.js';
2
2
  import { TDashboard, TFrame } from '../../../lib/types/index.js';
3
3
  import { AppearanceSpec } from '../../../lib/appearance/index.js';
4
+ import { DashboardListViewer } from '../../../shared/dashboard-viewer/index.js';
4
5
  export interface ResourceListItem {
5
6
  id: string;
6
7
  title: string;
@@ -38,6 +39,9 @@ export interface ResourceListItem {
38
39
  email: string;
39
40
  };
40
41
  };
42
+ /** Dashboard lists only (dashboard favorites, FAV-D5); absent from older servers, read as false. */
43
+ isFavorite?: boolean;
44
+ favoritedAt?: string | null;
41
45
  }
42
46
  export interface CreateResourceRequest {
43
47
  title: string;
@@ -115,6 +119,10 @@ export declare function useResourceUpdateState(): {
115
119
  export declare function useResourceManagement(resourceType: ResourceType, onDeleteSuccess?: () => void, onCreateSuccess?: (data?: any) => void): {
116
120
  resources: any;
117
121
  organizationAppearance: AppearanceSpec | null;
122
+ /** When the list arrived (client clock, ms); favorites resolve against it (FAV-D20). */
123
+ listFetchedAt: number;
124
+ /** Dashboard lists: whether this session can change favorites (FAV-D18). */
125
+ listViewer: DashboardListViewer | null;
118
126
  isLoading: boolean;
119
127
  isError: boolean;
120
128
  isFetching: boolean;
@@ -152,6 +160,10 @@ export declare function useResourceManagement(resourceType: ResourceType, onDele
152
160
  export declare function useDashboardManagement(onDeleteSuccess?: () => void, onCreateSuccess?: (data?: any) => void): {
153
161
  resources: any;
154
162
  organizationAppearance: AppearanceSpec | null;
163
+ /** When the list arrived (client clock, ms); favorites resolve against it (FAV-D20). */
164
+ listFetchedAt: number;
165
+ /** Dashboard lists: whether this session can change favorites (FAV-D18). */
166
+ listViewer: DashboardListViewer | null;
155
167
  isLoading: boolean;
156
168
  isError: boolean;
157
169
  isFetching: boolean;
@@ -189,6 +201,10 @@ export declare function useDashboardManagement(onDeleteSuccess?: () => void, onC
189
201
  export declare function useVisualManagement(onDeleteSuccess?: () => void, onCreateSuccess?: (data?: any) => void): {
190
202
  resources: any;
191
203
  organizationAppearance: AppearanceSpec | null;
204
+ /** When the list arrived (client clock, ms); favorites resolve against it (FAV-D20). */
205
+ listFetchedAt: number;
206
+ /** Dashboard lists: whether this session can change favorites (FAV-D18). */
207
+ listViewer: DashboardListViewer | null;
192
208
  isLoading: boolean;
193
209
  isError: boolean;
194
210
  isFetching: boolean;
@@ -3,5 +3,5 @@ type DashboardPlusProps = {
3
3
  showControls?: boolean;
4
4
  showFooter?: boolean;
5
5
  } & DashboardProps;
6
- export declare function DashboardPlus({ showControls, showFooter, ...rest }: DashboardPlusProps): import("react").JSX.Element;
6
+ export declare function DashboardPlus({ showControls, showFooter, liveScreen, ...rest }: DashboardPlusProps): import("react").JSX.Element;
7
7
  export {};
@@ -0,0 +1,86 @@
1
+ import { ReactNode } from 'react';
2
+ /**
3
+ * Responsive dashboard toolbars (design: semaphor-app `/design/responsive-toolbars`).
4
+ *
5
+ * Both toolbars, this package's and the app's navbar, follow one rule set. A
6
+ * toolbar measures its own width (an embed lives in a host column of any
7
+ * size, so the viewport says nothing). Every item has a tier: `always`, `md`
8
+ * (shown from 640px of toolbar) or `lg` (from 960px). As the toolbar narrows,
9
+ * labels collapse to icons first, then an item below its tier stops rendering
10
+ * its button and registers its menu form here, which the toolbar's existing
11
+ * ⋯ menu renders in toolbar order. A `menu` item lives in ⋯ at every width.
12
+ * Editing controls cannot move, so their group scrolls when it still does not
13
+ * fit, and ⋯ stays in view.
14
+ *
15
+ * Outside a toolbar (for example the Activity bell on the Briefings page) the
16
+ * context reads as `lg` with no menu, so every control renders as before.
17
+ */
18
+ export type ToolbarWidth = 'sm' | 'md' | 'lg';
19
+ export type ToolbarTier = 'always' | 'md' | 'lg' | 'menu';
20
+ /** Toolbar widths (px) where the `md` and `lg` tiers start. */
21
+ export declare const TOOLBAR_MD_MIN = 640;
22
+ export declare const TOOLBAR_LG_MIN = 960;
23
+ export declare function toolbarWidthFor(px: number): ToolbarWidth;
24
+ /** Whether an item of `tier` shows its button at `width`. */
25
+ export declare function fitsToolbar(tier: ToolbarTier, width: ToolbarWidth): boolean;
26
+ /** The menu form an item registers while its button does not fit. */
27
+ export type ToolbarOverflowItem = {
28
+ readonly id: string;
29
+ readonly label: string;
30
+ readonly icon?: ReactNode;
31
+ /** A short right-aligned note: a count, a current value. */
32
+ readonly hint?: string;
33
+ /** Shown as a check, for a toggle. */
34
+ readonly checked?: boolean;
35
+ /** Toolbar order, so the menu lists moved items as the toolbar did. */
36
+ readonly order: number;
37
+ readonly onSelect: () => void;
38
+ };
39
+ export type ToolbarContextValue = {
40
+ readonly width: ToolbarWidth;
41
+ /** Inside a toolbar that has a ⋯ menu for moved items. */
42
+ readonly hasOverflowMenu: boolean;
43
+ readonly overflowItems: readonly ToolbarOverflowItem[];
44
+ register(item: ToolbarOverflowItem): () => void;
45
+ /** Which moved control's popover is open from the menu. */
46
+ readonly openOverflowId: string | null;
47
+ setOpenOverflowId(id: string | null): void;
48
+ /** Beside the ⋯ button: where a moved control anchors its popover. */
49
+ readonly anchorSlot: HTMLElement | null;
50
+ setAnchorSlot(element: HTMLElement | null): void;
51
+ };
52
+ export declare const ToolbarContext: import('react').Context<ToolbarContextValue>;
53
+ /**
54
+ * Measures an element's width: pass `measure` as the element's `ref`. Starts
55
+ * at `lg` so a wide first paint never jumps.
56
+ */
57
+ export declare function useMeasuredToolbarWidth<T extends HTMLElement>(): {
58
+ measure: (element: T | null) => void;
59
+ width: ToolbarWidth;
60
+ };
61
+ /** The toolbar's width (`lg` outside a toolbar). */
62
+ export declare function useToolbarWidth(): ToolbarWidth;
63
+ /** The moved items, for a toolbar's ⋯ menu. */
64
+ export declare function useToolbarOverflowItems(): readonly ToolbarOverflowItem[];
65
+ /**
66
+ * One toolbar item. `collapsed` means it should not render its button. While
67
+ * collapsed and `menu` is given, its menu form is registered. Popover controls
68
+ * use `popoverOpen` and `setPopoverOpen`: from the menu they open anchored at
69
+ * the ⋯ menu, which is where the item now lives.
70
+ */
71
+ export declare function useToolbarItem(id: string, tier: ToolbarTier, menu?: Omit<ToolbarOverflowItem, 'id' | 'onSelect'> & {
72
+ /** Defaults to opening the item's popover from the menu. */
73
+ readonly onSelect?: () => void;
74
+ /**
75
+ * Runs when the menu opens the item's popover. Radix calls `onOpenChange`
76
+ * only for its own trigger, not when the `open` prop changes, so work a
77
+ * control does on open (Activity marks finished work seen) goes here too.
78
+ */
79
+ readonly onOpen?: () => void;
80
+ }): {
81
+ collapsed: boolean;
82
+ popoverOpen: boolean;
83
+ setPopoverOpen(open: boolean): void;
84
+ /** Where to portal a collapsed popover's anchor (`null` outside a toolbar). */
85
+ anchorSlot: HTMLElement | null;
86
+ };
@@ -0,0 +1,14 @@
1
+ import { ReactNode } from 'react';
2
+ import { ToolbarWidth } from './toolbar-context.js';
3
+ /** Wraps one toolbar: its width, and the moved items its ⋯ menu renders. */
4
+ export declare function ToolbarProvider({ width, hasOverflowMenu, children, }: {
5
+ width: ToolbarWidth;
6
+ /** False while the toolbar shows no ⋯ menu: then nothing moves into one. */
7
+ hasOverflowMenu?: boolean;
8
+ children: ReactNode;
9
+ }): import("react").JSX.Element;
10
+ /**
11
+ * Place right before the toolbar's ⋯ button: a moved control's popover
12
+ * anchors here, so it opens under the menu it was chosen from.
13
+ */
14
+ export declare function ToolbarOverflowAnchorSlot(): import("react").JSX.Element;
@@ -18,6 +18,13 @@ export type DashboardViewerState = {
18
18
  /** Live table settings per card. Never written into `card.config` or `tablePrefs`. */
19
19
  readonly tableSettings: Readonly<Record<string, ViewerTableSettings>>;
20
20
  readonly notices: readonly ViewerNotice[];
21
+ /**
22
+ * The server's answer from the dashboard's viewer payload (FAV-D17). Read
23
+ * through the favorites store, where this viewer's later writes win.
24
+ */
25
+ readonly isFavorite: boolean;
26
+ /** When the dashboard response this state came from arrived (client clock, ms; 0 when unknown). */
27
+ readonly fetchedAt: number;
21
28
  };
22
29
  /** Session-only until the dashboard load says otherwise (TECH-SPEC 7). */
23
30
  export declare const INITIAL_DASHBOARD_VIEWER_STATE: DashboardViewerState;
@@ -0,0 +1,24 @@
1
+ export type SetDashboardFavoriteInput = {
2
+ readonly dashboardId: string;
3
+ readonly isFavorite: boolean;
4
+ };
5
+ export type DashboardFavorites = {
6
+ /**
7
+ * What to show: this viewer's write while in flight or newer than the
8
+ * server data, else the server's value. `serverFetchedAt` is when that data
9
+ * arrived (client clock, ms).
10
+ */
11
+ isFavorite(dashboardId: string, serverIsFavorite: boolean, serverFetchedAt?: number): boolean;
12
+ /** A write for this dashboard is waiting for the server. */
13
+ isPending(dashboardId: string): boolean;
14
+ /** Resolves true when the server saved it; false after it was put back. */
15
+ setFavorite(input: SetDashboardFavoriteInput): Promise<boolean>;
16
+ };
17
+ /**
18
+ * Dashboard favorites for the viewer the token names (FAV-D15). Reads and
19
+ * writes go through one viewer-scoped store (`dashboard-favorites-store.ts`);
20
+ * server responses are read as they are and never edited, so a cached list or
21
+ * dashboard response cannot disagree with a write made since (ledger R-01,
22
+ * R-02, R-05).
23
+ */
24
+ export declare function useDashboardFavorite(): DashboardFavorites;
@@ -6,6 +6,8 @@ export declare function useDashboardQuery(): {
6
6
  organizationAppearance?: import('../types/index.js').AppearanceSpec | null;
7
7
  viewer?: import('../types/index.js').DashboardViewerPayload;
8
8
  } | null | undefined;
9
+ /** When `data` arrived (client clock, ms); dashboard favorites read it (FAV-D20). */
10
+ dataUpdatedAt: number;
9
11
  isLoading: boolean;
10
12
  isFetching: boolean;
11
13
  isError: boolean;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The viewer's default dashboard, as one ⋯ menu item in both dashboard
3
+ * toolbars (responsive toolbars: the DEFAULT chip and house button left the
4
+ * toolbar). The hub list keeps its Default chip.
5
+ */
6
+ export declare function useDefaultDashboardToggle(dashboardId: string | null | undefined): {
7
+ available: boolean;
8
+ isDefault: boolean;
9
+ /** True until the preference has loaded, and while a change is saving. */
10
+ disabled: boolean;
11
+ toggle(): void;
12
+ };
@@ -154,6 +154,13 @@ export type DashboardStore = {
154
154
  * replacement of the document but a proposal's own Undo, clears them.
155
155
  */
156
156
  appliedProposals: AppliedProposal[];
157
+ /**
158
+ * Advances each time an edit session ends: leaving edit mode (Cancel,
159
+ * close) or a successful Save that stays in edit mode. Save keeps the
160
+ * dashboard object (P7-27), so identity alone can't mark it; a live screen
161
+ * drops every kept copy here (embedded live changes LC-D14).
162
+ */
163
+ editSessionEpoch: number;
157
164
  /** The last toolbar Arrange, for its Undo. Cleared by any dashboard load, leaving edit mode, or a successful undo (responsive layouts SPEC §6.4). */
158
165
  lastArrange?: LastArrange;
159
166
  isVisualEditing: boolean;
@@ -420,6 +427,8 @@ type Actions = {
420
427
  removeFrame: (sheetId: string, frameId: string) => void;
421
428
  removeCard: (sheetId: string, card: TCard) => void;
422
429
  setIsDashboardEditing: (editing: boolean) => void;
430
+ /** The toolbar's Save succeeded: the edit session's changes are saved (LC-D14). */
431
+ markDashboardSaved: () => void;
423
432
  /**
424
433
  * Applies an assistant proposal to the dashboard on screen (spec 8.1,
425
434
  * D7-18, D7-27): only while the dashboard is still `basedOn`, checked and
@@ -15,6 +15,7 @@ import { DashboardAIContext } from './ai-context-types.js';
15
15
  import { CardInteractionConfig, InteractionTargetOverride } from './interaction-types.js';
16
16
  import { SemanticExecutionPayload } from './semantic-runtime-types.js';
17
17
  import { ReportRuntimeContext } from '../../shared/report-runtime-context/index.js';
18
+ import { LiveScreenPort } from '../../shared/live-channel/index.js';
18
19
  import { CsvEncoding } from '../../shared/format-utils/exporters/csv-utils.js';
19
20
  import { PresentationExecutionSnapshot, TemporalInputPresentation } from '../../shared/format-utils/index.js';
20
21
  import { JSX } from 'react';
@@ -285,6 +286,12 @@ export type DashboardProps = {
285
286
  onEvent?: (event: TEvent) => void;
286
287
  /** Receives dashboard editing lifecycle transitions from the shared runtime. */
287
288
  onDashboardLifecycleEvent?: (event: DashboardLifecycleEvent) => void;
289
+ /**
290
+ * Makes this dashboard a live screen: an agent's changes arrive through the
291
+ * port and land unsaved, with Undo in a one-line note (embedded live changes
292
+ * LC-D31). Only Semaphor's embed page passes it.
293
+ */
294
+ liveScreen?: LiveScreenPort;
288
295
  onSave?: (dashboard: TDashboard) => void;
289
296
  onFilterValuesChange?: (filterValues: TFilterValue[]) => void;
290
297
  LoadingComponent?: (props: LoadingProps) => React.ReactNode;
@@ -1578,13 +1585,31 @@ export type TEvent = {
1578
1585
  type: 'success' | 'error' | 'info' | 'warning';
1579
1586
  message: any;
1580
1587
  };
1581
- /** Supported lifecycle transitions emitted by an editable dashboard session. */
1588
+ /**
1589
+ * Supported lifecycle transitions emitted by an editable dashboard session:
1590
+ * its unsaved state, and an assistant's change applied on a live screen or
1591
+ * undone from its note (embedded live changes LC-D13).
1592
+ */
1582
1593
  export type DashboardLifecycleEvent = {
1583
1594
  type: 'dashboard:dirty-state';
1584
1595
  dashboardId: string;
1585
1596
  payload: {
1586
1597
  dirty: boolean;
1587
1598
  };
1599
+ } | {
1600
+ type: 'dashboard:change-applied';
1601
+ dashboardId: string;
1602
+ payload: {
1603
+ deliveryId: string;
1604
+ summary: string[];
1605
+ };
1606
+ } | {
1607
+ type: 'dashboard:change-undone';
1608
+ dashboardId: string;
1609
+ payload: {
1610
+ deliveryId: string;
1611
+ summary: string[];
1612
+ };
1588
1613
  };
1589
1614
  /**
1590
1615
  * Style for the dashboard
@@ -0,0 +1,2 @@
1
+ export * from './shared/live-channel/index.js'
2
+ export {}
@@ -82,12 +82,23 @@ export type AssistantStagePart = {
82
82
  stageId: string;
83
83
  label: string;
84
84
  state: 'live' | 'done' | 'skipped';
85
+ /**
86
+ * What kind of work the step does, for its icon: the server picks it with
87
+ * the label, from the same table. Absent on a step with no kind of its own
88
+ * and on turns stored before it.
89
+ */
90
+ activity?: AssistantStepActivity;
85
91
  /**
86
92
  * A step that changes the dashboard on screen (Phase 7): what the model
87
93
  * wrote before it is the answer, not a working note (P7-23, P7-45).
88
94
  */
89
95
  change?: true;
90
96
  };
97
+ /**
98
+ * Finding what to use, reading it, running an analysis or SQL, changing the
99
+ * dashboard, or working out another way after a step failed.
100
+ */
101
+ export type AssistantStepActivity = 'find' | 'read' | 'analyze' | 'sql' | 'change' | 'retry';
91
102
  /**
92
103
  * Where one answer's time and tokens went (spec 3.9, AG-D25). The server
93
104
  * sends it only to people who may see it (a development server, a super
@@ -7821,56 +7821,26 @@ export type ProposeChangeCaller = {
7821
7821
  generate: boolean;
7822
7822
  /** The SQL query form. */
7823
7823
  sql: boolean;
7824
+ /**
7825
+ * A session that changes the dashboard on the user's screen (a live token,
7826
+ * Semaphor's own assistant): it changes only the open dashboard, in place,
7827
+ * so `saveAs`, `preview` and `domainId` are not offered and, since the schema
7828
+ * is strict, are refused if sent (embedded live changes LC-D17).
7829
+ */
7830
+ onScreen: boolean;
7824
7831
  };
7825
7832
  /**
7826
7833
  * The propose tool's input for one caller (DE-INV-7, design rule 5): only the
7827
7834
  * changes and query forms this caller may use. `shape` is what an MCP tool
7828
- * registers; `schema` parses a call.
7835
+ * registers; `schema` parses a call. This is the one place that decides what
7836
+ * on-screen propose accepts (LC-D17).
7829
7837
  */
7830
7838
  export declare function buildProposeChangeInputSchema(caller: ProposeChangeCaller): {
7831
- shape: {
7832
- projectId: z.ZodOptional<z.ZodString>;
7833
- dashboardId: z.ZodOptional<z.ZodString>;
7834
- domainId: z.ZodOptional<z.ZodString>;
7835
- changes: z.ZodArray<z.ZodDiscriminatedUnion<"op", [z.ZodDiscriminatedUnionOption<"op">, ...z.ZodDiscriminatedUnionOption<"op">[]]>, "many">;
7836
- saveAs: z.ZodOptional<z.ZodEnum<["original", "copy"]>>;
7837
- preview: z.ZodOptional<z.ZodEnum<["sample", "rows", "none"]>>;
7838
- include: z.ZodOptional<z.ZodArray<z.ZodLiteral<"outline">, "many">>;
7839
- rationale: z.ZodOptional<z.ZodString>;
7840
- };
7841
- schema: z.ZodObject<{
7842
- projectId: z.ZodOptional<z.ZodString>;
7843
- dashboardId: z.ZodOptional<z.ZodString>;
7844
- domainId: z.ZodOptional<z.ZodString>;
7845
- changes: z.ZodArray<z.ZodDiscriminatedUnion<"op", [z.ZodDiscriminatedUnionOption<"op">, ...z.ZodDiscriminatedUnionOption<"op">[]]>, "many">;
7846
- saveAs: z.ZodOptional<z.ZodEnum<["original", "copy"]>>;
7847
- preview: z.ZodOptional<z.ZodEnum<["sample", "rows", "none"]>>;
7848
- include: z.ZodOptional<z.ZodArray<z.ZodLiteral<"outline">, "many">>;
7849
- rationale: z.ZodOptional<z.ZodString>;
7850
- }, "strict", z.ZodTypeAny, {
7851
- changes: {
7852
- [x: string]: any;
7853
- op?: unknown;
7854
- }[];
7855
- domainId?: string | undefined;
7856
- dashboardId?: string | undefined;
7857
- projectId?: string | undefined;
7858
- saveAs?: "original" | "copy" | undefined;
7859
- preview?: "rows" | "none" | "sample" | undefined;
7860
- include?: "outline"[] | undefined;
7861
- rationale?: string | undefined;
7862
- }, {
7863
- changes: {
7864
- [x: string]: any;
7865
- op?: unknown;
7866
- }[];
7867
- domainId?: string | undefined;
7868
- dashboardId?: string | undefined;
7869
- projectId?: string | undefined;
7870
- saveAs?: "original" | "copy" | undefined;
7871
- preview?: "rows" | "none" | "sample" | undefined;
7872
- include?: "outline"[] | undefined;
7873
- rationale?: string | undefined;
7839
+ shape: z.ZodRawShape;
7840
+ schema: z.ZodObject<z.ZodRawShape, "strict", z.ZodTypeAny, {
7841
+ [x: string]: any;
7842
+ }, {
7843
+ [x: string]: any;
7874
7844
  }>;
7875
7845
  };
7876
7846
  export type ProposeChangeInput = {
@@ -63,6 +63,24 @@ export type DashboardViewerPayload = {
63
63
  readonly teamScope?: 'tenant' | 'organization';
64
64
  readonly canPublish: boolean;
65
65
  };
66
+ /**
67
+ * Whether the person has favorited this dashboard (dashboard favorites,
68
+ * FAV-D17). Read with the rest of the preference row; `false` for
69
+ * session-only access.
70
+ */
71
+ readonly isFavorite: boolean;
72
+ };
73
+ /**
74
+ * The dashboard list's top-level `viewer` (`GET /api/management/v1/dashboards`,
75
+ * FAV-D18): whether the person the token names can change favorites.
76
+ */
77
+ export type DashboardListViewer = Pick<DashboardViewerPayload, 'access' | 'accessReason'>;
78
+ /** `PUT` and `DELETE /api/management/v1/dashboards/{id}/favorite` (FAV-D4). */
79
+ export type DashboardFavoriteState = {
80
+ readonly dashboardId: string;
81
+ readonly isFavorite: boolean;
82
+ /** ISO 8601; `null` when not a favorite. */
83
+ readonly favoritedAt: string | null;
66
84
  };
67
85
  /**
68
86
  * How many saved bookmarks and remembered table settings reference each part
@@ -0,0 +1 @@
1
+ export * from './live-channel-contract.js';
@@ -0,0 +1,126 @@
1
+ import { TDashboard } from '../../lib/types/common-types.js';
2
+ import { DashboardOperation, OperationContext } from '../dashboard-authoring/operations/operation-types.js';
3
+ /**
4
+ * The live channel's shared contract (embedded live changes LC-D30, SPEC.md
5
+ * section 2): what travels between Semaphor's server and a live screen (the
6
+ * embedded dashboard), what agents hear back, and every timing. Pure and
7
+ * server-safe; semaphor-app imports it as `react-semaphor/live-channel`, and
8
+ * nothing else in either repo declares these types (LC-INV-30).
9
+ *
10
+ * Every value crossing the wire is parsed by its validator on receipt, on
11
+ * both sides; a value that fails is dropped (an event) or refused 400 (a
12
+ * POST), never half-used (C-1).
13
+ */
14
+ /** Always the first event on a connection. */
15
+ export type ConnectedEvent = {
16
+ type: 'connected';
17
+ connectionId: string;
18
+ };
19
+ export type ScreenCopyRequest = {
20
+ type: 'copy_request';
21
+ requestId: string;
22
+ /** The dashboard the call asked for. */
23
+ dashboardId: string;
24
+ };
25
+ export type ScreenDelivery = {
26
+ type: 'delivery';
27
+ deliveryId: string;
28
+ /** The revision it was built on. */
29
+ revisionId: string;
30
+ proposalId: string;
31
+ operations: DashboardOperation[];
32
+ context: OperationContext;
33
+ /** Propose's summary sentences. */
34
+ summary: string[];
35
+ /** Positive; the screen never writes after receipt plus this. */
36
+ applyWithinMs: number;
37
+ };
38
+ export type LiveChannelEvent = ConnectedEvent | ScreenCopyRequest | ScreenDelivery;
39
+ export type ScreenCopyAnswer = {
40
+ kind: 'uploaded';
41
+ screenId: string;
42
+ requestId: string;
43
+ revisionId: string;
44
+ dashboard: TDashboard;
45
+ };
46
+ export type ScreenOutcome = {
47
+ status: 'applied';
48
+ } | {
49
+ status: 'not_applied';
50
+ reason: 'dashboard_changed' | 'not_editable' | 'refused' | 'expired';
51
+ message: string;
52
+ };
53
+ export type DeliveryOutcomeReport = {
54
+ screenId: string;
55
+ deliveryId: string;
56
+ outcome: ScreenOutcome;
57
+ };
58
+ /**
59
+ * A delivery ends when propose returns (plan revision 20): the screen's
60
+ * report, or `not_confirmed` when none came within the outcome wait. The
61
+ * dashboard on screen is the truth; the agent reads it again to see whether
62
+ * the change is there.
63
+ */
64
+ export type DeliveryOutcome = ScreenOutcome | {
65
+ status: 'not_confirmed';
66
+ };
67
+ export type LiveDelivery = {
68
+ deliveryId: string;
69
+ outcome: DeliveryOutcome;
70
+ };
71
+ export type LiveScreenState = {
72
+ eligible: boolean;
73
+ dashboardId?: string;
74
+ };
75
+ /**
76
+ * What the embed page hands the dashboard (LC-D31): semaphor-app owns the
77
+ * transport behind it; react-semaphor's dashboard owns the screen state.
78
+ */
79
+ export type LiveScreenPort = {
80
+ /** UUID v4, made once per page load. */
81
+ screenId: string;
82
+ setScreenState(state: LiveScreenState): void;
83
+ subscribe(listener: (event: ScreenCopyRequest | ScreenDelivery) => void): () => void;
84
+ /** Once, no retry: the server's wait is short. */
85
+ answerCopyRequest(answer: ScreenCopyAnswer): Promise<void>;
86
+ /** Once, no retry: a report that doesn't arrive is `not_confirmed`. */
87
+ reportOutcome(report: DeliveryOutcomeReport): Promise<void>;
88
+ };
89
+ export declare const LIVE_CHANNEL_TIMINGS: {
90
+ readonly heartbeatMs: 25000;
91
+ /** A screen's record expires this long after its last heartbeat: it is gone. */
92
+ readonly heartbeatExpiryMs: 75000;
93
+ readonly hiddenTabGraceMs: 120000;
94
+ /** Then the last value repeatedly. */
95
+ readonly reconnectBackoffMs: readonly [0, 1000, 2000, 5000];
96
+ /** One per call. */
97
+ readonly copyAnswerWaitMs: 3000;
98
+ readonly outcomeWaitMs: 8000;
99
+ /** applyWithinMs = the outcome wait less this. */
100
+ readonly applyMarginMs: 1000;
101
+ /** A copy answer or an outcome is kept this long past its call's wait. */
102
+ readonly replyRetentionMs: 30000;
103
+ /** Distinct screens; a sixth gets 429. */
104
+ readonly connectionsPerToken: 5;
105
+ };
106
+ /** The shape of the timings; tests pass shorter ones. */
107
+ export type LiveChannelTimings = {
108
+ readonly [K in keyof typeof LIVE_CHANNEL_TIMINGS]: (typeof LIVE_CHANNEL_TIMINGS)[K] extends readonly number[] ? readonly number[] : number;
109
+ };
110
+ export type Parsed<T> = {
111
+ ok: true;
112
+ value: T;
113
+ } | {
114
+ ok: false;
115
+ problem: string;
116
+ };
117
+ /** A screen id: a UUID v4. */
118
+ export declare function isScreenId(value: unknown): value is string;
119
+ export declare function parseLiveChannelEvent(eventName: string, data: string): Parsed<LiveChannelEvent>;
120
+ export declare function parseScreenCopyAnswer(body: unknown, query: {
121
+ screenId: string;
122
+ requestId: string;
123
+ }): Parsed<ScreenCopyAnswer>;
124
+ export declare function parseDeliveryOutcomeReport(body: unknown): Parsed<DeliveryOutcomeReport>;
125
+ /** A screen's outcome, as reported and as stored. */
126
+ export declare function parseScreenOutcome(value: unknown): ScreenOutcome | null;
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "email": "support@semaphor.cloud"
6
6
  },
7
7
  "license": "MIT",
8
- "version": "0.1.548",
8
+ "version": "0.1.550",
9
9
  "description": "Fully interactive and customizable dashboards for your apps.",
10
10
  "keywords": [
11
11
  "react",
@@ -92,6 +92,10 @@
92
92
  "types": "./dist/types/activity.d.ts",
93
93
  "import": "./dist/activity/index.js"
94
94
  },
95
+ "./live-channel": {
96
+ "types": "./dist/types/live-channel.d.ts",
97
+ "import": "./dist/live-channel/index.js"
98
+ },
95
99
  "./briefings": {
96
100
  "types": "./dist/types/briefings.d.ts",
97
101
  "import": "./dist/briefings/index.js"