create-agents24-app 0.1.0 → 0.1.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 (75) hide show
  1. package/README.md +40 -2
  2. package/dist/{chunk-OCIF3LSI.js → chunk-PXJTBSPX.js} +99 -23
  3. package/dist/chunk-PXJTBSPX.js.map +1 -0
  4. package/dist/cli.js +39 -61
  5. package/dist/cli.js.map +1 -1
  6. package/dist/index.d.ts +6 -7
  7. package/dist/index.js +9 -1
  8. package/dist/scaffold/components.json +25 -0
  9. package/dist/scaffold/manifest.json +28 -0
  10. package/dist/scaffold/src/app.tsx +71 -0
  11. package/dist/scaffold/src/chat.css +54 -0
  12. package/dist/scaffold/src/components/chat/chat-composer.tsx +237 -0
  13. package/dist/scaffold/src/components/chat/chat-message.tsx +76 -0
  14. package/dist/scaffold/src/components/chat/chat-shell.tsx +257 -0
  15. package/dist/scaffold/src/components/chat/collapsible-user-message.tsx +37 -0
  16. package/dist/scaffold/src/components/chat/external-link-dialog.tsx +48 -0
  17. package/dist/scaffold/src/components/chat/identity-control.tsx +69 -0
  18. package/dist/scaffold/src/components/chat/message-parts.tsx +83 -0
  19. package/dist/scaffold/src/components/chat/theme-menu.tsx +79 -0
  20. package/dist/scaffold/src/components/chat/thread-sidebar.tsx +114 -0
  21. package/dist/scaffold/src/components/chat/timeline-loading.ts +17 -0
  22. package/dist/scaffold/src/components/chat/turn-outline.tsx +73 -0
  23. package/dist/scaffold/src/components/theme-provider.tsx +91 -0
  24. package/dist/scaffold/src/components/ui/attachment.tsx +204 -0
  25. package/dist/scaffold/src/components/ui/bubble.tsx +125 -0
  26. package/dist/scaffold/src/components/ui/button-group.tsx +83 -0
  27. package/dist/scaffold/src/components/ui/button.tsx +65 -0
  28. package/dist/scaffold/src/components/ui/dialog.tsx +171 -0
  29. package/dist/scaffold/src/components/ui/dropdown-menu.tsx +271 -0
  30. package/dist/scaffold/src/components/ui/input.tsx +19 -0
  31. package/dist/scaffold/src/components/ui/marker.tsx +69 -0
  32. package/dist/scaffold/src/components/ui/message-scroller.tsx +129 -0
  33. package/dist/scaffold/src/components/ui/message.tsx +92 -0
  34. package/dist/scaffold/src/components/ui/popover.tsx +40 -0
  35. package/dist/scaffold/src/components/ui/select.tsx +92 -0
  36. package/dist/scaffold/src/components/ui/separator.tsx +28 -0
  37. package/dist/scaffold/src/components/ui/sheet.tsx +150 -0
  38. package/dist/scaffold/src/components/ui/sidebar.tsx +677 -0
  39. package/dist/scaffold/src/components/ui/skeleton.tsx +13 -0
  40. package/dist/scaffold/src/components/ui/textarea.tsx +18 -0
  41. package/dist/scaffold/src/components/ui/tooltip.tsx +56 -0
  42. package/dist/scaffold/src/hooks/use-mobile.ts +24 -0
  43. package/dist/scaffold/src/identity.ts +17 -0
  44. package/dist/scaffold/src/index.css +221 -0
  45. package/dist/scaffold/src/index.tsx +39 -0
  46. package/dist/scaffold/src/lib/utils.ts +6 -0
  47. package/dist/scaffold/styles.css +3 -0
  48. package/dist/scaffold-manifest.json +66 -0
  49. package/package.json +7 -3
  50. package/templates/common/README.md +16 -3
  51. package/templates/common/index.html +3 -3
  52. package/templates/common/scripts/apply-preset.mjs +17 -0
  53. package/templates/common/scripts/scope-preset-theme.mjs +38 -0
  54. package/templates/common/src/styles.css +10 -6
  55. package/templates/common/src/use-thread-query-navigation.ts +41 -0
  56. package/templates/common/tsconfig.json +2 -1
  57. package/templates/integrations/bff/server/env.ts +3 -3
  58. package/templates/integrations/bff/server/index.ts +1 -2
  59. package/templates/integrations/bff/server/principal.ts +3 -3
  60. package/templates/integrations/bff/src/host-identity.ts +6 -0
  61. package/templates/integrations/bff/src/main.tsx +21 -16
  62. package/templates/integrations/bff/tsconfig.json +2 -1
  63. package/templates/integrations/bff/vite.config.ts +5 -1
  64. package/templates/integrations/client-deployment/src/main.tsx +26 -18
  65. package/templates/integrations/client-deployment/vite.config.ts +37 -4
  66. package/templates/starters/rag/agents24/agents/assistant.md +11 -0
  67. package/templates/starters/rag/agents24/agents24.yaml +19 -0
  68. package/templates/starters/rag/agents24/rag/knowledge.yaml +32 -0
  69. package/templates/starters/rag/agents24/stores/knowledge.yaml +10 -0
  70. package/templates/starters/rag/agents24/workflows/main.yaml +16 -0
  71. package/versions.json +4 -4
  72. package/dist/chunk-OCIF3LSI.js.map +0 -1
  73. package/templates/themes/essential/src/theme.css +0 -2
  74. package/templates/themes/flow/src/theme.css +0 -60
  75. package/templates/themes/workbench/src/theme.css +0 -51
