@tomorrowos/sdk 1.1.3 → 1.1.4

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.
@@ -1,11 +1,12 @@
1
1
  # Vercel / v0 - Verbatim question bank
2
2
 
3
- > **Protocol:** `vercel-questions/1.7` (pairs with `VERCEL_SETUP.md` 1.18+ / `@tomorrowos/sdk` 0.9.70+)
3
+ > **Protocol:** `vercel-questions/1.8` (pairs with `VERCEL_SETUP.md` 1.19+ / `@tomorrowos/sdk` 0.9.70+)
4
4
  > **For Agents:** When asking the user a setup question, **copy-paste the block below for that step EXACTLY**.
5
5
  > Do **not** paraphrase, reorder, rename options, or invent alternatives (no S3, no Supabase Storage, no "Blob recommended", no "disable media").
6
6
  > After each answer, configure per `VERCEL_SETUP.md`, then paste the **next** block.
7
7
  > **Q1 and Q2 are choice questions — present them as a clickable choice UI** (buttons / radio / option cards) using the exact option labels below. Do **not** ask the user to type `1` or `2` in chat when a choice UI is available (chat typing is fallback only).
8
- > **Q3 is a form only - never a multiple-choice question. Q4 is optional CMS password (`CMS_PASSWORD`).**
8
+ > **Q3 is a form only - never a multiple-choice question.**
9
+ > **Q4 is optional CMS password (`CMS_PASSWORD`) — immediately after Q3, no yes/no prelude.** Open the password Env/Secret input; blank/skip is valid.
9
10
  > **HARD STOP on Q3:** show the form, then **wait** for the user's reply. Optional fields do **not** mean you may auto-skip.
10
11
  > **Q4 is optional:** blank/skip is valid; they can set `CMS_PASSWORD` later.
11
12
  > **After Q4 (or after Q3 if you deferred Q4):** run `VERCEL_SETUP.md` **IRON GATE — v0 Preview hygiene** before debugging Neon/Postgres or Blob.
@@ -93,18 +94,22 @@ How should playlist media (images/videos) be stored?
93
94
  - Auto-continuing to init/scaffold/deploy without a user Q3 reply or explicit "skip"
94
95
  - Interpreting "do not re-ask" as "do not wait for the first reply"
95
96
 
96
- After the user submits (including all-blank) or says "skip": apply `brand.json`, then paste **Q4**. **Do not** re-ask Q3 a second time.
97
+ After the user submits (including all-blank) or says "skip": apply `brand.json`, then open **Q4 immediately** (CMS_PASSWORD Env input — **no** yes/no prelude). **Do not** re-ask Q3 a second time.
97
98
  Blank fields -> keep existing `brand.json`. Logo blank -> `./assets/logo.svg`.
98
99
 
99
100
  ---
100
101
 
101
- ## Q4 - Optional CMS password (paste this entire block)
102
+ ## Q4 - Optional CMS password (Env input immediately after Q3)
102
103
 
103
- Optional: set a CMS password now?
104
+ **IRON RULE — no prelude:** Right after Q3, open the **CMS_PASSWORD** Env/Secret input. **Forbidden first:** "Do you want a password?", "Enable auth?", "Protect the CMS?", Option A/B yes/no.
104
105
 
105
- If yes, reply with the password to store as Environment Variable **`CMS_PASSWORD`**.
106
+ **UX (required):** One Env/Secret field labeled **`CMS_PASSWORD`** (password input). User may enter a password **or** leave blank / skip.
106
107
 
107
- Leave blank / reply **skip** / **later** / **no** to keep the panel open for now — you can add `CMS_PASSWORD` later in Vercel → Settings → Environment Variables and redeploy.
108
+ **Title / helper:**
109
+
110
+ Optional CMS password — Environment Variable **`CMS_PASSWORD`**.
111
+
112
+ Enter a password to lock the Control Panel, or leave blank / skip to keep the panel open. You can add `CMS_PASSWORD` later in Vercel → Settings → Environment Variables and redeploy.
108
113
 
109
114
  **Notes for the agent (do not invent extra UX):**
110
115
  - This is **optional**. Blank/skip is a valid complete answer.
package/VERCEL_SETUP.md CHANGED
@@ -5,14 +5,15 @@
5
5
  >
6
6
  > **On Vercel, this file is the setup questionnaire** (not `REPLIT_SETUP.md`).
7
7
  >
