@calliopelabs/ui 0.13.0 → 0.16.0

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 (115) hide show
  1. package/README.md +192 -4
  2. package/dist/agent/AgentChat.d.ts +63 -0
  3. package/dist/agent/AgentChat.js +117 -0
  4. package/dist/agent/AgentLauncher.d.ts +25 -0
  5. package/dist/agent/AgentLauncher.js +25 -0
  6. package/dist/agent/AgentProvider.d.ts +82 -0
  7. package/dist/agent/AgentProvider.js +176 -0
  8. package/dist/agent/CalliopeAgent.d.ts +43 -0
  9. package/dist/agent/CalliopeAgent.js +111 -0
  10. package/dist/agent/WorkflowRenderers.d.ts +61 -0
  11. package/dist/agent/WorkflowRenderers.js +102 -0
  12. package/dist/agent/controller.d.ts +167 -0
  13. package/dist/agent/controller.js +496 -0
  14. package/dist/agent/copilotkit/CopilotKitAgentProvider.d.ts +41 -0
  15. package/dist/agent/copilotkit/CopilotKitAgentProvider.js +145 -0
  16. package/dist/agent/copilotkit/index.d.ts +6 -0
  17. package/dist/agent/copilotkit/index.js +6 -0
  18. package/dist/agent/engine.d.ts +41 -0
  19. package/dist/agent/engine.js +93 -0
  20. package/dist/agent/index.d.ts +17 -0
  21. package/dist/agent/index.js +17 -0
  22. package/dist/agent/mock.d.ts +56 -0
  23. package/dist/agent/mock.js +143 -0
  24. package/dist/agent/renderers.d.ts +49 -0
  25. package/dist/agent/renderers.js +27 -0
  26. package/dist/agent/surface.d.ts +30 -0
  27. package/dist/agent/surface.js +90 -0
  28. package/dist/agent/tool.d.ts +98 -0
  29. package/dist/agent/tool.js +81 -0
  30. package/dist/appearance/brands.d.ts +31 -12
  31. package/dist/appearance/brands.js +32 -51
  32. package/dist/chat/AgentProgress.d.ts +19 -0
  33. package/dist/chat/AgentProgress.js +34 -0
  34. package/dist/chat/Composer.d.ts +31 -0
  35. package/dist/chat/Composer.js +44 -0
  36. package/dist/chat/MessageBubble.d.ts +23 -0
  37. package/dist/chat/MessageBubble.js +26 -0
  38. package/dist/chat/MessageList.d.ts +43 -0
  39. package/dist/chat/MessageList.js +71 -0
  40. package/dist/chat/ModelPicker.d.ts +17 -0
  41. package/dist/chat/ModelPicker.js +13 -0
  42. package/dist/chat/ToolCallCard.d.ts +27 -0
  43. package/dist/chat/ToolCallCard.js +52 -0
  44. package/dist/chat/model.d.ts +123 -0
  45. package/dist/chat/model.js +337 -0
  46. package/dist/chat/patch.d.ts +12 -0
  47. package/dist/chat/patch.js +149 -0
  48. package/dist/chat/useAgUiRun.d.ts +52 -0
  49. package/dist/chat/useAgUiRun.js +137 -0
  50. package/dist/css/appearance.js +1 -1
  51. package/dist/css/calliope.css +5 -0
  52. package/dist/css/tokens.css +5 -0
  53. package/dist/index.d.ts +15 -1
  54. package/dist/index.js +16 -1
  55. package/dist/primitives/Badge.d.ts +14 -0
  56. package/dist/primitives/Badge.js +25 -0
  57. package/dist/primitives/Button.d.ts +1 -1
  58. package/dist/primitives/ContextMenu.d.ts +18 -0
  59. package/dist/primitives/ContextMenu.js +34 -0
  60. package/dist/primitives/ScrollArea.d.ts +16 -0
  61. package/dist/primitives/ScrollArea.js +11 -0
  62. package/dist/primitives/Toast.d.ts +37 -0
  63. package/dist/primitives/Toast.js +43 -0
  64. package/dist/primitives/Tooltip.d.ts +16 -0
  65. package/dist/primitives/Tooltip.js +26 -0
  66. package/dist/provider/messages.d.ts +135 -0
  67. package/dist/provider/messages.js +131 -0
  68. package/dist/theme/css-layer.js +2 -1
  69. package/dist/theme/mappings/palette.d.ts +52 -0
  70. package/dist/theme/mappings/palette.js +208 -0
  71. package/dist/theme/mappings/render.d.ts +9 -0
  72. package/dist/theme/mappings/render.js +520 -0
  73. package/dist/theme/mappings/targets.d.ts +43 -0
  74. package/dist/theme/mappings/targets.js +222 -0
  75. package/dist/theme/tokens.d.ts +10 -9
  76. package/dist/theme/tokens.generated.d.ts +356 -0
  77. package/dist/theme/tokens.generated.js +360 -0
  78. package/dist/theme/tokens.js +20 -264
  79. package/dist/tokens/README.jupyterlab.md +125 -0
  80. package/dist/tokens/README.md +15 -0
  81. package/dist/tokens/README.native.md +29 -0
  82. package/dist/tokens/README.plain.md +84 -0
  83. package/dist/tokens/README.python.md +33 -0
  84. package/dist/tokens/README.vscode.md +114 -0
  85. package/dist/tokens/jupyterlab.css +1710 -0
  86. package/dist/tokens/plain.css +930 -0
  87. package/dist/tokens/tokens.native.d.ts +85 -0
  88. package/dist/tokens/tokens.native.js +773 -0
  89. package/dist/tokens/tokens.py +1043 -0
  90. package/dist/tokens/vscode.css +1138 -0
  91. package/dist/workbench/FileBrowser.d.ts +62 -0
  92. package/dist/workbench/FileBrowser.js +117 -0
  93. package/dist/workbench/FileGrid.d.ts +13 -0
  94. package/dist/workbench/FileGrid.js +114 -0
  95. package/dist/workbench/FileIcon.d.ts +10 -0
  96. package/dist/workbench/FileIcon.js +24 -0
  97. package/dist/workbench/FileList.d.ts +35 -0
  98. package/dist/workbench/FileList.js +160 -0
  99. package/dist/workbench/FilePreview.d.ts +66 -0
  100. package/dist/workbench/FilePreview.js +108 -0
  101. package/dist/workbench/FileTree.d.ts +37 -0
  102. package/dist/workbench/FileTree.js +218 -0
  103. package/dist/workbench/UploadDropzone.d.ts +52 -0
  104. package/dist/workbench/UploadDropzone.js +115 -0
  105. package/dist/workbench/dnd.d.ts +17 -0
  106. package/dist/workbench/dnd.js +77 -0
  107. package/dist/workbench/index.d.ts +16 -0
  108. package/dist/workbench/index.js +16 -0
  109. package/dist/workbench/model.d.ts +72 -0
  110. package/dist/workbench/model.js +214 -0
  111. package/dist/workbench/selection.d.ts +16 -0
  112. package/dist/workbench/selection.js +46 -0
  113. package/dist/workbench/typeahead.d.ts +15 -0
  114. package/dist/workbench/typeahead.js +22 -0
  115. package/package.json +39 -2
