fimo 0.11.0-staging.4 → 0.11.0-staging.6

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 (55) hide show
  1. package/assets/agent-templates/content-translator/GOAL.md +3 -3
  2. package/assets/agent-templates/seo-audit/config.yaml +1 -1
  3. package/assets/skills/fimo/SKILL.md +1 -0
  4. package/assets/skills/fimo-cli/SKILL.md +8 -6
  5. package/assets/skills/fimo-cli/references/agents.md +71 -23
  6. package/assets/skills/fimo-cli/references/branches.md +2 -2
  7. package/assets/skills/fimo-cli/references/credits.md +1 -1
  8. package/assets/skills/fimo-cli/references/deploy.md +1 -1
  9. package/assets/skills/fimo-cli/references/describe.md +1 -1
  10. package/assets/skills/fimo-cli/references/history.md +1 -1
  11. package/assets/skills/fimo-cli/references/init.md +4 -2
  12. package/assets/skills/fimo-cli/references/integrations/firecrawl.md +12 -3
  13. package/assets/skills/fimo-cli/references/integrations.md +15 -3
  14. package/assets/skills/fimo-cli/references/invite.md +1 -1
  15. package/assets/skills/fimo-cli/references/labels.md +1 -1
  16. package/assets/skills/fimo-cli/references/locales.md +4 -4
  17. package/assets/skills/fimo-cli/references/mcp.md +85 -0
  18. package/assets/skills/fimo-cli/references/project-vars-and-secrets.md +1 -1
  19. package/assets/skills/fimo-cli/references/projects.md +7 -7
  20. package/assets/skills/fimo-code/references/labels.md +2 -2
  21. package/assets/skills/fimo-code/references/locales.md +5 -5
  22. package/assets/skills/fimo-code/references/setup-plain-vite.md +4 -4
  23. package/assets/skills/fimo-code/references/setup-react-router.md +5 -5
  24. package/assets/skills/fimo-code/references/ui.md +1 -1
  25. package/assets/skills/fimo-migration/references/workflow.md +1 -1
  26. package/assets/skills/fimo-migration/scripts/build-canonical-manifest.mjs +32 -3
  27. package/assets/skills/fimo-studio/references/custom-domains.md +1 -1
  28. package/dist/build/vite/index.d.ts +3 -3
  29. package/dist/build/vite/plugins/fimo-config.d.ts +2 -2
  30. package/dist/build/vite/plugins/fimo-config.js +5 -5
  31. package/dist/build/vite/plugins/robots.d.ts +1 -1
  32. package/dist/build/vite/plugins/robots.js +3 -3
  33. package/dist/build/vite/plugins/server-config.js +1 -1
  34. package/dist/build/vite/plugins/sitemap.js +2 -2
  35. package/dist/build/vite/plugins/translations.js +14 -10
  36. package/dist/cli/bundle.json +1 -1
  37. package/dist/cli/index.js +142 -131
  38. package/dist/runtime/app/prefetch.d.ts +1 -1
  39. package/dist/runtime/app/prefetch.js +2 -2
  40. package/dist/runtime/paths/get-fimo-paths.d.ts +1 -1
  41. package/dist/runtime/paths/get-fimo-paths.js +2 -2
  42. package/dist/runtime/paths/types.d.ts +1 -1
  43. package/dist/runtime/project-layout.d.ts +14 -0
  44. package/dist/runtime/project-layout.js +57 -0
  45. package/dist/runtime/seo/resolver.d.ts +1 -1
  46. package/dist/runtime/seo/resolver.js +1 -1
  47. package/dist/runtime/shared/fimo-config.server.d.ts +2 -0
  48. package/dist/runtime/shared/fimo-config.server.js +17 -4
  49. package/dist/runtime/templates.d.ts +4 -4
  50. package/dist/runtime/templates.js +11 -6
  51. package/dist/scripts/validate-route-metadata.js +8 -6
  52. package/package.json +7 -1
  53. package/templates/react-router/AGENTS.md +1 -1
  54. package/templates/react-router/package.json +1 -1
  55. /package/templates/react-router/{fimo-config.json → .fimo/config.json} +0 -0