8
- > Protocol id: `vercel-setup/1.18` - pairs with `@tomorrowos/sdk` **0.9.70+** (`templates/cms-starter-v0`, Fluid Functions WebSockets).
8
+ > Protocol id: `vercel-setup/1.19` - pairs with `@tomorrowos/sdk` **0.9.70+** (`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
  > **Q1/Q2 = clickable choice UI (same pattern):** open a **button / radio / option-card UI** with the two fixed choices. Do **not** ask the user to type `1` or `2` in chat when a choice UI is available. Chat “reply 1 or 2” is fallback only.
12
12
  > **Q3 = form only:** open **all seven optional inputs at once**, then **HARD STOP and WAIT** for submit or "skip". Never auto-skip because fields are optional. Never ask a branding choice first. Never show only Name + Primary colour. Logo = **Upload** above **Logo URL**.
13
- > **Q4 = optional `CMS_PASSWORD`:** blank/skip is valid; can set later. Control Panel auth only — never Vercel Deployment Protection / whole-site password.
13
+ > **Q4 = optional `CMS_PASSWORD` (immediately after Q3, no prelude):** open the **CMS password Env/Secret input** right away. Blank/skip is valid. **Forbidden:** yes/no “Do you want a password / enable auth?” before the field. Control Panel auth only — never Vercel Deployment Protection / whole-site password.
14
14
  > **After Q&A (before debugging DB):** run **IRON GATE — v0 Preview hygiene** (clear root Next leftovers, restart supervised `dev`, prove `GET /status` is TomorrowOS JSON). Do **not** spend turns “fixing Neon/Blob” while port 3000 is still a stale Next/Turbopack process.
15
- > **Publish Output Directory:** must stay **empty / unset**. Build error `Output Directory "public" is empty` means the dashboard still points at `public/` — **clear it**; do **not** “fix” by stuffing `public/robots.txt` while leaving Output = `public`.
15
+ > **Publish Output Directory:** must stay **empty / unset**.
16
+ > **Publish Build Command:** must be **empty / skip build** (`"buildCommand": ""` in `vercel.json` + dashboard). A defined build command (even a no-op `npm run build`) forces Vercel **static-build** mode and requires `public/` — that causes `Output Directory "public" is empty` / not found. Do **not** “fix” by stuffing `public/robots.txt`.
16
17
  > **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).
17
18
  > **`TOMORROWOS_STORE` and `DATABASE_SSL` are agent-only** - set them automatically after Q1; never put them in a user-facing Env form for the customer to type.
18
19
 
@@ -22,7 +23,8 @@ The following rules are **mandatory acceptance criteria**, not suggestions. The
22
23
 
23
24
  1. **One TomorrowOS instance only.** Use the shared instance exported through `api/index.ts`. **Never create a second `TomorrowOS` instance in `api/ws.ts`** or any other route.
24
25
  2. **Never use `public/` as the Vercel Output Directory.** The dashboard Output Directory must be **empty / unset**. Serve the Control Panel at runtime from `cms-panel/` through TomorrowOS `staticRoot`.
25
- 2a. **Build error `The Output Directory "public" is empty`:** This is **not** fixed by adding `public/robots.txt` as the primary solution. It means Project Settings still has Output Directory = `public`. **Clear/unset Output Directory**, confirm Framework = Other, Fluid Function `api/index.ts` + rewrites, then redeploy. Filling `public/` only papers over a wrong static-output setting.
26
+ 2a. **Build Command must be empty / skip build** (`"buildCommand": ""` in `vercel.json`, dashboard Build Command empty). Do **not** use a no-op `npm run build` / `node -e "process.exit(0)"` as the Production build command — any defined build command with Framework=Other puts Vercel in **static-build** mode and requires a `public/` output directory.
27
+ 2b. **Build errors `The Output Directory "public" is empty` or `public` not found:** First clear Output Directory if it is set to `public`. If Output is already null and the error remains, the cause is a **defined Build Command** — set Build Command / `buildCommand` to **empty string** and redeploy. Filling `public/` only papers over wrong static-output mode.
26
28
  3. **Preview may use Next only as an isolated reverse-proxy shell under `preview/`.** Preview must not replace TomorrowOS or determine the Production runtime.
27
29
  4. **Publish must use the Fluid Function.** Production must run `api/index.ts` ??the shared exported `http.Server`, with Fluid compute enabled. It must not use `next start`, a static export, or a bare `(req, res)` handler.
28
30
  5. **After every Production deployment, verify all three gates before saying setup is complete:**
@@ -45,11 +47,11 @@ Open VERCEL_QUESTIONS.md first.
45
47
  For Q1 and Q2: open a **clickable choice UI** (buttons / radio / option cards) using the verbatim options from VERCEL_QUESTIONS.md. Do not ask me to type 1 or 2 in chat when UI is available.
46
48
  For Q1, Q2, Q3: use exact option wording from VERCEL_QUESTIONS.md. Do not rephrase options.
47
49
  For Q3: DO NOT ask a branding choice. Open one form with ALL SEVEN optional inputs at once, then HARD STOP and WAIT for my submit or "skip". Never auto-continue with defaults without my reply. Never only Name + Primary colour. Logo = Upload above Logo URL.
48
- After Q3, paste Q4 (optional CMS password). Blank/skip is valid.
50
+ After Q3, open Q4 immediately: one Env/Secret input for CMS_PASSWORD (blank/skip OK). Do NOT ask yes/no "want a password?" first.
49
51
  After Q1 database choice, YOU set TOMORROWOS_STORE and DATABASE_SSL. Do not ask me to fill those.
50
52
  After Q2 media storage choice, YOU set TOMORROWOS_MEDIA. Do not ask me to fill those.
51
53
  After answers: run IRON GATE v0 Preview hygiene BEFORE debugging Postgres/media — clear root Next leftovers, restart supervised dev, prove GET /status is TomorrowOS JSON.
52
- Before Publish: Output Directory must be empty/unset (NOT public). If build says Output Directory public is empty, CLEAR Output Directory — do not stuff public/robots.txt as the fix.
54
+ Before Publish: Output Directory empty/unset (NOT public). Build Command EMPTY (buildCommand: "") — never a no-op npm run build (forces static public/ check). Do not stuff public/robots.txt.
53
55
  Run: npx @tomorrowos/sdk@latest init . --hosting v0 --force
54
56
  Keep cms-starter-v0 layout.
55
57
  Apply the NON-NEGOTIABLE VERCEL RUNTIME CONTRACT exactly:
@@ -111,8 +113,8 @@ almost always means **Vercel still thinks this is a Next.js / static deploy**, n
111
113
  If it still says **Next.js**, patch it via Vercel API / CLI / dashboard **before** redeploying.
112
114
  `"framework": null` in `vercel.json` alone is **not enough** if the dashboard still says Next.js.
113
115
  2. **Install Command** = `npm install` / `pnpm install` / `yarn` (normal install).
114
- 3. **Build Command** = a **no-op that exits 0** (e.g. `node -e "process.exit(0)"` or `npm run build` where `build` is that no-op).
115
- **Never** run `next build` for Production.
116
+ 3. **Build Command** = **empty / skip build** (`""` in `vercel.json` and dashboard).
117
+ **Never** run `next build` for Production. **Never** use a no-op `npm run build` / `node -e "process.exit(0)"` as the Production build command — that forces static-build mode and the `public/` output check.
116
118
  4. **Production entry** = Fluid **Vercel Function** `api/index.ts` that **`export default server`** from shared `cms-app.ts` (see [WebSockets docs](https://vercel.com/docs/functions/websockets)). Local `npm start` may still use root `server.ts`.
117
119
  5. **Output Directory** = **empty / unset**. Do **not** set `outputDirectory: "."` as a fake static site.
118
120
  6. **Do** use a single `api/index.ts` that exports the TomorrowOS `http.Server`. **Do not** create a second TomorrowOS in `api/ws.ts`, and **do not** use bare `(req, res)` handlers that drop upgrades.
@@ -136,19 +138,29 @@ almost always means **Vercel still thinks this is a Next.js / static deploy**, n
136
138
  ```text
137
139
  Error: The Output Directory "public" is empty.
138
140
  ```
139
- **Root cause B:** Project Settings **Output Directory is still `public`**, but this CMS has **no** (or empty) static export folder — UI lives in `cms-panel/` and is served by the Fluid Function.
141
+ or (after deleting `public/`):
142
+ ```text
143
+ No Output Directory named "public"
144
+ ```
145
+ (wording may vary; both mean Vercel is in **static-build** mode looking for `public/`)
146
+
147
+ **Root cause B (check in order):**
148
+ 1. Project Settings **Output Directory = `public`** (explicit override) — clear it.
149
+ 2. Output Directory is already **null**, but a **Build Command is defined** (`npm run build` or any no-op). With Framework=Other, a defined build command forces static-build mode and defaults the output check to `public/` — even when dashboard Output is unset.
140
150
 
141
151
  **Correct fix (mandatory for A and B):**
142
152
 
143
- 1. Set **Output Directory** = **empty / unset** (dashboard and/or project settings API).
144
- 2. Framework Preset = **Other** / null; Fluid on; `api/index.ts` + rewrites per Scheme A.
145
- 3. Redeploy. Verify `GET /status` is **JSON** and WebSocket is **101**.
153
+ 1. Set **Output Directory** = **empty / unset**.
154
+ 2. Set **Build Command** = **empty** (`"buildCommand": ""` in `vercel.json` + dashboard). This is a **functions-only** deploy; skip the static build step entirely.
155
+ 3. Framework Preset = **Other** / null; Fluid on; `api/index.ts` + rewrites per Scheme A.
156
+ 4. Redeploy. Verify `GET /status` is **JSON** and WebSocket is **101**.
146
157
 
147
158
  **Forbidden “fixes”:**
148
159
 
149
160
  - Adding `public/robots.txt` / `.gitkeep` **so a static Output Directory = `public` build passes** — that leaves Production on the static trap path.
161
+ - Keeping a no-op `buildCommand: "npm run build"` while hoping Output=null is enough — the defined build command still triggers the `public/` check.
150
162
  - Setting Output Directory to `cms-panel`, `.`, or `public`.
151
- - Claiming Publish succeeded because the build log turned green while Output is still `public`.
163
+ - Claiming Publish succeeded because the build log turned green while Output is still `public` or Build Command still runs a static check.
152
164
 
153
165
  **Optional:** If some tooling creates an empty `public/` folder, delete it or ignore it — **never** point Output Directory at it.
154
166
 
@@ -192,10 +204,14 @@ Ask **only** these questions, in **this exact order**. **Copy the ?Ask exactly??
192
204
  | 1 | **Question 1** ? Database (Supabase ? Neon) | Always |
193
205
  | 2 | **Question 2** ? Media (**Cloudinary recommended** ? Vercel Blob) | Always (after Q1) |
194
206
  | 3 | **Question 3** - Brand form (`brand.json` only; **not a choice** - open all 7 optional inputs at once) | Always (after Q2) |
195
- | 4 | **Question 4** - Optional CMS password Env `CMS_PASSWORD` (**optional**; blank = skip, can set later) | Always last |
207
+ | 4 | **Question 4** - Optional CMS password Env `CMS_PASSWORD` (**immediately after Q3**; blank = skip; **no** yes/no prelude) | Always last |
196
208
 
197
209
  **That is the complete list (Q1–Q4).** Do **not** ask how many screens / devices.
198
210
 
211
+ | Step UX | Rule |
212
+ |---------|------|
213
+ | Q4 CMS password | **Immediately after Q3** — one Env/Secret input for `CMS_PASSWORD` (blank/skip allowed). **Never** ask a yes/no "do you want a password?" first. |
214
+
199
215
  **Forbidden invented Question 2 options (never offer these in chat or UI):**
200
216
 
201
217
  - ???Vercel Blob **(recommended)**??as option 1 ??Blob is option **2**, not recommended over Cloudinary
@@ -232,6 +248,7 @@ Then ask **Question 1**.
232
248
 
233
249
  1. **Open `VERCEL_QUESTIONS.md` first.** Ask Q1 → configure → Q2 → configure → Q3 → Q4. Never paraphrase question options. Never use `REPLIT_SETUP.md` as the questionnaire. **Never** ask for OpenAI or other LLM API keys.
234
250
  1a. **Q1 and Q2 UX:** Prefer a **clickable choice UI** (same pattern for both): two option buttons/cards matching the verbatim labels. **Forbidden when UI exists:** chat-only “Reply with 1 or 2”. Chat typing is fallback only if the platform cannot render choices.
251
+ 1b. **Q4 UX:** Immediately after Q3, open the **`CMS_PASSWORD` Env/Secret input**. **Forbidden:** yes/no “Do you want a password / enable auth?” prelude. Blank/skip is a complete answer.
235
252
  2. **Question 2 options are fixed:** (1) Cloudinary **(recommended)**, (2) Vercel Blob. Do not reorder; do not invent Supabase Storage, local disk, or disable-uploads.
236
253
  3. **Cloudinary:** open **one** Vercel Env popup with **all** Cloudinary fields together. Do **not** quiz one credential at a time.
237
254
  4. **`TOMORROWOS_STORE` + `DATABASE_SSL` = agent-owned.** After Q1 choice (and URL if needed), set them yourself in Vercel Env Vars. **Never** include them as blank fields for the customer. Mapping: Supabase ? `TOMORROWOS_STORE=supabase` + `DATABASE_SSL=true`; Neon ? `TOMORROWOS_STORE=postgres` + `DATABASE_SSL=true`. **Do not offer SQLite as a questionnaire choice** ? it is ephemeral on Vercel and unsuitable for production.
@@ -252,7 +269,7 @@ Then ask **Question 1**.
252
269
  19. **Q3 is a form, not a question — and you must WAIT.** After Q2, open one dialog with **all seven** optional inputs visible together, then **stop and wait** for submit or explicit **"skip"**. **Never** auto-continue because fields are optional. **Never** ask a preliminary branding choice. **Never** show only Product Name + Primary colour. **Never** use multiple-choice / Option A-B for branding. Logo = **Upload** above **Logo URL**.
253
270
  20. **IRON GATE after Q&A:** Before blaming Neon / Blob / migrations, complete **IRON GATE — v0 Preview hygiene** below. Preview 500s are usually leftover root Next or a stale supervised `next-server`, not a bad Q1/Q2 choice.
254
271
 
255
- **Question order:** Q1 -> (auto-set store env) -> Q2 -> Q3 form (**wait for user**) -> Q4 optional `CMS_PASSWORD` -> **IRON GATE** -> execution checklist.
272
+ **Question order:** Q1 -> (auto-set store env) -> Q2 -> Q3 form (**wait for user**) -> Q4 `CMS_PASSWORD` Env input (**no yes/no prelude**; blank/skip OK) -> **IRON GATE** -> execution checklist.
256
273
 
257
274
  ---
258
275
 
@@ -415,7 +432,7 @@ SDK behaviour (0.9.32+):
415
432
  "fluid": true,
416
433
  "framework": null,
417
434
  "installCommand": "npm install",
418
- "buildCommand": "npm run build",
435
+ "buildCommand": "",
419
436
  "functions": {
420
437
  "api/index.ts": {
421
438
  "maxDuration": 300,
@@ -429,7 +446,7 @@ SDK behaviour (0.9.32+):
429
446
  }
430
447
  ```
431
448
 
432
- **`maxDuration` plan limits:** Hobby / many default plans allow **1??00** seconds. **800** requires a higher Vercel plan. Prefer **`300`** unless the account already allows more ??otherwise Publish fails with *?maxDuration must be between 1 and 300??upgrade your plan??.
449
+ **`maxDuration` plan limits:** Hobby / many default plans allow **1–300** seconds. **800** requires a higher Vercel plan. Prefer **`300`** unless the account already allows more — otherwise Publish fails with *maxDuration must be between 1 and 300 / upgrade your plan*.
433
450
 
434
451
  **Why rewrites:** Public URLs stay `https://app.vercel.app/` and `/status` while the Function mount is `/api`. Device `wss://app.vercel.app/` is rewritten to the same Function so one isolate handles HTTP + WS.
435
452
 
@@ -439,8 +456,8 @@ SDK behaviour (0.9.32+):
439
456
 
440
457
  - `"fluid": true` is required for WebSockets
441
458
  - **Do not** set `outputDirectory` to `cms-panel` / `public`
442
- - `"buildCommand"` = no-op ??**never** `next build` for Production
443
- - Dashboard Output Directory must stay **empty**
459
+ - `"buildCommand": ""` — **skip build entirely** (functions-only). **Never** `next build`. **Never** a no-op `npm run build` as Production build (forces static `public/` check)
460
+ - Dashboard Output Directory must stay **empty**; dashboard Build Command must stay **empty** (or match `""`)
444
461
 
445
462
  ### A4 — Vercel Project Settings (dashboard — mandatory)
446
463
 
@@ -448,14 +465,17 @@ SDK behaviour (0.9.32+):
448
465
  |---------|----------------|
449
466
  | Framework Preset | **Other** / null — **not Next.js** |
450
467
  | Install Command | `npm install` |
451
- | Build Command | `npm run build` (no-op) |
468
+ | **Build Command** | **empty / skip** — **not** `npm run build` |
452
469
  | **Output Directory** | **empty / unset** — **never `public`** |
453
470
  | Fluid compute | **On** |
454
471
  | WebSockets | Account must allow Functions WebSockets (see docs — Permissions Required) |
455
472
 
456
- **If Publish build fails with `The Output Directory "public" is empty`:** the dashboard still has Output = `public`. **Clear/unset it** via Project Settings (or settings API), then redeploy. Do **not** add `public/robots.txt` (or any static filler) as the primary fix while Output stays `public`.
473
+ **If Publish build fails with `The Output Directory "public" is empty` or `public` not found:**
474
+ 1. Clear Output Directory if set to `public`.
475
+ 2. If Output is already null: set **Build Command** / `vercel.json` `"buildCommand"` to **`""`** and redeploy. A defined build command (even no-op) forces static-build mode.
476
+ 3. Do **not** add `public/robots.txt` as the primary fix.
457
477
 
458
- **`vercel.json` must not set `outputDirectory`.** Leaving it out is correct; dashboard Output must still be forced empty because Framework=Other may default to “public if it exists”.
478
+ **`vercel.json` must not set `outputDirectory`.** Leaving it out is correct. **`buildCommand` must be `""`** (empty string), not omitted if the dashboard still has a leftover `npm run build` — set both file and dashboard.
459
479
 
460
480
  ### A5 ??Publish acceptance (all must pass)
461
481
 
@@ -532,7 +552,7 @@ Adapt script names / process runners as needed. **Invariant:**
532
552
 
533
553
  - **Local `npm start`** = TomorrowOS Node with `server.listen`.
534
554
  - **Vercel Production** = Function `api/index.ts` (SDK `autoListen=false` when `VERCEL` is set).
535
- - **`build`** = no-op exit 0 (never `next build` for Production).
555
+ - **`vercel.json` `"buildCommand"`** = `""` (skip build). Optional `package.json` `"build"` no-op is unused by Vercel Publish — **never** wire it as the Production Build Command.
536
556
  - **Preview / v0** = Next on public port + TomorrowOS on internal port + proxy.
537
557
 
538
558
  ### Minimal dependencies (Production)
@@ -649,23 +669,23 @@ Write `vercel.json` so Production cannot be mistaken for Next. Minimum:
649
669
  "fluid": true,
650
670
  "framework": null,
651
671
  "installCommand": "npm install",
652
- "buildCommand": "npm run build"
672
+ "buildCommand": ""
653
673
  }
