@tomorrowos/sdk 0.9.42 → 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 +74 -74
- package/README.md +4 -3
- package/REPLIT_SETUP.md +83 -33
- package/VERCEL_QUESTIONS.md +23 -23
- package/VERCEL_SETUP.md +1 -1
- package/package.json +1 -1
- package/templates/cms-starter/package.json +2 -2
- package/templates/cms-starter-v0/package.json +2 -2
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
|
|
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
|
|
18
|
-
Never test Supabase connection
|
|
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
|
-
-
|
|
25
|
-
-
|
|
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
|
|
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
|
|
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`
|
|
50
|
-
| Control Panel HTML at `/` via `staticRoot: public` | Vite-only SPA that
|
|
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
|
|
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)
|
|
59
|
-
- **Render / Fly.io**
|
|
60
|
-
- **Vercel Fluid**
|
|
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
|
|
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
|
|
68
|
-
- **Lovable Cloud Storage** (Object Storage replacement
|
|
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
|
|
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**
|
|
79
|
-
| 2 | **Question 2**
|
|
80
|
-
| 3 | **Question 3**
|
|
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**
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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**
|
|
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
|
|
99
|
-
2. **One question at a time.** Wait for the user
|
|
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
|
|
104
|
-
7. After Q&A, **configure and deploy**
|
|
105
|
-
8. **Supabase / Lovable Postgres: configure only
|
|
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
|
|
111
|
+
- Q1 鈫?Q2 鈫?Q3 鈫?execution checklist
|
|
112
112
|
|
|
113
113
|
---
|
|
114
114
|
|
|
115
|
-
## Question 1
|
|
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
|
|
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)
|
|
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
|
|
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
|
|
170
|
+
## Question 2 鈥?Media storage (uploads / thumbnails)
|
|
171
171
|
|
|
172
|
-
### Step A
|
|
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**
|
|
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)
|
|
182
|
-
> - **Local disk only**
|
|
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
|
|
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
|
|
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
|
|
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)
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
255
|
-
> 5. **Text colour** (hex, optional
|
|
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**
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
-
-
|
|
398
|
-
-
|
|
399
|
-
-
|
|
400
|
-
-
|
|
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`**
|
|
407
|
-
- Standalone screen-count / platform / hosting questionnaires outside Q1
|
|
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
|
|
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
|
-
|
|
|
437
|
-
| Lovable Publish URL does not pair TVs | Expected
|
|
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
|
|
446
|
+
## Replit 鈫?Lovable mapping (for Agents)
|
|
447
447
|
|
|
448
448
|
| Replit | Lovable |
|
|
449
449
|
|--------|---------|
|
|
450
|
-
| Replit Secrets | Lovable **Cloud
|
|
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`
|
|
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
|
|
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:
|
|
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
|
|
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
|
package/REPLIT_SETUP.md
CHANGED
|
@@ -14,9 +14,10 @@ Follow @tomorrowos/sdk REPLIT_SETUP.md and set up my TomorrowOS CMS.
|
|
|
14
14
|
Ask only the questions listed in REPLIT_SETUP.md, in order. Do not use LLM_PROMPT.md.
|
|
15
15
|
Artifact kind must be **web** (never **api**).
|
|
16
16
|
Question 1 database options in this order: 1) Supabase (Recommended) 2) Built-in Replit PostgreSQL 3) SQLite.
|
|
17
|
-
If Supabase:
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
If Supabase: show the SUPABASE_URL Secrets input immediately after the choice (same Question 1 — once only).
|
|
18
|
+
If Cloudinary: show all CLOUDINARY_* Secrets inputs immediately after the choice (same Question 2 — one multi-field dialog).
|
|
19
|
+
Question 3: one multi-field dialog with all seven branding inputs stacked (all optional; blanks keep brand.json defaults). Never ask branding fields one-by-one with Next.
|
|
20
|
+
After all setup questions are answered, configure and start — minimal verification only (Web app type + Preview at /). **Never test database connection** in Preview — configure and move on. No DB or WebSocket tests.
|
|
20
21
|
Do not skip steps.
|
|
21
22
|
```
|
|
22
23
|
|
|
@@ -67,16 +68,24 @@ Replit Agent must ask **only** the questions defined in **this file**, in **this
|
|
|
67
68
|
|
|
68
69
|
**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.
|
|
69
70
|
|
|
71
|
+
**Critical — UI shape (Replit multi-input dialogs):** Prefer Replit’s **Secrets / form UI with multiple input fields in one dialog**. Do **not** run a chat wizard that asks one field, waits, then “Next” for the next field.
|
|
72
|
+
|
|
73
|
+
| Step | Required UI |
|
|
74
|
+
|------|-------------|
|
|
75
|
+
| Q1 + Supabase | Database choice → **immediately** one Secrets input for `SUPABASE_URL` (still Question 1) |
|
|
76
|
+
| Q2 + Cloudinary | Media choice → **immediately** one multi-field Secrets dialog for all `CLOUDINARY_*` keys (still Question 2) |
|
|
77
|
+
| Q3 branding | **One** multi-field dialog with **all seven** branding inputs stacked (name, tagline, primary, background, text, secondary, logo) |
|
|
78
|
+
|
|
70
79
|
**Critical — Question 1 option order (exact):** Present database choices in **this order only**:
|
|
71
80
|
1. **Supabase Postgres (Recommended)**
|
|
72
81
|
2. **Built-in Replit PostgreSQL**
|
|
73
82
|
3. **SQLite (local file — fine for testing)**
|
|
74
83
|
|
|
75
|
-
**Critical — Supabase path collected once only:** If the user picks Supabase, collect `SUPABASE_URL` in **one** step (Secrets UI **or** chat paste — not both). After it is saved, **never** ask for the connection string / `SUPABASE_URL` again
|
|
84
|
+
**Critical — Supabase path collected once only:** If the user picks Supabase, collect `SUPABASE_URL` **immediately after the choice**, in **one** step (Secrets UI **or** a single chat paste — not both). After it is saved, **never** ask for the connection string / `SUPABASE_URL` again.
|
|
76
85
|
|
|
77
|
-
**Critical:** Question 2 is **not complete** when the user says “Cloudinary” or “yes”. You **must
|
|
86
|
+
**Critical:** Question 2 is **not complete** when the user says “Cloudinary” or “yes”. You **must immediately** open the **multi-field** Cloudinary Secrets dialog (same Question 2 — **not** “2b”, **not** one key per message) and collect `CLOUDINARY_CLOUD_NAME`, `CLOUDINARY_API_KEY`, and `CLOUDINARY_API_SECRET` **before** Question 3.
|
|
78
87
|
|
|
79
|
-
**Critical — Question 3:**
|
|
88
|
+
**Critical — Question 3:** All seven branding fields are **optional** and must appear in **one stacked multi-input dialog**. Empty / skip / “use defaults” → keep starter **`brand.json`**. **Never** ask name, then colours, then logo across separate turns.
|
|
80
89
|
|
|
81
90
|
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). For Q3, “complete” includes the user skipping or leaving fields blank.
|
|
82
91
|
|
|
@@ -91,10 +100,13 @@ Then ask **Question 1** — do not switch to `LLM_PROMPT.md`.
|
|
|
91
100
|
## Hard rules
|
|
92
101
|
|
|
93
102
|
1. **Ask only REPLIT_SETUP.md questions 1–3** (see **Questionnaire scope**). Never use `LLM_PROMPT.md` on Replit.
|
|
94
|
-
2. **One
|
|
103
|
+
2. **One questionnaire step at a time (Q1 → Q2 → Q3).** Wait for that step to finish before opening the next. **Inside** a step, use **one multi-field dialog** when collecting Secrets or branding — **never** field-by-field “Next” wizards.
|
|
104
|
+
2a. **Q1 Supabase:** choice → **immediately** `SUPABASE_URL` input (same Question 1).
|
|
105
|
+
2b. **Q2 Cloudinary:** choice → **immediately** multi-field `CLOUDINARY_*` Secrets dialog (same Question 2).
|
|
106
|
+
2c. **Q3:** one dialog, **seven inputs stacked** (all optional).
|
|
95
107
|
3. **Do not invent** Cloudinary credentials, Supabase URLs, or brand colours. **Do not ask** screen / device count.
|
|
96
108
|
4. **Do not use Replit’s reserved `DATABASE_URL` Secret for Supabase.** On Replit, `DATABASE_URL` is often the **built-in Replit PostgreSQL** URL. For Supabase always use **`SUPABASE_URL`**. For built-in Replit Postgres, use **`DATABASE_URL`** with `TOMORROWOS_STORE=postgres`.
|
|
97
|
-
4a. **If Supabase is chosen: never collect `SUPABASE_URL` twice.** One capture after the choice is enough
|
|
109
|
+
4a. **If Supabase is chosen: never collect `SUPABASE_URL` twice.** One capture right after the choice is enough.
|
|
98
110
|
4b. **Question 3 fields are all optional.** Missing values → keep starter `brand.json` defaults; do not block or re-prompt.
|
|
99
111
|
4c. **`TOMORROWOS_STORE` + `DATABASE_SSL` are agent-owned.** After the Q1 choice (and URL if needed), set them yourself. Never ask the user to type those names/values.
|
|
100
112
|
5. **Prefer `npx @tomorrowos/sdk init`** (or the package’s `templates/cms-starter`) as the project seed. Do not rebuild pairing, WebSocket, or playlist APIs from scratch.
|
|
@@ -108,7 +120,7 @@ Then ask **Question 1** — do not switch to `LLM_PROMPT.md`.
|
|
|
108
120
|
|
|
109
121
|
- Q1 → Q2 → Q3 → execution checklist
|
|
110
122
|
|
|
111
|
-
Never insert extra questions between these steps. When the user chooses
|
|
123
|
+
Never insert extra questions between these steps. When the user chooses Supabase, **Question 1 continues** with the `SUPABASE_URL` Secrets input **immediately**. When the user chooses Cloudinary, **Question 2 continues** with the multi-field Cloudinary Secrets dialog **immediately**.
|
|
112
124
|
|
|
113
125
|
---
|
|
114
126
|
|
|
@@ -418,21 +430,24 @@ Present **exactly these three options, in this order** (Supabase first / recomme
|
|
|
418
430
|
|
|
419
431
|
### Step B1 — If **1 Supabase (Recommended)**
|
|
420
432
|
|
|
433
|
+
**Immediately after the user selects Supabase** (same Question 1 — do **not** go to Q2 first, do **not** announce “next question”): open the Secrets / connection-string input.
|
|
434
|
+
|
|
421
435
|
Collect `SUPABASE_URL` **exactly once** (IRON RULE).
|
|
422
436
|
|
|
423
437
|
| Allowed (pick **one**) | Forbidden |
|
|
424
438
|
|------------------------|-----------|
|
|
425
|
-
|
|
|
439
|
+
| **Immediately** open Replit **Secrets** UI for `SUPABASE_URL` after the choice | Waiting until later / Q2 / execution to ask for the URI |
|
|
426
440
|
| Save Secret once, then move on | Opening Secrets **and** also asking them to paste the same URI in chat |
|
|
427
441
|
| Reuse the saved Secret in execution | Asking again in Q2 / Q3 / “confirm your Supabase Secret” / Publish / checklist |
|
|
442
|
+
| | Asking “Do you still want to add SUPABASE_URL?” as a separate step after they already chose Supabase |
|
|
428
443
|
|
|
429
444
|
If `SUPABASE_URL` is **already** present in Replit Secrets when this branch starts, **do not** ask for it again — confirm you will use the existing Secret and proceed to Question 2 (unless the user explicitly wants to replace it).
|
|
430
445
|
|
|
431
|
-
**Preferred on Replit:** open an **input / Secrets** UI for:
|
|
446
|
+
**Preferred on Replit (same Question 1 turn after choice):** open an **input / Secrets** UI for:
|
|
432
447
|
|
|
433
448
|
- `SUPABASE_URL`
|
|
434
449
|
|
|
435
|
-
**Only if** the Secrets UI is unavailable, ask exactly in chat
|
|
450
|
+
**Only if** the Secrets UI is unavailable, ask exactly in chat **in the very next message after the choice**. **Do not** also open a second Secrets prompt for the same value:
|
|
436
451
|
|
|
437
452
|
> Paste your Supabase Postgres connection string below. I will store it as the Replit Secret **`SUPABASE_URL`** (not `DATABASE_URL` — that name is for built-in Replit PostgreSQL).
|
|
438
453
|
>
|
|
@@ -520,26 +535,32 @@ tomorrowos.listen({
|
|
|
520
535
|
>
|
|
521
536
|
> Do you want me to set up **Cloudinary**? (yes / no)
|
|
522
537
|
|
|
523
|
-
### Step B — If YES / Cloudinary (same Question 2 —
|
|
538
|
+
### Step B — If YES / Cloudinary (same Question 2 — immediate multi-field Secrets dialog)
|
|
539
|
+
|
|
540
|
+
**Do this in the same Question 2 flow, immediately when the user chooses Cloudinary.**
|
|
524
541
|
|
|
525
|
-
|
|
542
|
+
- ❌ Do **not** say “Question 2b”, “next step”, or “Great — I’ll use Cloudinary” as a separate message before the form
|
|
543
|
+
- ❌ Do **not** ask for cloud name, then API key, then secret across three turns
|
|
544
|
+
- ✅ **Go straight to one Secrets / form dialog with multiple inputs stacked**
|
|
526
545
|
|
|
527
|
-
**Preferred on Replit:** open the **Replit Secrets** UI with fields
|
|
546
|
+
**Preferred on Replit:** open the **Replit Secrets** UI **immediately** with **all** of these fields in **one** dialog:
|
|
528
547
|
|
|
529
548
|
- `CLOUDINARY_CLOUD_NAME`
|
|
530
549
|
- `CLOUDINARY_API_KEY`
|
|
531
550
|
- `CLOUDINARY_API_SECRET`
|
|
532
551
|
- Optional: `CLOUDINARY_FOLDER` (e.g. `tomorrowos`)
|
|
533
552
|
|
|
534
|
-
**If Secrets UI is unavailable, ask exactly (one message
|
|
553
|
+
**If Secrets UI is unavailable, ask exactly once (one message — all fields listed together; user may paste all in one reply):**
|
|
535
554
|
|
|
536
|
-
> Paste your Cloudinary credentials (from [cloudinary.com/console](https://cloudinary.com/console) → Dashboard → **API Keys**). I will store them as Replit **Secrets
|
|
555
|
+
> Paste your Cloudinary credentials (from [cloudinary.com/console](https://cloudinary.com/console) → Dashboard → **API Keys**). I will store them as Replit **Secrets** in one go:
|
|
537
556
|
>
|
|
538
557
|
> 1. **`CLOUDINARY_CLOUD_NAME`**
|
|
539
558
|
> 2. **`CLOUDINARY_API_KEY`**
|
|
540
559
|
> 3. **`CLOUDINARY_API_SECRET`**
|
|
541
560
|
>
|
|
542
561
|
> Optional: **`CLOUDINARY_FOLDER`**
|
|
562
|
+
>
|
|
563
|
+
> You can send all values in a single reply.
|
|
543
564
|
|
|
544
565
|
**You must then:**
|
|
545
566
|
|
|
@@ -564,36 +585,60 @@ The SDK auto-detects these env vars and uploads media to Cloudinary. New uploads
|
|
|
564
585
|
|
|
565
586
|
---
|
|
566
587
|
|
|
567
|
-
## Question 3 — Brand / TomorrowOS app look (`brand.json` only; **
|
|
588
|
+
## Question 3 — Brand / TomorrowOS app look (`brand.json` only; **one multi-field dialog**)
|
|
568
589
|
|
|
569
|
-
> **Scope:** Question 3 answers **only** update **`brand.json
|
|
590
|
+
> **Scope:** Question 3 answers **only** update **`brand.json`**.
|
|
591
|
+
> **Question 3 does NOT affect:** Replit Publish, artifact `kind`, `.replit`, `server.ts`, Secrets, Supabase, Cloudinary, ports, deployment target, or CMS server wiring.
|
|
592
|
+
>
|
|
593
|
+
> **IRON RULE — one dialog, seven stacked inputs:** Present **all seven** branding fields in a **single** Replit form / multi-input dialog (or one chat message that lists all seven for one reply). The user fills what they want and submits **once**.
|
|
570
594
|
>
|
|
571
|
-
> **
|
|
595
|
+
> ❌ **Forbidden:** asking product name → wait → Next → tagline → Next → primary colour → …
|
|
596
|
+
> ❌ **Forbidden:** splitting branding into multiple questionnaire steps
|
|
597
|
+
> ✅ **Required:** one stacked form with every field visible together
|
|
572
598
|
>
|
|
573
|
-
> **Every field
|
|
599
|
+
> **Every field is optional.** Blank / skip / “use defaults” → keep starter `brand.json`. **Do not** re-ask for missing fields.
|
|
600
|
+
|
|
601
|
+
> **This is the only branding block.** Do not ask separate LLM_PROMPT “target platform”, “use case”, or “hosting” questions. **Do not** ask screen count.
|
|
574
602
|
|
|
575
|
-
|
|
603
|
+
### Preferred UI (Replit form / multi-input dialog)
|
|
576
604
|
|
|
577
|
-
**
|
|
605
|
+
Open **one** dialog titled e.g. **Brand your TomorrowOS experience** with these **seven inputs stacked in this order** (labels may match exactly):
|
|
578
606
|
|
|
579
|
-
|
|
607
|
+
1. **Product / venue name** (optional — default from `brand.json`, e.g. `My Venue`)
|
|
608
|
+
2. **Tagline** (optional — default e.g. `Digital signage`)
|
|
609
|
+
3. **Primary colour** (optional hex — default e.g. `#FF8A3D`)
|
|
610
|
+
4. **Background colour** (optional — default e.g. `#FAFAF9`)
|
|
611
|
+
5. **Text colour** (optional — default e.g. `#0A0908`)
|
|
612
|
+
6. **Secondary / accent colour** (optional — default e.g. `#F5F3EF`)
|
|
613
|
+
7. **Logo** (optional) — upload SVG/PNG or paste a URL (otherwise keep `./assets/logo.svg`)
|
|
614
|
+
|
|
615
|
+
Helper text on the dialog: *All fields optional. Leave blank to keep starter brand.json defaults. Submit once.*
|
|
616
|
+
|
|
617
|
+
### If a form UI is unavailable — one chat message only
|
|
618
|
+
|
|
619
|
+
Ask **exactly once** (user may answer all fields in a single reply, partially, or “skip”):
|
|
620
|
+
|
|
621
|
+
> Let’s brand your TomorrowOS experience (**all optional — one reply**). Leave any field blank to keep starter `brand.json` defaults:
|
|
622
|
+
>
|
|
623
|
+
> 1. **Product / venue name**
|
|
624
|
+
> 2. **Tagline**
|
|
625
|
+
> 3. **Primary colour** (hex)
|
|
626
|
+
> 4. **Background colour** (hex)
|
|
627
|
+
> 5. **Text colour** (hex)
|
|
628
|
+
> 6. **Secondary / accent colour** (hex)
|
|
629
|
+
> 7. **Logo** (upload or URL)
|
|
580
630
|
>
|
|
581
|
-
>
|
|
582
|
-
> 2. **Tagline** (optional — default e.g. `Digital signage`)
|
|
583
|
-
> 3. **Primary colour** (optional hex — default e.g. `#FF8A3D`)
|
|
584
|
-
> 4. **Background colour** (optional — default e.g. `#FAFAF9`)
|
|
585
|
-
> 5. **Text colour** (optional — default e.g. `#0A0908`)
|
|
586
|
-
> 6. **Secondary / accent colour** (optional — default e.g. `#F5F3EF`)
|
|
587
|
-
> 7. **Logo** (optional) — upload an SVG/PNG, or a URL to fetch into `./assets/` (otherwise keep `./assets/logo.svg`)
|
|
631
|
+
> Reply with whatever you have in one message, or say **skip**.
|
|
588
632
|
|
|
589
633
|
**Defaults rule (mandatory):**
|
|
590
634
|
|
|
591
635
|
1. Start from the current project **`brand.json`** (after `init`, this matches the SDK starter).
|
|
592
|
-
2. Overlay **only** fields the user actually provided.
|
|
636
|
+
2. Overlay **only** fields the user actually provided in that single submission.
|
|
593
637
|
3. If the user gives **no** product name → keep existing `"name"`.
|
|
594
638
|
4. If the user gives **no** colours → keep existing `primaryColor` / `backgroundColor` / `textColor` / `secondaryColor`.
|
|
595
639
|
5. If the user says **skip** / **defaults** / **n/a** / sends an empty answer → leave `brand.json` unchanged (except set `cms.hostingTarget` to `"here"` if needed — see below).
|
|
596
640
|
6. **Never** re-ask for missing branding fields. **Never** treat blank name/colour as an error.
|
|
641
|
+
7. **Never** follow up with “What about primary colour?” after they already submitted the branding dialog.
|
|
597
642
|
|
|
598
643
|
**Then write / update `brand.json` only** at the project root (validate mentally against `brand.schema.json` in the SDK). **Do not** modify `.replit`, `server.ts`, Secrets, or deployment settings from these answers.
|
|
599
644
|
|
|
@@ -753,6 +798,9 @@ Do **not**:
|
|
|
753
798
|
- Change the production start command away from `tsx server.ts` / `npm run start`
|
|
754
799
|
- Point Supabase at Replit’s reserved `DATABASE_URL` when `SUPABASE_URL` should be used
|
|
755
800
|
- List Q1 databases with **Replit PostgreSQL first** or mark it recommended instead of Supabase
|
|
801
|
+
- Delay `SUPABASE_URL` until after Q1 is “done” or until Q2 — it must follow the Supabase choice **immediately**
|
|
802
|
+
- Collect Cloudinary keys one-at-a-time with Next / separate turns — must be **one multi-field dialog** right after Cloudinary choice
|
|
803
|
+
- Ask Q3 branding fields one-by-one (name → Next → colour → …) — must be **one stacked seven-field dialog**
|
|
756
804
|
- **Ask for `SUPABASE_URL` / the Postgres connection string more than once** (Secrets UI + chat, or again during execution / Publish)
|
|
757
805
|
- Ask the user to type `TOMORROWOS_STORE` or `DATABASE_SSL`
|
|
758
806
|
- Skip Cloudinary recommendation without stating the persistence tradeoff
|
|
@@ -810,7 +858,9 @@ TOMORROWOS_STORE=sqlite
|
|
|
810
858
|
|
|
811
859
|
## Protocol version
|
|
812
860
|
|
|
813
|
-
`replit-setup/1.
|
|
861
|
+
`replit-setup/1.11` — aligned with TomorrowOS protocol `1.0` and `@tomorrowos/sdk` store drivers `sqlite` | `supabase` | `postgres` | `memory`.
|
|
862
|
+
|
|
863
|
+
**Changelog 1.11:** Q1 Supabase → **immediate** `SUPABASE_URL` Secrets input; Q2 Cloudinary → **immediate multi-field** `CLOUDINARY_*` dialog; Q3 = **one stacked dialog with all seven** branding inputs (no field-by-field Next).
|
|
814
864
|
|
|
815
865
|
**Changelog 1.10:** Question 1 is a **database choice** with fixed order: **1) Supabase (Recommended) → 2) Built-in Replit PostgreSQL → 3) SQLite**. Supabase still collects `SUPABASE_URL` once only.
|
|
816
866
|
|
package/VERCEL_QUESTIONS.md
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
# Vercel / v0
|
|
1
|
+
# Vercel / v0 鈥?Verbatim question bank
|
|
2
2
|
|
|
3
|
-
> **Protocol:** `vercel-questions/1.0` (pairs with `VERCEL_SETUP.md` 1.9+ / `@tomorrowos/sdk` 0.9.
|
|
3
|
+
> **Protocol:** `vercel-questions/1.0` (pairs with `VERCEL_SETUP.md` 1.9+ / `@tomorrowos/sdk` 0.9.43+)
|
|
4
4
|
> **For Agents:** When asking the user a setup question, **copy-paste the block below for that step EXACTLY**.
|
|
5
|
-
> Do **not** paraphrase, reorder, rename options, or invent alternatives (no S3, no Supabase Storage, no
|
|
5
|
+
> Do **not** paraphrase, reorder, rename options, or invent alternatives (no S3, no Supabase Storage, no 鈥淏lob recommended鈥? no 鈥渄isable media鈥?.
|
|
6
6
|
> After each answer, configure per `VERCEL_SETUP.md`, then paste the **next** block.
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
## Q1
|
|
10
|
+
## Q1 鈥?Database (paste this entire block)
|
|
11
11
|
|
|
12
12
|
Which database should TomorrowOS use on Vercel?
|
|
13
13
|
|
|
14
|
-
**1. Supabase Postgres (recommended)**
|
|
14
|
+
**1. Supabase Postgres (recommended)** 鈥?durable pairing/playlists; use the **Session pooler** URL (`*.pooler.supabase.com:6543`).
|
|
15
15
|
|
|
16
|
-
**2. Neon Postgres**
|
|
16
|
+
**2. Neon Postgres** 鈥?serverless Postgres native to Vercel; use Neon鈥檚 **pooled** connection string from the Neon dashboard (not the direct un-pooled host for serverless).
|
|
17
17
|
|
|
18
|
-
**3. SQLite (`data/tomorrowos.db`)**
|
|
18
|
+
**3. SQLite (`data/tomorrowos.db`)** 鈥?**demo / local only on Vercel.** The filesystem is ephemeral; pairings and playlists will not survive redeploys. Only choose this if you understand the limitation.
|
|
19
19
|
|
|
20
|
-
Reply with **1**, **2**, or **3** (or
|
|
20
|
+
Reply with **1**, **2**, or **3** (or 鈥淪upabase鈥?/ 鈥淣eon鈥?/ 鈥淪QLite鈥?.
|
|
21
21
|
|
|
22
22
|
---
|
|
23
23
|
|
|
24
|
-
## After Q1
|
|
24
|
+
## After Q1 鈥?agent only (do not ask the user)
|
|
25
25
|
|
|
26
26
|
| Choice | You set silently | User only provides |
|
|
27
27
|
|--------|------------------|--------------------|
|
|
@@ -33,38 +33,38 @@ Never show blank Env fields for `TOMORROWOS_STORE` or `DATABASE_SSL`.
|
|
|
33
33
|
|
|
34
34
|
---
|
|
35
35
|
|
|
36
|
-
## Q2
|
|
36
|
+
## Q2 鈥?Media (paste this entire block)
|
|
37
37
|
|
|
38
38
|
How should playlist media (images/videos) be stored?
|
|
39
39
|
|
|
40
|
-
**1. Cloudinary (recommended)**
|
|
40
|
+
**1. Cloudinary (recommended)** 鈥?durable public HTTPS URLs (`https://res.cloudinary.com/...`). Works out of the box with `@tomorrowos/sdk` auto-detection. **Prefer this on Vercel.**
|
|
41
41
|
|
|
42
|
-
**2. Vercel Blob**
|
|
42
|
+
**2. Vercel Blob** 鈥?Vercel-native object storage; durable `https://*.public.blob.vercel-storage.com/...` URLs. Use when you want media on the same Vercel project without a Cloudinary account.
|
|
43
43
|
|
|
44
|
-
**3. Local disk only**
|
|
44
|
+
**3. Local disk only** 鈥?`cms-panel/uploads` or `public/uploads` (OK for quick local tests; **not** for production Vercel fleets 鈥?files are ephemeral).
|
|
45
45
|
|
|
46
|
-
Reply with **1**, **2**, or **3** (or
|
|
46
|
+
Reply with **1**, **2**, or **3** (or 鈥淐loudinary鈥?/ 鈥淰ercel Blob鈥?/ 鈥渓ocal鈥?.
|
|
47
47
|
|
|
48
|
-
**Forbidden replacements (never ask these):** Vercel Blob as recommended #1; Supabase Storage; S3 / R2 / B2 / `MEDIA_S3_*`;
|
|
48
|
+
**Forbidden replacements (never ask these):** Vercel Blob as recommended #1; Supabase Storage; S3 / R2 / B2 / `MEDIA_S3_*`; 鈥渘o media storage鈥?/ disable uploads.
|
|
49
49
|
|
|
50
50
|
---
|
|
51
51
|
|
|
52
|
-
## Q3
|
|
52
|
+
## Q3 鈥?Brand (paste this entire block)
|
|
53
53
|
|
|
54
|
-
Let
|
|
54
|
+
Let鈥檚 brand your TomorrowOS experience. Choose **one**:
|
|
55
55
|
|
|
56
|
-
**Option A
|
|
56
|
+
**Option A 鈥?Website URL (recommended if you have a site)**
|
|
57
57
|
Paste **one public website URL**. I will use it **only** to fill **`brand.json`**: product name, tagline, primary / secondary / **background** / text colours, fonts, and logo.
|
|
58
|
-
I will **not** rebuild that website or add login
|
|
58
|
+
I will **not** rebuild that website or add login 鈥?unless you explicitly ask for login/auth later.
|
|
59
59
|
|
|
60
|
-
**Option B
|
|
60
|
+
**Option B 鈥?Manual brand fields**
|
|
61
61
|
Send as many of these as you can (name + at least one colour + logo is ideal):
|
|
62
62
|
1. **Product / venue name** (required)
|
|
63
63
|
2. **Tagline** (optional)
|
|
64
64
|
3. **Primary colour** (hex, e.g. `#FF8A3D`)
|
|
65
|
-
4. **Background colour** (hex
|
|
66
|
-
5. **Text colour** (hex, optional
|
|
65
|
+
4. **Background colour** (hex 鈥?page / panel background)
|
|
66
|
+
5. **Text colour** (hex, optional 鈥?default `#0A0908`)
|
|
67
67
|
6. **Secondary / accent colour** (hex, optional)
|
|
68
|
-
7. **Logo**
|
|
68
|
+
7. **Logo** 鈥?upload SVG/PNG into the project, or a public image URL I can fetch into `./assets/`
|
|
69
69
|
|
|
70
70
|
Reply with a URL **or** the manual fields. Do not send only a name with no colours/logo unless you want defaults (I will confirm defaults before writing).
|
package/VERCEL_SETUP.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
>
|
|
6
6
|
> **On Vercel, this file is the setup questionnaire** (not `REPLIT_SETUP.md`, not `LLM_PROMPT.md`).
|
|
7
7
|
>
|
|
8
|
-
> Protocol id: `vercel-setup/1.9` ? pairs with `@tomorrowos/sdk` **0.9.
|
|
8
|
+
> Protocol id: `vercel-setup/1.9` ? pairs with `@tomorrowos/sdk` **0.9.43+** (`templates/cms-starter-v0`, Fluid Functions WebSockets).
|
|
9
9
|
>
|
|
10
10
|
> **Questions source of truth:** `VERCEL_QUESTIONS.md` ? Agents must **open that file and paste each Q block verbatim**. Do not paraphrase.
|
|
11
11
|
> **Copy questions verbatim from `VERCEL_QUESTIONS.md`.** Do not invent alternate Q2 options (no ?Supabase Storage?? no S3, no ?disable media?? no making Blob the recommended option).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tomorrowos/sdk",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.43",
|
|
4
4
|
"description": "TomorrowOS CMS server SDK - WebSocket transport, pairing, device commands, optional static CMS UI. Includes CLI (tomorrowos init / build) and starter templates.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-cms",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.43",
|
|
4
4
|
"description": "CMS server on @tomorrowos/sdk. Add your UI (React, static files, etc.) alongside this server.",
|
|
5
5
|
"private": true,
|
|
6
6
|
"type": "module",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"build-player": "tomorrowos build --platform tizen"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@tomorrowos/sdk": "^0.9.
|
|
16
|
+
"@tomorrowos/sdk": "^0.9.43",
|
|
17
17
|
"dotenv": "^17.2.3",
|
|
18
18
|
"tsx": "^4.19.0"
|
|
19
19
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-cms",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.43",
|
|
4
4
|
"description": "TomorrowOS CMS for Vercel / v0 Publish (Fluid Function + WebSockets + optional Next Preview).",
|
|
5
5
|
"private": true,
|
|
6
6
|
"type": "module",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"build-player": "tomorrowos build --platform tizen"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@tomorrowos/sdk": "^0.9.
|
|
20
|
+
"@tomorrowos/sdk": "^0.9.43",
|
|
21
21
|
"dotenv": "^17.2.3",
|
|
22
22
|
"tsx": "^4.19.0"
|
|
23
23
|
},
|