fimo 0.21.0-staging.2 → 0.21.0-staging.3

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 (56) hide show
  1. package/assets/agent-templates/_default/GOAL.md +10 -0
  2. package/assets/agent-templates/_default/capabilities.yaml +10 -0
  3. package/assets/content-templates/shared/types.eta +1 -1
  4. package/assets/skills/fimo-cli/SKILL.md +1 -1
  5. package/assets/skills/fimo-cli/references/agents.md +85 -32
  6. package/assets/skills/fimo-cli/references/deploy.md +9 -0
  7. package/assets/skills/fimo-cli/references/domains.md +4 -4
  8. package/assets/skills/fimo-cli/references/init.md +4 -0
  9. package/assets/skills/fimo-cli/references/locales.md +1 -1
  10. package/assets/skills/fimo-cli/references/mcp.md +1 -1
  11. package/assets/skills/fimo-cli/references/media.md +18 -1
  12. package/assets/skills/fimo-code/references/frameworks/next/locales.md +4 -4
  13. package/assets/skills/fimo-code/references/frameworks/react-router.md +2 -1
  14. package/assets/skills/fimo-code/references/frameworks/sveltekit.md +3 -5
  15. package/assets/skills/fimo-code/references/locales.md +2 -2
  16. package/assets/skills/fimo-studio/references/billing-and-credits.md +6 -4
  17. package/assets/skills/fimo-studio/references/preview-and-responsive.md +1 -0
  18. package/dist/cli/bundle.json +1 -1
  19. package/dist/cli/index.js +102 -101
  20. package/dist/runtime/app/FimoProviders.js +8 -1
  21. package/dist/runtime/app/FimoScripts.d.ts +0 -1
  22. package/dist/runtime/app/FimoScripts.js +1 -4
  23. package/dist/runtime/next/client.d.ts +2 -2
  24. package/dist/runtime/next/client.js +1 -1
  25. package/dist/runtime/next/provider.d.ts +0 -5
  26. package/dist/runtime/next/provider.js +21 -6
  27. package/dist/runtime/preview/script.d.ts +3 -0
  28. package/dist/runtime/preview/script.js +14 -0
  29. package/dist/runtime/react/primitives/contracts.d.ts +7 -1
  30. package/dist/runtime/sveltekit/preview.d.ts +1 -2
  31. package/dist/runtime/sveltekit/preview.js +1 -14
  32. package/dist/scripts/sync-schemas.js +81 -0
  33. package/package.json +6 -1
  34. package/templates/astro/AGENTS.md +1 -1
  35. package/templates/astro/package.json +2 -1
  36. package/templates/astro/pnpm-workspace.yaml +6 -2
  37. package/templates/nextjs/.fimo/config.json +1 -2
  38. package/templates/nextjs/AGENTS.md +5 -15
  39. package/templates/nextjs/next.config.ts +3 -1
  40. package/templates/nextjs/package.json +2 -1
  41. package/templates/nextjs/pnpm-workspace.yaml +6 -2
  42. package/templates/nextjs/src/app/layout.tsx +16 -0
  43. package/templates/nextjs/src/locales.ts +3 -6
  44. package/templates/react-router/AGENTS.md +1 -1
  45. package/templates/react-router/package.json +3 -2
  46. package/templates/react-router/pnpm-workspace.yaml +6 -6
  47. package/templates/react-router/src/vite-env.d.ts +0 -1
  48. package/templates/sveltekit/AGENTS.md +1 -1
  49. package/templates/sveltekit/package.json +2 -1
  50. package/templates/sveltekit/pnpm-workspace.yaml +6 -2
  51. package/templates/nextjs/src/app/(default)/layout.tsx +0 -10
  52. package/templates/nextjs/src/app/[locale]/layout.tsx +0 -22
  53. package/templates/nextjs/src/app/[locale]/page.tsx +0 -1
  54. package/templates/nextjs/src/components/Document.tsx +0 -26
  55. package/templates/nextjs/src/components/FimoPreviewBridge.tsx +0 -13
  56. /package/templates/nextjs/src/app/{(default)/page.tsx → page.tsx} +0 -0
@@ -14,6 +14,7 @@ import { getFimoTextDirection, resolveFimoLocale, toHtmlLang } from '../i18n/loc
14
14
  import { ScreenshotProvider } from '../iframe/ScreenshotProvider.js';
15
15
  import { getSafePreviewNavigationPath, isPreviewRuntimeEnabled } from '../preview/bridge.js';
16
16
  import { getPreviewLocationChange, getPreviewParentOrigin } from '../preview/location.js';
17
+ import { ensurePreviewScript } from '../preview/script.js';
17
18
  import { getActiveRouterRoutes } from '../react-router/active-routes.js';
18
19
  import { matchFimoRoute } from '../routes/index.js';
19
20
  import { OptionalTracking } from '../t/OptionalTracking.js';