654
674
  ```
655
675
 
656
- Use `pnpm` / `yarn` variants of install/build if that is the project?s package manager.
676
+ Use `pnpm` / `yarn` variants of install if that is the project's package manager. **`buildCommand` must be `""`** (skip build) — do **not** set `npm run build` even as a no-op.
657
677
 
658
- **Do not** add `startCommand`, `processes`, or `outputDirectory` to `vercel.json` when v0 schema rejects them. Start = `package.json` `"start": "tsx server.ts"`. Output Directory = **empty in dashboard**.
678
+ **Do not** add `startCommand`, `processes`, or `outputDirectory` to `vercel.json` when v0 schema rejects them. Start = `package.json` `"start": "tsx server.ts"`. Output Directory = **empty in dashboard**. Build Command = **empty in dashboard**.
659
679
 
660
- **Also force Project Settings (dashboard or Vercel API) ??this is mandatory (see Scheme A4):**
680
+ **Also force Project Settings (dashboard or Vercel API) — this is mandatory (see Scheme A4):**
661
681
 
662
682
  | Setting | Required value |
663
683
  |---------|----------------|
664
- | Framework Preset | **Other** / null ??**not Next.js** |
684
+ | Framework Preset | **Other** / null — **not Next.js** |
665
685
  | Install Command | `npm install` (or pnpm/yarn) |
666
- | Build Command | `npm run build` (no-op exit 0) |
667
- | Output Directory | **empty / null** ??**NOT `public`** |
668
- | Start Command | `npm run start` ??`tsx server.ts` (or `.mts`) ??set in **dashboard**, not `vercel.json` |
686
+ | **Build Command** | **empty / skip** — **not** `npm run build` |
687
+ | Output Directory | **empty / null** — **NOT `public`** |
688
+ | Start Command | `npm run start` — `tsx server.ts` (or `.mts`) — set in **dashboard**, not `vercel.json` |
669
689
  | Fluid compute | **On** |
670
690
 
671
691
  If `next` / `next.config.*` exist for Preview and the dashboard still auto-selects Next.js:
@@ -967,9 +987,20 @@ Set `cmsEndpoint` only if they already know the public `https://?vercel.app` URL
967
987
 
