@nextsparkjs/cli 0.1.0-beta.87 → 0.1.0-beta.89
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/cli.js +208 -118
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
// src/cli.ts
|
|
13
13
|
import { config } from "dotenv";
|
|
14
14
|
import { Command } from "commander";
|
|
15
|
-
import
|
|
15
|
+
import chalk20 from "chalk";
|
|
16
16
|
import { readFileSync as readFileSync11 } from "fs";
|
|
17
17
|
|
|
18
18
|
// src/commands/dev.ts
|
|
@@ -22,7 +22,7 @@ import ora from "ora";
|
|
|
22
22
|
|
|
23
23
|
// src/utils/paths.ts
|
|
24
24
|
import { existsSync } from "fs";
|
|
25
|
-
import { resolve, dirname } from "path";
|
|
25
|
+
import { resolve, join, dirname } from "path";
|
|
26
26
|
import { fileURLToPath } from "url";
|
|
27
27
|
var __filename = fileURLToPath(import.meta.url);
|
|
28
28
|
var __dirname = dirname(__filename);
|
|
@@ -52,6 +52,16 @@ function isMonorepoMode() {
|
|
|
52
52
|
const npmCorePath = resolve(cwd, "node_modules", "@nextsparkjs", "core");
|
|
53
53
|
return !existsSync(npmCorePath);
|
|
54
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
|
+
}
|
|
55
65
|
|
|
56
66
|
// src/commands/dev.ts
|
|
57
67
|
async function devCommand(options) {
|
|
@@ -120,11 +130,11 @@ async function devCommand(options) {
|
|
|
120
130
|
// src/commands/build.ts
|
|
121
131
|
import { spawn as spawn2 } from "child_process";
|
|
122
132
|
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
123
|
-
import { join } from "path";
|
|
133
|
+
import { join as join2 } from "path";
|
|
124
134
|
import chalk2 from "chalk";
|
|
125
135
|
import ora2 from "ora";
|
|
126
136
|
function loadProjectEnv(projectRoot) {
|
|
127
|
-
const envPath =
|
|
137
|
+
const envPath = join2(projectRoot, ".env");
|
|
128
138
|
const envVars = {};
|
|
129
139
|
if (existsSync2(envPath)) {
|
|
130
140
|
const content = readFileSync(envPath, "utf-8");
|
|
@@ -217,11 +227,11 @@ Build failed with exit code ${code}`));
|
|
|
217
227
|
// src/commands/generate.ts
|
|
218
228
|
import { spawn as spawn3 } from "child_process";
|
|
219
229
|
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
220
|
-
import { join as
|
|
230
|
+
import { join as join3 } from "path";
|
|
221
231
|
import chalk3 from "chalk";
|
|
222
232
|
import ora3 from "ora";
|
|
223
233
|
function loadProjectEnv2(projectRoot) {
|
|
224
|
-
const envPath =
|
|
234
|
+
const envPath = join3(projectRoot, ".env");
|
|
225
235
|
const envVars = {};
|
|
226
236
|
if (existsSync3(envPath)) {
|
|
227
237
|
const content = readFileSync2(envPath, "utf-8");
|
|
@@ -301,11 +311,11 @@ Registry generation failed with exit code ${code}`));
|
|
|
301
311
|
// src/commands/registry.ts
|
|
302
312
|
import { spawn as spawn4 } from "child_process";
|
|
303
313
|
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
|
|
304
|
-
import { join as
|
|
314
|
+
import { join as join4 } from "path";
|
|
305
315
|
import chalk4 from "chalk";
|
|
306
316
|
import ora4 from "ora";
|
|
307
317
|
function loadProjectEnv3(projectRoot) {
|
|
308
|
-
const envPath =
|
|
318
|
+
const envPath = join4(projectRoot, ".env");
|
|
309
319
|
const envVars = {};
|
|
310
320
|
if (existsSync4(envPath)) {
|
|
311
321
|
const content = readFileSync3(envPath, "utf-8");
|
|
@@ -427,7 +437,7 @@ Watcher exited with code ${code}`));
|
|
|
427
437
|
|
|
428
438
|
// src/commands/init.ts
|
|
429
439
|
import { existsSync as existsSync8, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync7 } from "fs";
|
|
430
|
-
import { join as
|
|
440
|
+
import { join as join9 } from "path";
|
|
431
441
|
import chalk12 from "chalk";
|
|
432
442
|
import ora8 from "ora";
|
|
433
443
|
|
|
@@ -437,22 +447,22 @@ import ora7 from "ora";
|
|
|
437
447
|
import { confirm as confirm5, select as select6 } from "@inquirer/prompts";
|
|
438
448
|
import { execSync } from "child_process";
|
|
439
449
|
import { existsSync as existsSync7, readdirSync } from "fs";
|
|
440
|
-
import { join as
|
|
450
|
+
import { join as join8 } from "path";
|
|
441
451
|
|
|
442
452
|
// src/wizard/banner.ts
|
|
443
453
|
import chalk5 from "chalk";
|
|
444
454
|
import { readFileSync as readFileSync4 } from "fs";
|
|
445
455
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
446
|
-
import { dirname as dirname2, join as
|
|
456
|
+
import { dirname as dirname2, join as join5 } from "path";
|
|
447
457
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
448
458
|
var __dirname2 = dirname2(__filename2);
|
|
449
459
|
function getCliVersion() {
|
|
450
460
|
const possiblePaths = [
|
|
451
|
-
|
|
461
|
+
join5(__dirname2, "../package.json"),
|
|
452
462
|
// from dist/
|
|
453
|
-
|
|
463
|
+
join5(__dirname2, "../../package.json"),
|
|
454
464
|
// from dist/wizard/ or src/wizard/
|
|
455
|
-
|
|
465
|
+
join5(__dirname2, "../../../package.json")
|
|
456
466
|
// fallback
|
|
457
467
|
];
|
|
458
468
|
for (const packageJsonPath of possiblePaths) {
|
|
@@ -2019,7 +2029,7 @@ async function copyContentFeatures(config2) {
|
|
|
2019
2029
|
|
|
2020
2030
|
// src/wizard/generators/theme-plugins-installer.ts
|
|
2021
2031
|
import { existsSync as existsSync6, cpSync, mkdirSync, readFileSync as readFileSync6, writeFileSync } from "fs";
|
|
2022
|
-
import { join as
|
|
2032
|
+
import { join as join7, resolve as resolve2 } from "path";
|
|
2023
2033
|
import chalk9 from "chalk";
|
|
2024
2034
|
import ora6 from "ora";
|
|
2025
2035
|
|
|
@@ -2027,12 +2037,12 @@ import ora6 from "ora";
|
|
|
2027
2037
|
import chalk8 from "chalk";
|
|
2028
2038
|
import ora5 from "ora";
|
|
2029
2039
|
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
2030
|
-
import { join as
|
|
2040
|
+
import { join as join6 } from "path";
|
|
2031
2041
|
async function addTheme(packageSpec, options = {}) {
|
|
2032
2042
|
const spinner = ora5(`Adding theme ${packageSpec}`).start();
|
|
2033
2043
|
let cleanup = null;
|
|
2034
2044
|
try {
|
|
2035
|
-
const contentsDir =
|
|
2045
|
+
const contentsDir = join6(process.cwd(), "contents");
|
|
2036
2046
|
if (!existsSync5(contentsDir)) {
|
|
2037
2047
|
spinner.fail('contents/ directory not found. Run "nextspark init" first.');
|
|
2038
2048
|
return;
|
|
@@ -2095,10 +2105,10 @@ async function addTheme(packageSpec, options = {}) {
|
|
|
2095
2105
|
}
|
|
2096
2106
|
function checkPluginExists(pluginName) {
|
|
2097
2107
|
const name = pluginName.replace(/^@[^/]+\//, "").replace(/^nextspark-plugin-/, "").replace(/^plugin-/, "");
|
|
2098
|
-
return existsSync5(
|
|
2108
|
+
return existsSync5(join6(process.cwd(), "contents", "plugins", name));
|
|
2099
2109
|
}
|
|
2100
2110
|
function getCoreVersion() {
|
|
2101
|
-
const pkgPath =
|
|
2111
|
+
const pkgPath = join6(process.cwd(), "node_modules", "@nextsparkjs", "core", "package.json");
|
|
2102
2112
|
if (existsSync5(pkgPath)) {
|
|
2103
2113
|
try {
|
|
2104
2114
|
const pkg2 = JSON.parse(readFileSync5(pkgPath, "utf-8"));
|
|
@@ -2139,20 +2149,20 @@ var THEME_REQUIRED_PLUGINS2 = {
|
|
|
2139
2149
|
};
|
|
2140
2150
|
function isMonorepoMode2() {
|
|
2141
2151
|
const possiblePaths = [
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2152
|
+
join7(process.cwd(), "pnpm-workspace.yaml"),
|
|
2153
|
+
join7(process.cwd(), "..", "pnpm-workspace.yaml"),
|
|
2154
|
+
join7(process.cwd(), "..", "..", "pnpm-workspace.yaml")
|
|
2145
2155
|
];
|
|
2146
2156
|
return possiblePaths.some((p) => existsSync6(p));
|
|
2147
2157
|
}
|
|
2148
2158
|
function getMonorepoRoot() {
|
|
2149
2159
|
const possibleRoots = [
|
|
2150
2160
|
process.cwd(),
|
|
2151
|
-
|
|
2152
|
-
|
|
2161
|
+
join7(process.cwd(), ".."),
|
|
2162
|
+
join7(process.cwd(), "..", "..")
|
|
2153
2163
|
];
|
|
2154
2164
|
for (const root of possibleRoots) {
|
|
2155
|
-
if (existsSync6(
|
|
2165
|
+
if (existsSync6(join7(root, "pnpm-workspace.yaml"))) {
|
|
2156
2166
|
return resolve2(root);
|
|
2157
2167
|
}
|
|
2158
2168
|
}
|
|
@@ -2162,15 +2172,15 @@ function getLocalPackageDir(type, name) {
|
|
|
2162
2172
|
const monorepoRoot = getMonorepoRoot();
|
|
2163
2173
|
if (!monorepoRoot) return null;
|
|
2164
2174
|
const baseDir = type === "theme" ? "themes" : "plugins";
|
|
2165
|
-
const packageDir =
|
|
2166
|
-
if (existsSync6(packageDir) && existsSync6(
|
|
2175
|
+
const packageDir = join7(monorepoRoot, baseDir, name);
|
|
2176
|
+
if (existsSync6(packageDir) && existsSync6(join7(packageDir, "package.json"))) {
|
|
2167
2177
|
return packageDir;
|
|
2168
2178
|
}
|
|
2169
2179
|
return null;
|
|
2170
2180
|
}
|
|
2171
2181
|
async function copyLocalTheme(name, sourceDir) {
|
|
2172
|
-
const targetDir =
|
|
2173
|
-
const themesDir =
|
|
2182
|
+
const targetDir = join7(process.cwd(), "contents", "themes", name);
|
|
2183
|
+
const themesDir = join7(process.cwd(), "contents", "themes");
|
|
2174
2184
|
if (!existsSync6(themesDir)) {
|
|
2175
2185
|
mkdirSync(themesDir, { recursive: true });
|
|
2176
2186
|
}
|
|
@@ -2183,8 +2193,8 @@ async function copyLocalTheme(name, sourceDir) {
|
|
|
2183
2193
|
return true;
|
|
2184
2194
|
}
|
|
2185
2195
|
async function copyLocalPlugin(name, sourceDir) {
|
|
2186
|
-
const targetDir =
|
|
2187
|
-
const pluginsDir =
|
|
2196
|
+
const targetDir = join7(process.cwd(), "contents", "plugins", name);
|
|
2197
|
+
const pluginsDir = join7(process.cwd(), "contents", "plugins");
|
|
2188
2198
|
if (!existsSync6(pluginsDir)) {
|
|
2189
2199
|
mkdirSync(pluginsDir, { recursive: true });
|
|
2190
2200
|
}
|
|
@@ -2197,7 +2207,7 @@ async function copyLocalPlugin(name, sourceDir) {
|
|
|
2197
2207
|
return true;
|
|
2198
2208
|
}
|
|
2199
2209
|
async function updateTsConfigPaths(name, type) {
|
|
2200
|
-
const tsconfigPath =
|
|
2210
|
+
const tsconfigPath = join7(process.cwd(), "tsconfig.json");
|
|
2201
2211
|
if (!existsSync6(tsconfigPath)) {
|
|
2202
2212
|
return;
|
|
2203
2213
|
}
|
|
@@ -2242,7 +2252,7 @@ async function installTheme2(theme) {
|
|
|
2242
2252
|
prefixText: " "
|
|
2243
2253
|
}).start();
|
|
2244
2254
|
try {
|
|
2245
|
-
const targetDir =
|
|
2255
|
+
const targetDir = join7(process.cwd(), "contents", "themes", theme);
|
|
2246
2256
|
if (existsSync6(targetDir)) {
|
|
2247
2257
|
spinner.info(chalk9.gray(`Reference theme ${theme} already exists`));
|
|
2248
2258
|
return true;
|
|
@@ -2295,7 +2305,7 @@ async function installPlugins(plugins) {
|
|
|
2295
2305
|
prefixText: " "
|
|
2296
2306
|
}).start();
|
|
2297
2307
|
try {
|
|
2298
|
-
const pluginDir =
|
|
2308
|
+
const pluginDir = join7(process.cwd(), "contents", "plugins", plugin);
|
|
2299
2309
|
if (existsSync6(pluginDir)) {
|
|
2300
2310
|
spinner.info(chalk9.gray(`Plugin ${plugin} already installed`));
|
|
2301
2311
|
continue;
|
|
@@ -3116,6 +3126,7 @@ async function generateProject(config2) {
|
|
|
3116
3126
|
await copyProjectFiles();
|
|
3117
3127
|
await updateGlobalsCss(config2);
|
|
3118
3128
|
await copyStarterTheme(config2);
|
|
3129
|
+
await fs8.ensureDir(path7.join(process.cwd(), "contents", "plugins"));
|
|
3119
3130
|
await copyContentFeatures(config2);
|
|
3120
3131
|
await updateThemeConfig(config2);
|
|
3121
3132
|
await updateDevConfig(config2);
|
|
@@ -3572,7 +3583,7 @@ async function runWizard(options = { mode: "interactive" }) {
|
|
|
3572
3583
|
prefixText: " "
|
|
3573
3584
|
}).start();
|
|
3574
3585
|
try {
|
|
3575
|
-
const registryScript =
|
|
3586
|
+
const registryScript = join8(webDir, "node_modules/@nextsparkjs/core/scripts/build/registry.mjs");
|
|
3576
3587
|
registrySpinner.stop();
|
|
3577
3588
|
execSync(`node "${registryScript}" --build`, {
|
|
3578
3589
|
cwd: webDir,
|
|
@@ -3589,8 +3600,8 @@ async function runWizard(options = { mode: "interactive" }) {
|
|
|
3589
3600
|
const devCmd = isMonorepo ? "pnpm dev" : "pnpm dev";
|
|
3590
3601
|
console.log(chalk11.yellow(` Registries will be built automatically when you run "${devCmd}"`));
|
|
3591
3602
|
}
|
|
3592
|
-
await promptAIWorkflowSetup(config2);
|
|
3593
|
-
showNextSteps(config2, selectedTheme);
|
|
3603
|
+
const aiChoice = await promptAIWorkflowSetup(config2);
|
|
3604
|
+
showNextSteps(config2, selectedTheme, aiChoice);
|
|
3594
3605
|
} catch (error) {
|
|
3595
3606
|
if (error instanceof Error) {
|
|
3596
3607
|
if (error.message.includes("User force closed")) {
|
|
@@ -3697,8 +3708,9 @@ function formatDevTool(tool) {
|
|
|
3697
3708
|
};
|
|
3698
3709
|
return mapping[tool] || tool;
|
|
3699
3710
|
}
|
|
3700
|
-
function showNextSteps(config2, referenceTheme = null) {
|
|
3711
|
+
function showNextSteps(config2, referenceTheme = null, aiChoice = "skip") {
|
|
3701
3712
|
const isMonorepo = config2.projectType === "web-mobile";
|
|
3713
|
+
const aiSetupDone = aiChoice === "claude";
|
|
3702
3714
|
console.log("");
|
|
3703
3715
|
console.log(chalk11.cyan(" " + "=".repeat(60)));
|
|
3704
3716
|
console.log(chalk11.bold.green(" \u2728 NextSpark project ready!"));
|
|
@@ -3707,12 +3719,12 @@ function showNextSteps(config2, referenceTheme = null) {
|
|
|
3707
3719
|
console.log(chalk11.bold.white(" Next steps:"));
|
|
3708
3720
|
console.log("");
|
|
3709
3721
|
const envPath = isMonorepo ? "web/.env" : ".env";
|
|
3710
|
-
console.log(chalk11.white(" 1. Configure your
|
|
3711
|
-
console.log(chalk11.gray(` Edit
|
|
3722
|
+
console.log(chalk11.white(" 1. Configure your environment:"));
|
|
3723
|
+
console.log(chalk11.gray(` Edit ${envPath} with your credentials:`));
|
|
3712
3724
|
console.log("");
|
|
3713
3725
|
console.log(chalk11.yellow(" DATABASE_URL"));
|
|
3714
3726
|
console.log(chalk11.gray(" PostgreSQL connection string"));
|
|
3715
|
-
console.log(chalk11.
|
|
3727
|
+
console.log(chalk11.gray(` Recommended: ${chalk11.cyan("https://supabase.com")} | ${chalk11.cyan("https://neon.com")}`));
|
|
3716
3728
|
console.log("");
|
|
3717
3729
|
console.log(chalk11.yellow(" BETTER_AUTH_SECRET"));
|
|
3718
3730
|
console.log(chalk11.gray(" Generate with:"));
|
|
@@ -3724,11 +3736,23 @@ function showNextSteps(config2, referenceTheme = null) {
|
|
|
3724
3736
|
console.log(chalk11.white(" 3. Start the development server:"));
|
|
3725
3737
|
console.log(chalk11.cyan(" pnpm dev"));
|
|
3726
3738
|
console.log("");
|
|
3739
|
+
let nextStep = 4;
|
|
3727
3740
|
if (isMonorepo) {
|
|
3728
|
-
console.log(chalk11.white(
|
|
3741
|
+
console.log(chalk11.white(` ${nextStep}. (Optional) Start the mobile app:`));
|
|
3729
3742
|
console.log(chalk11.cyan(" pnpm dev:mobile"));
|
|
3730
3743
|
console.log(chalk11.gray(" Or: cd mobile && pnpm start"));
|
|
3731
3744
|
console.log("");
|
|
3745
|
+
nextStep++;
|
|
3746
|
+
}
|
|
3747
|
+
if (aiSetupDone) {
|
|
3748
|
+
console.log(chalk11.white(` ${nextStep}. Start building with AI:`));
|
|
3749
|
+
console.log(chalk11.gray(" Open Claude Code in your project and run:"));
|
|
3750
|
+
console.log(chalk11.cyan(" /how-to:start"));
|
|
3751
|
+
console.log("");
|
|
3752
|
+
} else {
|
|
3753
|
+
console.log(chalk11.white(` ${nextStep}. (Optional) Setup AI workflows:`));
|
|
3754
|
+
console.log(chalk11.cyan(" nextspark setup:ai"));
|
|
3755
|
+
console.log("");
|
|
3732
3756
|
}
|
|
3733
3757
|
console.log(chalk11.gray(" " + "-".repeat(60)));
|
|
3734
3758
|
if (isMonorepo) {
|
|
@@ -3744,18 +3768,10 @@ function showNextSteps(config2, referenceTheme = null) {
|
|
|
3744
3768
|
const refPath = isMonorepo ? `web/contents/themes/${referenceTheme}/` : `contents/themes/${referenceTheme}/`;
|
|
3745
3769
|
console.log(chalk11.gray(` Reference: ${chalk11.white(refPath)}`));
|
|
3746
3770
|
}
|
|
3747
|
-
console.log("");
|
|
3748
|
-
console.log(chalk11.white(` ${isMonorepo ? "5" : "4"}. (Optional) Setup AI workflows:`));
|
|
3749
|
-
console.log(chalk11.cyan(" nextspark setup:ai"));
|
|
3750
|
-
console.log("");
|
|
3751
|
-
console.log(chalk11.gray(" Docs: https://nextspark.dev/docs"));
|
|
3771
|
+
console.log(chalk11.gray(` Docs: ${chalk11.cyan("https://nextspark.dev/docs")}`));
|
|
3752
3772
|
console.log("");
|
|
3753
3773
|
}
|
|
3754
3774
|
async function promptAIWorkflowSetup(config2) {
|
|
3755
|
-
console.log("");
|
|
3756
|
-
console.log(chalk11.cyan(" " + "=".repeat(60)));
|
|
3757
|
-
console.log(chalk11.bold.white(" AI Workflow Setup (Optional)"));
|
|
3758
|
-
console.log(chalk11.cyan(" " + "=".repeat(60)));
|
|
3759
3775
|
console.log("");
|
|
3760
3776
|
const choice = await select6({
|
|
3761
3777
|
message: "Setup AI-assisted development workflows?",
|
|
@@ -3767,12 +3783,11 @@ async function promptAIWorkflowSetup(config2) {
|
|
|
3767
3783
|
]
|
|
3768
3784
|
});
|
|
3769
3785
|
if (choice === "skip") {
|
|
3770
|
-
|
|
3771
|
-
return;
|
|
3786
|
+
return "skip";
|
|
3772
3787
|
}
|
|
3773
3788
|
if (choice === "cursor" || choice === "antigravity") {
|
|
3774
3789
|
showInfo(`${choice} support is coming soon. For now, use Claude Code.`);
|
|
3775
|
-
return;
|
|
3790
|
+
return "skip";
|
|
3776
3791
|
}
|
|
3777
3792
|
const projectRoot = process.cwd();
|
|
3778
3793
|
const isMonorepo = isMonorepoProject(config2);
|
|
@@ -3781,9 +3796,9 @@ async function promptAIWorkflowSetup(config2) {
|
|
|
3781
3796
|
cwd: projectRoot,
|
|
3782
3797
|
stdio: "inherit"
|
|
3783
3798
|
});
|
|
3784
|
-
let setupScript =
|
|
3799
|
+
let setupScript = join8(projectRoot, "node_modules", "@nextsparkjs", "ai-workflow", "scripts", "setup.mjs");
|
|
3785
3800
|
if (!existsSync7(setupScript) && isMonorepo) {
|
|
3786
|
-
setupScript =
|
|
3801
|
+
setupScript = join8(projectRoot, "web", "node_modules", "@nextsparkjs", "ai-workflow", "scripts", "setup.mjs");
|
|
3787
3802
|
}
|
|
3788
3803
|
if (existsSync7(setupScript)) {
|
|
3789
3804
|
execSync(`node "${setupScript}" ${choice}`, {
|
|
@@ -3796,7 +3811,9 @@ async function promptAIWorkflowSetup(config2) {
|
|
|
3796
3811
|
}
|
|
3797
3812
|
} catch (error) {
|
|
3798
3813
|
showError('Failed to install AI workflow package. Run "nextspark setup:ai" later.');
|
|
3814
|
+
return "skip";
|
|
3799
3815
|
}
|
|
3816
|
+
return choice;
|
|
3800
3817
|
}
|
|
3801
3818
|
function findLocalCoreTarball() {
|
|
3802
3819
|
const cwd = process.cwd();
|
|
@@ -3806,14 +3823,14 @@ function findLocalCoreTarball() {
|
|
|
3806
3823
|
(f) => f.includes("nextsparkjs-core") && f.endsWith(".tgz")
|
|
3807
3824
|
);
|
|
3808
3825
|
if (coreTarball) {
|
|
3809
|
-
return
|
|
3826
|
+
return join8(cwd, coreTarball);
|
|
3810
3827
|
}
|
|
3811
3828
|
} catch {
|
|
3812
3829
|
}
|
|
3813
3830
|
return null;
|
|
3814
3831
|
}
|
|
3815
3832
|
function isCoreInstalled() {
|
|
3816
|
-
const corePath =
|
|
3833
|
+
const corePath = join8(process.cwd(), "node_modules", "@nextsparkjs", "core");
|
|
3817
3834
|
return existsSync7(corePath);
|
|
3818
3835
|
}
|
|
3819
3836
|
async function installCore() {
|
|
@@ -3831,8 +3848,8 @@ async function installCore() {
|
|
|
3831
3848
|
packageSpec = localTarball;
|
|
3832
3849
|
spinner.text = "Installing @nextsparkjs/core from local tarball...";
|
|
3833
3850
|
}
|
|
3834
|
-
const useYarn = existsSync7(
|
|
3835
|
-
const usePnpm = existsSync7(
|
|
3851
|
+
const useYarn = existsSync7(join8(process.cwd(), "yarn.lock"));
|
|
3852
|
+
const usePnpm = existsSync7(join8(process.cwd(), "pnpm-lock.yaml"));
|
|
3836
3853
|
let installCmd;
|
|
3837
3854
|
if (usePnpm) {
|
|
3838
3855
|
installCmd = `pnpm add ${packageSpec}`;
|
|
@@ -3858,7 +3875,7 @@ async function installCore() {
|
|
|
3858
3875
|
}
|
|
3859
3876
|
}
|
|
3860
3877
|
function isMobileInstalled() {
|
|
3861
|
-
const mobilePath =
|
|
3878
|
+
const mobilePath = join8(process.cwd(), "node_modules", "@nextsparkjs", "mobile");
|
|
3862
3879
|
return existsSync7(mobilePath);
|
|
3863
3880
|
}
|
|
3864
3881
|
function findLocalMobileTarball() {
|
|
@@ -3869,7 +3886,7 @@ function findLocalMobileTarball() {
|
|
|
3869
3886
|
(f) => f.includes("nextsparkjs-mobile") && f.endsWith(".tgz")
|
|
3870
3887
|
);
|
|
3871
3888
|
if (mobileTarball) {
|
|
3872
|
-
return
|
|
3889
|
+
return join8(cwd, mobileTarball);
|
|
3873
3890
|
}
|
|
3874
3891
|
} catch {
|
|
3875
3892
|
}
|
|
@@ -3890,8 +3907,8 @@ async function installMobile() {
|
|
|
3890
3907
|
packageSpec = localTarball;
|
|
3891
3908
|
spinner.text = "Installing @nextsparkjs/mobile from local tarball...";
|
|
3892
3909
|
}
|
|
3893
|
-
const useYarn = existsSync7(
|
|
3894
|
-
const usePnpm = existsSync7(
|
|
3910
|
+
const useYarn = existsSync7(join8(process.cwd(), "yarn.lock"));
|
|
3911
|
+
const usePnpm = existsSync7(join8(process.cwd(), "pnpm-lock.yaml"));
|
|
3895
3912
|
let installCmd;
|
|
3896
3913
|
if (usePnpm) {
|
|
3897
3914
|
installCmd = `pnpm add ${packageSpec}`;
|
|
@@ -3929,10 +3946,10 @@ function parsePlugins(pluginsStr) {
|
|
|
3929
3946
|
}
|
|
3930
3947
|
function hasExistingProject() {
|
|
3931
3948
|
const projectRoot = process.cwd();
|
|
3932
|
-
return existsSync8(
|
|
3949
|
+
return existsSync8(join9(projectRoot, "contents")) || existsSync8(join9(projectRoot, ".nextspark"));
|
|
3933
3950
|
}
|
|
3934
3951
|
function generateInitialRegistries(registriesDir) {
|
|
3935
|
-
writeFileSync2(
|
|
3952
|
+
writeFileSync2(join9(registriesDir, "block-registry.ts"), `// Auto-generated by nextspark init
|
|
3936
3953
|
import type { ComponentType } from 'react'
|
|
3937
3954
|
|
|
3938
3955
|
export const BLOCK_REGISTRY: Record<string, {
|
|
@@ -3945,26 +3962,26 @@ export const BLOCK_REGISTRY: Record<string, {
|
|
|
3945
3962
|
|
|
3946
3963
|
export const BLOCK_COMPONENTS: Record<string, React.LazyExoticComponent<ComponentType<any>>> = {}
|
|
3947
3964
|
`);
|
|
3948
|
-
writeFileSync2(
|
|
3965
|
+
writeFileSync2(join9(registriesDir, "theme-registry.ts"), `// Auto-generated by nextspark init
|
|
3949
3966
|
export const THEME_REGISTRY: Record<string, unknown> = {}
|
|
3950
3967
|
`);
|
|
3951
|
-
writeFileSync2(
|
|
3968
|
+
writeFileSync2(join9(registriesDir, "entity-registry.ts"), `// Auto-generated by nextspark init
|
|
3952
3969
|
export const ENTITY_REGISTRY: Record<string, unknown> = {}
|
|
3953
3970
|
`);
|
|
3954
|
-
writeFileSync2(
|
|
3971
|
+
writeFileSync2(join9(registriesDir, "entity-registry.client.ts"), `// Auto-generated by nextspark init
|
|
3955
3972
|
export const CLIENT_ENTITY_REGISTRY: Record<string, unknown> = {}
|
|
3956
3973
|
export function parseChildEntity(path: string) { return null }
|
|
3957
3974
|
export function getEntityApiPath(entity: string) { return \`/api/\${entity}\` }
|
|
3958
3975
|
export function clientMetaSystemAdapter() { return {} }
|
|
3959
3976
|
export type ClientEntityConfig = Record<string, unknown>
|
|
3960
3977
|
`);
|
|
3961
|
-
writeFileSync2(
|
|
3978
|
+
writeFileSync2(join9(registriesDir, "billing-registry.ts"), `// Auto-generated by nextspark init
|
|
3962
3979
|
export const BILLING_REGISTRY = { plans: [], features: [] }
|
|
3963
3980
|
`);
|
|
3964
|
-
writeFileSync2(
|
|
3981
|
+
writeFileSync2(join9(registriesDir, "plugin-registry.ts"), `// Auto-generated by nextspark init
|
|
3965
3982
|
export const PLUGIN_REGISTRY: Record<string, unknown> = {}
|
|
3966
3983
|
`);
|
|
3967
|
-
writeFileSync2(
|
|
3984
|
+
writeFileSync2(join9(registriesDir, "testing-registry.ts"), `// Auto-generated by nextspark init
|
|
3968
3985
|
export const FLOW_REGISTRY: Record<string, unknown> = {}
|
|
3969
3986
|
export const FEATURE_REGISTRY: Record<string, unknown> = {}
|
|
3970
3987
|
export const TAGS_REGISTRY: Record<string, unknown> = {}
|
|
@@ -3972,11 +3989,11 @@ export const COVERAGE_SUMMARY = { total: 0, covered: 0 }
|
|
|
3972
3989
|
export type FlowEntry = unknown
|
|
3973
3990
|
export type FeatureEntry = unknown
|
|
3974
3991
|
`);
|
|
3975
|
-
writeFileSync2(
|
|
3992
|
+
writeFileSync2(join9(registriesDir, "docs-registry.ts"), `// Auto-generated by nextspark init
|
|
3976
3993
|
export const DOCS_REGISTRY = { sections: [], pages: [] }
|
|
3977
3994
|
export type DocSectionMeta = { title: string; slug: string }
|
|
3978
3995
|
`);
|
|
3979
|
-
writeFileSync2(
|
|
3996
|
+
writeFileSync2(join9(registriesDir, "index.ts"), `// Auto-generated by nextspark init
|
|
3980
3997
|
export * from './block-registry'
|
|
3981
3998
|
export * from './theme-registry'
|
|
3982
3999
|
export * from './entity-registry'
|
|
@@ -3991,15 +4008,15 @@ async function simpleInit(options) {
|
|
|
3991
4008
|
const spinner = ora8("Initializing NextSpark project...").start();
|
|
3992
4009
|
const projectRoot = process.cwd();
|
|
3993
4010
|
try {
|
|
3994
|
-
const nextspark =
|
|
3995
|
-
const registriesDir =
|
|
4011
|
+
const nextspark = join9(projectRoot, ".nextspark");
|
|
4012
|
+
const registriesDir = join9(nextspark, "registries");
|
|
3996
4013
|
if (!existsSync8(registriesDir) || options.force) {
|
|
3997
4014
|
mkdirSync2(registriesDir, { recursive: true });
|
|
3998
4015
|
spinner.text = "Creating .nextspark/registries/";
|
|
3999
4016
|
generateInitialRegistries(registriesDir);
|
|
4000
4017
|
spinner.text = "Generated initial registries";
|
|
4001
4018
|
}
|
|
4002
|
-
const tsconfigPath =
|
|
4019
|
+
const tsconfigPath = join9(projectRoot, "tsconfig.json");
|
|
4003
4020
|
if (existsSync8(tsconfigPath)) {
|
|
4004
4021
|
spinner.text = "Updating tsconfig.json paths...";
|
|
4005
4022
|
const tsconfig = JSON.parse(readFileSync7(tsconfigPath, "utf-8"));
|
|
@@ -4011,7 +4028,7 @@ async function simpleInit(options) {
|
|
|
4011
4028
|
};
|
|
4012
4029
|
writeFileSync2(tsconfigPath, JSON.stringify(tsconfig, null, 2));
|
|
4013
4030
|
}
|
|
4014
|
-
const envExample =
|
|
4031
|
+
const envExample = join9(projectRoot, ".env.example");
|
|
4015
4032
|
if (!existsSync8(envExample)) {
|
|
4016
4033
|
const envContent = `# NextSpark Configuration
|
|
4017
4034
|
DATABASE_URL="postgresql://user:password@localhost:5432/db"
|
|
@@ -4062,21 +4079,21 @@ async function initCommand(options) {
|
|
|
4062
4079
|
|
|
4063
4080
|
// src/commands/add-mobile.ts
|
|
4064
4081
|
import { existsSync as existsSync9, cpSync as cpSync2, readFileSync as readFileSync8, writeFileSync as writeFileSync3, renameSync, mkdirSync as mkdirSync3 } from "fs";
|
|
4065
|
-
import { join as
|
|
4082
|
+
import { join as join10 } from "path";
|
|
4066
4083
|
import chalk13 from "chalk";
|
|
4067
4084
|
import ora9 from "ora";
|
|
4068
4085
|
import { execSync as execSync2 } from "child_process";
|
|
4069
4086
|
function findMobileCoreDir() {
|
|
4070
4087
|
const projectRoot = process.cwd();
|
|
4071
|
-
const npmPath =
|
|
4088
|
+
const npmPath = join10(projectRoot, "node_modules", "@nextsparkjs", "mobile");
|
|
4072
4089
|
if (existsSync9(npmPath)) {
|
|
4073
4090
|
return npmPath;
|
|
4074
4091
|
}
|
|
4075
|
-
const monoPath =
|
|
4092
|
+
const monoPath = join10(projectRoot, "packages", "mobile");
|
|
4076
4093
|
if (existsSync9(monoPath)) {
|
|
4077
4094
|
return monoPath;
|
|
4078
4095
|
}
|
|
4079
|
-
const parentNpmPath =
|
|
4096
|
+
const parentNpmPath = join10(projectRoot, "..", "node_modules", "@nextsparkjs", "mobile");
|
|
4080
4097
|
if (existsSync9(parentNpmPath)) {
|
|
4081
4098
|
return parentNpmPath;
|
|
4082
4099
|
}
|
|
@@ -4086,7 +4103,7 @@ function findMobileCoreDir() {
|
|
|
4086
4103
|
}
|
|
4087
4104
|
async function addMobileCommand(options = {}) {
|
|
4088
4105
|
const projectRoot = process.cwd();
|
|
4089
|
-
const mobileDir =
|
|
4106
|
+
const mobileDir = join10(projectRoot, "mobile");
|
|
4090
4107
|
console.log();
|
|
4091
4108
|
console.log(chalk13.bold("Adding NextSpark Mobile App"));
|
|
4092
4109
|
console.log();
|
|
@@ -4102,7 +4119,7 @@ async function addMobileCommand(options = {}) {
|
|
|
4102
4119
|
console.log(chalk13.red(error.message));
|
|
4103
4120
|
process.exit(1);
|
|
4104
4121
|
}
|
|
4105
|
-
const templatesDir =
|
|
4122
|
+
const templatesDir = join10(mobileCoreDir, "templates");
|
|
4106
4123
|
if (!existsSync9(templatesDir)) {
|
|
4107
4124
|
console.log(chalk13.red("Error: Could not find mobile templates"));
|
|
4108
4125
|
console.log(chalk13.gray(`Expected at: ${templatesDir}`));
|
|
@@ -4112,12 +4129,12 @@ async function addMobileCommand(options = {}) {
|
|
|
4112
4129
|
try {
|
|
4113
4130
|
mkdirSync3(mobileDir, { recursive: true });
|
|
4114
4131
|
cpSync2(templatesDir, mobileDir, { recursive: true });
|
|
4115
|
-
const pkgTemplatePath =
|
|
4116
|
-
const pkgPath =
|
|
4132
|
+
const pkgTemplatePath = join10(mobileDir, "package.json.template");
|
|
4133
|
+
const pkgPath = join10(mobileDir, "package.json");
|
|
4117
4134
|
if (existsSync9(pkgTemplatePath)) {
|
|
4118
4135
|
renameSync(pkgTemplatePath, pkgPath);
|
|
4119
4136
|
const pkg2 = JSON.parse(readFileSync8(pkgPath, "utf-8"));
|
|
4120
|
-
const rootPkgPath =
|
|
4137
|
+
const rootPkgPath = join10(projectRoot, "package.json");
|
|
4121
4138
|
if (existsSync9(rootPkgPath)) {
|
|
4122
4139
|
const rootPkg = JSON.parse(readFileSync8(rootPkgPath, "utf-8"));
|
|
4123
4140
|
const rawName = rootPkg.name || "my-project";
|
|
@@ -4631,11 +4648,11 @@ async function doctorCommand() {
|
|
|
4631
4648
|
// src/commands/db.ts
|
|
4632
4649
|
import { spawn as spawn5 } from "child_process";
|
|
4633
4650
|
import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
|
|
4634
|
-
import { join as
|
|
4651
|
+
import { join as join11 } from "path";
|
|
4635
4652
|
import chalk16 from "chalk";
|
|
4636
4653
|
import ora10 from "ora";
|
|
4637
4654
|
function loadProjectEnv4(projectRoot) {
|
|
4638
|
-
const envPath =
|
|
4655
|
+
const envPath = join11(projectRoot, ".env");
|
|
4639
4656
|
const envVars = {};
|
|
4640
4657
|
if (existsSync10(envPath)) {
|
|
4641
4658
|
const content = readFileSync9(envPath, "utf-8");
|
|
@@ -4660,7 +4677,7 @@ async function dbMigrateCommand() {
|
|
|
4660
4677
|
try {
|
|
4661
4678
|
const coreDir = getCoreDir();
|
|
4662
4679
|
const projectRoot = getProjectRoot();
|
|
4663
|
-
const migrationsScript =
|
|
4680
|
+
const migrationsScript = join11(coreDir, "scripts", "db", "run-migrations.mjs");
|
|
4664
4681
|
if (!existsSync10(migrationsScript)) {
|
|
4665
4682
|
spinner.fail("Migrations script not found");
|
|
4666
4683
|
console.error(chalk16.red(`Expected script at: ${migrationsScript}`));
|
|
@@ -4720,7 +4737,7 @@ async function dbSeedCommand() {
|
|
|
4720
4737
|
|
|
4721
4738
|
// src/commands/sync-app.ts
|
|
4722
4739
|
import { existsSync as existsSync11, readdirSync as readdirSync2, mkdirSync as mkdirSync4, copyFileSync, readFileSync as readFileSync10 } from "fs";
|
|
4723
|
-
import { join as
|
|
4740
|
+
import { join as join12, dirname as dirname4, relative } from "path";
|
|
4724
4741
|
import chalk17 from "chalk";
|
|
4725
4742
|
import ora11 from "ora";
|
|
4726
4743
|
var EXCLUDED_TEMPLATE_PATTERNS = ["(templates)"];
|
|
@@ -4743,7 +4760,7 @@ function getAllFiles(dir, baseDir = dir) {
|
|
|
4743
4760
|
}
|
|
4744
4761
|
const entries = readdirSync2(dir, { withFileTypes: true });
|
|
4745
4762
|
for (const entry of entries) {
|
|
4746
|
-
const fullPath =
|
|
4763
|
+
const fullPath = join12(dir, entry.name);
|
|
4747
4764
|
const relativePath = relative(baseDir, fullPath);
|
|
4748
4765
|
if (entry.isDirectory()) {
|
|
4749
4766
|
files.push(...getAllFiles(fullPath, baseDir));
|
|
@@ -4768,14 +4785,14 @@ function backupDirectory(source, target) {
|
|
|
4768
4785
|
}
|
|
4769
4786
|
const files = getAllFiles(source);
|
|
4770
4787
|
for (const file of files) {
|
|
4771
|
-
const sourcePath =
|
|
4772
|
-
const targetPath =
|
|
4788
|
+
const sourcePath = join12(source, file);
|
|
4789
|
+
const targetPath = join12(target, file);
|
|
4773
4790
|
copyFile(sourcePath, targetPath);
|
|
4774
4791
|
}
|
|
4775
4792
|
}
|
|
4776
4793
|
function getCoreVersion2(coreDir) {
|
|
4777
4794
|
try {
|
|
4778
|
-
const pkgPath =
|
|
4795
|
+
const pkgPath = join12(coreDir, "package.json");
|
|
4779
4796
|
const pkg2 = JSON.parse(readFileSync10(pkgPath, "utf-8"));
|
|
4780
4797
|
return pkg2.version || "unknown";
|
|
4781
4798
|
} catch {
|
|
@@ -4788,8 +4805,8 @@ async function syncAppCommand(options) {
|
|
|
4788
4805
|
const coreDir = getCoreDir();
|
|
4789
4806
|
const projectRoot = getProjectRoot();
|
|
4790
4807
|
const coreVersion = getCoreVersion2(coreDir);
|
|
4791
|
-
const templatesDir =
|
|
4792
|
-
const appDir =
|
|
4808
|
+
const templatesDir = join12(coreDir, "templates", "app");
|
|
4809
|
+
const appDir = join12(projectRoot, "app");
|
|
4793
4810
|
if (!existsSync11(templatesDir)) {
|
|
4794
4811
|
spinner.fail("Templates directory not found in @nextsparkjs/core");
|
|
4795
4812
|
console.error(chalk17.red(`
|
|
@@ -4817,7 +4834,7 @@ async function syncAppCommand(options) {
|
|
|
4817
4834
|
if (options.verbose) {
|
|
4818
4835
|
console.log(chalk17.gray(" Files to sync:"));
|
|
4819
4836
|
for (const file of filesToUpdate) {
|
|
4820
|
-
const targetPath =
|
|
4837
|
+
const targetPath = join12(appDir, file);
|
|
4821
4838
|
const status = existsSync11(targetPath) ? chalk17.yellow("update") : chalk17.green("create");
|
|
4822
4839
|
console.log(chalk17.gray(` ${status} ${file}`));
|
|
4823
4840
|
}
|
|
@@ -4854,7 +4871,7 @@ async function syncAppCommand(options) {
|
|
|
4854
4871
|
}
|
|
4855
4872
|
}
|
|
4856
4873
|
if (options.backup && !options.dryRun) {
|
|
4857
|
-
const backupDir =
|
|
4874
|
+
const backupDir = join12(projectRoot, `app.backup.v${coreVersion}.${Date.now()}`);
|
|
4858
4875
|
spinner.start("Creating backup...");
|
|
4859
4876
|
backupDirectory(appDir, backupDir);
|
|
4860
4877
|
spinner.succeed(`Backup created: ${relative(projectRoot, backupDir)}`);
|
|
@@ -4864,8 +4881,8 @@ async function syncAppCommand(options) {
|
|
|
4864
4881
|
let updated = 0;
|
|
4865
4882
|
let created = 0;
|
|
4866
4883
|
for (const file of filesToUpdate) {
|
|
4867
|
-
const sourcePath =
|
|
4868
|
-
const targetPath =
|
|
4884
|
+
const sourcePath = join12(templatesDir, file);
|
|
4885
|
+
const targetPath = join12(appDir, file);
|
|
4869
4886
|
const isNew = !existsSync11(targetPath);
|
|
4870
4887
|
copyFile(sourcePath, targetPath);
|
|
4871
4888
|
if (isNew) {
|
|
@@ -4878,12 +4895,12 @@ async function syncAppCommand(options) {
|
|
|
4878
4895
|
}
|
|
4879
4896
|
}
|
|
4880
4897
|
spinner.succeed(`Synced ${filesToUpdate.length} files (${updated} updated, ${created} created)`);
|
|
4881
|
-
const rootTemplatesDir =
|
|
4898
|
+
const rootTemplatesDir = join12(coreDir, "templates");
|
|
4882
4899
|
let rootUpdated = 0;
|
|
4883
4900
|
let rootCreated = 0;
|
|
4884
4901
|
for (const file of ROOT_TEMPLATE_FILES) {
|
|
4885
|
-
const sourcePath =
|
|
4886
|
-
const targetPath =
|
|
4902
|
+
const sourcePath = join12(rootTemplatesDir, file);
|
|
4903
|
+
const targetPath = join12(projectRoot, file);
|
|
4887
4904
|
if (existsSync11(sourcePath)) {
|
|
4888
4905
|
const isNew = !existsSync11(targetPath);
|
|
4889
4906
|
copyFile(sourcePath, targetPath);
|
|
@@ -4935,20 +4952,10 @@ ${error.stack}
|
|
|
4935
4952
|
|
|
4936
4953
|
// src/commands/setup-ai.ts
|
|
4937
4954
|
import { existsSync as existsSync12 } from "fs";
|
|
4938
|
-
import { join as
|
|
4955
|
+
import { join as join13 } from "path";
|
|
4939
4956
|
import { execSync as execSync3 } from "child_process";
|
|
4940
4957
|
import chalk18 from "chalk";
|
|
4941
4958
|
import ora12 from "ora";
|
|
4942
|
-
function resolveAIWorkflowPath() {
|
|
4943
|
-
const cwd = process.cwd();
|
|
4944
|
-
const nmPath = join12(cwd, "node_modules", "@nextsparkjs", "ai-workflow");
|
|
4945
|
-
if (existsSync12(nmPath)) return nmPath;
|
|
4946
|
-
const webNmPath = join12(cwd, "web", "node_modules", "@nextsparkjs", "ai-workflow");
|
|
4947
|
-
if (existsSync12(webNmPath)) return webNmPath;
|
|
4948
|
-
const monoPath = join12(cwd, "packages", "ai-workflow");
|
|
4949
|
-
if (existsSync12(monoPath)) return monoPath;
|
|
4950
|
-
return null;
|
|
4951
|
-
}
|
|
4952
4959
|
var VALID_EDITORS = ["claude", "cursor", "antigravity", "all"];
|
|
4953
4960
|
async function setupAICommand(options) {
|
|
4954
4961
|
const editor = options.editor || "claude";
|
|
@@ -4961,7 +4968,7 @@ async function setupAICommand(options) {
|
|
|
4961
4968
|
console.log(chalk18.cyan(" AI Workflow Setup"));
|
|
4962
4969
|
console.log(chalk18.gray(" " + "-".repeat(40)));
|
|
4963
4970
|
console.log("");
|
|
4964
|
-
const pkgPath =
|
|
4971
|
+
const pkgPath = getAIWorkflowDir();
|
|
4965
4972
|
if (!pkgPath) {
|
|
4966
4973
|
console.log(chalk18.red(" @nextsparkjs/ai-workflow package not found."));
|
|
4967
4974
|
console.log("");
|
|
@@ -4970,7 +4977,7 @@ async function setupAICommand(options) {
|
|
|
4970
4977
|
console.log("");
|
|
4971
4978
|
process.exit(1);
|
|
4972
4979
|
}
|
|
4973
|
-
const setupScript =
|
|
4980
|
+
const setupScript = join13(pkgPath, "scripts", "setup.mjs");
|
|
4974
4981
|
if (!existsSync12(setupScript)) {
|
|
4975
4982
|
console.log(chalk18.red(" Setup script not found in ai-workflow package."));
|
|
4976
4983
|
console.log(chalk18.gray(` Expected: ${setupScript}`));
|
|
@@ -4996,6 +5003,88 @@ async function setupAICommand(options) {
|
|
|
4996
5003
|
}
|
|
4997
5004
|
}
|
|
4998
5005
|
|
|
5006
|
+
// src/commands/sync-ai.ts
|
|
5007
|
+
import { existsSync as existsSync13 } from "fs";
|
|
5008
|
+
import { join as join14 } from "path";
|
|
5009
|
+
import { execSync as execSync4 } from "child_process";
|
|
5010
|
+
import chalk19 from "chalk";
|
|
5011
|
+
import ora13 from "ora";
|
|
5012
|
+
var VALID_EDITORS2 = ["claude", "cursor", "antigravity", "all"];
|
|
5013
|
+
async function syncAICommand(options) {
|
|
5014
|
+
const editor = options.editor || "claude";
|
|
5015
|
+
if (!VALID_EDITORS2.includes(editor)) {
|
|
5016
|
+
console.log(chalk19.red(` Unknown editor: ${editor}`));
|
|
5017
|
+
console.log(chalk19.gray(` Available: ${VALID_EDITORS2.join(", ")}`));
|
|
5018
|
+
process.exit(1);
|
|
5019
|
+
}
|
|
5020
|
+
console.log("");
|
|
5021
|
+
console.log(chalk19.cyan(" AI Workflow Sync"));
|
|
5022
|
+
console.log(chalk19.gray(" " + "-".repeat(40)));
|
|
5023
|
+
console.log("");
|
|
5024
|
+
const editorDir = editor === "cursor" ? ".cursor" : ".claude";
|
|
5025
|
+
const editorDirPath = join14(process.cwd(), editorDir);
|
|
5026
|
+
if (!existsSync13(editorDirPath)) {
|
|
5027
|
+
console.log(chalk19.red(` No ${editorDir}/ directory found.`));
|
|
5028
|
+
console.log("");
|
|
5029
|
+
console.log(chalk19.gray(" AI workflow must be set up first. Run:"));
|
|
5030
|
+
console.log(chalk19.cyan(" nextspark setup:ai --editor " + editor));
|
|
5031
|
+
console.log("");
|
|
5032
|
+
process.exit(1);
|
|
5033
|
+
}
|
|
5034
|
+
const pkgPath = getAIWorkflowDir();
|
|
5035
|
+
if (!pkgPath) {
|
|
5036
|
+
console.log(chalk19.red(" @nextsparkjs/ai-workflow package not found."));
|
|
5037
|
+
console.log("");
|
|
5038
|
+
console.log(chalk19.gray(" Install it first:"));
|
|
5039
|
+
console.log(chalk19.cyan(" pnpm add -D -w @nextsparkjs/ai-workflow"));
|
|
5040
|
+
console.log("");
|
|
5041
|
+
process.exit(1);
|
|
5042
|
+
}
|
|
5043
|
+
const setupScript = join14(pkgPath, "scripts", "setup.mjs");
|
|
5044
|
+
if (!existsSync13(setupScript)) {
|
|
5045
|
+
console.log(chalk19.red(" Setup script not found in ai-workflow package."));
|
|
5046
|
+
console.log(chalk19.gray(` Expected: ${setupScript}`));
|
|
5047
|
+
process.exit(1);
|
|
5048
|
+
}
|
|
5049
|
+
if (!options.force) {
|
|
5050
|
+
console.log(chalk19.yellow(" This will sync AI workflow files from @nextsparkjs/ai-workflow."));
|
|
5051
|
+
console.log(chalk19.gray(" Framework files will be overwritten. Custom files will be preserved."));
|
|
5052
|
+
console.log(chalk19.gray(" Config JSON files will never be overwritten.\n"));
|
|
5053
|
+
try {
|
|
5054
|
+
const { confirm: confirm6 } = await import("@inquirer/prompts");
|
|
5055
|
+
const confirmed = await confirm6({
|
|
5056
|
+
message: "Proceed with sync?",
|
|
5057
|
+
default: true
|
|
5058
|
+
});
|
|
5059
|
+
if (!confirmed) {
|
|
5060
|
+
console.log(chalk19.yellow("\n Sync cancelled.\n"));
|
|
5061
|
+
process.exit(0);
|
|
5062
|
+
}
|
|
5063
|
+
} catch {
|
|
5064
|
+
console.error(chalk19.red("\n Failed to load confirmation prompt. Use --force to skip.\n"));
|
|
5065
|
+
process.exit(1);
|
|
5066
|
+
}
|
|
5067
|
+
}
|
|
5068
|
+
const spinner = ora13({
|
|
5069
|
+
text: `Syncing AI workflow for ${editor}...`,
|
|
5070
|
+
prefixText: " "
|
|
5071
|
+
}).start();
|
|
5072
|
+
try {
|
|
5073
|
+
spinner.stop();
|
|
5074
|
+
execSync4(`node "${setupScript}" ${editor}`, {
|
|
5075
|
+
cwd: process.cwd(),
|
|
5076
|
+
stdio: "inherit"
|
|
5077
|
+
});
|
|
5078
|
+
} catch (error) {
|
|
5079
|
+
console.log("");
|
|
5080
|
+
console.log(chalk19.red(" AI workflow sync failed."));
|
|
5081
|
+
if (error instanceof Error) {
|
|
5082
|
+
console.log(chalk19.gray(` ${error.message}`));
|
|
5083
|
+
}
|
|
5084
|
+
process.exit(1);
|
|
5085
|
+
}
|
|
5086
|
+
}
|
|
5087
|
+
|
|
4999
5088
|
// src/cli.ts
|
|
5000
5089
|
config();
|
|
5001
5090
|
var pkg = JSON.parse(readFileSync11(new URL("../package.json", import.meta.url), "utf-8"));
|
|
@@ -5021,8 +5110,9 @@ program.command("db:migrate").description("Run database migrations (alias)").act
|
|
|
5021
5110
|
program.command("db:seed").description("Seed database with sample data (alias)").action(dbSeedCommand);
|
|
5022
5111
|
program.command("sync:app").description("Sync /app folder with @nextsparkjs/core templates").option("--dry-run", "Preview changes without applying").option("-f, --force", "Skip confirmation prompt").option("--backup", "Backup existing files before overwriting").option("-v, --verbose", "Show detailed file operations").action(syncAppCommand);
|
|
5023
5112
|
program.command("setup:ai").description("Setup AI workflow for your editor (Claude Code, Cursor, Antigravity)").option("-e, --editor <editor>", "Editor to setup (claude, cursor, antigravity, all)", "claude").action(setupAICommand);
|
|
5113
|
+
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);
|
|
5024
5114
|
program.showHelpAfterError();
|
|
5025
5115
|
program.configureOutput({
|
|
5026
|
-
writeErr: (str) => process.stderr.write(
|
|
5116
|
+
writeErr: (str) => process.stderr.write(chalk20.red(str))
|
|
5027
5117
|
});
|
|
5028
5118
|
program.parse();
|