generatesaas 3.6.0 → 3.8.0

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,56 +1,44 @@
1
1
  ---
2
2
  name: update
3
- description: Update a GenerateSaaS project to the latest boilerplate version. Use this whenever the user asks to "update my GenerateSaaS project", "update auto", update their GenerateSaaS boilerplate/template, or pull the latest GenerateSaaS changes. Fetches and stages the new version, surfaces newly available options, classifies files, analyzes dependencies, and applies changes while preserving user customizations - the user controls every decision. Saying "auto" runs the whole update unattended, stopping only for risky or uncertain decisions.
3
+ description: Update a GenerateSaaS project to the latest boilerplate version. Use this whenever the user asks to "update my GenerateSaaS project", update their GenerateSaaS boilerplate/template, or pull the latest GenerateSaaS changes. Fetches and stages the new version, surfaces newly available options, classifies files, and merges every upstream change into the user's customizations - stopping only when a change is risky, uncertain, or alters what the app does or how it looks.
4
4
  ---
5
5
 
6
6
  # GenerateSaaS Update
7
7
 
8
8
  Update your project to the latest GenerateSaaS boilerplate version while preserving all your customizations.
9
9
 
10
+ ## Intent
11
+
12
+ The owner wants **every change from the new version**. A customization the user made is **kept and merged with the upstream change in the same file**. The only reason to hold an upstream change back is a conflict with a customization you cannot resolve with confidence, or one of the [mandatory stops](#mandatory-stops).
13
+
14
+ Run the whole update **unattended** by default - fetch, stage, classify, merge, validate, and complete - without asking the user to pick a mode or confirm each step. Stop only at a mandatory stop, and only there.
15
+
10
16
  ## Core Principles
11
17
 
12
- 1. **User decides everything** - Present clear information and options. Never make decisions that affect user code without explicit approval. Every meaningful change requires the user's input.
13
- 2. **Never break user code** - If an upstream change conflicts with user modifications, present the situation and let the user choose. When in doubt, keep the user's version and explain what was skipped.
14
- 3. **Full transparency** - For every change, explain: what changed upstream, why it changed, and how it affects the user's code. The user should always know exactly what is happening.
15
- 4. **Track everything** - Every change is tracked in a checklist. Mark items as completed, skipped, or failed with clear reasons.
18
+ 1. **Take every upstream change** - bring the new version in fully and merge it with the user's customizations in the same file. Never silently drop an upstream change.
19
+ 2. **Never break user code** - when an upstream change conflicts with a customization you cannot merge with confidence, stop and ask. Keep the user's version if they choose, and record what was skipped.
20
+ 3. **Full transparency** - the final report says what was auto-applied, what was merged, what was held and why, and what the user must still do (migrations, env).
21
+ 4. **Track everything** - every change is tracked in the plan file: completed, merged, skipped, or failed, with a reason.
16
22
 
17
23
  ## Workflow Overview
18
24
 
19
25
  ```
20
26
  Step 0: Pre-flight safety checks
21
27
  Step 1: Fetch + stage + prepare update data (you run the CLI, then the script)
22
- Step 2: Present changelog to user
28
+ Step 2: Summarize the changelog
23
29
  Step 2.5: Review newly available options - adopt or keep default (re-stage if adopted)
24
30
  Step 3: Classify files (script)
25
31
  Step 4: Analyze dependencies
26
- Step 5: Present update plan - user chooses interaction mode
32
+ Step 5: Write the plan, then apply
27
33
  Step 6: Apply safe auto-updates (script)
28
- Step 7: Review modified files with user - one by one
34
+ Step 7: Merge modified files - stopping only at a mandatory stop
29
35
  Step 8: Post-update validation
30
36
  Step 9: Complete update (script)
31
37
  ```
32
38
 
33
- **You own the whole flow.** When the user says "update my GenerateSaaS project," do
34
- everything end-to-end - including fetching and staging the new version (Step 1).
35
- The user does not run any CLI command themselves.
36
-
37
- **Automatic mode.** If the user's request includes the word "auto" (e.g. "update auto",
38
- "update my GenerateSaaS project, auto"), or `staging.json` has `"mode": "auto"` (set by
39
- `generatesaas update auto`), run the entire update **unattended** in Automatic mode: skip
40
- the Step 5 mode prompt and proceed start to finish, making the best decisions to bring in
41
- upstream changes while preserving the user's customizations. Automatic mode still **stops to
42
- ask** whenever a decision is genuinely risky or you are not confident - and it always runs
43
- the Step 2.5 new-options review (surfacing a new feature is never a decision to assume). The
44
- exact always-ask triggers are listed in Step 5 and "When to Always Ask".
45
-
46
- **What the staged update contains (important):** `generatesaas update` re-shapes the
47
- new version's template into THIS project's exact configuration before staging - same
48
- frontend, payment provider, database, feature flags, etc. So everything in
49
- `.generatesaas/staging/` and the `.generatesaas/template/` baseline is buyer-shaped:
50
- you will never see another framework's files, a provider the project doesn't use, the
51
- boilerplate's internal tooling, or dev-only secrets. Every diff you surface already
52
- applies to this project. The 3-way merge baseline (`.generatesaas/template/`) is a
53
- faithful pristine copy of what this project started from - trust it.
39
+ **You own the whole flow.** When the user says "update my GenerateSaaS project," do everything end-to-end - including fetching and staging the new version (Step 1). The user does not run any CLI command themselves.
40
+
41
+ **What the staged update contains (important):** `generatesaas update` re-shapes the new version's template into THIS project's exact configuration before staging - same frontend, payment provider, database, feature flags, etc. So everything in `.generatesaas/staging/` and the `.generatesaas/template/` baseline is buyer-shaped: you will never see another framework's files, a provider the project doesn't use, the boilerplate's internal tooling, or dev-only secrets. Every diff you surface already applies to this project. The 3-way merge baseline (`.generatesaas/template/`) is a faithful pristine copy of what this project started from - trust it.
54
42
 