968
988
  > **Optional.** Protect the Control Panel with app-level auth. You may **skip** and set Env Var `CMS_PASSWORD` later (then Redeploy).
969
989
 
970
- **Ask (Env input or one chat reply):**
990
+ > **IRON RULE — no prelude:** As soon as Q3 is submitted/skipped, open **this** step next. Do **not** first ask whether they want a password / auth / lock. Open the password Env/Secret field (or one chat prompt) immediately; blank/skip is a complete Q4 answer.
971
991
 
972
- > Optional: set a CMS password now? If yes, enter the password to store as Environment Variable **`CMS_PASSWORD`**. Leave blank / skip to keep the panel open for now — you can add this later in Vercel → Settings → Environment Variables and redeploy.
992
+ **UX (required):** Open **one** Env/Secret input labeled **`CMS_PASSWORD`** (password field). User may enter a password **or** leave blank / skip.
993
+
994
+ **Ask (Env input — preferred — or one chat reply):**
995
+
996
+ > Optional CMS password — Environment Variable **`CMS_PASSWORD`**.
997
+ >
998
+ > Enter a password to lock the Control Panel, or leave blank / skip to keep the panel open. You can add `CMS_PASSWORD` later in Vercel → Settings → Environment Variables and redeploy.
999
+
1000
+ **Forbidden before / instead of this input:**
1001
+ - "Do you want to protect the CMS?"
1002
+ - "Add a password?" / "Enable auth?"
1003
+ - Option A/B or yes/no for password first
973
1004
 
