fimo 0.10.1-staging.4 → 0.11.0-staging.2

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.
@@ -17,6 +17,10 @@ When you are about to do Fimo work:
17
17
  1. List what's available: `npx fimo@latest skills list`
18
18
  2. Load the relevant skill: `npx fimo@latest skills get <name>` (add `--ref <doc>` for a reference doc)
19
19
 
20
+ Reference paths mentioned in streamed skill output, such as `references/media.md`, are identifiers,
21
+ not files in the project. Load them through the CLI, for example
22
+ `npx fimo@latest skills get fimo-cli --ref media`. Do not use a filesystem read tool for them.
23
+
20
24
  Pick by task:
21
25
 
22
26
  - Writing code — schema-driven JSX, schemas/forms JSON, `t()` labels, `fimo/ui` media → `fimo-code`
@@ -73,7 +73,7 @@ something else (e.g. `handle`, `permalink`).
73
73
  | `reference` | `{ "id": "..." }`, `null`, or an array of reference objects when `many: true` | References to another schema |
74
74
  | `blocks` | ordered array of objects | Fixed groups, repeated sections, or selectable page blocks |
75
75
 
76
- A `date` field currently generates as `any` in the TS client, so for typed access (and the `<Date>` component) prefer a `string` field holding an ISO date — which is what the `publishDate` examples below do.
76
+ A `date` field generates as `string` in the TS client and wraps in `FimoString` at read time — the same source-tracked shape as `string`/`text` — so `<Date value={post.someDate} />` and plain string methods (`.slice()`, template literals, …) both work directly.
77
77
 
78
78
  ## Enumerated strings
79
79
 
