@tomorrowos/sdk 0.9.41 → 0.9.43

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/LOVABLE_SETUP.md CHANGED
@@ -12,21 +12,21 @@ When a human pastes a prompt like this, **read this file and start Question 1 im
12
12
  ```text
13
13
  Follow @tomorrowos/sdk LOVABLE_SETUP.md and set up my TomorrowOS CMS.
14
14
  Ask only the questions listed in LOVABLE_SETUP.md, in order. Do not use LLM_PROMPT.md.
15
- Do not build a Vite/React mock of TomorrowOS �?use @tomorrowos/sdk cms-starter (Node + WebSocket).
15
+ Do not build a Vite/React mock of TomorrowOS 鈥?use @tomorrowos/sdk cms-starter (Node + WebSocket).
16
16
  Question 3 only updates brand.json.
17
- After setup questions (including Cloudinary Secrets if chosen), configure and deploy �?minimal verification only.
18
- Never test Supabase connection �?save SUPABASE_URL and move on. No Supabase or WebSocket tests.
17
+ After setup questions (including Cloudinary Secrets if chosen), configure and deploy 鈥?minimal verification only.
18
+ Never test Supabase connection 鈥?save SUPABASE_URL and move on. No Supabase or WebSocket tests.
19
19
  Do not skip steps.
20
20
  ```
21
21
 
22
22
  Alternate triggers that also activate this protocol:
23
23
 
24
- - “Set up TomorrowOS on Lovable using LOVABLE_SETUP.md�?
25
- - “Configure my TomorrowOS CMS (Lovable wizard)�?
24
+ - 鈥淪et up TomorrowOS on Lovable using LOVABLE_SETUP.md鈥?
25
+ - 鈥淐onfigure my TomorrowOS CMS (Lovable wizard)鈥?
26
26
 
27
27
  When any of these triggers fire, **ignore `LLM_PROMPT.md` entirely** for the Q&A phase.
28
28
 
29
- **Before Question 1:** read **IRON RULE: real Node CMS only** below. If the project is already a default Lovable Vite + React app with no `@tomorrowos/sdk` server, **do not** keep building that as the TV CMS �?seed or replace with the SDK `cms-starter` layout first.
29
+ **Before Question 1:** read **IRON RULE: real Node CMS only** below. If the project is already a default Lovable Vite + React app with no `@tomorrowos/sdk` server, **do not** keep building that as the TV CMS 鈥?seed or replace with the SDK `cms-starter` layout first.
30
30
 
31
31
  ---
32
32
 
@@ -41,78 +41,78 @@ TomorrowOS CMS needs a **Node.js process** that:
41
41
  - serves the Control Panel at **`GET /`**
42
42
  - keeps **WebSocket** connections open for Tizen / BrightSign players
43
43
 
44
- Lovable’s default app is **Vite + React + Lovable Cloud** (Postgres / Auth / Storage / Edge Functions). That stack **cannot** replace `@tomorrowos/sdk`’s long-lived WebSocket CMS by itself.
44
+ Lovable鈥檚 default app is **Vite + React + Lovable Cloud** (Postgres / Auth / Storage / Edge Functions). That stack **cannot** replace `@tomorrowos/sdk`鈥檚 long-lived WebSocket CMS by itself.
45
45
 
46
46
  | Required | Forbidden |
47
47
  |----------|-----------|
48
48
  | Project seeded from **`npx @tomorrowos/sdk init`** (or `templates/cms-starter`) | Rebuilding pairing / WebSocket / `setPolicy` in React or Edge Functions |
49
- | Live Node entry: `npm run start` �?`tsx server.ts` | Claiming Lovable Cloud **Publish** alone is the TV CMS endpoint |
50
- | Control Panel HTML at `/` via `staticRoot: public` | Vite-only SPA that “looks like�?a CMS but has no TomorrowOS server |
49
+ | Live Node entry: `npm run start` 鈫?`tsx server.ts` | Claiming Lovable Cloud **Publish** alone is the TV CMS endpoint |
50
+ | Control Panel HTML at `/` via `staticRoot: public` | Vite-only SPA that 鈥渓ooks like鈥?a CMS but has no TomorrowOS server |
51
51
  | Durable DB via Supabase / Lovable Cloud Postgres URL | Inventing a hand-rolled store protocol |
