fimo 2.10.0-staging.4 → 2.10.0-staging.5
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/assets/skills/fimo/SKILL.md +1 -1
- package/assets/skills/fimo-cli/SKILL.md +1 -0
- package/assets/skills/fimo-cli/references/init.md +4 -0
- package/assets/skills/fimo-migration/SKILL.md +73 -59
- package/assets/skills/fimo-migration/references/import-contract.md +1 -1
- package/assets/skills/fimo-migration/references/qa.md +14 -3
- package/assets/skills/fimo-migration/references/workers/content-planner.md +4 -1
- package/assets/skills/fimo-migration/references/workers/validator.md +4 -3
- package/assets/skills/fimo-migration/references/workers.md +2 -2
- package/assets/skills/fimo-migration/references/workflow.md +14 -24
- package/assets/skills/fimo-migration/scripts/check-rendered-guardrails.mjs +102 -1
- package/assets/skills/fimo-studio/references/ai-chat.md +1 -1
- package/dist/cli/bundle.json +1 -1
- package/dist/cli/index.js +21 -21
- package/package.json +8 -8
- package/templates/astro/package.json +3 -3
- package/templates/nextjs/package.json +4 -4
- package/templates/react-router/package.json +5 -5
- package/templates/sveltekit/package.json +3 -3
- package/templates/vite/package.json +5 -5
|
@@ -41,7 +41,7 @@ Pick by task:
|
|
|
41
41
|
- AI agent setup — connect Claude Code, Codex, Cursor, or another agent → `fimo-cli` (`references/agent-setup.md`)
|
|
42
42
|
- Integrations — Search Console, Slack, or an MCP server: add, inspect, search, or run its tools → `fimo-cli` (`references/integrations.md`)
|
|
43
43
|
- The Fimo Studio dashboard / web app UI → `fimo-studio`
|
|
44
|
-
- Migrating an existing site into Fimo → `fimo-migration`
|
|
44
|
+
- Migrating an existing site into Fimo, or putting an existing app on Fimo (`fimo link`) → `fimo-migration`
|
|
45
45
|
|
|
46
46
|
For project setup, load `fimo-cli` first. Its `references/init.md` decision tree distinguishes a new or empty
|
|
47
47
|
project, an existing Fimo site, and an external migration; load `fimo-migration` for the last path.
|
|
@@ -111,6 +111,7 @@ Load the matching reference when the user's request fires its trigger. Recipes t
|
|
|
111
111
|
- "Create a Branch / feature Branch / switch Branches / merge Branches / diff two Branches / Branch status / what changed on this Branch / sync from parent / cut a release / tag a version / go to prod" → `references/branches.md`
|
|
112
112
|
- "List my projects / clone an existing project locally / check out a project / delete this project / unpublish / rename the project / manage projects across the org" → `references/projects.md`
|
|
113
113
|
- "Migrate an existing Webflow / Framer / Squarespace / Wix / Carrd site from only a published URL" → load the `fimo-migration` skill, set the target up with `fimo migrate init <dir>`, and read the published site yourself with a browser — the CLI does not crawl it
|
|
114
|
+
- "Put my existing site or app on Fimo / link or deploy the app in this folder / host the site I built" → load the `fimo-migration` skill and follow its source-backed, same-framework path: `fimo link` keeps every word typed in the code, which Studio cannot edit, until the migration's content pass moves it to labels and the CMS
|
|
114
115
|
- "Migrate from an exported project, source repository, Webflow code export plus CMS CSVs, Framer CMS CSVs, Squarespace XML/CSV, Wix CSVs, Carrd/static export, or downloaded site files" → load the `fimo-migration` skill and use the source repo/export as the migration source of truth
|
|
115
116
|
- "How do AI agents read my site / markdown for agents" → `references/deploy.md`
|
|
116
117
|
- "Modify the URL of the website / change my project's address / connect a custom domain (e.g. blog.example.com) / rename the Fimo-provided `*.fimo.site` subdomain / buy a new domain through Fimo / set up a domain" → `references/domains.md`
|
|
@@ -105,6 +105,10 @@ Use `fimo link <projectId>` to adopt the application in the current folder witho
|
|
|
105
105
|
fimo link <projectId> --relink
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
+
Linking keeps every word typed in the code, where Fimo Studio shows "Nothing to edit". When people will edit the site,
|
|
109
|
+
load `fimo-migration` and follow its source-backed, same-framework path: its content pass moves that
|
|
110
|
+
text to labels and the CMS, and its `editable-text` guardrail proves it.
|
|
111
|
+
|
|
108
112
|
## What gets written (create-new path)
|
|
109
113
|
|
|
110
114
|
`fimo init` (create-new path) scaffolds:
|
|
@@ -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
|
|
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
|
|
27
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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`).
|
|
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
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
`fimo migrate init`
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
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
|
|
268
|
-
`fimo migrate init <target-dir> --
|
|
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
|
-
|
|
281
|
-
|
|
282
|
-
|
|
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>` —
|
|
293
|
-
|
|
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
|
-
|
|
300
|
-
|
|
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
|
|
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`
|
|
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
|
|
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
|
|
213
|
-
|
|
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,
|
|
27
|
-
navigation rules are proven on rendered HTML or a running
|
|
28
|
-
`scripts/check-rendered-guardrails.mjs`, never by grepping
|
|
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.
|
|
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.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
target records an absolute package-manager cache
|
|
38
|
-
`latest`, or a CLI and API from
|
|
39
|
-
producer repair release setup
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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 };
|
|
@@ -24,7 +24,7 @@ The **Compliance** default runs three routines backed by Studio's built-in `fimo
|
|
|
24
24
|
|
|
25
25
|
### Routines
|
|
26
26
|
|
|
27
|
-
A routine is saved instructions an agent runs in a thread of its own, by hand, on a schedule, or when something happens in the project, so each run sees its earlier runs and the agent's chat never fills with its work. The agent creates, changes, runs and deletes its routines from its chat with its `routines` tool: a person asks in the chat ("check the prices every Monday", "run after each publish"), and Studio only shows routines. A trigger is set in words; Fimo checks them and either says when the routine runs or why it cannot follow them and what it can do instead; for what Fimo cannot see as an event (traffic, rankings, errors) the agent offers a schedule whose run checks it and stops when there is nothing to do. Fimo follows publishes of the site (or only its first publish) and content changes on the main branch by content type, action, locale, changed fields, the entry's current values ("price over 100", "status changes to archived") or a yes/no question about what the content says ("mentions Contentful or Sanity"; for "a competitor" it uses the names given or those in the site knowledge, and asks for them otherwise; a run started on an uncertain answer says so), media files uploaded or changed (by name or file type), the site's code changing through a deploy or a merge (by file path glob, or a yes/no question about the changed files such as "a page was added"), another routine of the same agent finishing (optionally with a yes/no question about its report; never its own end), a visitor submitting a form (optionally with a yes/no question about the answers), a form or content type changing, a branch merged into main, a locale added, removed or made the default, a publish of the site failing, a domain added or removed, and the prices on a page of another web site changing ("tell me when https://example.com/pricing changes its prices": checked daily, a change must hold on three reads before the routine runs, the run lists each plan with its old and new price, the routine page shows the watch as **OK**, **Needs repair**, **Blocked** or **Unstable** with its last check, at most 10 watched pages a project); comparing a field's old and new values is not supported; what a routine changes, publishes or reports can start the agent's other routines, in chains of any length, each routine at most once per change that started the chain (across every routine that change leads to, so routines never loop or multiply; a person's new change, a run by hand or on a schedule starts a new chain); events that come in while a run is busy wait, then run together in one next run
|
|
27
|
+
A routine is saved instructions an agent runs in a thread of its own, by hand, on a schedule, or when something happens in the project, so each run sees its earlier runs and the agent's chat never fills with its work. The agent creates, changes, runs and deletes its routines from its chat with its `routines` tool: a person asks in the chat ("check the prices every Monday", "run after each publish"), and Studio only shows routines. A trigger is set in words; Fimo checks them and either says when the routine runs or why it cannot follow them and what it can do instead; for what Fimo cannot see as an event (traffic, rankings, errors) the agent offers a schedule whose run checks it and stops when there is nothing to do. Fimo follows publishes of the site (or only its first publish) and content changes on the main branch by content type, action, locale, changed fields, the entry's current values ("price over 100", "status changes to archived") or a yes/no question about what the content says ("mentions Contentful or Sanity"; for "a competitor" it uses the names given or those in the site knowledge, and asks for them otherwise; a run started on an uncertain answer says so), media files uploaded or changed (by name or file type), the site's code changing through a deploy or a merge (by file path glob, or a yes/no question about the changed files such as "a page was added"), another routine of the same agent finishing (optionally with a yes/no question about its report; never its own end), a visitor submitting a form (optionally with a yes/no question about the answers), a form or content type changing, a branch merged into main, a locale added, removed or made the default, a publish of the site failing, a domain added or removed, and the prices on a page of another web site changing ("tell me when https://example.com/pricing changes its prices": checked daily, a change must hold on three reads before the routine runs, the run lists each plan with its old and new price, the routine page shows the watch as **OK**, **Needs repair**, **Blocked** or **Unstable** with its last check, at most 10 watched pages a project); comparing a field's old and new values is not supported; what a routine changes, publishes or reports can start the agent's other routines, in chains of any length, each routine at most once per change that started the chain (across every routine that change leads to, so routines never loop or multiply; a person's new change, a run by hand or on a schedule starts a new chain); events that come in while a run is busy wait, then run together in one next run, which the Runs list shows as one run with its event count (a very large burst, such as a bulk import, runs in several runs, in order); the agent can also make a routine's event runs wait until the changes stop for a set number of minutes (at most 2 hours from the first), then read them all in one run (a yes/no question is then answered once for all the waiting changes, each entry once in its latest version; a waiting change it says no to leaves the queue, and when it says no to all of them no run starts); the default routines that read what changed (Technical SEO, Meta tags, Image SEO, Internal linking, AI readiness, Structured data, AI citation optimization, Content lifecycle, Translation, Accessibility, Mobile optimization, Brand compliance) wait 10 minutes after the last change, and those that guard the live site (Broken links, Hreflang, Cookie consent, Privacy and legal pages) run at once. The agent's settings list its **Routines** as cards (name, when it runs such as its event trigger's title, **Every Monday at 08:00** or **By hand**, next run, an **Active** switch); the default agents come with theirs (a new project's defaults wake on changes from five minutes after it is created, so its first push and seed start no run). A routine's page is read-only: **What it does** (one or two plain sentences the agent writes with the routine, Fimo's for a default routine), with **Instructions** folded under it (the task, run on every trigger; a routine created before descriptions shows only its **Instructions**), **Model** (the model its runs use: Opus 5.5 by default, while most default routines run on Claude Haiku 5.5 or Claude Sonnet 5.5; the agent sets another when asked), **Triggers** (**By hand** with **Run now**, which starts a run right away; **Schedule** and the event trigger, given a short title by Fimo from the words it was set with and showing those words, shown when set), the **Runs** list (newest first, two lines each: how it ended (**Quiet**, **Sent to agent**, **Asked for a decision**, or **Failed** and **Stopped** in red), when and what started it (**On schedule**, **On event**, or **By hand** with the person's name or **agent** when their message started it), then the first sentence of what it told the agent; select one to open the routine's thread, read-only, at that run), and the **Active** switch in the header (pauses the schedule and the trigger, not **Run now**). Routines report to the agent, never to a person: a run that has something the agent should know writes it to the agent's chat as a message only the agent reads, and the agent takes a turn on it (reports waiting together are read in one turn); a run with nothing to say reports nothing. The agent decides what the team sees: nothing (the chat stays as it was, the row stays read), one short message (several reports folded into one), or a form when a person must decide, and the chat's row reads **Needs you** while that form is open. A person answers the form in the chat; the agent sends the decision to the routine with its `routines` tool and the routine runs again with it. Only the agent answers a routine: its page has no answer box. Quiet runs leave no message: they fold into one line placed where the last run happened among the messages (**N runs since <date>**), counted from the last report the agent answered visibly, and the chat's row reads **Ran <date>** with that count while the newest thing in the chat is a run, the ordinary status and the last words when a message is newer, and **First check <day> <time>** or **No checks scheduled** before the first run. A routine whose runs keep failing or are refused for credits is reported to the agent once per streak, as a message from Fimo. Routine runs use the plan's agent-hours, from each run's start to its end (Studio chats do not); Billing shows the hours used this period, and each run shows its duration and credits. Once the included hours are used, nothing runs (no schedule, event or Run now, which the routines tool reports to the agent); Studio shows **Routines paused** under the chat list and in the agent's settings with the reset date and the button that resumes them sooner (**Upgrade**), and the routine's page says until when. No run lasts longer than 2 hours.
|
|
28
28
|
|
|
29
29
|
## Sending a Message
|
|
30
30
|
|