@@ -170,7 +171,8 @@ export function FimoProviders({ children, locale }) {
170
171
  const activeLocale = useMemo(() => locale ?? getRouteLocale(location.pathname), [locale, location.pathname]);
171
172
  const activeDir = getFimoTextDirection(activeLocale);
172
173
  // @ts-ignore - import.meta.env is provided by Vite and React Router.
173
- const previewEnabled = isPreviewRuntimeEnabled(import.meta.env.VITE_PREVIEW_SCRIPT_URL);
174
+ const previewScriptUrl = import.meta.env.VITE_PREVIEW_SCRIPT_URL;
175
+ const previewEnabled = isPreviewRuntimeEnabled(previewScriptUrl);
174
176
  useEffect(() => {
175
177
  if (typeof document === 'undefined') {
176
178
  return;
@@ -178,6 +180,11 @@ export function FimoProviders({ children, locale }) {
178
180
  document.documentElement.lang = toHtmlLang(activeLocale);
179
181
  document.documentElement.dir = activeDir;
180
182
  }, [activeDir, activeLocale]);
183
+ useEffect(() => {
184
+ if (previewEnabled) {
185
+ ensurePreviewScript(previewScriptUrl);
186
+ }
187
+ }, [previewEnabled, previewScriptUrl]);
181
188
  return (_jsx(ErrorBoundary, { FallbackComponent: AppErrorBoundary, onError: onError, children: _jsx(EnsureQueryClient, { children: _jsx(FimoLocaleProvider, { value: {
182
189
  ...localeResolution,
183
190
  locale: activeLocale,
@@ -3,7 +3,6 @@ import 'virtual:fimo-overlay-hmr';
3
3
  * Renders extra <script> tags in <head>:
4
4
  * - Dev overlay runtime (window.error / unhandledrejection bridge to parent)
5
5
  * - JSON-LD Schema.org Organization + WebSite (when seo.siteName + seo.url set)
6
- * - Preview script (when VITE_PREVIEW_SCRIPT_URL is set, e.g. iframe preview mode)
7
6
  *
8
7
  * The overlay runtime is embedded inline via the `virtual:fimo-overlay-runtime`
9
8
  * module (resolved by `overlayPlugin` in `fimo/vite`). The previous approach
@@ -33,7 +33,6 @@ function buildSiteSchemas() {
33
33
  * Renders extra <script> tags in <head>:
34
34
  * - Dev overlay runtime (window.error / unhandledrejection bridge to parent)
35
35
  * - JSON-LD Schema.org Organization + WebSite (when seo.siteName + seo.url set)
36
- * - Preview script (when VITE_PREVIEW_SCRIPT_URL is set, e.g. iframe preview mode)
37
36
  *
38
37
  * The overlay runtime is embedded inline via the `virtual:fimo-overlay-runtime`
39
38
  * module (resolved by `overlayPlugin` in `fimo/vite`). The previous approach
@@ -41,8 +40,6 @@ function buildSiteSchemas() {
41
40
  * since framework mode bypasses `index.html` entirely.
42
41
  */
43
42
  export function FimoScripts() {
44
- // @ts-ignore - import.meta.env is a Vite feature
45
- const previewScriptUrl = import.meta.env.VITE_PREVIEW_SCRIPT_URL;
46
43
  const siteSchemas = buildSiteSchemas();
47
- return (_jsxs(_Fragment, { children: [runtime ? _jsx("script", { type: "module", dangerouslySetInnerHTML: { __html: runtime } }) : null, previewScriptUrl ? _jsx("script", { src: previewScriptUrl, defer: true }) : null, siteSchemas.map((schema, index) => (_jsx("script", { type: "application/ld+json", dangerouslySetInnerHTML: { __html: JSON.stringify(schema) } }, index)))] }));
44
+ return (_jsxs(_Fragment, { children: [runtime ? _jsx("script", { type: "module", dangerouslySetInnerHTML: { __html: runtime } }) : null, siteSchemas.map((schema, index) => (_jsx("script", { type: "application/ld+json", dangerouslySetInnerHTML: { __html: JSON.stringify(schema) } }, index)))] }));
48
45
  }
@@ -22,7 +22,7 @@ export { Text } from '../react/primitives/editable/Text.js';
22
22
  export { Video } from '../react/primitives/editable/Video.js';
23
23
  export type { BoolOps, DateOps, Field, Fields, FilterFor, FimoPart, FimoPolymorphicReference, FimoReference, FimoRichTextContent, FimoSource, NullOnlyOps, NumberOps, Populate, Populated, PopulatedResult, Projected, ProjectedWithPopulate, Query, ReferenceField, ReferenceMap, ScalarOps, Sort, SortField, StringOps, Where, WithReferences, } from '../content/index.js';
24
24
  export type { FimoRichTextComponents, FimoRichTextMarkProps, FimoRichTextNodeProps, } from '../react/primitives/contracts.js';
25
- export { FimoPreviewBridge, FimoProvider, useLabels } from './provider.js';
26
- export type { FimoPreviewBridgeProps, FimoProviderProps } from './provider.js';
25
+ export { FimoProvider, useLabels } from './provider.js';
26
+ export type { FimoProviderProps } from './provider.js';
27
27
  export type { Labels, LabelsSnapshot } from '../labels/core.js';
28
28
  //# sourceMappingURL=client.d.ts.map
@@ -22,4 +22,4 @@ export { RichText } from '../react/primitives/editable/RichText.js';
22
22
  export { StaticImage } from '../react/primitives/renderers/StaticImage.js';
23
23
  export { Text } from '../react/primitives/editable/Text.js';
24
24
  export { Video } from '../react/primitives/editable/Video.js';
25
- export { FimoPreviewBridge, FimoProvider, useLabels } from './provider.js';
25
+ export { FimoProvider, useLabels } from './provider.js';
@@ -8,11 +8,6 @@ export interface FimoProviderProps {
8
8
  queryClient?: QueryClient;
9
9
  }
10
10
  export declare function FimoProvider({ children, labels, locale, queryClient }: FimoProviderProps): import("react/jsx-runtime").JSX.Element;
11
- export interface FimoPreviewBridgeProps {
12
- readonly navigate: (to: string) => unknown;
13
- readonly pathname: string;
14
- }
15
- export declare function FimoPreviewBridge({ navigate, pathname }: FimoPreviewBridgeProps): ReactNode;
16
11
  export declare function useNextContentLocale(requestedLocale: string | undefined, defaultLocale: string): string;
17
12
  export declare function useLabels(): Labels;
18
13
  //# sourceMappingURL=provider.d.ts.map
@@ -1,8 +1,11 @@
1
1
  'use client';
2
- import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
4
- import { createContext, useContext, useEffect, useMemo, useState } from 'react';
4
+ import { useRouter as usePagesRouter } from 'next/compat/router.js';
5
+ import { usePathname } from 'next/navigation.js';
6
+ import { createContext, Suspense, useCallback, useContext, useEffect, useMemo, useState } from 'react';
5
7
  import { createLabels } from '../labels/core.js';
8
+ import { ensurePreviewScript } from '../preview/script.js';
6
9
  import { connectNextPreview } from './preview.js';
7
10
  /**
8
11
  * Last resort when an application renders `FimoProvider` without a locale and
@@ -16,13 +19,25 @@ export function FimoProvider({ children, labels, locale, queryClient }) {
16
19
  const [client] = useState(() => queryClient ?? new QueryClient());
17
20
  const activeLocale = locale?.trim() || labels?.locale;
18
21
  const value = useMemo(() => ({ labels, locale: activeLocale }), [activeLocale, labels]);
19
- return (_jsx(FimoNextContext.Provider, { value: value, children: _jsx(QueryClientProvider, { client: client, children: children }) }));
22
+ const previewScriptUrl = process.env.NEXT_PUBLIC_FIMO_PREVIEW_SCRIPT_URL;
23
+ return (_jsx(FimoNextContext.Provider, { value: value, children: _jsxs(QueryClientProvider, { client: client, children: [previewScriptUrl ? (_jsx(Suspense, { fallback: null, children: _jsx(FimoPreviewRuntime, { previewScriptUrl: previewScriptUrl }) })) : null, children] }) }));
20
24
  }
21
- export function FimoPreviewBridge({ navigate, pathname }) {
25
+ function FimoPreviewRuntime({ previewScriptUrl }) {
22
26
  const context = useContext(FimoNextContext);
23
27
  const locale = context.locale ?? UNRESOLVED_LOCALE;
24
- const previewScriptUrl = process.env.NEXT_PUBLIC_FIMO_PREVIEW_SCRIPT_URL;
25
- useEffect(() => connectNextPreview({ locale, navigate, pathname, previewScriptUrl }), [locale, navigate, pathname, previewScriptUrl]);
28
+ const appPathname = usePathname();
29
+ const pagesRouter = usePagesRouter();
30
+ const pathname = appPathname ?? pagesRouter?.asPath.split(/[?#]/, 1)[0] ?? '/';
31
+ const navigate = useCallback((to) => {
32
+ if (pagesRouter) {
33
+ return pagesRouter.push(to);
34
+ }
35
+ window.history.pushState(null, '', to);
36
+ }, [pagesRouter]);
37
+ useEffect(() => {
38
+ ensurePreviewScript(previewScriptUrl);
39
+ return connectNextPreview({ locale, navigate, pathname, previewScriptUrl });
40
+ }, [locale, navigate, pathname, previewScriptUrl]);
26
41
  return null;
27
42
  }
28
43
  export function useNextContentLocale(requestedLocale, defaultLocale) {
@@ -0,0 +1,3 @@
1
+ /** Load the platform preview script once. Empty configuration keeps preview disabled. */
2
+ export declare function ensurePreviewScript(src: string | undefined, target?: Document): boolean;
3
+ //# sourceMappingURL=script.d.ts.map
@@ -0,0 +1,14 @@
1
+ /** Load the platform preview script once. Empty configuration keeps preview disabled. */
2
+ export function ensurePreviewScript(src, target = document) {
3
+ if (!src) {
4
+ return false;
5
+ }
6
+ const exists = Array.from(target.scripts).some((script) => script.getAttribute('src') === src);
7
+ if (!exists) {
8
+ const script = target.createElement('script');
9
+ script.src = src;
10
+ script.defer = true;
11
+ target.head.appendChild(script);
12
+ }
13
+ return true;
14
+ }
@@ -66,7 +66,13 @@ export interface RichTextProps extends Omit<ComponentPropsWithoutRef<'div'>, 'ch
66
66
  value: FimoRichText | null | undefined;
67
67
  components?: FimoRichTextComponents;
68
68
  }
69
- export type StaticImageProps = Omit<ComponentPropsWithoutRef<'img'>, 'children'> & {
69
+ export type StaticImageProps = Omit<ComponentPropsWithoutRef<'img'>, 'children' | 'src'> & {
70
+ /**
71
+ * Direct URL to the image. React's own `img` typings widened `src` to accept
72
+ * a Blob; this renderer resolves a URL through the optimizer, so it stays a
73
+ * string. Same reason `BaseVideoProps` omits `src`.
74
+ */
75
+ src?: string;
70
76
  /** Image quality (1-100). Defaults to 85. */
71
77
  quality?: number;
72
78
  /** Resize fit mode. Also maps to CSS object-fit. Defaults to 'scale-down'. */
@@ -1,3 +1,4 @@
1
+ export { ensurePreviewScript } from '../preview/script.js';
1
2
  export interface PreviewNavigation {
2
3
  /** SvelteKit `goto` — the app router stays in charge of the transition. */
3
4
  goto: (to: string) => unknown;
@@ -6,8 +7,6 @@ export interface PreviewNavigation {
6
7
  /** Optional app-owned locale resolver, evaluated for every bridge message. */
7
8
  locale?: () => string | undefined;
8
9
  }
9
- /** Load the platform preview script once. Empty configuration keeps preview disabled. */
10
- export declare function ensurePreviewScript(src: string | undefined): boolean;
11
10
  /**
12
11
  * Report where the app is now, and in which locale. Studio keeps its URL,
13
12
  * route selector and content locale in sync from this.
@@ -1,18 +1,5 @@
1
1
  import { getDocumentLocale, getPreviewLocationChange, getPreviewParentOrigin } from '../shared/preview-location.js';
2
- /** Load the platform preview script once. Empty configuration keeps preview disabled. */
3
- export function ensurePreviewScript(src) {
4
- if (!src) {
5
- return false;
6
- }
7
- const exists = Array.from(document.scripts).some((script) => script.getAttribute('src') === src);
8
- if (!exists) {
9
- const script = document.createElement('script');
10
- script.src = src;
11
- script.defer = true;
12
- document.head.appendChild(script);
13
- }
14
- return true;
15
- }
2
+ export { ensurePreviewScript } from '../preview/script.js';
16
3
  /**
17
4
  * Report where the app is now, and in which locale. Studio keeps its URL,
18
5
  * route selector and content locale in sync from this.
@@ -25,6 +25,23 @@ const SCHEMA_DEFINITION_SCHEMA = z.object({
25
25
  i18n: z.object({ enabled: z.boolean().optional() }).optional(),
26
26
  fields: z.record(z.string(), z.unknown()).optional(),
27
27
  });
28
+ const RUNTIME_TYPE_IMPORT_ORDER = [
29
+ 'Fields',
30
+ 'FimoBoolean',
31
+ 'FimoMedia',
32
+ 'FimoPolymorphicReference',
33
+ 'FimoReference',
34
+ 'FimoRichText',
35
+ 'FimoRichTextContent',
36
+ 'FimoString',
37
+ 'Populate',
38
+ 'PopulatedResult',
39
+ 'ProjectedWithPopulate',
40
+ 'Query',
41
+ 'Sort',
42
+ 'Where',
43
+ 'WithReferences',
44
+ ];
28
45
  const CONTENT_TEMPLATE_PATHS = {
29
46
  types: { current: 'shared/types.eta', legacy: 'types-template.eta' },
30
47
  sharedServer: { current: 'shared/server.eta' },
@@ -335,6 +352,69 @@ function referenceImportsFor(schema, fields) {
335
352
  }
336
353
  return [...imports.values()].sort((a, b) => a.pascal.localeCompare(b.pascal));
337
354
  }
355
+ function collectFieldRuntimeTypeImports(field, imports) {
356
+ if (!field || typeof field !== 'object' || Array.isArray(field)) {
357
+ return;
358
+ }
359
+ const definition = field;
360
+ switch (definition.type) {
361
+ case 'boolean':
362
+ imports.add('FimoBoolean');
363
+ return;
364
+ case 'media':
365
+ imports.add('FimoMedia');
366
+ return;
367
+ case 'reference':
368
+ imports.add(Array.isArray(definition.targets) && definition.targets.length > 0
369
+ ? 'FimoPolymorphicReference'
370
+ : 'FimoReference');
371
+ return;
372
+ case 'richtext':
373
+ imports.add('FimoRichText');
374
+ imports.add('FimoRichTextContent');
375
+ return;
376
+ case 'blocks': {
377
+ const schema = definition.schema;
378
+ if (!schema || typeof schema !== 'object' || Array.isArray(schema)) {
379
+ return;
380
+ }
381
+ const blockSchema = schema;
382
+ const fieldGroups = Array.isArray(blockSchema.oneOf)
383
+ ? blockSchema.oneOf.map((variant) => variant && typeof variant === 'object' && !Array.isArray(variant)
384
+ ? variant.fields
385
+ : undefined)
386
+ : [blockSchema.fields];
387
+ for (const fields of fieldGroups) {
388
+ if (!fields || typeof fields !== 'object' || Array.isArray(fields)) {
389
+ continue;
390
+ }
391
+ for (const nestedField of Object.values(fields)) {
392
+ collectFieldRuntimeTypeImports(nestedField, imports);
393
+ }
394
+ }
395
+ return;
396
+ }
397
+ default:
398
+ return;
399
+ }
400
+ }
401
+ function runtimeTypeImportsFor(fields) {
402
+ const imports = new Set([
403
+ 'Fields',
404
+ 'FimoString',
405
+ 'Populate',
406
+ 'PopulatedResult',
407
+ 'ProjectedWithPopulate',
408
+ 'Query',
409
+ 'Sort',
410
+ 'Where',
411
+ 'WithReferences',
412
+ ]);
413
+ for (const field of Object.values(fields)) {
414
+ collectFieldRuntimeTypeImports(field, imports);
415
+ }
416
+ return RUNTIME_TYPE_IMPORT_ORDER.filter((typeImport) => imports.has(typeImport));
417
+ }
338
418
  function schemaToModel(schema, localizedByUid) {
339
419
  const fields = normalizeFields(schema.fields ?? {});
340
420
  return {
@@ -353,6 +433,7 @@ function schemaToModel(schema, localizedByUid) {
353
433
  .map(([fieldName]) => fieldName),
354
434
  fields,
355
435
  referenceImports: referenceImportsFor(schema, fields),
436
+ runtimeTypeImports: runtimeTypeImportsFor(fields),
356
437
  };
357
438
  }
358
439
  export function syncSchemas(options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fimo",
3
- "version": "0.21.0-staging.2",
3
+ "version": "0.21.0-staging.3",
4
4
  "description": "Fimo CLI - create, deploy, and manage Fimo projects",
5
5
  "bin": {
6
6
  "fimo": "dist/cli/index.js"
@@ -168,6 +168,7 @@
168
168
  "better-auth": "1.6.25",
169
169
  "cheerio": "^1.0.0",
170
170
  "commander": "^13.1.0",
171
+ "next": "15.5.20",
171
172
  "open": "^10.1.2",
172
173
  "react": "^19.2.4",
173
174
  "react-dom": "^19.2.4",
@@ -183,6 +184,7 @@
183
184
  "@sveltejs/kit": "^2.0.0",
184
185
  "@tanstack/react-query": "^5.80.6",
185
186
  "astro": "^5.0.0 || ^6.0.0 || ^7.0.0",
187
+ "next": "^15.0.0 || ^16.0.0",
186
188
  "react": "^18.2.0 || ^19.0.0",
187
189
  "react-dom": "^18.2.0 || ^19.0.0",
188
190
  "react-router": "^7.0.0 || ^8.0.0",
@@ -199,6 +201,9 @@
199
201
  "astro": {
200
202
  "optional": true
201
203
  },
204
+ "next": {
205
+ "optional": true
206
+ },
202
207
  "react": {
203
208
  "optional": true
204
209
  },
@@ -27,7 +27,7 @@ a code-only task, or use `npx fimo@latest` for project-local code generation and
27
27
  ## Project rules
28
28
 
29
29
  - **Deploy is on-demand**, not a save step. Batch related edits into one deploy.
30
- - With pnpm, run `pnpm install --config.dangerouslyAllowAllBuilds=true`; a bare install can skip the build scripts required by Fimo and the framework toolchain.
30
+ - Use the selected package manager's committed build-script policy. pnpm projects pin `pnpm@10.26.0` and approve `esbuild` and `fimo` through `pnpm-workspace.yaml#allowBuilds`; Bun projects trust the same packages through `package.json#trustedDependencies`. Run a plain install with the selected manager so local installation matches Preview and production publishing. Review new dependencies before extending the policy; all three paths stop on unreviewed scripts.
31
31
  - Treat the user's language request as part of setup. The first explicitly requested locale is the primary locale; put it first and set it as `i18n.defaultLocale` in `.fimo/config.json`. If no language is requested, keep `en` and state that choice. Astro reads this configuration directly, keeps the default locale unprefixed, and prefixes the others.
32
32
  - Preserve both the unprefixed default pages and the `[locale]` page tree. Astro has no optional single-segment file route, so the paired native pages keep one-locale URLs clean and allow another locale without changing the route shape. Use `Astro.currentLocale` for Fimo content reads, `getLabels`, and document language.
33
33
  - Keep `.fimo/config.json#routes` as Studio metadata aligned with Astro's page files. It does not configure Astro routing.
@@ -18,5 +18,6 @@
18
18
  },
19
19
  "engines": {
20
20
  "node": ">=22.22.0"
21
- }
21
+ },
22
+ "packageManager": "pnpm@10.26.0"
22
23
  }
@@ -1,4 +1,8 @@
1
- # Build approval is handled by Fimo-controlled install commands. Do not add a
2
- # package-level allowlist because Fimo installs with dangerouslyAllowAllBuilds.
1
+ # Keep dependency-script decisions explicit across local, Preview, and production installs.
2
+
3
+ strictDepBuilds: true
4
+ allowBuilds:
5
+ esbuild: true
6
+ fimo: true
3
7
 
4
8
  packages: []
@@ -7,8 +7,7 @@
7
7
  "routes": {
8
8
  "home": {
9
9
  "label": "Home",
10
- "path": "/:locale",
11
- "params": { "locale": { "type": "locale", "optional": true } }
10
+ "path": "/"
12
11
  }
13
12
  },
14
13
  "version": "4",
@@ -35,24 +35,14 @@ The scaffolded homepage is disposable. Replace it on the first real generation.
35
35
  ## Project rules
36
36
 
37
37
  - **Deploy is on-demand**, not a save step. Batch related edits into one deploy.
38
- - With pnpm, run `pnpm install --config.dangerouslyAllowAllBuilds=true`; a bare install can skip the build scripts required by Fimo and the framework toolchain.
39
- - Treat the user's language request as part of setup. The first explicitly requested locale is the primary locale; put it first and set it as `i18n.defaultLocale` in `.fimo/config.json`, with every requested locale in `i18n.locales`. If no language is requested, keep `en` and state that choice. That file is the only place to change: `src/locales.ts` reads it, so the served language, `<html lang>`, and the prefixed URLs follow. Never introduce a default-locale environment variable.
40
- - Preserve the unprefixed `app/(default)` route group and the native `app/[locale]` boundary. Each is its own root layout, so each renders `src/components/Document.tsx` with the locale that tree serves; that is what makes `<html lang>` and the Fimo locale context correct on both. Mirror new routes in both groups when they are localized. Next.js has no optional single-segment folder, so do not replace this small pattern with middleware, rewrites, or a catch-all locale router.
41
- - Keep the client-only `src/components/FimoPreviewBridge.tsx` inside `Document`. It reports the native Next pathname and settled locale to Studio and sends Studio navigation through Next's router; keep Next imports out of Fimo's shared runtime.
42
- - Keep `.fimo/config.json#routes` as Studio metadata, not as the Next.js router. In that metadata, `params.locale.optional: true` means omit the configured default locale from the URL; use `optional: false` only when every locale, including the default, must be prefixed.
38
+ - Use the selected package manager's committed build-script policy. pnpm projects pin `pnpm@10.26.0` and approve `esbuild` and `fimo` through `pnpm-workspace.yaml#allowBuilds`; Bun projects trust the same packages through `package.json#trustedDependencies`. Run a plain install with the selected manager so local installation matches Preview and production publishing. Review new dependencies before extending the policy; all three paths stop on unreviewed scripts.
39
+ - Treat the user's language request as part of setup. The first explicitly requested locale is the primary locale; put it first and set it as `i18n.defaultLocale` in `.fimo/config.json`, with every requested locale in `i18n.locales`. If no language is requested, keep `en` and state that choice. That file is the only place to change: `src/locales.ts` reads it, so the served language and `<html lang>` follow. It does not create locale URLs; implement a URL strategy only when the product asks for one. Never introduce a default-locale environment variable.
40
+ - Next's `app` tree is the router and stays authoritative: the starter is one ordinary root layout plus `/` as the homepage, and unknown paths get Next's native 404. When a product requires locale URLs, implement the framework-native strategy (`[locale]` segments, middleware, cookies, domains, or an i18n library), pass the resolved locale into Fimo server reads and `FimoProvider`, and load `fimo skills get fimo-code --ref frameworks/next/locales` first. Do not impose locale-prefixed URLs on a default-only project.
41
+ - `FimoProvider` owns the optional Studio preview runtime. Do not add a preview bridge component, read Fimo preview environment variables, or inject Fimo scripts in application code.
42
+ - Keep `.fimo/config.json#routes` as Studio metadata, not as the Next.js router. Describe only URLs the application actually serves; add a `:locale` segment to a route's metadata only after the application implements that locale routing. There, `params.locale.optional: true` means omit the configured default locale from the URL; use `optional: false` only when every locale, including the default, must be prefixed.
43
43
  - The application owns routes, locale resolution, links, HTML language/direction, and SEO. Fimo connects to those decisions.
44
44
  - Do not add a second deployment platform.
45
45
  - Never edit `.fimo/project.json`; it links this directory to the remote project.
46
46
  - Keep `.fimo/config.json#runtime` true to the code: framework, `dev`/`build`/`install` commands, output directory. Update it when you rename a package script, move the build output, or change framework; the reference is `fimo skills get fimo-code --ref frameworks/hosting`.
47
47
  - Keep secrets in the Fimo dashboard, not in committed environment files.
48
48
  - Pass flags to interactive Fimo commands when scripting them.
49
-
50
- <!-- BEGIN:nextjs-agent-rules -->
51
-
52
- # This is NOT the Next.js you know
53
-
54
- This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices.
55
-
56
- This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.
57
-
58
- <!-- END:nextjs-agent-rules -->
@@ -1,6 +1,8 @@
1
1
  import type { NextConfig } from 'next';
2
2
  import { withFimo } from 'fimo/next/config';
3
3
 
4
- const nextConfig: NextConfig = {};
4
+ const nextConfig: NextConfig = {
5
+ agentRules: false,
6
+ };
5
7
 
6
8
  export default withFimo(nextConfig);
@@ -26,5 +26,6 @@
26
26
  },
27
27
  "engines": {
28
28
  "node": ">=22.22.0"
29
- }
29
+ },
30
+ "packageManager": "pnpm@10.26.0"
30
31
  }
@@ -1,4 +1,8 @@
1
- # Build approval is handled by Fimo-controlled install commands. Do not add a
2
- # package-level allowlist because Fimo installs with dangerouslyAllowAllBuilds.
1
+ # Keep dependency-script decisions explicit across local, Preview, and production installs.
2
+
3
+ strictDepBuilds: true
4
+ allowBuilds:
5
+ esbuild: true
6
+ fimo: true
3
7
 
4
8
  packages: []
@@ -0,0 +1,16 @@
1
+ import { FimoProvider } from 'fimo/next/client';
2
+ import type { ReactNode } from 'react';
3
+
4
+ import { defaultLocale } from '../locales';
5
+
6
+ import './globals.css';
7
+
8
+ export default function RootLayout({ children }: Readonly<{ children: ReactNode }>) {
9
+ return (
10
+ <html lang={defaultLocale}>
11
+ <body>
12
+ <FimoProvider locale={defaultLocale}>{children}</FimoProvider>
13
+ </body>
14
+ </html>
15
+ );
16
+ }
@@ -3,11 +3,8 @@ import fimoConfig from '../.fimo/config.json';
3
3
  /**
4
4
  * Locale policy read from the same file Fimo and Studio read, so the site
5
5
  * language cannot drift from the project configuration. Change the locales in
6
- * `.fimo/config.json#i18n`; nothing here needs editing.
6
+ * `.fimo/config.json#i18n`; nothing here needs editing. Configured locales are
7
+ * content configuration only — URL locale routing is a separate application
8
+ * decision implemented in the `app` tree when the product asks for it.
7
9
  */
8
10
  export const defaultLocale: string = fimoConfig.i18n.defaultLocale;
9
-
10
- /** Only non-default locales carry a URL prefix; the default locale stays at the site root. */
11
- export const prefixedLocales: ReadonlySet<string> = new Set(
12
- fimoConfig.i18n.locales.filter((locale) => locale !== defaultLocale)
13
- );
@@ -40,7 +40,7 @@ breaks that. Load `fimo-code` for the exact primitives, but the rule is:
40
40
  ## Project rules
41
41
 
42
42
  - **Deploy is on-demand**, not a save step. Batch related edits into one deploy.
43
- - With pnpm, run `pnpm install --config.dangerouslyAllowAllBuilds=true`; a bare install can skip the build scripts required by Fimo and the framework toolchain.
43
+ - Use the selected package manager's committed build-script policy. pnpm projects pin `pnpm@10.26.0` and approve `esbuild` and `fimo` through `pnpm-workspace.yaml#allowBuilds`; Bun projects trust the same packages through `package.json#trustedDependencies`. Run a plain install with the selected manager so local installation matches Preview and production publishing. Review new dependencies before extending the policy; all three paths stop on unreviewed scripts.
44
44
  - Treat the user's language request as part of setup. The first explicitly requested locale is the primary locale; put it first and set it as `i18n.defaultLocale` in `.fimo/config.json`. If no language is requested, keep `en` and state that choice.
45
45
  - Preserve the application-owned `:locale?` route boundary in `src/routes.ts` and pass its route parameter to `FimoProviders` in `LocaleLayout.tsx`. The missing parameter uses the configured default, so a one-locale site stays at `/`. Add locales in `.fimo/config.json` without rebuilding the route tree; use `:locale` without `?` only when every locale must be prefixed.
46
46
  - Keep `.fimo/config.json#routes` aligned as Studio metadata, not as the React Router source of truth. Do not add a global locale-routing strategy, a Fimo route helper, or a Fimo-owned route tree.
@@ -21,7 +21,7 @@
21
21
  "cmdk": "^1.1.1",
22
22
  "date-fns": "^4.1.0",
23
23
  "embla-carousel-react": "^8.6.0",
24
- "fimo": "0.21.0-staging.2",
24
+ "fimo": "0.21.0-staging.3",
25
25
  "input-otp": "^1.4.2",
26
26
  "isbot": "^5",
27
27
  "lucide-react": "^0.577.0",
@@ -55,5 +55,6 @@
55
55
  },
56
56
  "engines": {
57
57
  "node": ">=22.22.0"
58
- }
58
+ },
59
+ "packageManager": "pnpm@10.26.0"
59
60
  }
@@ -1,8 +1,8 @@
1
- # Build approval is handled by Fimo-controlled install commands (`fimo create
2
- # --install`, sandbox `fimopm install`, and E2E helpers) via scoped pnpm
3
- # allow-all-builds flags. Do NOT add `allowBuilds` / `onlyBuiltDependencies`
4
- # here: pnpm refuses to have both an allowlist and allow-all-builds
5
- # (ERR_PNPM_CONFIG_CONFLICT_BUILT_DEPENDENCIES), which makes sandbox installs
6
- # fail before the project's `fimo` dep is available.
1
+ # Keep dependency-script decisions explicit across local, Preview, and production installs.
2
+
3
+ strictDepBuilds: true
4
+ allowBuilds:
5
+ esbuild: true
6
+ fimo: true
7
7
 
8
8
  packages: []
@@ -3,7 +3,6 @@
3
3
  interface ImportMetaEnv {
4
4
  readonly VITE_API_URL?: string;
5
5
  readonly FIMO_ENV?: string;
6
- readonly VITE_PREVIEW_SCRIPT_URL?: string;
7
6
  }
8
7
 
9
8
  interface ImportMeta {
@@ -27,7 +27,7 @@ a code-only task, or use `npx fimo@latest` for project-local code generation and
27
27
  ## Project rules
28
28
 
29
29
  - **Deploy is on-demand**, not a save step. Batch related edits into one deploy.
30
- - With pnpm, run `pnpm install --config.dangerouslyAllowAllBuilds=true`; a bare install can skip the build scripts required by Fimo and the framework toolchain.
30
+ - Use the selected package manager's committed build-script policy. pnpm projects pin `pnpm@10.26.0` and approve `esbuild` and `fimo` through `pnpm-workspace.yaml#allowBuilds`; Bun projects trust the same packages through `package.json#trustedDependencies`. Run a plain install with the selected manager so local installation matches Preview and production publishing. Review new dependencies before extending the policy; all three paths stop on unreviewed scripts.
31
31
  - Treat the user's language request as part of setup. The first explicitly requested locale is the primary locale; put it first and set it as `i18n.defaultLocale` in `.fimo/config.json`. If no language is requested, keep `en` and state that choice. `src/locales.ts` derives the default and prefixed locale set from that config.
32
32
  - Preserve the native `[[locale=locale]]` route boundary. The optional parameter keeps the default locale at `/`; the matcher prevents ordinary top-level routes from being mistaken for locales. The root server layout passes the tracked `event.params` through `resolveLocale`, then sends that locale to `getLabels` and `FimoProvider`. Remove the extra brackets only when every locale must be prefixed.
33
33
  - Keep the document language request-aware: `src/hooks.server.ts` renders the initial `<html lang>`, and the root layout updates it after client navigation.
@@ -24,5 +24,6 @@
24
24
  },
25
25
  "engines": {
26
26
  "node": ">=22.22.0"
27
- }
27
+ },
28
+ "packageManager": "pnpm@10.26.0"
28
29
  }
@@ -1,4 +1,8 @@
1
- # Build approval is handled by Fimo-controlled install commands. Do not add a
2
- # package-level allowlist because Fimo installs with dangerouslyAllowAllBuilds.
1
+ # Keep dependency-script decisions explicit across local, Preview, and production installs.
2
+
3
+ strictDepBuilds: true
4
+ allowBuilds:
5
+ esbuild: true
6
+ fimo: true
3
7
 
4
8
  packages: []
@@ -1,10 +0,0 @@
1
- import type { ReactNode } from 'react';
2
-
3
- import Document from '../../components/Document';
4
- import { defaultLocale } from '../../locales';
5
-
6
- import '../globals.css';
7
-
8
- export default function DefaultLocaleLayout({ children }: Readonly<{ children: ReactNode }>) {
9
- return <Document locale={defaultLocale}>{children}</Document>;
10
- }
@@ -1,22 +0,0 @@
1
- import { notFound } from 'next/navigation';
2
- import type { ReactNode } from 'react';
3
-
4
- import Document from '../../components/Document';
5
- import { prefixedLocales } from '../../locales';
6
-
7
- import '../globals.css';
8
-
9
- export default async function LocaleLayout({
10
- children,
11
- params,
12
- }: Readonly<{ children: ReactNode; params: Promise<{ locale: string }> }>) {
13
- const { locale } = await params;
14
-
15
- // The default locale is served unprefixed by `app/(default)`, so its prefix
16
- // is not a second URL for the same page.
17
- if (!prefixedLocales.has(locale)) {
18
- notFound();
19
- }
20
-
21
- return <Document locale={locale}>{children}</Document>;
22
- }
@@ -1 +0,0 @@
1
- export { default } from '../(default)/page';