52
52
 
53
53
  ### How Publish works on Lovable (read carefully)
54
54
 
55
- 1. **Lovable Agent** = wizard + editor (ask Q1–Q3, write Secrets / `brand.json` / `server.ts`).
55
+ 1. **Lovable Agent** = wizard + editor (ask Q1鈥換3, write Secrets / `brand.json` / `server.ts`).
56
56
  2. **GitHub sync** = required so the Node CMS can be hosted where Node + WebSocket work.
57
57
  3. **TV-facing CMS host** (pick one; do not invent a fourth):
58
- - **Railway** (recommended companion) �?long-lived Node, `npm run start`
59
- - **Render / Fly.io** �?same pattern as Railway
60
- - **Vercel Fluid** �?only if following **`VERCEL_SETUP.md`** / `cms-starter-v0` (do not mix Replit-style root `server.ts` with broken Vercel static deploy)
58
+ - **Railway** (recommended companion) 鈥?long-lived Node, `npm run start`
59
+ - **Render / Fly.io** 鈥?same pattern as Railway
60
+ - **Vercel Fluid** 鈥?only if following **`VERCEL_SETUP.md`** / `cms-starter-v0` (do not mix Replit-style root `server.ts` with broken Vercel static deploy)
61
61
 
62
- **Do not tell the user “Publish on Lovable Cloud�?is done** unless the **Node CMS URL** (Railway / Render / Fly / Vercel Fluid) is live and serves the Control Panel at `/`.
62
+ **Do not tell the user 鈥淧ublish on Lovable Cloud鈥?is done** unless the **Node CMS URL** (Railway / Render / Fly / Vercel Fluid) is live and serves the Control Panel at `/`.
63
63
 
64
64
  Lovable Cloud remains useful for:
65
65
 
66
66
  - **Secrets** UI
67
- - **Postgres** (same family as Supabase �?use as `SUPABASE_URL` / database URL)
68
- - **Lovable Cloud Storage** (Object Storage replacement �?see Question 2)
67
+ - **Postgres** (same family as Supabase 鈥?use as `SUPABASE_URL` / database URL)
68
+ - **Lovable Cloud Storage** (Object Storage replacement 鈥?see Question 2)
69
69
 
70
70
  ---
71
71
 
72
- ## Questionnaire scope (STRICT �?read before asking anything)
72
+ ## Questionnaire scope (STRICT 鈥?read before asking anything)
73
73
 
74
74
  Lovable Agent must ask **only** the questions defined in **this file**, in **this exact order**:
75
75
 
76
76
  | Step | Section | When |
77
77
  |------|---------|------|
78
- | 1 | **Question 1** �?Supabase / Lovable Cloud Postgres connection string | Always |
79
- | 2 | **Question 2** �?Media storage (+ Cloudinary Secrets if chosen) | Always (after Q1) |
80
- | 3 | **Question 3** �?Brand / TomorrowOS app look | Always last, before execution |
78
+ | 1 | **Question 1** 鈥?Supabase / Lovable Cloud Postgres connection string | Always |
79
+ | 2 | **Question 2** 鈥?Media storage (+ Cloudinary Secrets if chosen) | Always (after Q1) |
80
+ | 3 | **Question 3** 鈥?Brand / TomorrowOS app look | Always last, before execution |
81
81
 
82
- **That is the complete list.** There are no other setup questions. **Do not** ask how many screens / devices. There is **no** “Question 2b�?�?Cloudinary credentials are collected **inside Question 2**, immediately after the user chooses Cloudinary.
82
+ **That is the complete list.** There are no other setup questions. **Do not** ask how many screens / devices. There is **no** 鈥淨uestion 2b鈥?鈥?Cloudinary credentials are collected **inside Question 2**, immediately after the user chooses Cloudinary.
83
83
 