974
1005
  **Why:**
975
1006
  - Locks the **CMS Control Panel only** (not the whole deployment).
@@ -1010,9 +1041,9 @@ Then (**Scheme A — mandatory for Publish**):
1010
1041
 
1011
1042
  1. Keep **`server.ts`** at **project root** with top-level `listen()` + `export default server`.
1012
1043
  2. **Immediately** move leftover v0 Next from root into **`preview/`** or delete root Next files (`next.config.*`, `app/`, Next `tsconfig` / `postcss` / `next-env.d.ts`, starter `components/`). Production must not see root Next.
1013
- 3. Write `vercel.json` per **Scheme A3** (`fluid`, `framework: null`, no-op `buildCommand` — **no** `startCommand`).
1014
- 4. **Force Project Settings** per **Scheme A4** (Framework = Other, Output Directory **empty/unset**, Start = `npm run start`, Fluid on). Patch dashboard via API if it still says Next.js **or** Output = `public`.
1015
- 4a. **Pre-Publish Output check:** If settings show Output Directory = `public` (or build fails with `Output Directory "public" is empty`), **clear Output Directory** and redeploy. Do **not** add `public/robots.txt` to satisfy a static output path.
1044
+ 3. Write `vercel.json` per **Scheme A3** (`fluid`, `framework: null`, `"buildCommand": ""` — **no** `startCommand`, **no** no-op `npm run build`).
1045
+ 4. **Force Project Settings** per **Scheme A4** (Framework = Other, Output Directory **empty/unset**, Build Command **empty**, Start = `npm run start`, Fluid on). Patch dashboard via API if it still says Next.js, Output = `public`, **or** Build = `npm run build`.
1046
+ 4a. **Pre-Publish build/output check:** If build fails with `Output Directory "public" is empty` / not found: clear Output Directory **and** set Build Command / `buildCommand` to **`""`**. Do **not** add `public/robots.txt`. Do **not** keep a no-op build command.
1016
1047
  5. Do **not** add root `api/` catch-all for raw `http.Server`.
