fimo 2.9.0 → 2.10.0-staging.10

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.
Files changed (40) hide show
  1. package/README.md +9 -0
  2. package/assets/skills/fimo/SKILL.md +2 -2
  3. package/assets/skills/fimo-cli/SKILL.md +3 -4
  4. package/assets/skills/fimo-cli/references/account.md +2 -0
  5. package/assets/skills/fimo-cli/references/agent-setup.md +1 -1
  6. package/assets/skills/fimo-cli/references/assets.md +2 -0
  7. package/assets/skills/fimo-cli/references/branches.md +10 -2
  8. package/assets/skills/fimo-cli/references/content.md +11 -1
  9. package/assets/skills/fimo-cli/references/deploy.md +1 -26
  10. package/assets/skills/fimo-cli/references/domains.md +4 -4
  11. package/assets/skills/fimo-cli/references/history.md +1 -1
  12. package/assets/skills/fimo-cli/references/init.md +22 -18
  13. package/assets/skills/fimo-cli/references/integrations.md +50 -71
  14. package/assets/skills/fimo-cli/references/mcp.md +3 -10
  15. package/assets/skills/fimo-cli/references/project-vars-and-secrets.md +19 -3
  16. package/assets/skills/fimo-cli/references/site-checks.md +38 -0
  17. package/assets/skills/fimo-code/references/content/richtext.md +2 -2
  18. package/assets/skills/fimo-migration/SKILL.md +73 -59
  19. package/assets/skills/fimo-migration/references/import-contract.md +1 -1
  20. package/assets/skills/fimo-migration/references/qa.md +14 -3
  21. package/assets/skills/fimo-migration/references/workers/content-planner.md +4 -1
  22. package/assets/skills/fimo-migration/references/workers/validator.md +4 -3
  23. package/assets/skills/fimo-migration/references/workers.md +2 -2
  24. package/assets/skills/fimo-migration/references/workflow.md +14 -24
  25. package/assets/skills/fimo-migration/scripts/check-rendered-guardrails.mjs +102 -1
  26. package/assets/skills/fimo-studio/SKILL.md +3 -3
  27. package/assets/skills/fimo-studio/references/ai-chat.md +5 -5
  28. package/assets/skills/fimo-studio/references/billing-and-credits.md +20 -11
  29. package/assets/skills/fimo-studio/references/integrations.md +105 -0
  30. package/assets/skills/fimo-studio/references/project-creation.md +4 -4
  31. package/dist/cli/bundle.json +1 -1
  32. package/dist/cli/index.js +340 -318
  33. package/package.json +12 -12
  34. package/release.json +2 -2
  35. package/templates/astro/package.json +3 -3
  36. package/templates/nextjs/package.json +4 -4
  37. package/templates/react-router/package.json +5 -5
  38. package/templates/sveltekit/package.json +3 -3
  39. package/templates/vite/package.json +5 -5
  40. package/assets/skills/fimo-studio/references/connections.md +0 -51
@@ -24,6 +24,9 @@ URL can describe the live version, but one synthetic run is not field data.
24
24
 
25
25
  Inspect the available tools and skills before choosing a method.
26
26
 
27
+ - For SEO, links, images, structured data or AI readiness, start with
28
+ `fimo site check` (below): it picks the target and reports findings.
29
+
27
30
  - If `agent-browser` is available, load its skill and version-matched `core`
28
31
  guidance before using it.
29
32
  - Otherwise use equivalent browser automation, accessibility, HTTP, network,
@@ -35,6 +38,41 @@ Inspect the available tools and skills before choosing a method.
35
38
  own guidance and name the target. If it does not, report that limitation and
36
39
  use only measurements that can actually run.
37
40
 