84
- **Critical:** Question 2 is **not complete** when the user says “Cloudinary�?or “yes�? You **must** immediately collect `CLOUDINARY_CLOUD_NAME`, `CLOUDINARY_API_KEY`, and `CLOUDINARY_API_SECRET` **before** Question 3. Do **not** skip to branding with placeholder or invented credentials.
84
+ **Critical:** Question 2 is **not complete** when the user says 鈥淐loudinary鈥?or 鈥測es鈥? You **must** immediately collect `CLOUDINARY_CLOUD_NAME`, `CLOUDINARY_API_KEY`, and `CLOUDINARY_API_SECRET` **before** Question 3. Do **not** skip to branding with placeholder or invented credentials.
85
85
 
86
- If the user volunteers extra info early (e.g. brand name before Q3), **record it** and still ask the current question’s required fields you do not yet have. Do not skip ahead to execution until Q1–Q3 are complete (Question 2 includes Cloudinary Secrets when applicable).
86
+ If the user volunteers extra info early (e.g. brand name before Q3), **record it** and still ask the current question鈥檚 required fields you do not yet have. Do not skip ahead to execution until Q1鈥換3 are complete (Question 2 includes Cloudinary Secrets when applicable).
87
87
 
88
- If the user says “just set it up, don’t ask questions,�?respond:
88
+ If the user says 鈥渏ust set it up, don鈥檛 ask questions,鈥?respond:
89
89
 
90
- > I need a few quick answers from LOVABLE_SETUP.md (Postgres connection string, media storage �?plus Cloudinary credentials if you choose Cloudinary �?and branding). It takes about a minute and ensures the CMS deploys correctly with Lovable + a Node host.
90
+ > I need a few quick answers from LOVABLE_SETUP.md (Postgres connection string, media storage 鈥?plus Cloudinary credentials if you choose Cloudinary 鈥?and branding). It takes about a minute and ensures the CMS deploys correctly with Lovable + a Node host.
91
91
 
92
- Then ask **Question 1** �?do not switch to `LLM_PROMPT.md`.
92
+ Then ask **Question 1** 鈥?do not switch to `LLM_PROMPT.md`.
93
93
 
94
94
  ---
95
95
 
96
96
  ## Hard rules
97
97
 
98
- 1. **Ask only LOVABLE_SETUP.md questions 1�?.** Never use `LLM_PROMPT.md` on Lovable for this wizard.
99
- 2. **One question at a time.** Wait for the user’s answer before asking the next (unless they already answered several in one message). **Exception:** If the user chooses Cloudinary in Question 2, **stay on Question 2** and immediately collect Cloudinary Secrets �?do **not** announce a separate �?b�?
98
+ 1. **Ask only LOVABLE_SETUP.md questions 1鈥?.** Never use `LLM_PROMPT.md` on Lovable for this wizard.
99
+ 2. **One question at a time.** Wait for the user鈥檚 answer before asking the next (unless they already answered several in one message). **Exception:** If the user chooses Cloudinary in Question 2, **stay on Question 2** and immediately collect Cloudinary Secrets 鈥?do **not** announce a separate 鈥?b鈥?
100
100
  3. **Do not invent** Cloudinary credentials, database URLs, or brand colours. **Do not ask** screen / device count.
101
101
  4. **Prefer `SUPABASE_URL`** for the Postgres connection string Secret name (same as Replit). Lovable Cloud / linked Supabase both work. Do not commit passwords into git.
102
102
  5. **Prefer `npx @tomorrowos/sdk init`** (or copy `templates/cms-starter`) as the project seed. Do not rebuild pairing, WebSocket, or playlist APIs from scratch.
103
- 6. **Never commit secrets.** Put credentials in Lovable **Cloud �?Secrets** (and the Node host’s env vars: Railway / Render / Fly / Vercel).
104
- 7. After Q&A, **configure and deploy** �?do **not** run a long test suite (see **Post-Q&A: minimal verification only**).
105
- 8. **Supabase / Lovable Postgres: configure only �?never test.** Save `SUPABASE_URL` + `TOMORROWOS_STORE=supabase` and proceed. Do not ping Postgres or treat preview DB errors as a failed setup.
103
+ 6. **Never commit secrets.** Put credentials in Lovable **Cloud 鈫?Secrets** (and the Node host鈥檚 env vars: Railway / Render / Fly / Vercel).
104
+ 7. After Q&A, **configure and deploy** 鈥?do **not** run a long test suite (see **Post-Q&A: minimal verification only**).
105
+ 8. **Supabase / Lovable Postgres: configure only 鈥?never test.** Save `SUPABASE_URL` + `TOMORROWOS_STORE=supabase` and proceed. Do not ping Postgres or treat preview DB errors as a failed setup.
106
106
  9. **Do not** replace `@tomorrowos/sdk` with Edge Functions, React state, or a fake WebSocket.