@@ -0,0 +1,43 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { XIcon } from "lucide-react";
4
+ import { Toast as ToastPrimitive } from "radix-ui";
5
+ import * as React from "react";
6
+ import { cn } from "../lib/cn.js";
7
+ import { useUI } from "../provider/UIProvider.js";
8
+ import { StatusDot } from "../status/StatusDot.js";
9
+ const ToastContext = React.createContext(null);
10
+ /**
11
+ * Transient notices, bottom right, on Radix Toast: they pause on hover and
12
+ * focus, F8 jumps to them, and swiping or Escape closes one. Wrap the app
13
+ * once and call `useToast().toast(...)` anywhere under it.
14
+ */
15
+ export function ToastProvider({ children, duration = 5000, className }) {
16
+ const { messages } = useUI();
17
+ const [toasts, setToasts] = React.useState([]);
18
+ const counter = React.useRef(0);
19
+ const api = React.useMemo(() => ({
20
+ toast: (options) => {
21
+ const id = options.id ?? `toast-${++counter.current}`;
22
+ setToasts((list) => {
23
+ const entry = { ...options, id };
24
+ return list.some((t) => t.id === id)
25
+ ? list.map((t) => (t.id === id ? entry : t))
26
+ : [...list, entry];
27
+ });
28
+ return id;
29
+ },
30
+ dismiss: (id) => setToasts((list) => list.filter((t) => t.id !== id)),
31
+ }), []);
32
+ return (_jsx(ToastContext.Provider, { value: api, children: _jsxs(ToastPrimitive.Provider, { duration: duration, label: messages.toast.region, children: [children, toasts.map((t) => (_jsxs(ToastPrimitive.Root, { "data-slot": "toast", "data-tone": t.tone, open: true, duration: t.duration, type: t.tone === "error" ? "foreground" : "background", onOpenChange: (open) => {
33
+ if (!open)
34
+ api.dismiss(t.id);
35
+ }, className: "pointer-events-auto relative flex w-full items-start gap-2.5 rounded-lg bg-popover p-3 pr-9 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 data-[state=open]:animate-cui-fade-in data-[swipe=end]:translate-x-(--radix-toast-swipe-end-x) data-[swipe=move]:translate-x-(--radix-toast-swipe-move-x)", children: [t.tone && _jsx(StatusDot, { tone: t.tone, className: "mt-1.5" }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [_jsx(ToastPrimitive.Title, { className: "font-medium [overflow-wrap:anywhere]", children: t.title }), t.description && (_jsx(ToastPrimitive.Description, { className: "[overflow-wrap:anywhere] text-muted-foreground", children: t.description })), t.action && (_jsx(ToastPrimitive.Action, { altText: t.action.altText, onClick: t.action.onClick, className: "mt-1 w-fit rounded-lg text-sm font-medium text-primary underline-offset-4 outline-none hover:underline focus-visible:ring-2 focus-visible:ring-ring/50", children: t.action.label }))] }), _jsx(ToastPrimitive.Close, { "aria-label": messages.toast.close, className: "absolute top-2 right-2 inline-flex size-6 items-center justify-center rounded-lg text-muted-foreground outline-none hover:bg-accent hover:text-accent-foreground focus-visible:ring-2 focus-visible:ring-ring/50", children: _jsx(XIcon, { className: "size-3.5", "aria-hidden": true }) })] }, t.id))), _jsx(ToastPrimitive.Viewport, { "data-slot": "toast-viewport", className: cn("fixed right-0 bottom-0 z-50 m-0 flex w-full max-w-sm list-none flex-col gap-2 p-4 outline-none", className) })] }) }));
36
+ }
37
+ /** The toast API of the nearest ToastProvider. Throws outside one, so a missing provider is loud. */
38
+ export function useToast() {
39
+ const api = React.useContext(ToastContext);
40
+ if (!api)
41
+ throw new Error("useToast needs a ToastProvider above it");
42
+ return api;
43
+ }
@@ -0,0 +1,16 @@
1
+ import { Tooltip as TooltipPrimitive } from "radix-ui";
2
+ import type * as React from "react";
3
+ /**
4
+ * Shares one open delay across the tooltips under it. A Tooltip outside a
5
+ * provider makes its own, so the provider is optional; an app with many
6
+ * icon buttons wraps its shell once.
7
+ */
8
+ export declare function TooltipProvider({ delayDuration, ...props }: React.ComponentProps<typeof TooltipPrimitive.Provider>): React.JSX.Element;
9
+ /**
10
+ * A short hint on hover and keyboard focus. It names nothing: an icon-only
11
+ * control still needs its own `aria-label`; the tooltip repeats it for
12
+ * sighted pointer users.
13
+ */
14
+ export declare function Tooltip(props: React.ComponentProps<typeof TooltipPrimitive.Root>): React.JSX.Element;
15
+ export declare function TooltipTrigger(props: React.ComponentProps<typeof TooltipPrimitive.Trigger>): React.JSX.Element;
16
+ export declare function TooltipContent({ className, sideOffset, children, ...props }: React.ComponentProps<typeof TooltipPrimitive.Content>): React.JSX.Element;
@@ -0,0 +1,26 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { Tooltip as TooltipPrimitive } from "radix-ui";
4
+ import { cn } from "../lib/cn.js";
5
+ /**
6
+ * Shares one open delay across the tooltips under it. A Tooltip outside a
7
+ * provider makes its own, so the provider is optional; an app with many
8
+ * icon buttons wraps its shell once.
9
+ */
10
+ export function TooltipProvider({ delayDuration = 300, ...props }) {
11
+ return (_jsx(TooltipPrimitive.Provider, { "data-slot": "tooltip-provider", delayDuration: delayDuration, ...props }));
12
+ }
13
+ /**
14
+ * A short hint on hover and keyboard focus. It names nothing: an icon-only
15
+ * control still needs its own `aria-label`; the tooltip repeats it for
16
+ * sighted pointer users.
17
+ */
18
+ export function Tooltip(props) {
19
+ return (_jsx(TooltipProvider, { children: _jsx(TooltipPrimitive.Root, { "data-slot": "tooltip", ...props }) }));
20
+ }
21
+ export function TooltipTrigger(props) {
22
+ return _jsx(TooltipPrimitive.Trigger, { "data-slot": "tooltip-trigger", ...props });
23
+ }
24
+ export function TooltipContent({ className, sideOffset = 4, children, ...props }) {
25
+ return (_jsx(TooltipPrimitive.Portal, { children: _jsx(TooltipPrimitive.Content, { "data-slot": "tooltip-content", sideOffset: sideOffset, className: cn("z-50 w-fit max-w-xs origin-(--radix-tooltip-content-transform-origin) rounded-lg bg-foreground px-2 py-1 text-xs text-balance text-background data-[state=delayed-open]:animate-cui-fade-in", className), ...props, children: children }) }));
26
+ }
@@ -1,4 +1,6 @@
1
1
  import type { ProductTheme } from "../appearance/product.js";