55
43
  ---
56
44
 
@@ -84,29 +72,25 @@ If starting fresh, delete the old plan file. Note: files that were auto-applied
84
72
 
85
73
  ### Step 1: Fetch, Stage, and Prepare Update Data
86
74
 
87
- **1a. Stage the new version yourself.** Unless a staged update already exists
88
- (`.generatesaas/staging.json` present), run the CLI to fetch the latest version and
89
- stage it - re-shaped for this project's exact configuration:
75
+ **1a. Stage the new version yourself.** Unless a staged update already exists (`.generatesaas/staging.json` present), run the CLI to fetch the latest version and stage it - re-shaped for this project's exact configuration:
90
76
 
91
77
  ```bash
92
78
  npx generatesaas@latest update
93
79
  ```
94
80
 
95
- This resolves the saved API key from `~/.generatesaas` (written at init), so it runs
96
- non-interactively - it never prompts you for a key. It refreshes the skill files,
97
- downloads the new version, shapes it into this project's configuration, and writes
98
- `.generatesaas/staging/` + `staging.json`. If it reports "Already on the latest
99
- version," there is nothing to update - tell the user and stop. If it fails because the
100
- API key is missing or rejected, ask the user to run `generatesaas auth` (which sets the
101
- key once and saves it), then re-run the update. For a network error, ask them to retry.
81
+ This resolves the saved API key from `~/.generatesaas` (written at init), so it runs non-interactively - it never prompts you for a key. It refreshes the skill files, downloads the new version, shapes it into this project's configuration, and writes `.generatesaas/staging/` + `staging.json`. If it reports "Already on the latest version," there is nothing to update - tell the user and stop. If it fails because the API key is missing or rejected, ask the user to run `generatesaas auth` (which sets the key once and saves it), then re-run the update. For a network error, ask them to retry.
82
+
83
+ **If `update` exits asking a question.** A few decisions are the buyer's alone (a retired desktop-AI shape, a retired option whose new default spends money or profiles end users). Because you run the CLI without a terminal, it cannot prompt you: it prints the question with a **stable id** and its **allowed choices**, then exits non-zero. Do not guess. Relay the question and its choices to the user, collect their answer, and re-run with the choice appended:
84
+
85
+ ```bash
86
+ npx generatesaas@latest update --answer <id>=<choice>
87
+ ```
88
+
89
+ `--answer` is repeatable - pass one per question if the CLI asks more than one. An unknown id or choice is rejected with the valid values, so read the error and correct the flag.
102
90
 
103
- > Note: this command also rewrites the skill scripts to their latest version. That is
104
- > expected - the scripts you run in the following steps are the freshly-installed ones.
91
+ > Note: this command also rewrites the skill scripts to their latest version. That is expected - the scripts you run in the following steps are the freshly-installed ones.
105
92
 
106
- **Re-read this SKILL.md now**, from `__SKILL_ROOT__/generatesaas-update/SKILL.md`. The command
107
- just overwrote it along with the scripts, so the copy in your context is the PREVIOUS release's
108
- instructions while every script you are about to run is the new one. Follow the file on disk
109
- wherever the two disagree.
93
+ **Re-read this SKILL.md now**, from `__SKILL_ROOT__/generatesaas-update/SKILL.md`. The command just overwrote it along with the scripts, so the copy in your context is the PREVIOUS release's instructions while every script you are about to run is the new one. Follow the file on disk wherever the two disagree.
110
94
 
111
95
  **1b. Prepare the diff/classification data:**
112
96
 
@@ -116,16 +100,10 @@ node __SKILL_ROOT__/generatesaas-update/scripts/prepare-update.js
116
100
 
117
101
  Creates:
118
102
  - `references/changelog.md` - what changed and why
119
- - `references/diffs/<path>.diff` - one unified diff per changed file, named by the
120
- file's project-relative path with `.diff` appended (e.g.
121
- `references/diffs/packages/config/src/index.ts.diff`). Diffs cover `modified` +
122
- `added` files; `unmodified`, `deleted`, and `removed` files have none.
123
- - `references/update-manifest.json` - lists of added, modified, and removed files,
124
- plus `renamed` (upstream renames detected by identical content: `[{from, to}]`)
125
- and `sensitive` (database schema, `packages/database/drizzle/`, and
126
- `.env.example` changes that carry follow-up work: migrations, new env vars)
103
+ - `references/diffs/<path>.diff` - one unified diff per changed file, named by the file's project-relative path with `.diff` appended (e.g. `references/diffs/packages/config/src/index.ts.diff`). Diffs cover `modified` + `added` files; `unmodified`, `deleted`, and `removed` files have none.
104
+ - `references/update-manifest.json` - lists of added, modified, and removed files, plus `renamed` (upstream renames detected by identical content: `[{from, to}]`) and `sensitive` (database schema, `packages/database/drizzle/`, and `.env.example` changes that carry follow-up work: migrations, new env vars)
127
105
 
128
- ### Step 2: Present Changelog
106
+ ### Step 2: Summarize the Changelog
129
107
 
130
108
  Read `references/changelog.md`. When the update spans multiple releases, it contains one `# vX.Y.Z` section per release, oldest first - read ALL of them, not just the last; a breaking change can sit in any intermediate release. A `[BREAKING]` marker on a section header is authoritative (it comes from the version index: a major bump or release notes flagged BREAKING) - always call those releases out explicitly.
131
109
 
@@ -136,7 +114,7 @@ Each release's notes may be one of two shapes:
136
114
 
