@cellajs/cli 0.4.2 → 0.6.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @cellajs/cli
2
2
 
3
- Keep your app in sync with upstream [cella template](https://github.com/cellajs/cella) updates while preserving your
3
+ Upgrade your app with upstream [cella template](https://github.com/cellajs/cella) changes while preserving your
4
4
  customizations.
5
5
 
6
6
  ## Usage
@@ -9,7 +9,7 @@ From your monorepo root, run `pnpm cella` for the interactive menu, or call a se
9
9
 
10
10
  ```bash
11
11
  pnpm cella analyze
12
- pnpm cella sync
12
+ pnpm cella upgrade
13
13
  pnpm cella audit
14
14
  ```
15
15
 
@@ -17,12 +17,12 @@ pnpm cella audit
17
17
 
18
18
  | Service | Description |
19
19
  |---------|-------------|
20
- | `analyze` | Dry run to see what would change on sync. It leaves your files and branches alone but updates git metadata: it fetches upstream and writes `refs/cella/last-sync` and a graft for the sync base |
21
- | `sync` | Merge upstream changes onto a fresh branch, sync package.json and open a squash-merge PR into `main` |
22
- | `migrate` | List the upstream migration notes this app has not handled yet, read them, run their codemods, record them |
20
+ | `analyze` | Dry run to see what would change on upgrade. It leaves your files and branches alone but updates git metadata: it fetches upstream and writes `refs/cella/last-upgrade` and a graft for the upgrade base |
21
+ | `upgrade` | Merge upstream changes onto a fresh branch, merge package.json and open a squash-merge PR into `main` |
22
+ | `align` | List the upstream alignments this app has not handled yet, read them, run their codemods, record them |
23
23
  | `audit` | Update outdated packages and runtime pins, then rebuild the security overrides from a fresh audit; report the security fixes this machine's Node, pnpm and gh miss |
24
24
  | `stats` | Count files by category and workspace package; with `--since <ref>`, count what the current branch changed, by kind of file |
25
- | `forks` * | Run normal sync inside local fork repositories |
25
+ | `forks` * | Run the upgrade inside local fork repositories |
26
26
  | `contributions` * | Pull and adopt changes from local forks |
27
27
 
28
28
  \* `forks` and `contributions` only appear when you have `forks` configured in `cella.config.ts`.
@@ -37,9 +37,9 @@ Per-service help: `pnpm cella <service> --help`.
37
37
 
38
38
  | Service | Useful options |
39
39
  |---------|----------------|
40
- | analyze | `--list`, `--json`, `--scope <all\|risk\|protected>`, `--track <release\|branch>`, `--ref <ref>`, `--unpinned` |
41
- | sync | `--track <release\|branch>`, `--ref <ref>`, `--keep-config`, `--unpinned` |
42
- | migrate | `--all`, `--json`, `--show <id>`, `--extract <id>`, `--run <id> [-- <codemod args>]`, `--mark <ids...>` |
40
+ | analyze | `--list`, `--json`, `--scope <all\|risk\|protected>`, `--all`, `--track <release\|branch>`, `--ref <ref>`, `--unpinned` |
41
+ | upgrade | `--track <release\|branch>`, `--ref <ref>`, `--keep-config`, `--unpinned` |
42
+ | align | `--all`, `--json`, `--show <id>`, `--extract <id>`, `--run <id> [-- <codemod args>]`, `--mark <ids...>` |
43
43
  | audit | `--list` |
44
44
  | forks | `--fork <name>`, `--keep-config` |
45
45
  | contributions | `--fork <name>`, `--json` |
@@ -52,10 +52,10 @@ Per-service help: `pnpm cella <service> --help`.
52
52
 
53
53
  ## Configuration
54
54
 
55
- Sync behavior lives in `cella.config.ts` at your monorepo root (a sensible default ships with new
55
+ Upgrade behavior lives in `cella.config.ts` at your monorepo root (a sensible default ships with new
56
56
  apps). To deviate files or folders from the template:
57
57
 
58
- - **`ignored`**: files completely excluded from sync (existing and new)
58
+ - **`ignored`**: files completely excluded from upgrades (existing and new)
59
59
  - **`pinned`**: full fork control, existing, modified, or deleted files are preserved
60
60
 
61
61
  An `ignored` entry may name a path your app does not have, to keep it from arriving (a file upstream
@@ -69,42 +69,42 @@ to upstream, which only drops upstream's next change to it.
69
69
 
70
70
  ## Upstream tracking
71
71
 
72
- The sync CLI tracks upstream cella one of two ways, set via `settings.upstreamTrack`:
72
+ The CLI tracks upstream cella one of two ways, set via `settings.upstreamTrack`:
73
73
 
74
74
  | Mode | Behavior | For |
75
75
  |------|----------|-----|
76
- | `release` (default) | Sync to a last cella release tag. Stable and reviewable: each bump maps to a changelog. | Most forks |
76
+ | `release` (default) | Upgrade to the latest cella release tag. Stable and reviewable: each bump maps to a changelog. | Most forks |
77
77
  | `branch` | Follow the bleeding-edge tip of `settings.upstreamBranch`. | cella maintainers, active development |
78
78
 
79
79
  For a one-off run that ignores the configured mode, pass `--track`:
80
80
 
81
81
  ```bash
82
- pnpm cella sync --track branch # follow the tip once, without editing config
82
+ pnpm cella upgrade --track branch # follow the tip once, without editing config
83
83
  ```
84
84
 
85
- To sync to one specific upstream point, pin it with `--ref` (it wins over `--track`): a commit sha,
85
+ To upgrade to one specific upstream point, pin it with `--ref` (it wins over `--track`): a commit sha,
86
86
  a release tag or an upstream branch name, resolved on the upstream remote (`main` is upstream's
87
87
  `main`, not yours). The ref must be on `settings.upstreamBranch` or in an upstream release; a
88
- release tag syncs as that release, anything else is recorded like branch tracking.
88
+ release tag upgrades as that release, anything else is recorded like branch tracking.
89
89
 
90
90
  ```bash
91
- pnpm cella sync --ref 4f7d87c # sync up to this upstream commit
91
+ pnpm cella upgrade --ref 4f7d87c # upgrade up to this upstream commit
92
92
  ```
93
93
 
94
- A run never syncs to a point behind the last sync: when an earlier `--ref` or `--track branch` run
95
- went past the latest release, release tracking ends with a `nothing to sync` message until a newer
96
- release exists, instead of reverting what the app already has. A `--ref` behind the last sync is
94
+ A run never upgrades to a point behind the last upgrade: when an earlier `--ref` or `--track branch` run
95
+ went past the latest release, release tracking ends with a `nothing to upgrade` message until a newer
96
+ release exists, instead of reverting what the app already has. A `--ref` behind the last upgrade is
97
97
  refused. Either way the run changes nothing and leaves you on the branch you started from.
98
98
 
99
- ## Sync workflow
99
+ ## Upgrade workflow
100
100
 
101
- `pnpm cella sync` never commits to `main` directly.
101
+ `pnpm cella upgrade` never commits to `main` directly.
102
102
 
103
103
  ```
104
- main ──▶ cella/sync/<stamp> ──(3-way merge)──▶ PR ──(squash)──▶ main
104
+ main ──▶ cella/upgrade/<stamp> ──(3-way merge)──▶ PR ──(squash)──▶ main
105
105
  ```
106
106
 
107
- It runs a real git 3-way merge. `sync` is **idempotent and staged**: each run advances the sync
107
+ It runs a real git 3-way merge. `upgrade` is **idempotent and staged**: each run advances the upgrade
108
108
  one stage, and the run that commits never ships: the pause on the committed branch is where
109
109
  drift triage (`pnpm cella analyze` diffs committed HEAD) and follow-up commits happen.
110
110
 
@@ -112,86 +112,136 @@ drift triage (`pnpm cella analyze` diffs committed HEAD) and follow-up commits h
112
112
  are reconciled (`pnpm install` + `pnpm check`), everything is staged, and the delta is
113
113
  committed; then the run stops on the branch. A conflicted merge stops earlier so you can
114
114
  resolve in your IDE (`git add` the resolved files) and re-run to commit.
115
- 2. **Final re-run `pnpm cella sync`** on the committed branch ships it: pushes to `origin`,
116
- opens a PR into `main` (via `gh`) titled like the sync commit, even with follow-up commits on
115
+ 2. **Final re-run `pnpm cella upgrade`** on the committed branch ships it: pushes to `origin`,
116
+ opens a PR into `main` (via `gh`) titled like the upgrade commit, even with follow-up commits on
117
117
  top, and switches you back to `main`.
118
118
 
119
119
  Before the merge starts, a first run checks that it can go ahead, and stops without changing
120
120
  anything when it cannot: the temporary branch is removed again and you are back on the branch you
121
121
  started from. It stops when upstream needs a newer `@cellajs/cli` than the one running, and when
122
- upstream changed its own sync config in ways yours does not follow (see
123
- [Upstream changes that never sync](#upstream-changes-that-never-sync)).
122
+ upstream changed its own CLI config in ways yours does not follow (see
123
+ [Upstream changes that never merge](#upstream-changes-that-never-merge)).
124
124
 
125
- `sync` also runs from a linked git worktree while another worktree has `main` checked out: it
126
- never switches to `main`. It compares `main` with `origin/main` by ref and cuts the sync branch
125
+ `upgrade` also runs from a linked git worktree while another worktree has `main` checked out: it
126
+ never switches to `main`. It compares `main` with `origin/main` by ref and cuts the upgrade branch
127
127
  from `main`; when `main` is behind and checked out elsewhere, it cuts from `origin/main` instead
128
128
  and leaves `main` as it is. After shipping, the worktree detaches at `main` instead of switching
129
129
  to it.
130
130
 
131
131
  When the commit stage runs, the in-progress merge state (`MERGE_HEAD`) is discarded, so the staged delta
132
- collapses into a **single-parent commit** (`chore: sync upstream cella <sha>`). This keeps the PR
132
+ collapses into a **single-parent commit** (`chore: upgrade cella to <sha>`). This keeps the PR
133
133
  to one clean commit with the incremental diff; a two-parent merge commit would instead list the
134
134
  upstream branch's entire history, because the fork doesn't share pushed ancestry with upstream
135
135
  and the local `git replace` graft that makes merges incremental is never pushed. Ancestry lives
136
- in `refs/cella/last-sync` (and the committed `cella.manifest.json` for fresh clones), so
136
+ in `refs/cella/last-upgrade` (and the committed `cella.manifest.json` for fresh clones), so
137
137
  `git merge-base` keeps working across throwaway branches; each is safe to delete once its PR
138
138
  lands. The three-segment name can't collide with git's ref namespacing.
139
139
 
140
- If conflicts remain when you re-run, `sync` lists them and stops (never starting a second cycle
140
+ If conflicts remain when you re-run, `upgrade` lists them and stops (never starting a second cycle
141
141
  mid-merge). If `pnpm check`, the push, or `gh` fails, it degrades gracefully, reporting the
142
142
  issue and printing the remaining manual steps:
143
143
 
144
144
  ```bash
145
- git push -u origin cella/sync/<stamp>
146
- gh pr create --base main --head cella/sync/<stamp> --fill
145
+ git push -u origin cella/upgrade/<stamp>
146
+ gh pr create --base main --head cella/upgrade/<stamp> --fill
147
147
  ```
148
148
 
149
- ## Migration notes
149
+ ## Analyze output
150
150
 
151
- Upstream ships a note for every change that app code has to follow, in `cella/migrations/<id>/`:
152
- a README (frontmatter, title, summary, then the steps) and sometimes a codemod. The notes stay
153
- upstream. The sync never brings that folder into the app and removes a copy it finds; `migrate`
154
- reads the notes from the upstream commit the app last synced to, which the sync already fetched.
151
+ `pnpm cella analyze` prints its file sections in the order they need you: what merges on its own
152
+ first (`behind`, `diverged`), then pinned files, drifted files, and the upstream changes the upgrade
153
+ leaves out (`protected but behind upstream`). The summary and `next steps` close the run, so the
154
+ last lines are the ones to act on. A file row is its path, linked per `fileLinkMode`, with a count
155
+ and a short age (`3h`, `2d`, `3mo`) in columns.
155
156
 
156
- The app keeps one small record, `cella/cella.migrations.json`, listing the notes it has not
157
- handled yet. The sync adds the notes that arrive with it, `migrate --mark` removes them, and the
158
- file is deleted once the list is empty. No file means nothing is pending, so a new app starts
159
- without one.
157
+ Large groups collapse: more than 15 behind files become one row per folder, more than 8 pinned files
158
+ keep the ones missing 10 or more upstream lines, and five or more protected files of one kind under
159
+ one override entry become one row (`backend/drizzle/ · 42 × snapshot.json`). `--all` lists every
160
+ path.
160
161
 
161
- Notes are information, never a gate. Each sync run, and `analyze`, ends with one line:
162
+ Analyze and upgrade both end with `next steps`, numbered in the order you take them: the review page,
163
+ the command to run next, and the alignments the upgrade brings or that are still open.
162
164
 
163
165
  ```
164
- migration notes: 94 of 97 handled · 3 arrived with this sync · 3 open: pnpm cella migrate
166
+ next steps
167
+ ────────────────────────────────────────────────────────────
168
+
169
+ 1 review file:///Users/you/app/.git/cella-diff/analyze-review.html
170
+ 22 diffs in 3 sections · 42 listed without a diff
171
+ 2 upgrade pnpm cella upgrade
172
+ commits on a fresh branch, a rerun opens the PR · 36 update, 2 merge
173
+ 3 align 1 alignment arrives with this upgrade
174
+ ○ Migration notes become alignments · manual · not breaking
175
+ after the upgrade: pnpm cella align
165
176
  ```
166
177
 
167
- and the sync PR lists the open notes with links. Handle them in the sync PR or later; they stay
168
- listed until marked.
178
+ Without a terminal (piped, or read by an agent) each alignment row also gets its id, for
179
+ `pnpm cella align --show <id>`.
180
+
181
+ ## Alignments
182
+
183
+ Upstream ships an alignment for every change that app code has to follow, in
184
+ `cella/alignments/<id>/`: a README (frontmatter, title, summary, then the steps) and sometimes a
185
+ codemod. Alignments stay upstream. The upgrade never brings that folder into the app and removes a
186
+ copy it finds (also of `cella/migrations/`, the migration notes upstream deleted when it started
187
+ the alignments); `align` reads them from the upstream commit the app last upgraded to, which the upgrade
188
+ already fetched.
189
+
190
+ The frontmatter says what the change asks of the app: `breaking`, `clientCacheBump`,
191
+ `caughtBy` (`compiler`, `tests` or `nothing`: what catches app code the change leaves behind),
192
+ `generate` (the change needs `pnpm generate`), `grep` (words app code may still use) and, beside a
193
+ codemod, its `roots`.
194
+
195
+ The app keeps one small record, `cella/cella.alignments.json`, listing the alignments it has not
196
+ handled yet. The upgrade adds the ones that arrive with it, `align --mark` removes them, and the file
197
+ is deleted once the list is empty. No file means nothing is pending, so a new app starts without
198
+ one.
199
+
200
+ Alignments are information, never a gate. `analyze` and each upgrade run list them under
201
+ [`next steps`](#analyze-output): by title, with their kind, at most five. In `analyze` the ones in
202
+ the upgrade range *arrive with this upgrade*; they become open once the upgrade lands, which is when
203
+ `pnpm cella align` lists them. `pnpm cella align` itself ends with one line:
204
+
205
+ ```
206
+ alignments: 94 of 97 handled · 3 open: pnpm cella align
207
+ ```
208
+
209
+ The upgrade PR lists the open alignments with links. Handle them in the upgrade PR or later; they
210
+ stay listed until marked.
169
211
 
170
212
  ```bash
171
- pnpm cella migrate # open notes, with summary and links
172
- pnpm cella migrate --show <id> # one note's README
173
- pnpm cella migrate --run <id> # run its codemod, report only
174
- pnpm cella migrate --run <id> -- rewrite frontend/src # run it with your own arguments
175
- pnpm cella migrate --extract <id> # its folder under node_modules/.cache/cella/migrations/<id>/
176
- pnpm cella migrate --mark <id> [...] # record notes as handled
213
+ pnpm cella align # open alignments, with summary and links
214
+ pnpm cella align --show <id> # one alignment's README and what git tells about it
215
+ pnpm cella align --run <id> # run its codemod, report only
216
+ pnpm cella align --run <id> -- rewrite frontend/src # run it with your own arguments
217
+ pnpm cella align --extract <id> # its folder under node_modules/.cache/cella/alignments/<id>/
218
+ pnpm cella align --mark <id> [...] # record alignments as handled
177
219
  ```
178
220
 
179
- `--run` extracts the note and runs its codemod with `tsx` from your app root. Everything after `--`
180
- goes to the codemod as given; without it the codemod gets `inventory` and the note's `roots`, the
181
- report-only run.
221
+ Next to its README, each alignment shows what git can tell about it: the upstream commit and PR
222
+ that added it, the other alignments of that commit, the files of that commit the app pins, ignores
223
+ or changed, and the lines of app code that hold one of its `grep` words. Only files that differ
224
+ from the upstream commit of the last upgrade count, so a template file the app never touched is
225
+ never a hit. Two or more open alignments with `generate` get one line: work their code steps first, then
226
+ generate once. `--show` reads an alignment the last upgrade does not have yet from the fetched
227
+ upstream branch, so it works before the upgrade that brings it.
228
+
229
+ `--run` extracts the alignment and runs its codemod with `tsx` from your app root. Everything after
230
+ `--` goes to the codemod as given; without it the codemod gets `inventory` and the alignment's
231
+ `roots`, the report-only run.
182
232
 
183
233
  A codemod's roots cover template-owned files too, and a file that is identical to upstream already
184
234
  is the way upstream wants it: upstream may have changed it after writing the codemod, so a rewrite
185
235
  there only creates drift. Before the codemod starts, `--run` notes which files are byte-identical
186
- to the last synced upstream commit (`upstream.commit` in `cella/cella.manifest.json`, during a
187
- staged sync the incoming commit). After the run, each of those files the codemod changed gets its
236
+ to the upstream commit of the last upgrade (`upstream.commit` in `cella/cella.manifest.json`,
237
+ during a staged upgrade the incoming commit). After the run, each of those files the codemod changed gets its
188
238
  upstream content back, and the run prints how many it restored. Files your app changed keep the
189
239
  codemod's rewrite. The codemod's own report still counts the restored files, in a report-only run
190
240
  too. A codemod run by hand from the `--extract` folder has no such protection.
191
241
 
192
- ## Sync rules
242
+ ## Merge rules
193
243
 
194
- For each file, `sync` compares fork and upstream **content** (blob comparison) and resolves it
244
+ For each file, `upgrade` compares fork and upstream **content** (blob comparison) and resolves it
195
245
  per the table below. Unconfigured files converge on upstream; `ignored` and `pinned` let you opt
196
246
  out:
197
247
 
@@ -203,72 +253,77 @@ out:
203
253
  | Deleted in upstream | ✅ Keep | ✅ Keep | 🗑️ Delete |
204
254
  | Only in your app | ✅ Keep | ✅ Keep | ✅ Keep |
205
255
 
206
- **Choosing an override:** `ignored` = file never syncs and is fully hidden (app-specific docs,
256
+ **Choosing an override:** `ignored` = file never merges and is fully hidden (app-specific docs,
207
257
  assets, config you own). `pinned` = your version always wins but stays visible (files you
208
- customize). Unconfigured = syncs automatically. Run `pnpm cella analyze` first to preview.
258
+ customize). Unconfigured = merges automatically. Run `pnpm cella analyze` first to preview.
209
259
 
210
260
  ## Status indicators
211
261
 
212
- During analysis and sync, files are displayed with status indicators:
262
+ During analysis and upgrade, files are displayed with status indicators:
213
263
 
214
264
  | Symbol | Label | Meaning | Action |
215
265
  |:------:|-------|---------|--------|
216
266
  | ◇ | `managed` | Package/config file changed | Handled separately by cella |
217
- | ⨂ | `ignored` | Protected by ignored config | Excluded from sync |
267
+ | ⨂ | `ignored` | Protected by ignored config | Excluded from upgrades |
218
268
  | ✓ | `identical` | Fork matches upstream | No action needed |
219
269
  | ↑ | `ahead` | Fork changed (pinned), upstream did not | Protected, keeping fork |
220
270
  | ! | `drifted` | Fork changed, not protected | At risk, consider pinning |
221
- | ↓ | `behind` | Upstream has changes | Will sync from upstream |
271
+ | ↓ | `behind` | Upstream has changes | Will update from upstream |
222
272
  | ⇅ | `diverged` | Both sides changed | Will merge from upstream |
223
273
  | ⨀ | `pinned` | Both changed, fork wins | Protected, keeping fork: review, see below |
224
274
  | + | `local` | Only in fork, never in upstream | No action needed |
225
275
 
226
276
  ### Protected but behind upstream
227
277
 
228
- A pinned or ignored file wins whole-file: when upstream also changed it since the last sync,
278
+ A pinned or ignored file wins whole-file: when upstream also changed it since the last upgrade,
229
279
  upstream's hunks are dropped, not merged. That is easy to miss (a pinned stylesheet quietly
230
- missing new upstream utilities that synced components rely on), so both commands call it out:
280
+ missing new upstream utilities that merged components rely on), so both commands call it out:
231
281
 
232
282
  - `analyze` lists them in a `⚠ protected but behind upstream` section (pinned files as ⨀,
233
- ignored as ⨂) with the number of lines upstream changed; `--list`/`--json` include them in
234
- `--scope all` and `--scope protected` (`--json` adds `upstreamChanged` and `upstreamChangedLines`).
235
- - `sync` prints the same list at the end of its summary, right when the drop happens.
283
+ ignored as ⨂) with the number of lines upstream changed, together with the ignored files only
284
+ upstream changed (tagged `new` or `deleted`, see below). New files come first, then the most
285
+ changed; generated output the fork regenerates itself (`sdk/gen`, `*.gen.*` files) is left out.
286
+ `--list`/`--json` include them in `--scope all` and `--scope protected` (`--json` adds
287
+ `upstreamChanged` and `upstreamChangedLines`).
288
+ - `upgrade` prints the same list at the end of its summary, right when the drop happens.
236
289
 
237
290
  ```
238
291
  ⚠ 3 protected files kept the fork version, dropping upstream changes:
239
292
  ⨀ frontend/src/styling/tailwind.css · 21 lines changed upstream
240
293
  ⨂ shared/config/default.ts · 4 lines changed upstream
241
294
  ⨂ shared/config/staging.ts · 2 lines changed upstream
242
- pinned/ignored files where upstream also changed since the last sync; the fork side wins on conflict, so review what upstream changed and adopt what you need.
295
+ pinned/ignored files where upstream also changed since the last upgrade; the fork side wins on conflict, so review what upstream changed and adopt what you need.
243
296
  ```
244
297
 
245
- The [review page](#review-page) shows what upstream changed in each of them since the last sync.
246
- The check is relative to the last sync point: a drop that happened in an earlier sync only shows
247
- up as plain `ahead` afterwards. For that case the `↑ protected in fork` section annotates pinned
248
- files with `· N upstream lines absent` (lines upstream has that the fork lacks, compared at the
249
- tips, `--json`: `upstreamLinesAbsent`). That is upstream content the fork never received,
298
+ The [review page](#review-page) shows what upstream changed in each of them since the last upgrade.
299
+ The check is relative to the last upgrade: a drop that happened in an earlier upgrade only shows
300
+ up as plain `ahead` afterwards. For that case the `↑ protected in fork` section counts the
301
+ `upstream lines absent` from each pinned file (lines upstream has that the fork lacks, compared at
302
+ the tips, `--json`: `upstreamLinesAbsent`). That is upstream content the fork never received,
250
303
  deliberately or not: the review page shows the difference, so you can decide. Ignored files are
251
304
  not annotated.
252
305
 
253
- To pull upstream into every pinned file at once, run `sync --unpinned`: pins are lifted for that
306
+ To pull upstream into every pinned file at once, run `upgrade --unpinned`: pins are lifted for that
254
307
  run (managed files stay pinned) and the merge uses the full upstream history, so changes earlier
255
- syncs dropped come back too. Review the staged merge in your editor and keep what you want;
308
+ upgrades dropped come back too. Review the staged merge in your editor and keep what you want;
256
309
  `analyze --unpinned` previews it.
257
310
 
258
- ### Upstream changes that never sync
311
+ ### Upstream changes that never merge
259
312
 
260
- Two more kinds of upstream change never reach the fork on their own. `analyze` prints both after
261
- its summary, and `sync` after its merge summary:
313
+ Two more kinds of upstream change never reach the fork on their own. `analyze` lists the first in
314
+ `protected but behind upstream` and prints the second after its file sections; `upgrade` prints both
315
+ after its merge summary:
262
316
 
263
317
  - **Ignored paths changed upstream.** Upstream changed, added or deleted a file under an `ignored`
264
318
  entry (app-owned module folders included) and the fork left it untouched. No conflict marks it,
265
- so this is where new config keys and version bumps under `shared/config` show up. Each `ignored`
266
- entry gets one line with a file count, and the [review page](#review-page) shows the diffs. Files
319
+ so this is where new config keys and version bumps under `shared/config` show up. In `upgrade`
320
+ each `ignored` entry gets one line with a file count, and the [review page](#review-page) shows
321
+ the diffs. Files
267
322
  both sides changed stay in the section above, and generated output the fork regenerates itself
268
323
  (`sdk/gen`, `*.gen.*` files) is left out. `--list`/`--json` include these
269
324
  files in `--scope all` and `--scope protected` (`--json`: `upstreamOnly`).
270
- - **Upstream sync config changes.** `cella/cella.config.ts` never syncs, so entries upstream adds to
271
- its own `overrides.pinned` or `overrides.ignored`, and keys it adds to `settings.packageJsonSync`
325
+ - **Upstream CLI config changes.** `cella/cella.config.ts` never merges, so entries upstream adds to
326
+ its own `overrides.pinned` or `overrides.ignored`, and keys it adds to `settings.packageJsonKeys`
272
327
  (the template your config started from), never arrive. The report names each entry upstream added
273
328
  that your config lacks (`+`) and each entry upstream dropped that your config still has (`−`). It
274
329
  reads upstream's config without running it and never edits yours. `--json` puts the lists on the
@@ -277,76 +332,79 @@ its summary, and `sync` after its merge summary:
277
332
  ```
278
333
  ⚠ ignored paths changed upstream · 1 file under 1 entry
279
334
  ⨂ frontend/src/modules/marketing · 1 file
280
- the fork left these untouched and ignored paths never sync: review and adopt what you need.
335
+ the fork left these untouched and ignored paths never merge: review and adopt what you need.
281
336
 
282
- ⚠ upstream changed its sync config · 2 entries to review
337
+ ⚠ upstream changed its CLI config · 2 entries to review
283
338
  + pinned: backend/src/bundle-config.ts
284
- + packageJsonSync: exports
285
- cella/cella.config.ts never syncs: add or drop these by hand where they fit your app.
339
+ + packageJsonKeys: exports
340
+ cella/cella.config.ts never merges: add or drop these by hand where they fit your app.
286
341
  ```
287
342
 
288
- `analyze` only reports these. `sync` checks the sync config before a new merge and stops when it
343
+ `analyze` only reports these. `upgrade` checks the CLI config before a new merge and stops when it
289
344
  finds entries: the merge runs on your config, so with a list that is behind, a path upstream now
290
- ignores or pins would arrive as an ordinary synced file (upstream renamed an ignored folder, your
345
+ ignores or pins would arrive as an ordinary merged file (upstream renamed an ignored folder, your
291
346
  list still names the old one). Nothing has changed at that point. Add or drop the entries that fit
292
347
  your app in `cella/cella.config.ts`, commit and rerun, or pass `--keep-config` to merge with your
293
348
  config as it stands; the report then follows the merge summary as before. The rerun that commits an
294
349
  already staged merge never stops for this.
295
350
 
296
351
  ```bash
297
- pnpm cella sync --keep-config # merge although upstream changed its sync config
352
+ pnpm cella upgrade --keep-config # merge although upstream changed its CLI config
298
353
  ```
299
354
 
300
355
  ### Review page
301
356
 
302
357
  The terminal lists files; the review page shows their diffs, side by side and highlighted, on one
303
- page in your browser under the same section titles. `analyze` and `sync` write it whenever a list
304
- has files, and print its path last:
358
+ page in your browser under the same section titles. `analyze` and `upgrade` write it whenever a list
359
+ has files, and list it first under [`next steps`](#analyze-output):
305
360
 
306
361
  ```
307
- ⧈ review page with 3 diffs, opened in the browser:
308
- /Users/you/app/.git/cella-diff/sync-review.html
362
+ 1 review file:///Users/you/app/.git/cella-diff/upgrade-review.html
363
+ 3 diffs of upstream changes that did not arrive · opened in the browser
309
364
  ```
310
365
 
311
- | Section | `analyze` | `sync` | The diff shows |
366
+ | Section | `analyze` | `upgrade` | The diff shows |
312
367
  | --- | --- | --- | --- |
313
- | protected but behind upstream (sync: protected files kept the fork version) | ✓ | ✓ | what upstream changed since the last sync |
314
- | ignored paths changed upstream | ✓ | ✓ | what upstream changed since the last sync |
315
- | pinned files that match the previous upstream | ✓ | ✓ | what upstream changed since the last sync |
368
+ | protected but behind upstream (upgrade: protected files kept the fork version) | ✓ | ✓ | what upstream changed since the last upgrade |
369
+ | ignored paths changed upstream (analyze: under protected but behind upstream) | ✓ | ✓ | what upstream changed since the last upgrade |
370
+ | pinned files that match the previous upstream | ✓ | ✓ | what upstream changed since the last upgrade |
316
371
  | protected in fork, upstream lines absent | ✓ | | the fork against upstream, both as they are now |
317
- | drifted from upstream | ✓ | | what the fork changed since the last sync |
372
+ | drifted from upstream | ✓ | | what the fork changed since the last upgrade |
318
373
 
319
- `sync` opens the page in your browser when it runs in a terminal: the files on it are upstream
320
- changes the merge did not bring in, and the committed sync branch is where you adopt them.
321
- `analyze` only prints the path, since you run it often and pinned files keep their absent lines.
374
+ `upgrade` opens the page in your browser when it runs in a terminal: the files on it are upstream
375
+ changes the merge did not bring in, and the committed upgrade branch is where you adopt them.
376
+ `analyze` only lists the page, since you run it often and pinned files keep their absent lines.
322
377
  The page lives in the git dir, so it never shows up in `git status`, and each run overwrites it. It
323
- holds 50 diffs at most; the rest, and files without a text diff, are listed by path.
378
+ renders at most 50 diffs and 15,000 diff lines, and a single diff over 2,000 lines is listed
379
+ instead (a rendered line costs about 0.6 KB of page). Sections take turns, one file each, so every
380
+ section gets diffs before one fills the page. The rest, and files without a text diff, are listed
381
+ by path.
324
382
 
325
- ## Package.json sync
383
+ ## Package.json merge
326
384
 
327
- `packageJsonSync` controls which package.json sections sync from upstream:
385
+ `packageJsonKeys` controls which package.json sections merge from upstream:
328
386
 
329
387
  ```typescript
330
- packageJsonSync: ['dependencies', 'devDependencies', 'scripts']
388
+ packageJsonKeys: ['dependencies', 'devDependencies', 'scripts']
331
389
  ```
332
390
 
333
391
  **Supported keys:** `dependencies`, `devDependencies`, `peerDependencies`, `optionalDependencies`, `scripts`, `engines`, `packageManager`, `overrides`, `exports`, `pnpm`
334
392
 
335
393
  Each section merges three-way against the merge-base package.json (upstream as of your last
336
- sync). An entry your fork never touched follows upstream: it is **added**, **updated** (a rewritten
394
+ upgrade). An entry your fork never touched follows upstream: it is **added**, **updated** (a rewritten
337
395
  script, a changed range) or **removed** when upstream dropped it. An entry your fork added or
338
396
  changed stays as it is; only a strictly higher upstream version still bumps it, and never for
339
397
  `scripts`. An entry your fork removed is not re-added. A dependency or script upstream dropped
340
398
  stays while your own code still uses it: files that differ from upstream and scripts your fork
341
399
  added or changed are searched for an import of the package, a run of its CLI, or a package manager
342
- command that runs the script. The sync lists every change and warns about each entry it kept this
400
+ command that runs the script. The upgrade lists every change and warns about each entry it kept this
343
401
  way, so you can remove it once your code no longer needs it. `exports` are add-only: an entry your fork
344
402
  already defines is never rewritten, and `exports` only merges when both sides are subpath maps
345
- (`{ ".": …, "./config": … }`). A workspace upstream added since your last sync arrives with its
403
+ (`{ ".": …, "./config": … }`). A workspace upstream added since your last upgrade arrives with its
346
404
  package.json copied verbatim. A merged section is sorted alphabetically, except `scripts`: they
347
405
  keep upstream's order, and a script only your fork has stays after the one it follows.
348
406
 
349
- `type` always syncs, whatever `packageJsonSync` lists: it follows upstream where your fork kept the
407
+ `type` always merges, whatever `packageJsonKeys` lists: it follows upstream where your fork kept the
350
408
  previous value, and a package.json without `type` gets upstream's. Set it yourself (for example
351
409
  `"commonjs"`) to keep your own.
352
410
 
package/dist/config.d.ts CHANGED
@@ -3,11 +3,11 @@
3
3
  * schema, and the internal types the services share.
4
4
  */
5
5
 
6
- declare const PACKAGE_JSON_SYNC_KEYS: readonly ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies", "scripts", "engines", "packageManager", "overrides", "exports", "pnpm"];
7
- /** Valid package.json keys that can be synced */
8
- type PackageJsonSyncKey = (typeof PACKAGE_JSON_SYNC_KEYS)[number];
6
+ declare const PACKAGE_JSON_KEYS: readonly ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies", "scripts", "engines", "packageManager", "overrides", "exports", "pnpm"];
7
+ /** Valid package.json keys that can merge from upstream */
8
+ type PackageJsonKey = (typeof PACKAGE_JSON_KEYS)[number];
9
9
  /**
10
- * Sync settings: all configurable options for the sync CLI.
10
+ * Settings: all configurable options for the cella CLI.
11
11
  * Hover over each property for documentation.
12
12
  */
13
13
  interface SyncSettings {
@@ -20,21 +20,25 @@ interface SyncSettings {
20
20
  upstreamBranch?: string;
21
21
  /**
22
22
  * How to track upstream cella. Defaults to 'release'.
23
- * - 'release' (default): sync to a published cella release tag (`0.18.1`, with or without `v`). Stable and
23
+ * - 'release' (default): upgrade to a published cella release tag (`0.18.1`, with or without `v`). Stable and
24
24
  * reviewable: each bump maps to a changelog. Uses the latest release.
25
25
  * - 'branch': follow the bleeding-edge tip of `upstreamBranch`. For cella
26
26
  * maintainers and forks doing active development on top of unreleased changes.
27
27
  */
28
28
  upstreamTrack?: 'release' | 'branch';
29
29
  /**
30
- * Trunk branch that `pnpm cella sync` cuts the temporary branch from and that you open the
30
+ * Trunk branch that `pnpm cella upgrade` cuts the temporary branch from and that you open the
31
31
  * squash-merge PR into. Defaults to 'main'. Cutting fresh from trunk each cycle keeps every
32
32
  * PR limited to that cycle's upstream delta (no accumulation) and `main` linear.
33
33
  */
34
34
  releaseBase?: string;
35
- /** Which package.json keys to sync (default: ['dependencies', 'devDependencies']). `type` always syncs. */
36
- packageJsonSync?: PackageJsonSyncKey[];
37
- /** Automatic package.json sync after the sync service completes (default: true). Set to false to turn it off. */
35
+ /** Which package.json keys merge from upstream (default: ['dependencies', 'devDependencies']). `type` always merges. */
36
+ packageJsonKeys?: PackageJsonKey[];
37
+ /** Merge the `packageJsonKeys` of every package.json after the upgrade merge (default: true). */
38
+ mergePackageJson?: boolean;
39
+ /** @deprecated Renamed to `packageJsonKeys`. */
40
+ packageJsonSync?: PackageJsonKey[];
41
+ /** @deprecated Renamed to `mergePackageJson`. */
38
42
  syncWithPackages?: boolean;
39
43
  /**
40
44
  * How to link files in CLI output.
@@ -48,7 +52,7 @@ interface SyncSettings {
48
52
  *
49
53
  * Cella is the upstream/source-of-truth. For each fork it can:
50
54
  * - pull contributions FROM the fork's `pullBranch` (contributions service)
51
- * - run the normal temporary-branch sync flow inside the fork (forks service)
55
+ * - run the normal temporary-branch upgrade flow inside the fork (forks service)
52
56
  */
53
57
  interface ForkConfig {
54
58
  /** Display name for the fork (also used as the contrib/<name> branch slug) */
@@ -102,4 +106,4 @@ interface CellaCliConfig {
102
106
  */
103
107
  declare function defineConfig(config: CellaCliConfig): CellaCliConfig;
104
108
 
105
- export { type CellaCliConfig, type PackageJsonSyncKey, defineConfig };
109
+ export { type CellaCliConfig, type PackageJsonKey, defineConfig };
package/dist/config.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/config/types.ts
2
2
  import { z } from "zod";
3
- var PACKAGE_JSON_SYNC_KEYS = [
3
+ var PACKAGE_JSON_KEYS = [
4
4
  "dependencies",
5
5
  "devDependencies",
6
6
  "peerDependencies",
@@ -21,7 +21,9 @@ var cellaConfigSchema = z.object({
21
21
  upstreamBranch: z.string().min(1).optional(),
22
22
  upstreamTrack: z.enum(["release", "branch"]).optional(),
23
23
  releaseBase: z.string().min(1).optional(),
24
- packageJsonSync: z.array(z.enum(PACKAGE_JSON_SYNC_KEYS)).optional(),
24
+ packageJsonKeys: z.array(z.enum(PACKAGE_JSON_KEYS)).optional(),
25
+ mergePackageJson: z.boolean().optional(),
26
+ packageJsonSync: z.array(z.enum(PACKAGE_JSON_KEYS)).optional(),
25
27
  syncWithPackages: z.boolean().optional(),
26
28
  fileLinkMode: z.enum(["commit", "file"]).optional()
27
29
  }).strict(),