@@ -0,0 +1,56 @@
1
+ import * as React from "react"
2
+ import { Slot } from "radix-ui"
3
+
4
+ import { cn } from "../../lib/utils"
5
+
6
+ function TooltipProvider({ children }: { children: React.ReactNode }) {
7
+ return children
8
+ }
9
+
10
+ function Tooltip({ className, ...props }: React.ComponentProps<"span">) {
11
+ return (
12
+ <span
13
+ data-slot="tooltip"
14
+ className={cn("group/tooltip relative inline-flex", className)}
15
+ {...props}
16
+ />
17
+ )
18
+ }
19
+
20
+ function TooltipTrigger({
21
+ asChild: _asChild,
22
+ ...props
23
+ }: React.ComponentProps<typeof Slot.Root> & { asChild?: boolean }) {
24
+ return <Slot.Root data-slot="tooltip-trigger" {...props} />
25
+ }
26
+
27
+ function TooltipContent({
28
+ className,
29
+ align: _align,
30
+ side = "top",
31
+ sideOffset: _sideOffset,
32
+ ...props
33
+ }: React.ComponentProps<"span"> & {
34
+ side?: "top" | "right" | "bottom" | "left"
35
+ sideOffset?: number
36
+ align?: "start" | "center" | "end"
37
+ }) {
38
+ return (
39
+ <span
40
+ role="tooltip"
41
+ data-side={side}
42
+ data-slot="tooltip-content"
43
+ className={cn(
44
+ "pointer-events-none absolute z-50 hidden w-max max-w-xs items-center gap-1.5 rounded-xl bg-foreground px-3 py-1.5 text-xs text-background group-hover/tooltip:inline-flex group-focus-within/tooltip:inline-flex",
45
+ "data-[side=top]:bottom-full data-[side=top]:left-1/2 data-[side=top]:mb-2 data-[side=top]:-translate-x-1/2",
46
+ "data-[side=bottom]:top-full data-[side=bottom]:left-1/2 data-[side=bottom]:mt-2 data-[side=bottom]:-translate-x-1/2",
47
+ "data-[side=left]:end-full data-[side=left]:top-1/2 data-[side=left]:me-2 data-[side=left]:-translate-y-1/2",
48
+ "data-[side=right]:start-full data-[side=right]:top-1/2 data-[side=right]:ms-2 data-[side=right]:-translate-y-1/2",
49
+ className
50
+ )}
51
+ {...props}
52
+ />
53
+ )
54
+ }
55
+
56
+ export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger }
@@ -0,0 +1,24 @@
1
+ import * as React from "react"
2
+
3
+ const MOBILE_BREAKPOINT = 768
4
+
5
+ export function useIsMobile() {
6
+ const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
7
+
8
+ React.useEffect(() => {
9
+ const onChange = () => {
10
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
11
+ }
12
+ if (typeof window.matchMedia !== "function") {
13
+ onChange()
14
+ window.addEventListener("resize", onChange)
15
+ return () => window.removeEventListener("resize", onChange)
16
+ }
17
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
18
+ mql.addEventListener("change", onChange)
19
+ onChange()
20
+ return () => mql.removeEventListener("change", onChange)
21
+ }, [])
22
+
23
+ return !!isMobile
24
+ }
@@ -0,0 +1,17 @@
1
+ export type Agents24ChatIdentityState =
2
+ | "loading"
3
+ | "guest"
4
+ | "authenticated"
5
+ | "signed_out"
6
+ | "error"
7
+
8
+ export type Agents24ChatIdentity = {
9
+ state: Agents24ChatIdentityState
10
+ displayName?: string
11
+ secondaryText?: string
12
+ avatarUrl?: string
13
+ onSignIn?: () => void | Promise<void>
14
+ onSignOut?: () => void | Promise<void>
15
+ }
16
+
17
+ export const GUEST_CHAT_IDENTITY: Agents24ChatIdentity = { state: "guest" }
@@ -0,0 +1,221 @@
1
+ @import "tailwindcss";
2
+ @import "tw-animate-css";
3
+ @import "@fontsource-variable/jetbrains-mono";
4
+ @import "@fontsource-variable/merriweather";
5
+ @import "@fontsource-variable/inter";
6
+
7
+ @source "./**/*.{ts,tsx}";
8
+
9
+ @custom-variant dark (&:is(.dark *));
10
+
11
+ @theme inline {
12
+ --font-heading: var(--a24-font-heading);
13
+ --font-sans: var(--a24-font-sans);
14
+ --color-sidebar-ring: var(--sidebar-ring);
15
+ --color-sidebar-border: var(--sidebar-border);
16
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
17
+ --color-sidebar-accent: var(--sidebar-accent);
18
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
19
+ --color-sidebar-primary: var(--sidebar-primary);
20
+ --color-sidebar-foreground: var(--sidebar-foreground);
21
+ --color-sidebar: var(--sidebar);
22
+ --color-ring: var(--ring);
23
+ --color-input: var(--input);
24
+ --color-border: var(--border);
25
+ --color-destructive: var(--destructive);
26
+ --color-accent-foreground: var(--accent-foreground);
27
+ --color-accent: var(--accent);
28
+ --color-muted-foreground: var(--muted-foreground);
29
+ --color-muted: var(--muted);
30
+ --color-secondary-foreground: var(--secondary-foreground);
31
+ --color-secondary: var(--secondary);
32
+ --color-primary-foreground: var(--primary-foreground);
33
+ --color-primary: var(--primary);
34
+ --color-popover-foreground: var(--popover-foreground);
35
+ --color-popover: var(--popover);
36
+ --color-card-foreground: var(--card-foreground);
37
+ --color-card: var(--card);
38
+ --color-foreground: var(--foreground);
39
+ --color-background: var(--background);
40
+ --radius-sm: calc(var(--radius) * 0.6);
41
+ --radius-md: calc(var(--radius) * 0.8);
42
+ --radius-lg: var(--radius);
43
+ --radius-xl: calc(var(--radius) * 1.4);
44
+ --radius-2xl: calc(var(--radius) * 1.8);
45
+ --radius-3xl: calc(var(--radius) * 2.2);
46
+ --radius-4xl: calc(var(--radius) * 2.6);
47
+ --a24-composer-single-row-radius: 9999px;
48
+ --color-chart-5: var(--chart-5);
49
+ --color-chart-4: var(--chart-4);
50
+ --color-chart-3: var(--chart-3);
51
+ --color-chart-2: var(--chart-2);
52
+ --color-chart-1: var(--chart-1);
53
+ --font-serif: var(--a24-font-heading);
54
+ --font-mono: var(--a24-font-mono);
55
+ }
56
+
57
+ [data-agents24-theme-root] {
58
+ color-scheme: light;
59
+ --a24-font-heading: 'Inter Variable', sans-serif;
60
+ --a24-font-sans: 'Inter Variable', sans-serif;
61
+ --a24-font-mono: 'JetBrains Mono Variable', monospace;
62
+ --radius-sm: calc(var(--radius) * 0.6);
63
+ --radius-md: calc(var(--radius) * 0.8);
64
+ --radius-lg: var(--radius);
65
+ --radius-xl: calc(var(--radius) * 1.4);
66
+ --radius-2xl: calc(var(--radius) * 1.8);
67
+ --radius-3xl: calc(var(--radius) * 2.2);
68
+ --radius-4xl: calc(var(--radius) * 2.6);
69
+ --background: oklch(1 0 0);
70
+ --foreground: oklch(0.147 0.004 49.25);
71
+ --card: oklch(1 0 0);
72
+ --card-foreground: oklch(0.147 0.004 49.25);
73
+ --popover: oklch(1 0 0);
74
+ --popover-foreground: oklch(0.147 0.004 49.25);
75
+ --primary: oklch(0.52 0.105 223.128);
76
+ --primary-foreground: oklch(0.984 0.019 200.873);
77
+ --secondary: oklch(0.967 0.001 286.375);
78
+ --secondary-foreground: oklch(0.21 0.006 285.885);
79
+ --muted: oklch(0.97 0.001 106.424);
80
+ --muted-foreground: oklch(0.553 0.013 58.071);
81
+ --accent: oklch(0.97 0.001 106.424);
82
+ --accent-foreground: oklch(0.216 0.006 56.043);
83
+ --destructive: oklch(0.577 0.245 27.325);
84
+ --border: oklch(0.923 0.003 48.717);
85
+ --input: oklch(0.923 0.003 48.717);
86
+ --ring: oklch(0.709 0.01 56.259);
87
+ --radius: 0.875rem;
88
+ --sidebar: oklch(0.985 0.001 106.423);
89
+ --sidebar-foreground: oklch(0.147 0.004 49.25);
90
+ --sidebar-primary: oklch(0.609 0.126 221.723);
91
+ --sidebar-primary-foreground: oklch(0.984 0.019 200.873);
92
+ --sidebar-accent: oklch(0.97 0.001 106.424);
93
+ --sidebar-accent-foreground: oklch(0.216 0.006 56.043);
94
+ --sidebar-border: oklch(0.923 0.003 48.717);
95
+ --sidebar-ring: oklch(0.709 0.01 56.259);
96
+ --chart-1: oklch(0.845 0.143 164.978);
97
+ --chart-2: oklch(0.696 0.17 162.48);
98
+ --chart-3: oklch(0.596 0.145 163.225);
99
+ --chart-4: oklch(0.508 0.118 165.612);
100
+ --chart-5: oklch(0.432 0.095 166.913);
101
+ }
102
+
103
+ [data-agents24-theme-root].dark {
104
+ color-scheme: dark;
105
+ --background: oklch(0.147 0.004 49.25);
106
+ --foreground: oklch(0.985 0.001 106.423);
107
+ --card: oklch(0.216 0.006 56.043);
108
+ --card-foreground: oklch(0.985 0.001 106.423);
109
+ --popover: oklch(0.216 0.006 56.043);
110
+ --popover-foreground: oklch(0.985 0.001 106.423);
111
+ --primary: oklch(0.45 0.085 224.283);
112
+ --primary-foreground: oklch(0.984 0.019 200.873);
113
+ --secondary: oklch(0.274 0.006 286.033);
114
+ --secondary-foreground: oklch(0.985 0 0);
115
+ --muted: oklch(0.268 0.007 34.298);
116
+ --muted-foreground: oklch(0.709 0.01 56.259);
117
+ --accent: oklch(0.268 0.007 34.298);
118
+ --accent-foreground: oklch(0.985 0.001 106.423);
119
+ --destructive: oklch(0.704 0.191 22.216);
120
+ --border: oklch(1 0 0 / 10%);
121
+ --input: oklch(1 0 0 / 15%);
122
+ --ring: oklch(0.553 0.013 58.071);
123
+ --sidebar: oklch(0.216 0.006 56.043);
124
+ --sidebar-foreground: oklch(0.985 0.001 106.423);
125
+ --sidebar-primary: oklch(0.715 0.143 215.221);
126
+ --sidebar-primary-foreground: oklch(0.302 0.056 229.695);
127
+ --sidebar-accent: oklch(0.268 0.007 34.298);
128
+ --sidebar-accent-foreground: oklch(0.985 0.001 106.423);
129
+ --sidebar-border: oklch(1 0 0 / 10%);
130
+ --sidebar-ring: oklch(0.553 0.013 58.071);
131
+ --chart-1: oklch(0.845 0.143 164.978);
132
+ --chart-2: oklch(0.696 0.17 162.48);
133
+ --chart-3: oklch(0.596 0.145 163.225);
134
+ --chart-4: oklch(0.508 0.118 165.612);
135
+ --chart-5: oklch(0.432 0.095 166.913);
136
+ }
137
+
138
+ [data-agents24-theme-root][data-agents24-theme="sharp"] {
139
+ --a24-composer-single-row-radius: 0;
140
+ --a24-font-heading: 'Merriweather Variable', serif;
141
+ --a24-font-sans: 'JetBrains Mono Variable', monospace;
142
+ --a24-font-mono: 'JetBrains Mono Variable', monospace;
143
+ --background: oklch(1 0 0);
144
+ --foreground: oklch(0.141 0.005 285.823);
145
+ --card: oklch(1 0 0);
146
+ --card-foreground: oklch(0.141 0.005 285.823);
147
+ --popover: oklch(1 0 0);
148
+ --popover-foreground: oklch(0.141 0.005 285.823);
149
+ --primary: oklch(0.21 0.006 285.885);
150
+ --primary-foreground: oklch(0.985 0 0);
151
+ --secondary: oklch(0.967 0.001 286.375);
152
+ --secondary-foreground: oklch(0.21 0.006 285.885);
153
+ --muted: oklch(0.967 0.001 286.375);
154
+ --muted-foreground: oklch(0.552 0.016 285.938);
155
+ --accent: oklch(0.967 0.001 286.375);
156
+ --accent-foreground: oklch(0.21 0.006 285.885);
157
+ --destructive: oklch(0.577 0.245 27.325);
158
+ --border: oklch(0.92 0.004 286.32);
159
+ --input: oklch(0.92 0.004 286.32);
160
+ --ring: oklch(0.705 0.015 286.067);
161
+ --radius: 0;
162
+ --sidebar: oklch(0.985 0 0);
163
+ --sidebar-foreground: oklch(0.141 0.005 285.823);
164
+ --sidebar-primary: oklch(0.21 0.006 285.885);
165
+ --sidebar-primary-foreground: oklch(0.985 0 0);
166
+ --sidebar-accent: oklch(0.967 0.001 286.375);
167
+ --sidebar-accent-foreground: oklch(0.21 0.006 285.885);
168
+ --sidebar-border: oklch(0.92 0.004 286.32);
169
+ --sidebar-ring: oklch(0.705 0.015 286.067);
170
+ --chart-1: oklch(0.865 0.127 207.078);
171
+ --chart-2: oklch(0.715 0.143 215.221);
172
+ --chart-3: oklch(0.609 0.126 221.723);
173
+ --chart-4: oklch(0.52 0.105 223.128);
174
+ --chart-5: oklch(0.45 0.085 224.283);
175
+ }
176
+
177
+ [data-agents24-theme-root][data-agents24-theme="sharp"].dark {
178
+ --background: oklch(0.141 0.005 285.823);
179
+ --foreground: oklch(0.985 0 0);
180
+ --card: oklch(0.21 0.006 285.885);
181
+ --card-foreground: oklch(0.985 0 0);
182
+ --popover: oklch(0.21 0.006 285.885);
183
+ --popover-foreground: oklch(0.985 0 0);
184
+ --primary: oklch(0.92 0.004 286.32);
185
+ --primary-foreground: oklch(0.21 0.006 285.885);
186
+ --secondary: oklch(0.274 0.006 286.033);
187
+ --secondary-foreground: oklch(0.985 0 0);
188
+ --muted: oklch(0.274 0.006 286.033);
189
+ --muted-foreground: oklch(0.705 0.015 286.067);
190
+ --accent: oklch(0.274 0.006 286.033);
191
+ --accent-foreground: oklch(0.985 0 0);
192
+ --destructive: oklch(0.704 0.191 22.216);
193
+ --border: oklch(1 0 0 / 10%);
194
+ --input: oklch(1 0 0 / 15%);
195
+ --ring: oklch(0.552 0.016 285.938);
196
+ --sidebar: oklch(0.21 0.006 285.885);
197
+ --sidebar-foreground: oklch(0.985 0 0);
198
+ --sidebar-primary: oklch(0.488 0.243 264.376);
199
+ --sidebar-primary-foreground: oklch(0.985 0 0);
200
+ --sidebar-accent: oklch(0.274 0.006 286.033);
201
+ --sidebar-accent-foreground: oklch(0.985 0 0);
202
+ --sidebar-border: oklch(1 0 0 / 10%);
203
+ --sidebar-ring: oklch(0.552 0.016 285.938);
204
+ --chart-1: oklch(0.865 0.127 207.078);
205
+ --chart-2: oklch(0.715 0.143 215.221);
206
+ --chart-3: oklch(0.609 0.126 221.723);
207
+ --chart-4: oklch(0.52 0.105 223.128);
208
+ --chart-5: oklch(0.45 0.085 224.283);
209
+ }
210
+
211
+ @layer base {
212
+ [data-agents24-theme-root], [data-agents24-theme-root] * {
213
+ @apply border-border outline-ring/50;
214
+ box-sizing: border-box;
215
+ }
216
+ [data-agents24-theme-root] {
217
+ @apply size-full overflow-hidden bg-background font-sans text-foreground antialiased;
218
+ }
219
+ [data-agents24-theme-root] button,
220
+ [data-agents24-theme-root] textarea { font: inherit; }
221
+ }
@@ -0,0 +1,39 @@
1
+ import * as React from "react"
2
+
3
+ import { App, type Agents24ChatAppProps } from "./app"
4
+ import {
5
+ ThemeProvider,
6
+ type Agents24ChatAppearanceController,
7
+ type Agents24ChatTheme,
8
+ } from "./components/theme-provider"
9
+ import { TooltipProvider } from "./components/ui/tooltip"
10
+
11
+ export type Agents24ChatScaffoldProps = Agents24ChatAppProps & {
12
+ appearanceController?: Agents24ChatAppearanceController
13
+ theme?: Agents24ChatTheme
14
+ }
15
+
16
+ export function Agents24ChatScaffold({ appearanceController, theme, ...props }: Agents24ChatScaffoldProps) {
17
+ return (
18
+ <ThemeProvider controller={appearanceController} theme={theme}>
19
+ <TooltipProvider>
20
+ <App {...props} />
21
+ </TooltipProvider>
22
+ </ThemeProvider>
23
+ )
24
+ }
25
+
26
+ export { App as Agents24ChatScaffoldApp }
27
+ export { ThemeProvider as Agents24ChatThemeProvider }
28
+ export type {
29
+ Agents24ChatAppearance,
30
+ Agents24ChatAppearanceController,
31
+ Agents24ChatTheme,
32
+ } from "./components/theme-provider"
33
+ export type { Agents24ChatIdentity, Agents24ChatIdentityState } from "./identity"
34
+ export type {
35
+ ChatHitlResponse,
36
+ Agents24ChatScaffoldComponents,
37
+ Agents24ChatTimelineSlotProps,
38
+ } from "./app"
39
+ export { TooltipProvider as Agents24ChatTooltipProvider }
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
@@ -0,0 +1,3 @@
1
+ @import "@agents24/chat-react/styles.css";
2
+ @import "./src/index.css";
3
+ @import "./src/chat.css";
@@ -0,0 +1,66 @@
1
+ {
2
+ "schema_version": "agents24.chat-scaffold-build.v1",
3
+ "default_preset": "b2D1FHzlY",
4
+ "dependencies": {
5
+ "@fontsource-variable/inter": "^5.3.0",
6
+ "@fontsource-variable/jetbrains-mono": "^5.3.0",
7
+ "@fontsource-variable/merriweather": "^5.3.0",
8
+ "@shadcn/react": "^0.2.1",
9
+ "class-variance-authority": "^0.7.1",
10
+ "clsx": "^2.1.1",
11
+ "lucide-react": "0.542.0",
12
+ "radix-ui": "1.4.3",
13
+ "streamdown": "^2.5.0",
14
+ "tailwind-merge": "^3.6.0",
15
+ "tw-animate-css": "^1.4.0"
16
+ },
17
+ "devDependencies": {
18
+ "@tailwindcss/vite": "^4.1.16",
19
+ "shadcn": "4.13.1",
20
+ "tailwindcss": "^4.1.16"
21
+ },
22
+ "source": "packages/agents24-chat-react/scaffold",
23
+ "sha256": "c0cd4f7235384fb8297a0f5d364dbf75898e1a12e2b8c88128ee78f4ac0044c0",
24
+ "files": [
25
+ "components.json",
26
+ "manifest.json",
27
+ "src/app.tsx",
28
+ "src/chat.css",
29
+ "src/components/chat/chat-composer.tsx",
30
+ "src/components/chat/chat-message.tsx",
31
+ "src/components/chat/chat-shell.tsx",
32
+ "src/components/chat/collapsible-user-message.tsx",
33
+ "src/components/chat/external-link-dialog.tsx",
34
+ "src/components/chat/identity-control.tsx",
35
+ "src/components/chat/message-parts.tsx",
36
+ "src/components/chat/theme-menu.tsx",
37
+ "src/components/chat/thread-sidebar.tsx",
38
+ "src/components/chat/timeline-loading.ts",
39
+ "src/components/chat/turn-outline.tsx",
40
+ "src/components/theme-provider.tsx",
41
+ "src/components/ui/attachment.tsx",
42
+ "src/components/ui/bubble.tsx",
43
+ "src/components/ui/button-group.tsx",
44
+ "src/components/ui/button.tsx",
45
+ "src/components/ui/dialog.tsx",
46
+ "src/components/ui/dropdown-menu.tsx",
47
+ "src/components/ui/input.tsx",
48
+ "src/components/ui/marker.tsx",
49
+ "src/components/ui/message-scroller.tsx",
50
+ "src/components/ui/message.tsx",
51
+ "src/components/ui/popover.tsx",
52
+ "src/components/ui/select.tsx",
53
+ "src/components/ui/separator.tsx",
54
+ "src/components/ui/sheet.tsx",
55
+ "src/components/ui/sidebar.tsx",
56
+ "src/components/ui/skeleton.tsx",
57
+ "src/components/ui/textarea.tsx",
58
+ "src/components/ui/tooltip.tsx",
59
+ "src/hooks/use-mobile.ts",
60
+ "src/identity.ts",
61
+ "src/index.css",
62
+ "src/index.tsx",
63
+ "src/lib/utils.ts",
64
+ "styles.css"
65
+ ]
66
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-agents24-app",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Create a production-ready Agents24 React application.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -33,7 +33,8 @@
33
33
  "provenance": false
34
34
  },