107
107
  10. **Media durability:** Lovable has **no Replit Object Storage mount** on a local `public/uploads` disk. Use **Cloudinary** or **Lovable Cloud Storage** (see Question 2). Plain local `public/uploads` is ephemeral on most Node hosts unless a volume is attached.
108
108
 
109
109
  **Question order (always):**
110
110
 
111
- - Q1 �?Q2 �?Q3 �?execution checklist
111
+ - Q1 鈫?Q2 鈫?Q3 鈫?execution checklist
112
112
 
113
113
  ---
114
114
 
115
- ## Question 1 �?Supabase / Lovable Cloud Postgres (always)
115
+ ## Question 1 鈥?Supabase / Lovable Cloud Postgres (always)
116
116
 
117
117
  > **This is the first setup question.** Always configure durable Postgres. **Do not** ask how many screens / devices.
118
118
 
@@ -122,7 +122,7 @@ Then ask **Question 1**
122
122
  >
123
123
  > Example shape: `postgresql://postgres.[PROJECT]:[PASSWORD]@aws-0-[REGION].pooler.supabase.com:6543/postgres`
124
124
  >
125
- > If you use **Lovable Cloud**, open **Cloud �?Database** (or project connection settings) and copy the Postgres URI. Also confirm SSL (usually **yes**).
125
+ > If you use **Lovable Cloud**, open **Cloud 鈫?Database** (or project connection settings) and copy the Postgres URI. Also confirm SSL (usually **yes**).
126
126
 
127
127
  **You must then:**
128
128
 
@@ -130,7 +130,7 @@ Then ask **Question 1**
130
130
  2. Save also:
131
131
  - `TOMORROWOS_STORE=supabase`
132
132
  - `DATABASE_SSL=true` (unless the user explicitly says SSL is off)
133
- 3. Mirror the same env vars on the **Node host** (Railway / Render / Fly / Vercel) �?Lovable Secrets alone do not reach a Railway process.
133
+ 3. Mirror the same env vars on the **Node host** (Railway / Render / Fly / Vercel) 鈥?Lovable Secrets alone do not reach a Railway process.
134
134
  4. Wire `server.ts` like the Replit starter:
135
135
 
136
136
  ```ts
@@ -158,7 +158,7 @@ tomorrowos.listen({
158
158
  ```
159
159
 
160
160
  5. **Do not** write the real password into committed files.
161
- 6. **Do not** test the database connection after saving �?configuration only.
161
+ 6. **Do not** test the database connection after saving 鈥?configuration only.
162
162
  7. **Do not** proceed to Question 2 until `SUPABASE_URL` is saved.
163
163
 
164
164
  If the user refuses Postgres, warn that fleets need a durable store, then offer SQLite only after they explicitly confirm (SQLite is a poor fit on ephemeral Lovable/Railway disks).
@@ -167,27 +167,27 @@ If the user refuses Postgres, warn that fleets need a durable store, then offer
167
167
 
168
168
  ---
169
169
 
170
- ## Question 2 �?Media storage (uploads / thumbnails)
170
+ ## Question 2 鈥?Media storage (uploads / thumbnails)
171
171
 
172
- ### Step A �?Ask storage choice
172
+ ### Step A 鈥?Ask storage choice
173
173
 
174
174
  **Ask exactly:**
175
175
 
176
176
  > How should playlist media (images/videos) be stored?
177
177
  >