1017
1048
  6. Do **not** add `.replit*`.
1018
1049
  7. If Q2 = Vercel Blob: set `BLOB_READ_WRITE_TOKEN` + `TOMORROWOS_MEDIA=vercel-blob` (SDK-native; no custom bridge).
@@ -1059,15 +1090,16 @@ vercel --prod
1059
1090
 
1060
1091
  **Publish acceptance checklist (all must pass ??Scheme A5):**
1061
1092
 
1062
- 1. Framework Preset = **Other** / null (dashboard confirms ??not Next.js)
1093
+ 1. Framework Preset = **Other** / null (dashboard confirms — not Next.js)
1063
1094
  2. Output Directory = **empty** (not `public`)
1095
+ 2a. Build Command = **empty** (`"buildCommand": ""` — not `npm run build`)
1064
1096
  3. Start Command = Node `TomorrowOS.listen` (`npm run start` / `tsx server.ts`)
1065
1097
  4. Fluid compute on
1066
1098
  5. Env Vars present for Production
1067
- 6. Production `GET /status` returns **JSON** ??**not** HTML (`Unexpected token 'T'` means this failed)
1068
- 7. Production `GET /` returns Control Panel HTML ??**not** `404: NOT_FOUND`
1099
+ 6. Production `GET /status` returns **JSON** — **not** HTML (`Unexpected token 'T'` means this failed)
1100
+ 7. Production `GET /` returns Control Panel HTML — **not** `404: NOT_FOUND`
1069
1101
 
1070
- If step 6 fails but step 7 passes: **static `public/` trap** ??Vercel is not running Node. Re-apply Scheme A3?A4; try **Path B** (Git / `vercel --prod`); do **not** invent `api/` + `rewrites`.
1102
+ If step 6 fails but step 7 passes: **static `public/` trap** — Vercel is not running Node. Re-apply Scheme A3–A4; try **Path B** (Git / `vercel --prod`); do **not** invent `api/` + `rewrites`.
1071
1103
 
1072
1104
  Tell the user:
1073
1105
 