@@ -167,6 +167,7 @@ A field may declare `showIf` (every clause must match) or `showIfAny` (one claus
167
167
  - `min` and `max` constrain the total number of blocks. Use `min: 1` to require at least one block; `required: true` has the same minimum-one behavior.
168
168
  - Fimo creates a stable `_key` for each item. A `oneOf` item also carries `_type`, matching the variant `uid`.
169
169
  - Nested fields support the same defaults and validators as top-level fields.
170
+ - **Each block item's own scalar fields wrap the same way their field type wraps at the top level** — a nested `string`/`text` field is a `FimoString`, a nested `richtext` field is a `FimoRichText`, a nested `media` field is a `FimoMedia`, a nested `boolean` is a `FimoBoolean`, a nested `date` is a `FimoString`, a nested `json` field is a shallow-cloned, source-tagged object, a nested `number` stays a plain `number`, and a nested `blocks` field recurses the same way. Pass those nested values to the matching `fimo/ui` component exactly like a top-level field — `<Text value={section.heading} />` or `<Json value={section.metadata} />` inside a `.map()` over `page.sections` stays inline-editable.
170
171
  - Blocks inherit the owning entry's locale.
171
172
  - Nested references use one fixed `target`. Unpopulated reads return `{ id, documentId }`, like top-level references.
172
173
  - Nested population and filtering are not supported yet.
@@ -516,22 +517,25 @@ Populate is depth-one. It only works for reference fields; trying to populate a
516
517
 
517
518
  The entry objects a hook returns are **not** plain JS values. The generated client wraps each _trackable_ field in a `fimo/ui` primitive that carries source metadata for inline editing. Which fields wrap, and which stay plain:
518
519
 
519
- | Schema field type | Field value you get | Notes |
520
- | ----------------- | ----------------------------------- | ------------------------------------------------------------------------------------- |
521
- | `string` | `FimoString` | `extends String` — **not** a primitive `string` |
522
- | `text` | `FimoString` | Multiline plain text with the same source tracking as `string` |
523
- | `richtext` | `FimoRichText` | Tiptap JSONContent + source metadata |
524
- | `boolean` | `FimoBoolean` | class; `.valueOf()` → `boolean` |
525
- | `media` | `FimoMedia` / `FimoMedia[]` | shape + rendering in `references/assets.md` |
526
- | `number` | `number` | plain — not wrapped |
527
- | `json` | `Record<string, any>` | plain — not wrapped |
528
- | `date` | `any` (raw ISO date string) | not wrapped (`FimoDate` is not emitted — see below) |
529
- | `reference` | `FimoReference` / `FimoReference[]` | reference object(s) with target `id`; use `populate` when embedded targets are needed |
520
+ | Schema field type | Field value you get | Notes |
521
+ | ----------------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
522
+ | `string` | `FimoString` | `extends String` — **not** a primitive `string` |
523
+ | `text` | `FimoString` | Multiline plain text with the same source tracking as `string` |
524
+ | `richtext` | `FimoRichText` | Tiptap JSONContent + source metadata |
525
+ | `boolean` | `FimoBoolean` | class; `.valueOf()` → `boolean` |
526
+ | `media` | `FimoMedia` / `FimoMedia[]` | shape + rendering in `references/assets.md` |
527
+ | `number` | `number` | plain — not wrapped. A wrapper would break `<span>{post.views}</span>` (React renders a boxed `String` directly but throws on a boxed `Number`), so it stays untracked and unclickable in the editing surfaces |
528
+ | `json` | `Record<string, any>` | the same shape you wrote, plus a hidden (non-enumerable, symbol-keyed) source tag — render with `<Json>`, see below |
529
+ | `date` | `FimoString` | same wrapper as `string`/`text`, **not** `FimoDate` — see below |
530
+ | `blocks` | array of plain objects | the array/objects themselves are plain; each item's own scalar fields are wrapped by their own field type (a nested `string` is still `FimoString`, a nested `number` stays a plain `number`, …) — see "Blocks" above |
531
+ | `reference` | `FimoReference` / `FimoReference[]` | reference object(s) with target `id`; use `populate` when embedded targets are needed |
530
532
 
531
533
  Rules of thumb:
532
534
 
533
- - **Pass the whole primitive to the matching `fimo/ui` component** — `<Text value={post.title} />`, `<Image value={post.cover} />`, `<RichText value={post.body} />`, `<Boolean value={p.inStock} />`. Don't unwrap first; the component reads the source metadata so the field stays inline-editable in the dashboard.
535
+ - **Pass the whole primitive to the matching `fimo/ui` component** — `<Text value={post.title} />`, `<Image value={post.cover} />`, `<RichText value={post.body} />`, `<Boolean value={p.inStock} />`, `<Date value={post.publishDate} />`, `<Json value={post.metadata} />`. Don't unwrap first; the component reads the source metadata so the field stays inline-editable in the dashboard.
534
536
  - **`FimoString extends String`**, so `typeof post.title === 'object'` and `post.title === 'Hi'` is `false`. It stringifies fine inside JSX and template literals; call `.toString()` only when something genuinely needs a primitive `string`.
537
+ - **`number` fields are the one scalar type left unwrapped** — `post.views` is a plain `number`, so `{post.views}` renders directly in JSX, `typeof`/`===`/arithmetic all behave normally, and there is no `<Number>` component. This is deliberate, not a gap: wrapping it would break direct JSX rendering in every existing site.
538
+ - **`json` fields are a shallow clone of what you wrote**, tagged with a hidden source symbol — not the original object, and not a class instance. Reading it behaves exactly like plain JSON (`JSON.stringify` round-trips it unchanged; `for...in`/`Object.keys` see only your own keys). Render it with `<Json value={post.metadata} />` (default renders as a `<span>`; pass `as="pre"` for a formatted block, or a children render function for specific keys) so it stays inline-editable and live-updates in the dashboard preview like every other field.
535
539
  - **Never hand-construct** a `FimoString` / `FimoMedia` / etc. — that bypasses source tracking. For a literal string use `t()`; for a literal image use `<StaticImage>`.
536
540
  - `t()` also returns a `FimoString` (see `references/labels.md`).
537
541
 
@@ -553,7 +557,7 @@ class FimoBoolean {
553
557
  }
554
558
  ```
555
559
 
556
- > **`FimoDate`:** exported from `fimo/ui` (it's the `<Date>` component's value type), but the generated schema client does **not** wrap `date` fields in it today — they arrive as a raw ISO string. `<Date value={post.someDate} />` accepts that at runtime either way.
560
+ > **`FimoDate`:** exported from `fimo/ui` (it's one of the `<Date>` component's accepted value types), but the generated schema client does **not** wrap `date` fields in it — a `date` field wraps as `FimoString` instead (see the table above), because the generated TypeScript type for a `date` field is `string`, and `FimoString` is what keeps that contract's string methods (`.slice()`, `.includes()`, …) working. `<Date value={post.someDate} />` accepts a `FimoString`, a `FimoDate`, a raw `Date`, or a raw string — all four render correctly.
557
561
 
558
562
  ## UI code pattern
559
563
 
@@ -579,7 +583,7 @@ export function BlogList() {
579
583
  }
580
584
  ```
581
585
 
582
- For the `<Text>` / `<RichText>` / `<Image>` / `<Date>` components and the rules of thumb, see `references/ui.md`.
586
+ For the `<Text>` / `<RichText>` / `<Image>` / `<Date>` / `<Json>` components and the rules of thumb, see `references/ui.md`.
583
587
 
584
588
  ## Read path (published app, no auth)
585
589
 
@@ -17,6 +17,7 @@ Use these to render content-type field values consistently. They carry source me
17
17
  | `<Video>` | Schema `media` video fields | `<Video value={post.heroVideo} />` |
18
18
  | `<Date>` | Schema date fields | `<Date value={post.publishDate} />` |
19
19
  | `<Boolean>` | Schema boolean fields | `<Boolean value={product.inStock} />` |
20
+ | `<Json>` | Schema `json` fields | `<Json value={post.metadata} as="pre" />` |
20
21
  | `` fimo`...` `` | Compose tracked values (mix `t()` + schema text) | ``<Text value={fimo`${t('by')} ${post.author}`} />`` |
21
22
  | `useLabels()` | `t('key')` hook | see `references/labels.md` |
22
23
  | `useLocale()` | Active locale and route locale metadata | see `references/locales.md` |
@@ -29,6 +30,7 @@ Use these to render content-type field values consistently. They carry source me
29
30
  4. **Label text → `<Text value={t('key')} />`**, not `<h1>{t(...)}</h1>`. Label values live in the DB for `i18n.defaultLocale` from `fimo-config.json` unless a non-default locale is explicitly targeted. See `references/labels.md`.
30
31
  5. **Mixed schema + translated text** → the `` fimo`...` `` template literal inside `<Text>`.
31
32
  6. **Never hand-roll richtext rendering** — always `<RichText>`. To restyle a node, pass `components={{ heading: ..., link: ..., ... }}`.
33
+ 7. **Schema `json` → `<Json>`**, not a hand-rolled `<pre data-fimo-source={getFimoSource(post.metadata)}>{JSON.stringify(post.metadata)}</pre>`. Default renders as a `<span>`; pass `as="pre"` (with a `whitespace-pre-wrap` class) for a formatted block, or a children render function for custom display of specific keys.
32
34
 
33
35
  ## App code conventions
34
36
 
@@ -78,6 +80,7 @@ The template uses **Vite + React 19 + TypeScript + Tailwind v4 + shadcn/ui + rea
78
80
 
79
81
  - Raw `<a href>` for internal nav → use `<FimoLink>` for locale-aware paths or React Router `<Link>` / `<NavLink>` only when intentionally bypassing Fimo locale helpers.
80
82
  - Raw `<img>` for schema media → use `<Image>` (with width/height).
83
+ - Raw `<pre data-fimo-source={getFimoSource(...)}>` for schema `json` fields → use `<Json>`.
81
84
  - Hardcoded strings in JSX → wrap in `t('key')` and add the DB value with `fimo labels set`.
82
85
  - Calling `t()` with a dynamic first argument → key must be a string literal.
83
86
  - Editing generated `.ts` files under `src/schemas/` or `src/forms/` → regenerate them through `fimo validate` or the matching push command.
@@ -33,6 +33,14 @@ To halt the AI mid-generation, use the **Stop button** in the input bar — whil
33
33
 
34
34
  While the AI works, you see small badges in the chat showing what it is doing. Each badge displays a tool name and its current status. Examples include reading files, writing code, searching your project, or generating images. These badges help you follow along without needing to understand the technical details.
35
35
 
36
+ ## Reviewing Changes That Could Not Merge
37
+
38
+ Chat changes are prepared separately and then applied to the environment you are viewing. Most changes merge automatically.
39
+
40
+ If the project changed in the same place while the AI was working, the response shows a **Review changes** card instead. Open it to inspect the proposal, resolve any conflicts, and merge when it is ready. Until you merge it, the proposal is not part of the environment and later chat messages will not see it.
41
+
42
+ Discarding the merge leaves the current environment unchanged and keeps the proposal separate.
43
+
36
44
  ## Tips for Better Results
37
45
 
38
46
  - **Be specific**: Mention colors, layout, text content, and spacing when you can.
@@ -16,6 +16,12 @@ To push your latest changes live, open the publish panel from the header **Publi
16
16
 
17
17
  > **Tip:** Before your site has ever been published, the chat shows a one-click **Publish** button that deploys immediately without opening the panel.
18
18
 
19
+ ## Publishing Changes That Need Review
20
+
21
+ If an AI chat change cannot merge automatically, use the response's **Review changes** card first. Resolve the conflicts and merge the proposal into `main`.
22
+
23
+ When the AI requested publication, the review dialog offers **Merge and publish** after the conflicts are resolved. Publishing starts only after the merge succeeds, so unresolved or discarded proposals never reach the live site.
24
+
19
25
  ## What You See When You Click Publish
20
26
 
21
27
  The header **Publish** button itself only shows the label "Publish" (or a spinner while a deploy is running). Open the panel to see the current state:
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "bundled": true,
3
3
  "bundler": "esbuild",
4
- "bundledAt": "2026-07-28T17:34:40.817Z",
4
+ "bundledAt": "2026-07-30T16:52:56.741Z",
5
5
  "cliVersion": "0.10.0",
6
6
  "external": [
7
7
  "oxc-parser",