178
- > **Recommended: Cloudinary** �?public HTTPS URLs; `@tomorrowos/sdk` auto-detects `CLOUDINARY_*` Secrets and `/media/upload` works out of the box.
178
+ > **Recommended: Cloudinary** 鈥?public HTTPS URLs; `@tomorrowos/sdk` auto-detects `CLOUDINARY_*` Secrets and `/media/upload` works out of the box.
179
179
  >
180
180
  > Alternatives:
181
- > - **Lovable Cloud Storage** (replaces Replit Object Storage) �?public Storage bucket on Lovable Cloud / Supabase Storage; durable HTTPS URLs for players.
182
- > - **Local disk only** �?`public/uploads` on the Node host (fine for quick tests; files may disappear on redeploy without a volume).
181
+ > - **Lovable Cloud Storage** (replaces Replit Object Storage) 鈥?public Storage bucket on Lovable Cloud / Supabase Storage; durable HTTPS URLs for players.
182
+ > - **Local disk only** 鈥?`public/uploads` on the Node host (fine for quick tests; files may disappear on redeploy without a volume).
183
183
  >
184
- > Do you want me to set up **Cloudinary**? (yes / no �?if no, say whether you want **Lovable Cloud Storage** or local only)
184
+ > Do you want me to set up **Cloudinary**? (yes / no 鈥?if no, say whether you want **Lovable Cloud Storage** or local only)
185
185
 
186
- ### Step B �?If YES / Cloudinary (same Question 2 �?no �?b�?
186
+ ### Step B 鈥?If YES / Cloudinary (same Question 2 鈥?no 鈥?b鈥?
187
187
 
188
188
  **Do this immediately** when the user chooses Cloudinary. **Go straight to collecting Secrets.**
189
189
 
190
- **Preferred:** Lovable **Cloud �?Secrets** fields for:
190
+ **Preferred:** Lovable **Cloud 鈫?Secrets** fields for:
191
191
 
192
192
  - `CLOUDINARY_CLOUD_NAME`
193
193
  - `CLOUDINARY_API_KEY`
@@ -196,7 +196,7 @@ If the user refuses Postgres, warn that fleets need a durable store, then offer
196
196
 
197
197
  **If Secrets UI is unavailable, ask exactly:**
198
198
 