35
35
  "dependencies": {
36
- "@clack/prompts": "1.7.0"
36
+ "@clack/prompts": "1.7.0",
37
+ "shadcn": "4.13.1"
37
38
  },
38
39
  "devDependencies": {
39
40
  "@types/node": "^24.7.2",
@@ -41,7 +42,10 @@
41
42
  "typescript": "^5.9.3"
42
43
  },
43
44
  "scripts": {
44
- "build": "tsup",
45
+ "sync:scaffold": "node scripts/sync-chat-scaffold.mjs",
46
+ "check:scaffold": "node scripts/sync-chat-scaffold.mjs --check",
47
+ "build": "tsup && pnpm run sync:scaffold && tsc --noEmit",
48
+ "materialize:fixture": "pnpm run build && node scripts/materialize-dev-fixture.mjs",
45
49
  "test": "pnpm run build && node --test tests/*.test.mjs",
46
50
  "prepack": "pnpm run build && pnpm run test"
47
51
  }
@@ -1,8 +1,8 @@
1
1
  # __APP_NAME__
2
2
 
3
- Last Updated: 2026-07-19
3
+ Last Updated: 2026-07-29
4
4
 
5
- This app was generated by `create-agents24-app` with the `__INTEGRATION__` integration and `__THEME__` visual recipe.
5
+ This app was generated by `create-agents24-app` with the `__INTEGRATION__` integration and Shadcn preset `__PRESET__`.
6
6
 