41
+ ## Check pages with `fimo site check`
42
+
43
+ `fimo site check` reads pages of the current Branch's hosted preview over HTTP
44
+ and reports findings by topic. Name the pages a change touches, or pass `--all`
45
+ for the whole site: the home page, the sitemap, llms.txt and every page they
46
+ link to, at most 300 pages.
47
+
48
+ ```bash
49
+ fimo site check / /pricing --json # named pages, every topic
50
+ fimo site check /blog/my-post --topic meta-tags # one topic
51
+ fimo site check --all --branch main # every page of main's hosted preview
52
+ fimo site check /about --browser --topic accessibility,mobile
53
+ fimo site check / --url http://localhost:3000 # another address, such as your dev server
54
+ fimo site links /pricing # each link on the page and its target's status
55
+ ```
56
+
57
+ - Name at most 50 pages per run. Paths, bare names and full URLs all work.
58
+ - Topics: `technical`, `meta-tags`, `broken-links`, `image-seo`,
59
+ `internal-linking`, `hreflang`, `ai-readiness`, `structured-data`,
60
+ `citation`, `lifecycle`, `refresh`, `accessibility`, `mobile`, `consent`,
61
+ `privacy`. Without `--topic`, every topic runs.
62
+ - `--browser` renders every page in a real browser (needs `agent-browser`).
63
+ Use it for `accessibility`, `mobile`, `consent` and `privacy`; the other
64
+ topics read HTML. A page whose HTML has no content before JavaScript runs (a
65
+ client-rendered site) is read in the browser without `--browser`; the output
66
+ says how many.
67
+ - The target is the Branch's hosted preview. While it builds, the command
68
+ waits up to 90 seconds. `prod` has no preview: check `--branch main`, or the
69
+ published address with `--url`.
70
+ - Findings that compare pages (shared titles, title shape, pages nothing links
71
+ to, pages missing from the sitemap) need `--all`.
72
+ - Each finding is `auto` (one right fix), `suggest` (a person decides) or
73
+ `note`. Read `data.output` in `--json` mode. Lines marked "could not tell"
74
+ are not clean: say what could not be checked.
75
+
38
76
  ## 3. Pick the lens the question needs
39
77
 
40
78
  | The user asks | Evidence to obtain |
@@ -33,7 +33,7 @@ generated client hydration helper where required.
33
33
 
34
34
  ## Entry payload
35
35
 
36
- CLI entry writes put every value, including the collection slug, under `data`:
36
+ `entries create` and `entries update` take `--body` with every field, including the collection slug, under `data`:
37
37
 
38
38
  ```json
39
39
  {
@@ -46,7 +46,7 @@ CLI entry writes put every value, including the collection slug, under `data`:
46
46
  }
47
47
  ```
48
48
 
49
- Do not put `slug` at the top level; unsupported top-level keys are stripped.
49
+ Keep `slug` inside `data`; `entries create` rejects unsupported top-level keys.
50
50
 
51
51
  Slugs should be lowercase, hyphenated, stable, meaningful, and unique per content type. Fimo slugifies the supplied candidate. If omitted, Fimo generates one, which is unsuitable for content with durable public URLs.
52
52
 
@@ -20,11 +20,11 @@ into a real Fimo project without silently dropping source material.
20
20
  > supports the source framework, preserve it explicitly and verify the runtime
21
21
  > before importing data.
22
22
  >
23
- > Use the CLI invocation selected for this flow for every `fimo` command in the migration. Otherwise use `npx fimo@latest`; do not install it globally.
23
+ > Use the pinned CLI invocation selected for this flow for every `fimo` command in the migration (see CLI provenance); do not install it globally.
24
24
 
25
25
  The first pass is a faithful migration, not a framework conversion. Detect the
26
- source framework before creating the target and pass it explicitly to
27
- `fimo migrate init`. For a Next.js source, use `--framework nextjs`; never rely
26
+ source framework before setup. When `fimo migrate init` creates the target, pass
27
+ it explicitly: for a Next.js source, use `--framework nextjs`; never rely
28
28
  on the React Router default. The setup receipt must report the target runtime
29
29
  framework, and a mismatch is a setup failure before any schemas, entries,
30
30
  assets, labels, or forms are imported.
@@ -90,30 +90,43 @@ artifact, and record which one.
90
90
 
91
91
  ## Initialized target precondition
92
92
 