199
- > Paste your Cloudinary credentials (from [cloudinary.com/console](https://cloudinary.com/console) �?Dashboard �?**API Keys**). I will store them as Secrets:
199
+ > Paste your Cloudinary credentials (from [cloudinary.com/console](https://cloudinary.com/console) 鈫?Dashboard 鈫?**API Keys**). I will store them as Secrets:
200
200
  >
201
201
  > 1. **`CLOUDINARY_CLOUD_NAME`**
202
202
  > 2. **`CLOUDINARY_API_KEY`**
@@ -209,20 +209,20 @@ If the user refuses Postgres, warn that fleets need a durable store, then offer
209
209
  1. Save those Secrets in Lovable **and** on the Node host.
210
210
  2. **Do not** invent or placeholder credentials.
211
211
  3. **Do not** proceed to Question 3 until all three required Secrets exist.
212
- 4. **Do not** run a Cloudinary upload test �?configuration only.
212
+ 4. **Do not** run a Cloudinary upload test 鈥?configuration only.
213
213
 
214
214
  The SDK auto-detects these env vars; new uploads return `https://res.cloudinary.com/...` URLs.
215
215
 
216
- ### If NO �?Lovable Cloud Storage (Object Storage replacement)
216
+ ### If NO 鈥?Lovable Cloud Storage (Object Storage replacement)
217
217
 
218
218
  This is the Lovable equivalent of **Replit Object Storage**: durable files with public HTTPS URLs, not an ephemeral disk folder.
219
219
 
220
220
  **Do this:**
221
221
 
222
- 1. Open / use **Cloud �?Storage**.
222
+ 1. Open / use **Cloud 鈫?Storage**.
223
223
  2. Create a **public** bucket named **`tomorrowos-uploads`** (or confirm it exists). Public read is required so Tizen / BrightSign players can fetch media by URL.
224
224
  3. Save Secrets (Lovable + Node host) as needed for Storage access used by your upload path, typically:
225
- - `SUPABASE_URL` (already from Q1 �?API URL form may differ from Postgres URI; if the project exposes a separate API URL, store it as `SUPABASE_API_URL` only when required)
225
+ - `SUPABASE_URL` (already from Q1 鈥?API URL form may differ from Postgres URI; if the project exposes a separate API URL, store it as `SUPABASE_API_URL` only when required)
226
226
  - Service role or upload-capable key **only in server-side Secrets**, never in client bundles
227
227
  4. Tell the user clearly:
228
228
  - Playlist items must use **absolute `https://...` Storage (or Cloudinary) URLs**.
@@ -231,7 +231,7 @@ This is the Lovable equivalent of **Replit Object Storage**: durable files with
231
231
  5. **Do not** claim that `public/uploads` on Lovable is durable like Replit Object Storage.
232
232
  6. **Do not** invent Cloudinary credentials.
233
233
 
234
- ### If NO �?local disk only
234
+ ### If NO 鈥?local disk only
235
235
 
236
236
  1. Ensure `public/uploads` exists on the Node host (`mkdir -p public/uploads`).
237
237
  2. Warn: redeploys may wipe files unless the host has a persistent volume.
@@ -239,22 +239,22 @@ This is the Lovable equivalent of **Replit Object Storage**: durable files with
239
239
 
240
240
  ---
241
241
 
242
- ## Question 3 �?Brand / TomorrowOS app look (`brand.json` only)
242
+ ## Question 3 鈥?Brand / TomorrowOS app look (`brand.json` only)
243
243
 
244
244
  > **Scope:** Question 3 answers **only** update **`brand.json`**.
245
245
  > **Do not** change deploy host, Secrets, or `server.ts` from branding answers.
246
246
 
247
247
  **Ask exactly (one message; user may answer in one reply):**
248
248
 
249
- > Let’s brand your TomorrowOS experience. Please provide:
249
+ > Let鈥檚 brand your TomorrowOS experience. Please provide:
250
250
  >
251
251
  > 1. **Product / venue name** (shown on screens and the Control Panel)
252
252
  > 2. **Tagline** (optional)
253
253
  > 3. **Primary colour** (hex, e.g. `#FF8A3D`)
254
- > 4. **Background colour** (hex, optional �?default `#FAFAF9`)
255
- > 5. **Text colour** (hex, optional �?default `#0A0908`)
254
+ > 4. **Background colour** (hex, optional 鈥?default `#FAFAF9`)
255
+ > 5. **Text colour** (hex, optional 鈥?default `#0A0908`)
256
256
  > 6. **Secondary / accent colour** (hex, optional)
257
- > 7. **Logo** �?upload an SVG/PNG into the project, or give a URL I can fetch into `./assets/`
257
+ > 7. **Logo** 鈥?upload an SVG/PNG into the project, or give a URL I can fetch into `./assets/`
258
258
 
259
259
  If the user only gives a name and primary colour, use defaults for the rest and say what you assumed.
260
260
 
@@ -288,11 +288,11 @@ If the user only gives a name and primary colour, use defaults for the rest and
288
288
 
289
289
  - Default `cms.hostingTarget` to `"self-hosted"` for Railway / Render / Fly.
290
290
  - Use `"vercel"` only when following the Vercel Fluid path.
291
- - Set `cmsEndpoint` only if the user already knows the public `wss://…` URL; otherwise leave it out and tell them to point players at the published HTTPS CMS URL (player converts `https://` �?`wss://`).
291
+ - Set `cmsEndpoint` only if the user already knows the public `wss://鈥 URL; otherwise leave it out and tell them to point players at the published HTTPS CMS URL (player converts `https://` 鈫?`wss://`).
292
292
 
293
293
  ---
294
294
 
295
- ## After all answers �?execution checklist
295
+ ## After all answers 鈥?execution checklist
296
296
 
297
297
  ### A. Seed the TomorrowOS CMS (not a Lovable React mock)
298
298
 
@@ -347,7 +347,7 @@ Copy the same keys to the **Node host** env.
347
347
  "start": "tsx server.ts"
348
348
  },
349
349
  "dependencies": {
350
- "@tomorrowos/sdk": "^0.9.41",
350
+ "@tomorrowos/sdk": "^0.9.43",
351
351
  "dotenv": "^17.2.3",
352
352
  "tsx": "^4.19.0"
353
353
  }
@@ -362,10 +362,10 @@ Copy the same keys to the **Node host** env.
362
362
  1. Enable **GitHub sync** from Lovable (or push the cms-starter repo).
363
363
  2. Create a **Railway** (or Render / Fly) service from that repo.
364
364
  3. Set Start Command: `npm run start`
365
- 4. Paste Secrets from Q1–Q2 into the host.
365
+ 4. Paste Secrets from Q1鈥換2 into the host.
366
366
  5. Deploy and open the public HTTPS URL.
367
367
 
368
- **If the user insists on Vercel:** stop using this Railway-oriented finish path and follow **`VERCEL_SETUP.md`** (`npx tomorrowos init --hosting v0`) instead �?do not half-migrate.
368
+ **If the user insists on Vercel:** stop using this Railway-oriented finish path and follow **`VERCEL_SETUP.md`** (`npx tomorrowos init --hosting v0`) instead 鈥?do not half-migrate.
369
369
 
370
370
  ### F. Minimal verification only
371
371
 
@@ -390,21 +390,21 @@ Copy the same keys to the **Node host** env.
390
390
 
391
391
  1. Confirm real **`@tomorrowos/sdk`** server (not a React mock).
392
392
  2. Write Secrets / `.env` / `brand.json` / `server.ts` from answers.
393
- 3. Deploy Node host �?Preview Control Panel at `/`.
393
+ 3. Deploy Node host 鈫?Preview Control Panel at `/`.
394
394
 
395
395
  ### Do NOT run after setup (unless user asks or deploy fails)
396
396
 
397
- - �?Supabase connection test
398
- - �?Cloudinary upload test
399
- - �?Formal WebSocket console gates
400
- - �?Long troubleshooting when `/` already shows the Control Panel
397
+ - 鉂?Supabase connection test
398
+ - 鉂?Cloudinary upload test
399
+ - 鉂?Formal WebSocket console gates
400
+ - 鉂?Long troubleshooting when `/` already shows the Control Panel
401
401
 
402
402
  ---
403
403
 
404
404
  ## What not to ask / change
405
405
 
406
- - **`LLM_PROMPT.md`** �?not used for this Lovable wizard
407
- - Standalone screen-count / platform / hosting questionnaires outside Q1–Q3
406
+ - **`LLM_PROMPT.md`** 鈥?not used for this Lovable wizard
407
+ - Standalone screen-count / platform / hosting questionnaires outside Q1鈥換3
408
408
  - Replacing `@tomorrowos/sdk` with Edge Functions or React
409
409
  - Saying **Lovable Cloud Publish** alone is enough for TVs
410
410
  - Treating **Lovable Cloud Storage** as automatic `public/uploads` persistence (it is **not** a disk mount like Replit Object Storage)
@@ -413,7 +413,7 @@ Copy the same keys to the **Node host** env.
413
413
 
414
414
  ---
415
415
 
416
- ## SQLite fallback �?only if user refuses Postgres
416
+ ## SQLite fallback 鈥?only if user refuses Postgres
417
417
 
418
418
  ```ts
419
419
  const store = createTomorrowOSStore({
@@ -433,8 +433,8 @@ Warn that SQLite on ephemeral hosts loses pairings on redeploy.
433
433
 
434
434
  | Symptom | Likely cause | Fix |
435
435
  |---------|--------------|-----|
436
- | “CMS�?is a React app with no pairing | Agent built a Lovable mock | Re-seed with `npx @tomorrowos/sdk init`; deploy Node host |
437
- | Lovable Publish URL does not pair TVs | Expected �?no WebSocket CMS there | Deploy Railway / Render / Fly / Vercel Fluid; use that URL |
436
+ | 鈥淐MS鈥?is a React app with no pairing | Agent built a Lovable mock | Re-seed with `npx @tomorrowos/sdk init`; deploy Node host |
437
+ | Lovable Publish URL does not pair TVs | Expected 鈥?no WebSocket CMS there | Deploy Railway / Render / Fly / Vercel Fluid; use that URL |
438
438
  | `tsx: not found` on host | `tsx` only in devDependencies | Move `tsx` to `dependencies` |
439
439
  | Uploads vanish after redeploy | Local `public/uploads` | Cloudinary or Lovable Cloud Storage public URLs |
440
440
  | Storage files 403 on player | Private bucket | Make `tomorrowos-uploads` **public** read |
@@ -443,11 +443,11 @@ Warn that SQLite on ephemeral hosts loses pairings on redeploy.
443
443
 
444
444
  ---
445
445
 
446
- ## Replit �?Lovable mapping (for Agents)
446
+ ## Replit 鈫?Lovable mapping (for Agents)
447
447
 
448
448
  | Replit | Lovable |
449
449
  |--------|---------|
450
- | Replit Secrets | Lovable **Cloud �?Secrets** (+ copy to Node host) |
450
+ | Replit Secrets | Lovable **Cloud 鈫?Secrets** (+ copy to Node host) |
451
451
  | Replit Object Storage / `public/uploads` | **Lovable Cloud Storage** public bucket `tomorrowos-uploads` (or Cloudinary) |
452
452
  | `.replit` + Autoscale Publish | **GitHub sync + Railway/Render/Fly** `npm run start` (or **VERCEL_SETUP.md**) |
453
453
  | Artifact `kind = web` | Real cms-starter Node app with Control Panel at `/` |
@@ -457,6 +457,6 @@ Warn that SQLite on ephemeral hosts loses pairings on redeploy.
457
457
 
458
458
  ## Protocol version
459
459
 
460
- `lovable-setup/1.0` �?aligned with TomorrowOS protocol `1.0` and `@tomorrowos/sdk` store drivers `sqlite` | `supabase` | `postgres` | `memory`.
460
+ `lovable-setup/1.0` 鈥?aligned with TomorrowOS protocol `1.0` and `@tomorrowos/sdk` store drivers `sqlite` | `supabase` | `postgres` | `memory`.
461
461
 
462
- **Changelog 1.0:** Initial Lovable wizard mirroring REPLIT_SETUP Q1–Q3; IRON RULE that Lovable Cloud Publish is not the WebSocket CMS host; Replit Object Storage replaced by Lovable Cloud Storage (+ Cloudinary still recommended for `/media/upload`).
462
+ **Changelog 1.0:** Initial Lovable wizard mirroring REPLIT_SETUP Q1鈥換3; IRON RULE that Lovable Cloud Publish is not the WebSocket CMS host; Replit Object Storage replaced by Lovable Cloud Storage (+ Cloudinary still recommended for `/media/upload`).
package/README.md CHANGED
@@ -65,11 +65,12 @@ In Replit Agent, paste:
65
65
  Follow @tomorrowos/sdk REPLIT_SETUP.md and set up my TomorrowOS CMS.
66
66
  Ask me the questions in order. Do not skip steps.
67
67
  Q1 database order: Supabase (Recommended), then Built-in Replit PostgreSQL, then SQLite.
68
- If Supabase: collect SUPABASE_URL once only. Question 3 branding is all optional (defaults from brand.json).
68
+ If Supabase: SUPABASE_URL Secrets input immediately after choice (once only).
69
+ If Cloudinary: all CLOUDINARY_* Secrets in one multi-field dialog immediately after choice.
70
+ Q3: one stacked dialog with all seven branding fields (optional; blanks keep brand.json defaults).
69
71
  ```
70
72
 
71
- That wizard asks database choice (**Supabase recommended first**), prefers Cloudinary for media, and writes
72
- `brand.json` from optional branding answers (missing fields keep starter defaults). On Replit, Supabase must use Secret
73
+ That wizard asks database choice (**Supabase recommended first**), prefers Cloudinary for media, and collects optional branding in **one multi-field dialog**. On Replit, Supabase must use Secret
73
74
  **`SUPABASE_URL`** (not the reserved `DATABASE_URL` — that is for built-in Replit PostgreSQL).
74
75
 
75
76
  ### Lovable guided setup