@fluxy-chat/create-fluxy-chat 0.5.5 → 0.5.8
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.
- package/CHANGELOG.md +28 -4
- package/package.json +1 -1
- package/templates/full/README.md +4 -4
- package/templates/full/package.json +8 -2
- package/templates/full/scripts/hoist-fluxy-sdk.mjs +17 -0
- package/templates/full/src/App.tsx +97 -46
- package/templates/full/src/index.css +80 -3
- package/templates/minimal/package.json +1 -1
- package/templates/react/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [0.5.
|
|
3
|
+
## [0.5.8] - 2026-08-19
|
|
4
4
|
|
|
5
5
|
### Fixed
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
- After `pnpm install`, remove a nested `@fluxy-chat/sdk@0.6.0` (incomplete tarball pulled in by `@fluxy-chat/react@0.1.1`) so Vite uses the complete 0.6.2 package.
|
|
8
|
+
|
|
9
|
+
## [0.5.7] - 2026-08-19
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Remove Vite alias to `@fluxy-chat/ui/dist/index.js` (that path is not in package `exports`; import `@fluxy-chat/ui` instead).
|
|
14
|
+
- Depend on `@fluxy-chat/ui@^0.1.4`.
|
|
15
|
+
|
|
16
|
+
## [0.5.6] - 2026-08-19
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- Hosted `full` template opens a local onboarding tour first. Clerk sign-in is the last step, then you land on a simple chat (same UI primitives as the console). Open a second tab to try realtime. Dashboard is a separate button, not the first screen.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Force `@fluxy-chat/sdk@0.6.2` via pnpm overrides so `pnpm install` + `pnpm dev` work without extra setup.
|
|
25
|
+
- Depend on `@fluxy-chat/ui@^0.1.3` (valid package exports).
|
|
10
26
|
|
|
11
27
|
## [0.5.5] - 2026-08-19
|
|
12
28
|
|
|
@@ -16,6 +32,14 @@
|
|
|
16
32
|
- Hosted `full` template uses the same chat UI primitives as FluxyChat (message bubbles/composer/status) to match dashboard/rooms/onboarding styling.
|
|
17
33
|
- Remove fuorvianti "dash" UI artifacts and wire message sending through the same chat path as the dashboard.
|
|
18
34
|
|
|
35
|
+
## [0.5.4] - 2026-08-19
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- Add `zustand` to `full` template dependencies so `pnpm install` gets everything without manual intervention.
|
|
40
|
+
- Fix `FluxyRealtimeProvider` usage: pass `workerUrl` + `authTokenProvider` instead of non-existent `client` prop (fixes "disconnected" state and message sending).
|
|
41
|
+
- Restyle full template UI to match FluxyChat dark theme (indigo/emerald palette, proper message bubbles, live/disconnected badge).
|
|
42
|
+
|
|
19
43
|
## [0.5.3] - 2026-08-19
|
|
20
44
|
|
|
21
45
|
### Fixed
|
package/package.json
CHANGED
package/templates/full/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# FluxyChat full stack starter
|
|
2
2
|
|
|
3
|
-
Chat + AI agent in a Vite app. Hosted mode
|
|
3
|
+
Chat + AI agent in a Vite app. Hosted mode starts with a short local tour, then Clerk, then your own room.
|
|
4
4
|
|
|
5
5
|
## Quick start
|
|
6
6
|
|
|
7
|
-
**Hosted (
|
|
7
|
+
**Hosted (no wrangler):**
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
npx @fluxy-chat/create-fluxy-chat@latest my-app --mode hosted -y
|
|
@@ -14,7 +14,7 @@ pnpm setup:hosted
|
|
|
14
14
|
pnpm dev
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Localhost opens a 3-step tour. Last step is sign in. After Clerk you come back to a simple chat. Open a second tab to try realtime. Use Open dashboard for rooms and agents.
|
|
18
18
|
|
|
19
19
|
**Local worker:**
|
|
20
20
|
|
|
@@ -40,7 +40,7 @@ pnpm dev
|
|
|
40
40
|
|
|
41
41
|
`.env` from `pnpm setup:hosted` only needs worker and console URLs. Member JWT, room, and agent come from Clerk after sign in.
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
Dashboard: [fluxychat.com/dashboard](https://fluxychat.com/dashboard)
|
|
44
44
|
|
|
45
45
|
## Learn more
|
|
46
46
|
|
|
@@ -11,12 +11,13 @@
|
|
|
11
11
|
"dev": "node scripts/fluxy-dev.mjs",
|
|
12
12
|
"dev:app": "vite",
|
|
13
13
|
"build": "tsc -b && vite build",
|
|
14
|
-
"preview": "vite preview"
|
|
14
|
+
"preview": "vite preview",
|
|
15
|
+
"postinstall": "node scripts/hoist-fluxy-sdk.mjs"
|
|
15
16
|
},
|
|
16
17
|
"dependencies": {
|
|
17
18
|
"@fluxy-chat/react": "^0.1.1",
|
|
18
19
|
"@fluxy-chat/sdk": "^0.6.2",
|
|
19
|
-
"@fluxy-chat/ui": "^0.1.
|
|
20
|
+
"@fluxy-chat/ui": "^0.1.3",
|
|
20
21
|
"class-variance-authority": "^0.7.1",
|
|
21
22
|
"clsx": "^2.1.1",
|
|
22
23
|
"lucide-react": "^0.511.0",
|
|
@@ -35,5 +36,10 @@
|
|
|
35
36
|
"tailwindcss": "^3.4.17",
|
|
36
37
|
"typescript": "^5.6.0",
|
|
37
38
|
"vite": "^6.0.0"
|
|
39
|
+
},
|
|
40
|
+
"pnpm": {
|
|
41
|
+
"overrides": {
|
|
42
|
+
"@fluxy-chat/sdk": "0.6.2"
|
|
43
|
+
}
|
|
38
44
|
}
|
|
39
45
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { existsSync, rmSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
const nestedSdk = join(
|
|
5
|
+
process.cwd(),
|
|
6
|
+
"node_modules",
|
|
7
|
+
"@fluxy-chat",
|
|
8
|
+
"react",
|
|
9
|
+
"node_modules",
|
|
10
|
+
"@fluxy-chat",
|
|
11
|
+
"sdk",
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
if (existsSync(nestedSdk)) {
|
|
15
|
+
rmSync(nestedSdk, { recursive: true, force: true });
|
|
16
|
+
console.log("[fluxy] removed nested @fluxy-chat/sdk so Vite uses the complete 0.6.2 package");
|
|
17
|
+
}
|
|
@@ -17,6 +17,19 @@ const SUGGESTED_PROMPTS = [
|
|
|
17
17
|
"What can this assistant do?",
|
|
18
18
|
];
|
|
19
19
|
|
|
20
|
+
function consoleOrigin(): string {
|
|
21
|
+
return consoleUrl.replace(/\/$/, "");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function clerkAuthHref(): string {
|
|
25
|
+
const returnTo = typeof window !== "undefined" ? window.location.origin : "http://localhost:5173";
|
|
26
|
+
return `${consoleOrigin()}/cli-auth?redirect_uri=${encodeURIComponent(returnTo)}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function dashboardHref(): string {
|
|
30
|
+
return `${consoleOrigin()}/dashboard`;
|
|
31
|
+
}
|
|
32
|
+
|
|
20
33
|
function sessionFromEnv(): CliSession | null {
|
|
21
34
|
if (!envWorkerUrl || !envJwt || !envRoomId) return null;
|
|
22
35
|
return {
|
|
@@ -30,31 +43,73 @@ function sessionFromEnv(): CliSession | null {
|
|
|
30
43
|
};
|
|
31
44
|
}
|
|
32
45
|
|
|
33
|
-
function
|
|
34
|
-
|
|
35
|
-
|
|
46
|
+
function Brand() {
|
|
47
|
+
return (
|
|
48
|
+
<div className="brand">
|
|
49
|
+
<img src={`${consoleOrigin()}/fluxychat-icon.svg`} alt="" width={28} height={28} />
|
|
50
|
+
<span>FluxyChat</span>
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const TOUR_STEPS = [
|
|
56
|
+
{
|
|
57
|
+
title: "You already have an app",
|
|
58
|
+
body: "This folder is a real Vite chat app. After a short sign-in we create your project and a private room. No public playground.",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
title: "Realtime is the point",
|
|
62
|
+
body: "After you are in, open this same URL in a second tab. Send a message in one window and watch it land in the other.",
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
title: "Then the console",
|
|
66
|
+
body: "Sign in is required: that is what creates (or reuses) your project and assistant room. After that the two-tab demo works. The dashboard is a separate button once you are in chat.",
|
|
67
|
+
},
|
|
68
|
+
] as const;
|
|
69
|
+
|
|
70
|
+
function LocalOnboarding() {
|
|
71
|
+
const [step, setStep] = useState(0);
|
|
72
|
+
const last = step === TOUR_STEPS.length - 1;
|
|
73
|
+
const current = TOUR_STEPS[step];
|
|
36
74
|
|
|
37
75
|
return (
|
|
38
76
|
<main className="app-shell">
|
|
39
77
|
<header className="topbar">
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
</
|
|
78
|
+
<Brand />
|
|
79
|
+
<span className="meta">
|
|
80
|
+
{step + 1} / {TOUR_STEPS.length}
|
|
81
|
+
</span>
|
|
44
82
|
</header>
|
|
45
|
-
<div className="
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
</p>
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
83
|
+
<div className="onboard">
|
|
84
|
+
<div className="dots" aria-hidden>
|
|
85
|
+
{TOUR_STEPS.map((_, i) => (
|
|
86
|
+
<span key={i} className={`dot-step ${i === step ? "active" : ""}`} />
|
|
87
|
+
))}
|
|
88
|
+
</div>
|
|
89
|
+
<p className="eyebrow">Quick start</p>
|
|
90
|
+
<h1>{current.title}</h1>
|
|
91
|
+
<p>{current.body}</p>
|
|
92
|
+
<div className="onboard-actions">
|
|
93
|
+
{step > 0 ? (
|
|
94
|
+
<button type="button" className="btn-ghost" onClick={() => setStep((s) => s - 1)}>
|
|
95
|
+
Back
|
|
96
|
+
</button>
|
|
97
|
+
) : null}
|
|
98
|
+
{last ? (
|
|
99
|
+
<a className="btn-primary" href={clerkAuthHref()}>
|
|
100
|
+
Sign in or create account
|
|
101
|
+
</a>
|
|
102
|
+
) : (
|
|
103
|
+
<button type="button" className="btn-primary" onClick={() => setStep((s) => s + 1)}>
|
|
104
|
+
Continue
|
|
105
|
+
</button>
|
|
106
|
+
)}
|
|
107
|
+
</div>
|
|
108
|
+
{last ? (
|
|
109
|
+
<p className="fine-print">
|
|
110
|
+
Clerk on fluxychat.com, then back here with your room ready.
|
|
111
|
+
</p>
|
|
112
|
+
) : null}
|
|
58
113
|
</div>
|
|
59
114
|
</main>
|
|
60
115
|
);
|
|
@@ -73,9 +128,9 @@ function ChatRoom({ session }: { session: CliSession }) {
|
|
|
73
128
|
|
|
74
129
|
async function onSend(content: string) {
|
|
75
130
|
setError(null);
|
|
76
|
-
const mentionsAgent = content
|
|
77
|
-
|
|
78
|
-
|
|
131
|
+
const mentionsAgent = content
|
|
132
|
+
.toLowerCase()
|
|
133
|
+
.includes((session.agentHandle || "@assistant").replace(/^@/, "").toLowerCase());
|
|
79
134
|
try {
|
|
80
135
|
if (mentionsAgent && session.agentId) {
|
|
81
136
|
await invokeAgent(content, { agentId: session.agentId });
|
|
@@ -95,7 +150,7 @@ function ChatRoom({ session }: { session: CliSession }) {
|
|
|
95
150
|
<span className="font-medium text-foreground">
|
|
96
151
|
{connected ? "Connected" : connectionState.status}
|
|
97
152
|
</span>
|
|
98
|
-
<span className="text-muted-foreground"
|
|
153
|
+
<span className="text-muted-foreground"> · {session.roomId}</span>
|
|
99
154
|
</span>
|
|
100
155
|
</div>
|
|
101
156
|
|
|
@@ -141,19 +196,16 @@ function ChatRoom({ session }: { session: CliSession }) {
|
|
|
141
196
|
export function App() {
|
|
142
197
|
const session = useMemo(() => loadCliSession() ?? sessionFromEnv(), []);
|
|
143
198
|
|
|
144
|
-
if (!session) return <
|
|
199
|
+
if (!session) return <LocalOnboarding />;
|
|
145
200
|
|
|
146
201
|
return (
|
|
147
202
|
<main className="app-shell">
|
|
148
203
|
<header className="topbar">
|
|
149
|
-
<
|
|
150
|
-
<img src={`${consoleUrl.replace(/\/$/, "")}/fluxychat-icon.svg`} alt="" width={28} height={28} />
|
|
151
|
-
<span>FluxyChat</span>
|
|
152
|
-
</div>
|
|
204
|
+
<Brand />
|
|
153
205
|
<nav className="top-links">
|
|
154
|
-
<span className="meta">{session.projectName || session.projectId || "
|
|
155
|
-
<a href={
|
|
156
|
-
Open
|
|
206
|
+
<span className="meta">{session.projectName || session.projectId || "your room"}</span>
|
|
207
|
+
<a href={dashboardHref()} target="_blank" rel="noreferrer">
|
|
208
|
+
Open dashboard
|
|
157
209
|
</a>
|
|
158
210
|
</nav>
|
|
159
211
|
</header>
|
|
@@ -166,13 +218,17 @@ export function App() {
|
|
|
166
218
|
<ChatRoom session={session} />
|
|
167
219
|
</FluxyRealtimeProvider>
|
|
168
220
|
<aside className="side">
|
|
221
|
+
<section>
|
|
222
|
+
<h2>Try this</h2>
|
|
223
|
+
<ul>
|
|
224
|
+
<li>Open a second tab on this same URL</li>
|
|
225
|
+
<li>Send a message in one tab. It should appear in the other.</li>
|
|
226
|
+
<li>Mention the agent to get a reply</li>
|
|
227
|
+
</ul>
|
|
228
|
+
</section>
|
|
169
229
|
<section>
|
|
170
230
|
<h2>Project</h2>
|
|
171
231
|
<dl>
|
|
172
|
-
<div>
|
|
173
|
-
<dt>ID</dt>
|
|
174
|
-
<dd>{session.projectId || "—"}</dd>
|
|
175
|
-
</div>
|
|
176
232
|
<div>
|
|
177
233
|
<dt>Room</dt>
|
|
178
234
|
<dd>{session.roomId}</dd>
|
|
@@ -184,16 +240,11 @@ export function App() {
|
|
|
184
240
|
</dl>
|
|
185
241
|
</section>
|
|
186
242
|
<section>
|
|
187
|
-
<h2>
|
|
188
|
-
<
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
<a href={`${consoleUrl.replace(/\/$/, "")}/onboarding?from=cli`} target="_blank" rel="noreferrer">
|
|
193
|
-
Continue onboarding in the console
|
|
194
|
-
</a>
|
|
195
|
-
</li>
|
|
196
|
-
</ul>
|
|
243
|
+
<h2>Console</h2>
|
|
244
|
+
<p className="side-copy">Rooms, agents, and settings live in the dashboard.</p>
|
|
245
|
+
<a className="btn-primary side-btn" href={dashboardHref()} target="_blank" rel="noreferrer">
|
|
246
|
+
Open dashboard
|
|
247
|
+
</a>
|
|
197
248
|
</section>
|
|
198
249
|
</aside>
|
|
199
250
|
</div>
|
|
@@ -76,14 +76,14 @@ body {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
.top-links a,
|
|
79
|
-
.side a {
|
|
79
|
+
.side a:not(.btn-primary) {
|
|
80
80
|
color: var(--fluxy-cta-color);
|
|
81
81
|
font-weight: 500;
|
|
82
82
|
text-decoration: none;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
.top-links a:hover,
|
|
86
|
-
.side a:hover {
|
|
86
|
+
.side a:not(.btn-primary):hover {
|
|
87
87
|
text-decoration: underline;
|
|
88
88
|
}
|
|
89
89
|
|
|
@@ -226,6 +226,78 @@ body {
|
|
|
226
226
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
+
.onboard {
|
|
230
|
+
margin: auto;
|
|
231
|
+
max-width: 520px;
|
|
232
|
+
width: calc(100% - 32px);
|
|
233
|
+
background: var(--surface-card);
|
|
234
|
+
border: 1px solid var(--border);
|
|
235
|
+
border-radius: 16px;
|
|
236
|
+
padding: 32px;
|
|
237
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.onboard h1 {
|
|
241
|
+
margin: 0 0 8px;
|
|
242
|
+
font-size: 24px;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.onboard p {
|
|
246
|
+
color: var(--text-muted);
|
|
247
|
+
font-size: 15px;
|
|
248
|
+
line-height: 1.55;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.dots {
|
|
252
|
+
display: flex;
|
|
253
|
+
gap: 6px;
|
|
254
|
+
margin-bottom: 16px;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.dot-step {
|
|
258
|
+
width: 8px;
|
|
259
|
+
height: 8px;
|
|
260
|
+
border-radius: 99px;
|
|
261
|
+
background: var(--border);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.dot-step.active {
|
|
265
|
+
background: var(--fluxy-cta-color);
|
|
266
|
+
width: 22px;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.onboard-actions {
|
|
270
|
+
display: flex;
|
|
271
|
+
align-items: center;
|
|
272
|
+
gap: 10px;
|
|
273
|
+
margin-top: 20px;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.btn-ghost {
|
|
277
|
+
border: 1px solid var(--border);
|
|
278
|
+
background: transparent;
|
|
279
|
+
color: var(--foreground);
|
|
280
|
+
border-radius: 10px;
|
|
281
|
+
padding: 10px 16px;
|
|
282
|
+
font-weight: 600;
|
|
283
|
+
font-size: 14px;
|
|
284
|
+
cursor: pointer;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.btn-primary.side-btn {
|
|
288
|
+
margin-top: 10px;
|
|
289
|
+
width: 100%;
|
|
290
|
+
justify-content: center;
|
|
291
|
+
box-sizing: border-box;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.side-copy {
|
|
295
|
+
margin: 0;
|
|
296
|
+
font-size: 13px;
|
|
297
|
+
color: var(--text-muted);
|
|
298
|
+
line-height: 1.45;
|
|
299
|
+
}
|
|
300
|
+
|
|
229
301
|
.eyebrow {
|
|
230
302
|
font-size: 11px;
|
|
231
303
|
font-weight: 650;
|
|
@@ -248,14 +320,19 @@ body {
|
|
|
248
320
|
|
|
249
321
|
.btn-primary {
|
|
250
322
|
display: inline-flex;
|
|
251
|
-
|
|
323
|
+
align-items: center;
|
|
324
|
+
justify-content: center;
|
|
325
|
+
margin-top: 0;
|
|
252
326
|
background: var(--fluxy-cta-color);
|
|
253
327
|
color: #fff;
|
|
328
|
+
border: none;
|
|
254
329
|
border-radius: 10px;
|
|
255
330
|
padding: 10px 16px;
|
|
256
331
|
font-weight: 600;
|
|
257
332
|
font-size: 14px;
|
|
258
333
|
text-decoration: none;
|
|
334
|
+
cursor: pointer;
|
|
335
|
+
font-family: inherit;
|
|
259
336
|
}
|
|
260
337
|
|
|
261
338
|
.btn-primary:hover {
|