2
+ import type { ChatRole, ChatRunStatus, ChatToolCallStatus } from "../chat/model.js";
3
+ import type { UploadState } from "../workbench/model.js";
2
4
  import type { WorkflowQuestionState } from "../workflow/question.js";
3
5
  import type { WorkflowAction, WorkflowAvailability, WorkflowScope, WorkflowStatus } from "../workflow/model.js";
4
6
  import type { ArtifactStatus, GateStatus, ReviewDecision, ReviewVerdict, RunStageStatus } from "../workflow/run.js";
@@ -102,6 +104,66 @@ export interface Messages {
102
104
  dialog: {
103
105
  close: string;
104
106
  };
107
+ workbench: {
108
+ /** The file browser's name. */
109
+ files: string;
110
+ /** The folder tree's name. */
111
+ folders: string;
112
+ /** The root directory in the breadcrumb. */
113
+ root: string;
114
+ /** The breadcrumb's landmark name. */
115
+ location: string;
116
+ /** A listing's accessible name: "Files in reports". */
117
+ filesIn: (folder: string) => string;
118
+ view: string;
119
+ listView: string;
120
+ gridView: string;
121
+ name: string;
122
+ size: string;
123
+ modified: string;
124
+ /** Read for a folder's or an unknown size's dash. */
125
+ noSize: string;
126
+ loading: string;
127
+ loadFailed: string;
128
+ retry: string;
129
+ /** A tree folder whose children failed to load; activating it retries. */
130
+ retryFolder: string;
131
+ empty: string;
132
+ emptyDescription: string;
133
+ noFolders: string;
134
+ itemCount: (count: number) => string;
135
+ selected: (count: number) => string;
136
+ /** The overlay while files from the desktop hover over the browser. */
137
+ dropToUpload: string;
138
+ dropHere: string;
139
+ browse: string;
140
+ maxSize: (size: string) => string;
141
+ /** The upload list's name. */
142
+ uploads: string;
143
+ uploading: (count: number) => string;
144
+ uploadsDone: string;
145
+ uploadState: (state: UploadState) => string;
146
+ cancelUpload: (name: string) => string;
147
+ dismissUpload: (name: string) => string;
148
+ previewOf: (name: string) => string;
149
+ previewLoading: string;
150
+ previewFailed: string;
151
+ noPreview: string;
152
+ closePreview: string;
153
+ /** A text preview's scrolling region. */
154
+ contentsOf: (name: string) => string;
155
+ /** A truncated preview: "Showing 100 of 4,210 rows". */
156
+ showing: (shown: number, total: number | null) => string;
157
+ partial: string;
158
+ /** A CSV column with no header. */
159
+ column: (index: number) => string;
160
+ noRows: string;
161
+ };
162
+ toast: {
163
+ /** The notifications region; Radix fills `{hotkey}` with the shortcut that focuses it. */
164
+ region: string;
165
+ close: string;
166
+ };
105
167
  confirm: {
106
168
  confirm: string;
107
169
  cancel: string;
@@ -550,6 +612,79 @@ export interface Messages {
550
612
  /** A field extraction found nothing in. */
551
613
  empty: string;
552
614
  };
615
+ chat: {
616
+ /** The message list's name. */
617
+ conversation: string;
618
+ empty: string;
619
+ emptyDescription: string;
620
+ /** Who said it: "You", "Assistant", "System", "Developer", "Tool". */
621
+ role: (role: ChatRole) => string;
622
+ /** A message's accessible name. */
623
+ messageFrom: (speaker: string) => string;
624
+ /** An answer that has started but has no text yet. */
625
+ thinking: string;
626
+ /** Read after a message still being written. */
627
+ writing: string;
628
+ jumpToLatest: string;
629
+ runFailed: string;
630
+ retry: string;
631
+ /** The composer's field. */
632
+ composer: string;
633
+ placeholder: string;
634
+ composerHint: string;
635
+ send: string;
636
+ stop: string;
637
+ attachments: string;
638
+ /** A tool call's accessible name. */
639
+ toolCall: (name: string) => string;
640
+ toolStatus: (status: ChatToolCallStatus | "approval") => string;
641
+ details: string;
642
+ arguments: string;
643
+ noArguments: string;
644
+ result: string;
645
+ toolError: string;
646
+ approvalNeeded: string;
647
+ approve: string;
648
+ deny: string;
649
+ approveTitle: (name: string) => string;
650
+ approveDescription: string;
651
+ denyTitle: (name: string) => string;
652
+ denyDescription: string;
653
+ denyReason: string;
654
+ /** The agent progress section's name. */
655
+ progress: string;
656
+ steps: string;
657
+ runStatus: (status: ChatRunStatus) => string;
658
+ model: string;
659
+ };
660
+ agent: {
661
+ /** The assistant's name: the panel's title and the launcher's. Takes the product's name when there is one. */
662
+ title: (product?: string) => string;
663
+ /** The launcher's name when closed and open. */
664
+ open: (title: string) => string;
665
+ close: string;
666
+ /** Read with the launcher's name: "2 unread". */
667
+ unread: (count: number) => string;
668
+ newConversation: string;
669
+ expand: string;
670
+ restore: string;
671
+ /** The suggestion chips' group. */
672
+ suggestions: string;
673
+ emptyTitle: string;
674
+ emptyDescription: string;
675
+ /** Under the composer while a tool waits on the person. */
676
+ waitingOnYou: string;
677
+ /** The shortcut as people read it, from the key list ("⌘/", "Ctrl+/"). */
678
+ shortcut: (keys: string) => string;
679
+ /** A question from the agent that is not a tool call. */
680
+ interrupt: string;
681
+ decline: string;
682
+ back: string;
683
+ /** Answers an artifact's form review. */
684
+ sendReview: string;
685
+ /** The shared state's section. */
686
+ sharedState: string;
687
+ };
553
688
  }
554
689
  export declare const defaultMessages: Messages;
555
690
  /** Any subset of the messages, one level deep. */
@@ -236,6 +236,61 @@ export const defaultMessages = {
236
236
  dialog: {
237
237
  close: "Close",
238
238
  },
239
+ workbench: {
240
+ files: "Files",
241
+ folders: "Folders",
242
+ root: "Home",
243
+ location: "Location",
244
+ filesIn: (folder) => `Files in ${folder}`,
245
+ view: "View",
246
+ listView: "List",
247
+ gridView: "Grid",
248
+ name: "Name",
249
+ size: "Size",
250
+ modified: "Modified",
251
+ noSize: "No size",
252
+ loading: "Loading files",
253
+ loadFailed: "Could not load this folder",
254
+ retry: "Retry",
255
+ retryFolder: "Could not load. Retry",
256
+ empty: "This folder is empty",
257
+ emptyDescription: "Drop files here to upload them.",
258
+ noFolders: "No folders",
259
+ itemCount: (count) => `${count.toLocaleString()} ${count === 1 ? "item" : "items"}`,
260
+ selected: (count) => `${count.toLocaleString()} selected`,
261
+ dropToUpload: "Drop files to upload",
262
+ dropHere: "Drop files here",
263
+ browse: "Choose files",
264
+ maxSize: (size) => `Up to ${size} each`,
265
+ uploads: "Uploads",
266
+ uploading: (count) => `Uploading ${count.toLocaleString()} ${count === 1 ? "file" : "files"}`,
267
+ uploadsDone: "Uploads finished",
268
+ uploadState: (state) => ({
269
+ queued: "Waiting",
270
+ uploading: "Uploading",
271
+ done: "Done",
272
+ error: "Failed",
273
+ canceled: "Cancelled",
274
+ })[state],
275
+ cancelUpload: (name) => `Cancel upload of ${name}`,
276
+ dismissUpload: (name) => `Clear ${name}`,
277
+ previewOf: (name) => `Preview of ${name}`,
278
+ previewLoading: "Loading preview",
279
+ previewFailed: "Could not preview this file",
280
+ noPreview: "No preview for this file",
281
+ closePreview: "Close preview",
282
+ contentsOf: (name) => `Contents of ${name}`,
283
+ showing: (shown, total) => total === null
284
+ ? `Showing the first ${shown.toLocaleString()}`
285
+ : `Showing ${shown.toLocaleString()} of ${total.toLocaleString()}`,
286
+ partial: "Showing the start of the file",
287
+ column: (index) => `Column ${index}`,
288
+ noRows: "No rows",
289
+ },
290
+ toast: {
291
+ region: "Notifications ({hotkey})",
292
+ close: "Dismiss notification",
293
+ },
239
294
  confirm: {
240
295
  confirm: "Confirm",
241
296
  cancel: "Cancel",
@@ -781,6 +836,82 @@ export const defaultMessages = {
781
836
  cancel: "Cancel",
782
837
  empty: "Nothing found",
783
838
  },
839
+ chat: {
840
+ conversation: "Conversation",
841
+ empty: "No messages yet",
842
+ emptyDescription: "Ask a question to start.",
843
+ role: (role) => ({
844
+ user: "You",
845
+ assistant: "Assistant",
846
+ system: "System",
847
+ developer: "Developer",
848
+ tool: "Tool",
849
+ })[role],
850
+ messageFrom: (speaker) => `Message from ${speaker}`,
851
+ thinking: "Thinking",
852
+ writing: "Still writing",
853
+ jumpToLatest: "Jump to latest",
854
+ runFailed: "The run failed",
855
+ retry: "Retry",
856
+ composer: "Message",
857
+ placeholder: "Ask anything",
858
+ composerHint: "Enter to send, Shift+Enter for a new line.",
859
+ send: "Send",
860
+ stop: "Stop",
861
+ attachments: "Attachments",
862
+ toolCall: (name) => `Tool call ${name}`,
863
+ toolStatus: (status) => ({
864
+ streaming: "preparing",
865
+ running: "running",
866
+ complete: "done",
867
+ failed: "failed",
868
+ cancelled: "cancelled",
869
+ approval: "needs approval",
870
+ })[status],
871
+ details: "Details",
872
+ arguments: "Arguments",
873
+ noArguments: "No arguments",
874
+ result: "Result",
875
+ toolError: "Error",
876
+ approvalNeeded: "The agent is waiting for your approval to run this.",
877
+ approve: "Approve",
878
+ deny: "Deny",
879
+ approveTitle: (name) => `Run ${name}?`,
880
+ approveDescription: "The agent runs it with the arguments shown and continues.",
881
+ denyTitle: (name) => `Deny ${name}?`,
882
+ denyDescription: "The agent does not run it and is told why.",
883
+ denyReason: "Reason",
884
+ progress: "Agent progress",
885
+ steps: "Steps",
886
+ runStatus: (status) => ({
887
+ idle: "idle",
888
+ running: "running",
889
+ finished: "finished",
890
+ interrupted: "waiting for you",
891
+ cancelled: "stopped",
892
+ error: "failed",
893
+ })[status],
894
+ model: "Model",
895
+ },
896
+ agent: {
897
+ title: (product) => (product ? `${product} assistant` : "Assistant"),
898
+ open: (title) => `Open ${title}`,
899
+ close: "Close",
900
+ unread: (count) => `${count.toLocaleString("en")} unread`,
901
+ newConversation: "New conversation",
902
+ expand: "Expand",
903
+ restore: "Restore",
904
+ suggestions: "Suggestions",
905
+ emptyTitle: "How can I help?",
906
+ emptyDescription: "Ask about what is on this page, or pick a starting point.",
907
+ waitingOnYou: "Answer the card above to continue.",
908
+ shortcut: (keys) => `Shortcut ${keys}`,
909
+ interrupt: "The agent is waiting for you",
910
+ decline: "Decline",
911
+ back: "Back",
912
+ sendReview: "Send review",
913
+ sharedState: "Shared state",
914
+ },
784
915
  };
785
916
  export function mergeMessages(overrides) {
786
917
  if (!overrides)
@@ -1,5 +1,5 @@
1
1
  import { BOOT_SOURCE, bootConfig } from "../appearance/boot.js";
2
- import { astroliftBrand, chatStudioBrand, cykickBrand, loadrBrand, workbenchBrand, zentinelleBrand, } from "../appearance/brands.js";
2
+ import { astroliftBrand, chatStudioBrand, cykickBrand, deepDataAgentBrand, loadrBrand, workbenchBrand, zentinelleBrand, } from "../appearance/brands.js";
3
3
  import { CORNERS, defineProduct } from "../appearance/product.js";
4
4
  import { accentDeclarations, block, renderThemeCss } from "./css.js";
5
5
  /**
@@ -16,6 +16,7 @@ export const CSS_LAYER_PRODUCTS = [
16
16
  chatStudioBrand,
17
17
  loadrBrand,
18
18
  cykickBrand,
19
+ deepDataAgentBrand,
19
20
  ].map((config) => defineProduct(config));
20
21
  const TOKENS_HEADER = `/*
21
22
  * @calliopelabs/ui CSS layer: tokens.
@@ -0,0 +1,52 @@
1
+ import { ACCENT_KEYS, DEFAULT_ACCENT, GROUNDS, GROUND_KEYS, type FamilyAccent, type Ground, type StatusName } from "../tokens.js";
2
+ export declare const COLOR_TOKENS: readonly ["background", "foreground", "card", "card-foreground", "popover", "popover-foreground", "primary", "primary-foreground", "secondary", "secondary-foreground", "muted", "muted-foreground", "accent", "accent-foreground", "destructive", "border", "input", "ring", "chart-1", "chart-2", "chart-3", "chart-4", "chart-5", "sidebar", "sidebar-foreground", "sidebar-primary", "sidebar-primary-foreground", "sidebar-accent", "sidebar-accent-foreground", "sidebar-border", "sidebar-ring", "sidebar-muted-foreground", "surface-0", "surface-1", "surface-2", ...(StatusName | "success-fg" | "warning-fg" | "info-fg" | "danger-fg" | "success-bg" | "warning-bg" | "info-bg" | "danger-bg" | "success-border" | "warning-border" | "info-border" | "danger-border")[]];
3
+ export type ColorToken = (typeof COLOR_TOKENS)[number];
4
+ export type Palette = Record<ColorToken, string>;
5
+ export { ACCENT_KEYS, DEFAULT_ACCENT, GROUNDS, GROUND_KEYS };
6
+ export type { FamilyAccent, Ground };
7
+ /** The ground `:root` paints when nothing chooses one (the preset's default). */
8
+ export declare const DEFAULT_GROUND: Ground;
9
+ /**
10
+ * The type stacks of the preset (`--font-sans`, `--font-mono`, `--font-head`
11
+ * in preset.css; a test holds them equal). Each names the app's loaded font
12
+ * variable first, then the family, then system fallbacks.
13
+ */
14
+ export declare const FONTS: {
15
+ readonly sans: "var(--font-plex-sans, \"IBM Plex Sans\"), system-ui, sans-serif";
16
+ readonly mono: "var(--font-plex-mono, \"IBM Plex Mono\"), ui-monospace, SFMono-Regular, Menlo, monospace";
17
+ readonly head: "var(--font-dm-sans, \"DM Sans\"), system-ui, sans-serif";
18
+ };
19
+ /** The family a stack names, for targets that take one font name (React Native). */
20
+ export declare function fontFamily(stack: string): string;
21
+ /** `--radius` in px, and the motion durations in ms, as numbers. */
22
+ export declare function staticNumbers(): {
23
+ radius: number;
24
+ motion: Record<"fast" | "base" | "slow", number>;
25
+ };
26
+ export interface Rgba {
27
+ r: number;
28
+ g: number;
29
+ b: number;
30
+ a: number;
31
+ }
32
+ /** Parses `#rrggbb` or `rgba(r, g, b, a)`; anything else is a token this module does not know. */
33
+ export declare function parseColor(value: string): Rgba;
34
+ /**
35
+ * A translucent token laid on its surface, for targets with no alpha
36
+ * (a terminal, Tk): `sidebar-*` tokens on the sidebar, the rest on the
37
+ * background. Opaque tokens come back as they are.
38
+ */
39
+ export declare function flatten(palette: Palette, token: ColorToken): Rgba;
40
+ /** The concrete palette of one ground with one family accent, with no product brand. */
41
+ export declare function resolvePalette(ground: Ground, accent?: FamilyAccent): Palette;
42
+ /** Every ground with every family accent. */
43
+ export declare function allPalettes(): Record<Ground, Record<FamilyAccent, Palette>>;
44
+ /**
45
+ * A target's values split for compact output: per ground, the entries every
46
+ * accent agrees on, and per ground and accent, the entries that move with
47
+ * the accent.
48
+ */
49
+ export declare function splitByAccent<K extends string, V>(values: (ground: Ground, accent: FamilyAccent) => Record<K, V>): {
50
+ ground: Record<Ground, Partial<Record<K, V>>>;
51
+ accent: Record<Ground, Record<FamilyAccent, Partial<Record<K, V>>>>;
52
+ };
@@ -0,0 +1,208 @@
1
+ import { ACCENTS, ACCENT_KEYS, DEFAULT_ACCENT, GROUNDS, GROUND_KEYS, MODE_TOKENS, STATIC_TOKENS, SURFACES, } from "../tokens.js";
2
+ /**
3
+ * The palette a page paints on one ground with one family accent, as
4
+ * concrete colours: what the preset's custom properties compute to on that
5
+ * page with no product brand set. Every token mapping (JupyterLab, VS Code,
6
+ * Python, React Native, plain CSS) is generated from this, and a test holds
7
+ * it to the preset's own cascade.
8
+ *
9
+ * Values are `#rrggbb` or `rgba(r, g, b, a)`. The preset's one colour
10
+ * function, `color-mix(in oklab, var(--primary) N%, transparent)`, is the
11
+ * primary at alpha N% (mixing with transparent only scales alpha), so it is
12
+ * written that way here.
13
+ */
14
+ const STATUS_NAMES = ["success", "warning", "info", "danger"];
15
+ export const COLOR_TOKENS = [
16
+ "background",
17
+ "foreground",
18
+ "card",
19
+ "card-foreground",
20
+ "popover",
21
+ "popover-foreground",
22
+ "primary",
23
+ "primary-foreground",
24
+ "secondary",
25
+ "secondary-foreground",
26
+ "muted",
27
+ "muted-foreground",
28
+ "accent",
29
+ "accent-foreground",
30
+ "destructive",
31
+ "border",
32
+ "input",
33
+ "ring",
34
+ "chart-1",
35
+ "chart-2",
36
+ "chart-3",
37
+ "chart-4",
38
+ "chart-5",
39
+ "sidebar",
40
+ "sidebar-foreground",
41
+ "sidebar-primary",
42
+ "sidebar-primary-foreground",
43
+ "sidebar-accent",
44
+ "sidebar-accent-foreground",
45
+ "sidebar-border",
46
+ "sidebar-ring",
47
+ "sidebar-muted-foreground",
48
+ "surface-0",
49
+ "surface-1",
50
+ "surface-2",
51
+ ...STATUS_NAMES.flatMap((name) => [name, `${name}-fg`, `${name}-bg`, `${name}-border`]),
52
+ ];
53
+ export { ACCENT_KEYS, DEFAULT_ACCENT, GROUNDS, GROUND_KEYS };
54
+ /** The ground `:root` paints when nothing chooses one (the preset's default). */
55
+ export const DEFAULT_GROUND = "black";
56
+ /**
57
+ * The type stacks of the preset (`--font-sans`, `--font-mono`, `--font-head`
58
+ * in preset.css; a test holds them equal). Each names the app's loaded font
59
+ * variable first, then the family, then system fallbacks.
60
+ */
61
+ export const FONTS = {
62
+ sans: 'var(--font-plex-sans, "IBM Plex Sans"), system-ui, sans-serif',
63
+ mono: 'var(--font-plex-mono, "IBM Plex Mono"), ui-monospace, SFMono-Regular, Menlo, monospace',
64
+ head: 'var(--font-dm-sans, "DM Sans"), system-ui, sans-serif',
65
+ };
66
+ /** The family a stack names, for targets that take one font name (React Native). */
67
+ export function fontFamily(stack) {
68
+ const name = /"([^"]+)"/.exec(stack)?.[1];
69
+ if (!name)
70
+ throw new Error(`no family in ${stack}`);
71
+ return name;
72
+ }
73
+ /** `--radius` in px, and the motion durations in ms, as numbers. */
74
+ export function staticNumbers() {
75
+ const n = (value, unit) => {
76
+ if (!value?.endsWith(unit))
77
+ throw new Error(`expected ${unit}: ${value}`);
78
+ return Number(value.slice(0, -unit.length));
79
+ };
80
+ return {
81
+ radius: n(STATIC_TOKENS.radius, "px"),
82
+ motion: {
83
+ fast: n(STATIC_TOKENS["motion-fast"], "ms"),
84
+ base: n(STATIC_TOKENS["motion-base"], "ms"),
85
+ slow: n(STATIC_TOKENS["motion-slow"], "ms"),
86
+ },
87
+ };
88
+ }
89
+ /** Parses `#rrggbb` or `rgba(r, g, b, a)`; anything else is a token this module does not know. */
90
+ export function parseColor(value) {
91
+ const hex = /^#([0-9a-f]{6})$/i.exec(value);
92
+ if (hex) {
93
+ const n = parseInt(hex[1] ?? "", 16);
94
+ return { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255, a: 1 };
95
+ }
96
+ const fn = /^rgba\((\d+), (\d+), (\d+), ([0-9.]+)\)$/.exec(value);
97
+ if (fn)
98
+ return { r: Number(fn[1]), g: Number(fn[2]), b: Number(fn[3]), a: Number(fn[4]) };
99
+ throw new Error(`unsupported colour ${value}`);
100
+ }
101
+ const rgbaString = ({ r, g, b, a }) => `rgba(${r}, ${g}, ${b}, ${a})`;
102
+ /**
103
+ * A translucent token laid on its surface, for targets with no alpha
104
+ * (a terminal, Tk): `sidebar-*` tokens on the sidebar, the rest on the
105
+ * background. Opaque tokens come back as they are.
106
+ */
107
+ export function flatten(palette, token) {
108
+ const top = parseColor(palette[token]);
109
+ if (top.a === 1)
110
+ return top;
111
+ const base = parseColor(palette[token.startsWith("sidebar-") ? "sidebar" : "background"]);
112
+ if (base.a !== 1)
113
+ throw new Error(`${token} sits on a translucent surface`);
114
+ const mix = (t, b) => Math.round(t * top.a + b * (1 - top.a));
115
+ return { r: mix(top.r, base.r), g: mix(top.g, base.g), b: mix(top.b, base.b), a: 1 };
116
+ }
117
+ const PRIMARY_TINT = /^color-mix\(in oklab, var\(--primary\) (\d+)%, transparent\)$/;
118
+ /** A surface value: a colour as it is, or the preset's primary tint at its alpha. */
119
+ function surface(value, primary) {
120
+ const tint = PRIMARY_TINT.exec(value);
121
+ if (tint)
122
+ return rgbaString({ ...parseColor(primary), a: Number(tint[1]) / 100 });
123
+ parseColor(value);
124
+ return value;
125
+ }
126
+ /** The concrete palette of one ground with one family accent, with no product brand. */
127
+ export function resolvePalette(ground, accent = DEFAULT_ACCENT) {
128
+ const { mode } = GROUNDS[ground];
129
+ const s = SURFACES[ground];
130
+ const m = MODE_TOKENS[mode];
131
+ const spec = ACCENTS[accent];
132
+ const primary = mode === "dark" ? spec.dark : spec.light;
133
+ const onPrimary = mode === "dark" ? spec.onDark : spec.onLight;
134
+ const chart = { ...m.chart, ...spec.chart?.[mode] };
135
+ const status = Object.fromEntries(STATUS_NAMES.flatMap((name) => {
136
+ const t = m.status[name];
137
+ return [
138
+ [name, t.base],
139
+ [`${name}-fg`, t.fg],
140
+ [`${name}-bg`, t.bg],
141
+ [`${name}-border`, t.border],
142
+ ];
143
+ }));
144
+ const palette = {
145
+ background: s.background,
146
+ foreground: m.foreground,
147
+ card: s.card,
148
+ "card-foreground": m.foreground,
149
+ popover: s.popover,
150
+ "popover-foreground": m.foreground,
151
+ primary,
152
+ "primary-foreground": onPrimary,
153
+ secondary: s.secondary,
154
+ "secondary-foreground": m.foreground,
155
+ muted: s.muted,
156
+ "muted-foreground": s.mutedForeground,
157
+ accent: s.accent,
158
+ "accent-foreground": m.foreground,
159
+ destructive: m.destructive,
160
+ border: s.border,
161
+ input: s.input,
162
+ ring: primary,
163
+ "chart-1": primary,
164
+ ...chart,
165
+ // With no product brand, a brand sidebar falls back to the ground's card.
166
+ sidebar: s.sidebar === "brand" ? s.card : s.sidebar,
167
+ "sidebar-foreground": m.sidebarForeground,
168
+ "sidebar-primary": primary,
169
+ "sidebar-primary-foreground": onPrimary,
170
+ "sidebar-accent": s.sidebarAccent,
171
+ "sidebar-accent-foreground": m.foreground,
172
+ "sidebar-border": s.sidebarBorder,
173
+ "sidebar-ring": primary,
174
+ "sidebar-muted-foreground": s.mutedForeground,
175
+ "surface-0": s.background,
176
+ "surface-1": s.card,
177
+ "surface-2": s.popover,
178
+ ...status,
179
+ };
180
+ for (const token of COLOR_TOKENS)
181
+ palette[token] = surface(palette[token], primary);
182
+ return palette;
183
+ }
184
+ /** Every ground with every family accent. */
185
+ export function allPalettes() {
186
+ return Object.fromEntries(GROUND_KEYS.map((ground) => [
187
+ ground,
188
+ Object.fromEntries(ACCENT_KEYS.map((accent) => [accent, resolvePalette(ground, accent)])),
189
+ ]));
190
+ }
191
+ /**
192
+ * A target's values split for compact output: per ground, the entries every
193
+ * accent agrees on, and per ground and accent, the entries that move with
194
+ * the accent.
195
+ */
196
+ export function splitByAccent(values) {
197
+ const ground = {};
198
+ const accent = {};
199
+ for (const g of GROUND_KEYS) {
200
+ const each = ACCENT_KEYS.map((a) => [a, values(g, a)]);
201
+ const first = each[0][1];
202
+ const keys = Object.keys(first);
203
+ const moves = new Set(keys.filter((k) => each.some(([, v]) => JSON.stringify(v[k]) !== JSON.stringify(first[k]))));
204
+ ground[g] = Object.fromEntries(keys.filter((k) => !moves.has(k)).map((k) => [k, first[k]]));
205
+ accent[g] = Object.fromEntries(each.map(([a, v]) => [a, Object.fromEntries([...moves].map((k) => [k, v[k]]))]));
206
+ }
207
+ return { ground, accent };
208
+ }
@@ -0,0 +1,9 @@
1
+ export declare function renderJupyterLabCss(): string;
2
+ export declare function renderVsCodeCss(): string;
3
+ export declare function renderPlainCss(): string;
4
+ export declare function renderPython(): string;
5
+ export declare function renderNativeJs(): string;
6
+ export declare function renderNativeDts(): string;
7
+ export declare function renderReadmes(): Record<string, string>;
8
+ /** Every generated file under src/tokens/, by file name. */
9
+ export declare function renderTokenFiles(): Record<string, string>;