93
- Before workers start, the root process must establish a real Fimo project and
94
- environment, link the migration checkout to it, and prove the data plane is
95
- reachable with a read such as `fimo schemas list -C <target> --branch <branch>` using
96
- the selected pinned CLI. Give workers the project id, environment, exact CLI
97
- invocation, and verification command. Generated `.fimo` JSON without a
98
- successful platform read is not initialization.
99
-
100
- Pick the setup path from the evidence:
101
-
102
- - **Source-backed, same framework** — copy or `git worktree` the source into the
103
- target directory first, then run `fimo link -C <target> --branch <branch>`
104
- (`fimo link <project-id> -C <target> --branch <branch>` when the owner supplied an
105
- id). Link creates or selects the project, keeps the source's code, framework,
106
- git history, and `origin`, initializes a repository when the copy has none,
107
- and adds only the Fimo dependency, `.fimo/project.json`, the `fimo` remote,
108
- and `.fimo/config.json#runtime.framework`. It never overlays a template, so
109
- the target must already contain the source.
110
- - **Empty target, or an explicit framework conversion** — `fimo init` or
111
- `fimo migrate init <dir>` with the chosen `--framework`. Both refuse a
112
- non-empty target and write nothing when they refuse.
113
-
114
- If authentication, organization selection, project creation, environment
115
- resolution, linking, or the verification read fails, stop before workers and
116
- report the exact failed command and setup requirement.
93
+ This is the one setup decision; every other reference points here. Pick the
94
+ row that matches the user's request and the folder's state. When the target is
95
+ genuinely unclear, ask once in the preflight question batch.
96
+
97
+ | Starting point | Setup | Original evidence |
98
+ | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
99
+ | The user asked to put this existing folder on Fimo; it is already linked | Reuse it. Verify its project, branch, and framework. Run `fimo link <same-id> -C <folder>` only to repair it. | Keep the baseline below. |
100
+ | The same, but the folder is not linked | Keep the baseline, then run `fimo link -C <folder> --branch <branch>`, with the project id when one was chosen. | Keep the baseline below. Never reset, overwrite, or discard existing work. |
101
+ | The source is read-only input, or the user asked for a separate target; same framework | Copy or clone the source into the target first. If the copy kept a `.fimo/project.json`, reuse that project or resolve it on purpose. Then run `fimo link -C <target> --branch <branch>`. | The original stays read-only. A `git worktree` shares the repository's config and remotes: use an independent copy or clone when adding the `fimo` remote must not touch the original. |
102
+ | An empty or new target with nothing to adopt, or an explicit framework conversion | `fimo migrate init <target> --framework <chosen>` (see Target setup). Never overlay a template on populated source. | The source repository or export stays separate. |
103
+
104
+ The baseline is an exact copy of the folder's pre-migration state, kept outside
105
+ the folder. A commit plus a detached worktree is enough only when the tree is
106
+ clean; otherwise also keep the dirty and untracked files. Never copy secret
107
+ values into evidence.
108
+
109
+ `fimo link` keeps the folder's code, framework, git history, branches, and
110
+ `origin`, initializes a repository when there is none, and adds only the Fimo
111
+ dependency, `.fimo/project.json`, the `fimo` remote, and
112
+ `.fimo/config.json#runtime.framework`. It never overlays a template.
113
+
114
+ Never invent a project or organization id, and never silently relink a folder
115
+ to another project (`fimo link --relink` needs the owner's explicit choice).
116
+ In a non-interactive shell, `fimo link` on an unlinked folder without an id,
117
+ and `fimo migrate init` without `--project-id`, create a new project in the
118
+ active organization, else the only one; `fimo migrate init` also takes `--org`. With several organizations and none
119
+ active, the CLI fails clearly: ask the user which one. Ask only for a selection
120
+ the CLI cannot resolve.
121
+
122
+ Every row ends at the same gate. Before workers start, prove the actual project
123
+ id and branch, a runtime framework that matches the source or the chosen
124
+ conversion, the selected pinned CLI, and a successful data-plane read such as
125
+ `fimo schemas list -C <target> --branch <branch>`. A local marker, generated
126
+ `.fimo` JSON, or a `ready: true` receipt without that read is not
127
+ initialization. Give workers the project id, branch, exact CLI invocation, and
128
+ verification command. If any setup step fails, stop before workers and report
129
+ the exact failed command and setup requirement.
117
130
 
118
131
  ## Core contract
119
132
 
@@ -135,7 +148,9 @@ report the exact failed command and setup requirement.
135
148
  ports the source's APIs, loaders, hardcoded content, integrations, and
136
149
  visible behavior into the new framework unchanged, and Fimo schemas,
137
150
  payloads, imports, and code wiring happen later through the content workers
138
- (`references/workers/content-execution.md`). If the framework or hosting
151
+ (`references/workers/content-execution.md`). That content pass is part of the
152
+ migration, never a follow-up: the `editable-text` guardrail
153
+ (`references/qa.md`) fails while visible text is still typed in the code. If the framework or hosting
139
154
  setup is unclear or unsupported, stop and ask instead of guessing,
140
155
  converting it, or deleting provider-specific files.
141
156
  - Inventory provider-specific files and rules before editing them. Classify each
@@ -247,25 +262,24 @@ report the exact failed command and setup requirement.
247
262
 
248
263
  ## Target setup
249
264
 
250
- The target is its own Fimo project directory. The client source checkout is
251
- read-only evidence: never run setup inside it, never modify it, and never
252
- hand-write a `.fimo/project.json` marker to fake a link.
253
-
254
- `fimo migrate init` is the setup gate for an empty target; a target that
255
- already holds the copied source is set up with `fimo link` instead (see
256
- Initialized target precondition). `fimo migrate init` validates the target and
257
- CLI auth, then delegates project selection and creation to the standard
258
- `fimo init` flow (same options, no separate creation path), and returns a setup
259
- receipt covering auth, the target link, the migration directory, and readiness.
260
- It fails with a structured error when auth is missing, the target is missing or
261
- invalid, or the project or organization is inaccessible. Both forms need a real
262
- ID supplied by the owner — without one, stop with an unresolved owner action
263
- instead of inventing an ID:
264
-
265
- - Link an owner-supplied (empty) project:
265
+ Choose the setup row in "Initialized target precondition". Never modify an
266
+ original that the row keeps read-only, and never hand-write a
267
+ `.fimo/project.json` marker to fake a link.
268
+
269
+ `fimo migrate init` serves the empty-target and conversion row. It validates
270
+ the target and CLI auth, then delegates project selection and creation to the
271
+ standard `fimo init` flow (same options, no separate creation path), and
272
+ returns a setup receipt covering auth, the target link, the migration
273
+ directory, and readiness. It fails with a structured error when auth is
274
+ missing, the target is missing or invalid, the target is populated but not
275
+ linked, or the project or organization is inaccessible:
276
+
277
+ - Use an existing (empty) project:
266
278
  `fimo migrate init <target-dir> --project-id <projectId> --framework <framework> --source-platform <platform>`
267
- - Create a new project in an owner-supplied organization:
268
- `fimo migrate init <target-dir> --org <organizationId> --framework <framework> --source-platform <platform>`
279
+ - Create a new project:
280
+ `fimo migrate init <target-dir> --framework <framework> --source-platform <platform>`,
281
+ adding `--org <organizationId>` when the precondition's organization rule
282
+ needs it.
269
283
 
270
284
  `--source-platform` names what the site is migrated from (`wordpress`, `nextjs`,
271
285
  `astro`, `react-router`, `webflow`, `framer`, `squarespace`, `wix`, `carrd`,
@@ -277,9 +291,11 @@ framework files before starting workers. A Next.js target must still have its
277
291
  Next runtime/configuration (`next.config.*` and the source router shape), not a
278
292
  React Router scaffold.
279
293
 
280
- Setup scaffolds the target and pushes its initial commit; that is the only
281
- remote write it performs — it never pushes schemas, uploads assets, or imports
282
- entries. Setup itself never deploys or publishes; the one new-project preview
294
+ `fimo migrate init` on a new target scaffolds it and pushes its initial
295
+ commit. `fimo link` and reusing a linked folder scaffold and push nothing; the
296
+ first commit waits for `fimo deploy`. Project creation or linking and that
297
+ initial push are the only remote writes setup performs — it never pushes
298
+ schemas, uploads assets, or imports entries. Setup itself never deploys or publishes; the one new-project preview
283
299
  deploy happens only after successful local QA (see Completion and deployment).
284
300
 
285
301
  ## Command surface
@@ -289,20 +305,18 @@ up and nothing else: it never reads, fetches, or renders the source site, and
289
305
  it produces no evidence pack, draft, manifest, or scaffold to inspect. Reading
290
306
  the source is your job, and every finding is yours to prove.
291
307
 
292
- - `fimo migrate init <dir> --project-id <projectId>` — link an owner-supplied
293
- project.
294
- - `fimo migrate init <dir> --org <organizationId>` — create a new project.
308
+ - `fimo migrate init <dir> --project-id <projectId>` — use an existing project.
309
+ - `fimo migrate init <dir> [--org <organizationId>]` — create a new project.
295
310
  - Both accept `--framework`, `--source-platform` (see Target setup),
296
311
  `--install` / `--no-install`, `--agents` / `-a`, `--mode`, `--template-root`,
297
312
  and `--json`; `-C <dir>` replaces the positional for an already-linked target.
298
313
 
299
- The link/creation and its initial commit push are the only remote writes. Data
300
- writes go through the normal commands against the linked target:
314
+ Setup (`fimo migrate init` or `fimo link`, chosen in Initialized target
315
+ precondition) makes only the remote writes listed in Target setup. Data writes
316
+ go through the normal commands against the linked target:
301
317
 
302
318
  - `fimo schemas push`, `fimo assets upload`, `fimo entries create|update`,
303
319
  `fimo singles update`, `fimo labels set|set-many`, `fimo forms push`.
304
- - `fimo link`: project creation or selection plus the in-place adoption of a
305
- copied source target.
306
320
  - `fimo deploy` / `fimo publish` — owner-approved only.
307
321
 
308
322
  ## Migration loop
@@ -312,7 +326,7 @@ writes go through the normal commands against the linked target:
312
326
  edit, or move environment values until the user answers every consent gate.
313
327
  2. Run the setup path from "Initialized target precondition" and inspect the
314
328
  initialized target before any worker edits it. A `fimo link` adoption keeps
315
- the source framework; the `fimo init` / `fimo migrate init` paths choose the
329
+ the source framework; the `fimo migrate init` path chooses the
316
330
  target framework through the same canonical option as
317
331
  `fimo init`: pass the detected source framework for a source-backed
318
332
  migration, the framework the user explicitly chose for a conversion, and —
@@ -404,8 +418,8 @@ Use one final status:
404
418
 
405
419
  Never call a migration complete when CMS entries, media mappings, forms, route
406
420
  coverage, or migration-induced content-delivery regressions are unknown. Local
407
- QA remains the acceptance gate. If
408
- `fimo migrate init` created a new Fimo project, run one `fimo deploy` after QA
421
+ QA remains the acceptance gate. If setup created a new Fimo project
422
+ (`fimo migrate init` or `fimo link`), run one `fimo deploy` after QA
409
423
  and return its preview and dashboard links; skip it when the user said not to
410
424
  deploy or `FIMO_MIGRATION_NO_DEPLOY=1` is set. For an existing linked project,
411
425
  offer the deployment and wait for approval. Never run `fimo publish` without an
@@ -10,7 +10,7 @@ items.
10
10
 
11
11
  Every data-plane write in this contract targets the linked project from
12
12
  workflow Phase 0. Planning and payload authoring need no link; running the
13
- writes does. When no owner-supplied target exists, the writes stay unresolved
13
+ writes does. When setup cannot produce a linked target, the writes stay unresolved
14
14
  owner actions; do not fake a link to make them pass.
15
15
 
16
16
  ## Media Files
@@ -182,6 +182,13 @@ check is the acceptance evidence.
182
182
  or imprint.
183
183
  - `links-resolve`: every internal link rendered on the inventoried routes
184
184
  points at an inventoried route or an explicitly allowed path prefix.
185
+ - `editable-text` (required in every inventory): every visible body text node
186
+ sits inside an element a Fimo primitive renders, so an editor can change it
187
+ in Studio. A faithful port is not editable yet: text still typed in the code
188
+ shows "Nothing to edit". Move it to a label or a CMS field. List in `allow`
189
+ only the exact text the owner keeps in code, such as a brand glyph or a
190
+ legal line, and record why in the migration report. Assistive and hidden
191
+ text does not count.
185
192
 
186
193
  Internal links are resolved against the final document URL and any
187
194
  `<base href>`; query and fragment do not change route identity. An `allow`
@@ -203,14 +210,18 @@ check is the acceptance evidence.
203
210
  "source": "<owner decision>"
204
211
  },
205
212
  { "id": "footer-privacy", "kind": "required-link", "href": "/legal/privacy", "source": "<source navigation>" },
206
- { "id": "nav-resolves", "kind": "links-resolve", "allow": ["/blog"], "source": "<source navigation>" }
213
+ { "id": "nav-resolves", "kind": "links-resolve", "allow": ["/blog"], "source": "<source navigation>" },
214
+ { "id": "editable-text", "kind": "editable-text", "allow": [], "source": "Fimo: visitors' text is editable" }
207
215
  ]
