figura-cli 0.19.0 → 0.21.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "figura-cli",
3
- "version": "0.19.0",
3
+ "version": "0.21.0",
4
4
  "description": "Command-line client for the Figura visualization SaaS",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -36,6 +36,7 @@
36
36
  "@panofm/figura-core": "workspace:*",
37
37
  "@types/node": "^20.14.0",
38
38
  "axios": "^1.7.9",
39
+ "package-manager-detector": "^1.8.0",
39
40
  "postgres": "^3.4.9",
40
41
  "typescript": "^5.5.0"
41
42
  }
@@ -101,6 +101,9 @@ so you hand it the studied structure in the brief (see step 3, "Server render").
101
101
  wrong tenant). Tell the user to run `figura link` in this repo, then
102
102
  re-verify. If the response has no `binding` field (older CLI/MCP), confirm
103
103
  the team slug matches this project with the user before proceeding.
104
+ - **Update notice?** If the whoami response carries a `notice` field, relay it
105
+ to the user verbatim (a one-line "figura-mcp is behind / below min — run …"),
106
+ then proceed. It's a passive nudge, shown once per session — never a blocker.
104
107
 
105
108
  2. **Default — build it yourself, with YOUR Claude.** Fetch the **canonical
106
109
  authoring scaffold** — **`figura_fig_scaffold`** (CLI:
@@ -171,7 +174,11 @@ so you hand it the studied structure in the brief (see step 3, "Server render").
171
174
  change). If you truly couldn't locate the source, say so in the brief and label
172
175
  the baseline an approximation, same as the hand-build fallback.
173
176
 
174
- 4. **Open the HOSTED fig for approval — never a local file.** Run
177
+ 4. **Verify, then open the HOSTED fig for approval — never a local file.** First
178
+ run **`figura fig verify <id>`**: the component CSS is stamped server-side, so
179
+ only the served bytes can tell a working fig from one that renders as empty
180
+ phones. It exits non-zero if a frame class shipped unsized — fix and re-land
181
+ before a human sees it. Then run
175
182
  `figura fig open <id>` (the id `figura_create_fig`/`figura_generate_fig` just
176
183
  returned). It opens **`viewUrl`** in the reviewer's browser — the actual
177
184
  Figura render (brand chrome, CSP, favicon, responsive frame), team-scoped so
@@ -227,7 +234,10 @@ truncation, and doesn't need a library):
227
234
  status chip and ONE condensed context line (`+ / –`). This view is for
228
235
  scanning and picking a direction, not for reading detail. The grid must
229
236
  wrap to one column before it can overflow — **a fig never scrolls
230
- horizontally**, at any viewport.
237
+ horizontally**, at any viewport. To shrink the framed phones, wrap each in the
238
+ kit's **`.fig-mini`** wrapper (see "Scaling a framed device" below), never a
239
+ rule on `.fig-device` and never CSS `zoom` (zoom leaks an unzoomed
240
+ `scrollWidth` into horizontal overflow — the exact thing this view forbids).
231
241
  - **Focus — full frame.** One state at a time behind state pills (Today / A /
232
242
  B / …), each state framed identically so flipping states in place reads as
233
243
  spot-the-difference. This is where the context lives, pinned on the frame
@@ -242,20 +252,30 @@ truncation, and doesn't need a library):
242
252
  arguing the pick against the others. Keep the chrome around the frames
243
253
  minimal — the frames are the content; no legends (chips label themselves),
244
254
  no repeated context, fluid `max-width` layout throughout.