7
7
  The app includes a strict document CSP. If you deploy the static client-deployment build without the generated BFF, configure your host to send `Content-Security-Policy: frame-ancestors 'none'`; browsers do not honor that directive in an HTML meta tag.
8
8
 
@@ -14,6 +14,8 @@ __PM_DEV__
14
14
 
15
15
  Configuration lives in `.env.local`. Commit `.env.example`, never `.env.local`.
16
16
 
17
+ __STARTER_SETUP__
18
+
17
19
  ## Production
18
20
 
19
21
  ```bash
@@ -21,4 +23,15 @@ __PM_BUILD__
21
23
  __PM_PRODUCTION__
22
24
  ```
23
25
 
24
- The chat layout comes directly from `@agents24/chat-react`; keep product-specific additions in the provided slots instead of copying the layout.
26
+ The application owns its Shadcn component source under `src/components`. Agents24 packages own the runtime, state, hardened streaming markdown, and MCP security helpers.
27
+
28
+ ## Timeline customization
29
+
30
+ The generated scaffold renders canonical ordered `message.parts` with the
31
+ default `AgentResponseTimeline`. Pass `components={{ Timeline }}` to
32
+ `Agents24ChatScaffold` to use the default, pass a copied/reordered `parts`
33
+ array to `AgentResponseTimeline`, or render a fully custom timeline with
34
+ `AgentChatPart` and the supplied HITL callbacks. Never mutate `message.parts`;
35
+ the replacement owns its accessibility and pending-HITL visibility.
36
+
37
+ To try another Shadcn preset later, run `__PM_PRESET__ <preset-code> --yes`. Commit first: Shadcn intentionally updates component source and theme variables.
@@ -1,9 +1,9 @@
1
1
  <!doctype html>
