fimo 2.2.0-staging.8 → 2.2.0
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/agent-templates/_default/config.yaml +6 -0
- package/assets/agent-templates/broken-link-sweeper/config.yaml +1 -0
- package/assets/content-templates/shared/types.eta +65 -6
- package/assets/skills/fimo-cli/SKILL.md +5 -3
- package/assets/skills/fimo-cli/references/agents.md +29 -4
- package/assets/skills/fimo-cli/references/assets.md +42 -3
- package/assets/skills/fimo-cli/references/branches.md +9 -8
- package/assets/skills/fimo-cli/references/content.md +4 -4
- package/assets/skills/fimo-cli/references/credits.md +12 -19
- package/assets/skills/fimo-cli/references/deploy.md +8 -8
- package/assets/skills/fimo-cli/references/forms.md +3 -1
- package/assets/skills/fimo-cli/references/history.md +3 -2
- package/assets/skills/fimo-cli/references/inbox.md +86 -0
- package/assets/skills/fimo-cli/references/init.md +7 -6
- package/assets/skills/fimo-cli/references/invite.md +11 -9
- package/assets/skills/fimo-cli/references/labels.md +3 -11
- package/assets/skills/fimo-cli/references/locales.md +5 -3
- package/assets/skills/fimo-cli/references/preview.md +1 -2
- package/assets/skills/fimo-cli/references/projects.md +8 -8
- package/assets/skills/fimo-cli/references/schedules.md +6 -4
- package/assets/skills/fimo-cli/references/webhooks.md +6 -4
- package/assets/skills/fimo-code/references/assets.md +22 -11
- package/assets/skills/fimo-code/references/content/clients.md +15 -1
- package/assets/skills/fimo-code/references/content/schema.md +1 -0
- package/assets/skills/fimo-code/references/frameworks/astro.md +1 -1
- package/assets/skills/fimo-code/references/frameworks/next/app-router.md +12 -1
- package/assets/skills/fimo-code/references/frameworks/next/locales.md +2 -2
- package/assets/skills/fimo-code/references/frameworks/next.md +1 -1
- package/assets/skills/fimo-code/references/locales.md +4 -2
- package/assets/skills/fimo-migration/SKILL.md +54 -16
- package/assets/skills/fimo-migration/references/frameworks/nextjs.md +8 -0
- package/assets/skills/fimo-migration/references/media.md +11 -0
- package/assets/skills/fimo-migration/references/qa.md +30 -4
- package/assets/skills/fimo-migration/references/questions-and-improvements.md +188 -0
- package/assets/skills/fimo-migration/references/workers/content-planner.md +8 -3
- package/assets/skills/fimo-migration/references/workers/validator.md +20 -6
- package/assets/skills/fimo-migration/references/workers.md +17 -6
- package/assets/skills/fimo-migration/references/workflow.md +36 -6
- package/assets/skills/fimo-studio/SKILL.md +3 -1
- package/assets/skills/fimo-studio/references/agents.md +25 -0
- package/assets/skills/fimo-studio/references/ai-chat.md +1 -2
- package/assets/skills/fimo-studio/references/billing-and-credits.md +14 -7
- package/assets/skills/fimo-studio/references/visual-editing.md +9 -1
- package/assets/skills/fimo-studio/references/webhooks.md +1 -1
- package/dist/cli/bundle.json +2 -2
- package/dist/cli/index.js +210 -179
- package/dist/runtime/content/client/collection-core.js +3 -2
- package/dist/runtime/content/client/core-types.d.ts +4 -3
- package/dist/runtime/content/client/internal.d.ts +2 -0
- package/dist/runtime/content/client/internal.js +54 -25
- package/dist/runtime/content/client/singleton-core.js +2 -1
- package/dist/runtime/content/index.d.ts +1 -1
- package/dist/runtime/content/index.js +1 -1
- package/dist/runtime/content/serialization.d.ts +4 -3
- package/dist/runtime/content/serialization.js +4 -3
- package/dist/runtime/primitives/lib/index.d.ts +1 -1
- package/dist/runtime/primitives/lib/index.js +1 -1
- package/dist/runtime/primitives/lib/primitives.d.ts +39 -12
- package/dist/runtime/primitives/lib/primitives.js +83 -17
- package/dist/runtime/primitives/lib/template.js +2 -2
- package/dist/runtime/shared/local-runtime-env.d.ts +2 -2
- package/dist/runtime/shared/local-runtime-env.js +14 -9
- package/dist/runtime/templates.d.ts +9 -2
- package/dist/runtime/templates.js +36 -7
- package/dist/scripts/validate-schemas.js +10 -15
- package/package.json +10 -8
- package/release.json +2 -2
- package/templates/astro/AGENTS.md +1 -1
- package/templates/astro/package.json +2 -2
- package/templates/nextjs/AGENTS.md +2 -2
- package/templates/nextjs/package.json +3 -3
- package/templates/nextjs/src/app/layout.tsx +4 -1
- package/templates/react-router/AGENTS.md +2 -2
- package/templates/react-router/package.json +4 -4
- package/templates/sveltekit/AGENTS.md +1 -1
- package/templates/sveltekit/package.json +2 -2
- package/templates/vite/AGENTS.md +5 -1
- package/templates/vite/package.json +4 -4
- package/templates/welcome/manifest.json +655 -0
- package/templates/welcome/media/analytics-overview.avif +0 -0
- package/templates/welcome/media/autonomous-loop.avif +0 -0
- package/templates/welcome/media/editable-preview.avif +0 -0
- package/templates/welcome/media/media-library.avif +0 -0
- package/templates/welcome/media/slack-teams.avif +0 -0
- package/templates/welcome/template/.fimo/agents/welcome-guide/GOAL.md +12 -0
- package/templates/welcome/template/.fimo/agents/welcome-guide/capabilities.yaml +3 -0
- package/templates/welcome/template/.fimo/agents/welcome-guide/config.yaml +8 -0
- package/templates/welcome/template/.fimo/config.json +53 -0
- package/templates/welcome/template/src/font.css +60 -0
- package/templates/welcome/template/src/pages/ArticleDetail.tsx +104 -0
- package/templates/welcome/template/src/pages/Index.tsx +36 -0
- package/templates/welcome/template/src/pages/SiteContent.tsx +674 -0
- package/templates/welcome/template/src/pages/fallback-content.ts +152 -0
- package/templates/welcome/template/src/routes.ts +9 -0
- package/templates/welcome/template/src/schemas/Article.json +34 -0
- package/templates/welcome/template/src/schemas/Article.ts +54 -0
- package/templates/welcome/template/src/schemas/Article.types.ts +93 -0
- package/templates/welcome/template/src/schemas/Author.json +17 -0
- package/templates/welcome/template/src/schemas/Author.ts +51 -0
- package/templates/welcome/template/src/schemas/Author.types.ts +54 -0
- package/templates/welcome/template/src/schemas/Category.json +17 -0
- package/templates/welcome/template/src/schemas/Category.ts +51 -0
- package/templates/welcome/template/src/schemas/Category.types.ts +54 -0
- package/templates/welcome/template/src/schemas/HomePage.json +110 -0
- package/templates/welcome/template/src/schemas/HomePage.ts +22 -0
- package/templates/welcome/template/src/schemas/HomePage.types.ts +116 -0
|
@@ -4,10 +4,21 @@
|
|
|
4
4
|
* All Fimo types carry hidden metadata that enables the preview editor
|
|
5
5
|
* to know where content comes from (schema field, translation key, etc.)
|
|
6
6
|
*/
|
|
7
|
-
var _a, _b, _c, _d, _e, _f;
|
|
7
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
8
8
|
// Symbol for accessing fimo metadata (hidden from JSON.stringify)
|
|
9
9
|
export const FIMO_SOURCE = Symbol.for('fimo.source');
|
|
10
|
+
export const FIMO_SOURCE_CONTEXT = Symbol.for('fimo.sourceContext');
|
|
10
11
|
export const FIMO_PARTS = Symbol.for('fimo.parts');
|
|
12
|
+
function defineSourceContext(value, context) {
|
|
13
|
+
if (context && context.length > 0) {
|
|
14
|
+
Object.defineProperty(value, FIMO_SOURCE_CONTEXT, {
|
|
15
|
+
value: Object.freeze([...context]),
|
|
16
|
+
enumerable: false,
|
|
17
|
+
configurable: true,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
11
22
|
/**
|
|
12
23
|
* FimoString - A string with source tracking
|
|
13
24
|
*
|
|
@@ -15,7 +26,7 @@ export const FIMO_PARTS = Symbol.for('fimo.parts');
|
|
|
15
26
|
* but carries hidden metadata for inline editing.
|
|
16
27
|
*/
|
|
17
28
|
export class FimoString extends String {
|
|
18
|
-
constructor(value, source) {
|
|
29
|
+
constructor(value, source, context) {
|
|
19
30
|
super(value);
|
|
20
31
|
Object.defineProperty(this, _a, {
|
|
21
32
|
enumerable: true,
|
|
@@ -29,7 +40,14 @@ export class FimoString extends String {
|
|
|
29
40
|
writable: true,
|
|
30
41
|
value: void 0
|
|
31
42
|
});
|
|
43
|
+
Object.defineProperty(this, _c, {
|
|
44
|
+
enumerable: true,
|
|
45
|
+
configurable: true,
|
|
46
|
+
writable: true,
|
|
47
|
+
value: void 0
|
|
48
|
+
});
|
|
32
49
|
this[FIMO_SOURCE] = source;
|
|
50
|
+
defineSourceContext(this, context);
|
|
33
51
|
}
|
|
34
52
|
/**
|
|
35
53
|
* Compose multiple tracked values into one FimoString.
|
|
@@ -41,7 +59,7 @@ export class FimoString extends String {
|
|
|
41
59
|
const trackedParts = parts.filter((p) => p.source);
|
|
42
60
|
// Single tracked part with no static text — just return a normal FimoString
|
|
43
61
|
if (trackedParts.length === 1 && parts.length === 1) {
|
|
44
|
-
return new FimoString(text, trackedParts[0].source);
|
|
62
|
+
return new FimoString(text, trackedParts[0].source, trackedParts[0].context);
|
|
45
63
|
}
|
|
46
64
|
const instance = new FimoString(text, null);
|
|
47
65
|
instance[FIMO_PARTS] = parts;
|
|
@@ -54,31 +72,50 @@ export class FimoString extends String {
|
|
|
54
72
|
return { source: this[FIMO_SOURCE] ?? '' };
|
|
55
73
|
}
|
|
56
74
|
}
|
|
57
|
-
_a = FIMO_SOURCE, _b = FIMO_PARTS;
|
|
75
|
+
_a = FIMO_SOURCE, _b = FIMO_SOURCE_CONTEXT, _c = FIMO_PARTS;
|
|
58
76
|
/**
|
|
59
77
|
* FimoDate - A date with source tracking
|
|
60
78
|
*/
|
|
61
79
|
export class FimoDate extends Date {
|
|
62
|
-
constructor(value, source) {
|
|
80
|
+
constructor(value, source, context) {
|
|
63
81
|
super(value);
|
|
64
|
-
Object.defineProperty(this,
|
|
82
|
+
Object.defineProperty(this, _d, {
|
|
83
|
+
enumerable: true,
|
|
84
|
+
configurable: true,
|
|
85
|
+
writable: true,
|
|
86
|
+
value: void 0
|
|
87
|
+
});
|
|
88
|
+
Object.defineProperty(this, _e, {
|
|
65
89
|
enumerable: true,
|
|
66
90
|
configurable: true,
|
|
67
91
|
writable: true,
|
|
68
92
|
value: void 0
|
|
69
93
|
});
|
|
70
94
|
this[FIMO_SOURCE] = source;
|
|
95
|
+
defineSourceContext(this, context);
|
|
71
96
|
}
|
|
72
97
|
get __fimo() {
|
|
73
98
|
return { source: this[FIMO_SOURCE] };
|
|
74
99
|
}
|
|
75
100
|
}
|
|
76
|
-
|
|
101
|
+
_d = FIMO_SOURCE, _e = FIMO_SOURCE_CONTEXT;
|
|
77
102
|
/**
|
|
78
|
-
* FimoMedia -
|
|
103
|
+
* FimoMedia - a media value with source tracking.
|
|
104
|
+
*
|
|
105
|
+
* A stored media value is a reference: the media-library `id`, the `url` that
|
|
106
|
+
* still resolves if the asset is deleted, and the `alt` the entry owns. The
|
|
107
|
+
* facts the asset owns, such as `name`, `mime`, and intrinsic `width`/`height`,
|
|
108
|
+
* are optional because a read only carries them when it named the field in
|
|
109
|
+
* `populate`. Renderers must treat them as enrichment.
|
|
79
110
|
*/
|
|
80
111
|
export class FimoMedia {
|
|
81
|
-
constructor(data, source) {
|
|
112
|
+
constructor(data, source, context) {
|
|
113
|
+
Object.defineProperty(this, "id", {
|
|
114
|
+
enumerable: true,
|
|
115
|
+
configurable: true,
|
|
116
|
+
writable: true,
|
|
117
|
+
value: void 0
|
|
118
|
+
});
|
|
82
119
|
Object.defineProperty(this, "url", {
|
|
83
120
|
enumerable: true,
|
|
84
121
|
configurable: true,
|
|
@@ -115,12 +152,19 @@ export class FimoMedia {
|
|
|
115
152
|
writable: true,
|
|
116
153
|
value: void 0
|
|
117
154
|
});
|
|
118
|
-
Object.defineProperty(this,
|
|
155
|
+
Object.defineProperty(this, _f, {
|
|
156
|
+
enumerable: true,
|
|
157
|
+
configurable: true,
|
|
158
|
+
writable: true,
|
|
159
|
+
value: void 0
|
|
160
|
+
});
|
|
161
|
+
Object.defineProperty(this, _g, {
|
|
119
162
|
enumerable: true,
|
|
120
163
|
configurable: true,
|
|
121
164
|
writable: true,
|
|
122
165
|
value: void 0
|
|
123
166
|
});
|
|
167
|
+
this.id = data.id;
|
|
124
168
|
this.url = data.url;
|
|
125
169
|
this.alt = data.alt;
|
|
126
170
|
this.name = data.name;
|
|
@@ -128,24 +172,31 @@ export class FimoMedia {
|
|
|
128
172
|
this.width = data.width;
|
|
129
173
|
this.height = data.height;
|
|
130
174
|
this[FIMO_SOURCE] = source;
|
|
175
|
+
defineSourceContext(this, context);
|
|
131
176
|
}
|
|
132
177
|
get __fimo() {
|
|
133
178
|
return { source: this[FIMO_SOURCE] };
|
|
134
179
|
}
|
|
135
180
|
}
|
|
136
|
-
|
|
181
|
+
_f = FIMO_SOURCE, _g = FIMO_SOURCE_CONTEXT;
|
|
137
182
|
/**
|
|
138
183
|
* FimoBoolean - Boolean with source tracking (for display purposes)
|
|
139
184
|
*/
|
|
140
185
|
export class FimoBoolean {
|
|
141
|
-
constructor(value, source) {
|
|
186
|
+
constructor(value, source, context) {
|
|
142
187
|
Object.defineProperty(this, "value", {
|
|
143
188
|
enumerable: true,
|
|
144
189
|
configurable: true,
|
|
145
190
|
writable: true,
|
|
146
191
|
value: void 0
|
|
147
192
|
});
|
|
148
|
-
Object.defineProperty(this,
|
|
193
|
+
Object.defineProperty(this, _h, {
|
|
194
|
+
enumerable: true,
|
|
195
|
+
configurable: true,
|
|
196
|
+
writable: true,
|
|
197
|
+
value: void 0
|
|
198
|
+
});
|
|
199
|
+
Object.defineProperty(this, _j, {
|
|
149
200
|
enumerable: true,
|
|
150
201
|
configurable: true,
|
|
151
202
|
writable: true,
|
|
@@ -153,6 +204,7 @@ export class FimoBoolean {
|
|
|
153
204
|
});
|
|
154
205
|
this.value = value;
|
|
155
206
|
this[FIMO_SOURCE] = source;
|
|
207
|
+
defineSourceContext(this, context);
|
|
156
208
|
}
|
|
157
209
|
get __fimo() {
|
|
158
210
|
return { source: this[FIMO_SOURCE] };
|
|
@@ -161,21 +213,27 @@ export class FimoBoolean {
|
|
|
161
213
|
return this.value;
|
|
162
214
|
}
|
|
163
215
|
}
|
|
164
|
-
|
|
216
|
+
_h = FIMO_SOURCE, _j = FIMO_SOURCE_CONTEXT;
|
|
165
217
|
/**
|
|
166
218
|
* FimoRichText - Rich text content with source tracking
|
|
167
219
|
*
|
|
168
220
|
* Wraps Tiptap JSONContent for rich text fields with inline editing support.
|
|
169
221
|
*/
|
|
170
222
|
export class FimoRichText {
|
|
171
|
-
constructor(content, source) {
|
|
223
|
+
constructor(content, source, context) {
|
|
172
224
|
Object.defineProperty(this, "content", {
|
|
173
225
|
enumerable: true,
|
|
174
226
|
configurable: true,
|
|
175
227
|
writable: true,
|
|
176
228
|
value: void 0
|
|
177
229
|
});
|
|
178
|
-
Object.defineProperty(this,
|
|
230
|
+
Object.defineProperty(this, _k, {
|
|
231
|
+
enumerable: true,
|
|
232
|
+
configurable: true,
|
|
233
|
+
writable: true,
|
|
234
|
+
value: void 0
|
|
235
|
+
});
|
|
236
|
+
Object.defineProperty(this, _l, {
|
|
179
237
|
enumerable: true,
|
|
180
238
|
configurable: true,
|
|
181
239
|
writable: true,
|
|
@@ -183,12 +241,13 @@ export class FimoRichText {
|
|
|
183
241
|
});
|
|
184
242
|
this.content = content;
|
|
185
243
|
this[FIMO_SOURCE] = source;
|
|
244
|
+
defineSourceContext(this, context);
|
|
186
245
|
}
|
|
187
246
|
get __fimo() {
|
|
188
247
|
return { source: this[FIMO_SOURCE] };
|
|
189
248
|
}
|
|
190
249
|
}
|
|
191
|
-
|
|
250
|
+
_k = FIMO_SOURCE, _l = FIMO_SOURCE_CONTEXT;
|
|
192
251
|
/**
|
|
193
252
|
* Type guard to check if a value is a FimoString
|
|
194
253
|
*/
|
|
@@ -219,6 +278,13 @@ export function getFimoSource(value) {
|
|
|
219
278
|
}
|
|
220
279
|
return undefined;
|
|
221
280
|
}
|
|
281
|
+
/** Get the hidden relation/component ancestry from a wrapped value. */
|
|
282
|
+
export function getFimoSourceContext(value) {
|
|
283
|
+
if (value != null && typeof value === 'object' && FIMO_SOURCE_CONTEXT in value) {
|
|
284
|
+
return value[FIMO_SOURCE_CONTEXT];
|
|
285
|
+
}
|
|
286
|
+
return undefined;
|
|
287
|
+
}
|
|
222
288
|
/**
|
|
223
289
|
* Get the decomposed parts from a composed FimoString, or undefined
|
|
224
290
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FIMO_SOURCE, FimoString, hasFimoSource } from './primitives.js';
|
|
1
|
+
import { FIMO_SOURCE, getFimoSourceContext, FimoString, hasFimoSource } from './primitives.js';
|
|
2
2
|
/**
|
|
3
3
|
* Template literal helper for composing multiple Fimo values
|
|
4
4
|
*
|
|
@@ -19,7 +19,7 @@ export function fimo(strings, ...values) {
|
|
|
19
19
|
const value = values[i];
|
|
20
20
|
const text = String(value);
|
|
21
21
|
const source = hasFimoSource(value) ? value[FIMO_SOURCE] : undefined;
|
|
22
|
-
parts.push({ text, source: source ?? undefined });
|
|
22
|
+
parts.push({ text, source: source ?? undefined, context: getFimoSourceContext(value) });
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
return FimoString.compose(parts);
|
|
@@ -31,8 +31,8 @@ export interface LocalProjectLink {
|
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
33
|
* Derive the local runtime env, or `null` when this directory is not a linked
|
|
34
|
-
* Fimo project
|
|
35
|
-
*
|
|
34
|
+
* Fimo project, Git cannot name the current Branch, or the link predates
|
|
35
|
+
* `tenantApiBaseUrl`.
|
|
36
36
|
*/
|
|
37
37
|
export declare function resolveLocalRuntimeEnv(options: {
|
|
38
38
|
readonly cwd: string;
|
|
@@ -19,11 +19,11 @@ import { execFileSync } from 'node:child_process';
|
|
|
19
19
|
import fs from 'node:fs';
|
|
20
20
|
import path from 'node:path';
|
|
21
21
|
import { CURRENT_PROJECT_LAYOUT, LEGACY_PROJECT_LAYOUT } from '../project-layout.js';
|
|
22
|
-
import {
|
|
22
|
+
import { LOCAL_CONTENT_API_ENV_KEYS, buildLocalRuntimeEnv, buildTenantApiUrl, isValidBranch, } from './branch-identity.js';
|
|
23
23
|
/**
|
|
24
24
|
* Derive the local runtime env, or `null` when this directory is not a linked
|
|
25
|
-
* Fimo project
|
|
26
|
-
*
|
|
25
|
+
* Fimo project, Git cannot name the current Branch, or the link predates
|
|
26
|
+
* `tenantApiBaseUrl`.
|
|
27
27
|
*/
|
|
28
28
|
export function resolveLocalRuntimeEnv(options) {
|
|
29
29
|
const root = findProjectRoot(options.cwd);
|
|
@@ -31,15 +31,17 @@ export function resolveLocalRuntimeEnv(options) {
|
|
|
31
31
|
if (!root || !link) {
|
|
32
32
|
return null;
|
|
33
33
|
}
|
|
34
|
-
const
|
|
35
|
-
|
|
34
|
+
const branch = currentBranch(root);
|
|
35
|
+
if (!branch) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
36
38
|
const tenantApiUrl = buildTenantApiUrl(link.projectId, branch, link.tenantApiBaseUrl);
|
|
37
39
|
return {
|
|
38
40
|
// `env` stays the field name: `resolveLocalRuntimeEnv` is a published
|
|
39
41
|
// `fimo/config` export that framework adapters destructure.
|
|
40
42
|
env: branch,
|
|
41
43
|
tenantApiUrl,
|
|
42
|
-
source:
|
|
44
|
+
source: 'branch',
|
|
43
45
|
values: buildLocalRuntimeEnv({ tenantApiUrl, branch }),
|
|
44
46
|
link,
|
|
45
47
|
};
|
|
@@ -125,12 +127,12 @@ export function readLocalEnvFiles(cwd) {
|
|
|
125
127
|
*/
|
|
126
128
|
function currentBranch(root) {
|
|
127
129
|
try {
|
|
128
|
-
const branch = execFileSync('git', ['
|
|
130
|
+
const branch = execFileSync('git', ['symbolic-ref', '--short', '-q', 'HEAD'], {
|
|
129
131
|
cwd: root,
|
|
130
132
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
131
133
|
encoding: 'utf-8',
|
|
132
134
|
}).trim();
|
|
133
|
-
return branch &&
|
|
135
|
+
return branch && isValidBranch(branch) ? branch : null;
|
|
134
136
|
}
|
|
135
137
|
catch {
|
|
136
138
|
return null;
|
|
@@ -162,7 +164,10 @@ function readProjectLink(root) {
|
|
|
162
164
|
parsed.projectId.length > 0 &&
|
|
163
165
|
typeof parsed.tenantApiBaseUrl === 'string' &&
|
|
164
166
|
parsed.tenantApiBaseUrl.length > 0) {
|
|
165
|
-
return {
|
|
167
|
+
return {
|
|
168
|
+
projectId: parsed.projectId,
|
|
169
|
+
tenantApiBaseUrl: parsed.tenantApiBaseUrl,
|
|
170
|
+
};
|
|
166
171
|
}
|
|
167
172
|
}
|
|
168
173
|
catch {
|
|
@@ -12,6 +12,7 @@ export declare const DEFAULT_TEMPLATE: TemplateFramework;
|
|
|
12
12
|
* out of `dist`) to reach the package root, then into `templates/<framework>`.
|
|
13
13
|
*/
|
|
14
14
|
export declare function getTemplatePath(framework?: TemplateFramework): string;
|
|
15
|
+
export declare function getWelcomeTemplatePath(): string;
|
|
15
16
|
/**
|
|
16
17
|
* Absolute path to the legacy template at `apps/api/templates/default/`.
|
|
17
18
|
*
|
|
@@ -30,7 +31,9 @@ export declare function getTemplatePath(framework?: TemplateFramework): string;
|
|
|
30
31
|
*/
|
|
31
32
|
export declare function getLegacyTemplateDir(): string;
|
|
32
33
|
export interface ReleaseMeta {
|
|
33
|
-
source: 'npm' | 'dev' | null;
|
|
34
|
+
source: 'npm' | 'url' | 'dev' | null;
|
|
35
|
+
/** Immutable artifact URL, baked into `source: 'url'` development tarballs. */
|
|
36
|
+
url?: string | null;
|
|
34
37
|
}
|
|
35
38
|
export interface DevReleaseVersion {
|
|
36
39
|
devJsonPath: string | null;
|
|
@@ -40,7 +43,11 @@ export declare function readReleaseMeta(): ReleaseMeta;
|
|
|
40
43
|
export declare function readCliSemver(): string | null;
|
|
41
44
|
/**
|
|
42
45
|
* Pure version: given a release manifest + CLI semver, return the value
|
|
43
|
-
* to pin `fimo` to (or null
|
|
46
|
+
* to pin `fimo` to (or null when nothing is known). Exported for unit tests.
|
|
47
|
+
*
|
|
48
|
+
* Throws rather than returning an unreproducible pin: a project that records a
|
|
49
|
+
* package-manager cache path (or a `fimo` its companions cannot follow) is
|
|
50
|
+
* broken on every other machine, and the error names the missing publish step.
|
|
44
51
|
*/
|
|
45
52
|
export declare function computeFimoPin(meta: ReleaseMeta, semver: string | null, options?: {
|
|
46
53
|
devPackageRoot?: string | null;
|
|
@@ -42,6 +42,9 @@ export const DEFAULT_TEMPLATE = 'nextjs';
|
|
|
42
42
|
export function getTemplatePath(framework = DEFAULT_TEMPLATE) {
|
|
43
43
|
return path.resolve(PACKAGE_ROOT, 'templates', framework);
|
|
44
44
|
}
|
|
45
|
+
export function getWelcomeTemplatePath() {
|
|
46
|
+
return path.resolve(PACKAGE_ROOT, 'templates', 'welcome');
|
|
47
|
+
}
|
|
45
48
|
/**
|
|
46
49
|
* Absolute path to the legacy template at `apps/api/templates/default/`.
|
|
47
50
|
*
|
|
@@ -69,8 +72,8 @@ export function readReleaseMeta() {
|
|
|
69
72
|
try {
|
|
70
73
|
const raw = fs.readFileSync(RELEASE_FILE, 'utf8');
|
|
71
74
|
const parsed = JSON.parse(raw);
|
|
72
|
-
const source = parsed.source === 'npm' || parsed.source === 'dev' ? parsed.source : null;
|
|
73
|
-
return { source };
|
|
75
|
+
const source = parsed.source === 'npm' || parsed.source === 'dev' || parsed.source === 'url' ? parsed.source : null;
|
|
76
|
+
return { source, url: typeof parsed.url === 'string' && parsed.url.length > 0 ? parsed.url : null };
|
|
74
77
|
}
|
|
75
78
|
catch {
|
|
76
79
|
return { source: null };
|
|
@@ -91,16 +94,34 @@ export function readCliSemver() {
|
|
|
91
94
|
}
|
|
92
95
|
/**
|
|
93
96
|
* Pure version: given a release manifest + CLI semver, return the value
|
|
94
|
-
* to pin `fimo` to (or null
|
|
97
|
+
* to pin `fimo` to (or null when nothing is known). Exported for unit tests.
|
|
98
|
+
*
|
|
99
|
+
* Throws rather than returning an unreproducible pin: a project that records a
|
|
100
|
+
* package-manager cache path (or a `fimo` its companions cannot follow) is
|
|
101
|
+
* broken on every other machine, and the error names the missing publish step.
|
|
95
102
|
*/
|
|
96
103
|
export function computeFimoPin(meta, semver, options = {}) {
|
|
97
104
|
if (meta.source === 'npm') {
|
|
98
|
-
|
|
99
|
-
|
|
105
|
+
return semver;
|
|
106
|
+
}
|
|
107
|
+
// A checkout wins over a baked artifact URL: `publish-cli --id` keeps its
|
|
108
|
+
// release.json in the workspace so the next local run still iterates on
|
|
109
|
+
// source, not on the tarball it just uploaded.
|
|
110
|
+
const localPin = options.devPackageRoot ? `file:${options.devPackageRoot}` : null;
|
|
111
|
+
if (localPin && pinsWholeGroup(localPin)) {
|
|
112
|
+
return localPin;
|
|
113
|
+
}
|
|
114
|
+
if (meta.source === 'url') {
|
|
115
|
+
if (!meta.url) {
|
|
116
|
+
throw new Error('Refusing to create a project from a development CLI that was published without a public artifact URL. ' +
|
|
117
|
+
'Republish it remotely with `pnpm -F fimo publish-cli -- --id <task-name>` and install that artifact.');
|
|
100
118
|
}
|
|
119
|
+
return meta.url;
|
|
101
120
|
}
|
|
102
|
-
if (
|
|
103
|
-
|
|
121
|
+
if (localPin) {
|
|
122
|
+
throw new Error(`Refusing to create a project pinned to ${localPin}: that path is not a Fimo checkout, so it is neither ` +
|
|
123
|
+
'reproducible on another machine nor able to pin the matching companion packages. Install `fimo` from npm, ' +
|
|
124
|
+
'or publish this CLI with `pnpm -F fimo publish-cli -- --id <task-name>` and install that artifact.');
|
|
104
125
|
}
|
|
105
126
|
return null;
|
|
106
127
|
}
|
|
@@ -233,6 +254,14 @@ export function deriveFimoPackagePin(name, fimoPin) {
|
|
|
233
254
|
}
|
|
234
255
|
return fimoPin;
|
|
235
256
|
}
|
|
257
|
+
/**
|
|
258
|
+
* Whether every Fimo package can be pinned from this `fimo` pin. A pin that
|
|
259
|
+
* only the CLI can follow leaves the companions on the template's `latest`,
|
|
260
|
+
* which silently mixes channels inside one project (FIMO-2070).
|
|
261
|
+
*/
|
|
262
|
+
function pinsWholeGroup(fimoPin) {
|
|
263
|
+
return FIMO_PACKAGES.every((name) => deriveFimoPackagePin(name, fimoPin) !== null);
|
|
264
|
+
}
|
|
236
265
|
/**
|
|
237
266
|
* Rewrite `fimo` and any companion packages present (in dependencies +
|
|
238
267
|
* devDependencies) to the current pin. Only touches entries that look like a
|
|
@@ -271,23 +271,18 @@ export function validateSchemaFile(absolutePath, file, schemaUids = new Set()) {
|
|
|
271
271
|
file,
|
|
272
272
|
});
|
|
273
273
|
}
|
|
274
|
-
if (!insideStructuredContent || field.type !== 'reference') {
|
|
274
|
+
if (!insideStructuredContent || field.type !== 'reference' || schemaUids.size === 0) {
|
|
275
275
|
return;
|
|
276
276
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
errors.push({
|
|
287
|
-
rule: 'schemas/reference-target',
|
|
288
|
-
message: `Reference field "${path.join('.')}" targets unknown schema "${field.target}".`,
|
|
289
|
-
file,
|
|
290
|
-
});
|
|
277
|
+
const referenceTargets = Array.isArray(field.targets) ? field.targets : field.target ? [field.target] : [];
|
|
278
|
+
for (const target of referenceTargets) {
|
|
279
|
+
if (!schemaUids.has(target)) {
|
|
280
|
+
errors.push({
|
|
281
|
+
rule: 'schemas/reference-target',
|
|
282
|
+
message: `Reference field "${path.join('.')}" targets unknown schema "${target}".`,
|
|
283
|
+
file,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
291
286
|
}
|
|
292
287
|
});
|
|
293
288
|
continue;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fimo",
|
|
3
|
-
"version": "2.2.0
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Fimo CLI - create, deploy, and manage Fimo projects",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"astro-component"
|
|
@@ -176,6 +176,7 @@
|
|
|
176
176
|
"test:integration:frameworks": "vitest run --config vitest.integration.config.ts",
|
|
177
177
|
"test:integration:next": "vitest run --config vitest.integration.config.ts test/integration/next-runtime.test.ts",
|
|
178
178
|
"test:integration:sveltekit": "vitest run --config vitest.integration.config.ts test/integration/sveltekit-runtime.test.ts",
|
|
179
|
+
"test:package-manager-compat": "pnpm --workspace-root run build --filter=fimo && node test/package-manager-compat/run.mjs",
|
|
179
180
|
"test:watch": "vitest",
|
|
180
181
|
"clean": "rm -rf dist *.tsbuildinfo"
|
|
181
182
|
},
|
|
@@ -183,17 +184,18 @@
|
|
|
183
184
|
"change-case": "^5.4.4",
|
|
184
185
|
"eta": "^3.5.0",
|
|
185
186
|
"oxc-parser": "^0.118.0",
|
|
186
|
-
"zod": "4.
|
|
187
|
+
"zod": "4.5.2"
|
|
187
188
|
},
|
|
188
189
|
"devDependencies": {
|
|
189
190
|
"@clack/core": "^1.2.0",
|
|
190
191
|
"@clack/prompts": "^1.2.0",
|
|
191
|
-
"@fimo/agents-bundle": "2.2.0
|
|
192
|
-
"@fimo/api-contracts": "2.2.0
|
|
193
|
-
"@fimo/cli-kit": "2.2.0
|
|
194
|
-
"@fimo/framework-detect": "2.2.0
|
|
195
|
-
"@fimo/routes": "2.2.0
|
|
196
|
-
"@fimo/
|
|
192
|
+
"@fimo/agents-bundle": "2.2.0",
|
|
193
|
+
"@fimo/api-contracts": "2.2.0",
|
|
194
|
+
"@fimo/cli-kit": "2.2.0",
|
|
195
|
+
"@fimo/framework-detect": "2.2.0",
|
|
196
|
+
"@fimo/routes": "2.2.0",
|
|
197
|
+
"@fimo/sdk": "2.2.0",
|
|
198
|
+
"@fimo/tsconfig": "2.2.0",
|
|
197
199
|
"@types/node": "22.18.6",
|
|
198
200
|
"agent-install": "^0.0.5",
|
|
199
201
|
"astro": "^7.1.6",
|
package/release.json
CHANGED
|
@@ -28,7 +28,7 @@ a code-only task, or use `npx fimo@latest` for project-local code generation and
|
|
|
28
28
|
|
|
29
29
|
- **Deploy is on-demand**, not a save step. Batch related edits into one deploy.
|
|
30
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
|
-
- Treat the user's language request as part of setup. The first explicitly requested locale is the primary locale
|
|
31
|
+
- Treat the user's language request as part of setup. The first explicitly requested locale is the primary locale. Load `fimo skills get fimo-cli --ref locales` and use `fimo locales` to configure the exact locale set and default. Never edit `i18n.defaultLocale` or `i18n.locales` directly. If no language is requested, keep `en` and state that choice. Astro reads the synchronized config, 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.
|
|
34
34
|
- Astro owns routes, locale resolution, links, HTML language/direction, and SEO. Fimo connects to those decisions.
|
|
@@ -36,11 +36,11 @@ The scaffolded homepage is disposable. Replace it on the first real generation.
|
|
|
36
36
|
|
|
37
37
|
- **Deploy is on-demand**, not a save step. Batch related edits into one deploy.
|
|
38
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
|
|
39
|
+
- Treat the user's language request as part of setup. The first explicitly requested locale is the primary locale. Load `fimo skills get fimo-cli --ref locales` and use `fimo locales` to configure the exact locale set and default. Never edit `i18n.defaultLocale` or `i18n.locales` directly. If no language is requested, keep `en` and state that choice. `src/locales.ts` reads the synchronized config, so the served language and `<html lang>` follow. Locale configuration does not create locale URLs; implement a URL strategy only when the product asks for one. Never introduce a default-locale environment variable.
|
|
40
40
|
- Next's `app` tree is the router and stays authoritative: the default shell 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
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
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
|
-
- The application owns routes, locale resolution, links, HTML language/direction, and SEO. Fimo
|
|
43
|
+
- The application owns routes, locale resolution, links, HTML language/direction, and per-page SEO overrides. Fimo supplies the site-wide SEO defaults (title, description, favicon, share image) from `.fimo/config.json#seo` through the root layout's `generateMetadata`/`generateViewport` (`buildFimoMetadata`/`buildFimoViewport` from `fimo-next`); keep that wiring, and add page-level `metadata`/`generateMetadata` exports where a page needs its own values — they merge over the defaults.
|
|
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`.
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@tanstack/react-query": "^5.80.6",
|
|
15
|
-
"fimo": "2.2.0
|
|
16
|
-
"fimo-next": "2.2.0
|
|
17
|
-
"fimo-react": "2.2.0
|
|
15
|
+
"fimo": "2.2.0",
|
|
16
|
+
"fimo-next": "2.2.0",
|
|
17
|
+
"fimo-react": "2.2.0",
|
|
18
18
|
"next": "^16.3.3",
|
|
19
19
|
"react": "^19.2.7",
|
|
20
20
|
"react-dom": "^19.2.7"
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { FimoProvider } from 'fimo-next';
|
|
1
|
+
import { FimoProvider, buildFimoMetadata, buildFimoViewport } from 'fimo-next';
|
|
2
2
|
import type { ReactNode } from 'react';
|
|
3
3
|
|
|
4
4
|
import { defaultLocale } from '../locales';
|
|
5
5
|
|
|
6
6
|
import './globals.css';
|
|
7
7
|
|
|
8
|
+
export const generateMetadata = () => buildFimoMetadata();
|
|
9
|
+
export const generateViewport = () => buildFimoViewport();
|
|
10
|
+
|
|
8
11
|
export default function RootLayout({ children }: Readonly<{ children: ReactNode }>) {
|
|
9
12
|
return (
|
|
10
13
|
<html lang={defaultLocale}>
|
|
@@ -41,8 +41,8 @@ breaks that. Load `fimo-code` for the exact primitives, but the rule is:
|
|
|
41
41
|
|
|
42
42
|
- **Deploy is on-demand**, not a save step. Batch related edits into one deploy.
|
|
43
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
|
-
- Treat the user's language request as part of setup. The first explicitly requested locale is the primary locale
|
|
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 `/`.
|
|
44
|
+
- Treat the user's language request as part of setup. The first explicitly requested locale is the primary locale. Load `fimo skills get fimo-cli --ref locales` and use `fimo locales` to configure the exact locale set and default. Never edit `i18n.defaultLocale` or `i18n.locales` directly. If no language is requested, keep `en` and state that choice.
|
|
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 `/`. Configured locales use the same 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.
|
|
47
47
|
- Do not add a second deploy tool (Vercel, Netlify, etc.).
|
|
48
48
|
- **Never edit `.fimo/project.json`** — it links this folder to the remote project.
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
"cmdk": "^1.1.1",
|
|
22
22
|
"date-fns": "^4.1.0",
|
|
23
23
|
"embla-carousel-react": "^8.6.0",
|
|
24
|
-
"fimo": "2.2.0
|
|
25
|
-
"fimo-react": "2.2.0
|
|
26
|
-
"fimo-react-router": "2.2.0
|
|
27
|
-
"fimo-vite": "2.2.0
|
|
24
|
+
"fimo": "2.2.0",
|
|
25
|
+
"fimo-react": "2.2.0",
|
|
26
|
+
"fimo-react-router": "2.2.0",
|
|
27
|
+
"fimo-vite": "2.2.0",
|
|
28
28
|
"input-otp": "^1.4.2",
|
|
29
29
|
"isbot": "^5",
|
|
30
30
|
"lucide-react": "^0.577.0",
|
|
@@ -28,7 +28,7 @@ a code-only task, or use `npx fimo@latest` for project-local code generation and
|
|
|
28
28
|
|
|
29
29
|
- **Deploy is on-demand**, not a save step. Batch related edits into one deploy.
|
|
30
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
|
-
- Treat the user's language request as part of setup. The first explicitly requested locale is the primary locale
|
|
31
|
+
- Treat the user's language request as part of setup. The first explicitly requested locale is the primary locale. Load `fimo skills get fimo-cli --ref locales` and use `fimo locales` to configure the exact locale set and default. Never edit `i18n.defaultLocale` or `i18n.locales` directly. If no language is requested, keep `en` and state that choice. `src/locales.ts` derives the default and prefixed locale set from the synchronized 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.
|
|
34
34
|
- Keep `.fimo/config.json#routes` as Studio metadata aligned with SvelteKit's route files. It does not configure SvelteKit routing.
|