@blocofy/cli 0.10.0 → 0.12.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 +208 -20
- package/bin/blocofy.mjs +424 -43
- package/lib/args.mjs +2 -1
- package/lib/http.mjs +4 -1
- package/lib/output.mjs +23 -4
- package/lib/site-state.mjs +33 -10
- package/lib/target.mjs +71 -13
- package/lib/theme-sync.mjs +163 -63
- package/lib/translations.mjs +1059 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ history. If the context already has a dev token for another site, nothing is sav
|
|
|
40
40
|
|
|
41
41
|
```
|
|
42
42
|
blocofy contexts [--json] # list saved contexts (never prints secrets)
|
|
43
|
-
blocofy use <name> # default context for
|
|
43
|
+
blocofy use <name> # default context for status / target / pages check outside a project
|
|
44
44
|
blocofy logout --context <name> # remove a context and its secrets
|
|
45
45
|
```
|
|
46
46
|
|
|
@@ -95,30 +95,66 @@ the admin panel, never touching the live site. Publish it with `blocofy theme pu
|
|
|
95
95
|
- `--instance <handle>` — push to a specific theme by its handle (safe targeted write — no
|
|
96
96
|
live-confirmation prompt).
|
|
97
97
|
- `--name <name>` — name the new draft (draft mode only; ignored on `--live`/`--instance`).
|
|
98
|
-
- `--dry-run` / `--validate` —
|
|
99
|
-
|
|
98
|
+
- `--dry-run` / `--validate` — check the push on the server without writing; the two flags are
|
|
99
|
+
aliases. The dry run covers exactly the files the push would send (remote-only files it keeps
|
|
100
|
+
included; with `--prune`, without the ones it would remove). A current platform plans the whole
|
|
101
|
+
deploy and prints the target, its pointer version and what happens to each file
|
|
102
|
+
(`+` created, `~` updated, `-` removed; unchanged files are counted).
|
|
100
103
|
- `--diff` — show what a push would change vs the target (read-only), then stop.
|
|
101
104
|
- `--idempotency-key <k>` — attach a key so a retried push is not double-applied.
|
|
102
105
|
- `--prune` — also remove target files that no longer exist locally (`locales/` included);
|
|
103
106
|
lists them first, and on the live theme asks to confirm (non-interactive shells add `--yes`).
|
|
104
107
|
|
|
105
|
-
|
|
106
|
-
|
|
108
|
+
Every push first runs that dry run, then writes the same files. On a current platform the write is
|
|
109
|
+
bound to the dry run: it is refused, with nothing written, if the files differ from what was checked
|
|
110
|
+
(`manifest_mismatch`), the target theme was deployed again in between (`pointer_version_conflict`),
|
|
111
|
+
or the push would now write to another theme than the one its dry run planned against — the live
|
|
112
|
+
theme was switched, or the draft to reuse changed (`target_changed`: nothing was deployed, though a
|
|
113
|
+
draft push may have created a new, empty draft that the next push reuses; run the push again).
|
|
114
|
+
A write that gets no answer (network error, 429/502/503/504) is resent (up to 3 times) under the same
|
|
115
|
+
key; a push the platform already committed is then reported as deployed (`already applied by an
|
|
116
|
+
earlier push with the same idempotency key`). If that resend is refused, the refusal cannot say
|
|
117
|
+
what the earlier attempt did: the message says whether it was committed or its outcome is
|
|
118
|
+
unknown (`details.earlierAttempt`), never "Nothing was written". Check the theme the dry run bound
|
|
119
|
+
the write to (`details.expectedTargetInstance`, not the current target a refusal names) with
|
|
120
|
+
`blocofy theme push --diff --instance <handle>` — or, for a new draft, find it with `blocofy status` —
|
|
121
|
+
before running the push again. A write whose last answer is still not definite (HTTP 500 or another
|
|
122
|
+
5xx, a 503, a 502 `readback_unverified` with `outcomeUnknown`, or no answer) has an unknown outcome
|
|
123
|
+
(`details.outcome: "unknown"`): the message names the push's key (`details.idempotencyKey`); run the
|
|
124
|
+
same command again with `--idempotency-key <that key>`, and a push that was deployed is reported as
|
|
125
|
+
deployed instead of being written again.
|
|
126
|
+
If the dry run would remove a file the push did not carry, the push stops
|
|
127
|
+
(`THEME_PUSH_TARGET_CHANGED`). The message says which case each file is:
|
|
128
|
+
- a path the push cannot send (not a file inside a theme folder, e.g. a bare `layout` row; listed in
|
|
129
|
+
`details.notCarryable`) stops every run the same way, and only `--prune` gets past it (it removes
|
|
130
|
+
the file);
|
|
131
|
+
- any other file was either added while the push was running, and running the push again keeps it,
|
|
132
|
+
or the push cannot read it (for example a theme file that is not published): then it stops every
|
|
133
|
+
run the same way, and you add `--prune` to remove it or add a local file at that path to replace it.
|
|
134
|
+
|
|
135
|
+
`Deployed atomically` is printed only when the server read the written files back and they match;
|
|
136
|
+
an older platform that does not read back gets `Deployed: … not verified`.
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
blocofy theme rename <handle> <new name> [--dir <dir>]
|
|
107
140
|
```
|
|
108
141
|
Rename a theme (the name is just a label). Works on any of your themes, including the live one.
|
|
142
|
+
- `--dir <dir>` — the bound project whose site the theme is on (default: cwd).
|
|
109
143
|
|
|
110
144
|
```
|
|
111
|
-
blocofy theme publish [--instance <handle>]
|
|
145
|
+
blocofy theme publish [dir] [--instance <handle>]
|
|
112
146
|
```
|
|
113
147
|
Publish a draft theme to the LIVE site: it replaces the live theme for every visitor. With no
|
|
114
148
|
flag, publishes the draft that `theme dev` / `theme push --draft` writes into. The server
|
|
115
|
-
refuses to publish a theme that has no pages (it would 404); preview first.
|
|
149
|
+
refuses to publish a theme that has no pages (it would 404); preview first. The site is the one
|
|
150
|
+
`[dir]`'s project is bound to (`dir` defaults to cwd), so `blocofy theme push ./shop && blocofy
|
|
151
|
+
theme publish ./shop` always publishes `./shop`'s site, whatever directory you run it from.
|
|
116
152
|
- `--instance <handle>` — publish a specific theme.
|
|
117
153
|
|
|
118
154
|
### Status
|
|
119
155
|
|
|
120
156
|
```
|
|
121
|
-
blocofy status
|
|
157
|
+
blocofy status [dir]
|
|
122
158
|
```
|
|
123
159
|
Show the live theme, page distribution per instance, drafts, and a health flag (`ok` /
|
|
124
160
|
`live_instance_empty` / `pages_split`). For a problem it names the theme holding the pages, the
|
|
@@ -172,14 +208,15 @@ exit 1. Files without `"locale"` use the site's default language (needs login);
|
|
|
172
208
|
outside a bound project only explicit `--context`/env credentials are used.
|
|
173
209
|
|
|
174
210
|
```
|
|
175
|
-
blocofy pages media-uses <page-handle> [--json]
|
|
211
|
+
blocofy pages media-uses <page-handle> [--dir <dir>] [--json]
|
|
176
212
|
```
|
|
177
213
|
List a page's localized-media decisions on its newest **draft** (v1 API, `pages:read`). Prints
|
|
178
|
-
the draft's revision id/version needed by `media-decide`.
|
|
214
|
+
the draft's revision id/version needed by `media-decide`. `--dir <dir>` (both media commands):
|
|
215
|
+
the bound project whose site the page is on (default: cwd).
|
|
179
216
|
|
|
180
217
|
```
|
|
181
218
|
blocofy pages media-decide <page-handle> --decisions <file.json>
|
|
182
|
-
[--expected-revision-id <n> --expected-version <n>] [--json]
|
|
219
|
+
[--expected-revision-id <n> --expected-version <n>] [--dir <dir>] [--json]
|
|
183
220
|
```
|
|
184
221
|
Apply one or more media decisions to the page's draft atomically (v1 API, `pages:write`). The
|
|
185
222
|
file is `{ "decisions": [ { path, facet, decision, target_asset?, alt?, caption?, decorative?,
|
|
@@ -189,6 +226,43 @@ get a random UUID. Transient failures (429/502/503/504, network) are retried aga
|
|
|
189
226
|
idempotency key, so a retry replays the same batch. Exit 0 on success (or "No changes" when
|
|
190
227
|
every item was already recorded).
|
|
191
228
|
|
|
229
|
+
### Translations
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
blocofy translations export --locale <tag> --out <file> [--force] [--format json|xliff] [--only all|missing|stale|pending] [--json]
|
|
233
|
+
blocofy translations import <file.json|file.xlf> [--dry-run] [--publish] [--on-source-change skip|apply] [--json]
|
|
234
|
+
```
|
|
235
|
+
`export` writes every text of one language that needs translating (pages, image texts, records,
|
|
236
|
+
menus, site settings, theme texts) to ONE file. The platform answers in windows; the command
|
|
237
|
+
follows every window until the last and merges them, then lists what was left out and why.
|
|
238
|
+
`--format xliff` writes XLIFF 1.2 for translation tools (the platform's own dialect, byte for
|
|
239
|
+
byte); `--only pending` limits the file to texts that are missing or need an update. The export
|
|
240
|
+
asks for every kind, so the API key needs the read scopes of all of them: `pages:read`,
|
|
241
|
+
`content:read`, `navigation:write` (menus have no read scope), `settings:read`, `themes:read` and
|
|
242
|
+
`models:read`; a key without one of them is refused for the whole export. An existing `--out` file
|
|
243
|
+
is never replaced silently: the command refuses before any request unless `--force` is given, and
|
|
244
|
+
the file is written through a temporary file and a rename.
|
|
245
|
+
|
|
246
|
+
`import` reads a JSON or XLIFF package, drops empty translations, and sends the rest as JSON in
|
|
247
|
+
chunks of at most 500 units (a page or record is never split; one group of up to 5,000 units is
|
|
248
|
+
sent whole). Every chunk is checked locally before the first request. It prints the count per
|
|
249
|
+
state (written, unchanged, empty, source changed, target changed, invalid, blocked). New pages and
|
|
250
|
+
records are created as drafts and page content goes to the draft; menus, site settings, theme texts,
|
|
251
|
+
a live record's text and a live page's title and SEO texts change at once (a live page's URL only
|
|
252
|
+
with `--publish`, once that page's publish succeeded). `--publish` also publishes the pages and records this
|
|
253
|
+
import wrote (needs `pages:write` and `content:write`) and reports what could not be published;
|
|
254
|
+
`--dry-run` writes nothing and reports what would change. The API key needs the write scopes of
|
|
255
|
+
the kinds in the package. A refusal (for example an invalid text) exits 2 with the server's error
|
|
256
|
+
JSON on stderr; if a later chunk fails, the chunks already written stay written, the report of
|
|
257
|
+
those chunks (counts, what was published or held back, a failed cache refresh) is printed before the
|
|
258
|
+
error (`--json`: one object with `"stopped": true` on stdout), and running the command again is safe
|
|
259
|
+
(written texts answer "unchanged"). Transient failures (429/502/503/504, network) are retried, except
|
|
260
|
+
for a chunk imported with `--publish`: a resend could not see what the first attempt already
|
|
261
|
+
published, so such a chunk is sent once. A 5xx or a lost connection stops the command with
|
|
262
|
+
`TRANSLATIONS_IMPORT_OUTCOME_UNKNOWN` (exit 1), naming the chunk that may or may not have been
|
|
263
|
+
applied and published; a 429 stops it with `TRANSLATIONS_IMPORT_NOT_APPLIED` (exit 1), since that
|
|
264
|
+
chunk was not applied.
|
|
265
|
+
|
|
192
266
|
### Settings
|
|
193
267
|
|
|
194
268
|
```
|
|
@@ -283,8 +357,28 @@ blocofy --help
|
|
|
283
357
|
|
|
284
358
|
## Contexts and project binding
|
|
285
359
|
|
|
286
|
-
|
|
287
|
-
|
|
360
|
+
A **context** is one named operator profile for one site. It references two **separate**
|
|
361
|
+
credentials, each kept in the secret store and never printed: the theme dev token (`bcf_…`,
|
|
362
|
+
verified with `GET /api/dev/whoami`) and the v1 API key (`blcf_live_…`, verified with
|
|
363
|
+
`GET /api/v1/ping`). They stay two credentials with their own scopes — the CLI never merges them
|
|
364
|
+
into one token and never sends one to the other's endpoint. Both pairs of a context must resolve
|
|
365
|
+
to the same site (`TARGET_CREDENTIAL_MISMATCH`); a secret of the wrong type in either slot is
|
|
366
|
+
refused before any request (`TARGET_CREDENTIAL_WRONG_TYPE`, exit 1 — e.g. a `blcf_live_…` key in
|
|
367
|
+
`BLOCOFY_TOKEN`).
|
|
368
|
+
|
|
369
|
+
Every remote command verifies its site first and prints a `Target` block on stderr (`--json`:
|
|
370
|
+
the same as a `{"target":…}` line with `platform_origin`, `context_source`,
|
|
371
|
+
`context_overrides`, `command` and `mode`):
|
|
372
|
+
|
|
373
|
+
```
|
|
374
|
+
Target: Alpha Bakery · s1a2b3 · alpha.myblocofy.com
|
|
375
|
+
Platform: https://app.blocofy.com
|
|
376
|
+
Context: alpha (from .blocofy/local.json)
|
|
377
|
+
Binding: .blocofy/project.json
|
|
378
|
+
Operation: theme push · draft
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
The context is chosen in this order:
|
|
288
382
|
|
|
289
383
|
1. `--context <name>`
|
|
290
384
|
2. `BLOCOFY_CONTEXT`
|
|
@@ -292,12 +386,32 @@ is chosen in this order:
|
|
|
292
386
|
4. `.blocofy/local.json` (the project's own context choice)
|
|
293
387
|
5. the one saved context matching the project's site
|
|
294
388
|
6. (terminal) pick from the matches
|
|
389
|
+
7. outside a project, and only for `status`, `target` and `pages check`: the `blocofy use` default
|
|
390
|
+
|
|
391
|
+
**Conflicts fail closed.** `BLOCOFY_CONTEXT`, the env credentials and `.blocofy/local.json` are
|
|
392
|
+
each a choice. When two of them name different contexts, the command is refused before
|
|
393
|
+
anything is read or written (`TARGET_CONTEXT_CONFLICT`, exit 3) — e.g. `BLOCOFY_URL`/
|
|
394
|
+
`BLOCOFY_TOKEN` exported in a shell that then runs inside a project whose `local.json` names a
|
|
395
|
+
context. Settle it with `--context <name>` (or unset the others); the `Context` line then lists
|
|
396
|
+
what it overrode, e.g. `alpha (from --context; overrides env credentials)`.
|
|
295
397
|
|
|
296
398
|
Inside a **bound project**, `blocofy use` is ignored — the project's binding decides, not the
|
|
297
|
-
global default context.
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
399
|
+
global default context. Outside one, the `use` default serves only `status`, `target` and
|
|
400
|
+
`pages check`, and the `Context` line says so (`from default context (blocofy use)`); every other
|
|
401
|
+
command in an unbound directory needs `--context`, `BLOCOFY_CONTEXT` or env credentials, so a
|
|
402
|
+
`use` in another terminal never changes what a diff, dry run or plan compares against. Commands
|
|
403
|
+
that change a site (`theme push`/`publish`/`rename`, `theme dev` sync, `pages push`, `settings
|
|
404
|
+
push`, `pages media-decide`) need a bound project; a pull into a new empty directory binds it
|
|
405
|
+
automatically. A wrong project/site pairing changes nothing (`TARGET_SITE_MISMATCH` — pass
|
|
406
|
+
`--adopt` on `link` to rebind deliberately).
|
|
407
|
+
|
|
408
|
+
Every command resolves its binding from the directory it acts on — the `[dir]` argument (or
|
|
409
|
+
`--dir <dir>` for `theme rename` and `pages media-uses|media-decide`), else cwd.
|
|
410
|
+
|
|
411
|
+
**CI:** commit `.blocofy/project.json` (never `local.json`) and set the env pairs the job needs
|
|
412
|
+
(`BLOCOFY_URL` + `BLOCOFY_TOKEN` for theme/pages/settings, plus `BLOCOFY_API_URL` +
|
|
413
|
+
`BLOCOFY_API_KEY` for the v1 commands and `site plan`/`apply`). The env credentials are then the
|
|
414
|
+
only choice, and each command still verifies they belong to the committed binding's site.
|
|
301
415
|
|
|
302
416
|
A binding made against an older server has no recorded `platform_origin`: it still matches the
|
|
303
417
|
same site (one warning printed; run `blocofy link --adopt` to record it). A server that reports
|
|
@@ -305,7 +419,8 @@ no origin cannot serve a binding that records one — that refuses with `TARGET_
|
|
|
305
419
|
server cannot prove it is the platform the binding was made against).
|
|
306
420
|
|
|
307
421
|
A refusal in this area (`TARGET_SITE_MISMATCH`, `TARGET_UNVERIFIED`, `TARGET_CREDENTIAL_MISMATCH`,
|
|
308
|
-
`TARGET_CONTEXT_REQUIRED`, `TARGET_CONTEXT_UNKNOWN`,
|
|
422
|
+
`TARGET_CONTEXT_CONFLICT`, `TARGET_CONTEXT_REQUIRED`, `TARGET_CONTEXT_UNKNOWN`,
|
|
423
|
+
`TARGET_BINDING_INVALID`, and `TARGET_CREDENTIAL_WRONG_TYPE` with exit 1) always means:
|
|
309
424
|
**nothing was read or written** — the command stops before it touches the site or the local
|
|
310
425
|
project files, and exits 3 (see [Exit codes](#exit-codes)).
|
|
311
426
|
|
|
@@ -328,11 +443,84 @@ line; the target block (`{"target":…}`) and any warning lines are printed on s
|
|
|
328
443
|
|
|
329
444
|
Retries: network errors and HTTP 429/502/503/504 are retried up to 3 times (`Retry-After`
|
|
330
445
|
honoured, max 30s per wait; else 0.3s/0.9s/2s), resending the identical request (`pages push`
|
|
331
|
-
carries one `x-idempotency-key` per push). HTTP 500 is never retried
|
|
332
|
-
on
|
|
446
|
+
carries one `x-idempotency-key` per push). HTTP 500 is never retried, nor is a `theme push` dry
|
|
447
|
+
run answered 502 `readback_unverified` (a verdict on a rolled-back plan, not a transient failure).
|
|
448
|
+
`translations import --publish` is never retried either: a resend could not see what the first
|
|
449
|
+
attempt already published, so a failed chunk stops the command with
|
|
450
|
+
`TRANSLATIONS_IMPORT_OUTCOME_UNKNOWN` (5xx, network) or `TRANSLATIONS_IMPORT_NOT_APPLIED` (429).
|
|
451
|
+
Each retry prints a notice on stderr.
|
|
333
452
|
|
|
334
453
|
## Changelog
|
|
335
454
|
|
|
455
|
+
- **0.12.0** — Translation packages (#925).
|
|
456
|
+
- `blocofy translations export --locale <tag> --out <file> [--format json|xliff] [--only …]`
|
|
457
|
+
writes every text of one language that needs translating to one JSON or XLIFF 1.2 file. It
|
|
458
|
+
follows every export window and lists what the platform left out, by reason.
|
|
459
|
+
- `blocofy translations import <file> [--dry-run] [--publish] [--on-source-change skip|apply]`
|
|
460
|
+
reads a JSON or XLIFF package and imports it in chunks of at most 500 units (a page or record
|
|
461
|
+
is never split, up to 5,000 units). It prints the count per state, what was published, and
|
|
462
|
+
whether the site cache could not be refreshed. A chunk imported with `--publish` is never
|
|
463
|
+
resent automatically: when it gets no definite answer the command stops with
|
|
464
|
+
`TRANSLATIONS_IMPORT_OUTCOME_UNKNOWN` (a 429: `TRANSLATIONS_IMPORT_NOT_APPLIED`), exit 1, names
|
|
465
|
+
the chunk, and running it again is safe. A run that stops part-way still prints the report of
|
|
466
|
+
the chunks done before it.
|
|
467
|
+
- `export` refuses an existing `--out` file unless `--force`.
|
|
468
|
+
- **0.11.0** — One named context per site, one explicit target (customer item 1.8).
|
|
469
|
+
The dev token and the v1 API key remain two separate credentials; a context references both.
|
|
470
|
+
- **Breaking:** conflicting context choices now fail closed. When `BLOCOFY_CONTEXT`, the env
|
|
471
|
+
credentials (`BLOCOFY_URL`/`BLOCOFY_TOKEN`, `BLOCOFY_API_URL`/`BLOCOFY_API_KEY`) and a
|
|
472
|
+
project's `.blocofy/local.json` name different contexts, the command stops with
|
|
473
|
+
`TARGET_CONTEXT_CONFLICT` (exit 3) instead of silently taking the first. A shell that exports
|
|
474
|
+
the env credentials inside a project with a `local.json` must pass `--context <name>` (or
|
|
475
|
+
unset them). An explicit `--context` still wins, and the target block lists what it overrode.
|
|
476
|
+
- **Breaking:** outside a bound project the `blocofy use` default is used only by `status`,
|
|
477
|
+
`target` and `pages check` (as contract C2 specified). `theme push --diff/--dry-run`,
|
|
478
|
+
`pages push --dry-run`, `site plan`, `theme dev --no-sync` and `pages media-uses` in an unbound
|
|
479
|
+
directory now need `--context`, `BLOCOFY_CONTEXT` or env credentials
|
|
480
|
+
(`TARGET_CONTEXT_REQUIRED`).
|
|
481
|
+
- The target block shows the platform the site was verified on and where the context choice
|
|
482
|
+
came from (`Platform:` line; `Context: <name> (from …)`); `--json` adds `platform_origin`,
|
|
483
|
+
`context_source`, `context_overrides`, `command` and `mode`.
|
|
484
|
+
- `theme publish [dir]` and `status [dir]` take the project directory as an argument, and
|
|
485
|
+
`theme rename` / `pages media-uses|media-decide` take `--dir <dir>`. Before, they always used
|
|
486
|
+
cwd, so `theme push ./a && theme publish` run from another project published that project's
|
|
487
|
+
draft. A directory that does not exist, or one given where the command takes none (a second
|
|
488
|
+
positional to `target`/`status`/`theme publish`, any directory positional to
|
|
489
|
+
`pages media-uses|media-decide`), is a usage error (exit 1) before any request.
|
|
490
|
+
- A secret of the wrong type (a `blcf_live_…` key as the dev token, a `bcf_…` token as the API
|
|
491
|
+
key) is refused before any request with `TARGET_CREDENTIAL_WRONG_TYPE`, naming the variable
|
|
492
|
+
or context — it was sent to the wrong endpoint and reported as `TARGET_UNVERIFIED`.
|
|
493
|
+
`login --token blcf_…` points at `login --api-key`.
|
|
494
|
+
- Theme push preflight bound to the write (customer item 6.5):
|
|
495
|
+
- `theme push` checks the MERGED payload (local files plus the remote-only files it keeps) in its
|
|
496
|
+
dry run, then writes exactly those files with the dry run's `manifestHash` and
|
|
497
|
+
`expectedPointerVersion`, and — when the platform names it — the theme the dry run planned
|
|
498
|
+
against (`expectedTargetInstance`; refused with `target_changed` if the target moved). The dry
|
|
499
|
+
run carries its own throwaway idempotency key, so
|
|
500
|
+
`--idempotency-key` retries of a committed push still converge.
|
|
501
|
+
- A write resent after an attempt without an answer is reported as deployed when the platform
|
|
502
|
+
had committed it. A refusal of such a resend says the earlier attempt's outcome is unknown (or
|
|
503
|
+
that it was committed) instead of "Nothing was written", and `details.earlierAttempt` names it.
|
|
504
|
+
- A write that gets no definite answer (a 5xx, a 503, `readback_unverified` with an unknown
|
|
505
|
+
outcome, or no answer after the resends) is reported as an unknown outcome, not a failure: the
|
|
506
|
+
message names this push's key, to run the same command again with `--idempotency-key <key>`
|
|
507
|
+
(the platform then reports the committed deploy instead of writing it again); `--json` details
|
|
508
|
+
carry `outcome: "unknown"` and `idempotencyKey`.
|
|
509
|
+
- A `target_changed` refusal names the theme the dry run planned against and the current target,
|
|
510
|
+
and says "Nothing was deployed" (a `--draft` push may have created a new, empty draft, which
|
|
511
|
+
the next push reuses). After a write's `readback_unverified` the CLI points at
|
|
512
|
+
`theme push --diff --instance <handle>` for the theme the write was bound to (or `blocofy status`
|
|
513
|
+
for a new draft), not at a plain `--diff`, which compares with the live theme only.
|
|
514
|
+
- Per-file outcomes are printed for the push and for `--dry-run`. `Deployed atomically` appears only
|
|
515
|
+
with a verified readback. New refusals with messages: `pointer_version_conflict`,
|
|
516
|
+
`site_state_version_conflict`, `manifest_mismatch`, `readback_unverified` (worded for the dry
|
|
517
|
+
run, where nothing was written, or for the write; `details.phase` says which) and the preflight path
|
|
518
|
+
errors (`path_too_long`, `reserved_path`, `binary_content_rejected`…, naming the file).
|
|
519
|
+
- A push stops with `THEME_PUSH_TARGET_CHANGED` when the dry run would remove a file the push did
|
|
520
|
+
not carry; the message says whether a re-run can keep it or only `--prune` gets past it, and
|
|
521
|
+
`details.notCarryable` lists the paths the push cannot send. `--prune` lists them for
|
|
522
|
+
confirmation instead. `--dry-run --prune` now plans the pruned set.
|
|
523
|
+
- Against an older platform the write body is unchanged from 0.10.
|
|
336
524
|
- **0.10.0** — Named contexts + verified project binding, and a declarative whole-site state.
|
|
337
525
|
- `login` now saves a **named context** (`--context <name>`, default the site's slug) instead
|
|
338
526
|
of one global credentials pair; `blocofy contexts` / `use` / `logout` manage them, and
|