208
216
  }
209
217
  ```
210
218
 
211
219
  2. The validator observes the rendered application, not files in the
212
- repository. For a server-rendered target, run the check with `--base-url`
213
- while the built app serves locally. For a client-rendered target, save each
220
+ repository, with Fimo editing metadata on: build and serve with
221
+ `FIMO_EDITING_METADATA=true`, or observe the dev server. Without it no text is
222
+ marked editable and `editable-text` fails as unmeasured. For a
223
+ server-rendered target, run the check with `--base-url` while the app serves
224
+ locally. For a client-rendered target, save each
214
225
  hydrated document from the browser pass as `<captures>/index.html` and
215
226
  `<captures>/<route>.html` and pass `--captures`. Save a JSON sidecar next to
216
227
  each HTML file, such as `index.html.json` or `legal/privacy.html.json`:
@@ -5,7 +5,10 @@ handoff. Do not import entries or rewrite application consumers.
5
5
 
6
6
  1. Trace active source clients, endpoint/query declarations, frontend types,
7
7
  and every consumer before designing schemas. Then inspect their
8
- content-bearing files, inline values, APIs, or CMS sources.
8
+ content-bearing files, inline values, APIs, or CMS sources, and the visible
9
+ text typed in route and component code: headings, paragraphs, buttons, link
10
+ and navigation text, alt and placeholder text. Each is an item, even when no
11
+ data source holds it.
9
12
  2. Classify each value as collection content, single content, an
10
13
  editor-visible label, or application-owned code. Repetition is evidence,
11
14
  not an automatic collection rule. Assistive text, identifiers, and values
@@ -23,9 +23,10 @@ passed.
23
23
  Verify:
24
24
 
25
25
  - every source route renders with expected status and representative content;
26
- - the rendered guardrail inventory passes: brand, legal, compliance, and
27
- navigation rules are proven on rendered HTML or a running local server with
28
- `scripts/check-rendered-guardrails.mjs`, never by grepping target source.
26
+ - the rendered guardrail inventory passes: brand, legal, compliance,
27
+ navigation, and `editable-text` rules are proven on rendered HTML or a running
28
+ local server with `scripts/check-rendered-guardrails.mjs`, never by grepping
29
+ target source. An inventory without an `editable-text` rule is incomplete.
29
30
  Browser captures include the response metadata required by `references/qa.md`;
30
31
  - schemas, entries, singles, labels, media, forms, and locales exist through
31
32
  CLI read-back;
@@ -62,8 +62,8 @@ other after it. Do not add a metadata format for a small overlap.
62
62
 
63
63
  ## Coordinator gates
64
64
 
65
- 1. Run `fimo migrate init` and inspect the real target paths before workers
66
- write.
65
+ 1. Pass the setup gate in SKILL.md "Initialized target precondition" and
66
+ inspect the real target paths before workers write.
67
67
  2. Start runtime/routes/content-planner/locales together, or the framework
68
68
  worker plus content planner/locales in conversion mode.
69
69
  3. Wait for every discovery receipt to become terminal, then perform one fan-in
@@ -15,32 +15,22 @@ ask a generic optimization question.
15
15
 
16
16
  ## Phase 0: Initialize the target
17
17
 
18
- 1. Confirm the target path. The target is a separate directory; the source
19
- checkout remains read-only evidence.
20
- 2. Initialize or reuse exactly one linked Fimo target before workers start:
21
- - link an existing project: `fimo migrate init <target-dir> --project-id <projectId> --framework <framework>`
22
- - create a project: `fimo migrate init <target-dir> --org <organizationId> --framework <framework>`
23
- - add `--source-platform <platform>` when the source platform is known
24
- (webflow, framer, squarespace, wix, carrd, wordpress, nextjs, astro,
25
- react-router, other). Nothing detects it; omitting it records `unknown`.
26
- Use the detected source framework for source-backed migrations. A framework
27
- conversion requires an explicit user choice; URL-only and rebuild
28
- migrations ask the user which framework to use. Never choose a framework by
29
- copying an arbitrary `--template-root`, invent a project ID, or hand-write
30
- `.fimo/project.json`.
31
- 3. Inspect the target's real `package.json`, `.fimo/config.json`, framework config, and route
18
+ 1. Pick the setup row in SKILL.md "Initialized target precondition", run it,
19
+ and pass its gate before workers start. Framework and `--source-platform`
20
+ rules for `fimo migrate init` live in SKILL.md "Target setup".
21
+ 2. Inspect the target's real `package.json`, `.fimo/config.json`, framework config, and route
32
22
  directories. They are the authority for paths. Do not infer an app root
33
23
  from a skill example and do not create a second `app/` or `src/app/` tree.
34
- 4. Verify dependency provenance before workers start. A project created by a
35
- published CLI pins that exact CLI release and matching companion packages.
36
- A local source-checkout project uses the checkout-local CLI. Stop when the
37
- target records an absolute package-manager cache path, an unapproved
38
- `latest`, or a CLI and API from different runtime channels; do not let the
39
- producer repair release setup inside the migration.
40
- 5. If the target is non-empty and not a Fimo project, stop and ask for a target
41
- path; do not overlay a template on top of it.
42
- 6. Keep source material in `.fimo/migration/source` or another explicit source
43
- location. Do not copy source files over the initialized target root.
24
+ 3. Verify dependency provenance before workers start. The target pins the
25
+ CLI artifact that set it up: an exact published release with matching
26
+ companion packages, or the exact dev artifact from SKILL.md "CLI
27
+ provenance". Stop when the target records an absolute package-manager cache
28
+ path, a `file:` link, an unapproved `latest`, or a CLI and API from
29
+ different runtime channels; do not let the producer repair release setup
30
+ inside the migration.
31
+ 4. When `fimo migrate init` scaffolded the target, keep source material in
32
+ `.fimo/migration/source` or another explicit source location. Do not copy
33
+ source files over the scaffolded target root.
44
34
 
45
35
  Write a short `.fimo/migration/migration-plan.md` containing the source
46
36
  location, selected framework, actual target directories, worker owners, and
@@ -26,7 +26,7 @@ const USAGE =
26
26
  'Usage: node check-rendered-guardrails.mjs [project-root] [--inventory .fimo/migration/guardrails.json] ' +
27
27
  '(--captures <dir> | --base-url <http://localhost:port>) [--output .fimo/migration/guardrails-report.md]';
28
28
 
29
- const RULE_KINDS = ['required-text', 'forbidden-text', 'required-link', 'links-resolve'];
29
+ const RULE_KINDS = ['required-text', 'forbidden-text', 'required-link', 'links-resolve', 'editable-text'];
30
30
 
31
31
  async function main() {
32
32
  const args = parseArgs(process.argv.slice(2));
@@ -318,6 +318,8 @@ function evaluateRules(inventory, observations) {
318
318
  return linkRule(rule, observed);
319
319
  case 'links-resolve':
320
320
  return linksResolveRule(rule, inventory, observed);
321
+ case 'editable-text':
322
+ return editableTextRule(rule, observed);
321
323
  default:
322
324
  return result(rule, false, observed.length, [`unknown rule kind ${rule.kind}`]);
323
325
  }
@@ -382,6 +384,105 @@ function linksResolveRule(rule, inventory, observed) {
382
384
  return result(rule, failures.length === 0, observed.length, failures, `${internal.length} internal links`);
383
385
  }
384
386
 
387
+ // FIMO-3141: text a visitor reads that no Fimo primitive renders shows "Nothing to edit" in Studio, so a faithful
388
+ // port is not done until each such text node is a label, a CMS field, or an `allow` entry the owner accepts in code
389
+ // (a brand glyph, a legal line). Fimo marks editable text only when editing metadata is on (the dev server, or a
390
+ // build with FIMO_EDITING_METADATA=true); a route with no mark at all is unmeasured, never passed.
391
+ /** @param {Rule} rule @param {Observation[]} observed */
392
+ function editableTextRule(rule, observed) {
393
+ const allow = new Set(asArray(rule.allow).filter(isNonEmptyString).map(normalizeText));
394
+ const failures = [];
395
+ let editable = 0;
396
+ let typed = 0;
397
+ let unmarked = 0;
398
+ for (const item of observed) {
399
+ const nodes = textNodes(item.html ?? '');
400
+ // A route with no mark at all is a site with no label or CMS text yet, or editing metadata that is off: its text
401
+ // is still listed, so a reviewer sees what would move, and the route never counts as measured.
402
+ if (!nodes.marked) {
403
+ unmarked += 1;
404
+ failures.push(
405
+ `no Fimo-marked text on ${item.route}: the site renders no label or CMS text yet, or editing metadata is off (capture the dev server or a build with FIMO_EDITING_METADATA=true)`
406
+ );
407
+ }
408
+ editable += nodes.editable;
409
+ for (const text of uniqueArray(nodes.typed)) {
410
+ if (allow.has(normalizeText(text))) continue;
411
+ typed += 1;
412
+ failures.push(`"${text}" on ${item.route} is typed in the code`);
413
+ }
414
+ }
415
+ const summary = `${editable} editable, ${typed} typed in the code${unmarked > 0 ? `, ${unmarked} routes with no Fimo mark` : ''}`;
416
+ return result(rule, failures.length === 0, observed.length, failures, summary);
417
+ }
418
+
419
+ const VOID_ELEMENTS = new Set([
420
+ 'area',
421
+ 'base',
422
+ 'br',
423
+ 'col',
424
+ 'embed',
425
+ 'hr',
426
+ 'img',
427
+ 'input',
428
+ 'link',
429
+ 'meta',
430
+ 'param',
431
+ 'source',
432
+ 'track',
433
+ 'wbr',
434
+ ]);
435
+
436
+ // Body text nodes with at least two letters: those inside an element Fimo marks (`data-fimo-source`,
437
+ // `data-fimo-richtext`) are editable; the rest are typed in the code. Assistive and hidden text is skipped: it is
438
+ // not a label (see references/decision.md).
439
+ /** @param {string} html @returns {{marked: boolean, editable: number, typed: string[]}} */
440
+ function textNodes(html) {
441
+ const cleaned = html
442
+ .replace(/<!--[\s\S]*?-->/g, ' ')
443
+ .replace(/<[!?][^>]*>/g, ' ')
444
+ .replace(/<(script|style|noscript|template|head)\b[^>]*>[\s\S]*?<\/\1\s*>/gi, ' ');
445
+ const marked = /\sdata-fimo-(?:source|richtext)\b/i.test(cleaned);
446
+ /** @type {{tag: string, editable: boolean, hidden: boolean}[]} */
447
+ const stack = [];
448
+ let editable = 0;
449
+ /** @type {string[]} */
450
+ const typed = [];
451
+ for (const match of cleaned.matchAll(/<(\/?)([a-zA-Z][\w:-]*)([^>]*)>|([^<]+)/g)) {
452
+ const [, closing, rawTag, attributes = '', text] = match;
453
+ const parent = stack.at(-1);
454
+ if (text !== undefined) {
455
+ const value = normalizeText(decodeEntities(text));
456
+ if (parent?.hidden || (value.match(/\p{L}/gu) ?? []).length < 2) continue;
457
+ if (parent?.editable) editable += 1;
458
+ else typed.push(value);
459
+ continue;
460
+ }
461
+ const tag = rawTag.toLowerCase();
462
+ if (closing) {
463
+ const index = stack.map((entry) => entry.tag).lastIndexOf(tag);
464
+ if (index !== -1) stack.length = index;
465
+ continue;
466
+ }
467
+ if (VOID_ELEMENTS.has(tag) || attributes.trim().endsWith('/')) continue;
468
+ stack.push({
469
+ tag,
470
+ editable: Boolean(parent?.editable) || /\sdata-fimo-(?:source|richtext)\b/i.test(attributes),
471
+ hidden:
472
+ Boolean(parent?.hidden) ||
473
+ /\shidden\b/i.test(attributes.replace(/=\s*(?:"[^"]*"|'[^']*')/g, '')) ||
474
+ /\saria-hidden\s*=\s*["']?true\b/i.test(attributes) ||
475
+ /\sclass\s*=\s*["'][^"']*\b(?:sr-only|visually-hidden)\b/i.test(attributes),
476
+ });
477
+ }
478
+ return { marked, editable, typed };
479
+ }
480
+
481
+ /** @param {string} value */
482
+ function normalizeText(value) {
483
+ return value.replace(/\s+/g, ' ').trim();
484
+ }
485
+
385
486
  /** @param {Rule} rule @param {boolean} passed @param {number} observed @param {string[]} failures @param {string} [extra] @returns {Result} */
386
487
  function result(rule, passed, observed, failures, extra) {
387
488
  return { id: rule.id, kind: rule.kind, passed, observed, failures, extra: extra ?? null };
@@ -36,7 +36,7 @@ Use plain, friendly language. Describe what users see, where they click, and wha
36
36
 
37
37
  - **Header (desktop):** the site menu (site name; History is here) and the Branch switcher, then the workspaces: Chats, Getting started, Preview, Content, Assets, Analytics, Settings. Only workspaces the user can access appear. Workspaces that do not fit move into **More**. On the right: Earn free credits, Invite, Clone, Publish, and Merge on a Branch.
38
38
  - **Phone:** bottom tabs for Chat, Preview and Settings. Invite, Earn free credits and Clone ("Work on this site locally") move into the site menu.
39
- - **Settings:** General, Domains, Knowledge, SEO and Languages are listed directly. Models, Environments, Variables, Secrets, Schedules, Webhooks and Connections are under **Advanced settings**.
39
+ - **Settings:** General, Domains, Knowledge, SEO, Integrations and Languages are listed directly. Models, Environments, Variables, Secrets, Schedules and Webhooks are under **Advanced settings**.
40
40
  - **Shortcuts:** Alt+1 Preview, Alt+2 Content, Alt+3 Assets, Alt+5 Settings, Alt+E edit mode, Cmd/Ctrl+K command palette.
41
41
 
42
42
  When a reference says "open X", X can be inside **More** on a narrow window.
@@ -59,7 +59,7 @@ Read the relevant reference file when the user's question matches a topic.
59
59
  | Variables & Secrets | references/variables-and-secrets.md | "Where do I put an API key?", "Public or private variable?" |
60
60
  | Schedules | references/schedules.md | "Recurring commands", "Run history", "Run now" |
61
61
  | Webhooks | references/webhooks.md | "React to forms", "Send events to another service" |
62
- | Connections | references/connections.md | "Connect a service", "Add an MCP server" |
62
+ | Integrations | references/integrations.md | "Connect a service", "Add an MCP server", "Slack channels" |
63
63
  | Preview & Responsive | references/preview-and-responsive.md | "How does it look on mobile?", "How do I test sizes?" |
64
64
  | Visual Editing | references/visual-editing.md | "Can I edit visually?", "How do I change colors?" |
65
65
  | Version History | references/version-history.md | "How do I undo?", "How do I go back?" |
@@ -76,7 +76,7 @@ Read the relevant reference file when the user's question matches a topic.
76
76
  | Adding images | Media Library, AI Chat, Edit Mode |
77
77
  | Content/CMS | AI Chat, Media Library |
78
78
  | Webhooks | Site secrets, Forms, Publishing |
79
- | Connections | AI Chat, Site secrets |
79
+ | Apps | AI Chat, Site secrets |
80
80
  | Schedules | Site secrets, Environments |
81
81
  | API keys | Variables (private), Site secrets |
82
82
  | Visual changes | Edit Mode (CMS content), AI Chat (layout, styling, and code changes) |