137
115
  Also read `sensitive` in `references/update-manifest.json`: database schema changes mean a migration is likely required, anything under `packages/database/drizzle/` means upstream migrations that must be regenerated into the project's own history before they will run (see [Database](#database-schema-migrations)), and `.env.example` changes mean new or changed environment variables. Mention all three in the summary and again in the final post-update steps.
138
116
 
139
- Present a clear, organized summary:
117
+ Present a clear, organized summary (this is a summary, not a gate - continue straight to the next step):
140
118
 
141
119
  > ## What's New in v{targetVersion}
142
120
  >
@@ -147,19 +125,11 @@ Present a clear, organized summary:
147
125
 
148
126
  **Be honest about uncertainty.** Never present an inferred "Breaking changes: None" or "Migration steps: None" as if it were authoritative when the changelog is raw PR titles - say it's not specified and that you'll watch for schema/config/env changes during the file review. A silently-missed migration (e.g. a new DB column) is the worst failure mode.
149
127
 
150
- Then ask: *"Ready to proceed with the file analysis?"*
151
-
152
- Wait for the user to confirm before continuing.
153
-
154
128
  ### Step 2.5: Review Newly Available Options
155
129
 
156
- The boilerplate adds features over time. When this project predates one, `generatesaas update`
157
- records it in `staging.json` under `newOptions` (and has already default-filled the manifest so
158
- it stays complete). Read `newOptions` from `.generatesaas/staging.json`. **If it is absent or
159
- empty, skip this step entirely.**
130
+ The boilerplate adds features over time. When this project predates one, `generatesaas update` records it in `staging.json` under `newOptions` (and has already default-filled the manifest so it stays complete). Read `newOptions` from `.generatesaas/staging.json`. **If it is absent or empty, skip this step entirely.**
160
131
 
161
- Otherwise, present each option so the user can decide whether to adopt it. Each entry has
162
- `{ key, label, hint, default, impact, choices?, requiresLabel? }`. For each one:
132
+ Otherwise, present each option so the user can decide whether to adopt it. Adopting a new feature is a [mandatory stop](#mandatory-stops) - surfacing it is never a decision to assume. Each entry has `{ key, label, hint, default, impact, choices?, requiresLabel? }`. For each one:
163
133
 
164
134
  ```
165
135
  ### New since your version: {label}
@@ -177,9 +147,7 @@ it is a large surface you didn't originally choose" or "Safe to adopt - it is pu
177
147
  > 2. **Adopt it** - turn this feature on
178
148
  ```
179
149
 
180
- **An entry with `choices` is not a yes/no.** It takes one of several values, so the two-way block
181
- above cannot express it - offer the values as a numbered pick list instead, one line per choice,
182
- with the entry's `default` marked as the current behavior:
150
+ **An entry with `choices` is not a yes/no.** It takes one of several values, so the two-way block above cannot express it - offer the values as a numbered pick list instead, one line per choice, with the entry's `default` marked as the current behavior:
183
151
 
184
152
  ```
185
153
  **Default:** `{default}` (your project's current behavior is unchanged).
@@ -191,34 +159,19 @@ with the entry's `default` marked as the current behavior:
191
159
  > 3. **`{choices[2]}`** ...one line per choice, however many there are
192
160
  ```
193
161
 
194
- **Ask the user about every new option, in every mode - including Automatic.** Surfacing a new
195
- feature is exactly the kind of decision the update must never assume. Give your recommendation,
196
- but the user decides.
162
+ Give your recommendation, but the user decides.
197
163
 
198
164
  **Applying the decisions:**
199
165
 
200
- 1. For each option the user **adopts**, write the value they picked into
201
- `.generatesaas/manifest.json` under the entry's `key`. For an option with no `choices` that value
202
- is `true` (e.g. set `"desktop": true`); for one with `choices` it is the choice they named,
203
- verbatim (e.g. set `"errorTracking": "sentry"`). Never write `true` for an option that has
204
- `choices` - the CLI refuses any value outside them and stages nothing at all. The manifest is the
205
- single shaping input.
206
- 2. **If the user adopted at least one option, re-stage once** so re-shaping produces the
207
- feature's files. Re-run the CLI (append `auto` if you are in Automatic mode, so the staged
208
- metadata keeps the unattended signal):
166
+ 1. For each option the user **adopts**, write the value they picked into `.generatesaas/manifest.json` under the entry's `key`. For an option with no `choices` that value is `true` (e.g. set `"desktop": true`); for one with `choices` it is the choice they named, verbatim (e.g. set `"errorTracking": "sentry"`). Never write `true` for an option that has `choices` - the CLI refuses any value outside them and stages nothing at all. The manifest is the single shaping input.
167
+ 2. **If the user adopted at least one option, re-stage once** so re-shaping produces the feature's files:
209
168
 
210
169
  ```bash
211
170
  npx generatesaas@latest update
212
171
  ```
213
172
 
214
- Because the manifest now carries the adopted flags, the new `.generatesaas/staging/` includes
215
- the feature - config flags and whole new trees alike - with no hand-editing. This is why
216
- adoption is handled the same way for `config` and `structural` options: both are applied by
217
- re-shaping, never by mimicking the generator. The adopted keys are now present in the
218
- manifest, so they will not re-appear in `newOptions`.
219
- 3. Re-read `staging.json`, then continue to Step 3. Classification runs on the final staging, so
220
- the adopted feature's files are classified as `new` and created in Step 6. Nothing is applied
221
- before this point, so a re-stage never leaves a half-applied tree.
173
+ Because the manifest now carries the adopted flags, the new `.generatesaas/staging/` includes the feature - config flags and whole new trees alike - with no hand-editing. This is why adoption is handled the same way for `config` and `structural` options: both are applied by re-shaping, never by mimicking the generator. The adopted keys are now present in the manifest, so they will not re-appear in `newOptions`.
174
+ 3. Re-read `staging.json`, then continue to Step 3. Classification runs on the final staging, so the adopted feature's files are classified as `new` and created in Step 6. Nothing is applied before this point, so a re-stage never leaves a half-applied tree.
222
175
  4. If the user adopted nothing, continue to Step 3 directly.
