fimo 2.4.0-staging.1 → 2.4.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.
- package/assets/skills/fimo-cli/SKILL.md +3 -2
- package/assets/skills/fimo-cli/references/agent-setup.md +2 -1
- package/assets/skills/fimo-cli/references/agents.md +13 -1
- package/assets/skills/fimo-cli/references/branches.md +4 -4
- package/assets/skills/fimo-cli/references/deploy.md +3 -6
- package/assets/skills/fimo-cli/references/domains.md +5 -5
- package/assets/skills/fimo-cli/references/forms.md +4 -2
- package/assets/skills/fimo-cli/references/hosting.md +5 -4
- package/assets/skills/fimo-cli/references/preview.md +1 -1
- package/assets/skills/fimo-cli/references/projects.md +5 -5
- package/assets/skills/fimo-cli/references/site-checks.md +73 -0
- package/assets/skills/fimo-code/SKILL.md +1 -0
- package/assets/skills/fimo-code/references/assets.md +4 -2
- package/assets/skills/fimo-code/references/best-practices/next.md +0 -2
- package/assets/skills/fimo-code/references/content/schema.md +4 -1
- package/assets/skills/fimo-code/references/design.md +2 -2
- package/assets/skills/fimo-code/references/frameworks/astro.md +37 -1
- package/assets/skills/fimo-code/references/frameworks/compatibility.md +5 -5
- package/assets/skills/fimo-code/references/frameworks/hosting.md +23 -2
- package/assets/skills/fimo-code/references/frameworks/next/app-router.md +7 -21
- package/assets/skills/fimo-code/references/frameworks/next/seo.md +168 -0
- package/assets/skills/fimo-code/references/frameworks/next.md +1 -1
- package/assets/skills/fimo-code/references/frameworks/seo-head.md +78 -0
- package/assets/skills/fimo-code/references/frameworks/sveltekit.md +57 -4
- package/assets/skills/fimo-migration/SKILL.md +33 -33
- package/assets/skills/fimo-migration/references/content.md +1 -1
- package/assets/skills/fimo-migration/references/frameworks/nextjs.md +7 -0
- package/assets/skills/fimo-migration/references/import-contract.md +4 -6
- package/assets/skills/fimo-migration/references/manifest.md +4 -3
- package/assets/skills/fimo-migration/references/qa.md +6 -0
- package/assets/skills/fimo-migration/references/questions-and-improvements.md +1 -1
- package/assets/skills/fimo-migration/references/workflow.md +7 -5
- package/assets/skills/fimo-studio/references/agents.md +7 -1
- package/assets/skills/fimo-studio/references/billing-and-credits.md +21 -7
- package/assets/skills/fimo-studio/references/seo-settings.md +2 -0
- package/dist/cli/bundle.json +2 -2
- package/dist/cli/index.js +502 -986
- package/dist/runtime/astro/server-runtime.js +2 -2
- package/dist/runtime/paths/get-fimo-paths.js +1 -1
- package/dist/runtime/seo/head.d.ts +31 -0
- package/dist/runtime/seo/head.js +47 -0
- package/dist/runtime/seo/index.d.ts +2 -0
- package/dist/runtime/seo/index.js +1 -0
- package/dist/runtime/seo/resolver.d.ts +16 -2
- package/dist/runtime/seo/resolver.js +10 -0
- package/dist/runtime/seo/server.d.ts +13 -0
- package/dist/runtime/seo/server.js +23 -0
- package/dist/runtime/shared/branch-identity.d.ts +3 -5
- package/dist/runtime/shared/branch-identity.js +3 -5
- package/dist/runtime/shared/fimo-config.server.d.ts +2 -0
- package/dist/runtime/shared/fimo-config.server.js +18 -14
- package/dist/scripts/export-static.d.ts +3 -4
- package/dist/scripts/export-static.js +3 -20
- package/dist/scripts/sync-schemas.js +12 -5
- package/package.json +12 -8
- package/templates/astro/.fimo/config.json +1 -0
- package/templates/astro/AGENTS.md +1 -1
- package/templates/astro/astro.config.mjs +1 -0
- package/templates/astro/package.json +2 -2
- package/templates/astro/src/layouts/Base.astro +20 -4
- package/templates/astro/src/pages/[locale]/index.astro +1 -1
- package/templates/astro/src/pages/[locale]/projects/[slug].astro +4 -1
- package/templates/astro/src/pages/index.astro +1 -1
- package/templates/astro/src/pages/projects/[slug].astro +4 -1
- package/templates/nextjs/AGENTS.md +1 -1
- package/templates/nextjs/package.json +3 -3
- package/templates/nextjs/src/app/layout.tsx +5 -3
- package/templates/nextjs/src/app/page.tsx +6 -0
- package/templates/react-router/package.json +4 -4
- package/templates/sveltekit/AGENTS.md +1 -1
- package/templates/sveltekit/package.json +2 -2
- package/templates/sveltekit/src/routes/+layout.server.ts +4 -0
- package/templates/sveltekit/src/routes/+layout.svelte +12 -0
- package/templates/sveltekit/src/routes/[[locale=locale]]/+page.svelte +0 -5
- package/templates/vite/package.json +4 -4
- package/assets/skills/fimo-migration/scripts/build-canonical-manifest.mjs +0 -595
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Next.js SEO
|
|
2
|
+
|
|
3
|
+
Use the installed package APIs. The app owns routing, metadata policy and
|
|
4
|
+
rendering mode. Fimo supplies editable values, not a router or a merge policy.
|
|
5
|
+
|
|
6
|
+
## Read, resolve, convert
|
|
7
|
+
|
|
8
|
+
```ts
|
|
9
|
+
import { getFimoSeo } from 'fimo/seo/server';
|
|
10
|
+
import { toNextMetadata, toNextViewport } from 'fimo-next/seo';
|
|
11
|
+
|
|
12
|
+
// Root layout: global defaults, never implicitly Home.
|
|
13
|
+
export const generateMetadata = () => toNextMetadata(getFimoSeo());
|
|
14
|
+
export const generateViewport = () => toNextViewport(getFimoSeo());
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
For a new App Router site, keep this root wiring. Home is an explicit route:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
// app/page.tsx
|
|
21
|
+
export const generateMetadata = () => toNextMetadata(getFimoSeo({ pathname: '/' }));
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
For each route module with configured route SEO, resolve its real pathname.
|
|
25
|
+
One dynamic module handles every slug. Reuse the app's content loader and URL
|
|
26
|
+
builder; do not try to infer a full pathname from Next's params in the root.
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
// app/blog/[slug]/page.tsx, using the app's existing loader and URL builder
|
|
30
|
+
export async function generateMetadata({ params }: { params: Promise<{ slug: string }> }) {
|
|
31
|
+
const { slug } = await params;
|
|
32
|
+
const article = await getArticle(slug);
|
|
33
|
+
return toNextMetadata(
|
|
34
|
+
getFimoSeo({
|
|
35
|
+
pathname: articlePath(article),
|
|
36
|
+
routeData: { article },
|
|
37
|
+
})
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Loaders should retain their normal not-found and caching behavior. Add
|
|
43
|
+
`generateViewport` at a route only when route-specific `themeColor` needs to
|
|
44
|
+
apply; share the existing cached loader if both exports need its data. Other
|
|
45
|
+
routes inherit the root color. When adding a page, follow the established
|
|
46
|
+
pattern and keep its Fimo catalog entry aligned with a URL the app serves.
|
|
47
|
+
|
|
48
|
+
`getFimoSeo({ pathname?, routeData?, rootDir? })` is synchronous and Node-only.
|
|
49
|
+
No pathname reads global SEO. A pathname applies matching route overrides.
|
|
50
|
+
It reads current or legacy project config using Fimo's config discovery;
|
|
51
|
+
missing config/SEO returns `undefined`, malformed JSON and other I/O errors
|
|
52
|
+
throw. Pass `rootDir` for a monorepo app located away from the process cwd.
|
|
53
|
+
It does not cache, fetch content, infer locales or invalidate Next's caches.
|
|
54
|
+
Config edits reach static output on rebuild and cached output on the app's
|
|
55
|
+
normal revalidation path. Fetched route content can remain cached across
|
|
56
|
+
builds; use the app's data-cache invalidation/revalidation policy and verify
|
|
57
|
+
the rendered value after a content edit. Rebuild success is not freshness proof.
|
|
58
|
+
|
|
59
|
+
For bundled data or Edge, supply config yourself to the pure resolver instead
|
|
60
|
+
of importing the Node reader:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { resolveSeoForPath } from 'fimo/seo';
|
|
64
|
+
import { toNextMetadata } from 'fimo-next/seo';
|
|
65
|
+
|
|
66
|
+
const seo = resolveSeoForPath(pathname, publicSeoConfig, { article });
|
|
67
|
+
const metadata = toNextMetadata(seo);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Bundle only public SEO/routes, not credentials or project connection data.
|
|
71
|
+
Every ancestor layout of an Edge page must also avoid the Node reader. Use
|
|
72
|
+
bundled public SEO for shared root defaults, not just for the Edge leaf.
|
|
73
|
+
The converters have no I/O or Next request dependency. Their output is for
|
|
74
|
+
App Router; Pages Router keeps its existing `next/head` or SEO library and
|
|
75
|
+
maps resolved Fimo values there. Do not convert routers for SEO.
|
|
76
|
+
|
|
77
|
+
## Available fields
|
|
78
|
+
|
|
79
|
+
Global values live at `seo` and overrides at `routes.<id>.seo` in the project's
|
|
80
|
+
existing Fimo config (normally `.fimo/config.json`). Preserve other config keys.
|
|
81
|
+
`fimo pages set` manages the route catalog but has no `--seo` flag; edit the
|
|
82
|
+
config to author route SEO. For example:
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"seo": { "title": "Journal", "description": "Notes from the field" },
|
|
87
|
+
"routes": {
|
|
88
|
+
"article": {
|
|
89
|
+
"path": "/blog/:slug",
|
|
90
|
+
"seo": { "title": "{{article.title}}", "description": "{{article.summary}}" }
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`FimoSEO` from `fimo/seo` has these optional string fields:
|
|
97
|
+
|
|
98
|
+
| Fimo field | Next output |
|
|
99
|
+
| ------------- | ------------------------------------------------------ |
|
|
100
|
+
| `title` | `title` |
|
|
101
|
+
| `description` | `description` |
|
|
102
|
+
| `siteName` | `openGraph.siteName` |
|
|
103
|
+
| `url` | `metadataBase`, relative canonical and `openGraph.url` |
|
|
104
|
+
| `image` | `openGraph.images` |
|
|
105
|
+
| `favicon` | `icons.icon` and `icons.apple` |
|
|
106
|
+
| `twitterSite` | `twitter.site` |
|
|
107
|
+
| `robots` | `robots` meta, not robots.txt |
|
|
108
|
+
| `themeColor` | `Viewport.themeColor`, not Metadata |
|
|
109
|
+
| `locale` | `openGraph.locale`, not URL or translation selection |
|
|
110
|
+
|
|
111
|
+
Route fields use the same shape. `{{article.title}}` reads caller-supplied
|
|
112
|
+
`routeData.article.title`; `siteName` and route `label` are built-in context.
|
|
113
|
+
A missing, empty or nonscalar token falls back for the entire field to its
|
|
114
|
+
global value, then absence. Tracked Fimo strings are supported. This does not
|
|
115
|
+
invent content when an article is missing.
|
|
116
|
+
|
|
117
|
+
Converters return `{}` for undefined SEO. They leave social title/description
|
|
118
|
+
and Twitter images unset so Next derives them from final page metadata/OG.
|
|
119
|
+
They default OG type to `website` and Twitter card to `summary_large_image`.
|
|
120
|
+
`url` is a site base; relative canonical/OG URLs follow the active route.
|
|
121
|
+
App-specific canonical policies, hreflang, JSON-LD, sitemaps, robots.txt,
|
|
122
|
+
verification tags and generated social images remain app-owned.
|
|
123
|
+
|
|
124
|
+
## Existing app: adopt only chosen fields
|
|
125
|
+
|
|
126
|
+
Inspect existing root/section/page exports and file-based icons/social images
|
|
127
|
+
first. Do not spread every resolved global value into a leaf: that can replace
|
|
128
|
+
a section's `noindex` policy or image. Keep the app's established metadata
|
|
129
|
+
builder and choose the fields Fimo should supply. For example, an app choosing
|
|
130
|
+
Fimo's editable description while retaining its title and policy:
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
export async function generateMetadata(context: Props) {
|
|
134
|
+
const application = await getApplicationMetadata(context);
|
|
135
|
+
const seo = getFimoSeo({ pathname: await getApplicationPathname(context) });
|
|
136
|
+
return {
|
|
137
|
+
...application,
|
|
138
|
+
...(seo?.description ? { description: seo.description } : {}),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
The loader/path helpers above belong to the app, not Fimo. For nested fields,
|
|
144
|
+
explicitly retain the siblings the app intends to keep. Next replaces
|
|
145
|
+
`openGraph`, `twitter`, `icons` and `alternates` objects across segments; there
|
|
146
|
+
is no generic deep-merge or null-based suppression guarantee. Never spread
|
|
147
|
+
parent `ResolvedMetadata` wholesale. File-based images can mask config values;
|
|
148
|
+
preserve them unless the user chooses to replace that behavior.
|
|
149
|
+
|
|
150
|
+
Use one title-suffix owner. If a Fimo template already produces a complete
|
|
151
|
+
title, return `title: { absolute: seo.title }` to bypass an ancestor
|
|
152
|
+
`title.template`, or remove the duplicated suffix from the Fimo template.
|
|
153
|
+
Next's layout `title.template` does not apply to a page in that same segment;
|
|
154
|
+
give Home its complete app-owned title when it needs the suffix too.
|
|
155
|
+
Preserve deliberate Twitter-specific images; otherwise allow Next's OG fallback.
|
|
156
|
+
|
|
157
|
+
The existing `buildFimoMetadata(rootDir?)` and `buildFimoViewport(rootDir?)` from `fimo-next`
|
|
158
|
+
remain global-only helpers. Their string argument is a directory, not a route.
|
|
159
|
+
|
|
160
|
+
## Prove the rendered result
|
|
161
|
+
|
|
162
|
+
Build and request representative Home, static and dynamic routes. Check the
|
|
163
|
+
actual title, description, canonical, OG/Twitter images, icons, robots and
|
|
164
|
+
theme color against configured values. Include missing template data and an
|
|
165
|
+
existing section policy. Confirm social titles follow the final page title,
|
|
166
|
+
suffixes occur once, and no Home values leak to other routes. A helper import
|
|
167
|
+
or a successful build alone does not prove SEO. Check supported runtime and
|
|
168
|
+
revalidation behavior when those are part of the task.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Use this reference when `fimo describe --json` reports `framework.slug: "nextjs"`, or the project uses an App Router (`app/` or `src/app/`) or Pages Router (`pages/` or `src/pages/`) tree.
|
|
4
4
|
|
|
5
|
-
Fimo supports schema-first content in both routers across static generation, ISR, request-time rendering, and Client Components. The application owns routes, locale resolution, links, `<html lang/dir>`, and
|
|
5
|
+
Fimo supports schema-first content in both routers across static generation, ISR, request-time rendering, and Client Components. The application owns routes, locale resolution, links, `<html lang/dir>`, and SEO policy. Fimo supplies content, labels, editing context and optional resolved SEO values. For site creation, new routes or SEO changes, load `references/frameworks/next/seo.md`.
|
|
6
6
|
|
|
7
7
|
## Choose the router reference
|
|
8
8
|
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Astro and SvelteKit SEO
|
|
2
|
+
|
|
3
|
+
Resolve route data, apply the app's policy, then convert. Both imports are pure
|
|
4
|
+
and bundle-safe. Neither reads files, fetches content, discovers a route, nor
|
|
5
|
+
sets framework caching. Use the installed package's exports.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { resolveSeoForPath, toSeoHead, type FimoSEO } from 'fimo/seo';
|
|
9
|
+
import config from '../../.fimo/config.json'; // adjust to the actual file
|
|
10
|
+
|
|
11
|
+
const resolved = resolveSeoForPath(pathname, config, { article });
|
|
12
|
+
const seo: FimoSEO = { ...resolved, title: String(article.title) };
|
|
13
|
+
const head = toSeoHead(seo, { canonicalUrl });
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`resolveSeoForPath` combines global defaults and the matching catalog route's
|
|
17
|
+
`seo`. Supply the actual pathname, including the app's locale/base path, and
|
|
18
|
+
the already-loaded data named by templates such as `{{article.title}}`.
|
|
19
|
+
Unresolved tokens fall back for the entire field. The route catalog is not a
|
|
20
|
+
router. For domain/custom locale routing, the app selects locale-specific
|
|
21
|
+
values explicitly. No global defaults are required to use route SEO.
|
|
22
|
+
|
|
23
|
+
All `FimoSEO` fields are optional strings:
|
|
24
|
+
|
|
25
|
+
| Fields | Output |
|
|
26
|
+
| ---------------------- | --------------------------------------------------------------------------------- |
|
|
27
|
+
| `title`, `description` | Native title/description and matching Open Graph/Twitter values |
|
|
28
|
+
| `image` | Open Graph and Twitter share image |
|
|
29
|
+
| `favicon` | Icon and apple-touch-icon links |
|
|
30
|
+
| `siteName`, `locale` | Open Graph site name and locale |
|
|
31
|
+
| `twitterSite` | Twitter site account |
|
|
32
|
+
| `robots`, `themeColor` | Native meta tags |
|
|
33
|
+
| `url` | Site base only. The app computes `canonicalUrl`; it emits canonical and `og:url`. |
|
|
34
|
+
|
|
35
|
+
`toSeoHead` returns `{ title?, meta, links }`. No configured values produces
|
|
36
|
+
empty arrays. Absent/empty fields emit no corresponding tags. The default
|
|
37
|
+
social type/card are `website`/`summary_large_image`; use the existing head
|
|
38
|
+
component for article tags, alternate languages, JSON-LD, and other app-owned
|
|
39
|
+
metadata. Filter a converter attribute before replacing that same tag.
|
|
40
|
+
|
|
41
|
+
Preserve editor-owned settings through resolution; do not copy their initial
|
|
42
|
+
values into app constants that overwrite config. Derive content-owned title
|
|
43
|
+
and description from the same loaded entry or singleton as the visible page,
|
|
44
|
+
including Home/About. Pass that data to resolution or compose its current
|
|
45
|
+
values before conversion. A correct first render does not prove editability.
|
|
46
|
+
|
|
47
|
+
App values win only where intentionally required. Keep overrides together and
|
|
48
|
+
record their reason in the existing code or handoff, not a new ownership
|
|
49
|
+
registry. Set `image: undefined` to remove a
|
|
50
|
+
global image, or `robots: 'noindex'` for an editorial page before conversion. An
|
|
51
|
+
explicit `undefined` in a spread removes a field; use conditional spreads to
|
|
52
|
+
retain defaults for missing optional overrides. Resolve once, then compose;
|
|
53
|
+
do not resolve again after applying policy.
|
|
54
|
+
|
|
55
|
+
Pass a final absolute canonical URL from the app's production URL policy.
|
|
56
|
+
`new URL(pathname, seo.url).href` fits a root-hosted starter; preserve existing
|
|
57
|
+
base paths, domains, trailing slashes and query policy in other apps. Never use
|
|
58
|
+
the preview/request origin as a production canonical. Omit `canonicalUrl` to
|
|
59
|
+
emit neither canonical nor `og:url`.
|
|
60
|
+
|
|
61
|
+
For existing apps, inventory the current head owner and extend it in place.
|
|
62
|
+
Do not add duplicate tags or overwrite unrelated metadata. Framework-escape
|
|
63
|
+
attributes; never render a raw HTML string. Each new route must use the app's
|
|
64
|
+
SEO path, with route data where needed. Verify title, description, canonical,
|
|
65
|
+
robots and social values in built HTML, not only the browser tab title.
|
|
66
|
+
|
|
67
|
+
Imported JSON is a build snapshot. Studio config changes need sync and
|
|
68
|
+
rebuild/redeploy. Content freshness follows the app's SSR/prerender/cache
|
|
69
|
+
policy; changing a helper does not change that policy.
|
|
70
|
+
|
|
71
|
+
For SEO integration acceptance, use an authorized isolated project to change
|
|
72
|
+
one inherited setting and one content-owned value after the initial render.
|
|
73
|
+
Follow the app's sync/build/cache policy, then compare built HTML and the
|
|
74
|
+
hydrated head; verify intentional overrides remain unchanged. Restore the
|
|
75
|
+
test values. Include client navigation and Back where supported. Never mutate
|
|
76
|
+
customer production data for this check. If edits or rendering are unavailable,
|
|
77
|
+
report freshness unproven. `fimo validate` checks declared contracts, not rendered
|
|
78
|
+
head propagation; a green result or helper import is not this acceptance proof.
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Use this reference when `fimo describe --json` reports
|
|
4
4
|
`framework.slug: "sveltekit"`. SvelteKit keeps owning routes, load functions,
|
|
5
|
-
locale resolution, links, document metadata, and SEO
|
|
5
|
+
locale resolution, links, document metadata, and per-page SEO; Fimo supplies the
|
|
6
|
+
site-wide SEO defaults from Studio's Settings → SEO.
|
|
6
7
|
|
|
7
8
|
## Compatibility
|
|
8
9
|
|
|
@@ -12,7 +13,7 @@ SvelteKit 1 or Svelte 4 projects are compatible.
|
|
|
12
13
|
|
|
13
14
|
## Install both packages
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
SvelteKit-specific APIs live in `fimo-sveltekit`, installed at the same version
|
|
16
17
|
as `fimo`:
|
|
17
18
|
|
|
18
19
|
```bash
|
|
@@ -95,9 +96,10 @@ export async function load(event) {
|
|
|
95
96
|
<script lang="ts">
|
|
96
97
|
import { afterNavigate } from '$app/navigation';
|
|
97
98
|
import { FimoProvider } from 'fimo-sveltekit/components';
|
|
98
|
-
import type { LayoutData } from './$types';
|
|
99
99
|
import type { Snippet } from 'svelte';
|
|
100
100
|
|
|
101
|
+
import type { LayoutData } from './$types';
|
|
102
|
+
|
|
101
103
|
let { data, children }: { data: LayoutData; children: Snippet } = $props();
|
|
102
104
|
|
|
103
105
|
afterNavigate(() => {
|
|
@@ -110,6 +112,57 @@ export async function load(event) {
|
|
|
110
112
|
</FimoProvider>
|
|
111
113
|
```
|
|
112
114
|
|
|
115
|
+
## SEO defaults
|
|
116
|
+
|
|
117
|
+
Resolve SEO in the existing server load and return `seoHead`. Preserve the
|
|
118
|
+
load's other data, including labels. A content page resolves after its read:
|
|
119
|
+
`resolveSeoForPath(event.url.pathname, config, { article })`, applies app
|
|
120
|
+
overrides, and returns its complete `seoHead` using `toSeoHead`.
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
// src/routes/+layout.server.ts, or a content page's +page.server.ts
|
|
124
|
+
import { resolveSeoForPath, toSeoHead } from 'fimo/seo';
|
|
125
|
+
import config from '../../.fimo/config.json';
|
|
126
|
+
|
|
127
|
+
export function load({ url }) {
|
|
128
|
+
const seo = resolveSeoForPath(url.pathname, config);
|
|
129
|
+
return {
|
|
130
|
+
seoHead: toSeoHead(seo, {
|
|
131
|
+
canonicalUrl: seo?.url ? new URL(url.pathname, seo.url).href : undefined,
|
|
132
|
+
}),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Render the final merged route data from one head owner. A leaf load's
|
|
138
|
+
`seoHead` replaces the default head as a whole.
|
|
139
|
+
|
|
140
|
+
```svelte
|
|
141
|
+
<!-- Inside the existing root layout, alongside its provider and children -->
|
|
142
|
+
<script lang="ts">
|
|
143
|
+
import { page } from '$app/state';
|
|
144
|
+
const head = $derived(page.data.seoHead ?? { meta: [], links: [] });
|
|
145
|
+
</script>
|
|
146
|
+
|
|
147
|
+
<svelte:head>
|
|
148
|
+
<title>{head.title ?? 'My site'}</title>
|
|
149
|
+
{#each head.meta as attributes}<meta {...attributes} />{/each}
|
|
150
|
+
{#each head.links as attributes}<link {...attributes} />{/each}
|
|
151
|
+
</svelte:head>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Do not add a second page title beside root social tags. Use the same final
|
|
155
|
+
values for all tags and check client navigation, including returning to a page
|
|
156
|
+
without overrides. Existing apps can keep their current head component and
|
|
157
|
+
extend it in place.
|
|
158
|
+
|
|
159
|
+
The example canonical policy fits a root-hosted site; preserve existing
|
|
160
|
+
production domains, base paths and trailing slashes. Imported config needs
|
|
161
|
+
sync and rebuild/redeploy. Content freshness follows the app's load,
|
|
162
|
+
prerender and cache policy.
|
|
163
|
+
|
|
164
|
+
Read `references/frameworks/seo-head.md` for the field and composition contract.
|
|
165
|
+
|
|
113
166
|
Generated values are serialized at a `load` boundary and hydrated in the
|
|
114
167
|
component that renders them. Use `Text`, `RichText`, `Image`, `Video`, `Date`,
|
|
115
168
|
`DateTime`, `Boolean`, `Json`, and `Number` from
|
|
@@ -142,7 +195,7 @@ component, read Fimo preview environment variables, or inject Fimo scripts.
|
|
|
142
195
|
|
|
143
196
|
## Boundaries
|
|
144
197
|
|
|
145
|
-
- SvelteKit owns routing, history, 404s, locale URLs, and SEO.
|
|
198
|
+
- SvelteKit owns routing, history, 404s, locale URLs, and per-page SEO; the root layout renders Fimo's site-wide SEO defaults.
|
|
146
199
|
- `fimo-sveltekit/vite` owns dev source tagging only.
|
|
147
200
|
- `FimoProvider` owns labels and the optional Studio preview bridge.
|
|
148
201
|
- Do not add React, React Query, or a Vite SPA fallback to a SvelteKit project.
|
|
@@ -100,9 +100,9 @@ Pick the setup path from the evidence:
|
|
|
100
100
|
and adds only the Fimo dependency, `.fimo/project.json`, the `fimo` remote,
|
|
101
101
|
and `.fimo/config.json#runtime.framework`. It never overlays a template, so
|
|
102
102
|
the target must already contain the source.
|
|
103
|
-
- **Empty target, or an explicit framework conversion** — `fimo init`
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
- **Empty target, or an explicit framework conversion** — `fimo init` or
|
|
104
|
+
`fimo migrate init <dir>` with the chosen `--framework`. Both refuse a
|
|
105
|
+
non-empty target and write nothing when they refuse.
|
|
106
106
|
|
|
107
107
|
If authentication, organization selection, project creation, environment
|
|
108
108
|
resolution, linking, or the verification read fails, stop before workers and
|
|
@@ -151,7 +151,7 @@ report the exact failed command and setup requirement.
|
|
|
151
151
|
unresolved item with the source evidence, the owner action, and the
|
|
152
152
|
user-visible impact. Never claim completion while source content is
|
|
153
153
|
unwired.
|
|
154
|
-
- Prefer source code and exports over
|
|
154
|
+
- Prefer source code and exports over what a page renders. Use a public URL as
|
|
155
155
|
visual, SEO, route, and behavior evidence when better source material exists.
|
|
156
156
|
When the source defines an active CMS but its deployed records are unavailable,
|
|
157
157
|
rebuild published content from the public site only after the user explicitly
|
|
@@ -205,8 +205,12 @@ report the exact failed command and setup requirement.
|
|
|
205
205
|
- **source-backed**: source repository, export, downloaded HTML, CMS data,
|
|
206
206
|
or media folder. The source files are truth; the workers read them
|
|
207
207
|
directly.
|
|
208
|
-
- **url-only**: only a published URL.
|
|
209
|
-
|
|
208
|
+
- **url-only**: only a published URL. You read the site yourself: open each
|
|
209
|
+
route in a browser, let client-side rendering finish, and record the
|
|
210
|
+
sections, copy, images, links, and forms you actually see. Fetching HTML
|
|
211
|
+
without executing JavaScript is not evidence — a client-rendered page
|
|
212
|
+
returns an empty root element, which reads as a site with no content.
|
|
213
|
+
Never report a route as covered from a fetch that returned no sections.
|
|
210
214
|
- **hybrid**: source material plus a public URL. Treat source material as
|
|
211
215
|
truth and the URL as comparison evidence.
|
|
212
216
|
4. Read `references/questions-and-improvements.md`, finish its read-only
|
|
@@ -220,6 +224,10 @@ report the exact failed command and setup requirement.
|
|
|
220
224
|
- Content data/code workers -> `references/workers/content-execution.md`.
|
|
221
225
|
- Independent validator -> `references/workers/validator.md`.
|
|
222
226
|
- Next.js source -> `references/frameworks/nextjs.md`.
|
|
227
|
+
- Astro/SvelteKit SEO -> the target's `fimo-code` framework reference and
|
|
228
|
+
`frameworks/seo-head`. Preserve the existing head owner and URL policy;
|
|
229
|
+
follow its value-ownership and edit-and-render contract, preserving
|
|
230
|
+
intentional source overrides rather than freezing editor-owned values.
|
|
223
231
|
- React Router/Vite source -> load the target project's `fimo-code`
|
|
224
232
|
`frameworks/react-router`, `frameworks/vite-react`, and
|
|
225
233
|
`frameworks/hosting` references as applicable.
|
|
@@ -254,7 +262,8 @@ instead of inventing an ID:
|
|
|
254
262
|
|
|
255
263
|
`--source-platform` names what the site is migrated from (`wordpress`, `nextjs`,
|
|
256
264
|
`astro`, `react-router`, `webflow`, `framer`, `squarespace`, `wix`, `carrd`,
|
|
257
|
-
`other`); pass what the source
|
|
265
|
+
`other`); pass what the source proves, `unknown` only when nothing does. It is
|
|
266
|
+
explicit only — nothing detects it, and omitting it records `unknown`.
|
|
258
267
|
|
|
259
268
|
After setup, check `.fimo/config.json#runtime.framework` and the scaffold's
|
|
260
269
|
framework files before starting workers. A Next.js target must still have its
|
|
@@ -268,32 +277,23 @@ deploy happens only after successful local QA (see Completion and deployment).
|
|
|
268
277
|
|
|
269
278
|
## Command surface
|
|
270
279
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
- `fimo migrate
|
|
277
|
-
|
|
278
|
-
- `fimo migrate
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
reports, and final migration report; they do not bootstrap another JSON
|
|
286
|
-
registry.
|
|
287
|
-
|
|
288
|
-
Commands that perform actual data writes, all requiring the linked target:
|
|
280
|
+
`fimo migrate init <dir>` is the only migration subcommand. It sets the target
|
|
281
|
+
up and nothing else: it never reads, fetches, or renders the source site, and
|
|
282
|
+
it produces no evidence pack, draft, manifest, or scaffold to inspect. Reading
|
|
283
|
+
the source is your job, and every finding is yours to prove.
|
|
284
|
+
|
|
285
|
+
- `fimo migrate init <dir> --project-id <projectId>` — link an owner-supplied
|
|
286
|
+
project.
|
|
287
|
+
- `fimo migrate init <dir> --org <organizationId>` — create a new project.
|
|
288
|
+
- Both accept `--framework`, `--source-platform` (see Target setup),
|
|
289
|
+
`--install` / `--no-install`, `--agents` / `-a`, `--mode`, `--template-root`,
|
|
290
|
+
and `--json`; `-C <dir>` replaces the positional for an already-linked target.
|
|
291
|
+
|
|
292
|
+
The link/creation and its initial commit push are the only remote writes. Data
|
|
293
|
+
writes go through the normal commands against the linked target:
|
|
289
294
|
|
|
290
295
|
- `fimo schemas push`, `fimo assets upload`, `fimo entries create|update`,
|
|
291
296
|
`fimo singles update`, `fimo labels set|set-many`, `fimo forms push`.
|
|
292
|
-
- `fimo migrate init` (source-backed form): the project link/creation and
|
|
293
|
-
initial commit push described above. Pass `--source-platform <platform>`
|
|
294
|
-
(webflow, framer, squarespace, wix, carrd, wordpress, nextjs, astro,
|
|
295
|
-
react-router, other) when the source is known; URL crawls detect it.
|
|
296
|
-
|
|
297
297
|
- `fimo link`: project creation or selection plus the in-place adoption of a
|
|
298
298
|
copied source target.
|
|
299
299
|
- `fimo deploy` / `fimo publish` — owner-approved only.
|
|
@@ -378,9 +378,9 @@ Commands that perform actual data writes, all requiring the linked target:
|
|
|
378
378
|
- `references/workers/content-execution.md` - data import and code-wiring
|
|
379
379
|
contracts.
|
|
380
380
|
- `references/workers/validator.md` - independent fan-in validation.
|
|
381
|
-
-
|
|
382
|
-
older migration
|
|
383
|
-
|
|
381
|
+
- `scripts/apply-decision.mjs` and `scripts/write-migration-report.mjs` replay
|
|
382
|
+
an older JSON-ledger migration. A new migration writes the plain-text plan
|
|
383
|
+
and report instead; do not invoke them unless the user asks for that replay.
|
|
384
384
|
|
|
385
385
|
## Completion and deployment
|
|
386
386
|
|
|
@@ -119,7 +119,7 @@ Then use source headers, values, and repeated patterns:
|
|
|
119
119
|
- excerpt/summary/dek -> `text`
|
|
120
120
|
- image/photo/thumbnail/media/asset/file -> `media`, carrying the source alt on
|
|
121
121
|
the media value; never add a separate alt field (`references/media.md`)
|
|
122
|
-
- date/published/created/updated -> `date`; use `datetime` only when the
|
|
122
|
+
- date/published/created/updated -> `date`; use `datetime` only when the source
|
|
123
123
|
values carry a time and a UTC offset, which `datetime` requires
|
|
124
124
|
- event start/end time -> `datetime`
|
|
125
125
|
- price/amount/rating/order/count -> `number`
|
|
@@ -86,6 +86,13 @@ behavior in place; when one cannot be preserved, record an explicit gap with
|
|
|
86
86
|
the affected routes instead of shipping pages that silently lost their share
|
|
87
87
|
metadata.
|
|
88
88
|
|
|
89
|
+
Before adopting Fimo SEO values, load the target's `fimo-code` reference
|
|
90
|
+
`frameworks/next/seo`. Record which fields remain app-owned and which become
|
|
91
|
+
editor-managed. Preserve section robots policies, title templates and
|
|
92
|
+
file-based images; verify the rendered result on representative routes. Link
|
|
93
|
+
the established route pattern in the project's instructions so later pages
|
|
94
|
+
reuse it. Do not replace an existing SEO library or add a universal merge wrapper.
|
|
95
|
+
|
|
89
96
|
## Fimo connection
|
|
90
97
|
|
|
91
98
|
Follow the target project's `fimo-code` Next.js reference and render its
|
|
@@ -9,18 +9,16 @@ assets, schemas, entries, and forms, or the gaps are owner-visible unresolved
|
|
|
9
9
|
items.
|
|
10
10
|
|
|
11
11
|
Every data-plane write in this contract targets the linked project from
|
|
12
|
-
workflow Phase 0.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
When no owner-supplied target exists, the writes stay unresolved owner
|
|
16
|
-
actions; do not fake a link to make them pass.
|
|
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
|
|
14
|
+
owner actions; do not fake a link to make them pass.
|
|
17
15
|
|
|
18
16
|
## Media Files
|
|
19
17
|
|
|
20
18
|
Discovery must include:
|
|
21
19
|
|
|
22
20
|
- local export media folders
|
|
23
|
-
- media URLs
|
|
21
|
+
- media URLs found in the source HTML/CSS
|
|
24
22
|
- CMS media fields
|
|
25
23
|
- SEO/share images
|
|
26
24
|
- downloadable files linked from pages or entries
|
|
@@ -4,9 +4,10 @@ New migrations do not create a canonical `manifest.json`. The coordinator uses
|
|
|
4
4
|
the readable `.fimo/migration/migration-plan.md` and
|
|
5
5
|
`.fimo/migration/migration-report.md` instead.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
A pre-existing project may still contain `.fimo/migrations/current/manifest.json`
|
|
8
|
+
from a retired URL crawl. Nothing writes it any more, and it was never
|
|
9
|
+
trustworthy on a client-rendered site: read it as a hint at most, re-verify
|
|
10
|
+
every claim against the source, and do not copy it into another registry.
|
|
10
11
|
|
|
11
12
|
JSON remains appropriate for actual Fimo artifacts: schema files and the
|
|
12
13
|
content payloads passed to data-plane commands. It is not needed to describe
|
|
@@ -67,6 +67,12 @@ items.
|
|
|
67
67
|
categories, tags, redirects, and locales are preserved when present.
|
|
68
68
|
- Existing SEO, OG, and social behavior - including dynamic OG image routes -
|
|
69
69
|
is preserved or explicitly reported as a gap.
|
|
70
|
+
- Editor-owned SEO remains connected to its setting, entry, or singleton.
|
|
71
|
+
Inspect the implementation lane's before/after edit-and-render receipt from
|
|
72
|
+
an authorized isolated target, including preserved intentional overrides and
|
|
73
|
+
required rebuild/cache steps. If absent, report freshness unproven and hand
|
|
74
|
+
back a bounded test; this read-only validator does not mutate content.
|
|
75
|
+
`fimo validate` and matching initial tags do not prove later edits propagate.
|
|
70
76
|
- When the source has no low-risk SEO or social value, safe defaults derived
|
|
71
77
|
from verified page/site data are present or the missing behavior is reported;
|
|
72
78
|
the migration must not invent marketing claims.
|
|
@@ -94,7 +94,7 @@ The question should sound like this:
|
|
|
94
94
|
|
|
95
95
|
If the owner chooses the public website, stay inside the selected route scope.
|
|
96
96
|
Public retrieval does not authorize private endpoint discovery, credential use,
|
|
97
|
-
or a broader
|
|
97
|
+
or a broader sweep. Record the URL, retrieval time, redirects, and every field
|
|
98
98
|
or relation that remains unknown.
|
|
99
99
|
|
|
100
100
|
## Ask what happens outside a partial migration
|
|
@@ -18,12 +18,11 @@ ask a generic optimization question.
|
|
|
18
18
|
1. Confirm the target path. The target is a separate directory; the source
|
|
19
19
|
checkout remains read-only evidence.
|
|
20
20
|
2. Initialize or reuse exactly one linked Fimo target before workers start:
|
|
21
|
-
- URL migration: `fimo migrate init <source-url> <target-dir> --framework <framework>`
|
|
22
21
|
- link an existing project: `fimo migrate init <target-dir> --project-id <projectId> --framework <framework>`
|
|
23
22
|
- create a project: `fimo migrate init <target-dir> --org <organizationId> --framework <framework>`
|
|
24
23
|
- add `--source-platform <platform>` when the source platform is known
|
|
25
24
|
(webflow, framer, squarespace, wix, carrd, wordpress, nextjs, astro,
|
|
26
|
-
react-router, other)
|
|
25
|
+
react-router, other). Nothing detects it; omitting it records `unknown`.
|
|
27
26
|
Use the detected source framework for source-backed migrations. A framework
|
|
28
27
|
conversion requires an explicit user choice; URL-only and rebuild
|
|
29
28
|
migrations ask the user which framework to use. Never choose a framework by
|
|
@@ -78,9 +77,12 @@ Treat absent/private fields as unknown, keep uncertain fields optional, and do
|
|
|
78
77
|
not turn sampled values into enums. Bounded retrieval scripts are accelerators
|
|
79
78
|
the planner may adapt or replace, never schema decision makers.
|
|
80
79
|
|
|
81
|
-
For URL-only migrations,
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
For URL-only migrations, read the published site yourself with a browser. Open
|
|
81
|
+
every selected route, let client-side rendering finish, and record the sections,
|
|
82
|
+
copy, images, links, and forms you actually see. An HTML response fetched
|
|
83
|
+
without executing JavaScript is not evidence: a client-rendered page returns an
|
|
84
|
+
empty root element, and treating that as the page reports an empty site as a
|
|
85
|
+
complete one.
|
|
84
86
|
|
|
85
87
|
## Phase 2: Fan out workers
|
|
86
88
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Agents
|
|
2
2
|
|
|
3
|
-
Project agents are versioned bundles from the project's repository. Studio lets project members inspect their configuration and run history, while project managers can start, stop, and
|
|
3
|
+
Project agents are versioned bundles from the project's repository. Studio lets project members inspect their configuration and run history, while project managers can start, stop, resume, and delete them.
|
|
4
4
|
|
|
5
5
|
## Open an agent
|
|
6
6
|
|
|
@@ -20,6 +20,12 @@ A stopped agent shows **Paused** in the header. **Resume** makes the same trigge
|
|
|
20
20
|
|
|
21
21
|
Only project managers see Run, Stop, and Resume. Other project members can still see schedule timing, status, settings, and run history.
|
|
22
22
|
|
|
23
|
+
## Delete an agent
|
|
24
|
+
|
|
25
|
+
Project managers can open **Agent actions** beside Run/Stop, choose **Delete agent**, and confirm. Deletion stops planned or running work and commits removal of the agent bundle from `main`. Recorded runs remain in history. Remove the bundle from a local checkout before deploying again, or that deployment recreates the agent.
|
|
26
|
+
|
|
27
|
+
If a run cannot be stopped or `main` changes before deletion commits, the definition stays intact and the agent may remain paused. Reload and retry, or resume it if you want to keep it.
|
|
28
|
+
|
|
23
29
|
## Inspect runs
|
|
24
30
|
|
|
25
31
|
Open **Runs** on an agent to see only that bundle's history. Select a run to read its status, report, captured changes, and any question or review state that needs attention.
|