@@ -1119,8 +1151,9 @@ More detail: https://docs.tomorrowos.org/docs/os/tizen and https://docs.tomorrow
1119
1151
 
1120
1152
  | Symptom | Likely cause | Fix |
1121
1153
  |---------|--------------|-----|
1122
- | Build: `Output Directory "public" is empty` | Dashboard Output Directory still = `public` on a Function/CMS app | **Unset Output Directory**; Framework Other; Fluid `api/index.ts`; redeploy. Do **not** primary-fix with `public/robots.txt` |
1154
+ | Build: `Output Directory "public" is empty` / public not found | (1) Output Directory = `public`, **or** (2) Output null but **Build Command defined** → static-build mode | Clear Output; set `"buildCommand": ""` + dashboard Build empty; Fluid `api/index.ts`. Do **not** primary-fix with `public/robots.txt` or keep no-op `npm run build` |
1123
1155
  | Agent asked Q2 as chat “type 1 or 2” while choice UI available | Off-protocol Q2 UX | Re-ask Q2 with **clickable** Cloudinary / Vercel Blob options (same pattern as Q1) |
1156
+ | Agent asked yes/no “want a CMS password?” before Q4 | Off-protocol Q4 UX | After Q3, open **CMS_PASSWORD** Env input immediately (blank/skip OK) |
1124
1157
  | Preview 500 / Turbopack / `ENOENT .../app` after Q1–Q3 | Leftover **root** Next from v0 starter; not Neon/Blob | **IRON GATE:** delete/move root `app/` + `next.config.*`; keep `preview/`; restart supervised `dev`; prove `/status` JSON |
1125
1158
  | `Internal Server Error` + logs blame missing `DATABASE_URL` in a **manual** Bash server | `dotenv` loaded `.env` only; secret is in `.env.development.local` / supervised env | Restart **supervised** Preview process; or load both env files — do **not** immediately change Neon URL |
1126
1159
  | `EADDRINUSE :3000` while debugging | Second `pnpm dev` / stale `next-server` after script rewrite | Kill stale Next/tsx; one process; let supervisor re-exec new `"dev"` |
@@ -1134,7 +1167,7 @@ More detail: https://docs.tomorrowos.org/docs/os/tizen and https://docs.tomorrow
1134
1167
  | `vercel.json` error: invalid `startCommand` | v0 schema rejects it | Remove from `vercel.json`; Function entry does not need startCommand |
1135
1168
  | Separate `api/ws.ts` with a second `new TomorrowOS` | Two isolates ??pairing memory split | **One** Function only (`api/index.ts` ??shared `cms-app.ts`) |
1136
1169
  | `vercel inspect` shows Output = `public if it exists` | Framework=Other static default | Force Output Directory **empty**; use `cms-panel/`; Path B redeploy |
1137
- | Build runs `next build` / missing routes-manifest | Next auto-detected from root `next.config` / `app/` | Move Next to `preview/`; Framework null/Other; `build` = no-op |
1170
+ | Build runs `next build` / missing routes-manifest | Next auto-detected from root `next.config` / `app/` | Move Next to `preview/`; Framework null/Other; `"buildCommand": ""` |
1138
1171
  | Preview blank but logs show TomorrowOS listening | v0 Next intercepts public port | Add Next reverse proxy ??internal TomorrowOS port |
1139
1172
  | Preview works, Publish broken / Next-only | Production still on Next | Switch Production to Fluid Function `api/index.ts` |
1140
1173
  | `ENETUNREACH` / IPv6 / `:5432` | Direct Postgres URL | Use **pooled** URL (Supabase `:6543` or Neon pooler) |
@@ -1202,7 +1235,9 @@ Protocol complete when:
1202
1235
 
1203
1236
  ## Protocol version
1204
1237
 
1205
- `vercel-setup/1.18` - pairs with `@tomorrowos/sdk` 0.9.70+ and `VERCEL_QUESTIONS.md` 1.7.
1238
+ `vercel-setup/1.19` - pairs with `@tomorrowos/sdk` 0.9.70+ and `VERCEL_QUESTIONS.md` 1.8.
1239
+
1240
+ **Changelog 1.19:** Publish Build Command must be **empty** (`"buildCommand": ""`) — a defined no-op `npm run build` forces Vercel static-build mode and the `public/` output check (empty → “not found” after deleting `public/`). Q4 opens **immediately after Q3** as the `CMS_PASSWORD` Env input with **no** yes/no password prelude.
1206
1241
 
1207
1242
  **Changelog 1.18:** Q1/Q2 must use **clickable choice UI** (not chat “type 1 or 2” when UI exists). Publish build error `Output Directory "public" is empty` → **clear Output Directory** (forbidden primary fix: stuff `public/robots.txt` while Output stays `public`). Strengthens static-output trap docs.
1208
1243
 
package/VERCEL_UPGRADE.md CHANGED
@@ -40,6 +40,7 @@ When any of these triggers fire:
40
40
  4. **Do NOT** blindly overwrite `cms-panel/methods.js`, `cms-panel/index.html`, `cms-panel/panel.css`, `server.ts`, `cms-app.ts`, or `api/index.ts` with template copies. Always **diff → report → merge only with user consent** (or apply surgical patches that preserve custom code).
41
41
  5. **Do NOT** create a second `new TomorrowOS(...)` in `api/ws.ts` or elsewhere. **One** shared instance only.