2
- <html lang="en" data-agents24-color-mode="system">
2
+ <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
- <meta content="width=device-width, initial-scale=1.0" name="viewport" />
6
- <meta content="default-src 'self'; base-uri 'none'; object-src 'none'; script-src 'self'; style-src 'self'; img-src 'self' data: blob:; connect-src 'self' __CONNECT_SOURCE__ ws://127.0.0.1:* ws://localhost:*; form-action 'self'" http-equiv="Content-Security-Policy" />
5
+ <meta content="width=device-width, initial-scale=1.0, viewport-fit=cover" name="viewport" />
6
+ <meta content="default-src 'self'; base-uri 'none'; object-src 'none'; script-src 'self'; style-src 'self'; font-src 'self' data:; img-src 'self' data: blob:; connect-src 'self'__CONNECT_SOURCE__; form-action 'self'" http-equiv="Content-Security-Policy" />
7
7
  <link href="/src/styles.css" rel="stylesheet" />
8
8
  <title>__APP_NAME__</title>
9
9
  </head>
@@ -0,0 +1,17 @@
1
+ import { spawnSync } from "node:child_process"
2
+ import { resolve } from "node:path"
3
+ import { fileURLToPath } from "node:url"
4
+
5
+ import { scopePresetTheme } from "./scope-preset-theme.mjs"
6
+
7
+ const preset = String(process.argv[2] || "").trim()
8
+ if (!preset) throw new Error("Pass a shadcn preset code, for example: pnpm preset -- b2D1FHzlY")
9
+
10
+ const shadcn = fileURLToPath(import.meta.resolve("shadcn"))
11
+ const result = spawnSync(process.execPath, [shadcn, "apply", preset, "--yes", "--cwd", resolve(".")], {
12
+ stdio: "inherit",
13
+ })
14
+ if (result.error) throw result.error
15
+ if (result.status !== 0) process.exit(result.status || 1)
16
+
17
+ scopePresetTheme()
@@ -0,0 +1,38 @@
1
+ import { readFileSync, realpathSync, writeFileSync } from "node:fs"
2
+ import { resolve } from "node:path"
3
+ import { fileURLToPath } from "node:url"
4
+
5
+ const startMarker = "/* agents24-preset-theme:start */"
6
+ const endMarker = "/* agents24-preset-theme:end */"
7
+
8
+ function lastTopLevelBlock(css, selector) {
9
+ const escaped = selector.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
10
+ const matches = [...css.matchAll(new RegExp(`^${escaped}\\s*\\{([\\s\\S]*?)^\\}`, "gm"))]
11
+ return matches.at(-1)?.[1]?.trim() || null
12
+ }
13
+
14
+ export function scopePresetTheme(cssPath = resolve("src/index.css")) {
15
+ let css = readFileSync(cssPath, "utf8")
16
+ css = css.replace(new RegExp(`\\n?${startMarker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\s\\S]*?${endMarker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\n?`, "g"), "\n")
17
+
18
+ const light = lastTopLevelBlock(css, ":root")
19
+ const dark = lastTopLevelBlock(css, ".dark")
20
+ if (!light || !dark) throw new Error("The applied shadcn preset did not provide :root and .dark theme tokens.")
21
+
22
+ // Generated apps are standalone, but the chat root remains scoped so dialogs and
23
+ // overlays inherit one consistent theme. Remove the canonical default token blocks
24
+ // before adding the selected preset at the same scope.
25
+ css = css
26
+ .replace(/^\[data-agents24-theme-root\]\s*\{[\s\S]*?^\}\n?/m, "")
27
+ .replace(/^\[data-agents24-theme-root\]\.dark\s*\{[\s\S]*?^\}\n?/m, "")
28
+ .replace(/^\[data-agents24-theme-root\]\[data-agents24-theme="sharp"\]\s*\{[\s\S]*?^\}\n?/m, "")
29
+ .replace(/^\[data-agents24-theme-root\]\[data-agents24-theme="sharp"\]\.dark\s*\{[\s\S]*?^\}\n?/m, "")
30
+ .trimEnd()
31
+
32
+ css += `\n\n${startMarker}\n[data-agents24-theme-root] {\n color-scheme: light;\n${light}\n}\n\n[data-agents24-theme-root].dark {\n color-scheme: dark;\n${dark}\n}\n${endMarker}\n`
33
+ writeFileSync(cssPath, css)
34
+ }
35
+
36
+ if (process.argv[1] && realpathSync(resolve(process.argv[1])) === realpathSync(fileURLToPath(import.meta.url))) {
37
+ scopePresetTheme(process.argv[2] ? resolve(process.argv[2]) : undefined)
38
+ }
@@ -1,7 +1,11 @@
1
- @import "@agents24/chat-react/styles.css";
2
- @import "./theme.css";
1
+ @import "../styles.css";
2
+ @source "../node_modules/streamdown/dist/*.js";
3
3
 
