@nextsparkjs/cli 0.1.0-beta.100 → 0.1.0-beta.102
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/dist/add-plugin-KIJLCOEQ.js +8 -0
- package/dist/{chunk-5GBCARGX.js → chunk-DXL5CEZD.js} +9 -2
- package/dist/cli.js +962 -490
- package/package.json +1 -1
- package/dist/add-plugin-Q7DOR7XO.js +0 -10
- package/dist/add-plugin-Q7DOR7XO.js.map +0 -1
- package/dist/chunk-5GBCARGX.js.map +0 -1
- package/dist/chunk-DGUM43GV.js +0 -11
- package/dist/chunk-DGUM43GV.js.map +0 -1
- package/dist/chunk-QXD4PBX6.js +0 -435
- package/dist/chunk-QXD4PBX6.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/index.d.ts +0 -46
- package/dist/index.js +0 -24
- package/dist/index.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,65 +1,473 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
devCommand,
|
|
5
|
-
generateCommand,
|
|
6
|
-
getAIWorkflowDir,
|
|
7
|
-
getCoreDir,
|
|
8
|
-
getProjectRoot,
|
|
9
|
-
registryBuildCommand,
|
|
10
|
-
registryWatchCommand
|
|
11
|
-
} from "./chunk-QXD4PBX6.js";
|
|
12
|
-
import {
|
|
3
|
+
__require,
|
|
13
4
|
addPlugin,
|
|
14
5
|
addPluginCommand,
|
|
15
6
|
fetchPackage,
|
|
16
7
|
installTheme,
|
|
17
8
|
runPostinstall,
|
|
18
9
|
validateTheme
|
|
19
|
-
} from "./chunk-
|
|
20
|
-
import {
|
|
21
|
-
__require
|
|
22
|
-
} from "./chunk-DGUM43GV.js";
|
|
10
|
+
} from "./chunk-DXL5CEZD.js";
|
|
23
11
|
|
|
24
12
|
// src/cli.ts
|
|
25
13
|
import { config } from "dotenv";
|
|
26
14
|
import { Command } from "commander";
|
|
27
|
-
import
|
|
28
|
-
import { readFileSync as
|
|
15
|
+
import chalk20 from "chalk";
|
|
16
|
+
import { readFileSync as readFileSync11 } from "fs";
|
|
29
17
|
|
|
30
|
-
// src/commands/
|
|
31
|
-
import {
|
|
32
|
-
import
|
|
33
|
-
import
|
|
18
|
+
// src/commands/dev.ts
|
|
19
|
+
import { spawn } from "child_process";
|
|
20
|
+
import chalk from "chalk";
|
|
21
|
+
import ora from "ora";
|
|
22
|
+
|
|
23
|
+
// src/utils/paths.ts
|
|
24
|
+
import { existsSync } from "fs";
|
|
25
|
+
import { resolve, join, dirname } from "path";
|
|
26
|
+
import { fileURLToPath } from "url";
|
|
27
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
28
|
+
var __dirname = dirname(__filename);
|
|
29
|
+
function getCoreDir() {
|
|
30
|
+
const cwd = process.cwd();
|
|
31
|
+
const npmCorePath = resolve(cwd, "node_modules", "@nextsparkjs", "core");
|
|
32
|
+
if (existsSync(npmCorePath)) {
|
|
33
|
+
return npmCorePath;
|
|
34
|
+
}
|
|
35
|
+
const monorepoCorePath = resolve(__dirname, "..", "..", "..", "..", "core");
|
|
36
|
+
if (existsSync(monorepoCorePath)) {
|
|
37
|
+
return monorepoCorePath;
|
|
38
|
+
}
|
|
39
|
+
const cwdMonorepoCorePath = resolve(cwd, "..", "..", "packages", "core");
|
|
40
|
+
if (existsSync(cwdMonorepoCorePath)) {
|
|
41
|
+
return cwdMonorepoCorePath;
|
|
42
|
+
}
|
|
43
|
+
throw new Error(
|
|
44
|
+
"Could not find @nextsparkjs/core. Make sure it is installed as a dependency or you are running from within the monorepo."
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
function getProjectRoot() {
|
|
48
|
+
return process.cwd();
|
|
49
|
+
}
|
|
50
|
+
function isMonorepoMode() {
|
|
51
|
+
const cwd = process.cwd();
|
|
52
|
+
const npmCorePath = resolve(cwd, "node_modules", "@nextsparkjs", "core");
|
|
53
|
+
return !existsSync(npmCorePath);
|
|
54
|
+
}
|
|
55
|
+
function getAIWorkflowDir() {
|
|
56
|
+
const cwd = process.cwd();
|
|
57
|
+
const nmPath = join(cwd, "node_modules", "@nextsparkjs", "ai-workflow");
|
|
58
|
+
if (existsSync(nmPath)) return nmPath;
|
|
59
|
+
const webNmPath = join(cwd, "web", "node_modules", "@nextsparkjs", "ai-workflow");
|
|
60
|
+
if (existsSync(webNmPath)) return webNmPath;
|
|
61
|
+
const monoPath = join(cwd, "packages", "ai-workflow");
|
|
62
|
+
if (existsSync(monoPath)) return monoPath;
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/commands/dev.ts
|
|
67
|
+
async function devCommand(options) {
|
|
68
|
+
const spinner = ora("Starting development environment...").start();
|
|
69
|
+
try {
|
|
70
|
+
const coreDir = getCoreDir();
|
|
71
|
+
const projectRoot = getProjectRoot();
|
|
72
|
+
const mode = isMonorepoMode() ? "monorepo" : "npm";
|
|
73
|
+
spinner.succeed(`Core found at: ${coreDir} (${mode} mode)`);
|
|
74
|
+
const processes = [];
|
|
75
|
+
if (options.registry) {
|
|
76
|
+
console.log(chalk.blue("\n[Registry] Starting registry builder with watch mode..."));
|
|
77
|
+
const registryProcess = spawn("node", ["scripts/build/registry.mjs", "--watch"], {
|
|
78
|
+
cwd: coreDir,
|
|
79
|
+
stdio: "inherit",
|
|
80
|
+
env: {
|
|
81
|
+
...process.env,
|
|
82
|
+
NEXTSPARK_PROJECT_ROOT: projectRoot
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
processes.push(registryProcess);
|
|
86
|
+
registryProcess.on("error", (err) => {
|
|
87
|
+
console.error(chalk.red(`[Registry] Error: ${err.message}`));
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
console.log(chalk.green(`
|
|
91
|
+
[Dev] Starting Next.js dev server on port ${options.port}...`));
|
|
92
|
+
const devProcess = spawn("npx", ["next", "dev", "-p", options.port], {
|
|
93
|
+
cwd: projectRoot,
|
|
94
|
+
stdio: "inherit",
|
|
95
|
+
shell: true,
|
|
96
|
+
env: {
|
|
97
|
+
...process.env,
|
|
98
|
+
NEXTSPARK_CORE_DIR: coreDir
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
processes.push(devProcess);
|
|
102
|
+
devProcess.on("error", (err) => {
|
|
103
|
+
console.error(chalk.red(`[Dev] Error: ${err.message}`));
|
|
104
|
+
process.exit(1);
|
|
105
|
+
});
|
|
106
|
+
const cleanup = () => {
|
|
107
|
+
console.log(chalk.yellow("\nShutting down..."));
|
|
108
|
+
processes.forEach((p) => {
|
|
109
|
+
if (!p.killed) {
|
|
110
|
+
p.kill("SIGTERM");
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
process.exit(0);
|
|
114
|
+
};
|
|
115
|
+
process.on("SIGINT", cleanup);
|
|
116
|
+
process.on("SIGTERM", cleanup);
|
|
117
|
+
devProcess.on("exit", (code) => {
|
|
118
|
+
cleanup();
|
|
119
|
+
process.exit(code ?? 0);
|
|
120
|
+
});
|
|
121
|
+
} catch (error) {
|
|
122
|
+
spinner.fail("Failed to start development environment");
|
|
123
|
+
if (error instanceof Error) {
|
|
124
|
+
console.error(chalk.red(error.message));
|
|
125
|
+
}
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/commands/build.ts
|
|
131
|
+
import { spawn as spawn2 } from "child_process";
|
|
132
|
+
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
133
|
+
import { join as join2 } from "path";
|
|
134
|
+
import chalk2 from "chalk";
|
|
135
|
+
import ora2 from "ora";
|
|
136
|
+
function loadProjectEnv(projectRoot) {
|
|
137
|
+
const envPath = join2(projectRoot, ".env");
|
|
138
|
+
const envVars = {};
|
|
139
|
+
if (existsSync2(envPath)) {
|
|
140
|
+
const content = readFileSync(envPath, "utf-8");
|
|
141
|
+
for (const line of content.split("\n")) {
|
|
142
|
+
const trimmed = line.trim();
|
|
143
|
+
if (trimmed && !trimmed.startsWith("#")) {
|
|
144
|
+
const [key, ...valueParts] = trimmed.split("=");
|
|
145
|
+
if (key && valueParts.length > 0) {
|
|
146
|
+
let value = valueParts.join("=");
|
|
147
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
148
|
+
value = value.slice(1, -1);
|
|
149
|
+
}
|
|
150
|
+
envVars[key] = value;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return envVars;
|
|
156
|
+
}
|
|
157
|
+
async function buildCommand(options) {
|
|
158
|
+
const spinner = ora2("Preparing production build...").start();
|
|
159
|
+
try {
|
|
160
|
+
const coreDir = getCoreDir();
|
|
161
|
+
const projectRoot = getProjectRoot();
|
|
162
|
+
spinner.succeed("Core package found");
|
|
163
|
+
const projectEnv = loadProjectEnv(projectRoot);
|
|
164
|
+
if (options.registry) {
|
|
165
|
+
spinner.start("Generating registries...");
|
|
166
|
+
await new Promise((resolve4, reject) => {
|
|
167
|
+
const registryProcess = spawn2("node", ["scripts/build/registry.mjs"], {
|
|
168
|
+
cwd: coreDir,
|
|
169
|
+
stdio: "pipe",
|
|
170
|
+
env: {
|
|
171
|
+
...projectEnv,
|
|
172
|
+
...process.env,
|
|
173
|
+
NEXTSPARK_PROJECT_ROOT: projectRoot
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
let stderr = "";
|
|
177
|
+
registryProcess.stderr?.on("data", (data) => {
|
|
178
|
+
stderr += data.toString();
|
|
179
|
+
});
|
|
180
|
+
registryProcess.on("close", (code) => {
|
|
181
|
+
if (code === 0) {
|
|
182
|
+
resolve4();
|
|
183
|
+
} else {
|
|
184
|
+
reject(new Error(`Registry generation failed: ${stderr}`));
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
registryProcess.on("error", reject);
|
|
188
|
+
});
|
|
189
|
+
spinner.succeed("Registries generated");
|
|
190
|
+
}
|
|
191
|
+
spinner.start("Building for production...");
|
|
192
|
+
const buildProcess = spawn2("npx", ["next", "build"], {
|
|
193
|
+
cwd: projectRoot,
|
|
194
|
+
stdio: "inherit",
|
|
195
|
+
shell: true,
|
|
196
|
+
env: {
|
|
197
|
+
...projectEnv,
|
|
198
|
+
...process.env,
|
|
199
|
+
NEXTSPARK_CORE_DIR: coreDir,
|
|
200
|
+
NODE_ENV: "production"
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
buildProcess.on("error", (err) => {
|
|
204
|
+
spinner.fail("Build failed");
|
|
205
|
+
console.error(chalk2.red(err.message));
|
|
206
|
+
process.exit(1);
|
|
207
|
+
});
|
|
208
|
+
buildProcess.on("close", (code) => {
|
|
209
|
+
if (code === 0) {
|
|
210
|
+
console.log(chalk2.green("\nBuild completed successfully!"));
|
|
211
|
+
process.exit(0);
|
|
212
|
+
} else {
|
|
213
|
+
console.error(chalk2.red(`
|
|
214
|
+
Build failed with exit code ${code}`));
|
|
215
|
+
process.exit(code ?? 1);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
} catch (error) {
|
|
219
|
+
spinner.fail("Build preparation failed");
|
|
220
|
+
if (error instanceof Error) {
|
|
221
|
+
console.error(chalk2.red(error.message));
|
|
222
|
+
}
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// src/commands/generate.ts
|
|
228
|
+
import { spawn as spawn3 } from "child_process";
|
|
229
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
230
|
+
import { join as join3 } from "path";
|
|
231
|
+
import chalk3 from "chalk";
|
|
232
|
+
import ora3 from "ora";
|
|
233
|
+
function loadProjectEnv2(projectRoot) {
|
|
234
|
+
const envPath = join3(projectRoot, ".env");
|
|
235
|
+
const envVars = {};
|
|
236
|
+
if (existsSync3(envPath)) {
|
|
237
|
+
const content = readFileSync2(envPath, "utf-8");
|
|
238
|
+
for (const line of content.split("\n")) {
|
|
239
|
+
const trimmed = line.trim();
|
|
240
|
+
if (trimmed && !trimmed.startsWith("#")) {
|
|
241
|
+
const [key, ...valueParts] = trimmed.split("=");
|
|
242
|
+
if (key && valueParts.length > 0) {
|
|
243
|
+
let value = valueParts.join("=");
|
|
244
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
245
|
+
value = value.slice(1, -1);
|
|
246
|
+
}
|
|
247
|
+
envVars[key] = value;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return envVars;
|
|
253
|
+
}
|
|
254
|
+
async function generateCommand(options) {
|
|
255
|
+
const spinner = ora3("Preparing registry generation...").start();
|
|
256
|
+
try {
|
|
257
|
+
const coreDir = getCoreDir();
|
|
258
|
+
const projectRoot = getProjectRoot();
|
|
259
|
+
const mode = isMonorepoMode() ? "monorepo" : "npm";
|
|
260
|
+
spinner.succeed(`Core found at: ${coreDir} (${mode} mode)`);
|
|
261
|
+
const projectEnv = loadProjectEnv2(projectRoot);
|
|
262
|
+
const watchArg = options.watch ? ["--watch"] : [];
|
|
263
|
+
const action = options.watch ? "Watching" : "Generating";
|
|
264
|
+
console.log(chalk3.blue(`
|
|
265
|
+
${action} registries...`));
|
|
266
|
+
const generateProcess = spawn3("node", ["scripts/build/registry.mjs", ...watchArg], {
|
|
267
|
+
cwd: coreDir,
|
|
268
|
+
stdio: "inherit",
|
|
269
|
+
env: {
|
|
270
|
+
...projectEnv,
|
|
271
|
+
...process.env,
|
|
272
|
+
NEXTSPARK_PROJECT_ROOT: projectRoot
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
generateProcess.on("error", (err) => {
|
|
276
|
+
console.error(chalk3.red(`Error: ${err.message}`));
|
|
277
|
+
process.exit(1);
|
|
278
|
+
});
|
|
279
|
+
generateProcess.on("close", (code) => {
|
|
280
|
+
if (code === 0) {
|
|
281
|
+
if (!options.watch) {
|
|
282
|
+
console.log(chalk3.green("\nRegistry generation completed!"));
|
|
283
|
+
}
|
|
284
|
+
process.exit(0);
|
|
285
|
+
} else {
|
|
286
|
+
console.error(chalk3.red(`
|
|
287
|
+
Registry generation failed with exit code ${code}`));
|
|
288
|
+
process.exit(code ?? 1);
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
if (options.watch) {
|
|
292
|
+
const cleanup = () => {
|
|
293
|
+
console.log(chalk3.yellow("\nStopping watcher..."));
|
|
294
|
+
if (!generateProcess.killed) {
|
|
295
|
+
generateProcess.kill("SIGTERM");
|
|
296
|
+
}
|
|
297
|
+
process.exit(0);
|
|
298
|
+
};
|
|
299
|
+
process.on("SIGINT", cleanup);
|
|
300
|
+
process.on("SIGTERM", cleanup);
|
|
301
|
+
}
|
|
302
|
+
} catch (error) {
|
|
303
|
+
spinner.fail("Registry generation failed");
|
|
304
|
+
if (error instanceof Error) {
|
|
305
|
+
console.error(chalk3.red(error.message));
|
|
306
|
+
}
|
|
307
|
+
process.exit(1);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// src/commands/registry.ts
|
|
312
|
+
import { spawn as spawn4 } from "child_process";
|
|
313
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
|
|
314
|
+
import { join as join4 } from "path";
|
|
315
|
+
import chalk4 from "chalk";
|
|
34
316
|
import ora4 from "ora";
|
|
317
|
+
function loadProjectEnv3(projectRoot) {
|
|
318
|
+
const envPath = join4(projectRoot, ".env");
|
|
319
|
+
const envVars = {};
|
|
320
|
+
if (existsSync4(envPath)) {
|
|
321
|
+
const content = readFileSync3(envPath, "utf-8");
|
|
322
|
+
for (const line of content.split("\n")) {
|
|
323
|
+
const trimmed = line.trim();
|
|
324
|
+
if (trimmed && !trimmed.startsWith("#")) {
|
|
325
|
+
const [key, ...valueParts] = trimmed.split("=");
|
|
326
|
+
if (key && valueParts.length > 0) {
|
|
327
|
+
let value = valueParts.join("=");
|
|
328
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
329
|
+
value = value.slice(1, -1);
|
|
330
|
+
}
|
|
331
|
+
envVars[key] = value;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return envVars;
|
|
337
|
+
}
|
|
338
|
+
async function registryBuildCommand() {
|
|
339
|
+
const spinner = ora4("Building registries...").start();
|
|
340
|
+
try {
|
|
341
|
+
const coreDir = getCoreDir();
|
|
342
|
+
const projectRoot = getProjectRoot();
|
|
343
|
+
const mode = isMonorepoMode() ? "monorepo" : "npm";
|
|
344
|
+
const projectEnv = loadProjectEnv3(projectRoot);
|
|
345
|
+
spinner.text = `Building registries (${mode} mode)...`;
|
|
346
|
+
const buildProcess = spawn4("node", ["scripts/build/registry.mjs"], {
|
|
347
|
+
cwd: coreDir,
|
|
348
|
+
stdio: "pipe",
|
|
349
|
+
env: {
|
|
350
|
+
...projectEnv,
|
|
351
|
+
...process.env,
|
|
352
|
+
NEXTSPARK_PROJECT_ROOT: projectRoot
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
let stdout = "";
|
|
356
|
+
let stderr = "";
|
|
357
|
+
buildProcess.stdout?.on("data", (data) => {
|
|
358
|
+
stdout += data.toString();
|
|
359
|
+
});
|
|
360
|
+
buildProcess.stderr?.on("data", (data) => {
|
|
361
|
+
stderr += data.toString();
|
|
362
|
+
});
|
|
363
|
+
buildProcess.on("close", (code) => {
|
|
364
|
+
if (code === 0) {
|
|
365
|
+
spinner.succeed("Registries built successfully");
|
|
366
|
+
if (stdout.trim()) {
|
|
367
|
+
console.log(chalk4.gray(stdout.trim()));
|
|
368
|
+
}
|
|
369
|
+
process.exit(0);
|
|
370
|
+
} else {
|
|
371
|
+
spinner.fail("Registry build failed");
|
|
372
|
+
if (stderr.trim()) {
|
|
373
|
+
console.error(chalk4.red(stderr.trim()));
|
|
374
|
+
}
|
|
375
|
+
process.exit(code ?? 1);
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
buildProcess.on("error", (err) => {
|
|
379
|
+
spinner.fail("Registry build failed");
|
|
380
|
+
console.error(chalk4.red(err.message));
|
|
381
|
+
process.exit(1);
|
|
382
|
+
});
|
|
383
|
+
} catch (error) {
|
|
384
|
+
spinner.fail("Registry build failed");
|
|
385
|
+
if (error instanceof Error) {
|
|
386
|
+
console.error(chalk4.red(error.message));
|
|
387
|
+
}
|
|
388
|
+
process.exit(1);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
async function registryWatchCommand() {
|
|
392
|
+
const spinner = ora4("Starting registry watcher...").start();
|
|
393
|
+
try {
|
|
394
|
+
const coreDir = getCoreDir();
|
|
395
|
+
const projectRoot = getProjectRoot();
|
|
396
|
+
const mode = isMonorepoMode() ? "monorepo" : "npm";
|
|
397
|
+
spinner.succeed(`Registry watcher started (${mode} mode)`);
|
|
398
|
+
console.log(chalk4.blue("\nWatching for changes... Press Ctrl+C to stop.\n"));
|
|
399
|
+
const projectEnv = loadProjectEnv3(projectRoot);
|
|
400
|
+
const watchProcess = spawn4("node", ["scripts/build/registry.mjs", "--watch"], {
|
|
401
|
+
cwd: coreDir,
|
|
402
|
+
stdio: "inherit",
|
|
403
|
+
env: {
|
|
404
|
+
...projectEnv,
|
|
405
|
+
...process.env,
|
|
406
|
+
NEXTSPARK_PROJECT_ROOT: projectRoot
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
watchProcess.on("error", (err) => {
|
|
410
|
+
console.error(chalk4.red(`Watcher error: ${err.message}`));
|
|
411
|
+
process.exit(1);
|
|
412
|
+
});
|
|
413
|
+
const cleanup = () => {
|
|
414
|
+
console.log(chalk4.yellow("\nStopping registry watcher..."));
|
|
415
|
+
if (!watchProcess.killed) {
|
|
416
|
+
watchProcess.kill("SIGTERM");
|
|
417
|
+
}
|
|
418
|
+
process.exit(0);
|
|
419
|
+
};
|
|
420
|
+
process.on("SIGINT", cleanup);
|
|
421
|
+
process.on("SIGTERM", cleanup);
|
|
422
|
+
watchProcess.on("close", (code) => {
|
|
423
|
+
if (code !== 0) {
|
|
424
|
+
console.error(chalk4.red(`
|
|
425
|
+
Watcher exited with code ${code}`));
|
|
426
|
+
}
|
|
427
|
+
process.exit(code ?? 0);
|
|
428
|
+
});
|
|
429
|
+
} catch (error) {
|
|
430
|
+
spinner.fail("Failed to start registry watcher");
|
|
431
|
+
if (error instanceof Error) {
|
|
432
|
+
console.error(chalk4.red(error.message));
|
|
433
|
+
}
|
|
434
|
+
process.exit(1);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// src/commands/init.ts
|
|
439
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync7 } from "fs";
|
|
440
|
+
import { join as join9 } from "path";
|
|
441
|
+
import chalk12 from "chalk";
|
|
442
|
+
import ora8 from "ora";
|
|
35
443
|
|
|
36
444
|
// src/wizard/index.ts
|
|
37
|
-
import
|
|
38
|
-
import
|
|
39
|
-
import { confirm as confirm5, select as
|
|
445
|
+
import chalk11 from "chalk";
|
|
446
|
+
import ora7 from "ora";
|
|
447
|
+
import { confirm as confirm5, select as select7 } from "@inquirer/prompts";
|
|
40
448
|
import { execSync } from "child_process";
|
|
41
|
-
import { existsSync as
|
|
42
|
-
import { join as
|
|
449
|
+
import { existsSync as existsSync7, readdirSync } from "fs";
|
|
450
|
+
import { join as join8 } from "path";
|
|
43
451
|
|
|
44
452
|
// src/wizard/banner.ts
|
|
45
|
-
import
|
|
46
|
-
import { readFileSync } from "fs";
|
|
47
|
-
import { fileURLToPath } from "url";
|
|
48
|
-
import { dirname, join } from "path";
|
|
49
|
-
var
|
|
50
|
-
var
|
|
453
|
+
import chalk5 from "chalk";
|
|
454
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
455
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
456
|
+
import { dirname as dirname2, join as join5 } from "path";
|
|
457
|
+
var __filename2 = fileURLToPath2(import.meta.url);
|
|
458
|
+
var __dirname2 = dirname2(__filename2);
|
|
51
459
|
function getCliVersion() {
|
|
52
460
|
const possiblePaths = [
|
|
53
|
-
|
|
461
|
+
join5(__dirname2, "../package.json"),
|
|
54
462
|
// from dist/
|
|
55
|
-
|
|
463
|
+
join5(__dirname2, "../../package.json"),
|
|
56
464
|
// from dist/wizard/ or src/wizard/
|
|
57
|
-
|
|
465
|
+
join5(__dirname2, "../../../package.json")
|
|
58
466
|
// fallback
|
|
59
467
|
];
|
|
60
468
|
for (const packageJsonPath of possiblePaths) {
|
|
61
469
|
try {
|
|
62
|
-
const packageJson = JSON.parse(
|
|
470
|
+
const packageJson = JSON.parse(readFileSync4(packageJsonPath, "utf-8"));
|
|
63
471
|
if (packageJson.name === "@nextsparkjs/cli" && packageJson.version) {
|
|
64
472
|
return packageJson.version;
|
|
65
473
|
}
|
|
@@ -78,29 +486,29 @@ var BANNER = `
|
|
|
78
486
|
`;
|
|
79
487
|
function showBanner() {
|
|
80
488
|
const version = getCliVersion();
|
|
81
|
-
console.log(
|
|
82
|
-
console.log(
|
|
83
|
-
console.log(
|
|
489
|
+
console.log(chalk5.cyan(BANNER));
|
|
490
|
+
console.log(chalk5.bold.white(" Welcome to NextSpark - The Complete SaaS Framework for Next.js"));
|
|
491
|
+
console.log(chalk5.gray(` Version ${version} - Create production-ready SaaS applications in minutes
|
|
84
492
|
`));
|
|
85
|
-
console.log(
|
|
493
|
+
console.log(chalk5.gray(" " + "=".repeat(60) + "\n"));
|
|
86
494
|
}
|
|
87
495
|
function showSection(title, step, totalSteps) {
|
|
88
496
|
console.log("");
|
|
89
|
-
console.log(
|
|
90
|
-
console.log(
|
|
497
|
+
console.log(chalk5.cyan(` Step ${step}/${totalSteps}: ${title}`));
|
|
498
|
+
console.log(chalk5.gray(" " + "-".repeat(40)));
|
|
91
499
|
console.log("");
|
|
92
500
|
}
|
|
93
501
|
function showSuccess(message) {
|
|
94
|
-
console.log(
|
|
502
|
+
console.log(chalk5.green(` \u2713 ${message}`));
|
|
95
503
|
}
|
|
96
504
|
function showWarning(message) {
|
|
97
|
-
console.log(
|
|
505
|
+
console.log(chalk5.yellow(` \u26A0 ${message}`));
|
|
98
506
|
}
|
|
99
507
|
function showError(message) {
|
|
100
|
-
console.log(
|
|
508
|
+
console.log(chalk5.red(` \u2717 ${message}`));
|
|
101
509
|
}
|
|
102
510
|
function showInfo(message) {
|
|
103
|
-
console.log(
|
|
511
|
+
console.log(chalk5.blue(` \u2139 ${message}`));
|
|
104
512
|
}
|
|
105
513
|
|
|
106
514
|
// src/wizard/prompts/project-info.ts
|
|
@@ -456,7 +864,24 @@ async function promptContentFeaturesConfig(mode = "interactive", totalSteps = 9)
|
|
|
456
864
|
}
|
|
457
865
|
|
|
458
866
|
// src/wizard/prompts/auth-config.ts
|
|
459
|
-
import { checkbox as checkbox5 } from "@inquirer/prompts";
|
|
867
|
+
import { checkbox as checkbox5, input as input2, select as select5 } from "@inquirer/prompts";
|
|
868
|
+
var REGISTRATION_MODE_OPTIONS = [
|
|
869
|
+
{
|
|
870
|
+
name: "Open (anyone can register)",
|
|
871
|
+
value: "open",
|
|
872
|
+
description: "Email+password and Google OAuth signup available to everyone"
|
|
873
|
+
},
|
|
874
|
+
{
|
|
875
|
+
name: "Domain-Restricted (Google OAuth only for specific domains)",
|
|
876
|
+
value: "domain-restricted",
|
|
877
|
+
description: "Only Google OAuth for allowed email domains (e.g., @yourcompany.com)"
|
|
878
|
+
},
|
|
879
|
+
{
|
|
880
|
+
name: "Invitation-Only (registration via invite link)",
|
|
881
|
+
value: "invitation-only",
|
|
882
|
+
description: "Users can only register when invited by an existing user"
|
|
883
|
+
}
|
|
884
|
+
];
|
|
460
885
|
var AUTH_METHOD_OPTIONS = [
|
|
461
886
|
{
|
|
462
887
|
name: "Email & Password",
|
|
@@ -481,6 +906,7 @@ var SECURITY_OPTIONS = [
|
|
|
481
906
|
];
|
|
482
907
|
function getDefaultAuthConfig() {
|
|
483
908
|
return {
|
|
909
|
+
registrationMode: "open",
|
|
484
910
|
emailPassword: true,
|
|
485
911
|
googleOAuth: false,
|
|
486
912
|
emailVerification: true
|
|
@@ -490,10 +916,40 @@ async function promptAuthConfig(mode = "interactive", totalSteps = 8) {
|
|
|
490
916
|
showSection("Authentication", 8, totalSteps);
|
|
491
917
|
showInfo("Configure how users will authenticate to your application.");
|
|
492
918
|
console.log("");
|
|
493
|
-
const
|
|
494
|
-
message: "
|
|
495
|
-
choices:
|
|
919
|
+
const registrationMode = await select5({
|
|
920
|
+
message: "How should new users register?",
|
|
921
|
+
choices: REGISTRATION_MODE_OPTIONS,
|
|
922
|
+
default: "open"
|
|
496
923
|
});
|
|
924
|
+
console.log("");
|
|
925
|
+
let emailPassword = true;
|
|
926
|
+
let googleOAuth = false;
|
|
927
|
+
let allowedDomains;
|
|
928
|
+
if (registrationMode === "domain-restricted") {
|
|
929
|
+
googleOAuth = true;
|
|
930
|
+
emailPassword = false;
|
|
931
|
+
showInfo("Domain-restricted mode: Google OAuth enabled, email login hidden on login page.");
|
|
932
|
+
console.log("");
|
|
933
|
+
const domainsInput = await input2({
|
|
934
|
+
message: "Allowed email domains (comma-separated, e.g. yourcompany.com, partner.org):",
|
|
935
|
+
validate: (value) => {
|
|
936
|
+
if (!value.trim()) return "At least one domain is required for domain-restricted mode";
|
|
937
|
+
const domains = value.split(",").map((d) => d.trim()).filter(Boolean);
|
|
938
|
+
const invalid = domains.find((d) => !d.includes("."));
|
|
939
|
+
if (invalid) return `Invalid domain: "${invalid}" (must contain a dot)`;
|
|
940
|
+
return true;
|
|
941
|
+
}
|
|
942
|
+
});
|
|
943
|
+
allowedDomains = domainsInput.split(",").map((d) => d.trim().toLowerCase()).filter(Boolean);
|
|
944
|
+
console.log("");
|
|
945
|
+
} else {
|
|
946
|
+
const selectedMethods = await checkbox5({
|
|
947
|
+
message: "Which authentication methods do you want to enable?",
|
|
948
|
+
choices: AUTH_METHOD_OPTIONS
|
|
949
|
+
});
|
|
950
|
+
emailPassword = selectedMethods.includes("emailPassword");
|
|
951
|
+
googleOAuth = selectedMethods.includes("googleOAuth");
|
|
952
|
+
}
|
|
497
953
|
let selectedSecurity = ["emailVerification"];
|
|
498
954
|
if (mode === "expert") {
|
|
499
955
|
console.log("");
|
|
@@ -505,9 +961,11 @@ async function promptAuthConfig(mode = "interactive", totalSteps = 8) {
|
|
|
505
961
|
});
|
|
506
962
|
}
|
|
507
963
|
const auth = {
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
964
|
+
registrationMode,
|
|
965
|
+
emailPassword,
|
|
966
|
+
googleOAuth,
|
|
967
|
+
emailVerification: selectedSecurity.includes("emailVerification"),
|
|
968
|
+
allowedDomains
|
|
511
969
|
};
|
|
512
970
|
return { auth };
|
|
513
971
|
}
|
|
@@ -650,17 +1108,17 @@ async function promptDevConfig(mode = "interactive", totalSteps = 8) {
|
|
|
650
1108
|
}
|
|
651
1109
|
|
|
652
1110
|
// src/wizard/prompts/theme-selection.ts
|
|
653
|
-
import { select as
|
|
654
|
-
import
|
|
1111
|
+
import { select as select6 } from "@inquirer/prompts";
|
|
1112
|
+
import chalk6 from "chalk";
|
|
655
1113
|
async function promptThemeSelection() {
|
|
656
1114
|
console.log("");
|
|
657
|
-
console.log(
|
|
658
|
-
console.log(
|
|
1115
|
+
console.log(chalk6.cyan(" Reference Theme Installation"));
|
|
1116
|
+
console.log(chalk6.gray(" " + "-".repeat(40)));
|
|
659
1117
|
console.log("");
|
|
660
|
-
console.log(
|
|
661
|
-
console.log(
|
|
1118
|
+
console.log(chalk6.gray(" A reference theme provides a complete example to learn from."));
|
|
1119
|
+
console.log(chalk6.gray(" Your custom theme (based on starter) will be your active theme."));
|
|
662
1120
|
console.log("");
|
|
663
|
-
const theme = await
|
|
1121
|
+
const theme = await select6({
|
|
664
1122
|
message: "Which reference theme would you like to install?",
|
|
665
1123
|
choices: [
|
|
666
1124
|
{
|
|
@@ -696,7 +1154,7 @@ async function promptThemeSelection() {
|
|
|
696
1154
|
|
|
697
1155
|
// src/wizard/prompts/plugins-selection.ts
|
|
698
1156
|
import { checkbox as checkbox8 } from "@inquirer/prompts";
|
|
699
|
-
import
|
|
1157
|
+
import chalk7 from "chalk";
|
|
700
1158
|
var THEME_REQUIRED_PLUGINS = {
|
|
701
1159
|
"default": ["langchain"],
|
|
702
1160
|
"blog": [],
|
|
@@ -706,11 +1164,11 @@ var THEME_REQUIRED_PLUGINS = {
|
|
|
706
1164
|
async function promptPluginsSelection(selectedTheme) {
|
|
707
1165
|
const requiredPlugins = selectedTheme ? THEME_REQUIRED_PLUGINS[selectedTheme] || [] : [];
|
|
708
1166
|
console.log("");
|
|
709
|
-
console.log(
|
|
710
|
-
console.log(
|
|
1167
|
+
console.log(chalk7.cyan(" Plugin Selection"));
|
|
1168
|
+
console.log(chalk7.gray(" " + "-".repeat(40)));
|
|
711
1169
|
if (requiredPlugins.length > 0) {
|
|
712
1170
|
console.log("");
|
|
713
|
-
console.log(
|
|
1171
|
+
console.log(chalk7.gray(` Note: ${requiredPlugins.join(", ")} will be installed (required by theme)`));
|
|
714
1172
|
}
|
|
715
1173
|
console.log("");
|
|
716
1174
|
const plugins = await checkbox8({
|
|
@@ -746,10 +1204,10 @@ function getRequiredPlugins(theme) {
|
|
|
746
1204
|
}
|
|
747
1205
|
|
|
748
1206
|
// src/wizard/prompts/env-config.ts
|
|
749
|
-
import { confirm as confirm3, input as
|
|
1207
|
+
import { confirm as confirm3, input as input3 } from "@inquirer/prompts";
|
|
750
1208
|
|
|
751
1209
|
// src/wizard/prompts/git-config.ts
|
|
752
|
-
import { confirm as confirm4, input as
|
|
1210
|
+
import { confirm as confirm4, input as input4 } from "@inquirer/prompts";
|
|
753
1211
|
|
|
754
1212
|
// src/wizard/prompts/index.ts
|
|
755
1213
|
async function runAllPrompts() {
|
|
@@ -828,24 +1286,24 @@ async function runExpertPrompts() {
|
|
|
828
1286
|
// src/wizard/generators/index.ts
|
|
829
1287
|
import fs8 from "fs-extra";
|
|
830
1288
|
import path7 from "path";
|
|
831
|
-
import { fileURLToPath as
|
|
1289
|
+
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
832
1290
|
|
|
833
1291
|
// src/wizard/generators/theme-renamer.ts
|
|
834
1292
|
import fs from "fs-extra";
|
|
835
1293
|
import path from "path";
|
|
836
|
-
import { fileURLToPath as
|
|
837
|
-
var
|
|
838
|
-
var
|
|
1294
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1295
|
+
var __filename3 = fileURLToPath3(import.meta.url);
|
|
1296
|
+
var __dirname3 = path.dirname(__filename3);
|
|
839
1297
|
function getTemplatesDir() {
|
|
840
1298
|
const rootDir = process.cwd();
|
|
841
1299
|
const possiblePaths = [
|
|
842
1300
|
// From project root node_modules (most common for installed packages)
|
|
843
1301
|
path.resolve(rootDir, "node_modules/@nextsparkjs/core/templates"),
|
|
844
1302
|
// From CLI dist folder for development
|
|
845
|
-
path.resolve(
|
|
1303
|
+
path.resolve(__dirname3, "../../core/templates"),
|
|
846
1304
|
// Legacy paths for different build structures
|
|
847
|
-
path.resolve(
|
|
848
|
-
path.resolve(
|
|
1305
|
+
path.resolve(__dirname3, "../../../../../core/templates"),
|
|
1306
|
+
path.resolve(__dirname3, "../../../../core/templates")
|
|
849
1307
|
];
|
|
850
1308
|
for (const p of possiblePaths) {
|
|
851
1309
|
if (fs.existsSync(p)) {
|
|
@@ -1170,29 +1628,32 @@ function getTargetThemesDir2() {
|
|
|
1170
1628
|
return path2.resolve(process.cwd(), "contents", "themes");
|
|
1171
1629
|
}
|
|
1172
1630
|
async function updateAuthConfig(config2) {
|
|
1173
|
-
const
|
|
1631
|
+
const appConfigPath = path2.join(
|
|
1174
1632
|
getTargetThemesDir2(),
|
|
1175
1633
|
config2.projectSlug,
|
|
1176
1634
|
"config",
|
|
1177
|
-
"
|
|
1635
|
+
"app.config.ts"
|
|
1178
1636
|
);
|
|
1179
|
-
if (!await fs2.pathExists(
|
|
1637
|
+
if (!await fs2.pathExists(appConfigPath)) {
|
|
1180
1638
|
return;
|
|
1181
1639
|
}
|
|
1182
|
-
let content = await fs2.readFile(
|
|
1640
|
+
let content = await fs2.readFile(appConfigPath, "utf-8");
|
|
1183
1641
|
content = content.replace(
|
|
1184
|
-
/(
|
|
1185
|
-
`$1${config2.auth.
|
|
1642
|
+
/(mode:\s*)'open'(\s*as\s*const)/,
|
|
1643
|
+
`$1'${config2.auth.registrationMode}'$2`
|
|
1186
1644
|
);
|
|
1187
1645
|
content = content.replace(
|
|
1188
|
-
/(google:\s*{
|
|
1646
|
+
/(google:\s*{\s*enabled:\s*)(?:true|false)/s,
|
|
1189
1647
|
`$1${config2.auth.googleOAuth}`
|
|
1190
1648
|
);
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1649
|
+
if (config2.auth.registrationMode === "domain-restricted") {
|
|
1650
|
+
const domains = config2.auth.allowedDomains?.length ? config2.auth.allowedDomains.map((d) => `'${d}'`).join(", ") : "'yourcompany.com'";
|
|
1651
|
+
content = content.replace(
|
|
1652
|
+
/\/\/\s*allowedDomains:\s*\['yourcompany\.com'\],\s*\/\/\s*Only for 'domain-restricted' mode/,
|
|
1653
|
+
`allowedDomains: [${domains}],`
|
|
1654
|
+
);
|
|
1655
|
+
}
|
|
1656
|
+
await fs2.writeFile(appConfigPath, content, "utf-8");
|
|
1196
1657
|
}
|
|
1197
1658
|
async function updateDashboardUIConfig(config2) {
|
|
1198
1659
|
const dashboardConfigPath = path2.join(
|
|
@@ -1544,19 +2005,19 @@ async function processI18n(config2) {
|
|
|
1544
2005
|
// src/wizard/generators/content-features-generator.ts
|
|
1545
2006
|
import fs4 from "fs-extra";
|
|
1546
2007
|
import path4 from "path";
|
|
1547
|
-
import { fileURLToPath as
|
|
1548
|
-
var
|
|
1549
|
-
var
|
|
2008
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
2009
|
+
var __filename4 = fileURLToPath4(import.meta.url);
|
|
2010
|
+
var __dirname4 = path4.dirname(__filename4);
|
|
1550
2011
|
function getTemplatesDir2() {
|
|
1551
2012
|
const rootDir = process.cwd();
|
|
1552
2013
|
const possiblePaths = [
|
|
1553
2014
|
// From project root node_modules (most common for installed packages)
|
|
1554
2015
|
path4.resolve(rootDir, "node_modules/@nextsparkjs/core/templates"),
|
|
1555
2016
|
// From CLI dist folder for development
|
|
1556
|
-
path4.resolve(
|
|
2017
|
+
path4.resolve(__dirname4, "../../core/templates"),
|
|
1557
2018
|
// Legacy paths for different build structures
|
|
1558
|
-
path4.resolve(
|
|
1559
|
-
path4.resolve(
|
|
2019
|
+
path4.resolve(__dirname4, "../../../../../core/templates"),
|
|
2020
|
+
path4.resolve(__dirname4, "../../../../core/templates")
|
|
1560
2021
|
];
|
|
1561
2022
|
for (const p of possiblePaths) {
|
|
1562
2023
|
if (fs4.existsSync(p)) {
|
|
@@ -1620,22 +2081,22 @@ async function copyContentFeatures(config2) {
|
|
|
1620
2081
|
}
|
|
1621
2082
|
|
|
1622
2083
|
// src/wizard/generators/theme-plugins-installer.ts
|
|
1623
|
-
import { existsSync as
|
|
1624
|
-
import { join as
|
|
1625
|
-
import
|
|
1626
|
-
import
|
|
2084
|
+
import { existsSync as existsSync6, cpSync, mkdirSync, readFileSync as readFileSync6, writeFileSync } from "fs";
|
|
2085
|
+
import { join as join7, resolve as resolve2 } from "path";
|
|
2086
|
+
import chalk9 from "chalk";
|
|
2087
|
+
import ora6 from "ora";
|
|
1627
2088
|
|
|
1628
2089
|
// src/commands/add-theme.ts
|
|
1629
|
-
import
|
|
1630
|
-
import
|
|
1631
|
-
import { existsSync, readFileSync as
|
|
1632
|
-
import { join as
|
|
2090
|
+
import chalk8 from "chalk";
|
|
2091
|
+
import ora5 from "ora";
|
|
2092
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
2093
|
+
import { join as join6 } from "path";
|
|
1633
2094
|
async function addTheme(packageSpec, options = {}) {
|
|
1634
|
-
const spinner =
|
|
2095
|
+
const spinner = ora5(`Adding theme ${packageSpec}`).start();
|
|
1635
2096
|
let cleanup = null;
|
|
1636
2097
|
try {
|
|
1637
|
-
const contentsDir =
|
|
1638
|
-
if (!
|
|
2098
|
+
const contentsDir = join6(process.cwd(), "contents");
|
|
2099
|
+
if (!existsSync5(contentsDir)) {
|
|
1639
2100
|
spinner.fail('contents/ directory not found. Run "nextspark init" first.');
|
|
1640
2101
|
return;
|
|
1641
2102
|
}
|
|
@@ -1649,15 +2110,15 @@ async function addTheme(packageSpec, options = {}) {
|
|
|
1649
2110
|
const validation = validateTheme(packageJson, extractedPath);
|
|
1650
2111
|
if (!validation.valid) {
|
|
1651
2112
|
spinner.fail("Invalid theme");
|
|
1652
|
-
validation.errors.forEach((e) => console.log(
|
|
2113
|
+
validation.errors.forEach((e) => console.log(chalk8.red(` \u2717 ${e}`)));
|
|
1653
2114
|
return;
|
|
1654
2115
|
}
|
|
1655
2116
|
if (validation.warnings.length > 0) {
|
|
1656
|
-
validation.warnings.forEach((w) => console.log(
|
|
2117
|
+
validation.warnings.forEach((w) => console.log(chalk8.yellow(` \u26A0 ${w}`)));
|
|
1657
2118
|
}
|
|
1658
2119
|
if (packageJson.requiredPlugins?.length && !options.skipPostinstall) {
|
|
1659
2120
|
spinner.stop();
|
|
1660
|
-
console.log(
|
|
2121
|
+
console.log(chalk8.blue("\n Installing required plugins..."));
|
|
1661
2122
|
const installingPlugins = /* @__PURE__ */ new Set();
|
|
1662
2123
|
for (const plugin of packageJson.requiredPlugins) {
|
|
1663
2124
|
if (!checkPluginExists(plugin)) {
|
|
@@ -1681,14 +2142,14 @@ async function addTheme(packageSpec, options = {}) {
|
|
|
1681
2142
|
};
|
|
1682
2143
|
await runPostinstall(packageJson, result.installedPath, context);
|
|
1683
2144
|
}
|
|
1684
|
-
console.log(
|
|
2145
|
+
console.log(chalk8.green(`
|
|
1685
2146
|
\u2713 Theme ${result.name} installed successfully!`));
|
|
1686
|
-
console.log(
|
|
1687
|
-
console.log(
|
|
2147
|
+
console.log(chalk8.gray(` Location: contents/themes/${result.name}/`));
|
|
2148
|
+
console.log(chalk8.gray(` Set NEXT_PUBLIC_ACTIVE_THEME=${result.name} to activate`));
|
|
1688
2149
|
} catch (error) {
|
|
1689
2150
|
spinner.fail("Failed to add theme");
|
|
1690
2151
|
if (error instanceof Error) {
|
|
1691
|
-
console.log(
|
|
2152
|
+
console.log(chalk8.red(` ${error.message}`));
|
|
1692
2153
|
}
|
|
1693
2154
|
throw error;
|
|
1694
2155
|
} finally {
|
|
@@ -1697,13 +2158,13 @@ async function addTheme(packageSpec, options = {}) {
|
|
|
1697
2158
|
}
|
|
1698
2159
|
function checkPluginExists(pluginName) {
|
|
1699
2160
|
const name = pluginName.replace(/^@[^/]+\//, "").replace(/^nextspark-plugin-/, "").replace(/^plugin-/, "");
|
|
1700
|
-
return
|
|
2161
|
+
return existsSync5(join6(process.cwd(), "contents", "plugins", name));
|
|
1701
2162
|
}
|
|
1702
2163
|
function getCoreVersion() {
|
|
1703
|
-
const pkgPath =
|
|
1704
|
-
if (
|
|
2164
|
+
const pkgPath = join6(process.cwd(), "node_modules", "@nextsparkjs", "core", "package.json");
|
|
2165
|
+
if (existsSync5(pkgPath)) {
|
|
1705
2166
|
try {
|
|
1706
|
-
const pkg2 = JSON.parse(
|
|
2167
|
+
const pkg2 = JSON.parse(readFileSync5(pkgPath, "utf-8"));
|
|
1707
2168
|
return pkg2.version || "0.0.0";
|
|
1708
2169
|
} catch {
|
|
1709
2170
|
return "0.0.0";
|
|
@@ -1739,23 +2200,23 @@ var THEME_REQUIRED_PLUGINS2 = {
|
|
|
1739
2200
|
"crm": [],
|
|
1740
2201
|
"productivity": []
|
|
1741
2202
|
};
|
|
1742
|
-
function
|
|
2203
|
+
function isMonorepoMode2() {
|
|
1743
2204
|
const possiblePaths = [
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
2205
|
+
join7(process.cwd(), "pnpm-workspace.yaml"),
|
|
2206
|
+
join7(process.cwd(), "..", "pnpm-workspace.yaml"),
|
|
2207
|
+
join7(process.cwd(), "..", "..", "pnpm-workspace.yaml")
|
|
1747
2208
|
];
|
|
1748
|
-
return possiblePaths.some((p) =>
|
|
2209
|
+
return possiblePaths.some((p) => existsSync6(p));
|
|
1749
2210
|
}
|
|
1750
2211
|
function getMonorepoRoot() {
|
|
1751
2212
|
const possibleRoots = [
|
|
1752
2213
|
process.cwd(),
|
|
1753
|
-
|
|
1754
|
-
|
|
2214
|
+
join7(process.cwd(), ".."),
|
|
2215
|
+
join7(process.cwd(), "..", "..")
|
|
1755
2216
|
];
|
|
1756
2217
|
for (const root of possibleRoots) {
|
|
1757
|
-
if (
|
|
1758
|
-
return
|
|
2218
|
+
if (existsSync6(join7(root, "pnpm-workspace.yaml"))) {
|
|
2219
|
+
return resolve2(root);
|
|
1759
2220
|
}
|
|
1760
2221
|
}
|
|
1761
2222
|
return null;
|
|
@@ -1764,20 +2225,20 @@ function getLocalPackageDir(type, name) {
|
|
|
1764
2225
|
const monorepoRoot = getMonorepoRoot();
|
|
1765
2226
|
if (!monorepoRoot) return null;
|
|
1766
2227
|
const baseDir = type === "theme" ? "themes" : "plugins";
|
|
1767
|
-
const packageDir =
|
|
1768
|
-
if (
|
|
2228
|
+
const packageDir = join7(monorepoRoot, baseDir, name);
|
|
2229
|
+
if (existsSync6(packageDir) && existsSync6(join7(packageDir, "package.json"))) {
|
|
1769
2230
|
return packageDir;
|
|
1770
2231
|
}
|
|
1771
2232
|
return null;
|
|
1772
2233
|
}
|
|
1773
2234
|
async function copyLocalTheme(name, sourceDir) {
|
|
1774
|
-
const targetDir =
|
|
1775
|
-
const themesDir =
|
|
1776
|
-
if (!
|
|
2235
|
+
const targetDir = join7(process.cwd(), "contents", "themes", name);
|
|
2236
|
+
const themesDir = join7(process.cwd(), "contents", "themes");
|
|
2237
|
+
if (!existsSync6(themesDir)) {
|
|
1777
2238
|
mkdirSync(themesDir, { recursive: true });
|
|
1778
2239
|
}
|
|
1779
|
-
if (
|
|
1780
|
-
console.log(
|
|
2240
|
+
if (existsSync6(targetDir)) {
|
|
2241
|
+
console.log(chalk9.gray(` Theme ${name} already exists, skipping...`));
|
|
1781
2242
|
return true;
|
|
1782
2243
|
}
|
|
1783
2244
|
cpSync(sourceDir, targetDir, { recursive: true });
|
|
@@ -1785,13 +2246,13 @@ async function copyLocalTheme(name, sourceDir) {
|
|
|
1785
2246
|
return true;
|
|
1786
2247
|
}
|
|
1787
2248
|
async function copyLocalPlugin(name, sourceDir) {
|
|
1788
|
-
const targetDir =
|
|
1789
|
-
const pluginsDir =
|
|
1790
|
-
if (!
|
|
2249
|
+
const targetDir = join7(process.cwd(), "contents", "plugins", name);
|
|
2250
|
+
const pluginsDir = join7(process.cwd(), "contents", "plugins");
|
|
2251
|
+
if (!existsSync6(pluginsDir)) {
|
|
1791
2252
|
mkdirSync(pluginsDir, { recursive: true });
|
|
1792
2253
|
}
|
|
1793
|
-
if (
|
|
1794
|
-
console.log(
|
|
2254
|
+
if (existsSync6(targetDir)) {
|
|
2255
|
+
console.log(chalk9.gray(` Plugin ${name} already exists, skipping...`));
|
|
1795
2256
|
return true;
|
|
1796
2257
|
}
|
|
1797
2258
|
cpSync(sourceDir, targetDir, { recursive: true });
|
|
@@ -1799,12 +2260,12 @@ async function copyLocalPlugin(name, sourceDir) {
|
|
|
1799
2260
|
return true;
|
|
1800
2261
|
}
|
|
1801
2262
|
async function updateTsConfigPaths(name, type) {
|
|
1802
|
-
const tsconfigPath =
|
|
1803
|
-
if (!
|
|
2263
|
+
const tsconfigPath = join7(process.cwd(), "tsconfig.json");
|
|
2264
|
+
if (!existsSync6(tsconfigPath)) {
|
|
1804
2265
|
return;
|
|
1805
2266
|
}
|
|
1806
2267
|
try {
|
|
1807
|
-
const content =
|
|
2268
|
+
const content = readFileSync6(tsconfigPath, "utf-8");
|
|
1808
2269
|
const tsconfig = JSON.parse(content);
|
|
1809
2270
|
if (!tsconfig.compilerOptions) {
|
|
1810
2271
|
tsconfig.compilerOptions = {};
|
|
@@ -1839,17 +2300,17 @@ async function installTheme2(theme) {
|
|
|
1839
2300
|
if (!theme) {
|
|
1840
2301
|
return true;
|
|
1841
2302
|
}
|
|
1842
|
-
const spinner =
|
|
2303
|
+
const spinner = ora6({
|
|
1843
2304
|
text: `Installing reference theme: ${theme}...`,
|
|
1844
2305
|
prefixText: " "
|
|
1845
2306
|
}).start();
|
|
1846
2307
|
try {
|
|
1847
|
-
const targetDir =
|
|
1848
|
-
if (
|
|
1849
|
-
spinner.info(
|
|
2308
|
+
const targetDir = join7(process.cwd(), "contents", "themes", theme);
|
|
2309
|
+
if (existsSync6(targetDir)) {
|
|
2310
|
+
spinner.info(chalk9.gray(`Reference theme ${theme} already exists`));
|
|
1850
2311
|
return true;
|
|
1851
2312
|
}
|
|
1852
|
-
if (
|
|
2313
|
+
if (isMonorepoMode2()) {
|
|
1853
2314
|
const localDir = getLocalPackageDir("theme", theme);
|
|
1854
2315
|
if (localDir) {
|
|
1855
2316
|
spinner.text = `Copying reference theme from local: ${theme}...`;
|
|
@@ -1862,7 +2323,7 @@ async function installTheme2(theme) {
|
|
|
1862
2323
|
await copyLocalPlugin(plugin, pluginDir);
|
|
1863
2324
|
}
|
|
1864
2325
|
}
|
|
1865
|
-
spinner.succeed(
|
|
2326
|
+
spinner.succeed(chalk9.green(`Reference theme ${theme} installed!`));
|
|
1866
2327
|
return true;
|
|
1867
2328
|
}
|
|
1868
2329
|
}
|
|
@@ -1871,17 +2332,17 @@ async function installTheme2(theme) {
|
|
|
1871
2332
|
const packageSpec = THEME_PACKAGES[theme];
|
|
1872
2333
|
const success = await installThemeViaCli(packageSpec);
|
|
1873
2334
|
if (success) {
|
|
1874
|
-
spinner.succeed(
|
|
2335
|
+
spinner.succeed(chalk9.green(`Reference theme ${theme} installed!`));
|
|
1875
2336
|
return true;
|
|
1876
2337
|
} else {
|
|
1877
|
-
spinner.fail(
|
|
1878
|
-
console.log(
|
|
2338
|
+
spinner.fail(chalk9.red(`Failed to install theme: ${theme}`));
|
|
2339
|
+
console.log(chalk9.gray(" Hint: Make sure @nextsparkjs/cli is installed or the theme package is published"));
|
|
1879
2340
|
return false;
|
|
1880
2341
|
}
|
|
1881
2342
|
} catch (error) {
|
|
1882
|
-
spinner.fail(
|
|
2343
|
+
spinner.fail(chalk9.red(`Failed to install theme: ${theme}`));
|
|
1883
2344
|
if (error instanceof Error) {
|
|
1884
|
-
console.log(
|
|
2345
|
+
console.log(chalk9.red(` Error: ${error.message}`));
|
|
1885
2346
|
}
|
|
1886
2347
|
return false;
|
|
1887
2348
|
}
|
|
@@ -1892,23 +2353,23 @@ async function installPlugins(plugins) {
|
|
|
1892
2353
|
}
|
|
1893
2354
|
let allSuccess = true;
|
|
1894
2355
|
for (const plugin of plugins) {
|
|
1895
|
-
const spinner =
|
|
2356
|
+
const spinner = ora6({
|
|
1896
2357
|
text: `Installing plugin: ${plugin}...`,
|
|
1897
2358
|
prefixText: " "
|
|
1898
2359
|
}).start();
|
|
1899
2360
|
try {
|
|
1900
|
-
const pluginDir =
|
|
1901
|
-
if (
|
|
1902
|
-
spinner.info(
|
|
2361
|
+
const pluginDir = join7(process.cwd(), "contents", "plugins", plugin);
|
|
2362
|
+
if (existsSync6(pluginDir)) {
|
|
2363
|
+
spinner.info(chalk9.gray(`Plugin ${plugin} already installed`));
|
|
1903
2364
|
continue;
|
|
1904
2365
|
}
|
|
1905
|
-
if (
|
|
2366
|
+
if (isMonorepoMode2()) {
|
|
1906
2367
|
const localDir = getLocalPackageDir("plugin", plugin);
|
|
1907
2368
|
if (localDir) {
|
|
1908
2369
|
spinner.text = `Copying plugin from local: ${plugin}...`;
|
|
1909
2370
|
const success2 = await copyLocalPlugin(plugin, localDir);
|
|
1910
2371
|
if (success2) {
|
|
1911
|
-
spinner.succeed(
|
|
2372
|
+
spinner.succeed(chalk9.green(`Plugin ${plugin} installed!`));
|
|
1912
2373
|
continue;
|
|
1913
2374
|
}
|
|
1914
2375
|
}
|
|
@@ -1917,16 +2378,16 @@ async function installPlugins(plugins) {
|
|
|
1917
2378
|
const packageSpec = PLUGIN_PACKAGES[plugin];
|
|
1918
2379
|
const success = await installPluginViaCli(packageSpec);
|
|
1919
2380
|
if (success) {
|
|
1920
|
-
spinner.succeed(
|
|
2381
|
+
spinner.succeed(chalk9.green(`Plugin ${plugin} installed!`));
|
|
1921
2382
|
} else {
|
|
1922
|
-
spinner.fail(
|
|
1923
|
-
console.log(
|
|
2383
|
+
spinner.fail(chalk9.red(`Failed to install plugin: ${plugin}`));
|
|
2384
|
+
console.log(chalk9.gray(" Hint: Make sure @nextsparkjs/cli is installed or the plugin package is published"));
|
|
1924
2385
|
allSuccess = false;
|
|
1925
2386
|
}
|
|
1926
2387
|
} catch (error) {
|
|
1927
|
-
spinner.fail(
|
|
2388
|
+
spinner.fail(chalk9.red(`Failed to install plugin: ${plugin}`));
|
|
1928
2389
|
if (error instanceof Error) {
|
|
1929
|
-
console.log(
|
|
2390
|
+
console.log(chalk9.red(` Error: ${error.message}`));
|
|
1930
2391
|
}
|
|
1931
2392
|
allSuccess = false;
|
|
1932
2393
|
}
|
|
@@ -1938,19 +2399,19 @@ async function installThemeAndPlugins(theme, plugins) {
|
|
|
1938
2399
|
return true;
|
|
1939
2400
|
}
|
|
1940
2401
|
console.log("");
|
|
1941
|
-
console.log(
|
|
1942
|
-
console.log(
|
|
2402
|
+
console.log(chalk9.cyan(" Installing Reference Theme & Plugins"));
|
|
2403
|
+
console.log(chalk9.gray(" " + "-".repeat(40)));
|
|
1943
2404
|
console.log("");
|
|
1944
2405
|
const themeSuccess = await installTheme2(theme);
|
|
1945
2406
|
if (!themeSuccess && theme) {
|
|
1946
|
-
console.log(
|
|
2407
|
+
console.log(chalk9.yellow(" Warning: Theme installation failed, continuing with plugins..."));
|
|
1947
2408
|
}
|
|
1948
2409
|
const pluginsSuccess = await installPlugins(plugins);
|
|
1949
2410
|
console.log("");
|
|
1950
2411
|
if (themeSuccess && pluginsSuccess) {
|
|
1951
|
-
console.log(
|
|
2412
|
+
console.log(chalk9.green(" All installations completed successfully!"));
|
|
1952
2413
|
} else {
|
|
1953
|
-
console.log(
|
|
2414
|
+
console.log(chalk9.yellow(" Some installations had issues. Check the messages above."));
|
|
1954
2415
|
}
|
|
1955
2416
|
return themeSuccess && pluginsSuccess;
|
|
1956
2417
|
}
|
|
@@ -1958,10 +2419,10 @@ async function installThemeAndPlugins(theme, plugins) {
|
|
|
1958
2419
|
// src/wizard/generators/env-setup.ts
|
|
1959
2420
|
import fs5 from "fs-extra";
|
|
1960
2421
|
import path5 from "path";
|
|
1961
|
-
import { fileURLToPath as
|
|
1962
|
-
var
|
|
1963
|
-
var
|
|
1964
|
-
var ENV_TEMPLATE_PATH = path5.resolve(
|
|
2422
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
2423
|
+
var __filename5 = fileURLToPath5(import.meta.url);
|
|
2424
|
+
var __dirname5 = path5.dirname(__filename5);
|
|
2425
|
+
var ENV_TEMPLATE_PATH = path5.resolve(__dirname5, "../../../templates/env.template");
|
|
1965
2426
|
|
|
1966
2427
|
// src/wizard/generators/git-init.ts
|
|
1967
2428
|
import fs6 from "fs-extra";
|
|
@@ -1969,9 +2430,9 @@ import fs6 from "fs-extra";
|
|
|
1969
2430
|
// src/wizard/generators/monorepo-generator.ts
|
|
1970
2431
|
import fs7 from "fs-extra";
|
|
1971
2432
|
import path6 from "path";
|
|
1972
|
-
import { fileURLToPath as
|
|
1973
|
-
var
|
|
1974
|
-
var
|
|
2433
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
2434
|
+
var __filename6 = fileURLToPath6(import.meta.url);
|
|
2435
|
+
var __dirname6 = path6.dirname(__filename6);
|
|
1975
2436
|
var DIRS = {
|
|
1976
2437
|
WEB: "web",
|
|
1977
2438
|
MOBILE: "mobile",
|
|
@@ -2043,10 +2504,10 @@ function getMobileTemplatesDir() {
|
|
|
2043
2504
|
// From CWD node_modules (installed package)
|
|
2044
2505
|
path6.resolve(process.cwd(), "node_modules/@nextsparkjs/mobile/templates"),
|
|
2045
2506
|
// From CLI dist folder: ../../mobile/templates (development)
|
|
2046
|
-
path6.resolve(
|
|
2507
|
+
path6.resolve(__dirname6, "../../mobile/templates"),
|
|
2047
2508
|
// Legacy paths for different build structures
|
|
2048
|
-
path6.resolve(
|
|
2049
|
-
path6.resolve(
|
|
2509
|
+
path6.resolve(__dirname6, "../../../../../mobile/templates"),
|
|
2510
|
+
path6.resolve(__dirname6, "../../../../mobile/templates")
|
|
2050
2511
|
];
|
|
2051
2512
|
for (const p of possiblePaths) {
|
|
2052
2513
|
if (fs7.existsSync(p)) {
|
|
@@ -2498,18 +2959,18 @@ function getWebDir(targetDir, config2) {
|
|
|
2498
2959
|
}
|
|
2499
2960
|
|
|
2500
2961
|
// src/wizard/generators/index.ts
|
|
2501
|
-
var
|
|
2502
|
-
var
|
|
2962
|
+
var __filename7 = fileURLToPath7(import.meta.url);
|
|
2963
|
+
var __dirname7 = path7.dirname(__filename7);
|
|
2503
2964
|
function getTemplatesDir3(projectRoot) {
|
|
2504
2965
|
const rootDir = projectRoot || process.cwd();
|
|
2505
2966
|
const possiblePaths = [
|
|
2506
2967
|
// From project root node_modules (most common for installed packages)
|
|
2507
2968
|
path7.resolve(rootDir, "node_modules/@nextsparkjs/core/templates"),
|
|
2508
2969
|
// From CLI dist folder for development
|
|
2509
|
-
path7.resolve(
|
|
2970
|
+
path7.resolve(__dirname7, "../../core/templates"),
|
|
2510
2971
|
// Legacy paths for different build structures
|
|
2511
|
-
path7.resolve(
|
|
2512
|
-
path7.resolve(
|
|
2972
|
+
path7.resolve(__dirname7, "../../../../../core/templates"),
|
|
2973
|
+
path7.resolve(__dirname7, "../../../../core/templates")
|
|
2513
2974
|
];
|
|
2514
2975
|
for (const p of possiblePaths) {
|
|
2515
2976
|
if (fs8.existsSync(p)) {
|
|
@@ -2772,6 +3233,7 @@ var SAAS_PRESET = {
|
|
|
2772
3233
|
blog: false
|
|
2773
3234
|
},
|
|
2774
3235
|
auth: {
|
|
3236
|
+
registrationMode: "open",
|
|
2775
3237
|
emailPassword: true,
|
|
2776
3238
|
googleOAuth: true,
|
|
2777
3239
|
emailVerification: true
|
|
@@ -2811,6 +3273,7 @@ var BLOG_PRESET = {
|
|
|
2811
3273
|
blog: true
|
|
2812
3274
|
},
|
|
2813
3275
|
auth: {
|
|
3276
|
+
registrationMode: "invitation-only",
|
|
2814
3277
|
emailPassword: true,
|
|
2815
3278
|
googleOAuth: false,
|
|
2816
3279
|
emailVerification: false
|
|
@@ -2850,6 +3313,7 @@ var CRM_PRESET = {
|
|
|
2850
3313
|
blog: false
|
|
2851
3314
|
},
|
|
2852
3315
|
auth: {
|
|
3316
|
+
registrationMode: "invitation-only",
|
|
2853
3317
|
emailPassword: true,
|
|
2854
3318
|
googleOAuth: true,
|
|
2855
3319
|
emailVerification: true
|
|
@@ -2897,7 +3361,7 @@ function applyPreset(projectInfo, presetName, typeOverride) {
|
|
|
2897
3361
|
}
|
|
2898
3362
|
|
|
2899
3363
|
// src/wizard/preview.ts
|
|
2900
|
-
import
|
|
3364
|
+
import chalk10 from "chalk";
|
|
2901
3365
|
var BOX = {
|
|
2902
3366
|
vertical: "\u2502",
|
|
2903
3367
|
// |
|
|
@@ -2990,12 +3454,12 @@ function showConfigPreview(config2) {
|
|
|
2990
3454
|
const groups = groupFilesByCategory(files);
|
|
2991
3455
|
const themeDir = `contents/themes/${config2.projectSlug}`;
|
|
2992
3456
|
console.log("");
|
|
2993
|
-
console.log(
|
|
2994
|
-
console.log(
|
|
3457
|
+
console.log(chalk10.cyan.bold(" Theme Preview"));
|
|
3458
|
+
console.log(chalk10.gray(" " + "=".repeat(50)));
|
|
2995
3459
|
console.log("");
|
|
2996
|
-
console.log(
|
|
2997
|
-
console.log(
|
|
2998
|
-
console.log(
|
|
3460
|
+
console.log(chalk10.white.bold(` ${BOX.topLeft}${"\u2500".repeat(48)}${BOX.topRight}`));
|
|
3461
|
+
console.log(chalk10.white.bold(` ${BOX.vertical}`) + chalk10.cyan(` ${themeDir}/`) + " ".repeat(48 - themeDir.length - 2) + chalk10.white.bold(BOX.vertical));
|
|
3462
|
+
console.log(chalk10.white.bold(` ${BOX.vertical}${"\u2500".repeat(48)}${BOX.vertical}`));
|
|
2999
3463
|
const categoryLabels = {
|
|
3000
3464
|
config: "Configuration",
|
|
3001
3465
|
entities: "Entities",
|
|
@@ -3020,40 +3484,40 @@ function showConfigPreview(config2) {
|
|
|
3020
3484
|
if (categoryFiles.length === 0) continue;
|
|
3021
3485
|
const label = categoryLabels[category];
|
|
3022
3486
|
const icon = categoryIcons[category];
|
|
3023
|
-
console.log(
|
|
3487
|
+
console.log(chalk10.white.bold(` ${BOX.vertical} `) + chalk10.yellow(`[${icon}] ${label}`) + chalk10.gray(` (${categoryFiles.length} files)`));
|
|
3024
3488
|
for (let i = 0; i < categoryFiles.length; i++) {
|
|
3025
3489
|
const file = categoryFiles[i];
|
|
3026
3490
|
const isLast = i === categoryFiles.length - 1;
|
|
3027
3491
|
const prefix = isLast ? BOX.corner : BOX.tee;
|
|
3028
3492
|
const formattedPath = formatFilePath(file, themeDir);
|
|
3029
|
-
console.log(
|
|
3493
|
+
console.log(chalk10.white.bold(` ${BOX.vertical} `) + chalk10.gray(` ${prefix}${BOX.horizontal} `) + chalk10.white(formattedPath));
|
|
3030
3494
|
}
|
|
3031
|
-
console.log(
|
|
3495
|
+
console.log(chalk10.white.bold(` ${BOX.vertical}`));
|
|
3032
3496
|
}
|
|
3033
|
-
console.log(
|
|
3497
|
+
console.log(chalk10.white.bold(` ${BOX.bottomLeft}${"\u2500".repeat(48)}${BOX.bottomRight}`));
|
|
3034
3498
|
console.log("");
|
|
3035
|
-
console.log(
|
|
3036
|
-
console.log(
|
|
3499
|
+
console.log(chalk10.cyan.bold(" Summary"));
|
|
3500
|
+
console.log(chalk10.gray(" " + "-".repeat(30)));
|
|
3037
3501
|
console.log("");
|
|
3038
3502
|
const totalFiles = files.length;
|
|
3039
3503
|
const estimatedSize = "~350KB";
|
|
3040
|
-
console.log(
|
|
3041
|
-
console.log(
|
|
3504
|
+
console.log(chalk10.white(` Total files: `) + chalk10.green.bold(totalFiles.toString()));
|
|
3505
|
+
console.log(chalk10.white(` Estimated size: `) + chalk10.green.bold(estimatedSize));
|
|
3042
3506
|
console.log("");
|
|
3043
|
-
console.log(
|
|
3507
|
+
console.log(chalk10.gray(" By category:"));
|
|
3044
3508
|
for (const category of categoryOrder) {
|
|
3045
3509
|
const count = groups[category].length;
|
|
3046
3510
|
if (count > 0) {
|
|
3047
3511
|
const label = categoryLabels[category].padEnd(16);
|
|
3048
|
-
console.log(
|
|
3512
|
+
console.log(chalk10.gray(` ${label}`) + chalk10.white(count.toString().padStart(3)) + chalk10.gray(" files"));
|
|
3049
3513
|
}
|
|
3050
3514
|
}
|
|
3051
3515
|
console.log("");
|
|
3052
|
-
console.log(
|
|
3516
|
+
console.log(chalk10.gray(" Locales configured:"));
|
|
3053
3517
|
for (const locale of config2.supportedLocales) {
|
|
3054
3518
|
const isDefault = locale === config2.defaultLocale;
|
|
3055
|
-
const suffix = isDefault ?
|
|
3056
|
-
console.log(
|
|
3519
|
+
const suffix = isDefault ? chalk10.cyan(" (default)") : "";
|
|
3520
|
+
console.log(chalk10.gray(` - `) + chalk10.white(locale) + suffix);
|
|
3057
3521
|
}
|
|
3058
3522
|
console.log("");
|
|
3059
3523
|
}
|
|
@@ -3137,7 +3601,7 @@ async function runWizard(options = { mode: "interactive" }) {
|
|
|
3137
3601
|
}
|
|
3138
3602
|
}
|
|
3139
3603
|
console.log("");
|
|
3140
|
-
const spinner =
|
|
3604
|
+
const spinner = ora7({
|
|
3141
3605
|
text: "Generating your NextSpark project...",
|
|
3142
3606
|
prefixText: " "
|
|
3143
3607
|
}).start();
|
|
@@ -3154,7 +3618,7 @@ async function runWizard(options = { mode: "interactive" }) {
|
|
|
3154
3618
|
const projectRoot = process.cwd();
|
|
3155
3619
|
const webDir = getWebDir(projectRoot, config2);
|
|
3156
3620
|
const isMonorepo = isMonorepoProject(config2);
|
|
3157
|
-
const installSpinner =
|
|
3621
|
+
const installSpinner = ora7({
|
|
3158
3622
|
text: isMonorepo ? "Installing dependencies (monorepo)..." : "Installing dependencies...",
|
|
3159
3623
|
prefixText: " "
|
|
3160
3624
|
}).start();
|
|
@@ -3168,14 +3632,14 @@ async function runWizard(options = { mode: "interactive" }) {
|
|
|
3168
3632
|
installSpinner.succeed("Dependencies installed!");
|
|
3169
3633
|
} catch (error) {
|
|
3170
3634
|
installSpinner.fail("Failed to install dependencies");
|
|
3171
|
-
console.log(
|
|
3635
|
+
console.log(chalk11.yellow(' Run "pnpm install" manually to install dependencies'));
|
|
3172
3636
|
}
|
|
3173
|
-
const registrySpinner =
|
|
3637
|
+
const registrySpinner = ora7({
|
|
3174
3638
|
text: "Building registries...",
|
|
3175
3639
|
prefixText: " "
|
|
3176
3640
|
}).start();
|
|
3177
3641
|
try {
|
|
3178
|
-
const registryScript =
|
|
3642
|
+
const registryScript = join8(webDir, "node_modules/@nextsparkjs/core/scripts/build/registry.mjs");
|
|
3179
3643
|
registrySpinner.stop();
|
|
3180
3644
|
execSync(`node "${registryScript}" --build`, {
|
|
3181
3645
|
cwd: webDir,
|
|
@@ -3190,7 +3654,7 @@ async function runWizard(options = { mode: "interactive" }) {
|
|
|
3190
3654
|
} catch (error) {
|
|
3191
3655
|
registrySpinner.fail("Failed to build registries");
|
|
3192
3656
|
const devCmd = isMonorepo ? "pnpm dev" : "pnpm dev";
|
|
3193
|
-
console.log(
|
|
3657
|
+
console.log(chalk11.yellow(` Registries will be built automatically when you run "${devCmd}"`));
|
|
3194
3658
|
}
|
|
3195
3659
|
const aiChoice = await promptAIWorkflowSetup(config2);
|
|
3196
3660
|
showNextSteps(config2, selectedTheme, aiChoice);
|
|
@@ -3208,7 +3672,7 @@ async function runWizard(options = { mode: "interactive" }) {
|
|
|
3208
3672
|
}
|
|
3209
3673
|
function showModeIndicator(options) {
|
|
3210
3674
|
if (options.preset) {
|
|
3211
|
-
showInfo(`Using preset: ${
|
|
3675
|
+
showInfo(`Using preset: ${chalk11.cyan(options.preset)} - ${PRESET_DESCRIPTIONS[options.preset]}`);
|
|
3212
3676
|
console.log("");
|
|
3213
3677
|
} else if (options.mode === "quick") {
|
|
3214
3678
|
showInfo("Quick mode: Running essential prompts only (steps 1-5)");
|
|
@@ -3238,43 +3702,52 @@ async function runPresetMode(presetName, options) {
|
|
|
3238
3702
|
}
|
|
3239
3703
|
function showConfigSummary(config2) {
|
|
3240
3704
|
console.log("");
|
|
3241
|
-
console.log(
|
|
3242
|
-
console.log(
|
|
3243
|
-
console.log(
|
|
3705
|
+
console.log(chalk11.cyan(" " + "=".repeat(60)));
|
|
3706
|
+
console.log(chalk11.bold.white(" Configuration Summary"));
|
|
3707
|
+
console.log(chalk11.cyan(" " + "=".repeat(60)));
|
|
3244
3708
|
console.log("");
|
|
3245
|
-
console.log(
|
|
3246
|
-
console.log(
|
|
3247
|
-
console.log(
|
|
3248
|
-
console.log(
|
|
3249
|
-
console.log(
|
|
3709
|
+
console.log(chalk11.white(" Project:"));
|
|
3710
|
+
console.log(chalk11.gray(` Name: ${chalk11.white(config2.projectName)}`));
|
|
3711
|
+
console.log(chalk11.gray(` Slug: ${chalk11.white(config2.projectSlug)}`));
|
|
3712
|
+
console.log(chalk11.gray(` Description: ${chalk11.white(config2.projectDescription)}`));
|
|
3713
|
+
console.log(chalk11.gray(` Type: ${chalk11.white(config2.projectType === "web-mobile" ? "Web + Mobile (Monorepo)" : "Web only")}`));
|
|
3250
3714
|
console.log("");
|
|
3251
|
-
console.log(
|
|
3252
|
-
console.log(
|
|
3253
|
-
console.log(
|
|
3715
|
+
console.log(chalk11.white(" Team Mode:"));
|
|
3716
|
+
console.log(chalk11.gray(` Mode: ${chalk11.white(config2.teamMode)}`));
|
|
3717
|
+
console.log(chalk11.gray(` Roles: ${chalk11.white(config2.teamRoles.join(", "))}`));
|
|
3254
3718
|
console.log("");
|
|
3255
|
-
console.log(
|
|
3256
|
-
console.log(
|
|
3257
|
-
console.log(
|
|
3719
|
+
console.log(chalk11.white(" Internationalization:"));
|
|
3720
|
+
console.log(chalk11.gray(` Default: ${chalk11.white(config2.defaultLocale)}`));
|
|
3721
|
+
console.log(chalk11.gray(` Languages: ${chalk11.white(config2.supportedLocales.join(", "))}`));
|
|
3258
3722
|
console.log("");
|
|
3259
|
-
console.log(
|
|
3260
|
-
console.log(
|
|
3261
|
-
console.log(
|
|
3723
|
+
console.log(chalk11.white(" Billing:"));
|
|
3724
|
+
console.log(chalk11.gray(` Model: ${chalk11.white(config2.billingModel)}`));
|
|
3725
|
+
console.log(chalk11.gray(` Currency: ${chalk11.white(config2.currency.toUpperCase())}`));
|
|
3262
3726
|
console.log("");
|
|
3263
|
-
console.log(
|
|
3727
|
+
console.log(chalk11.white(" Features:"));
|
|
3264
3728
|
const enabledFeatures = Object.entries(config2.features).filter(([_, enabled]) => enabled).map(([feature]) => feature);
|
|
3265
|
-
console.log(
|
|
3729
|
+
console.log(chalk11.gray(` Enabled: ${chalk11.white(enabledFeatures.join(", ") || "None")}`));
|
|
3266
3730
|
console.log("");
|
|
3267
|
-
console.log(
|
|
3268
|
-
|
|
3269
|
-
|
|
3731
|
+
console.log(chalk11.white(" Authentication:"));
|
|
3732
|
+
console.log(chalk11.gray(` Registration: ${chalk11.white(formatRegistrationMode(config2.auth.registrationMode))}`));
|
|
3733
|
+
const enabledAuth = Object.entries(config2.auth).filter(([key, enabled]) => key !== "registrationMode" && enabled).map(([method]) => formatAuthMethod(method));
|
|
3734
|
+
console.log(chalk11.gray(` Methods: ${chalk11.white(enabledAuth.join(", ") || "None")}`));
|
|
3270
3735
|
console.log("");
|
|
3271
|
-
console.log(
|
|
3736
|
+
console.log(chalk11.white(" Dashboard:"));
|
|
3272
3737
|
const enabledDashboard = Object.entries(config2.dashboard).filter(([_, enabled]) => enabled).map(([feature]) => formatDashboardFeature(feature));
|
|
3273
|
-
console.log(
|
|
3738
|
+
console.log(chalk11.gray(` Features: ${chalk11.white(enabledDashboard.join(", ") || "None")}`));
|
|
3274
3739
|
console.log("");
|
|
3275
|
-
console.log(
|
|
3740
|
+
console.log(chalk11.white(" Dev Tools:"));
|
|
3276
3741
|
const enabledDevTools = Object.entries(config2.dev).filter(([_, enabled]) => enabled).map(([tool]) => formatDevTool(tool));
|
|
3277
|
-
console.log(
|
|
3742
|
+
console.log(chalk11.gray(` Enabled: ${chalk11.white(enabledDevTools.join(", ") || "None")}`));
|
|
3743
|
+
}
|
|
3744
|
+
function formatRegistrationMode(mode) {
|
|
3745
|
+
const mapping = {
|
|
3746
|
+
"open": "Open (anyone can register)",
|
|
3747
|
+
"domain-restricted": "Domain-Restricted (Google OAuth only)",
|
|
3748
|
+
"invitation-only": "Invitation-Only"
|
|
3749
|
+
};
|
|
3750
|
+
return mapping[mode] || mode;
|
|
3278
3751
|
}
|
|
3279
3752
|
function formatAuthMethod(method) {
|
|
3280
3753
|
const mapping = {
|
|
@@ -3304,68 +3777,68 @@ function showNextSteps(config2, referenceTheme = null, aiChoice = "skip") {
|
|
|
3304
3777
|
const isMonorepo = config2.projectType === "web-mobile";
|
|
3305
3778
|
const aiSetupDone = aiChoice === "claude";
|
|
3306
3779
|
console.log("");
|
|
3307
|
-
console.log(
|
|
3308
|
-
console.log(
|
|
3309
|
-
console.log(
|
|
3780
|
+
console.log(chalk11.cyan(" " + "=".repeat(60)));
|
|
3781
|
+
console.log(chalk11.bold.green(" \u2728 NextSpark project ready!"));
|
|
3782
|
+
console.log(chalk11.cyan(" " + "=".repeat(60)));
|
|
3310
3783
|
console.log("");
|
|
3311
|
-
console.log(
|
|
3784
|
+
console.log(chalk11.bold.white(" Next steps:"));
|
|
3312
3785
|
console.log("");
|
|
3313
3786
|
const envPath = isMonorepo ? "web/.env" : ".env";
|
|
3314
|
-
console.log(
|
|
3315
|
-
console.log(
|
|
3787
|
+
console.log(chalk11.white(" 1. Configure your environment:"));
|
|
3788
|
+
console.log(chalk11.gray(` Edit ${envPath} with your credentials:`));
|
|
3316
3789
|
console.log("");
|
|
3317
|
-
console.log(
|
|
3318
|
-
console.log(
|
|
3319
|
-
console.log(
|
|
3790
|
+
console.log(chalk11.yellow(" DATABASE_URL"));
|
|
3791
|
+
console.log(chalk11.gray(" PostgreSQL connection string"));
|
|
3792
|
+
console.log(chalk11.gray(` Recommended: ${chalk11.cyan("https://supabase.com")} | ${chalk11.cyan("https://neon.com")}`));
|
|
3320
3793
|
console.log("");
|
|
3321
|
-
console.log(
|
|
3322
|
-
console.log(
|
|
3323
|
-
console.log(
|
|
3794
|
+
console.log(chalk11.yellow(" BETTER_AUTH_SECRET"));
|
|
3795
|
+
console.log(chalk11.gray(" Generate with:"));
|
|
3796
|
+
console.log(chalk11.cyan(" openssl rand -base64 32"));
|
|
3324
3797
|
console.log("");
|
|
3325
|
-
console.log(
|
|
3326
|
-
console.log(
|
|
3798
|
+
console.log(chalk11.white(" 2. Run database migrations:"));
|
|
3799
|
+
console.log(chalk11.cyan(" pnpm db:migrate"));
|
|
3327
3800
|
console.log("");
|
|
3328
|
-
console.log(
|
|
3329
|
-
console.log(
|
|
3801
|
+
console.log(chalk11.white(" 3. Start the development server:"));
|
|
3802
|
+
console.log(chalk11.cyan(" pnpm dev"));
|
|
3330
3803
|
console.log("");
|
|
3331
3804
|
let nextStep = 4;
|
|
3332
3805
|
if (isMonorepo) {
|
|
3333
|
-
console.log(
|
|
3334
|
-
console.log(
|
|
3335
|
-
console.log(
|
|
3806
|
+
console.log(chalk11.white(` ${nextStep}. (Optional) Start the mobile app:`));
|
|
3807
|
+
console.log(chalk11.cyan(" pnpm dev:mobile"));
|
|
3808
|
+
console.log(chalk11.gray(" Or: cd mobile && pnpm start"));
|
|
3336
3809
|
console.log("");
|
|
3337
3810
|
nextStep++;
|
|
3338
3811
|
}
|
|
3339
3812
|
if (aiSetupDone) {
|
|
3340
|
-
console.log(
|
|
3341
|
-
console.log(
|
|
3342
|
-
console.log(
|
|
3813
|
+
console.log(chalk11.white(` ${nextStep}. Start building with AI:`));
|
|
3814
|
+
console.log(chalk11.gray(" Open Claude Code in your project and run:"));
|
|
3815
|
+
console.log(chalk11.cyan(" /how-to:start"));
|
|
3343
3816
|
console.log("");
|
|
3344
3817
|
} else {
|
|
3345
|
-
console.log(
|
|
3346
|
-
console.log(
|
|
3818
|
+
console.log(chalk11.white(` ${nextStep}. (Optional) Setup AI workflows:`));
|
|
3819
|
+
console.log(chalk11.cyan(" nextspark setup:ai"));
|
|
3347
3820
|
console.log("");
|
|
3348
3821
|
}
|
|
3349
|
-
console.log(
|
|
3822
|
+
console.log(chalk11.gray(" " + "-".repeat(60)));
|
|
3350
3823
|
if (isMonorepo) {
|
|
3351
|
-
console.log(
|
|
3352
|
-
console.log(
|
|
3353
|
-
console.log(
|
|
3354
|
-
console.log(
|
|
3824
|
+
console.log(chalk11.gray(` Structure: ${chalk11.white("Monorepo (web/ + mobile/)")}`));
|
|
3825
|
+
console.log(chalk11.gray(` Web theme: ${chalk11.white(`web/contents/themes/${config2.projectSlug}/`)}`));
|
|
3826
|
+
console.log(chalk11.gray(` Mobile app: ${chalk11.white("mobile/")}`));
|
|
3827
|
+
console.log(chalk11.gray(` Active theme: ${chalk11.green(`NEXT_PUBLIC_ACTIVE_THEME=${config2.projectSlug}`)}`));
|
|
3355
3828
|
} else {
|
|
3356
|
-
console.log(
|
|
3357
|
-
console.log(
|
|
3829
|
+
console.log(chalk11.gray(` Theme: ${chalk11.white(`contents/themes/${config2.projectSlug}/`)}`));
|
|
3830
|
+
console.log(chalk11.gray(` Active theme: ${chalk11.green(`NEXT_PUBLIC_ACTIVE_THEME=${config2.projectSlug}`)}`));
|
|
3358
3831
|
}
|
|
3359
3832
|
if (referenceTheme) {
|
|
3360
3833
|
const refPath = isMonorepo ? `web/contents/themes/${referenceTheme}/` : `contents/themes/${referenceTheme}/`;
|
|
3361
|
-
console.log(
|
|
3834
|
+
console.log(chalk11.gray(` Reference: ${chalk11.white(refPath)}`));
|
|
3362
3835
|
}
|
|
3363
|
-
console.log(
|
|
3836
|
+
console.log(chalk11.gray(` Docs: ${chalk11.cyan("https://nextspark.dev/docs")}`));
|
|
3364
3837
|
console.log("");
|
|
3365
3838
|
}
|
|
3366
3839
|
async function promptAIWorkflowSetup(config2) {
|
|
3367
3840
|
console.log("");
|
|
3368
|
-
const choice = await
|
|
3841
|
+
const choice = await select7({
|
|
3369
3842
|
message: "Setup AI-assisted development workflows?",
|
|
3370
3843
|
choices: [
|
|
3371
3844
|
{ name: "Claude Code (Recommended)", value: "claude" },
|
|
@@ -3388,11 +3861,11 @@ async function promptAIWorkflowSetup(config2) {
|
|
|
3388
3861
|
cwd: projectRoot,
|
|
3389
3862
|
stdio: "inherit"
|
|
3390
3863
|
});
|
|
3391
|
-
let setupScript =
|
|
3392
|
-
if (!
|
|
3393
|
-
setupScript =
|
|
3864
|
+
let setupScript = join8(projectRoot, "node_modules", "@nextsparkjs", "ai-workflow", "scripts", "setup.mjs");
|
|
3865
|
+
if (!existsSync7(setupScript) && isMonorepo) {
|
|
3866
|
+
setupScript = join8(projectRoot, "web", "node_modules", "@nextsparkjs", "ai-workflow", "scripts", "setup.mjs");
|
|
3394
3867
|
}
|
|
3395
|
-
if (
|
|
3868
|
+
if (existsSync7(setupScript)) {
|
|
3396
3869
|
execSync(`node "${setupScript}" ${choice}`, {
|
|
3397
3870
|
cwd: projectRoot,
|
|
3398
3871
|
stdio: "inherit"
|
|
@@ -3415,21 +3888,21 @@ function findLocalCoreTarball() {
|
|
|
3415
3888
|
(f) => f.includes("nextsparkjs-core") && f.endsWith(".tgz")
|
|
3416
3889
|
);
|
|
3417
3890
|
if (coreTarball) {
|
|
3418
|
-
return
|
|
3891
|
+
return join8(cwd, coreTarball);
|
|
3419
3892
|
}
|
|
3420
3893
|
} catch {
|
|
3421
3894
|
}
|
|
3422
3895
|
return null;
|
|
3423
3896
|
}
|
|
3424
3897
|
function isCoreInstalled() {
|
|
3425
|
-
const corePath =
|
|
3426
|
-
return
|
|
3898
|
+
const corePath = join8(process.cwd(), "node_modules", "@nextsparkjs", "core");
|
|
3899
|
+
return existsSync7(corePath);
|
|
3427
3900
|
}
|
|
3428
3901
|
async function installCore() {
|
|
3429
3902
|
if (isCoreInstalled()) {
|
|
3430
3903
|
return true;
|
|
3431
3904
|
}
|
|
3432
|
-
const spinner =
|
|
3905
|
+
const spinner = ora7({
|
|
3433
3906
|
text: "Installing @nextsparkjs/core...",
|
|
3434
3907
|
prefixText: " "
|
|
3435
3908
|
}).start();
|
|
@@ -3440,8 +3913,8 @@ async function installCore() {
|
|
|
3440
3913
|
packageSpec = localTarball;
|
|
3441
3914
|
spinner.text = "Installing @nextsparkjs/core from local tarball...";
|
|
3442
3915
|
}
|
|
3443
|
-
const useYarn =
|
|
3444
|
-
const usePnpm =
|
|
3916
|
+
const useYarn = existsSync7(join8(process.cwd(), "yarn.lock"));
|
|
3917
|
+
const usePnpm = existsSync7(join8(process.cwd(), "pnpm-lock.yaml"));
|
|
3445
3918
|
let installCmd;
|
|
3446
3919
|
if (usePnpm) {
|
|
3447
3920
|
installCmd = `pnpm add ${packageSpec}`;
|
|
@@ -3455,20 +3928,20 @@ async function installCore() {
|
|
|
3455
3928
|
stdio: "inherit",
|
|
3456
3929
|
cwd: process.cwd()
|
|
3457
3930
|
});
|
|
3458
|
-
spinner.succeed(
|
|
3931
|
+
spinner.succeed(chalk11.green("@nextsparkjs/core installed successfully!"));
|
|
3459
3932
|
return true;
|
|
3460
3933
|
} catch (error) {
|
|
3461
|
-
spinner.fail(
|
|
3934
|
+
spinner.fail(chalk11.red("Failed to install @nextsparkjs/core"));
|
|
3462
3935
|
if (error instanceof Error) {
|
|
3463
|
-
console.log(
|
|
3936
|
+
console.log(chalk11.red(` Error: ${error.message}`));
|
|
3464
3937
|
}
|
|
3465
|
-
console.log(
|
|
3938
|
+
console.log(chalk11.gray(" Hint: Make sure the package is available (npm registry or local tarball)"));
|
|
3466
3939
|
return false;
|
|
3467
3940
|
}
|
|
3468
3941
|
}
|
|
3469
3942
|
function isMobileInstalled() {
|
|
3470
|
-
const mobilePath =
|
|
3471
|
-
return
|
|
3943
|
+
const mobilePath = join8(process.cwd(), "node_modules", "@nextsparkjs", "mobile");
|
|
3944
|
+
return existsSync7(mobilePath);
|
|
3472
3945
|
}
|
|
3473
3946
|
function findLocalMobileTarball() {
|
|
3474
3947
|
const cwd = process.cwd();
|
|
@@ -3478,7 +3951,7 @@ function findLocalMobileTarball() {
|
|
|
3478
3951
|
(f) => f.includes("nextsparkjs-mobile") && f.endsWith(".tgz")
|
|
3479
3952
|
);
|
|
3480
3953
|
if (mobileTarball) {
|
|
3481
|
-
return
|
|
3954
|
+
return join8(cwd, mobileTarball);
|
|
3482
3955
|
}
|
|
3483
3956
|
} catch {
|
|
3484
3957
|
}
|
|
@@ -3488,7 +3961,7 @@ async function installMobile() {
|
|
|
3488
3961
|
if (isMobileInstalled()) {
|
|
3489
3962
|
return true;
|
|
3490
3963
|
}
|
|
3491
|
-
const spinner =
|
|
3964
|
+
const spinner = ora7({
|
|
3492
3965
|
text: "Installing @nextsparkjs/mobile...",
|
|
3493
3966
|
prefixText: " "
|
|
3494
3967
|
}).start();
|
|
@@ -3499,8 +3972,8 @@ async function installMobile() {
|
|
|
3499
3972
|
packageSpec = localTarball;
|
|
3500
3973
|
spinner.text = "Installing @nextsparkjs/mobile from local tarball...";
|
|
3501
3974
|
}
|
|
3502
|
-
const useYarn =
|
|
3503
|
-
const usePnpm =
|
|
3975
|
+
const useYarn = existsSync7(join8(process.cwd(), "yarn.lock"));
|
|
3976
|
+
const usePnpm = existsSync7(join8(process.cwd(), "pnpm-lock.yaml"));
|
|
3504
3977
|
let installCmd;
|
|
3505
3978
|
if (usePnpm) {
|
|
3506
3979
|
installCmd = `pnpm add ${packageSpec}`;
|
|
@@ -3514,14 +3987,14 @@ async function installMobile() {
|
|
|
3514
3987
|
stdio: "inherit",
|
|
3515
3988
|
cwd: process.cwd()
|
|
3516
3989
|
});
|
|
3517
|
-
spinner.succeed(
|
|
3990
|
+
spinner.succeed(chalk11.green("@nextsparkjs/mobile installed successfully!"));
|
|
3518
3991
|
return true;
|
|
3519
3992
|
} catch (error) {
|
|
3520
|
-
spinner.fail(
|
|
3993
|
+
spinner.fail(chalk11.red("Failed to install @nextsparkjs/mobile"));
|
|
3521
3994
|
if (error instanceof Error) {
|
|
3522
|
-
console.log(
|
|
3995
|
+
console.log(chalk11.red(` Error: ${error.message}`));
|
|
3523
3996
|
}
|
|
3524
|
-
console.log(
|
|
3997
|
+
console.log(chalk11.gray(" Hint: Make sure the package is available (npm registry or local tarball)"));
|
|
3525
3998
|
return false;
|
|
3526
3999
|
}
|
|
3527
4000
|
}
|
|
@@ -3538,10 +4011,10 @@ function parsePlugins(pluginsStr) {
|
|
|
3538
4011
|
}
|
|
3539
4012
|
function hasExistingProject() {
|
|
3540
4013
|
const projectRoot = process.cwd();
|
|
3541
|
-
return
|
|
4014
|
+
return existsSync8(join9(projectRoot, "contents")) || existsSync8(join9(projectRoot, ".nextspark"));
|
|
3542
4015
|
}
|
|
3543
4016
|
function generateInitialRegistries(registriesDir) {
|
|
3544
|
-
writeFileSync2(
|
|
4017
|
+
writeFileSync2(join9(registriesDir, "block-registry.ts"), `// Auto-generated by nextspark init
|
|
3545
4018
|
import type { ComponentType } from 'react'
|
|
3546
4019
|
|
|
3547
4020
|
export const BLOCK_REGISTRY: Record<string, {
|
|
@@ -3554,26 +4027,26 @@ export const BLOCK_REGISTRY: Record<string, {
|
|
|
3554
4027
|
|
|
3555
4028
|
export const BLOCK_COMPONENTS: Record<string, React.LazyExoticComponent<ComponentType<any>>> = {}
|
|
3556
4029
|
`);
|
|
3557
|
-
writeFileSync2(
|
|
4030
|
+
writeFileSync2(join9(registriesDir, "theme-registry.ts"), `// Auto-generated by nextspark init
|
|
3558
4031
|
export const THEME_REGISTRY: Record<string, unknown> = {}
|
|
3559
4032
|
`);
|
|
3560
|
-
writeFileSync2(
|
|
4033
|
+
writeFileSync2(join9(registriesDir, "entity-registry.ts"), `// Auto-generated by nextspark init
|
|
3561
4034
|
export const ENTITY_REGISTRY: Record<string, unknown> = {}
|
|
3562
4035
|
`);
|
|
3563
|
-
writeFileSync2(
|
|
4036
|
+
writeFileSync2(join9(registriesDir, "entity-registry.client.ts"), `// Auto-generated by nextspark init
|
|
3564
4037
|
export const CLIENT_ENTITY_REGISTRY: Record<string, unknown> = {}
|
|
3565
4038
|
export function parseChildEntity(path: string) { return null }
|
|
3566
4039
|
export function getEntityApiPath(entity: string) { return \`/api/\${entity}\` }
|
|
3567
4040
|
export function clientMetaSystemAdapter() { return {} }
|
|
3568
4041
|
export type ClientEntityConfig = Record<string, unknown>
|
|
3569
4042
|
`);
|
|
3570
|
-
writeFileSync2(
|
|
4043
|
+
writeFileSync2(join9(registriesDir, "billing-registry.ts"), `// Auto-generated by nextspark init
|
|
3571
4044
|
export const BILLING_REGISTRY = { plans: [], features: [] }
|
|
3572
4045
|
`);
|
|
3573
|
-
writeFileSync2(
|
|
4046
|
+
writeFileSync2(join9(registriesDir, "plugin-registry.ts"), `// Auto-generated by nextspark init
|
|
3574
4047
|
export const PLUGIN_REGISTRY: Record<string, unknown> = {}
|
|
3575
4048
|
`);
|
|
3576
|
-
writeFileSync2(
|
|
4049
|
+
writeFileSync2(join9(registriesDir, "testing-registry.ts"), `// Auto-generated by nextspark init
|
|
3577
4050
|
export const FLOW_REGISTRY: Record<string, unknown> = {}
|
|
3578
4051
|
export const FEATURE_REGISTRY: Record<string, unknown> = {}
|
|
3579
4052
|
export const TAGS_REGISTRY: Record<string, unknown> = {}
|
|
@@ -3581,11 +4054,11 @@ export const COVERAGE_SUMMARY = { total: 0, covered: 0 }
|
|
|
3581
4054
|
export type FlowEntry = unknown
|
|
3582
4055
|
export type FeatureEntry = unknown
|
|
3583
4056
|
`);
|
|
3584
|
-
writeFileSync2(
|
|
4057
|
+
writeFileSync2(join9(registriesDir, "docs-registry.ts"), `// Auto-generated by nextspark init
|
|
3585
4058
|
export const DOCS_REGISTRY = { sections: [], pages: [] }
|
|
3586
4059
|
export type DocSectionMeta = { title: string; slug: string }
|
|
3587
4060
|
`);
|
|
3588
|
-
writeFileSync2(
|
|
4061
|
+
writeFileSync2(join9(registriesDir, "index.ts"), `// Auto-generated by nextspark init
|
|
3589
4062
|
export * from './block-registry'
|
|
3590
4063
|
export * from './theme-registry'
|
|
3591
4064
|
export * from './entity-registry'
|
|
@@ -3597,21 +4070,21 @@ export * from './docs-registry'
|
|
|
3597
4070
|
`);
|
|
3598
4071
|
}
|
|
3599
4072
|
async function simpleInit(options) {
|
|
3600
|
-
const spinner =
|
|
4073
|
+
const spinner = ora8("Initializing NextSpark project...").start();
|
|
3601
4074
|
const projectRoot = process.cwd();
|
|
3602
4075
|
try {
|
|
3603
|
-
const nextspark =
|
|
3604
|
-
const registriesDir =
|
|
3605
|
-
if (!
|
|
4076
|
+
const nextspark = join9(projectRoot, ".nextspark");
|
|
4077
|
+
const registriesDir = join9(nextspark, "registries");
|
|
4078
|
+
if (!existsSync8(registriesDir) || options.force) {
|
|
3606
4079
|
mkdirSync2(registriesDir, { recursive: true });
|
|
3607
4080
|
spinner.text = "Creating .nextspark/registries/";
|
|
3608
4081
|
generateInitialRegistries(registriesDir);
|
|
3609
4082
|
spinner.text = "Generated initial registries";
|
|
3610
4083
|
}
|
|
3611
|
-
const tsconfigPath =
|
|
3612
|
-
if (
|
|
4084
|
+
const tsconfigPath = join9(projectRoot, "tsconfig.json");
|
|
4085
|
+
if (existsSync8(tsconfigPath)) {
|
|
3613
4086
|
spinner.text = "Updating tsconfig.json paths...";
|
|
3614
|
-
const tsconfig = JSON.parse(
|
|
4087
|
+
const tsconfig = JSON.parse(readFileSync7(tsconfigPath, "utf-8"));
|
|
3615
4088
|
tsconfig.compilerOptions = tsconfig.compilerOptions || {};
|
|
3616
4089
|
tsconfig.compilerOptions.paths = {
|
|
3617
4090
|
...tsconfig.compilerOptions.paths,
|
|
@@ -3620,8 +4093,8 @@ async function simpleInit(options) {
|
|
|
3620
4093
|
};
|
|
3621
4094
|
writeFileSync2(tsconfigPath, JSON.stringify(tsconfig, null, 2));
|
|
3622
4095
|
}
|
|
3623
|
-
const envExample =
|
|
3624
|
-
if (!
|
|
4096
|
+
const envExample = join9(projectRoot, ".env.example");
|
|
4097
|
+
if (!existsSync8(envExample)) {
|
|
3625
4098
|
const envContent = `# NextSpark Configuration
|
|
3626
4099
|
DATABASE_URL="postgresql://user:password@localhost:5432/db"
|
|
3627
4100
|
BETTER_AUTH_SECRET="your-secret-here-min-32-chars"
|
|
@@ -3632,14 +4105,14 @@ NEXT_PUBLIC_APP_URL=http://localhost:3000
|
|
|
3632
4105
|
spinner.text = "Created .env.example";
|
|
3633
4106
|
}
|
|
3634
4107
|
spinner.succeed("NextSpark initialized successfully!");
|
|
3635
|
-
console.log(
|
|
4108
|
+
console.log(chalk12.blue("\nNext steps:"));
|
|
3636
4109
|
console.log(" 1. Copy .env.example to .env and configure");
|
|
3637
4110
|
console.log(" 2. Run: nextspark generate");
|
|
3638
4111
|
console.log(" 3. Run: nextspark dev");
|
|
3639
4112
|
} catch (error) {
|
|
3640
4113
|
spinner.fail("Initialization failed");
|
|
3641
4114
|
if (error instanceof Error) {
|
|
3642
|
-
console.error(
|
|
4115
|
+
console.error(chalk12.red(error.message));
|
|
3643
4116
|
}
|
|
3644
4117
|
process.exit(1);
|
|
3645
4118
|
}
|
|
@@ -3650,8 +4123,8 @@ async function initCommand(options) {
|
|
|
3650
4123
|
return;
|
|
3651
4124
|
}
|
|
3652
4125
|
if (hasExistingProject() && !options.wizard && !options.preset && !options.theme) {
|
|
3653
|
-
console.log(
|
|
3654
|
-
console.log(
|
|
4126
|
+
console.log(chalk12.yellow("Existing NextSpark project detected."));
|
|
4127
|
+
console.log(chalk12.gray("Use --wizard to run the full wizard, or --registries-only for just registries."));
|
|
3655
4128
|
await simpleInit(options);
|
|
3656
4129
|
return;
|
|
3657
4130
|
}
|
|
@@ -3670,23 +4143,23 @@ async function initCommand(options) {
|
|
|
3670
4143
|
}
|
|
3671
4144
|
|
|
3672
4145
|
// src/commands/add-mobile.ts
|
|
3673
|
-
import { existsSync as
|
|
3674
|
-
import { join as
|
|
3675
|
-
import
|
|
3676
|
-
import
|
|
4146
|
+
import { existsSync as existsSync9, cpSync as cpSync2, readFileSync as readFileSync8, writeFileSync as writeFileSync3, renameSync, mkdirSync as mkdirSync3 } from "fs";
|
|
4147
|
+
import { join as join10 } from "path";
|
|
4148
|
+
import chalk13 from "chalk";
|
|
4149
|
+
import ora9 from "ora";
|
|
3677
4150
|
import { execSync as execSync2 } from "child_process";
|
|
3678
4151
|
function findMobileCoreDir() {
|
|
3679
4152
|
const projectRoot = process.cwd();
|
|
3680
|
-
const npmPath =
|
|
3681
|
-
if (
|
|
4153
|
+
const npmPath = join10(projectRoot, "node_modules", "@nextsparkjs", "mobile");
|
|
4154
|
+
if (existsSync9(npmPath)) {
|
|
3682
4155
|
return npmPath;
|
|
3683
4156
|
}
|
|
3684
|
-
const monoPath =
|
|
3685
|
-
if (
|
|
4157
|
+
const monoPath = join10(projectRoot, "packages", "mobile");
|
|
4158
|
+
if (existsSync9(monoPath)) {
|
|
3686
4159
|
return monoPath;
|
|
3687
4160
|
}
|
|
3688
|
-
const parentNpmPath =
|
|
3689
|
-
if (
|
|
4161
|
+
const parentNpmPath = join10(projectRoot, "..", "node_modules", "@nextsparkjs", "mobile");
|
|
4162
|
+
if (existsSync9(parentNpmPath)) {
|
|
3690
4163
|
return parentNpmPath;
|
|
3691
4164
|
}
|
|
3692
4165
|
throw new Error(
|
|
@@ -3695,40 +4168,40 @@ function findMobileCoreDir() {
|
|
|
3695
4168
|
}
|
|
3696
4169
|
async function addMobileCommand(options = {}) {
|
|
3697
4170
|
const projectRoot = process.cwd();
|
|
3698
|
-
const mobileDir =
|
|
4171
|
+
const mobileDir = join10(projectRoot, "mobile");
|
|
3699
4172
|
console.log();
|
|
3700
|
-
console.log(
|
|
4173
|
+
console.log(chalk13.bold("Adding NextSpark Mobile App"));
|
|
3701
4174
|
console.log();
|
|
3702
|
-
if (
|
|
3703
|
-
console.log(
|
|
3704
|
-
console.log(
|
|
4175
|
+
if (existsSync9(mobileDir) && !options.force) {
|
|
4176
|
+
console.log(chalk13.red("Error: Mobile app already exists at mobile/"));
|
|
4177
|
+
console.log(chalk13.gray("Use --force to overwrite"));
|
|
3705
4178
|
process.exit(1);
|
|
3706
4179
|
}
|
|
3707
4180
|
let mobileCoreDir;
|
|
3708
4181
|
try {
|
|
3709
4182
|
mobileCoreDir = findMobileCoreDir();
|
|
3710
4183
|
} catch (error) {
|
|
3711
|
-
console.log(
|
|
4184
|
+
console.log(chalk13.red(error.message));
|
|
3712
4185
|
process.exit(1);
|
|
3713
4186
|
}
|
|
3714
|
-
const templatesDir =
|
|
3715
|
-
if (!
|
|
3716
|
-
console.log(
|
|
3717
|
-
console.log(
|
|
4187
|
+
const templatesDir = join10(mobileCoreDir, "templates");
|
|
4188
|
+
if (!existsSync9(templatesDir)) {
|
|
4189
|
+
console.log(chalk13.red("Error: Could not find mobile templates"));
|
|
4190
|
+
console.log(chalk13.gray(`Expected at: ${templatesDir}`));
|
|
3718
4191
|
process.exit(1);
|
|
3719
4192
|
}
|
|
3720
|
-
const copySpinner =
|
|
4193
|
+
const copySpinner = ora9("Copying mobile app template...").start();
|
|
3721
4194
|
try {
|
|
3722
4195
|
mkdirSync3(mobileDir, { recursive: true });
|
|
3723
4196
|
cpSync2(templatesDir, mobileDir, { recursive: true });
|
|
3724
|
-
const pkgTemplatePath =
|
|
3725
|
-
const pkgPath =
|
|
3726
|
-
if (
|
|
4197
|
+
const pkgTemplatePath = join10(mobileDir, "package.json.template");
|
|
4198
|
+
const pkgPath = join10(mobileDir, "package.json");
|
|
4199
|
+
if (existsSync9(pkgTemplatePath)) {
|
|
3727
4200
|
renameSync(pkgTemplatePath, pkgPath);
|
|
3728
|
-
const pkg2 = JSON.parse(
|
|
3729
|
-
const rootPkgPath =
|
|
3730
|
-
if (
|
|
3731
|
-
const rootPkg = JSON.parse(
|
|
4201
|
+
const pkg2 = JSON.parse(readFileSync8(pkgPath, "utf-8"));
|
|
4202
|
+
const rootPkgPath = join10(projectRoot, "package.json");
|
|
4203
|
+
if (existsSync9(rootPkgPath)) {
|
|
4204
|
+
const rootPkg = JSON.parse(readFileSync8(rootPkgPath, "utf-8"));
|
|
3732
4205
|
const rawName = rootPkg.name || "my-project";
|
|
3733
4206
|
if (rawName.startsWith("@")) {
|
|
3734
4207
|
const scopeMatch = rawName.match(/^@[\w-]+/);
|
|
@@ -3744,11 +4217,11 @@ async function addMobileCommand(options = {}) {
|
|
|
3744
4217
|
copySpinner.succeed("Mobile app template copied");
|
|
3745
4218
|
} catch (error) {
|
|
3746
4219
|
copySpinner.fail("Failed to copy templates");
|
|
3747
|
-
console.log(
|
|
4220
|
+
console.log(chalk13.red(error.message));
|
|
3748
4221
|
process.exit(1);
|
|
3749
4222
|
}
|
|
3750
4223
|
if (!options.skipInstall) {
|
|
3751
|
-
const installSpinner =
|
|
4224
|
+
const installSpinner = ora9("Installing dependencies...").start();
|
|
3752
4225
|
try {
|
|
3753
4226
|
execSync2("npm install", {
|
|
3754
4227
|
cwd: mobileDir,
|
|
@@ -3759,28 +4232,28 @@ async function addMobileCommand(options = {}) {
|
|
|
3759
4232
|
installSpinner.succeed("Dependencies installed");
|
|
3760
4233
|
} catch (error) {
|
|
3761
4234
|
installSpinner.fail("Failed to install dependencies");
|
|
3762
|
-
console.log(
|
|
4235
|
+
console.log(chalk13.yellow(" Run `npm install` in mobile/ manually"));
|
|
3763
4236
|
}
|
|
3764
4237
|
}
|
|
3765
4238
|
console.log();
|
|
3766
|
-
console.log(
|
|
4239
|
+
console.log(chalk13.green.bold(" Mobile app created successfully!"));
|
|
3767
4240
|
console.log();
|
|
3768
|
-
console.log(
|
|
4241
|
+
console.log(chalk13.bold(" Next steps:"));
|
|
3769
4242
|
console.log();
|
|
3770
|
-
console.log(` ${
|
|
3771
|
-
console.log(` ${
|
|
3772
|
-
console.log(` ${
|
|
3773
|
-
console.log(` ${
|
|
4243
|
+
console.log(` ${chalk13.cyan("1.")} cd mobile`);
|
|
4244
|
+
console.log(` ${chalk13.cyan("2.")} Update ${chalk13.bold("app.config.ts")} with your app name and bundle ID`);
|
|
4245
|
+
console.log(` ${chalk13.cyan("3.")} Add your entities in ${chalk13.bold("src/entities/")}`);
|
|
4246
|
+
console.log(` ${chalk13.cyan("4.")} npm start`);
|
|
3774
4247
|
console.log();
|
|
3775
|
-
console.log(
|
|
4248
|
+
console.log(chalk13.gray(" Documentation: https://nextspark.dev/docs/mobile"));
|
|
3776
4249
|
console.log();
|
|
3777
4250
|
}
|
|
3778
4251
|
|
|
3779
4252
|
// src/commands/doctor.ts
|
|
3780
|
-
import
|
|
4253
|
+
import chalk15 from "chalk";
|
|
3781
4254
|
|
|
3782
4255
|
// src/doctor/index.ts
|
|
3783
|
-
import
|
|
4256
|
+
import chalk14 from "chalk";
|
|
3784
4257
|
|
|
3785
4258
|
// src/doctor/checks/dependencies.ts
|
|
3786
4259
|
import fs9 from "fs-extra";
|
|
@@ -4148,25 +4621,25 @@ async function checkImports() {
|
|
|
4148
4621
|
|
|
4149
4622
|
// src/doctor/index.ts
|
|
4150
4623
|
var STATUS_ICONS = {
|
|
4151
|
-
pass:
|
|
4152
|
-
warn:
|
|
4153
|
-
fail:
|
|
4624
|
+
pass: chalk14.green("\u2713"),
|
|
4625
|
+
warn: chalk14.yellow("\u26A0"),
|
|
4626
|
+
fail: chalk14.red("\u2717")
|
|
4154
4627
|
};
|
|
4155
4628
|
function formatResult(result) {
|
|
4156
4629
|
const icon = STATUS_ICONS[result.status];
|
|
4157
|
-
const nameColor = result.status === "fail" ?
|
|
4630
|
+
const nameColor = result.status === "fail" ? chalk14.red : result.status === "warn" ? chalk14.yellow : chalk14.white;
|
|
4158
4631
|
const name = nameColor(result.name.padEnd(18));
|
|
4159
|
-
const message =
|
|
4632
|
+
const message = chalk14.gray(result.message);
|
|
4160
4633
|
let output = `${icon} ${name} ${message}`;
|
|
4161
4634
|
if (result.fix && result.status !== "pass") {
|
|
4162
4635
|
output += `
|
|
4163
|
-
${" ".repeat(22)}${
|
|
4636
|
+
${" ".repeat(22)}${chalk14.cyan("\u2192")} ${chalk14.cyan(result.fix)}`;
|
|
4164
4637
|
}
|
|
4165
4638
|
return output;
|
|
4166
4639
|
}
|
|
4167
4640
|
function showHeader() {
|
|
4168
4641
|
console.log("");
|
|
4169
|
-
console.log(
|
|
4642
|
+
console.log(chalk14.cyan("\u{1FA7A} NextSpark Health Check"));
|
|
4170
4643
|
console.log("");
|
|
4171
4644
|
}
|
|
4172
4645
|
function showSummary(results) {
|
|
@@ -4174,11 +4647,11 @@ function showSummary(results) {
|
|
|
4174
4647
|
const warnings = results.filter((r) => r.status === "warn").length;
|
|
4175
4648
|
const failed = results.filter((r) => r.status === "fail").length;
|
|
4176
4649
|
console.log("");
|
|
4177
|
-
console.log(
|
|
4650
|
+
console.log(chalk14.gray("-".repeat(50)));
|
|
4178
4651
|
const summary = [
|
|
4179
|
-
|
|
4180
|
-
warnings > 0 ?
|
|
4181
|
-
failed > 0 ?
|
|
4652
|
+
chalk14.green(`${passed} passed`),
|
|
4653
|
+
warnings > 0 ? chalk14.yellow(`${warnings} warning${warnings > 1 ? "s" : ""}`) : null,
|
|
4654
|
+
failed > 0 ? chalk14.red(`${failed} failed`) : null
|
|
4182
4655
|
].filter(Boolean).join(", ");
|
|
4183
4656
|
console.log(`Summary: ${summary}`);
|
|
4184
4657
|
console.log("");
|
|
@@ -4220,7 +4693,7 @@ async function runDoctorCommand() {
|
|
|
4220
4693
|
var isDirectExecution = process.argv[1]?.includes("doctor") || process.argv.includes("doctor");
|
|
4221
4694
|
if (isDirectExecution && typeof __require !== "undefined") {
|
|
4222
4695
|
runDoctorCommand().catch((error) => {
|
|
4223
|
-
console.error(
|
|
4696
|
+
console.error(chalk14.red("An unexpected error occurred:"), error.message);
|
|
4224
4697
|
process.exit(1);
|
|
4225
4698
|
});
|
|
4226
4699
|
}
|
|
@@ -4231,23 +4704,23 @@ async function doctorCommand() {
|
|
|
4231
4704
|
await runDoctorCommand();
|
|
4232
4705
|
} catch (error) {
|
|
4233
4706
|
if (error instanceof Error) {
|
|
4234
|
-
console.error(
|
|
4707
|
+
console.error(chalk15.red(`Error: ${error.message}`));
|
|
4235
4708
|
}
|
|
4236
4709
|
process.exit(1);
|
|
4237
4710
|
}
|
|
4238
4711
|
}
|
|
4239
4712
|
|
|
4240
4713
|
// src/commands/db.ts
|
|
4241
|
-
import { spawn } from "child_process";
|
|
4242
|
-
import { existsSync as
|
|
4243
|
-
import { join as
|
|
4244
|
-
import
|
|
4245
|
-
import
|
|
4246
|
-
function
|
|
4247
|
-
const envPath =
|
|
4714
|
+
import { spawn as spawn5 } from "child_process";
|
|
4715
|
+
import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
|
|
4716
|
+
import { join as join11 } from "path";
|
|
4717
|
+
import chalk16 from "chalk";
|
|
4718
|
+
import ora10 from "ora";
|
|
4719
|
+
function loadProjectEnv4(projectRoot) {
|
|
4720
|
+
const envPath = join11(projectRoot, ".env");
|
|
4248
4721
|
const envVars = {};
|
|
4249
|
-
if (
|
|
4250
|
-
const content =
|
|
4722
|
+
if (existsSync10(envPath)) {
|
|
4723
|
+
const content = readFileSync9(envPath, "utf-8");
|
|
4251
4724
|
for (const line of content.split("\n")) {
|
|
4252
4725
|
const trimmed = line.trim();
|
|
4253
4726
|
if (trimmed && !trimmed.startsWith("#")) {
|
|
@@ -4265,30 +4738,30 @@ function loadProjectEnv(projectRoot) {
|
|
|
4265
4738
|
return envVars;
|
|
4266
4739
|
}
|
|
4267
4740
|
async function dbMigrateCommand() {
|
|
4268
|
-
const spinner =
|
|
4741
|
+
const spinner = ora10("Preparing to run migrations...").start();
|
|
4269
4742
|
try {
|
|
4270
4743
|
const coreDir = getCoreDir();
|
|
4271
4744
|
const projectRoot = getProjectRoot();
|
|
4272
|
-
const migrationsScript =
|
|
4273
|
-
if (!
|
|
4745
|
+
const migrationsScript = join11(coreDir, "scripts", "db", "run-migrations.mjs");
|
|
4746
|
+
if (!existsSync10(migrationsScript)) {
|
|
4274
4747
|
spinner.fail("Migrations script not found");
|
|
4275
|
-
console.error(
|
|
4748
|
+
console.error(chalk16.red(`Expected script at: ${migrationsScript}`));
|
|
4276
4749
|
process.exit(1);
|
|
4277
4750
|
}
|
|
4278
4751
|
spinner.succeed("Core package found");
|
|
4279
|
-
const projectEnv =
|
|
4752
|
+
const projectEnv = loadProjectEnv4(projectRoot);
|
|
4280
4753
|
if (!projectEnv.DATABASE_URL) {
|
|
4281
4754
|
spinner.fail("DATABASE_URL not found in .env file");
|
|
4282
|
-
console.error(
|
|
4755
|
+
console.error(chalk16.red("Please configure DATABASE_URL in your .env file"));
|
|
4283
4756
|
process.exit(1);
|
|
4284
4757
|
}
|
|
4285
4758
|
if (!projectEnv.NEXT_PUBLIC_ACTIVE_THEME) {
|
|
4286
4759
|
spinner.fail("NEXT_PUBLIC_ACTIVE_THEME not found in .env file");
|
|
4287
|
-
console.error(
|
|
4760
|
+
console.error(chalk16.red("Please configure NEXT_PUBLIC_ACTIVE_THEME in your .env file"));
|
|
4288
4761
|
process.exit(1);
|
|
4289
4762
|
}
|
|
4290
4763
|
spinner.start("Running database migrations...");
|
|
4291
|
-
const migrateProcess =
|
|
4764
|
+
const migrateProcess = spawn5("node", [migrationsScript], {
|
|
4292
4765
|
cwd: projectRoot,
|
|
4293
4766
|
stdio: "inherit",
|
|
4294
4767
|
env: {
|
|
@@ -4300,15 +4773,15 @@ async function dbMigrateCommand() {
|
|
|
4300
4773
|
});
|
|
4301
4774
|
migrateProcess.on("error", (err) => {
|
|
4302
4775
|
spinner.fail("Migration failed");
|
|
4303
|
-
console.error(
|
|
4776
|
+
console.error(chalk16.red(err.message));
|
|
4304
4777
|
process.exit(1);
|
|
4305
4778
|
});
|
|
4306
4779
|
migrateProcess.on("close", (code) => {
|
|
4307
4780
|
if (code === 0) {
|
|
4308
|
-
console.log(
|
|
4781
|
+
console.log(chalk16.green("\n\u2705 Migrations completed successfully!"));
|
|
4309
4782
|
process.exit(0);
|
|
4310
4783
|
} else {
|
|
4311
|
-
console.error(
|
|
4784
|
+
console.error(chalk16.red(`
|
|
4312
4785
|
\u274C Migrations failed with exit code ${code}`));
|
|
4313
4786
|
process.exit(code ?? 1);
|
|
4314
4787
|
}
|
|
@@ -4316,22 +4789,22 @@ async function dbMigrateCommand() {
|
|
|
4316
4789
|
} catch (error) {
|
|
4317
4790
|
spinner.fail("Migration preparation failed");
|
|
4318
4791
|
if (error instanceof Error) {
|
|
4319
|
-
console.error(
|
|
4792
|
+
console.error(chalk16.red(error.message));
|
|
4320
4793
|
}
|
|
4321
4794
|
process.exit(1);
|
|
4322
4795
|
}
|
|
4323
4796
|
}
|
|
4324
4797
|
async function dbSeedCommand() {
|
|
4325
|
-
console.log(
|
|
4326
|
-
console.log(
|
|
4798
|
+
console.log(chalk16.cyan("\u2139\uFE0F Sample data is included as part of the migration process."));
|
|
4799
|
+
console.log(chalk16.cyan(" Running db:migrate to apply all migrations including sample data...\n"));
|
|
4327
4800
|
await dbMigrateCommand();
|
|
4328
4801
|
}
|
|
4329
4802
|
|
|
4330
4803
|
// src/commands/sync-app.ts
|
|
4331
|
-
import { existsSync as
|
|
4332
|
-
import { join as
|
|
4333
|
-
import
|
|
4334
|
-
import
|
|
4804
|
+
import { existsSync as existsSync11, readdirSync as readdirSync2, mkdirSync as mkdirSync4, copyFileSync, readFileSync as readFileSync10 } from "fs";
|
|
4805
|
+
import { join as join12, dirname as dirname4, relative } from "path";
|
|
4806
|
+
import chalk17 from "chalk";
|
|
4807
|
+
import ora11 from "ora";
|
|
4335
4808
|
var EXCLUDED_TEMPLATE_PATTERNS = ["(templates)"];
|
|
4336
4809
|
var ROOT_TEMPLATE_FILES = [
|
|
4337
4810
|
"proxy.ts",
|
|
@@ -4347,12 +4820,12 @@ var MAX_VERBOSE_FILES = 10;
|
|
|
4347
4820
|
var MAX_SUMMARY_FILES = 5;
|
|
4348
4821
|
function getAllFiles(dir, baseDir = dir) {
|
|
4349
4822
|
const files = [];
|
|
4350
|
-
if (!
|
|
4823
|
+
if (!existsSync11(dir)) {
|
|
4351
4824
|
return files;
|
|
4352
4825
|
}
|
|
4353
4826
|
const entries = readdirSync2(dir, { withFileTypes: true });
|
|
4354
4827
|
for (const entry of entries) {
|
|
4355
|
-
const fullPath =
|
|
4828
|
+
const fullPath = join12(dir, entry.name);
|
|
4356
4829
|
const relativePath = relative(baseDir, fullPath);
|
|
4357
4830
|
if (entry.isDirectory()) {
|
|
4358
4831
|
files.push(...getAllFiles(fullPath, baseDir));
|
|
@@ -4365,50 +4838,50 @@ function getAllFiles(dir, baseDir = dir) {
|
|
|
4365
4838
|
return files;
|
|
4366
4839
|
}
|
|
4367
4840
|
function copyFile(source, target) {
|
|
4368
|
-
const targetDir =
|
|
4369
|
-
if (!
|
|
4841
|
+
const targetDir = dirname4(target);
|
|
4842
|
+
if (!existsSync11(targetDir)) {
|
|
4370
4843
|
mkdirSync4(targetDir, { recursive: true });
|
|
4371
4844
|
}
|
|
4372
4845
|
copyFileSync(source, target);
|
|
4373
4846
|
}
|
|
4374
4847
|
function backupDirectory(source, target) {
|
|
4375
|
-
if (!
|
|
4848
|
+
if (!existsSync11(source)) {
|
|
4376
4849
|
return;
|
|
4377
4850
|
}
|
|
4378
4851
|
const files = getAllFiles(source);
|
|
4379
4852
|
for (const file of files) {
|
|
4380
|
-
const sourcePath =
|
|
4381
|
-
const targetPath =
|
|
4853
|
+
const sourcePath = join12(source, file);
|
|
4854
|
+
const targetPath = join12(target, file);
|
|
4382
4855
|
copyFile(sourcePath, targetPath);
|
|
4383
4856
|
}
|
|
4384
4857
|
}
|
|
4385
4858
|
function getCoreVersion2(coreDir) {
|
|
4386
4859
|
try {
|
|
4387
|
-
const pkgPath =
|
|
4388
|
-
const pkg2 = JSON.parse(
|
|
4860
|
+
const pkgPath = join12(coreDir, "package.json");
|
|
4861
|
+
const pkg2 = JSON.parse(readFileSync10(pkgPath, "utf-8"));
|
|
4389
4862
|
return pkg2.version || "unknown";
|
|
4390
4863
|
} catch {
|
|
4391
4864
|
return "unknown";
|
|
4392
4865
|
}
|
|
4393
4866
|
}
|
|
4394
4867
|
async function syncAppCommand(options) {
|
|
4395
|
-
const spinner =
|
|
4868
|
+
const spinner = ora11({ text: "Preparing sync...", isSilent: options.dryRun }).start();
|
|
4396
4869
|
try {
|
|
4397
4870
|
const coreDir = getCoreDir();
|
|
4398
4871
|
const projectRoot = getProjectRoot();
|
|
4399
4872
|
const coreVersion = getCoreVersion2(coreDir);
|
|
4400
|
-
const templatesDir =
|
|
4401
|
-
const appDir =
|
|
4402
|
-
if (!
|
|
4873
|
+
const templatesDir = join12(coreDir, "templates", "app");
|
|
4874
|
+
const appDir = join12(projectRoot, "app");
|
|
4875
|
+
if (!existsSync11(templatesDir)) {
|
|
4403
4876
|
spinner.fail("Templates directory not found in @nextsparkjs/core");
|
|
4404
|
-
console.error(
|
|
4877
|
+
console.error(chalk17.red(`
|
|
4405
4878
|
Expected path: ${templatesDir}`));
|
|
4406
4879
|
process.exit(1);
|
|
4407
4880
|
}
|
|
4408
|
-
if (!
|
|
4881
|
+
if (!existsSync11(appDir)) {
|
|
4409
4882
|
spinner.fail("No /app directory found");
|
|
4410
|
-
console.error(
|
|
4411
|
-
console.error(
|
|
4883
|
+
console.error(chalk17.red("\n This project does not have an /app folder."));
|
|
4884
|
+
console.error(chalk17.yellow(' Run "nextspark init" first to initialize your project.\n'));
|
|
4412
4885
|
process.exit(1);
|
|
4413
4886
|
}
|
|
4414
4887
|
spinner.text = "Scanning template files...";
|
|
@@ -4417,36 +4890,36 @@ async function syncAppCommand(options) {
|
|
|
4417
4890
|
const customFiles = existingAppFiles.filter((f) => !templateFiles.includes(f));
|
|
4418
4891
|
const filesToUpdate = templateFiles;
|
|
4419
4892
|
spinner.succeed("Scan complete");
|
|
4420
|
-
console.log(
|
|
4893
|
+
console.log(chalk17.cyan(`
|
|
4421
4894
|
Syncing /app with @nextsparkjs/core@${coreVersion}...
|
|
4422
4895
|
`));
|
|
4423
4896
|
if (options.dryRun) {
|
|
4424
|
-
console.log(
|
|
4897
|
+
console.log(chalk17.yellow(" [DRY RUN] No changes will be made\n"));
|
|
4425
4898
|
}
|
|
4426
4899
|
if (options.verbose) {
|
|
4427
|
-
console.log(
|
|
4900
|
+
console.log(chalk17.gray(" Files to sync:"));
|
|
4428
4901
|
for (const file of filesToUpdate) {
|
|
4429
|
-
const targetPath =
|
|
4430
|
-
const status =
|
|
4431
|
-
console.log(
|
|
4902
|
+
const targetPath = join12(appDir, file);
|
|
4903
|
+
const status = existsSync11(targetPath) ? chalk17.yellow("update") : chalk17.green("create");
|
|
4904
|
+
console.log(chalk17.gray(` ${status} ${file}`));
|
|
4432
4905
|
}
|
|
4433
4906
|
console.log();
|
|
4434
4907
|
}
|
|
4435
|
-
console.log(
|
|
4436
|
-
console.log(
|
|
4908
|
+
console.log(chalk17.white(` Template files: ${filesToUpdate.length}`));
|
|
4909
|
+
console.log(chalk17.white(` Custom files preserved: ${customFiles.length}`));
|
|
4437
4910
|
if (customFiles.length > 0 && options.verbose) {
|
|
4438
|
-
console.log(
|
|
4911
|
+
console.log(chalk17.gray("\n Custom files (will be preserved):"));
|
|
4439
4912
|
for (const file of customFiles.slice(0, MAX_VERBOSE_FILES)) {
|
|
4440
|
-
console.log(
|
|
4913
|
+
console.log(chalk17.gray(` - ${file}`));
|
|
4441
4914
|
}
|
|
4442
4915
|
if (customFiles.length > MAX_VERBOSE_FILES) {
|
|
4443
|
-
console.log(
|
|
4916
|
+
console.log(chalk17.gray(` ... and ${customFiles.length - MAX_VERBOSE_FILES} more`));
|
|
4444
4917
|
}
|
|
4445
4918
|
}
|
|
4446
4919
|
if (!options.force && !options.dryRun) {
|
|
4447
|
-
console.log(
|
|
4920
|
+
console.log(chalk17.yellow(`
|
|
4448
4921
|
This will overwrite ${filesToUpdate.length} core template files.`));
|
|
4449
|
-
console.log(
|
|
4922
|
+
console.log(chalk17.gray(" Run with --dry-run to preview changes, or --force to skip this prompt.\n"));
|
|
4450
4923
|
try {
|
|
4451
4924
|
const { confirm: confirm6 } = await import("@inquirer/prompts");
|
|
4452
4925
|
const confirmed = await confirm6({
|
|
@@ -4454,16 +4927,16 @@ async function syncAppCommand(options) {
|
|
|
4454
4927
|
default: true
|
|
4455
4928
|
});
|
|
4456
4929
|
if (!confirmed) {
|
|
4457
|
-
console.log(
|
|
4930
|
+
console.log(chalk17.yellow("\n Sync cancelled.\n"));
|
|
4458
4931
|
process.exit(0);
|
|
4459
4932
|
}
|
|
4460
4933
|
} catch (promptError) {
|
|
4461
|
-
console.error(
|
|
4934
|
+
console.error(chalk17.red("\n Failed to load confirmation prompt. Use --force to skip.\n"));
|
|
4462
4935
|
process.exit(1);
|
|
4463
4936
|
}
|
|
4464
4937
|
}
|
|
4465
4938
|
if (options.backup && !options.dryRun) {
|
|
4466
|
-
const backupDir =
|
|
4939
|
+
const backupDir = join12(projectRoot, `app.backup.v${coreVersion}.${Date.now()}`);
|
|
4467
4940
|
spinner.start("Creating backup...");
|
|
4468
4941
|
backupDirectory(appDir, backupDir);
|
|
4469
4942
|
spinner.succeed(`Backup created: ${relative(projectRoot, backupDir)}`);
|
|
@@ -4473,9 +4946,9 @@ async function syncAppCommand(options) {
|
|
|
4473
4946
|
let updated = 0;
|
|
4474
4947
|
let created = 0;
|
|
4475
4948
|
for (const file of filesToUpdate) {
|
|
4476
|
-
const sourcePath =
|
|
4477
|
-
const targetPath =
|
|
4478
|
-
const isNew = !
|
|
4949
|
+
const sourcePath = join12(templatesDir, file);
|
|
4950
|
+
const targetPath = join12(appDir, file);
|
|
4951
|
+
const isNew = !existsSync11(targetPath);
|
|
4479
4952
|
copyFile(sourcePath, targetPath);
|
|
4480
4953
|
if (isNew) {
|
|
4481
4954
|
created++;
|
|
@@ -4487,40 +4960,40 @@ async function syncAppCommand(options) {
|
|
|
4487
4960
|
}
|
|
4488
4961
|
}
|
|
4489
4962
|
spinner.succeed(`Synced ${filesToUpdate.length} files (${updated} updated, ${created} created)`);
|
|
4490
|
-
const rootTemplatesDir =
|
|
4963
|
+
const rootTemplatesDir = join12(coreDir, "templates");
|
|
4491
4964
|
let rootUpdated = 0;
|
|
4492
4965
|
let rootCreated = 0;
|
|
4493
4966
|
for (const file of ROOT_TEMPLATE_FILES) {
|
|
4494
|
-
const sourcePath =
|
|
4495
|
-
const targetPath =
|
|
4496
|
-
if (
|
|
4497
|
-
const isNew = !
|
|
4967
|
+
const sourcePath = join12(rootTemplatesDir, file);
|
|
4968
|
+
const targetPath = join12(projectRoot, file);
|
|
4969
|
+
if (existsSync11(sourcePath)) {
|
|
4970
|
+
const isNew = !existsSync11(targetPath);
|
|
4498
4971
|
copyFile(sourcePath, targetPath);
|
|
4499
4972
|
if (isNew) {
|
|
4500
4973
|
rootCreated++;
|
|
4501
4974
|
if (options.verbose) {
|
|
4502
|
-
console.log(
|
|
4975
|
+
console.log(chalk17.green(` + Created: ${file}`));
|
|
4503
4976
|
}
|
|
4504
4977
|
} else {
|
|
4505
4978
|
rootUpdated++;
|
|
4506
4979
|
if (options.verbose) {
|
|
4507
|
-
console.log(
|
|
4980
|
+
console.log(chalk17.yellow(` ~ Updated: ${file}`));
|
|
4508
4981
|
}
|
|
4509
4982
|
}
|
|
4510
4983
|
}
|
|
4511
4984
|
}
|
|
4512
4985
|
if (rootUpdated + rootCreated > 0) {
|
|
4513
|
-
console.log(
|
|
4986
|
+
console.log(chalk17.gray(` Root files: ${rootUpdated} updated, ${rootCreated} created`));
|
|
4514
4987
|
}
|
|
4515
4988
|
}
|
|
4516
|
-
console.log(
|
|
4989
|
+
console.log(chalk17.green("\n \u2705 Sync complete!\n"));
|
|
4517
4990
|
if (customFiles.length > 0) {
|
|
4518
|
-
console.log(
|
|
4991
|
+
console.log(chalk17.gray(` Preserved ${customFiles.length} custom file(s):`));
|
|
4519
4992
|
for (const file of customFiles.slice(0, MAX_SUMMARY_FILES)) {
|
|
4520
|
-
console.log(
|
|
4993
|
+
console.log(chalk17.gray(` - app/${file}`));
|
|
4521
4994
|
}
|
|
4522
4995
|
if (customFiles.length > MAX_SUMMARY_FILES) {
|
|
4523
|
-
console.log(
|
|
4996
|
+
console.log(chalk17.gray(` ... and ${customFiles.length - MAX_SUMMARY_FILES} more
|
|
4524
4997
|
`));
|
|
4525
4998
|
} else {
|
|
4526
4999
|
console.log();
|
|
@@ -4529,11 +5002,11 @@ async function syncAppCommand(options) {
|
|
|
4529
5002
|
} catch (error) {
|
|
4530
5003
|
spinner.fail("Sync failed");
|
|
4531
5004
|
if (error instanceof Error) {
|
|
4532
|
-
console.error(
|
|
5005
|
+
console.error(chalk17.red(`
|
|
4533
5006
|
Error: ${error.message}
|
|
4534
5007
|
`));
|
|
4535
5008
|
if (options.verbose && error.stack) {
|
|
4536
|
-
console.error(
|
|
5009
|
+
console.error(chalk17.gray(` Stack trace:
|
|
4537
5010
|
${error.stack}
|
|
4538
5011
|
`));
|
|
4539
5012
|
}
|
|
@@ -4543,39 +5016,39 @@ ${error.stack}
|
|
|
4543
5016
|
}
|
|
4544
5017
|
|
|
4545
5018
|
// src/commands/setup-ai.ts
|
|
4546
|
-
import { existsSync as
|
|
4547
|
-
import { join as
|
|
5019
|
+
import { existsSync as existsSync12 } from "fs";
|
|
5020
|
+
import { join as join13 } from "path";
|
|
4548
5021
|
import { execSync as execSync3 } from "child_process";
|
|
4549
|
-
import
|
|
4550
|
-
import
|
|
5022
|
+
import chalk18 from "chalk";
|
|
5023
|
+
import ora12 from "ora";
|
|
4551
5024
|
var VALID_EDITORS = ["claude", "cursor", "antigravity", "all"];
|
|
4552
5025
|
async function setupAICommand(options) {
|
|
4553
5026
|
const editor = options.editor || "claude";
|
|
4554
5027
|
if (!VALID_EDITORS.includes(editor)) {
|
|
4555
|
-
console.log(
|
|
4556
|
-
console.log(
|
|
5028
|
+
console.log(chalk18.red(` Unknown editor: ${editor}`));
|
|
5029
|
+
console.log(chalk18.gray(` Available: ${VALID_EDITORS.join(", ")}`));
|
|
4557
5030
|
process.exit(1);
|
|
4558
5031
|
}
|
|
4559
5032
|
console.log("");
|
|
4560
|
-
console.log(
|
|
4561
|
-
console.log(
|
|
5033
|
+
console.log(chalk18.cyan(" AI Workflow Setup"));
|
|
5034
|
+
console.log(chalk18.gray(" " + "-".repeat(40)));
|
|
4562
5035
|
console.log("");
|
|
4563
5036
|
const pkgPath = getAIWorkflowDir();
|
|
4564
5037
|
if (!pkgPath) {
|
|
4565
|
-
console.log(
|
|
5038
|
+
console.log(chalk18.red(" @nextsparkjs/ai-workflow package not found."));
|
|
4566
5039
|
console.log("");
|
|
4567
|
-
console.log(
|
|
4568
|
-
console.log(
|
|
5040
|
+
console.log(chalk18.gray(" Install it first:"));
|
|
5041
|
+
console.log(chalk18.cyan(" pnpm add -D -w @nextsparkjs/ai-workflow"));
|
|
4569
5042
|
console.log("");
|
|
4570
5043
|
process.exit(1);
|
|
4571
5044
|
}
|
|
4572
|
-
const setupScript =
|
|
4573
|
-
if (!
|
|
4574
|
-
console.log(
|
|
4575
|
-
console.log(
|
|
5045
|
+
const setupScript = join13(pkgPath, "scripts", "setup.mjs");
|
|
5046
|
+
if (!existsSync12(setupScript)) {
|
|
5047
|
+
console.log(chalk18.red(" Setup script not found in ai-workflow package."));
|
|
5048
|
+
console.log(chalk18.gray(` Expected: ${setupScript}`));
|
|
4576
5049
|
process.exit(1);
|
|
4577
5050
|
}
|
|
4578
|
-
const spinner =
|
|
5051
|
+
const spinner = ora12({
|
|
4579
5052
|
text: `Setting up AI workflow for ${editor}...`,
|
|
4580
5053
|
prefixText: " "
|
|
4581
5054
|
}).start();
|
|
@@ -4587,61 +5060,61 @@ async function setupAICommand(options) {
|
|
|
4587
5060
|
});
|
|
4588
5061
|
} catch (error) {
|
|
4589
5062
|
console.log("");
|
|
4590
|
-
console.log(
|
|
5063
|
+
console.log(chalk18.red(" AI workflow setup failed."));
|
|
4591
5064
|
if (error instanceof Error) {
|
|
4592
|
-
console.log(
|
|
5065
|
+
console.log(chalk18.gray(` ${error.message}`));
|
|
4593
5066
|
}
|
|
4594
5067
|
process.exit(1);
|
|
4595
5068
|
}
|
|
4596
5069
|
}
|
|
4597
5070
|
|
|
4598
5071
|
// src/commands/sync-ai.ts
|
|
4599
|
-
import { existsSync as
|
|
4600
|
-
import { join as
|
|
5072
|
+
import { existsSync as existsSync13 } from "fs";
|
|
5073
|
+
import { join as join14 } from "path";
|
|
4601
5074
|
import { execSync as execSync4 } from "child_process";
|
|
4602
|
-
import
|
|
4603
|
-
import
|
|
5075
|
+
import chalk19 from "chalk";
|
|
5076
|
+
import ora13 from "ora";
|
|
4604
5077
|
var VALID_EDITORS2 = ["claude", "cursor", "antigravity", "all"];
|
|
4605
5078
|
async function syncAICommand(options) {
|
|
4606
5079
|
const editor = options.editor || "claude";
|
|
4607
5080
|
if (!VALID_EDITORS2.includes(editor)) {
|
|
4608
|
-
console.log(
|
|
4609
|
-
console.log(
|
|
5081
|
+
console.log(chalk19.red(` Unknown editor: ${editor}`));
|
|
5082
|
+
console.log(chalk19.gray(` Available: ${VALID_EDITORS2.join(", ")}`));
|
|
4610
5083
|
process.exit(1);
|
|
4611
5084
|
}
|
|
4612
5085
|
console.log("");
|
|
4613
|
-
console.log(
|
|
4614
|
-
console.log(
|
|
5086
|
+
console.log(chalk19.cyan(" AI Workflow Sync"));
|
|
5087
|
+
console.log(chalk19.gray(" " + "-".repeat(40)));
|
|
4615
5088
|
console.log("");
|
|
4616
5089
|
const editorDir = editor === "cursor" ? ".cursor" : ".claude";
|
|
4617
|
-
const editorDirPath =
|
|
4618
|
-
if (!
|
|
4619
|
-
console.log(
|
|
5090
|
+
const editorDirPath = join14(process.cwd(), editorDir);
|
|
5091
|
+
if (!existsSync13(editorDirPath)) {
|
|
5092
|
+
console.log(chalk19.red(` No ${editorDir}/ directory found.`));
|
|
4620
5093
|
console.log("");
|
|
4621
|
-
console.log(
|
|
4622
|
-
console.log(
|
|
5094
|
+
console.log(chalk19.gray(" AI workflow must be set up first. Run:"));
|
|
5095
|
+
console.log(chalk19.cyan(" nextspark setup:ai --editor " + editor));
|
|
4623
5096
|
console.log("");
|
|
4624
5097
|
process.exit(1);
|
|
4625
5098
|
}
|
|
4626
5099
|
const pkgPath = getAIWorkflowDir();
|
|
4627
5100
|
if (!pkgPath) {
|
|
4628
|
-
console.log(
|
|
5101
|
+
console.log(chalk19.red(" @nextsparkjs/ai-workflow package not found."));
|
|
4629
5102
|
console.log("");
|
|
4630
|
-
console.log(
|
|
4631
|
-
console.log(
|
|
5103
|
+
console.log(chalk19.gray(" Install it first:"));
|
|
5104
|
+
console.log(chalk19.cyan(" pnpm add -D -w @nextsparkjs/ai-workflow"));
|
|
4632
5105
|
console.log("");
|
|
4633
5106
|
process.exit(1);
|
|
4634
5107
|
}
|
|
4635
|
-
const setupScript =
|
|
4636
|
-
if (!
|
|
4637
|
-
console.log(
|
|
4638
|
-
console.log(
|
|
5108
|
+
const setupScript = join14(pkgPath, "scripts", "setup.mjs");
|
|
5109
|
+
if (!existsSync13(setupScript)) {
|
|
5110
|
+
console.log(chalk19.red(" Setup script not found in ai-workflow package."));
|
|
5111
|
+
console.log(chalk19.gray(` Expected: ${setupScript}`));
|
|
4639
5112
|
process.exit(1);
|
|
4640
5113
|
}
|
|
4641
5114
|
if (!options.force) {
|
|
4642
|
-
console.log(
|
|
4643
|
-
console.log(
|
|
4644
|
-
console.log(
|
|
5115
|
+
console.log(chalk19.yellow(" This will sync AI workflow files from @nextsparkjs/ai-workflow."));
|
|
5116
|
+
console.log(chalk19.gray(" Framework files will be overwritten. Custom files will be preserved."));
|
|
5117
|
+
console.log(chalk19.gray(" Config JSON files will never be overwritten.\n"));
|
|
4645
5118
|
try {
|
|
4646
5119
|
const { confirm: confirm6 } = await import("@inquirer/prompts");
|
|
4647
5120
|
const confirmed = await confirm6({
|
|
@@ -4649,15 +5122,15 @@ async function syncAICommand(options) {
|
|
|
4649
5122
|
default: true
|
|
4650
5123
|
});
|
|
4651
5124
|
if (!confirmed) {
|
|
4652
|
-
console.log(
|
|
5125
|
+
console.log(chalk19.yellow("\n Sync cancelled.\n"));
|
|
4653
5126
|
process.exit(0);
|
|
4654
5127
|
}
|
|
4655
5128
|
} catch {
|
|
4656
|
-
console.error(
|
|
5129
|
+
console.error(chalk19.red("\n Failed to load confirmation prompt. Use --force to skip.\n"));
|
|
4657
5130
|
process.exit(1);
|
|
4658
5131
|
}
|
|
4659
5132
|
}
|
|
4660
|
-
const spinner =
|
|
5133
|
+
const spinner = ora13({
|
|
4661
5134
|
text: `Syncing AI workflow for ${editor}...`,
|
|
4662
5135
|
prefixText: " "
|
|
4663
5136
|
}).start();
|
|
@@ -4669,9 +5142,9 @@ async function syncAICommand(options) {
|
|
|
4669
5142
|
});
|
|
4670
5143
|
} catch (error) {
|
|
4671
5144
|
console.log("");
|
|
4672
|
-
console.log(
|
|
5145
|
+
console.log(chalk19.red(" AI workflow sync failed."));
|
|
4673
5146
|
if (error instanceof Error) {
|
|
4674
|
-
console.log(
|
|
5147
|
+
console.log(chalk19.gray(` ${error.message}`));
|
|
4675
5148
|
}
|
|
4676
5149
|
process.exit(1);
|
|
4677
5150
|
}
|
|
@@ -4679,7 +5152,7 @@ async function syncAICommand(options) {
|
|
|
4679
5152
|
|
|
4680
5153
|
// src/cli.ts
|
|
4681
5154
|
config();
|
|
4682
|
-
var pkg = JSON.parse(
|
|
5155
|
+
var pkg = JSON.parse(readFileSync11(new URL("../package.json", import.meta.url), "utf-8"));
|
|
4683
5156
|
var program = new Command();
|
|
4684
5157
|
program.name("nextspark").description("NextSpark CLI - Professional SaaS Boilerplate").version(pkg.version);
|
|
4685
5158
|
program.command("dev").description("Start development server with registry watcher").option("-p, --port <port>", "Port to run the dev server on", process.env.PORT || "3000").option("--no-registry", "Disable registry watcher").action(devCommand);
|
|
@@ -4705,7 +5178,6 @@ program.command("setup:ai").description("Setup AI workflow for your editor (Clau
|
|
|
4705
5178
|
program.command("sync:ai").description("Sync AI workflow files from @nextsparkjs/ai-workflow").option("-e, --editor <editor>", "Editor to sync (claude, cursor, antigravity, all)", "claude").option("-f, --force", "Skip confirmation prompt").action(syncAICommand);
|
|
4706
5179
|
program.showHelpAfterError();
|
|
4707
5180
|
program.configureOutput({
|
|
4708
|
-
writeErr: (str) => process.stderr.write(
|
|
5181
|
+
writeErr: (str) => process.stderr.write(chalk20.red(str))
|
|
4709
5182
|
});
|
|
4710
5183
|
program.parse();
|
|
4711
|
-
//# sourceMappingURL=cli.js.map
|