245
- - **Verify before publishing.** Render the fig headless at a few viewport
246
- widths: `document.scrollWidth` must equal the viewport in every view and
247
- state (sideways scroll = broken beware CSS `zoom`, which leaks unzoomed
248
- width into scrollable overflow; scale minis with `transform` in
249
- fixed-aspect wrappers instead), and screenshot each state to check no
250
- annotation chip covers the content it annotates.
251
- When you write the fig's HTML out to render/screenshot it, save it to a
252
- **deterministic**, project-scoped path the repo's `.figura/figs/` (already
253
- gitignored), or `~/.figura/figs/` outside a bound repo — never `/tmp` or
254
- `mktemp`. A stable path means a rerun overwrites the same file instead of
255
- littering volatile temp locations, and matches where `figura fig open --local`
256
- writes (`<repo>/.figura/figs/figura-fig-<id>.html`) this is YOUR headless
257
- self-check copy, separate from the hosted `viewUrl` a human reviewer opens
258
- (step 4 above).
255
+ - **Verify the SERVED fig, not your local draft.** The component kit (device
256
+ frame, status bar, control bar) is stamped **server-side at save** — it does
257
+ **not** exist in the HTML you authored locally, so a headless render of your
258
+ own file shows *unstyled, empty* frames whether or not the fig is actually
259
+ correct. A local screenshot is structurally blind to the most common way a
260
+ framed fig breaks. So verify the fig that actually ships:
261
+ 1. **Land it first** (`figura_create_fig` / `figura_revise_fig`), then dump
262
+ the stamped bytes: `figura fig open <id> --local --print`. This is the
263
+ served document, kit and all.
264
+ 2. **Assert the kit stamped `figura fig verify <id>`.** One command, and it
265
+ **exits non-zero** if any frame class your markup uses shipped with no CSS
266
+ giving it dimensions. It checks every injected component (device frame,
267
+ status bar, control bar, browser chrome), cross-checks the manifest's
268
+ `components` array, and reports the fig's own `frameKit` / `complete` /
269
+ `doubleFramed` checks; `--json` for machine output. The engine won't
270
+ silently drop the kit anymore, and create/revise now warns loudly if it
271
+ ever did — this is the check that *proves* a frame renders.
272
+ 3. **Screenshot THAT** (the printed served HTML, saved to a deterministic
273
+ project-scoped path — the repo's `.figura/figs/` (gitignored), or
274
+ `~/.figura/figs/` outside a bound repo, never `/tmp`/`mktemp`), at a few
275
+ viewport widths: `document.scrollWidth` must equal the viewport in every
276
+ view and state (sideways scroll = broken), and no annotation chip may
277
+ cover the content it annotates. `figura fig open <id> --local` writes the
278
+ same served bytes to `<repo>/.figura/figs/figura-fig-<id>.html`.
259
279
 
260
280
  A **wipe-slider** stays the narrow tool for exactly two states of the same
261
281
  layout with pixel-level tweaks. Never ship a squeezed side-by-side as the
@@ -320,10 +340,32 @@ So when you **hand-build** a fig (the default path), you do your part of the
320
340
  contract — but the exact rules are **fetched, not restated here**: the
321
341
  presentation model (frameless single vs canvas composition), when to emit or
322
342
  omit the whole-fig `<meta name="figura:artboard">`, the `.fig-device` /
323
- `data-device` frame markup (and NOT authoring its CSS — Figura stamps the bezel,
324
- Dynamic Island, and safe-area insets), the `figura:context` / `figura:feature`
343
+ `data-device` frame markup (Figura stamps the bezel, Dynamic Island, and
344
+ safe-area insets **before** your `<style>`, so you normally leave those classes
345
+ alone — if you do style one, your rule wins by cascade and the frame still
346
+ works; to shrink a frame use the `.fig-mini` wrapper, never a hand-written
347
+ `.fig-device` width/height/transform), the `figura:context` / `figura:feature`
325
348
  metas, and the valid devices all live in the canonical scaffold.
326
349
 
350
+ **Scaling a framed device — use `.fig-mini`, never a rule on `.fig-device`.**
351
+ An overview grid needs shrunken frames, and the obvious way to write that is a
352
+ CSS rule on the injected class. Don't: your rule wins over the kit, so the frame
353
+ stops matching real device geometry — and `zoom` is worse, it leaks the unzoomed
354
+ width into scrollable overflow. The kit ships the wrapper instead:
355
+
356
+ ```html
357
+ <div class="fig-mini" style="--fig-scale:.34">
358
+ <div class="fig-device portrait" data-device="iphone-16">
359
+ <div class="fig-screen">…</div><div class="fig-di"></div><div class="fig-homebar"></div>
360
+ </div>
361
+ </div>
362
+ ```
363
+
364
+ `.fig-mini` scales its device with `transform` and takes the **scaled** layout
365
+ box, so a row of minis lays out at its visual size instead of reserving
366
+ full-size phones. Add `landscape` to the device (or the wrapper) and the box
367
+ flips with it. `--fig-scale` defaults to `.34`; set it per element.
368
+
327
369
  - **`figura_fig_scaffold`** (CLI: `figura fig scaffold`) is authoritative for the
328
370
  presentation model, the frame markup, and the output contract. Fetch it and
329
371
  follow it verbatim (step 2 above) — do NOT restate design/format rules from