@cmssy/cli 0.9.0 ā 0.10.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/config.d.ts +1 -1
- package/dist/cli.js +22 -8
- package/dist/cli.js.map +1 -1
- package/dist/commands/codegen.d.ts +7 -0
- package/dist/commands/codegen.d.ts.map +1 -0
- package/dist/commands/codegen.js +133 -0
- package/dist/commands/codegen.js.map +1 -0
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +5 -2
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/init.d.ts +0 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +342 -352
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/publish.js +109 -4
- package/dist/commands/publish.js.map +1 -1
- package/dist/utils/dev-generator/api-routes/blocks.d.ts +3 -0
- package/dist/utils/dev-generator/api-routes/blocks.d.ts.map +1 -0
- package/dist/utils/dev-generator/api-routes/blocks.js +194 -0
- package/dist/utils/dev-generator/api-routes/blocks.js.map +1 -0
- package/dist/utils/dev-generator/api-routes/config.d.ts +2 -0
- package/dist/utils/dev-generator/api-routes/config.d.ts.map +1 -0
- package/dist/utils/dev-generator/api-routes/config.js +107 -0
- package/dist/utils/dev-generator/api-routes/config.js.map +1 -0
- package/dist/utils/dev-generator/api-routes/preview.d.ts +2 -0
- package/dist/utils/dev-generator/api-routes/preview.d.ts.map +1 -0
- package/dist/utils/dev-generator/api-routes/preview.js +50 -0
- package/dist/utils/dev-generator/api-routes/preview.js.map +1 -0
- package/dist/utils/dev-generator/api-routes/workspaces.d.ts +2 -0
- package/dist/utils/dev-generator/api-routes/workspaces.d.ts.map +1 -0
- package/dist/utils/dev-generator/api-routes/workspaces.js +128 -0
- package/dist/utils/dev-generator/api-routes/workspaces.js.map +1 -0
- package/dist/utils/dev-generator/helpers.d.ts +23 -0
- package/dist/utils/dev-generator/helpers.d.ts.map +1 -0
- package/dist/utils/dev-generator/helpers.js +112 -0
- package/dist/utils/dev-generator/helpers.js.map +1 -0
- package/dist/utils/dev-generator/home-page.d.ts +2 -0
- package/dist/utils/dev-generator/home-page.d.ts.map +1 -0
- package/dist/utils/dev-generator/home-page.js +643 -0
- package/dist/utils/dev-generator/home-page.js.map +1 -0
- package/dist/utils/dev-generator/index.d.ts +12 -0
- package/dist/utils/dev-generator/index.d.ts.map +1 -0
- package/dist/utils/dev-generator/index.js +53 -0
- package/dist/utils/dev-generator/index.js.map +1 -0
- package/dist/utils/dev-generator/layout.d.ts +3 -0
- package/dist/utils/dev-generator/layout.d.ts.map +1 -0
- package/dist/utils/dev-generator/layout.js +59 -0
- package/dist/utils/dev-generator/layout.js.map +1 -0
- package/dist/utils/dev-generator/next-config.d.ts +3 -0
- package/dist/utils/dev-generator/next-config.d.ts.map +1 -0
- package/dist/utils/dev-generator/next-config.js +104 -0
- package/dist/utils/dev-generator/next-config.js.map +1 -0
- package/dist/utils/dev-generator/preview-pages.d.ts +3 -0
- package/dist/utils/dev-generator/preview-pages.d.ts.map +1 -0
- package/dist/utils/dev-generator/preview-pages.js +827 -0
- package/dist/utils/dev-generator/preview-pages.js.map +1 -0
- package/package.json +2 -2
package/dist/commands/init.js
CHANGED
|
@@ -6,295 +6,23 @@ import ora from "ora";
|
|
|
6
6
|
import path from "path";
|
|
7
7
|
import { getFieldTypes } from "../utils/field-schema.js";
|
|
8
8
|
import { generateTypes } from "../utils/type-generator.js";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
answers = {
|
|
15
|
-
projectName: name || "my-blocks",
|
|
16
|
-
authorName: "",
|
|
17
|
-
authorEmail: "",
|
|
18
|
-
initGit: true,
|
|
19
|
-
};
|
|
20
|
-
console.log(chalk.gray(`Using defaults: ${answers.projectName}\n`));
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
answers = await inquirer.prompt([
|
|
24
|
-
{
|
|
25
|
-
type: "input",
|
|
26
|
-
name: "projectName",
|
|
27
|
-
message: "Project name:",
|
|
28
|
-
default: name || "my-blocks",
|
|
29
|
-
validate: (input) => {
|
|
30
|
-
if (/^[a-z0-9-_]+$/.test(input))
|
|
31
|
-
return true;
|
|
32
|
-
return "Project name must contain only lowercase letters, numbers, hyphens, and underscores";
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
type: "input",
|
|
37
|
-
name: "authorName",
|
|
38
|
-
message: "Author name:",
|
|
39
|
-
default: "",
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
type: "input",
|
|
43
|
-
name: "authorEmail",
|
|
44
|
-
message: "Author email:",
|
|
45
|
-
default: "",
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
type: "confirm",
|
|
49
|
-
name: "initGit",
|
|
50
|
-
message: "Initialize git repository?",
|
|
51
|
-
default: true,
|
|
52
|
-
},
|
|
53
|
-
]);
|
|
54
|
-
}
|
|
55
|
-
const projectPath = path.join(process.cwd(), answers.projectName);
|
|
56
|
-
if (fs.existsSync(projectPath)) {
|
|
57
|
-
console.error(chalk.red(`\nā Directory "${answers.projectName}" already exists\n`));
|
|
58
|
-
process.exit(1);
|
|
59
|
-
}
|
|
60
|
-
const spinner = ora("Creating project structure...").start();
|
|
61
|
-
try {
|
|
62
|
-
// Create project directory
|
|
63
|
-
fs.mkdirSync(projectPath, { recursive: true });
|
|
64
|
-
// Create directory structure
|
|
65
|
-
const dirs = ["blocks", "templates", "public", "styles", ".cmssy"];
|
|
66
|
-
dirs.forEach((dir) => {
|
|
67
|
-
fs.mkdirSync(path.join(projectPath, dir), { recursive: true });
|
|
68
|
-
});
|
|
69
|
-
// Create cmssy.config.js
|
|
70
|
-
const config = {
|
|
71
|
-
framework: "react",
|
|
72
|
-
projectName: answers.projectName,
|
|
73
|
-
author: {
|
|
74
|
-
name: answers.authorName,
|
|
75
|
-
email: answers.authorEmail,
|
|
76
|
-
},
|
|
77
|
-
build: {
|
|
78
|
-
outDir: "public",
|
|
79
|
-
minify: true,
|
|
80
|
-
sourcemap: true,
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
|
-
fs.writeFileSync(path.join(projectPath, "cmssy.config.js"), `export default ${JSON.stringify(config, null, 2)};\n`);
|
|
84
|
-
// Create package.json (versions match cmssy platform)
|
|
85
|
-
const packageJson = {
|
|
86
|
-
name: answers.projectName,
|
|
87
|
-
version: "1.0.0",
|
|
88
|
-
type: "module",
|
|
89
|
-
scripts: {
|
|
90
|
-
dev: "cmssy dev",
|
|
91
|
-
build: "cmssy build",
|
|
92
|
-
},
|
|
93
|
-
dependencies: {
|
|
94
|
-
react: "^19.2.0",
|
|
95
|
-
"react-dom": "^19.2.0",
|
|
96
|
-
next: "^16.0.10",
|
|
97
|
-
},
|
|
98
|
-
devDependencies: {
|
|
99
|
-
"@types/node": "^22.0.0",
|
|
100
|
-
"@types/react": "^19.0.0",
|
|
101
|
-
"@types/react-dom": "^19.0.0",
|
|
102
|
-
typescript: "^5.7.2",
|
|
103
|
-
tailwindcss: "^4.1.18",
|
|
104
|
-
"@tailwindcss/postcss": "^4.1.18",
|
|
105
|
-
},
|
|
106
|
-
};
|
|
107
|
-
fs.writeFileSync(path.join(projectPath, "package.json"), JSON.stringify(packageJson, null, 2) + "\n");
|
|
108
|
-
// Create tsconfig.json (jsx: "preserve" for Next.js compatibility)
|
|
109
|
-
const tsConfig = {
|
|
110
|
-
compilerOptions: {
|
|
111
|
-
target: "ES2020",
|
|
112
|
-
module: "ESNext",
|
|
113
|
-
lib: ["ES2020", "DOM", "DOM.Iterable"],
|
|
114
|
-
jsx: "preserve",
|
|
115
|
-
moduleResolution: "bundler",
|
|
116
|
-
allowImportingTsExtensions: true,
|
|
117
|
-
resolveJsonModule: true,
|
|
118
|
-
isolatedModules: true,
|
|
119
|
-
noEmit: true,
|
|
120
|
-
strict: true,
|
|
121
|
-
skipLibCheck: true,
|
|
122
|
-
esModuleInterop: true,
|
|
123
|
-
allowSyntheticDefaultImports: true,
|
|
124
|
-
forceConsistentCasingInFileNames: true,
|
|
125
|
-
plugins: [{ name: "next" }],
|
|
126
|
-
paths: {
|
|
127
|
-
"cmssy-cli/config": ["./node_modules/cmssy-cli/config"],
|
|
128
|
-
},
|
|
129
|
-
},
|
|
130
|
-
include: [
|
|
131
|
-
"blocks/**/*.ts",
|
|
132
|
-
"blocks/**/*.tsx",
|
|
133
|
-
"templates/**/*.ts",
|
|
134
|
-
"templates/**/*.tsx",
|
|
135
|
-
"components/**/*.ts",
|
|
136
|
-
"components/**/*.tsx",
|
|
137
|
-
"lib/**/*.ts",
|
|
138
|
-
],
|
|
139
|
-
exclude: ["node_modules", "dist", "public", ".cmssy"],
|
|
140
|
-
};
|
|
141
|
-
fs.writeFileSync(path.join(projectPath, "tsconfig.json"), JSON.stringify(tsConfig, null, 2) + "\n");
|
|
142
|
-
// Create .gitignore
|
|
143
|
-
const gitignore = `node_modules/
|
|
144
|
-
dist/
|
|
145
|
-
public/
|
|
146
|
-
.env
|
|
147
|
-
.DS_Store
|
|
148
|
-
*.log
|
|
149
|
-
.cmssy/
|
|
150
|
-
.next/
|
|
151
|
-
`;
|
|
152
|
-
fs.writeFileSync(path.join(projectPath, ".gitignore"), gitignore);
|
|
153
|
-
// Create next.config.mjs (enables Next.js dev mode in cmssy dev)
|
|
154
|
-
const nextConfig = `/** @type {import('next').NextConfig} */
|
|
155
|
-
const nextConfig = {
|
|
156
|
-
// Cmssy blocks are built with esbuild on publish, this config is only for dev
|
|
157
|
-
images: {
|
|
158
|
-
remotePatterns: [{ protocol: 'https', hostname: '**' }],
|
|
159
|
-
},
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
export default nextConfig;
|
|
163
|
-
`;
|
|
164
|
-
fs.writeFileSync(path.join(projectPath, "next.config.mjs"), nextConfig);
|
|
165
|
-
// Create postcss.config.js
|
|
166
|
-
const postcssConfig = `export default {
|
|
167
|
-
plugins: {
|
|
168
|
-
"@tailwindcss/postcss": {},
|
|
169
|
-
},
|
|
170
|
-
};
|
|
171
|
-
`;
|
|
172
|
-
fs.writeFileSync(path.join(projectPath, "postcss.config.js"), postcssConfig);
|
|
173
|
-
// Create styles/main.css
|
|
174
|
-
const mainCss = `@import "tailwindcss";
|
|
175
|
-
@source "../blocks";
|
|
176
|
-
@source "../templates";
|
|
177
|
-
@source "../components";
|
|
178
|
-
|
|
179
|
-
/* Set default border color (Tailwind v4 reset uses currentColor) */
|
|
180
|
-
@layer base {
|
|
181
|
-
*,
|
|
182
|
-
::after,
|
|
183
|
-
::before {
|
|
184
|
-
border-color: var(--border, currentColor);
|
|
185
|
-
}
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Detect existing Next.js project in cwd
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
function detectNextProject(cwd) {
|
|
13
|
+
return ["next.config.js", "next.config.mjs", "next.config.ts"].some((f) => fs.existsSync(path.join(cwd, f)));
|
|
186
14
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
} */
|
|
199
|
-
`;
|
|
200
|
-
fs.writeFileSync(path.join(projectPath, "styles", "main.css"), mainCss);
|
|
201
|
-
// Create .env.example
|
|
202
|
-
const envExample = `# Cmssy API Configuration
|
|
203
|
-
# Run 'cmssy configure' to set these values
|
|
204
|
-
|
|
205
|
-
# Cmssy GraphQL API URL
|
|
206
|
-
CMSSY_API_URL=https://api.cmssy.io/graphql
|
|
207
|
-
|
|
208
|
-
# Cmssy API Token (get from Dashboard ā API Tokens)
|
|
209
|
-
CMSSY_API_TOKEN=
|
|
210
|
-
|
|
211
|
-
# Workspace ID (for workspace publish)
|
|
212
|
-
CMSSY_WORKSPACE_ID=
|
|
213
|
-
`;
|
|
214
|
-
fs.writeFileSync(path.join(projectPath, ".env.example"), envExample);
|
|
215
|
-
// Create .vscode/settings.json (VS Code performance + DX)
|
|
216
|
-
fs.mkdirSync(path.join(projectPath, ".vscode"), { recursive: true });
|
|
217
|
-
const vscodeSettings = {
|
|
218
|
-
"files.watcherExclude": {
|
|
219
|
-
"**/public/**": true,
|
|
220
|
-
"**/.cmssy/**": true,
|
|
221
|
-
"**/node_modules/**": true,
|
|
222
|
-
"**/.git/objects/**": true,
|
|
223
|
-
"**/.git/subtree-cache/**": true,
|
|
224
|
-
"**/.next/**": true,
|
|
225
|
-
"**/dist/**": true,
|
|
226
|
-
},
|
|
227
|
-
"search.exclude": {
|
|
228
|
-
"**/public": true,
|
|
229
|
-
"**/.cmssy": true,
|
|
230
|
-
"**/node_modules": true,
|
|
231
|
-
"**/.next": true,
|
|
232
|
-
"**/dist": true,
|
|
233
|
-
"**/pnpm-lock.yaml": true,
|
|
234
|
-
},
|
|
235
|
-
"files.exclude": {
|
|
236
|
-
"**/.cmssy": true,
|
|
237
|
-
"**/public": true,
|
|
238
|
-
},
|
|
239
|
-
"eslint.enable": false,
|
|
240
|
-
"typescript.tsdk": "node_modules/typescript/lib",
|
|
241
|
-
"typescript.tsserver.maxTsServerMemory": 2048,
|
|
242
|
-
"typescript.tsserver.experimental.enableProjectDiagnostics": false,
|
|
243
|
-
"tailwindCSS.files.exclude": [
|
|
244
|
-
"**/node_modules/**",
|
|
245
|
-
"**/.cmssy/**",
|
|
246
|
-
"**/public/**",
|
|
247
|
-
"**/.next/**",
|
|
248
|
-
"**/dist/**",
|
|
249
|
-
],
|
|
250
|
-
};
|
|
251
|
-
fs.writeFileSync(path.join(projectPath, ".vscode", "settings.json"), JSON.stringify(vscodeSettings, null, 2) + "\n");
|
|
252
|
-
// Create .vscode/extensions.json (recommended extensions)
|
|
253
|
-
const vscodeExtensions = {
|
|
254
|
-
recommendations: ["bradlc.vscode-tailwindcss", "csstools.postcss"],
|
|
255
|
-
unwantedRecommendations: ["dbaeumer.vscode-eslint"],
|
|
256
|
-
};
|
|
257
|
-
fs.writeFileSync(path.join(projectPath, ".vscode", "extensions.json"), JSON.stringify(vscodeExtensions, null, 2) + "\n");
|
|
258
|
-
// Create README.md
|
|
259
|
-
const readme = `# ${answers.projectName}
|
|
260
|
-
|
|
261
|
-
Cmssy project for building reusable UI blocks.
|
|
262
|
-
|
|
263
|
-
## Getting Started
|
|
264
|
-
|
|
265
|
-
\`\`\`bash
|
|
266
|
-
npm install
|
|
267
|
-
npm run dev
|
|
268
|
-
\`\`\`
|
|
269
|
-
|
|
270
|
-
## Commands
|
|
271
|
-
|
|
272
|
-
\`\`\`bash
|
|
273
|
-
cmssy dev # Start dev server
|
|
274
|
-
cmssy create block <name> # Create new block
|
|
275
|
-
cmssy build # Build for production
|
|
276
|
-
cmssy publish --workspace # Publish to workspace
|
|
277
|
-
\`\`\`
|
|
278
|
-
|
|
279
|
-
## Project Structure
|
|
280
|
-
|
|
281
|
-
\`\`\`
|
|
282
|
-
${answers.projectName}/
|
|
283
|
-
āāā blocks/ # Your UI blocks
|
|
284
|
-
āāā styles/
|
|
285
|
-
ā āāā main.css # Global Tailwind styles
|
|
286
|
-
āāā public/ # Build output
|
|
287
|
-
āāā cmssy.config.js
|
|
288
|
-
\`\`\`
|
|
289
|
-
`;
|
|
290
|
-
fs.writeFileSync(path.join(projectPath, "README.md"), readme);
|
|
291
|
-
spinner.succeed("Project structure created");
|
|
292
|
-
// Create example hero block
|
|
293
|
-
spinner.start("Creating example hero block...");
|
|
294
|
-
const heroBlockPath = path.join(projectPath, "blocks", "hero");
|
|
295
|
-
fs.mkdirSync(path.join(heroBlockPath, "src"), { recursive: true });
|
|
296
|
-
// Hero.tsx
|
|
297
|
-
const heroComponent = `import { BlockContent } from "./block";
|
|
15
|
+
function detectCmssyProject(cwd) {
|
|
16
|
+
return fs.existsSync(path.join(cwd, "cmssy.config.js"));
|
|
17
|
+
}
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Scaffold example hero block (shared between both modes)
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
async function scaffoldExampleBlock(projectPath, answers) {
|
|
22
|
+
const heroBlockPath = path.join(projectPath, "blocks", "hero");
|
|
23
|
+
fs.mkdirSync(path.join(heroBlockPath, "src"), { recursive: true });
|
|
24
|
+
// Hero.tsx
|
|
25
|
+
fs.writeFileSync(path.join(heroBlockPath, "src", "Hero.tsx"), `import { BlockContent } from "./block";
|
|
298
26
|
|
|
299
27
|
export default function Hero({ content }: { content: BlockContent }) {
|
|
300
28
|
const {
|
|
@@ -319,28 +47,22 @@ export default function Hero({ content }: { content: BlockContent }) {
|
|
|
319
47
|
</section>
|
|
320
48
|
);
|
|
321
49
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
const indexFile = `export { default } from "./Hero";
|
|
50
|
+
`);
|
|
51
|
+
// index.tsx
|
|
52
|
+
fs.writeFileSync(path.join(heroBlockPath, "src", "index.tsx"), `export { default } from "./Hero";
|
|
326
53
|
import "./index.css";
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
},
|
|
340
|
-
};
|
|
341
|
-
fs.writeFileSync(path.join(heroBlockPath, "package.json"), JSON.stringify(blockPackageJson, null, 2) + "\n");
|
|
342
|
-
// config.ts
|
|
343
|
-
const blockConfig = `import { defineBlock, field } from "@cmssy/cli/config";
|
|
54
|
+
`);
|
|
55
|
+
// index.css
|
|
56
|
+
fs.writeFileSync(path.join(heroBlockPath, "src", "index.css"), `@import "../../../styles/main.css";\n`);
|
|
57
|
+
// package.json
|
|
58
|
+
fs.writeFileSync(path.join(heroBlockPath, "package.json"), JSON.stringify({
|
|
59
|
+
name: `@${answers.projectName}/blocks.hero`,
|
|
60
|
+
version: "1.0.0",
|
|
61
|
+
description: "Hero section block",
|
|
62
|
+
author: { name: answers.authorName, email: answers.authorEmail },
|
|
63
|
+
}, null, 2) + "\n");
|
|
64
|
+
// config.ts
|
|
65
|
+
fs.writeFileSync(path.join(heroBlockPath, "config.ts"), `import { defineBlock, field } from "@cmssy/cli/config";
|
|
344
66
|
|
|
345
67
|
export default defineBlock({
|
|
346
68
|
name: "Hero Section",
|
|
@@ -371,60 +93,328 @@ export default defineBlock({
|
|
|
371
93
|
}),
|
|
372
94
|
},
|
|
373
95
|
});
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
96
|
+
`);
|
|
97
|
+
// preview.json
|
|
98
|
+
fs.writeFileSync(path.join(heroBlockPath, "preview.json"), JSON.stringify({
|
|
99
|
+
heading: "Welcome to Cmssy",
|
|
100
|
+
subheading: "Build reusable UI blocks with React & Tailwind",
|
|
101
|
+
ctaText: "Get Started",
|
|
102
|
+
ctaUrl: "#",
|
|
103
|
+
}, null, 2) + "\n");
|
|
104
|
+
// Generate types
|
|
105
|
+
const heroSchema = {
|
|
106
|
+
heading: {
|
|
107
|
+
type: "singleLine",
|
|
108
|
+
label: "Heading",
|
|
109
|
+
defaultValue: "Welcome to Cmssy",
|
|
110
|
+
},
|
|
111
|
+
subheading: {
|
|
112
|
+
type: "singleLine",
|
|
113
|
+
label: "Subheading",
|
|
114
|
+
defaultValue: "Build reusable UI blocks",
|
|
115
|
+
},
|
|
116
|
+
ctaText: {
|
|
117
|
+
type: "singleLine",
|
|
118
|
+
label: "CTA Text",
|
|
119
|
+
defaultValue: "Get Started",
|
|
120
|
+
},
|
|
121
|
+
ctaUrl: { type: "link", label: "CTA URL", defaultValue: "#" },
|
|
122
|
+
};
|
|
123
|
+
const fieldTypes = await getFieldTypes();
|
|
124
|
+
await generateTypes({
|
|
125
|
+
blockPath: heroBlockPath,
|
|
126
|
+
schema: heroSchema,
|
|
127
|
+
fieldTypes,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
// Write cmssy.config.js
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
function writeCmssyConfig(projectPath, answers) {
|
|
134
|
+
const config = {
|
|
135
|
+
framework: "react",
|
|
136
|
+
projectName: answers.projectName,
|
|
137
|
+
author: { name: answers.authorName, email: answers.authorEmail },
|
|
138
|
+
build: { outDir: "public", minify: true, sourcemap: true },
|
|
139
|
+
};
|
|
140
|
+
fs.writeFileSync(path.join(projectPath, "cmssy.config.js"), `export default ${JSON.stringify(config, null, 2)};\n`);
|
|
141
|
+
}
|
|
142
|
+
// ---------------------------------------------------------------------------
|
|
143
|
+
// Write styles/main.css
|
|
144
|
+
// ---------------------------------------------------------------------------
|
|
145
|
+
function writeMainCss(projectPath) {
|
|
146
|
+
const stylesDir = path.join(projectPath, "styles");
|
|
147
|
+
fs.mkdirSync(stylesDir, { recursive: true });
|
|
148
|
+
fs.writeFileSync(path.join(stylesDir, "main.css"), `@import "tailwindcss";
|
|
149
|
+
@source "../blocks";
|
|
150
|
+
@source "../templates";
|
|
151
|
+
@source "../components";
|
|
152
|
+
|
|
153
|
+
/* Set default border color (Tailwind v4 reset uses currentColor) */
|
|
154
|
+
@layer base {
|
|
155
|
+
*,
|
|
156
|
+
::after,
|
|
157
|
+
::before {
|
|
158
|
+
border-color: var(--border, currentColor);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
`);
|
|
162
|
+
}
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
// Write .env.example
|
|
165
|
+
// ---------------------------------------------------------------------------
|
|
166
|
+
function writeEnvExample(projectPath) {
|
|
167
|
+
fs.writeFileSync(path.join(projectPath, ".env.example"), `# Cmssy API Configuration
|
|
168
|
+
# Run 'cmssy configure' to set these values
|
|
169
|
+
|
|
170
|
+
# Cmssy GraphQL API URL
|
|
171
|
+
CMSSY_API_URL=https://api.cmssy.io/graphql
|
|
172
|
+
|
|
173
|
+
# Cmssy API Token (get from Dashboard ā API Tokens)
|
|
174
|
+
CMSSY_API_TOKEN=
|
|
175
|
+
|
|
176
|
+
# Workspace ID (for workspace publish)
|
|
177
|
+
CMSSY_WORKSPACE_ID=
|
|
178
|
+
`);
|
|
179
|
+
}
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
// Merge cmssy scripts into existing package.json
|
|
182
|
+
// ---------------------------------------------------------------------------
|
|
183
|
+
function mergeCmssyScripts(projectPath) {
|
|
184
|
+
const pkgPath = path.join(projectPath, "package.json");
|
|
185
|
+
if (!fs.existsSync(pkgPath))
|
|
186
|
+
return;
|
|
187
|
+
const pkg = fs.readJsonSync(pkgPath);
|
|
188
|
+
pkg.scripts = pkg.scripts || {};
|
|
189
|
+
if (!pkg.scripts["cmssy:dev"]) {
|
|
190
|
+
pkg.scripts["cmssy:dev"] = "cmssy dev";
|
|
191
|
+
}
|
|
192
|
+
if (!pkg.scripts["cmssy:build"]) {
|
|
193
|
+
pkg.scripts["cmssy:build"] = "cmssy build";
|
|
194
|
+
}
|
|
195
|
+
if (!pkg.scripts["cmssy:publish"]) {
|
|
196
|
+
pkg.scripts["cmssy:publish"] = "cmssy publish --all";
|
|
197
|
+
}
|
|
198
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
199
|
+
}
|
|
200
|
+
// ---------------------------------------------------------------------------
|
|
201
|
+
// New project mode: create-next-app + cmssy layer
|
|
202
|
+
// ---------------------------------------------------------------------------
|
|
203
|
+
async function initNewProject(name, options) {
|
|
204
|
+
console.log(chalk.blue.bold("\nšØ Cmssy - Create New Project\n"));
|
|
205
|
+
let answers;
|
|
206
|
+
if (options.yes) {
|
|
207
|
+
answers = { projectName: name, authorName: "", authorEmail: "" };
|
|
208
|
+
console.log(chalk.gray(`Using defaults: ${name}\n`));
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
answers = await inquirer.prompt([
|
|
212
|
+
{
|
|
213
|
+
type: "input",
|
|
214
|
+
name: "projectName",
|
|
215
|
+
message: "Project name:",
|
|
216
|
+
default: name,
|
|
217
|
+
validate: (input) => {
|
|
218
|
+
if (/^[a-z0-9-_]+$/.test(input))
|
|
219
|
+
return true;
|
|
220
|
+
return "Must contain only lowercase letters, numbers, hyphens, underscores";
|
|
221
|
+
},
|
|
390
222
|
},
|
|
391
|
-
|
|
392
|
-
type: "
|
|
393
|
-
|
|
394
|
-
|
|
223
|
+
{
|
|
224
|
+
type: "input",
|
|
225
|
+
name: "authorName",
|
|
226
|
+
message: "Author name:",
|
|
227
|
+
default: "",
|
|
395
228
|
},
|
|
396
|
-
|
|
397
|
-
type: "
|
|
398
|
-
|
|
399
|
-
|
|
229
|
+
{
|
|
230
|
+
type: "input",
|
|
231
|
+
name: "authorEmail",
|
|
232
|
+
message: "Author email:",
|
|
233
|
+
default: "",
|
|
400
234
|
},
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
235
|
+
]);
|
|
236
|
+
name = answers.projectName;
|
|
237
|
+
}
|
|
238
|
+
const projectPath = path.join(process.cwd(), name);
|
|
239
|
+
if (fs.existsSync(projectPath)) {
|
|
240
|
+
console.error(chalk.red(`\nā Directory "${name}" already exists\n`));
|
|
241
|
+
process.exit(1);
|
|
242
|
+
}
|
|
243
|
+
// Step 1: Run create-next-app
|
|
244
|
+
const spinner = ora("Running create-next-app...").start();
|
|
245
|
+
try {
|
|
246
|
+
execSync(`npx create-next-app@latest ${name} --typescript --tailwind --app --src-dir --no-eslint --import-alias "@/*"`, { cwd: process.cwd(), stdio: "pipe" });
|
|
247
|
+
spinner.succeed("Next.js project created");
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
spinner.fail("Failed to run create-next-app");
|
|
251
|
+
console.error(chalk.red("\nMake sure npx is available and you have internet access.\n"));
|
|
252
|
+
process.exit(1);
|
|
253
|
+
}
|
|
254
|
+
// Step 2: Add cmssy layer
|
|
255
|
+
spinner.start("Adding Cmssy configuration...");
|
|
256
|
+
try {
|
|
257
|
+
// Create directories
|
|
258
|
+
fs.mkdirSync(path.join(projectPath, "blocks"), { recursive: true });
|
|
259
|
+
fs.mkdirSync(path.join(projectPath, "templates"), { recursive: true });
|
|
260
|
+
fs.mkdirSync(path.join(projectPath, ".cmssy"), { recursive: true });
|
|
261
|
+
writeCmssyConfig(projectPath, answers);
|
|
262
|
+
writeMainCss(projectPath);
|
|
263
|
+
writeEnvExample(projectPath);
|
|
264
|
+
mergeCmssyScripts(projectPath);
|
|
265
|
+
// Add .cmssy/ to gitignore
|
|
266
|
+
const gitignorePath = path.join(projectPath, ".gitignore");
|
|
267
|
+
if (fs.existsSync(gitignorePath)) {
|
|
268
|
+
const content = fs.readFileSync(gitignorePath, "utf-8");
|
|
269
|
+
if (!content.includes(".cmssy")) {
|
|
270
|
+
fs.appendFileSync(gitignorePath, "\n# Cmssy\n.cmssy/\npublic/\n");
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
spinner.succeed("Cmssy configuration added");
|
|
274
|
+
// Step 3: Install @cmssy/types
|
|
275
|
+
spinner.start("Installing @cmssy/types...");
|
|
276
|
+
execSync("npm install --save-dev @cmssy/types @cmssy/cli", {
|
|
277
|
+
cwd: projectPath,
|
|
278
|
+
stdio: "pipe",
|
|
408
279
|
});
|
|
280
|
+
spinner.succeed("Dependencies installed");
|
|
281
|
+
// Step 4: Create example block
|
|
282
|
+
spinner.start("Creating example hero block...");
|
|
283
|
+
await scaffoldExampleBlock(projectPath, answers);
|
|
409
284
|
spinner.succeed("Example hero block created");
|
|
410
|
-
// Initialize git
|
|
411
|
-
if (answers.initGit) {
|
|
412
|
-
spinner.start("Initializing git repository...");
|
|
413
|
-
process.chdir(projectPath);
|
|
414
|
-
execSync("git init", { stdio: "ignore" });
|
|
415
|
-
execSync("git branch -m main", { stdio: "ignore" });
|
|
416
|
-
spinner.succeed("Git repository initialized");
|
|
417
|
-
}
|
|
418
285
|
console.log(chalk.green.bold("\nā Project created successfully!\n"));
|
|
419
286
|
console.log(chalk.cyan("Next steps:\n"));
|
|
420
|
-
console.log(chalk.white(` cd ${
|
|
421
|
-
console.log(chalk.white(" npm
|
|
422
|
-
console.log(chalk.
|
|
287
|
+
console.log(chalk.white(` cd ${name}`));
|
|
288
|
+
console.log(chalk.white(" npm run cmssy:dev\n"));
|
|
289
|
+
console.log(chalk.gray("Commands:"));
|
|
290
|
+
console.log(chalk.gray(" cmssy create block <name> Add a new block"));
|
|
291
|
+
console.log(chalk.gray(" cmssy dev Start dev server"));
|
|
292
|
+
console.log(chalk.gray(" cmssy publish --all -w ID Publish to workspace\n"));
|
|
423
293
|
}
|
|
424
294
|
catch (error) {
|
|
425
|
-
spinner.fail("Failed to
|
|
295
|
+
spinner.fail("Failed to set up Cmssy");
|
|
426
296
|
console.error(chalk.red("\nError:"), error);
|
|
427
297
|
process.exit(1);
|
|
428
298
|
}
|
|
429
299
|
}
|
|
300
|
+
// ---------------------------------------------------------------------------
|
|
301
|
+
// Existing project mode: add cmssy to current Next.js project
|
|
302
|
+
// ---------------------------------------------------------------------------
|
|
303
|
+
async function initExistingProject(options) {
|
|
304
|
+
const cwd = process.cwd();
|
|
305
|
+
console.log(chalk.blue.bold("\nšØ Cmssy - Initialize in Existing Project\n"));
|
|
306
|
+
console.log(chalk.gray(`Detected Next.js project in ${path.basename(cwd)}\n`));
|
|
307
|
+
if (detectCmssyProject(cwd)) {
|
|
308
|
+
console.error(chalk.red("ā This project already has cmssy.config.js. Nothing to do.\n"));
|
|
309
|
+
process.exit(1);
|
|
310
|
+
}
|
|
311
|
+
// Read project name from existing package.json
|
|
312
|
+
const pkgPath = path.join(cwd, "package.json");
|
|
313
|
+
const pkg = fs.existsSync(pkgPath) ? fs.readJsonSync(pkgPath) : {};
|
|
314
|
+
const defaultName = pkg.name || path.basename(cwd);
|
|
315
|
+
let answers;
|
|
316
|
+
if (options.yes) {
|
|
317
|
+
answers = { projectName: defaultName, authorName: "", authorEmail: "" };
|
|
318
|
+
console.log(chalk.gray(`Using defaults: ${defaultName}\n`));
|
|
319
|
+
}
|
|
320
|
+
else {
|
|
321
|
+
answers = await inquirer.prompt([
|
|
322
|
+
{
|
|
323
|
+
type: "input",
|
|
324
|
+
name: "projectName",
|
|
325
|
+
message: "Cmssy project name:",
|
|
326
|
+
default: defaultName,
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
type: "input",
|
|
330
|
+
name: "authorName",
|
|
331
|
+
message: "Author name:",
|
|
332
|
+
default: pkg.author?.name || "",
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
type: "input",
|
|
336
|
+
name: "authorEmail",
|
|
337
|
+
message: "Author email:",
|
|
338
|
+
default: pkg.author?.email || "",
|
|
339
|
+
},
|
|
340
|
+
]);
|
|
341
|
+
}
|
|
342
|
+
const spinner = ora("Adding Cmssy configuration...").start();
|
|
343
|
+
try {
|
|
344
|
+
// Create directories
|
|
345
|
+
fs.mkdirSync(path.join(cwd, "blocks"), { recursive: true });
|
|
346
|
+
fs.mkdirSync(path.join(cwd, "templates"), { recursive: true });
|
|
347
|
+
fs.mkdirSync(path.join(cwd, ".cmssy"), { recursive: true });
|
|
348
|
+
writeCmssyConfig(cwd, answers);
|
|
349
|
+
writeMainCss(cwd);
|
|
350
|
+
writeEnvExample(cwd);
|
|
351
|
+
mergeCmssyScripts(cwd);
|
|
352
|
+
// Add .cmssy/ to gitignore
|
|
353
|
+
const gitignorePath = path.join(cwd, ".gitignore");
|
|
354
|
+
if (fs.existsSync(gitignorePath)) {
|
|
355
|
+
const content = fs.readFileSync(gitignorePath, "utf-8");
|
|
356
|
+
if (!content.includes(".cmssy")) {
|
|
357
|
+
fs.appendFileSync(gitignorePath, "\n# Cmssy\n.cmssy/\n");
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
spinner.succeed("Cmssy configuration added");
|
|
361
|
+
// Install dependencies
|
|
362
|
+
spinner.start("Installing @cmssy/types...");
|
|
363
|
+
const packageManager = detectPackageManager(cwd);
|
|
364
|
+
const installCmd = packageManager === "pnpm"
|
|
365
|
+
? "pnpm add -D @cmssy/types @cmssy/cli"
|
|
366
|
+
: packageManager === "yarn"
|
|
367
|
+
? "yarn add -D @cmssy/types @cmssy/cli"
|
|
368
|
+
: "npm install --save-dev @cmssy/types @cmssy/cli";
|
|
369
|
+
execSync(installCmd, { cwd, stdio: "pipe" });
|
|
370
|
+
spinner.succeed("Dependencies installed");
|
|
371
|
+
// Create example block
|
|
372
|
+
spinner.start("Creating example hero block...");
|
|
373
|
+
await scaffoldExampleBlock(cwd, answers);
|
|
374
|
+
spinner.succeed("Example hero block created");
|
|
375
|
+
console.log(chalk.green.bold("\nā Cmssy initialized successfully!\n"));
|
|
376
|
+
console.log(chalk.cyan("Next steps:\n"));
|
|
377
|
+
console.log(chalk.white(" npm run cmssy:dev\n"));
|
|
378
|
+
console.log(chalk.gray("New files:"));
|
|
379
|
+
console.log(chalk.gray(" cmssy.config.js Project configuration"));
|
|
380
|
+
console.log(chalk.gray(" blocks/hero/ Example block"));
|
|
381
|
+
console.log(chalk.gray(" styles/main.css Tailwind source paths"));
|
|
382
|
+
console.log(chalk.gray(" .env.example API credentials template\n"));
|
|
383
|
+
}
|
|
384
|
+
catch (error) {
|
|
385
|
+
spinner.fail("Failed to initialize Cmssy");
|
|
386
|
+
console.error(chalk.red("\nError:"), error);
|
|
387
|
+
process.exit(1);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
// ---------------------------------------------------------------------------
|
|
391
|
+
// Detect package manager from lockfile
|
|
392
|
+
// ---------------------------------------------------------------------------
|
|
393
|
+
function detectPackageManager(cwd) {
|
|
394
|
+
if (fs.existsSync(path.join(cwd, "pnpm-lock.yaml")))
|
|
395
|
+
return "pnpm";
|
|
396
|
+
if (fs.existsSync(path.join(cwd, "yarn.lock")))
|
|
397
|
+
return "yarn";
|
|
398
|
+
return "npm";
|
|
399
|
+
}
|
|
400
|
+
// ---------------------------------------------------------------------------
|
|
401
|
+
// Main entry point
|
|
402
|
+
// ---------------------------------------------------------------------------
|
|
403
|
+
export async function initCommand(name, options = {}) {
|
|
404
|
+
if (name) {
|
|
405
|
+
// Explicit name ā create new project
|
|
406
|
+
await initNewProject(name, options);
|
|
407
|
+
}
|
|
408
|
+
else if (detectNextProject(process.cwd())) {
|
|
409
|
+
// No name, but in Next.js project ā existing mode
|
|
410
|
+
await initExistingProject(options);
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
console.error(chalk.red("\nā No project name provided and no Next.js project detected.\n"));
|
|
414
|
+
console.log(chalk.cyan("Usage:\n"));
|
|
415
|
+
console.log(chalk.white(" cmssy init my-blocks Create a new project"));
|
|
416
|
+
console.log(chalk.white(" cmssy init Initialize in existing Next.js project\n"));
|
|
417
|
+
process.exit(1);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
430
420
|
//# sourceMappingURL=init.js.map
|