223
176
 
224
177
  ### Step 3: Classify Files
@@ -230,11 +183,11 @@ node __SKILL_ROOT__/generatesaas-update/scripts/classify-files.js
230
183
  Read `references/classification.json`. It contains:
231
184
 
232
185
  - **unmodified** - file matches the original template, safe to replace
233
- - **modified** - user has customized this file, needs careful review
186
+ - **modified** - user has customized this file, needs a merge
234
187
  - **deleted** - user deleted this file, skip update for it
235
188
  - **new** - file doesn't exist locally and its directory tree is genuinely new upstream, safe to create
236
- - **newInDeletedTree** - file is new upstream BUT lives inside a directory tree the user intentionally deleted (the tree existed in the baseline and is now gone on disk). **Never auto-create these.** Ask the user whether to bring the tree back (see "For New Files In Deleted Trees" in Step 7).
237
- - **removed** - file was removed upstream, user decides whether to delete
189
+ - **newInDeletedTree** - file is new upstream BUT lives inside a directory tree the user intentionally deleted (the tree existed in the baseline and is now gone on disk). **Never auto-create these** (a [mandatory stop](#mandatory-stops)). Ask the user whether to bring the tree back (see "For New Files In Deleted Trees" in Step 7).
190
+ - **removed** - file was removed upstream, you decide whether to delete (see Step 7)
238
191
  - **crossDependencies** - import relationships between categories (if detected)
239
192
 
240
193
  ### Step 4: Analyze Dependencies
@@ -247,7 +200,7 @@ This step prevents breaking the user's code through indirect effects.
247
200
  - `newImportsModified` - new files that import from modified files
248
201
 
249
202
  2. **For each cross-dependency**, read the relevant diff at `references/diffs/<path>.diff`. Handle all three directions the classifier emits:
250
- - **`modifiedImportsUnmodified`** - a modified file imports from an auto-apply (unmodified) file. If the auto-apply file's diff changes **exports, function signatures, types, or interfaces** that the modified file uses → promote it from `unmodified` to `modified` (it needs user review alongside its dependent, so the merge accounts for the new API).
203
+ - **`modifiedImportsUnmodified`** - a modified file imports from an auto-apply (unmodified) file. If the auto-apply file's diff changes **exports, function signatures, types, or interfaces** that the modified file uses → promote it from `unmodified` to `modified` (it needs a merge alongside its dependent, so the merge accounts for the new API).
251
204
  - **`unmodifiedImportsModified`** - an auto-apply file imports from a modified file. After the modified file is handled in Step 7, re-check this auto-apply file: if the user kept their version of the modified file but the auto-apply file's new version expects the upstream API, the auto-apply file may not be compatible. Flag it and revisit in the Step 7 cascade-awareness check.
252
205
  - **`newImportsModified`** - a new file imports from a modified file. The new file will be auto-created in Step 6. After the modified file is handled, verify the new file's imports resolve against whatever version of the modified file the user ended up with (their merge, their kept version, or upstream). If the new file expects the upstream API but the user kept their version, surface it.
253
206
 
@@ -255,11 +208,9 @@ This step prevents breaking the user's code through indirect effects.
255
208
 
256
209
  4. If there are no cross-dependencies or all cross-dependencies are safe (no API changes), no reclassification is needed.
257
210
 
258
- ### Step 5: Present Update Plan and Choose Mode
259
-
260
- Generate the plan file at `.generatesaas/updates/update-{currentVersion}-to-{targetVersion}.md`.
211
+ ### Step 5: Write the Plan, Then Apply
261
212
 
262
- Present the plan organized by category:
213
+ Generate the plan file at `.generatesaas/updates/update-{currentVersion}-to-{targetVersion}.md`:
263
214
 
264
215
  ```markdown
265
216
  # Update: {currentVersion} → {targetVersion}
@@ -277,8 +228,8 @@ These files haven't been customized and will be updated automatically:
277
228
  New in this version:
278
229
  - [ ] `path/to/new-file.ts` - {what this file does}
279
230
 
280
- ## Files Needing Review ({count} files)
281
- These files have your customizations. Each one will be presented for your decision:
231
+ ## Files Needing a Merge ({count} files)
232
+ These files have your customizations. Each is merged with the upstream change:
282
233
  - [ ] `path/to/modified.ts` - Risk: {Low/Medium/High} - {what changed}
283
234
 
284
235
  ## Removed Upstream ({count} files)
@@ -289,119 +240,68 @@ Removed in the new version - you decide whether to delete:
289
240
  {Empty - items move here during execution with reasons}
290
241
  ```
291
242
 
292
- **If Automatic mode was triggered** (the request contained "auto", or `staging.json.mode === "auto"`),
293
- **skip this prompt** - do not ask the user to choose a mode. Use Automatic mode (described below)
294
- and proceed. Note in the plan that Automatic mode was selected.
243
+ Then show the user a **short plan** and continue - no mode question, no proceed gate:
295
244
 
296
- Otherwise, ask the user to choose their interaction level:
297
-
298
- > **How would you like to handle this update?**
245
+ > **Update plan: v{currentVersion} v{targetVersion}**
246
+ >
247
+ > - {N} safe files auto-applied, {N} new files created
248
+ > - {N} customized files merged with the upstream change
249
+ > - {N} removed upstream, {N} needing your decision
299
250
  >
300
- > 1. **Recommended** - Auto-apply safe files, then I'll walk you through each modified file with my recommendation. You approve or adjust each one.
301
- > 2. **Careful** - I'll present every single change for your approval, including auto-updates. Nothing happens without your explicit OK.
302
- > 3. **Quick** - Auto-apply safe files, auto-apply my recommended merges for low-risk files, and only ask you about medium/high-risk changes.
303
- > 4. **Automatic** - Run the whole update unattended: auto-apply safe files and auto-merge low- and medium-risk files I'm confident about, only stopping to ask when a decision is genuinely risky or I'm unsure. (This is what `update auto` selects.)
304
-
305
- **Wait for the user's choice.** Default to **Recommended** if they just say "proceed" or similar.
306
-
307
- #### Automatic mode behavior
308
-
309
- In Automatic mode, run the entire flow without prompting **except** at the mandatory stops below:
310
-
311
- - **Auto-apply** safe (`unmodified`) and genuinely-`new` files, same as Recommended.
312
- - **Auto-merge Low AND Medium risk** modified files when you are confident the merge preserves
313
- the user's customizations (this is the difference from Quick, which stops at Low). Report each
314
- merge you apply.
315
- - **Always stop and ask** - even in Automatic mode - for:
316
- - High-risk or structurally conflicting files, and files the user heavily rewrote (>30% diverged).
317
- - Database schema changes (never auto-merge schema).
318
- - `.env.example` changes that imply a decision (new required variables).
319
- - Removed-upstream files that other project code imports (run the import search first).
320
- - Renames where the user customized the old path (porting customizations is a judgment call).
321
- - **Any merge you are not confident preserves the user's intent.** When unsure, ask. It is
322
- always better to interrupt than to assume.
323
- - **Removed files:** auto-delete only when the user never modified the file AND no importers are
324
- found; otherwise ask.
325
- - **New files in deleted trees (`newInDeletedTree`):** keep them deleted (never resurrect a tree
326
- the user removed); note it in the summary, no prompt needed.
327
- - **Validation (Step 8):** run the FULL ladder - lint, type check, tests, dependency
328
- parity, the auth probe when auth changed, and the e2e gate; if the update introduced
329
- breakage you can fix with confidence, fix it and re-verify; if not, stop and ask.
330
- Unattended never means ungated: the e2e rung is still required.
331
-
332
- The Step 2.5 new-options review still runs and still asks per option - Automatic mode never
333
- auto-adopts a new feature.
251
+ > **I'll stop to ask you about:** {list the mandatory stops you expect for THIS update - e.g. a schema change, a new required env var, {N} new options, a removed file still imported, a merge that changes a route or a screen. Say "none expected" if you anticipate none.}
334
252
 
335
- ### Step 6: Apply Safe Auto-Updates
253
+ Then proceed to Step 6.
336
254
 
337
- Based on the user's chosen mode:
255
+ ### Step 6: Apply Safe Auto-Updates
338
256
 
339
- **Recommended / Quick / Automatic mode:**
257
+ Preview first (optional), then apply:
340
258
 
341
- Preview first (especially useful in Careful mode or when unsure), then apply:
342
259
  ```bash
343
260
  node __SKILL_ROOT__/generatesaas-update/scripts/apply-auto.js --dry-run # lists every file it would update/create, changes nothing
344
261
  node __SKILL_ROOT__/generatesaas-update/scripts/apply-auto.js
345
262
  ```
263
+
346
264
  `apply-auto.js` copies only `unmodified` (safe replace) + `new` (any upstream-added file whose tree the buyer has not deleted). It will **never** touch `newInDeletedTree` files, and it aborts without writing anything if any source is missing from staging (no half-applied tree). Report what was applied. Mark all auto-update and new file items as `[x]` in the plan - **except any file the script reports as held back**, which was never applied and moves to **Skipped** with the regenerate reason. Marking a held-back migration `[x]` records a table that does not exist as delivered, in the one artifact that outlives the session.
347
265
 
348
266
  It also holds back everything under `packages/database/drizzle/` and lists what it skipped. Those are NOT pending work you can copy in afterwards - migrations must be regenerated into the project's own history or they never run. See [Database](#database-schema-migrations).
349
267
 
350
- **Careful mode:**
351
- Present the list of safe auto-updates and new files to the user:
352
- > These {N} files haven't been customized and can be safely replaced with the new version. {N} new files will be created. Want me to apply all of these, or would you like to review any specific ones first?
353
-
354
- If the user wants to review specific files, show them the diff for each requested file. Apply only after approval. Do not count held-back migrations in either number - they are not being created, and presenting them as applied is the same error as marking them `[x]`.
268
+ ### Step 7: Merge Modified Files
355
269
 
356
- ### Step 7: Review Modified Files
357
-
358
- This is the most important step. Work through each file in the `modified` category.
270
+ This is the most important step. Work through each file in the `modified` category. Merge the upstream change into the user's file, preserving their customizations - and stop to ask only when a [mandatory stop](#mandatory-stops) applies.
359
271
 
360
272
  #### For Each Modified File
361
273
 
362
- For each file, you have three versions available for proper three-way merge context:
274
+ For each file, you have three versions available for a proper three-way merge:
363
275
 
364
276
  1. **Old template:** `.generatesaas/template/<path>` - the original boilerplate version
365
277
  2. **New template:** `.generatesaas/staging/<path>` - the updated boilerplate version
366
278
  3. **User's version:** the current file on disk - their customized version
367
279
 
368
- The diff at `references/diffs/<path>.diff` shows **pure upstream changes** (old template → new template), making it easy to see exactly what we changed and why.
369
-
370
- If `.generatesaas/template/<path>` does not exist (backward compat), fall back to comparing the user's file against staging directly. If no diff file exists, read both files to understand the differences.
280
+ The diff at `references/diffs/<path>.diff` shows **pure upstream changes** (old template → new template), making it easy to see exactly what changed and why. If `.generatesaas/template/<path>` does not exist (backward compat), fall back to comparing the user's file against staging directly. If no diff file exists, read both files to understand the differences.
371
281
 
372
- **Present the situation clearly:**
282
+ **Assess the merge:**
373
283
 
374
- ```
375
- ### `{file path}`
284
+ - **What changed upstream** (old template → new template, from the diff and changelog)
285
+ - **What the user changed** (old template → user's file)
286
+ - **Overlap** (None / Partial / Significant) and **Risk** (Low = changes don't overlap; Medium = some overlap, cleanly resolvable; High = structural conflict or a heavily rewritten file)
376
287
 
377
- **What changed upstream:** {describe changes from old template → new template, referencing the diff and changelog}
378
- **What you changed:** {describe changes from old template → user's file - compare the two to identify customizations}
379
- **Overlap:** {None / Partial / Significant}
380
- **Risk:** {Low / Medium / High}
288
+ **Then act by whether a mandatory stop applies:**
381
289
 
382
- {Explain risk: Low = changes don't overlap. Medium = some overlap but cleanly resolvable. High = significant structural conflict or the file was heavily rewritten.}
383
-
384
- **My recommendation:** {one of the actions below}
385
-
386
- {If recommending a merge, show the proposed result with comments marking the source:}
387
- ```
388
-
389
- **Then present the user's options:**
290
+ - **No mandatory stop, and you are confident the merge preserves the user's customizations:** apply the merge and report it (one line: what upstream added, what user code it kept). This is the default path for most files.
291
+ - **A mandatory stop applies** (you are not confident; the merge changes observable behaviour or how a screen looks; or another stop below): present both versions side by side and let the user choose:
390
292
 
293
+ > ### `{file path}`
294
+ >
295
+ > **What changed upstream:** {…}
296
+ > **What you changed:** {…}
297
+ > **Why I'm asking:** {which mandatory stop - low confidence, a changed route/default/limit/flow, changed layout/copy/theme, …}
298
+ >
391
299
  > **What would you like to do?**
392
300
  > 1. **Accept merge** - {brief description of the merged result}
393
301
  > 2. **Keep my version** - Skip this upstream change entirely
394
302
  > 3. **Use upstream version** - Replace with the new template version (your changes will be lost)
395
- > 4. **Show me the diff** - Display the raw upstream diff so I can review it
396
- > 5. **Let me customize** - Tell me exactly what you want
397
-
398
- **In Quick mode:** For **Low risk** files, apply the recommended merge automatically and report what was done. For **Medium/High risk**, always ask.
399
-
400
- **In Automatic mode:** For **Low and Medium risk** files, apply the recommended merge automatically when you are confident it preserves the user's customizations, and report what was done. For **High risk** files - and any merge you are not confident about - always ask (see "Automatic mode behavior" in Step 5).
401
-
402
- **In Recommended mode:** Present each file and wait for the user's decision.
403
-
404
- **In Careful mode:** Present each file with the full proposed merged code shown, and wait for the user's decision.
303
+ > 4. **Show me the diff** - Display the raw upstream diff
304
+ > 5. **Combine them differently** - Tell me exactly what you want
405
305
 
406
306
  #### For Removed Files
407
307
 
@@ -411,21 +311,10 @@ If `.generatesaas/template/<path>` does not exist (backward compat), fall back t
411
311
  - If the user **modified** the old file: their customizations exist nowhere in the new version. Port them to the `to` path (show the proposed result) before deleting the old file. Never let a rename silently drop customizations.
412
312
  - Imports of the old path elsewhere in the project must be updated to the new path - run the import search below for the old path either way.
413
313
 
414
- Before presenting each removed file, **search the entire project** for imports of it. Use grep to find `import ... from` or `require(...)` statements referencing the file's path (check relative paths, aliases, and package paths). This is critical - the classification script only scans files in the update, not user-created files that may also depend on the removed file.
415
-
416
- ```
417
- ### `{file path}` - Removed Upstream
418
-
419
- **Why it was removed:** {reason from changelog}
420
- **Your modifications:** {describe if the user modified it, or "None - file is unmodified"}
421
- **Files that import this:** {list ALL files found by searching, or "None found"}
314
+ Before deleting each removed file, **search the entire project** for imports of it. Use grep to find `import ... from` or `require(...)` statements referencing the file's path (check relative paths, aliases, and package paths). This is critical - the classification script only scans files in the update, not user-created files that may also depend on the removed file.
422
315
 
423
- > **What would you like to do?**
424
- > 1. **Delete it** - It's no longer needed upstream
425
- > 2. **Keep it** - I still use this file
426
- ```
427
-
428
- If ANY files import the removed file, always warn before deletion and explain what would break.
316
+ - **No importers and the user never modified it:** delete it, and note it in the plan.
317
+ - **Any importer, or the user modified it:** this is a [mandatory stop](#mandatory-stops). Warn before deletion, list every importer, and let the user choose to delete or keep it.
429
318
 
430
319
  #### For Deleted-by-User Files
431
320
 
@@ -433,7 +322,7 @@ Files the user intentionally deleted - skip silently. Just note in the plan: "Sk
433
322
 
434
323
  #### For New Files In Deleted Trees (`newInDeletedTree`)
435
324
 
436
- These are files the new version adds inside a directory the user previously deleted (e.g. a feature package they removed). Auto-creating them would silently resurrect the deleted tree. Group them by their deleted ancestor directory and ask once per tree:
325
+ These are files the new version adds inside a directory the user previously deleted (e.g. a feature package they removed). Auto-creating them would silently resurrect the deleted tree, so this is a [mandatory stop](#mandatory-stops). Group them by their deleted ancestor directory and ask once per tree:
437
326
 
438
327
  ```
439
328
  ### New upstream files under `{deleted dir}/` (which you removed)
@@ -450,7 +339,7 @@ Default to **keep deleted** unless the user says otherwise. If they keep it dele
450
339
 
451
340
  #### After Each File
452
341
 
453
- 1. Apply the user's chosen action immediately
342
+ 1. Apply the chosen action immediately
454
343
  2. Mark the item as `[x]` (completed) or move to **Skipped** with the reason
455
344
  3. **Update the plan file** after every file so progress is saved
456
345
 
@@ -472,10 +361,7 @@ Similarly, if an auto-applied file changed its exports and a modified file that
472
361
 
473
362
  ### Step 8: Post-Update Validation
474
363
 
475
- After all files are processed, run the validation ladder below - every rung. The static
476
- rungs cannot see hook-level auth breakage, a missing static asset, or content wiring;
477
- the e2e suite is the only gate that exercises sign-in, registration, payments and the
478
- rendered pages. **Do not declare the update complete while any rung is red.**
364
+ After all files are processed, run the validation ladder below - every rung. The static rungs cannot see hook-level auth breakage, a missing static asset, or content wiring; the e2e suite is the only gate that exercises sign-in, registration, payments and the rendered pages. **Do not declare the update complete while any rung is red.** A verification failure you cannot fix with confidence is a [mandatory stop](#mandatory-stops).
479
365
 
480
366
  1. **Static gates:**
481
367
  - Scan merged files for syntax errors or broken imports
@@ -517,7 +403,7 @@ rendered pages. **Do not declare the update complete while any rung is red.**
517
403
  >
518
404
  > These appear to be caused by the update. Want me to fix them?
519
405
 
520
- 7. Fix any issues the user approves, then re-verify the affected rungs.
406
+ 7. Fix any issues the user approves, then re-verify the affected rungs. If a failure resists a confident fix, stop and ask (a mandatory stop).
521
407
 
522
408
  ### Step 9: Complete Update
523
409
 
@@ -527,10 +413,7 @@ rendered pages. **Do not declare the update complete while any rung is red.**
527
413
  - Modified files where the user chose "Keep my version"
528
414
  - Modified files that were skipped for any reason (couldn't merge, user excluded, etc.)
529
415
  - Auto-apply files that were reverted in the cascade awareness step
530
- - Template test/spec files you adapted to the project's customizations during validation
531
- (e.g. an e2e spec whose seeded-balance or gating assumption the project legitimately
532
- breaks) - the adaptation is a kept-your-version outcome, and recording it keeps the
533
- next update's diff honest
416
+ - Template test/spec files you adapted to the project's customizations during validation (e.g. an e2e spec whose seeded-balance or gating assumption the project legitimately breaks) - the adaptation is a kept-your-version outcome, and recording it keeps the next update's diff honest
534
417
 
535
418
  **Do NOT include:**
536
419
  - Files where the user accepted a merge or chose "Use upstream version" (template changes were applied)
@@ -544,12 +427,7 @@ rendered pages. **Do not declare the update complete while any rung is red.**
544
427
 
545
428
  If no files were held back, skip creating this file.
546
429
 
547
- > Note: the completion script runs a safety net that auto-holds-back upstream
548
- > changes which were demonstrably never applied (the file was not touched during
549
- > the entire update). Do NOT rely on it - it cannot detect a file you edited
550
- > during a merge or that the user customized between updates - always write
551
- > held-back.json yourself. Treat its warnings as a signal that your bookkeeping
552
- > missed something.
430
+ > Note: the completion script runs a safety net that auto-holds-back upstream changes which were demonstrably never applied (the file was not touched during the entire update). Do NOT rely on it - it cannot detect a file you edited during a merge or that the user customized between updates - always write held-back.json yourself. Treat its warnings as a signal that your bookkeeping missed something.
553
431
 
554
432
  2. **Run the completion script:**
555
433
 
@@ -559,48 +437,55 @@ node __SKILL_ROOT__/generatesaas-update/scripts/complete-update.js
559
437
 
560
438
  This updates `.generatesaas/manifest.json` to the new version, regenerates file hashes, and cleans up staging.
561
439
 
562
- 3. **Present the final summary:**
440
+ 3. **Present the final report:**
563
441
 
564
442
  ```markdown
565
443
  ## Result
566
444
 
567
445
  - **Status:** Completed
568
446
  - **Files auto-updated:** {count}
569
- - **Files merged with your input:** {count}
447
+ - **Files merged:** {count}
570
448
  - **New files created:** {count}
571
- - **Changes skipped:** {count}
449
+ - **Changes held back:** {count}
572
450
  - **Issues fixed:** {count or "None"}
573
451
 
574
452
  ### Post-update steps
575
453
  - Run `pnpm install` if dependencies changed
576
454
  - Run database migrations if schema was updated
455
+ - CI no longer runs on push: `ci.yml` now runs on pull requests and manual dispatch, so your pushes are quiet by design - run `pnpm preflight` locally and the full set from the Actions tab ("Run workflow")
577
456
  - If your host auto-deploys on push, follow [Deploy Discipline](#deploy-discipline) below before pushing
578
457
  - {any other steps from the changelog}
579
458
 
580
- ### Skipped changes
581
- {For each skipped item: what was skipped and why - so the user can revisit later}
459
+ ### Held back
460
+ {For each held-back item: what it was and why - so the user can revisit later}
582
461
  ```
583
462
 
584
463
  ---
585
464
 
465
+ ## Mandatory stops
466
+
467
+ The update runs unattended, but it **always stops and asks** at any of these. This is the one rule; nothing below it is optional:
468
+
469
+ - **Database schema changes** - never auto-merge schema (see [Database](#database-schema-migrations)).
470
+ - **An env or config change that introduces a new required value** (a new required env var, a config key with no safe default).
471
+ - **Every new option** - never auto-adopt a feature (handled in [Step 2.5](#step-25-review-newly-available-options)).
472
+ - **A removed file that something still imports** - run the import search first (Step 7).
473
+ - **A `newInDeletedTree` file** - never resurrect a tree the user deleted (Step 7).
474
+ - **A merge you are not confident preserves the user's intent** - when unsure, ask. It is always better to interrupt than to assume.
475
+ - **A merge that changes application behaviour the user can observe** - a route, a default, a limit, a flow.
476
+ - **A merge that changes how a screen looks** - layout, copy the user customized, theme.
477
+ - **A verification failure you cannot fix with confidence** (Step 8).
478
+
479
+ For the two behaviour/appearance stops, show the two versions side by side and ask which to keep or how to combine them. Stopping is always safe - keep the user's version and record it in `held-back.json`.
480
+
586
481
  ## Deploy Discipline
587
482
 
588
- An update usually ends with a push, and many hosts (Dokploy, Coolify, Vercel, Railway)
589
- auto-deploy that push. The update is not "done locally" on such a project - the push IS
590
- the deploy. Rules:
591
-
592
- 1. **Never push a branch that auto-deploys until the full Step 8 ladder - the e2e gate
593
- included - is green locally.** Pushing first and validating after turns a red gate
594
- into a production incident.
595
- 2. **After pushing, watch the CI run to its conclusion.** A red run on a commit that
596
- already deployed is an incident to act on now, not a follow-up for later.
597
- 3. **If a push webhook deploys the project, never trigger a manual deployment alongside
598
- it.** Two racing deploys can fail with "service already exists" (HTTP 409) and leave
599
- the service half-recreated. Trigger manually only when the deploy queue has been
600
- empty for several minutes.
601
- 4. The structural fix is to deploy from a CI job that runs **after** the test jobs
602
- succeed, instead of from the push webhook - then a red gate can never reach
603
- production. See the deployment docs' going-to-production checklist.
483
+ An update usually ends with a push, and many hosts (Dokploy, Coolify, Vercel, Railway) auto-deploy that push. The update is not "done locally" on such a project - the push IS the deploy. Rules:
484
+
485
+ 1. **Never push a branch that auto-deploys until the full Step 8 ladder - the e2e gate included - is green locally.** Pushing first and validating after turns a red gate into a production incident.
486
+ 2. **Validate before the push, not after.** `ci.yml` no longer runs on push - it runs on pull requests and manual dispatch - so the push that deploys triggers no gate. Run `pnpm preflight` locally (or a green Actions dispatch) before pushing; a red gate found after a commit already deployed is an incident to act on now.
487
+ 3. **If a push webhook deploys the project, never trigger a manual deployment alongside it.** Two racing deploys can fail with "service already exists" (HTTP 409) and leave the service half-recreated. Trigger manually only when the deploy queue has been empty for several minutes.
488
+ 4. The structural fix is to deploy from a CI job that runs **after** the test jobs succeed, instead of from the push webhook - then a red gate can never reach production. See the deployment docs' going-to-production checklist.
604
489
 
605
490
  ## Merge Strategies
606
491
 
@@ -614,25 +499,25 @@ Config files are the most commonly customized.
614
499
  - Add new config keys with their default values
615
500
  - If a key was renamed upstream, migrate the user's value to the new key name
616
501
  - Keep user's formatting preferences if they differ
617
- - Present the merged config to the user for review
502
+ - A config change that alters a default the app runs on is a [mandatory stop](#mandatory-stops)
618
503
 
619
504
  ### Components (`.vue`, `.tsx`)
620
505
 
621
506
  - Preserve user-added props, slots, event handlers, and custom logic
622
507
  - Apply upstream structural changes (new elements, accessibility improvements, bug fixes)
623
508
  - Keep user's custom CSS classes and styles
624
- - If the component was significantly restructured upstream AND the user heavily modified it: present both versions side by side and let the user decide
509
+ - A change to layout, customized copy, or theme is a [mandatory stop](#mandatory-stops): present both versions side by side and let the user decide
625
510
 
626
511
  ### API Routes (`routes/*.ts`)
627
512
 
628
513
  - Preserve user-added endpoints and middleware
629
514
  - Apply upstream bug fixes and security patches to existing endpoints
630
515
  - Keep user-added business logic intact
631
- - Watch for new imports or dependency changes
516
+ - Watch for new imports or dependency changes; a changed route, default, or limit is a [mandatory stop](#mandatory-stops)
632
517
 
633
518
  ### Database (schema, migrations)
634
519
 
635
- - NEVER auto-merge schema files - always present for user review
520
+ - NEVER auto-merge schema files - always a [mandatory stop](#mandatory-stops)
636
521
  - Warn about schema changes that may require new migrations
637
522
 
638
523
  **Never copy an upstream migration into `packages/database/drizzle/` as-is, and never overwrite the project's `drizzle/meta/_journal.json` or `drizzle/meta/*_snapshot.json` with the upstream versions.** A project's migration history is its own: upstream changes get re-derived into it, never pasted over it. Regenerate instead:
@@ -675,6 +560,7 @@ Whichever path applies, `db:deploy` re-reads the live schema afterwards and fail
675
560
 
676
561
  - Add new environment variables with their example values and comments
677
562
  - Preserve user-added variables
563
+ - A new **required** variable is a [mandatory stop](#mandatory-stops) - the app will not boot without it
678
564
  - Never touch actual `.env` files
679
565
 
680
566
  ## When to Skip
@@ -691,14 +577,3 @@ When skipping, always explain:
691
577
  1. What the upstream change was trying to do
692
578
  2. Why it was skipped
693
579
  3. Whether the user should revisit it later
694
-
695
- ## When to Always Ask
696
-
697
- Even in Quick or Automatic mode, always ask the user about:
698
-
699
- - Database schema changes
700
- - Files where user modifications are extensive (>30% of the file differs from template)
701
- - Changes where upstream and user modifications touch the same code sections
702
- - Removed files that other code depends on
703
- - Config changes where user's value format conflicts with new requirements
704
- - Any change where you're unsure about the right action