@@ -1,7 +1,7 @@
1
1
  export declare function resolveFimoLocaleForUrl(url: string): import("./index.js").FimoLocaleResolution;
2
2
  /**
3
3
  * Fetch route data for SEO meta resolution.
4
- * Only fetches data for detail pages (routes with `params` in fimo-config.json).
4
+ * Only fetches data for detail pages (routes with `params` in .fimo/config.json).
5
5
  */
6
6
  export declare function resolveMetaEntries(url: string): Promise<Record<string, unknown> | undefined>;
7
7
  //# sourceMappingURL=prefetch.d.ts.map
@@ -2,7 +2,7 @@
2
2
  import fimoConfig from 'virtual:fimo-config';
3
3
  import { resolveFimoLocale } from '../i18n/locale.js';
4
4
  /**
5
- * Match a concrete URL against the routes in fimo-config.json.
5
+ * Match a concrete URL against the routes in .fimo/config.json.
6
6
  * Returns the matching route config or null.
7
7
  */
8
8
  function matchRoute(url) {
@@ -51,7 +51,7 @@ export function resolveFimoLocaleForUrl(url) {
51
51
  }
52
52
  /**
53
53
  * Fetch route data for SEO meta resolution.
54
- * Only fetches data for detail pages (routes with `params` in fimo-config.json).
54
+ * Only fetches data for detail pages (routes with `params` in .fimo/config.json).
55
55
  */
56
56
  export async function resolveMetaEntries(url) {
57
57
  // @ts-ignore – import.meta.env is a Vite feature, replaced at build time for both client and SSR
@@ -1,6 +1,6 @@
1
1
  import type { FimoPath, GetFimoPathsOptions } from './types.js';
2
2
  /**
3
- * Resolve the full list of paths from `fimo-config.json` and dynamic-route
3
+ * Resolve the full list of paths from `.fimo/config.json` and dynamic-route
4
4
  * schema entries. Use as input to your framework's prerender list, sitemap,
5
5
  * robots.txt, or any per-route logic.
6
6
  *
@@ -1,5 +1,5 @@
1
1
  // Resolve the list of paths a project should consider for prerender / sitemap /
2
- // robots / per-route SEO generation. Static paths come from fimo-config.json;
2
+ // robots / per-route SEO generation. Static paths come from .fimo/config.json;
3
3
  // dynamic routes are expanded by fetching schema entries from the content API.
4
4
  import { existsSync, readFileSync } from 'node:fs';
5
5
  import { resolve } from 'node:path';
@@ -72,7 +72,7 @@ function matchesAny(routeKey, patterns) {
72
72
  return patterns.some((p) => compilePattern(p).test(routeKey));
73
73
  }
74
74
  /**
75
- * Resolve the full list of paths from `fimo-config.json` and dynamic-route
75
+ * Resolve the full list of paths from `.fimo/config.json` and dynamic-route
76
76
  * schema entries. Use as input to your framework's prerender list, sitemap,
77
77
  * robots.txt, or any per-route logic.
78
78
  *
@@ -4,7 +4,7 @@ import type { RouteSEO } from '../shared/fimo-config.types.js';
4
4
  * sitemap / robots / per-route SEO generation. Returned by `getFimoPaths()`.
5
5
  */
6
6
  export interface FimoPath {
7
- /** Route key from `fimo-config.json#routes` (e.g. `'home'`, `'blog/post'`). */
7
+ /** Route key from `.fimo/config.json#routes` (e.g. `'home'`, `'blog/post'`). */
8
8
  routeKey: string;
9
9
  /** The configured path pattern (e.g. `'/'`, `'/blog/:slug'`). */
10
10
  pathPattern: string;
@@ -0,0 +1,14 @@
1
+ export type ProjectLayout = 'current' | 'legacy';
2
+ export interface ProjectLayoutPaths {
3
+ readonly project: string;
4
+ readonly config: string;
5
+ readonly agents: string;
6
+ }
7
+ export declare const CURRENT_PROJECT_LAYOUT: ProjectLayoutPaths;
8
+ export declare const LEGACY_PROJECT_LAYOUT: ProjectLayoutPaths;
9
+ export declare const LEGACY_AGENT_POLICY_PATH = "fimo.config.json";
10
+ export declare function detectProjectLayout(paths: Iterable<string>): ProjectLayout | null;
11
+ export declare function getProjectLayoutPaths(layout: ProjectLayout): ProjectLayoutPaths;
12
+ export declare function selectProjectConfigPath(paths: Iterable<string>, layout?: ProjectLayout | null): string;
13
+ export declare function selectProjectPolicyPath(paths: Iterable<string>, layout?: ProjectLayout | null): string;
14
+ //# sourceMappingURL=project-layout.d.ts.map
@@ -0,0 +1,57 @@
1
+ export const CURRENT_PROJECT_LAYOUT = {
2
+ project: '.fimo/project.json',
3
+ config: '.fimo/config.json',
4
+ agents: '.fimo/agents',
5
+ };
6
+ export const LEGACY_PROJECT_LAYOUT = {
7
+ project: '.fimo.settings.json',
8
+ config: 'fimo-config.json',
9
+ agents: 'agents',
10
+ };
11
+ export const LEGACY_AGENT_POLICY_PATH = 'fimo.config.json';
12
+ export function detectProjectLayout(paths) {
13
+ let hasCurrentProject = false;
14
+ let hasLegacyProject = false;
15
+ let hasCurrentMarker = false;
16
+ let hasLegacyMarker = false;
17
+ for (const input of paths) {
18
+ const file = input.replace(/\\/g, '/').replace(/^\.\//, '').replace(/\/$/, '');
19
+ hasCurrentProject || (hasCurrentProject = file === CURRENT_PROJECT_LAYOUT.project);
20
+ hasLegacyProject || (hasLegacyProject = file === LEGACY_PROJECT_LAYOUT.project);
21
+ hasCurrentMarker || (hasCurrentMarker = file === CURRENT_PROJECT_LAYOUT.config ||
22
+ file === CURRENT_PROJECT_LAYOUT.agents ||
23
+ file.startsWith(`${CURRENT_PROJECT_LAYOUT.agents}/`));
24
+ hasLegacyMarker || (hasLegacyMarker = file === LEGACY_PROJECT_LAYOUT.config || file === LEGACY_AGENT_POLICY_PATH);
25
+ }
26
+ if (hasCurrentProject) {
27
+ return 'current';
28
+ }
29
+ if (hasLegacyProject) {
30
+ return 'legacy';
31
+ }
32
+ if (hasCurrentMarker) {
33
+ return 'current';
34
+ }
35
+ return hasLegacyMarker ? 'legacy' : null;
36
+ }
37
+ export function getProjectLayoutPaths(layout) {
38
+ return layout === 'current' ? CURRENT_PROJECT_LAYOUT : LEGACY_PROJECT_LAYOUT;
39
+ }
40
+ export function selectProjectConfigPath(paths, layout) {
41
+ const files = new Set(Array.from(paths, (file) => file.replace(/\\/g, '/').replace(/^\.\//, '')));
42
+ const resolvedLayout = layout ?? detectProjectLayout(files) ?? 'current';
43
+ if (resolvedLayout === 'current') {
44
+ return CURRENT_PROJECT_LAYOUT.config;
45
+ }
46
+ return files.has(LEGACY_AGENT_POLICY_PATH) && !files.has(LEGACY_PROJECT_LAYOUT.config)
47
+ ? LEGACY_AGENT_POLICY_PATH
48
+ : LEGACY_PROJECT_LAYOUT.config;
49
+ }
50
+ export function selectProjectPolicyPath(paths, layout) {
51
+ const files = new Set(Array.from(paths, (file) => file.replace(/\\/g, '/').replace(/^\.\//, '')));
52
+ const resolvedLayout = layout ?? detectProjectLayout(files) ?? 'current';
53
+ if (resolvedLayout === 'current') {
54
+ return CURRENT_PROJECT_LAYOUT.config;
55
+ }
56
+ return files.has(LEGACY_AGENT_POLICY_PATH) ? LEGACY_AGENT_POLICY_PATH : LEGACY_PROJECT_LAYOUT.config;
57
+ }
@@ -3,7 +3,7 @@ import type { FimoConfig, FimoRouteConfig, FimoSEO } from '../shared/fimo-config
3
3
  * Shared SEO resolver for the generated app.
4
4
  *
5
5
  * This module answers one question:
6
- * "Given a pathname and the project's fimo-config.json, what SEO values
6
+ * "Given a pathname and the project's .fimo/config.json, what SEO values
7
7
  * should apply to this route?"
8
8
  *
9
9
  * It centralizes the rule set that was previously duplicated in multiple places:
@@ -2,7 +2,7 @@
2
2
  * Shared SEO resolver for the generated app.
3
3
  *
4
4
  * This module answers one question:
5
- * "Given a pathname and the project's fimo-config.json, what SEO values
5
+ * "Given a pathname and the project's .fimo/config.json, what SEO values
6
6
  * should apply to this route?"
7
7
  *
8
8
  * It centralizes the rule set that was previously duplicated in multiple places:
@@ -5,4 +5,6 @@ import type { FimoConfig } from './fimo-config.types.js';
5
5
  */
6
6
  export declare function getConfigServer(rootDir: string): FimoConfig;
7
7
  export declare function getConfigVersion(rootDir: string): number;
8
+ /** Resolve the current config path while keeping legacy projects readable. */
9
+ export declare function resolveFimoConfigPath(rootDir: string): string;
8
10
  //# sourceMappingURL=fimo-config.server.d.ts.map
@@ -1,6 +1,7 @@
1
- import { readFileSync } from 'fs';
1
+ import { existsSync, readFileSync } from 'fs';
2
2
  import { resolve } from 'path';
3
- // Matches the template's fimo-config.json (`version: "4"`) and the agents
3
+ import { CURRENT_PROJECT_LAYOUT, LEGACY_AGENT_POLICY_PATH, LEGACY_PROJECT_LAYOUT, selectProjectConfigPath, } from '../project-layout.js';
4
+ // Matches the template's `.fimo/config.json` (`version: "4"`) and the agents
4
5
  // workspace default — the fallback when a config omits the field.
5
6
  const LATEST_TEMPLATE_VERSION = 4;
6
7
  const defaultConfig = {
@@ -12,7 +13,7 @@ const defaultConfig = {
12
13
  */
13
14
  export function getConfigServer(rootDir) {
14
15
  try {
15
- const configPath = resolve(rootDir, 'fimo-config.json');
16
+ const configPath = resolveFimoConfigPath(rootDir);
16
17
  const content = readFileSync(configPath, 'utf-8');
17
18
  const raw = JSON.parse(content);
18
19
  return {
@@ -28,7 +29,7 @@ export function getConfigServer(rootDir) {
28
29
  }
29
30
  export function getConfigVersion(rootDir) {
30
31
  try {
31
- const configPath = resolve(rootDir, 'fimo-config.json');
32
+ const configPath = resolveFimoConfigPath(rootDir);
32
33
  const content = readFileSync(configPath, 'utf-8');
33
34
  const raw = JSON.parse(content);
34
35
  const parsed = Number.parseInt(String(raw.version ?? LATEST_TEMPLATE_VERSION), 10);
@@ -38,3 +39,15 @@ export function getConfigVersion(rootDir) {
38
39
  return LATEST_TEMPLATE_VERSION;
39
40
  }
40
41
  }
42
+ /** Resolve the current config path while keeping legacy projects readable. */
43
+ export function resolveFimoConfigPath(rootDir) {
44
+ const candidates = [
45
+ CURRENT_PROJECT_LAYOUT.project,
46
+ LEGACY_PROJECT_LAYOUT.project,
47
+ CURRENT_PROJECT_LAYOUT.config,
48
+ LEGACY_PROJECT_LAYOUT.config,
49
+ LEGACY_AGENT_POLICY_PATH,
50
+ ];
51
+ const existing = candidates.filter((candidate) => existsSync(resolve(rootDir, candidate)));
52
+ return resolve(rootDir, selectProjectConfigPath(existing));
53
+ }
@@ -45,17 +45,17 @@ export declare function readCliSemver(): string | null;
45
45
  export declare function computeFimoPin(meta: ReleaseMeta, semver: string | null, options?: {
46
46
  devPackageRoot?: string | null;
47
47
  }): string | null;
48
- export declare function computeRemoteFimoPin(meta: ReleaseMeta, semver: string | null, options?: {
48
+ export declare function computeRemoteFimoPin(meta: ReleaseMeta, semver: string | null, options: {
49
49
  devReleaseVersion?: string | null;
50
- fallback?: string | null;
50
+ fallback: string | null;
51
51
  }): string | null;
52
52
  /** Filesystem-backed wrapper around computeFimoPin. */
53
53
  export declare function resolveFimoPin(options?: {
54
54
  devPackageRoot?: string | null;
55
55
  }): string | null;
56
- export declare function resolveRemoteFimoPin(options?: {
56
+ export declare function resolveRemoteFimoPin(options: {
57
57
  devSearchStart?: string | null;
58
- fallback?: string | null;
58
+ fallback: string | null;
59
59
  }): string | null;
60
60
  export declare function readDevReleaseVersion(startPath?: string): DevReleaseVersion;
61
61
  interface PkgWithDeps {
@@ -27,7 +27,6 @@ const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
27
27
  const PACKAGE_ROOT = path.resolve(MODULE_DIR, '..', '..');
28
28
  const RELEASE_FILE = path.join(PACKAGE_ROOT, 'release.json');
29
29
  const PACKAGE_JSON_FILE = path.join(PACKAGE_ROOT, 'package.json');
30
- const FALLBACK_REMOTE_FIMO_PIN = 'latest';
31
30
  export const TEMPLATE_FRAMEWORKS = ['react-router', 'astro', 'next', 'vite'];
32
31
  export const DEFAULT_TEMPLATE = 'react-router';
33
32
  /**
@@ -105,7 +104,7 @@ export function computeFimoPin(meta, semver, options = {}) {
105
104
  }
106
105
  return null;
107
106
  }
108
- export function computeRemoteFimoPin(meta, semver, options = {}) {
107
+ export function computeRemoteFimoPin(meta, semver, options) {
109
108
  if (meta.source === 'npm') {
110
109
  if (semver) {
111
110
  return semver;
@@ -116,13 +115,13 @@ export function computeRemoteFimoPin(meta, semver, options = {}) {
116
115
  if (devReleaseVersion) {
117
116
  return devReleaseVersion;
118
117
  }
119
- return options.fallback === undefined ? FALLBACK_REMOTE_FIMO_PIN : options.fallback;
118
+ return options.fallback;
120
119
  }
121
120
  /** Filesystem-backed wrapper around computeFimoPin. */
122
121
  export function resolveFimoPin(options = {}) {
123
122
  return computeFimoPin(readReleaseMeta(), readCliSemver(), options);
124
123
  }
125
- export function resolveRemoteFimoPin(options = {}) {
124
+ export function resolveRemoteFimoPin(options) {
126
125
  const meta = readReleaseMeta();
127
126
  const semver = readCliSemver();
128
127
  const devRelease = meta.source === 'npm' ? { version: null } : readDevReleaseVersion(options.devSearchStart ?? PACKAGE_ROOT);
@@ -136,9 +135,15 @@ export function readDevReleaseVersion(startPath = PACKAGE_ROOT) {
136
135
  if (!devJsonPath) {
137
136
  return { devJsonPath: null, version: null };
138
137
  }
139
- const parsed = JSON.parse(fs.readFileSync(devJsonPath, 'utf8'));
138
+ let parsed;
139
+ try {
140
+ parsed = JSON.parse(fs.readFileSync(devJsonPath, 'utf8'));
141
+ }
142
+ catch {
143
+ throw new Error(`Invalid JSON in ${devJsonPath}. Run \`pnpm -F fimo publish-cli -- --id <task-name>\` from that Fimo checkout, then retry.`);
144
+ }
140
145
  if (typeof parsed.version !== 'string' || parsed.version.trim().length === 0) {
141
- throw new Error(`Missing "version" in ${devJsonPath}. Publish an experimental CLI build again.`);
146
+ throw new Error(`Missing "version" in ${devJsonPath}. Run \`pnpm -F fimo publish-cli -- --id <task-name>\` from that Fimo checkout, then retry.`);
142
147
  }
143
148
  return {
144
149
  devJsonPath,
@@ -1,5 +1,6 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
+ import { resolveFimoConfigPath } from '../runtime/shared/fimo-config.server.js';
3
4
  import { parseRoutesSource } from './lib/parse-routes-file.js';
4
5
  function readJson(filePath) {
5
6
  try {
@@ -27,7 +28,8 @@ function loadConfigRoutes(config) {
27
28
  }
28
29
  export function validateRouteMetadata(options = {}) {
29
30
  const cwd = options.cwd ?? process.cwd();
30
- const configFilePath = path.resolve(cwd, 'fimo-config.json');
31
+ const configFilePath = resolveFimoConfigPath(cwd);
32
+ const configDisplayPath = path.relative(cwd, configFilePath).replaceAll(path.sep, '/');
31
33
  const srcDir = path.resolve(cwd, 'src');
32
34
  const routesFilePath = path.resolve(srcDir, 'routes.ts');
33
35
  const errors = [];
@@ -47,7 +49,6 @@ export function validateRouteMetadata(options = {}) {
47
49
  pathToFile.set(fr.path, fr.file);
48
50
  }
49
51
  }
50
- // Load route metadata from fimo-config.json
51
52
  const config = readJson(configFilePath);
52
53
  const i18n = validateI18nConfig(config);
53
54
  errors.push(...i18n.errors);
@@ -59,14 +60,14 @@ export function validateRouteMetadata(options = {}) {
59
60
  continue;
60
61
  }
61
62
  if (fileRoute.path && !configPaths.has(fileRoute.path)) {
62
- errors.push(`Route with path "${fileRoute.path}" (file: "${fileRoute.file}") exists in src/routes.ts but has no matching entry in fimo-config.json.\nFix: add a route entry to fimo-config.json "routes" with a matching "path".`);
63
+ errors.push(`Route with path "${fileRoute.path}" (file: "${fileRoute.file}") exists in src/routes.ts but has no matching entry in ${configDisplayPath}.\nFix: add a route entry to ${configDisplayPath} "routes" with a matching "path".`);
63
64
  }
64
65
  }
65
66
  // Cross-validate: fimo-config routes should have matching routes.ts entries
66
67
  const filePaths = new Set(fileRoutes.filter((r) => !r.isLayout && r.path).map((r) => r.path));
67
68
  for (const route of configRoutes) {
68
69
  if (!filePaths.has(route.path)) {
69
- errors.push(`Route "${route.id}" (${route.path}) exists in fimo-config.json but is not registered in src/routes.ts.\nFix: add the route to src/routes.ts. Example: route('${route.path.replace(/^\//, '')}', './pages/YourPage.tsx')`);
70
+ errors.push(`Route "${route.id}" (${route.path}) exists in ${configDisplayPath} but is not registered in src/routes.ts.\nFix: add the route to src/routes.ts. Example: route('${route.path.replace(/^\//, '')}', './pages/YourPage.tsx')`);
70
71
  }
71
72
  }
72
73
  if (i18n.routingStrategy === 'path-prefix' && i18n.locales.length > 1) {
@@ -74,6 +75,7 @@ export function validateRouteMetadata(options = {}) {
74
75
  configRoutes,
75
76
  fileRoutes,
76
77
  i18n,
78
+ configDisplayPath,
77
79
  routesSourceUsesFimoRoutes: sourceUsesFimoRoutes(fileRoutes, routesFilePath),
78
80
  }));
79
81
  }
@@ -99,7 +101,7 @@ export function validateRouteMetadata(options = {}) {
99
101
  }
100
102
  if (route.paramNames.length > 0) {
101
103
  if (!route.params) {
102
- errors.push(`Dynamic route "${route.id}" (${route.path}) needs \`params\` metadata to generate prerender URLs.\nFix: add to the route in fimo-config.json: \`"params": { "${route.paramNames[0] || 'param'}": { "schema": "SchemaName", "queryField": "${route.paramNames[0] || 'slug'}", "displayField": "title" } }\``);
104
+ errors.push(`Dynamic route "${route.id}" (${route.path}) needs \`params\` metadata to generate prerender URLs.\nFix: add to the route in ${configDisplayPath}: \`"params": { "${route.paramNames[0] || 'param'}": { "schema": "SchemaName", "queryField": "${route.paramNames[0] || 'slug'}", "displayField": "title" } }\``);
103
105
  }
104
106
  else {
105
107
  for (const paramName of route.paramNames) {
@@ -200,7 +202,7 @@ function validateLocaleRouteCollisions(args) {
200
202
  for (const route of args.configRoutes) {
201
203
  const first = firstPathSegment(route.path);
202
204
  if (first && reservedPrefixes.has(first.toLowerCase())) {
203
- errors.push(`Route "${route.id}" (${route.path}) uses reserved locale prefix "${first}". Keep fimo-config.json routes canonical and unlocalized, for example "/pricing"; let fimoRoutes() or custom locale routing produce "/${first}/...".`);
205
+ errors.push(`Route "${route.id}" (${route.path}) uses reserved locale prefix "${first}". Keep ${args.configDisplayPath} routes canonical and unlocalized, for example "/pricing"; let fimoRoutes() or custom locale routing produce "/${first}/...".`);
204
206
  }
205
207
  }
206
208
  if (!args.routesSourceUsesFimoRoutes) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fimo",
3
- "version": "0.11.0-staging.4",
3
+ "version": "0.11.0-staging.6",
4
4
  "description": "Fimo CLI - create, deploy, and manage Fimo projects",
5
5
  "bin": {
6
6
  "fimo": "dist/cli/index.js"
@@ -41,6 +41,10 @@
41
41
  "./templates": {
42
42
  "types": "./dist/runtime/templates.d.ts",
43
43
  "import": "./dist/runtime/templates.js"
44
+ },
45
+ "./project-layout": {
46
+ "types": "./dist/runtime/project-layout.d.ts",
47
+ "import": "./dist/runtime/project-layout.js"
44
48
  }
45
49
  },
46
50
  "publishConfig": {
@@ -76,7 +80,9 @@
76
80
  "@fimo/agents-bundle": "workspace:*",
77
81
  "@fimo/api-contracts": "workspace:*",
78
82
  "@fimo/cli-kit": "workspace:*",
83
+ "@fimo/mcp": "workspace:*",
79
84
  "@fimo/tsconfig": "workspace:*",
85
+ "@modelcontextprotocol/sdk": "1.27.1",
80
86
  "@tanstack/react-query": "^5.80.6",
81
87
  "@types/node": "^22.15.29",
82
88
  "@types/react": "^19.2.14",
@@ -38,7 +38,7 @@ breaks that. Load `fimo-code` for the exact primitives, but the rule is:
38
38
 
39
39
  - **Deploy is on-demand**, not a save step. Batch related edits into one deploy.
40
40
  - Do not add a second deploy tool (Vercel, Netlify, etc.).
41
- - **Never edit `.fimo.settings.json`** — it links this folder to the remote project.
41
+ - **Never edit `.fimo/project.json`** — it links this folder to the remote project.
42
42
  - The scaffolded homepage is disposable starter content. Replace it on the first real generation.
43
43
  - **Secrets live in the Fimo dashboard**, not in a committed `.env`.
44
44
  - When scripting, pass flags to `fimo` commands (`fimo deploy -m "…"`, `fimo delete -y`) — bare interactive forms hang in non-TTY shells.
@@ -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.11.0-staging.4",
24
+ "fimo": "0.11.0-staging.6",
25
25
  "input-otp": "^1.4.2",
26
26
  "isbot": "^5",
27
27
  "lucide-react": "^0.577.0",