create-lumen 1.2.0 → 2.0.0-alpha.1
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/README.md +71 -9
- package/bin/cli.js +18 -4
- package/package.json +15 -4
- package/schema/fixtures/index.js +62 -0
- package/schema/fixtures/v2/invalid/architecture-preset-type-mismatch.json +35 -0
- package/schema/fixtures/v2/invalid/harness-empty-commands.json +37 -0
- package/schema/fixtures/v2/invalid/harness-missing-command.json +41 -0
- package/schema/fixtures/v2/invalid/invalid-manifest-version.json +33 -0
- package/schema/fixtures/v2/invalid/invalid-validation-mode.json +34 -0
- package/schema/fixtures/v2/invalid/malformed-paths.json +33 -0
- package/schema/fixtures/v2/invalid/missing-required-fields.json +17 -0
- package/schema/fixtures/v2/invalid/next-type-based.json +33 -0
- package/schema/fixtures/v2/invalid/next-vite.json +33 -0
- package/schema/fixtures/v2/invalid/react-bundler.json +34 -0
- package/schema/fixtures/v2/invalid/react-hybrid.json +33 -0
- package/schema/fixtures/v2/invalid/react-variant-mismatch.json +33 -0
- package/schema/fixtures/v2/invalid/shadcn-without-tailwind.json +33 -0
- package/schema/fixtures/v2/invalid/v1-flat-config.json +11 -0
- package/schema/fixtures/v2/valid/full-kitchen-sink.json +35 -0
- package/schema/fixtures/v2/valid/harness-full.json +44 -0
- package/schema/fixtures/v2/valid/next-app-router-feature-based.json +35 -0
- package/schema/fixtures/v2/valid/next-app-router-hybrid.json +35 -0
- package/schema/fixtures/v2/valid/next-app-router-none.json +33 -0
- package/schema/fixtures/v2/valid/next-pages-router-feature-based.json +35 -0
- package/schema/fixtures/v2/valid/next-pages-router-hybrid.json +35 -0
- package/schema/fixtures/v2/valid/next-pages-router-none.json +33 -0
- package/schema/fixtures/v2/valid/react-vite-feature-based.json +33 -0
- package/schema/fixtures/v2/valid/react-vite-none.json +33 -0
- package/schema/fixtures/v2/valid/react-vite-type-based.json +33 -0
- package/schema/fixtures/v2/valid/validation-none.json +41 -0
- package/schema/fixtures/v2/valid/validation-relaxed.json +41 -0
- package/schema/lumen.config.v2.json +269 -0
- package/skills/create-lumen/SKILL.md +110 -0
- package/skills/create-lumen/references/manifest-v2.md +9 -0
- package/src/agent-context.js +114 -0
- package/src/cli-args.js +294 -0
- package/src/css.js +20 -9
- package/src/dependencies.js +12 -6
- package/src/engine/capabilities.js +218 -0
- package/src/engine/index.js +2 -0
- package/src/engine/providers/base-provider.js +219 -0
- package/src/injector.js +26 -13
- package/src/main.js +66 -10
- package/src/manifest/emit.js +166 -0
- package/src/manifest/index.js +11 -0
- package/src/manifest/paths.js +128 -0
- package/src/manifest/schema.js +270 -0
- package/src/prompts.js +26 -6
- package/templates/conditional/linting/eslint/next/eslint.config.mjs +16 -0
- package/templates/css/tailwind/postcss.config.mjs +5 -0
- /package/templates/architectures/{component-based → type-based}/main.jsx +0 -0
- /package/templates/architectures/{component-based → type-based}/main.tsx +0 -0
- /package/templates/architectures/{component-based → type-based}/src/App.jsx +0 -0
- /package/templates/architectures/{component-based → type-based}/src/App.tsx +0 -0
- /package/templates/architectures/{component-based → type-based}/src/components/common/Button.jsx +0 -0
- /package/templates/architectures/{component-based → type-based}/src/components/common/Button.tsx +0 -0
- /package/templates/architectures/{component-based → type-based}/src/components/common/index.js +0 -0
- /package/templates/architectures/{component-based → type-based}/src/components/common/index.ts +0 -0
- /package/templates/architectures/{component-based → type-based}/src/components/form/.gitkeep +0 -0
- /package/templates/architectures/{component-based → type-based}/src/config/.gitkeep +0 -0
- /package/templates/architectures/{component-based → type-based}/src/hooks/useApp.js +0 -0
- /package/templates/architectures/{component-based → type-based}/src/hooks/useApp.ts +0 -0
- /package/templates/architectures/{component-based → type-based}/src/hooks/useLocalStorage.jsx +0 -0
- /package/templates/architectures/{component-based → type-based}/src/hooks/useLocalStorage.ts +0 -0
- /package/templates/architectures/{component-based → type-based}/src/layouts/MainLayout.jsx +0 -0
- /package/templates/architectures/{component-based → type-based}/src/layouts/MainLayout.tsx +0 -0
- /package/templates/architectures/{component-based → type-based}/src/pages/Home/Home.jsx +0 -0
- /package/templates/architectures/{component-based → type-based}/src/pages/Home/Home.tsx +0 -0
- /package/templates/architectures/{component-based → type-based}/src/pages/Home/index.js +0 -0
- /package/templates/architectures/{component-based → type-based}/src/pages/Home/index.ts +0 -0
- /package/templates/architectures/{component-based → type-based}/src/providers/.gitkeep +0 -0
- /package/templates/architectures/{component-based → type-based}/src/providers/AppProvider.jsx +0 -0
- /package/templates/architectures/{component-based → type-based}/src/providers/AppProvider.tsx +0 -0
- /package/templates/architectures/{component-based → type-based}/src/providers/appcontext.js +0 -0
- /package/templates/architectures/{component-based → type-based}/src/providers/appcontext.ts +0 -0
- /package/templates/architectures/{component-based → type-based}/src/services/.gitkeep +0 -0
- /package/templates/architectures/{component-based → type-based}/src/store/.gitkeep +0 -0
- /package/templates/architectures/{component-based → type-based}/src/styles/.gitkeep +0 -0
- /package/templates/architectures/{component-based → type-based}/src/types/index.js +0 -0
- /package/templates/architectures/{component-based → type-based}/src/types/index.ts +0 -0
- /package/templates/architectures/{component-based → type-based}/src/utils/cn.jsx +0 -0
- /package/templates/architectures/{component-based → type-based}/src/utils/cn.ts +0 -0
- /package/templates/conditional/axios/{component-based → type-based}/src/config/axios.config.js +0 -0
- /package/templates/conditional/axios/{component-based → type-based}/src/config/axios.config.ts +0 -0
- /package/templates/conditional/axios/{component-based → type-based}/src/services/axios.client.js +0 -0
- /package/templates/conditional/axios/{component-based → type-based}/src/services/axios.client.ts +0 -0
- /package/templates/conditional/axios/{component-based → type-based}/src/services/user.service.js +0 -0
- /package/templates/conditional/axios/{component-based → type-based}/src/services/user.service.ts +0 -0
- /package/templates/conditional/fetch/{component-based → type-based}/src/config/api.config.js +0 -0
- /package/templates/conditional/fetch/{component-based → type-based}/src/config/api.config.ts +0 -0
- /package/templates/conditional/fetch/{component-based → type-based}/src/services/api.client.js +0 -0
- /package/templates/conditional/fetch/{component-based → type-based}/src/services/api.client.ts +0 -0
- /package/templates/conditional/fetch/{component-based → type-based}/src/services/user.service.js +0 -0
- /package/templates/conditional/fetch/{component-based → type-based}/src/services/user.service.ts +0 -0
- /package/templates/conditional/icons/huge/{component-based → type-based}/bootstrap/src/pages/Home/Home.jsx +0 -0
- /package/templates/conditional/icons/huge/{component-based → type-based}/bootstrap/src/pages/Home/Home.tsx +0 -0
- /package/templates/conditional/icons/huge/{component-based → type-based}/src/pages/Home/Home.jsx +0 -0
- /package/templates/conditional/icons/huge/{component-based → type-based}/src/pages/Home/Home.tsx +0 -0
- /package/templates/conditional/icons/huge/{component-based → type-based}/tailwind/src/pages/Home/Home.jsx +0 -0
- /package/templates/conditional/icons/huge/{component-based → type-based}/tailwind/src/pages/Home/Home.tsx +0 -0
- /package/templates/conditional/icons/lucide/{component-based → type-based}/bootstrap/src/pages/Home/Home.jsx +0 -0
- /package/templates/conditional/icons/lucide/{component-based → type-based}/bootstrap/src/pages/Home/Home.tsx +0 -0
- /package/templates/conditional/icons/lucide/{component-based → type-based}/src/pages/Home/Home.jsx +0 -0
- /package/templates/conditional/icons/lucide/{component-based → type-based}/src/pages/Home/Home.tsx +0 -0
- /package/templates/conditional/icons/lucide/{component-based → type-based}/tailwind/src/pages/Home/Home.jsx +0 -0
- /package/templates/conditional/icons/lucide/{component-based → type-based}/tailwind/src/pages/Home/Home.tsx +0 -0
- /package/templates/conditional/router/{component-based → type-based}/bootstrap/src/layouts/MainLayout.jsx +0 -0
- /package/templates/conditional/router/{component-based → type-based}/bootstrap/src/layouts/MainLayout.tsx +0 -0
- /package/templates/conditional/router/{component-based → type-based}/src/App.jsx +0 -0
- /package/templates/conditional/router/{component-based → type-based}/src/App.tsx +0 -0
- /package/templates/conditional/router/{component-based → type-based}/src/layouts/MainLayout.jsx +0 -0
- /package/templates/conditional/router/{component-based → type-based}/src/layouts/MainLayout.tsx +0 -0
- /package/templates/conditional/router/{component-based → type-based}/src/router/guards/AuthGuard.jsx +0 -0
- /package/templates/conditional/router/{component-based → type-based}/src/router/guards/AuthGuard.tsx +0 -0
- /package/templates/conditional/router/{component-based → type-based}/src/router/guards/GuestGuard.jsx +0 -0
- /package/templates/conditional/router/{component-based → type-based}/src/router/guards/GuestGuard.tsx +0 -0
- /package/templates/conditional/router/{component-based → type-based}/src/router/index.jsx +0 -0
- /package/templates/conditional/router/{component-based → type-based}/src/router/index.tsx +0 -0
- /package/templates/conditional/router/{component-based → type-based}/tailwind/src/layouts/MainLayout.jsx +0 -0
- /package/templates/conditional/router/{component-based → type-based}/tailwind/src/layouts/MainLayout.tsx +0 -0
- /package/templates/conditional/state/redux/{component-based → type-based}/src/pages/Home/counterSlice.jsx +0 -0
- /package/templates/conditional/state/redux/{component-based → type-based}/src/pages/Home/counterSlice.ts +0 -0
- /package/templates/conditional/state/redux/{component-based → type-based}/src/providers/StoreProvider.jsx +0 -0
- /package/templates/conditional/state/redux/{component-based → type-based}/src/providers/StoreProvider.tsx +0 -0
- /package/templates/conditional/state/redux/{component-based → type-based}/src/store/hooks.js +0 -0
- /package/templates/conditional/state/redux/{component-based → type-based}/src/store/hooks.ts +0 -0
- /package/templates/conditional/state/redux/{component-based → type-based}/src/store/index.js +0 -0
- /package/templates/conditional/state/redux/{component-based → type-based}/src/store/index.ts +0 -0
- /package/templates/conditional/state/zustand/{component-based → type-based}/src/store/useCounterStore.jsx +0 -0
- /package/templates/conditional/state/zustand/{component-based → type-based}/src/store/useCounterStore.ts +0 -0
- /package/templates/conditional/testing/jest/{component-based → type-based}/src/__tests__/App.test.jsx +0 -0
- /package/templates/conditional/testing/jest/{component-based → type-based}/src/__tests__/App.test.tsx +0 -0
- /package/templates/conditional/testing/vitest/{component-based → type-based}/src/__tests__/App.test.jsx +0 -0
- /package/templates/conditional/testing/vitest/{component-based → type-based}/src/__tests__/App.test.tsx +0 -0
- /package/templates/css/component-styles/bootstrap/{component-based → type-based}/src/components/common/Button.jsx +0 -0
- /package/templates/css/component-styles/bootstrap/{component-based → type-based}/src/components/common/Button.tsx +0 -0
- /package/templates/css/component-styles/bootstrap/{component-based → type-based}/src/layouts/MainLayout.jsx +0 -0
- /package/templates/css/component-styles/bootstrap/{component-based → type-based}/src/layouts/MainLayout.tsx +0 -0
- /package/templates/css/component-styles/bootstrap/{component-based → type-based}/src/pages/Home/Home.jsx +0 -0
- /package/templates/css/component-styles/bootstrap/{component-based → type-based}/src/pages/Home/Home.tsx +0 -0
- /package/templates/css/component-styles/tailwind/{component-based → type-based}/src/components/common/Button.jsx +0 -0
- /package/templates/css/component-styles/tailwind/{component-based → type-based}/src/components/common/Button.tsx +0 -0
- /package/templates/css/component-styles/tailwind/{component-based → type-based}/src/layouts/MainLayout.jsx +0 -0
- /package/templates/css/component-styles/tailwind/{component-based → type-based}/src/layouts/MainLayout.tsx +0 -0
- /package/templates/css/component-styles/tailwind/{component-based → type-based}/src/pages/Home/Home.jsx +0 -0
- /package/templates/css/component-styles/tailwind/{component-based → type-based}/src/pages/Home/Home.tsx +0 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://lumen-sh.github.io/create-lumen/schema/lumen.config.v2.json",
|
|
4
|
+
"title": "Lumen manifest v2",
|
|
5
|
+
"description": "Schema for lumen.config.json v2 - emitted by create-lumen, consumed by lumen-cli. See docs/manifest-v2.md",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"$schema": {
|
|
9
|
+
"default": "https://lumen-sh.github.io/create-lumen/schema/lumen.config.v2.json",
|
|
10
|
+
"type": "string",
|
|
11
|
+
"format": "uri"
|
|
12
|
+
},
|
|
13
|
+
"manifestVersion": {
|
|
14
|
+
"type": "number",
|
|
15
|
+
"const": 2
|
|
16
|
+
},
|
|
17
|
+
"framework": {
|
|
18
|
+
"type": "object",
|
|
19
|
+
"properties": {
|
|
20
|
+
"name": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"enum": [
|
|
23
|
+
"react",
|
|
24
|
+
"next"
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
"variant": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"enum": [
|
|
30
|
+
"vite",
|
|
31
|
+
"app-router",
|
|
32
|
+
"pages-router"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
"bundler": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"enum": [
|
|
38
|
+
"turbopack",
|
|
39
|
+
"webpack"
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"adapter": {
|
|
43
|
+
"type": "string",
|
|
44
|
+
"enum": [
|
|
45
|
+
"node",
|
|
46
|
+
"vercel",
|
|
47
|
+
"cloudflare",
|
|
48
|
+
"static"
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"required": [
|
|
53
|
+
"name",
|
|
54
|
+
"variant"
|
|
55
|
+
],
|
|
56
|
+
"additionalProperties": false
|
|
57
|
+
},
|
|
58
|
+
"styling": {
|
|
59
|
+
"type": "object",
|
|
60
|
+
"properties": {
|
|
61
|
+
"engine": {
|
|
62
|
+
"type": "string",
|
|
63
|
+
"enum": [
|
|
64
|
+
"tailwind",
|
|
65
|
+
"bootstrap",
|
|
66
|
+
"none"
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"required": [
|
|
71
|
+
"engine"
|
|
72
|
+
],
|
|
73
|
+
"additionalProperties": false
|
|
74
|
+
},
|
|
75
|
+
"architecture": {
|
|
76
|
+
"type": "object",
|
|
77
|
+
"properties": {
|
|
78
|
+
"preset": {
|
|
79
|
+
"type": "string",
|
|
80
|
+
"enum": [
|
|
81
|
+
"feature-based",
|
|
82
|
+
"type-based",
|
|
83
|
+
"hybrid",
|
|
84
|
+
"none"
|
|
85
|
+
]
|
|
86
|
+
},
|
|
87
|
+
"type": {
|
|
88
|
+
"type": "string",
|
|
89
|
+
"enum": [
|
|
90
|
+
"feature-based",
|
|
91
|
+
"type-based",
|
|
92
|
+
"hybrid",
|
|
93
|
+
"none"
|
|
94
|
+
]
|
|
95
|
+
},
|
|
96
|
+
"validation": {
|
|
97
|
+
"default": "strict",
|
|
98
|
+
"type": "string",
|
|
99
|
+
"enum": [
|
|
100
|
+
"strict",
|
|
101
|
+
"relaxed",
|
|
102
|
+
"none"
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
"additionalProperties": false
|
|
107
|
+
},
|
|
108
|
+
"harness": {
|
|
109
|
+
"type": "object",
|
|
110
|
+
"properties": {
|
|
111
|
+
"commands": {
|
|
112
|
+
"minItems": 1,
|
|
113
|
+
"type": "array",
|
|
114
|
+
"items": {
|
|
115
|
+
"type": "object",
|
|
116
|
+
"properties": {
|
|
117
|
+
"name": {
|
|
118
|
+
"type": "string",
|
|
119
|
+
"minLength": 1
|
|
120
|
+
},
|
|
121
|
+
"command": {
|
|
122
|
+
"type": "string",
|
|
123
|
+
"minLength": 1
|
|
124
|
+
},
|
|
125
|
+
"required": {
|
|
126
|
+
"default": true,
|
|
127
|
+
"type": "boolean"
|
|
128
|
+
},
|
|
129
|
+
"description": {
|
|
130
|
+
"type": "string"
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
"required": [
|
|
134
|
+
"name",
|
|
135
|
+
"command"
|
|
136
|
+
],
|
|
137
|
+
"additionalProperties": false
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
"required": [
|
|
142
|
+
"commands"
|
|
143
|
+
],
|
|
144
|
+
"additionalProperties": false
|
|
145
|
+
},
|
|
146
|
+
"ui": {
|
|
147
|
+
"type": "object",
|
|
148
|
+
"properties": {
|
|
149
|
+
"kit": {
|
|
150
|
+
"type": "string",
|
|
151
|
+
"enum": [
|
|
152
|
+
"shadcn",
|
|
153
|
+
"none"
|
|
154
|
+
]
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
"required": [
|
|
158
|
+
"kit"
|
|
159
|
+
],
|
|
160
|
+
"additionalProperties": false
|
|
161
|
+
},
|
|
162
|
+
"docs": {
|
|
163
|
+
"type": "object",
|
|
164
|
+
"properties": {
|
|
165
|
+
"language": {
|
|
166
|
+
"type": "string",
|
|
167
|
+
"enum": [
|
|
168
|
+
"en",
|
|
169
|
+
"es"
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
"required": [
|
|
174
|
+
"language"
|
|
175
|
+
],
|
|
176
|
+
"additionalProperties": false
|
|
177
|
+
},
|
|
178
|
+
"paths": {
|
|
179
|
+
"type": "object",
|
|
180
|
+
"properties": {
|
|
181
|
+
"features": {
|
|
182
|
+
"type": "string",
|
|
183
|
+
"minLength": 1
|
|
184
|
+
},
|
|
185
|
+
"components": {
|
|
186
|
+
"type": "string",
|
|
187
|
+
"minLength": 1
|
|
188
|
+
},
|
|
189
|
+
"services": {
|
|
190
|
+
"type": "string",
|
|
191
|
+
"minLength": 1
|
|
192
|
+
},
|
|
193
|
+
"hooks": {
|
|
194
|
+
"type": "string",
|
|
195
|
+
"minLength": 1
|
|
196
|
+
},
|
|
197
|
+
"pages": {
|
|
198
|
+
"type": "string",
|
|
199
|
+
"minLength": 1
|
|
200
|
+
},
|
|
201
|
+
"ui": {
|
|
202
|
+
"type": "string",
|
|
203
|
+
"minLength": 1
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
"required": [
|
|
207
|
+
"features",
|
|
208
|
+
"components",
|
|
209
|
+
"services",
|
|
210
|
+
"hooks",
|
|
211
|
+
"pages",
|
|
212
|
+
"ui"
|
|
213
|
+
],
|
|
214
|
+
"additionalProperties": false
|
|
215
|
+
},
|
|
216
|
+
"tooling": {
|
|
217
|
+
"type": "object",
|
|
218
|
+
"properties": {
|
|
219
|
+
"language": {
|
|
220
|
+
"type": "string",
|
|
221
|
+
"enum": [
|
|
222
|
+
"ts",
|
|
223
|
+
"js"
|
|
224
|
+
]
|
|
225
|
+
},
|
|
226
|
+
"linter": {
|
|
227
|
+
"type": "string",
|
|
228
|
+
"enum": [
|
|
229
|
+
"eslint",
|
|
230
|
+
"oxlint",
|
|
231
|
+
"biome",
|
|
232
|
+
"none"
|
|
233
|
+
]
|
|
234
|
+
},
|
|
235
|
+
"formatter": {
|
|
236
|
+
"type": "string",
|
|
237
|
+
"enum": [
|
|
238
|
+
"prettier",
|
|
239
|
+
"oxfmt",
|
|
240
|
+
"none"
|
|
241
|
+
]
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
"required": [
|
|
245
|
+
"language",
|
|
246
|
+
"linter",
|
|
247
|
+
"formatter"
|
|
248
|
+
],
|
|
249
|
+
"additionalProperties": false
|
|
250
|
+
},
|
|
251
|
+
"reactCompiler": {
|
|
252
|
+
"type": "boolean"
|
|
253
|
+
},
|
|
254
|
+
"agentDocs": {
|
|
255
|
+
"type": "boolean"
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
"required": [
|
|
259
|
+
"manifestVersion",
|
|
260
|
+
"framework",
|
|
261
|
+
"styling",
|
|
262
|
+
"architecture",
|
|
263
|
+
"ui",
|
|
264
|
+
"docs",
|
|
265
|
+
"paths",
|
|
266
|
+
"tooling"
|
|
267
|
+
],
|
|
268
|
+
"additionalProperties": false
|
|
269
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: create-lumen
|
|
3
|
+
description: Scaffold and extend a lumen v2 project (manifestVersion 2). Read lumen.config.json, resolve generator paths via manifest.paths, respect feature barrels, @/* alias, harness commands, and validation modes.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# create-lumen
|
|
7
|
+
|
|
8
|
+
## When to use
|
|
9
|
+
|
|
10
|
+
Use this skill when the working directory contains (or should contain) a
|
|
11
|
+
`lumen.config.json` with `manifestVersion: 2`: scaffolding follow-ups,
|
|
12
|
+
`lumen g` generation, `lumen doctor` / `lumen harness` diagnostics.
|
|
13
|
+
|
|
14
|
+
Do NOT guess layout. Every target directory comes from the manifest.
|
|
15
|
+
|
|
16
|
+
## 1. Read `lumen.config.json`
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
cat lumen.config.json
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Required top-level keys: `manifestVersion: 2`, `framework`, `styling`,
|
|
23
|
+
`architecture`, `ui`, `docs`, `paths`, `tooling`, `harness`.
|
|
24
|
+
Source of truth: `src/manifest/schema.js` (`parseManifest`, Zod strict).
|
|
25
|
+
Full spec: `docs/contracts/manifest-v2-contract.md`, `docs/manifest-v2.md`.
|
|
26
|
+
|
|
27
|
+
If `manifestVersion` is missing / `framework` is a string → **v1 manifest**:
|
|
28
|
+
fail fast (exit 1), generate nothing, point to
|
|
29
|
+
`docs/migration/v1-to-v2.md`.
|
|
30
|
+
|
|
31
|
+
## 2. Resolve paths via `manifest.paths` (never hardcode)
|
|
32
|
+
|
|
33
|
+
Generators MUST do `<root>/<manifest.paths.<key>>`. POSIX `/` separators.
|
|
34
|
+
|
|
35
|
+
| Framework | Preset | features | components | services | hooks | pages | ui |
|
|
36
|
+
|---|---|---|---|---|---|---|---|
|
|
37
|
+
| React+Vite | `feature-based` | `src/features` | `src/shared/components` | `src/shared/services` | `src/shared/hooks` | `src/app/router` | `src/shared/components/ui` |
|
|
38
|
+
| React+Vite | `type-based` | `src/features` | `src/components` | `src/services` | `src/hooks` | `src/pages` | `src/ui` |
|
|
39
|
+
| Next App | `feature-based`/`hybrid` | `src/features` | `src/shared/components` | `src/shared/services` | `src/shared/hooks` | `app` | `src/shared/components/ui` |
|
|
40
|
+
| Next Pages | `feature-based` | `src/features` | `src/shared/components` | `src/shared/services` | `src/shared/hooks` | `pages` | `src/shared/components/ui` |
|
|
41
|
+
| Any | `none` | `src` | `src` (`components/` for Next) | `src/services` | `src/hooks` | per framework | `src…/ui` |
|
|
42
|
+
|
|
43
|
+
Resolver: `src/manifest/paths.js` (`resolvePaths`). Fixtures:
|
|
44
|
+
`schema/fixtures/v2/valid/react-vite-feature-based.json`,
|
|
45
|
+
`full-kitchen-sink.json`.
|
|
46
|
+
|
|
47
|
+
## 3. Feature structure + barrels
|
|
48
|
+
|
|
49
|
+
New feature at `<paths.features>/<name>/` (e.g. `src/features/billing`):
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
lumen g feature billing
|
|
53
|
+
lumen g component billing/InvoiceCard --feature billing
|
|
54
|
+
lumen g hook useBilling --feature billing
|
|
55
|
+
lumen g service billing-api --feature billing
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Rules:
|
|
59
|
+
|
|
60
|
+
- Private subfolders: `components/ hooks/ layouts/ pages/ services/ store/ types/`.
|
|
61
|
+
- Public barrel required: `<feature>/index.ts` (or `.js` when
|
|
62
|
+
`tooling.language === "js"`). External code imports only the barrel:
|
|
63
|
+
`import { InvoiceCard } from "@/features/billing"`.
|
|
64
|
+
- Extensions: `.tsx`/`.jsx` for JSX components, `.ts`/`.js` for pure logic,
|
|
65
|
+
per `tooling.language`.
|
|
66
|
+
|
|
67
|
+
## 4. Path alias `@/*`
|
|
68
|
+
|
|
69
|
+
`@/*` → `<root>/src/*` (guaranteed by `tsconfig` + Vite/Next config).
|
|
70
|
+
Feature-based: shared imports via `@/shared/...`.
|
|
71
|
+
Type-based: `@/components/...`, `@/hooks/...`, `@/services/...`.
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import { Button } from "@/shared/components/ui/button";
|
|
75
|
+
import { useBilling } from "@/features/billing";
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## 5. `harness.commands` execution
|
|
79
|
+
|
|
80
|
+
`lumen harness` runs each entry in order; `required: true` (default) fails
|
|
81
|
+
the run on error, `required: false` warns and continues.
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{ "name": "lint", "command": "oxlint .", "required": true }
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Defaults: `lint (oxlint .)`, `format (oxfmt --check .)`, `types (tsc -b)`,
|
|
88
|
+
`test (vitest run)`, `build (npm run build)`.
|
|
89
|
+
|
|
90
|
+
## 6. `architecture.validation` modes
|
|
91
|
+
|
|
92
|
+
| Mode | Behavior |
|
|
93
|
+
|---|---|
|
|
94
|
+
| `strict` | Enforce barrels, encapsulation, path rules; fail on violation. |
|
|
95
|
+
| `relaxed` | Warn on violation, still generate. |
|
|
96
|
+
| `none` | Skip architecture checks. |
|
|
97
|
+
|
|
98
|
+
Note: `architecture.preset` is canonical; legacy `type` is accepted as an
|
|
99
|
+
alias (`parseManifest` normalizes both). Valid presets: React →
|
|
100
|
+
`feature-based|type-based|none`; Next → `feature-based|hybrid|none`.
|
|
101
|
+
|
|
102
|
+
## 7. Common errors — reject, don't patch around
|
|
103
|
+
|
|
104
|
+
- **v1 rejection:** flat config (`css`, string `framework`/`architecture`) →
|
|
105
|
+
exit 1 + migration pointer. Never partially generate.
|
|
106
|
+
- **`shadcn` → `tailwind`:** `ui.kit: "shadcn"` requires
|
|
107
|
+
`styling.engine: "tailwind"` (v4 CSS-first, no `tailwind.config.js`).
|
|
108
|
+
- **`bundler`/`adapter` Next-only:** `framework.bundler` (`turbopack|webpack`)
|
|
109
|
+
and `adapter` (`node|vercel|cloudflare|static`) are prohibited on `react`.
|
|
110
|
+
`react` variant MUST be `vite`; `next` MUST be `app-router|pages-router`.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# manifest-v2 pointer
|
|
2
|
+
|
|
3
|
+
Canonical spec lives in `docs/` — do not duplicate it here.
|
|
4
|
+
|
|
5
|
+
- Contract: `docs/contracts/manifest-v2-contract.md`
|
|
6
|
+
- Shape / v1→v2 diff: `docs/manifest-v2.md`
|
|
7
|
+
- Zod source of truth: `src/manifest/schema.js`
|
|
8
|
+
- Path resolver: `src/manifest/paths.js`
|
|
9
|
+
- Valid fixtures: `schema/fixtures/v2/valid/`
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { promises as fsp } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { buildManifest } from "./manifest/emit.js";
|
|
4
|
+
|
|
5
|
+
const VALIDATION_NOTES = {
|
|
6
|
+
strict: "strict: architecture boundaries are enforced — do not import across features except via barrels or shared paths; violations must be fixed.",
|
|
7
|
+
relaxed: "relaxed: architecture boundaries are advisory — prefer barrels and shared paths, but cross-imports only warn.",
|
|
8
|
+
none: "none: no architecture validation — paths are still the canonical locations.",
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
function resolveManifest(manifestOrResponses) {
|
|
12
|
+
if (manifestOrResponses && typeof manifestOrResponses.manifestVersion !== "undefined") {
|
|
13
|
+
return manifestOrResponses;
|
|
14
|
+
}
|
|
15
|
+
if (manifestOrResponses && manifestOrResponses._manifestSource) {
|
|
16
|
+
return manifestOrResponses._manifestSource;
|
|
17
|
+
}
|
|
18
|
+
return buildManifest(manifestOrResponses);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Render the short agent conventions markdown from a manifest.
|
|
23
|
+
* Deterministic: derived only from stable manifest fields.
|
|
24
|
+
* @param {object} manifest - validated manifest v2
|
|
25
|
+
* @returns {string}
|
|
26
|
+
*/
|
|
27
|
+
export function renderConventions(manifest) {
|
|
28
|
+
const preset = manifest.architecture?.preset ?? manifest.architecture?.type ?? "feature-based";
|
|
29
|
+
const validation = manifest.architecture?.validation ?? "strict";
|
|
30
|
+
const paths = manifest.paths ?? {};
|
|
31
|
+
const harness = manifest.harness ?? { commands: [] };
|
|
32
|
+
const barrelFile = manifest.tooling?.language === "js" ? "index.js" : "index.ts";
|
|
33
|
+
|
|
34
|
+
const pathLines = Object.entries(paths)
|
|
35
|
+
.map(([key, value]) => `- ${key}: \`${value}\``)
|
|
36
|
+
.join("\n");
|
|
37
|
+
|
|
38
|
+
const harnessLines = (harness.commands ?? [])
|
|
39
|
+
.map((c) => `- \`${c.name}\`: \`${c.command}\` (${c.required === false ? "optional" : "required"})`)
|
|
40
|
+
.join("\n");
|
|
41
|
+
|
|
42
|
+
const harnessSummary = (harness.commands ?? []).map((c) => `\`${c.command}\``).join(", ");
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
`# Lumen Agent Conventions\n` +
|
|
46
|
+
`\n` +
|
|
47
|
+
`Generated from \`lumen.config.json\`. Resolve every file location via \`paths.*\` in \`.lumen/architecture.json\` (preset: \`${preset}\`, validation: \`${validation}\`).\n` +
|
|
48
|
+
`\n` +
|
|
49
|
+
`## Rules\n` +
|
|
50
|
+
`\n` +
|
|
51
|
+
`- Resolve all paths via \`paths.*\` — never hardcode alternative \`src/...\` locations.\n` +
|
|
52
|
+
`- Feature barrel: every \`src/features/<feature>/\` must re-export its public API via \`${barrelFile}\`.\n` +
|
|
53
|
+
`- Shared code: import shared utilities via \`@/shared\` (plus the \`@/...\` aliases from tsconfig/jsconfig).\n` +
|
|
54
|
+
`- Harness: before finishing, run each command in \`.lumen/project.json\` \`harness.commands\` in order (${harnessSummary}).\n` +
|
|
55
|
+
`- Validation mode \`${validation}\`: ${VALIDATION_NOTES[validation] ?? VALIDATION_NOTES.strict}\n` +
|
|
56
|
+
`\n` +
|
|
57
|
+
`## Paths\n` +
|
|
58
|
+
`\n` +
|
|
59
|
+
`${pathLines}\n` +
|
|
60
|
+
`\n` +
|
|
61
|
+
`## Harness\n` +
|
|
62
|
+
`\n` +
|
|
63
|
+
`${harnessLines}\n`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Build the deterministic agent-context payload from a validated manifest v2.
|
|
69
|
+
* No timestamps — output must be byte-stable.
|
|
70
|
+
* @param {object} manifest - validated manifest v2
|
|
71
|
+
* @returns {{ project: object, architecture: object, conventionsMd: string }}
|
|
72
|
+
*/
|
|
73
|
+
export function buildAgentContext(manifest) {
|
|
74
|
+
const project = {
|
|
75
|
+
manifestVersion: manifest.manifestVersion,
|
|
76
|
+
framework: manifest.framework,
|
|
77
|
+
styling: manifest.styling,
|
|
78
|
+
tooling: manifest.tooling,
|
|
79
|
+
harness: manifest.harness,
|
|
80
|
+
docs: manifest.docs,
|
|
81
|
+
};
|
|
82
|
+
const architecture = {
|
|
83
|
+
preset: manifest.architecture?.preset ?? manifest.architecture?.type,
|
|
84
|
+
validation: manifest.architecture?.validation ?? "strict",
|
|
85
|
+
paths: manifest.paths,
|
|
86
|
+
};
|
|
87
|
+
const conventionsMd = renderConventions(manifest);
|
|
88
|
+
return { project, architecture, conventionsMd };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function writeJson(filePath, value) {
|
|
92
|
+
return fsp.writeFile(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Emit the .lumen agent context dir into a scaffolded project.
|
|
97
|
+
* Accepts either a validated manifest v2 or scaffolder responses
|
|
98
|
+
* (uses responses._manifestSource when present, else buildManifest).
|
|
99
|
+
* Writes .lumen/project.json, .lumen/architecture.json, .lumen/conventions.md
|
|
100
|
+
* with 2-space indent + trailing newline. Byte-deterministic (no timestamps).
|
|
101
|
+
* @param {string} projectPath - absolute path to scaffolded project
|
|
102
|
+
* @param {object} manifestOrResponses
|
|
103
|
+
* @returns {Promise<string>} absolute path to the .lumen dir
|
|
104
|
+
*/
|
|
105
|
+
export async function emitAgentContext(projectPath, manifestOrResponses) {
|
|
106
|
+
const manifest = resolveManifest(manifestOrResponses);
|
|
107
|
+
const { project, architecture, conventionsMd } = buildAgentContext(manifest);
|
|
108
|
+
const dir = path.join(projectPath, ".lumen");
|
|
109
|
+
await fsp.mkdir(dir, { recursive: true });
|
|
110
|
+
await writeJson(path.join(dir, "project.json"), project);
|
|
111
|
+
await writeJson(path.join(dir, "architecture.json"), architecture);
|
|
112
|
+
await fsp.writeFile(path.join(dir, "conventions.md"), conventionsMd, "utf8");
|
|
113
|
+
return dir;
|
|
114
|
+
}
|