4
- * { box-sizing: border-box; }
5
- html, body, #root { height: 100%; margin: 0; }
6
- body { background: var(--a24-background); color: var(--a24-text); overflow: hidden; }
7
- .app-shell { height: 100%; min-height: 32rem; width: 100%; }
4
+ html,
5
+ body,
6
+ #root {
7
+ height: 100%;
8
+ margin: 0;
9
+ overflow: hidden;
10
+ width: 100%;
11
+ }
@@ -0,0 +1,41 @@
1
+ import type { AgentChatActiveThreadChange } from "@agents24/chat-react/runtime"
2
+ import * as React from "react"
3
+
4
+ const THREAD_ID_PARAM = "threadId"
5
+
6
+ function readThreadId(): string | null {
7
+ const value = new URL(window.location.href).searchParams.get(THREAD_ID_PARAM)
8
+ return value?.trim() || null
9
+ }
10
+
11
+ function writeThreadId(threadId: string | null, mode: "push" | "replace") {
12
+ const url = new URL(window.location.href)
13
+ if (threadId) url.searchParams.set(THREAD_ID_PARAM, threadId)
14
+ else url.searchParams.delete(THREAD_ID_PARAM)
15
+ window.history[mode === "push" ? "pushState" : "replaceState"](
16
+ { ...window.history.state, agents24ThreadId: threadId },
17
+ "",
18
+ url,
19
+ )
20
+ }
21
+
22
+ export function useThreadQueryNavigation() {
23
+ const [activeThreadId, setActiveThreadId] = React.useState<string | null>(readThreadId)
24
+
25
+ React.useEffect(() => {
26
+ const onPopState = () => setActiveThreadId(readThreadId())
27
+ window.addEventListener("popstate", onPopState)
28
+ return () => window.removeEventListener("popstate", onPopState)
29
+ }, [])
30
+
31
+ const onActiveThreadIdChange = React.useCallback((change: AgentChatActiveThreadChange) => {
32
+ setActiveThreadId((current) => {
33
+ if (current === change.threadId) return current
34
+ const mode = change.reason === "created" || change.reason === "deleted" ? "replace" : "push"
35
+ writeThreadId(change.threadId, mode)
36
+ return change.threadId
37
+ })
38
+ }, [])
39
+
40
+ return { activeThreadId, onActiveThreadIdChange }
41
+ }
@@ -15,7 +15,8 @@
15
15
  "isolatedModules": true,
16
16
  "noEmit": true,
17
17
  "jsx": "react-jsx",
18
- "types": ["vite/client"]
18
+ "types": ["vite/client", "node"],
19
+ "paths": { "@/*": ["./src/*"] }
19
20
  },
20
21
  "include": ["src", "server", "vite.config.ts"]
21
22
  }