42
42
  6. **Do NOT** set Vercel Output Directory to `public/` or switch Production to Next/`next start` / static-only.
43
+ 6a. **Do NOT** keep a Production Build Command of `npm run build` (even no-op) — use `"buildCommand": ""` so Vercel does not enter static-build / `public/` output checks.
43
44
  7. Prefer **`npm install @tomorrowos/sdk@latest`** over pinning an older version unless the user named a specific version.
44
45
  8. Keep `tsx` available at runtime (`dependencies`, not only `devDependencies`) if local `npm run start` / Preview still relies on `tsx server.ts`.
45
46
  9. After upgrade, re-check Production gates: `GET /status` → JSON, `GET /` → Control Panel, WebSocket `/` or `/api` → **101**.
@@ -54,7 +55,7 @@ Capture and remember:
54
55
  |------|-----|
55
56
  | **Old SDK version** | `package.json` → `dependencies["@tomorrowos/sdk"]`, and/or `npm ls @tomorrowos/sdk --depth=0` |
56
57
  | **Layout** | Confirm `cms-starter-v0` shape: `cms-app.ts` / `api/index.ts` / `cms-panel/` (or equivalent shared TomorrowOS export) |
57
- | **Runtime** | Confirm Fluid Function + `vercel.json` rewrites; Output Directory empty |
58
+ | **Runtime** | Confirm Fluid Function + `vercel.json` rewrites; Output Directory empty; **Build Command empty** (`"buildCommand": ""`) |
58
59
 
59
60
  If `@tomorrowos/sdk` is not a dependency, stop and tell the user this project does not look like a TomorrowOS CMS — offer `VERCEL_SETUP.md` instead. Do **not** run `init` unless they explicitly switch to setup.
60
61
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomorrowos/sdk",
3
- "version": "1.1.3",
3
+ "version": "1.1.4",
4
4
  "description": "Server SDK for building and self-hosting digital signage CMS products with TomorrowOS players.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "my-cms",
3
- "version": "1.1.3",
3
+ "version": "1.1.4",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "my-cms",
9
- "version": "1.1.3",
9
+ "version": "1.1.4",
10
10
  "dependencies": {
11
- "@tomorrowos/sdk": "^1.1.3",
11
+ "@tomorrowos/sdk": "^1.1.4",
12
12
  "dotenv": "^17.2.3",
13
13
  "tsx": "^4.19.0"
14
14
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "my-cms",
3
- "version": "1.1.3",
3
+ "version": "1.1.4",
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",
@@ -12,7 +12,7 @@
12
12
  "start": "tsx server.ts"
13
13
  },
14
14
  "dependencies": {
15
- "@tomorrowos/sdk": "^1.1.3",
15
+ "@tomorrowos/sdk": "^1.1.4",
16
16
  "dotenv": "^17.2.3",
17
17
  "tsx": "^4.19.0"
18
18
  },
@@ -10,7 +10,10 @@ This starter is for **Vercel Publish** and **v0**. It follows
10
10
  - **`preview/`** — Next.js shell for v0 Preview only
11
11
  - **`vercel.json`** — `fluid`, rewrites → `/api`, `maxDuration`
12
12
 
13
- **Publish setting (critical):** Vercel **Output Directory** must stay **empty / unset**. If the build fails with `The Output Directory "public" is empty`, clear Output Directory in Project Settings — do **not** add filler files under `public/` while Output is still set to `public`.
13
+ **Publish settings (critical):**
14
+ - **Output Directory** = empty / unset (never `public/`)
15
+ - **Build Command** = empty / skip (`"buildCommand": ""` in `vercel.json`) — a defined no-op `npm run build` forces Vercel static-build mode and requires `public/`
16
+ - If the build fails with `The Output Directory "public" is empty` (or public not found): clear Output Directory **and** set Build Command to empty — do **not** add filler files under `public/`
14
17
 
15
18
  ## Scaffold
16
19
 
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "my-cms",
3
- "version": "1.1.3",
3
+ "version": "1.1.4",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "my-cms",
9
- "version": "1.1.3",
9
+ "version": "1.1.4",
10
10
  "dependencies": {
11
- "@tomorrowos/sdk": "^1.1.3",
11
+ "@tomorrowos/sdk": "^1.1.4",
12
12
  "dotenv": "^17.2.3",
13
13
  "tsx": "^4.19.0"
14
14
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "my-cms",
3
- "version": "1.1.3",
3
+ "version": "1.1.4",
4
4
  "description": "TomorrowOS CMS for Vercel / v0 Publish (Fluid Function + WebSockets + optional Next Preview).",
5
5
  "private": true,
6
6
  "type": "module",
@@ -16,7 +16,7 @@
16
16
  "build": "node -e \"process.exit(0)\""
17
17
  },
18
18
  "dependencies": {
19
- "@tomorrowos/sdk": "^1.1.3",
19
+ "@tomorrowos/sdk": "^1.1.4",
20
20
  "dotenv": "^17.2.3",
21
21
  "tsx": "^4.19.0"
22
22
  },
@@ -3,7 +3,7 @@
3
3
  "fluid": true,
4
4
  "framework": null,
5
5
  "installCommand": "npm install",
6
- "buildCommand": "npm run build",
6
+ "buildCommand": "",
7
7
  "functions": {
8
8
  "api/index.ts": {
9
9
  "maxDuration": 300,