@atlashub/smartstack-cli 4.58.0 → 4.60.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -113279,13 +113279,18 @@ async function installRalphConfig(options = {}) {
|
|
|
113279
113279
|
result.errors.push("Ralph config template not found");
|
|
113280
113280
|
logger.warning("Ralph config template not found in package");
|
|
113281
113281
|
}
|
|
113282
|
-
const gitignoreSrc = (0, import_path2.join)(TEMPLATES_DIR, "ralph", ".
|
|
113282
|
+
const gitignoreSrc = (0, import_path2.join)(TEMPLATES_DIR, "ralph", "gitignore.template");
|
|
113283
113283
|
const gitignoreDest = (0, import_path2.join)(ralphDir, ".gitignore");
|
|
113284
113284
|
if (await import_fs_extra2.default.pathExists(gitignoreSrc)) {
|
|
113285
113285
|
if (!await import_fs_extra2.default.pathExists(gitignoreDest) || options.force) {
|
|
113286
113286
|
const content = await import_fs_extra2.default.readFile(gitignoreSrc);
|
|
113287
113287
|
await import_fs_extra2.default.writeFile(gitignoreDest, content);
|
|
113288
|
+
logger.success("Created .ralph/.gitignore");
|
|
113289
|
+
} else {
|
|
113290
|
+
logger.info(".ralph/.gitignore already exists (use --force to overwrite)");
|
|
113288
113291
|
}
|
|
113292
|
+
} else {
|
|
113293
|
+
logger.warning(".ralph/gitignore.template not found in package \u2014 .gitignore not created");
|
|
113289
113294
|
}
|
|
113290
113295
|
const readmeSrc = (0, import_path2.join)(TEMPLATES_DIR, "ralph", "README.md");
|
|
113291
113296
|
const readmeDest = (0, import_path2.join)(ralphDir, "README.md");
|
|
@@ -117199,7 +117204,7 @@ ${projectName}/
|
|
|
117199
117204
|
\u2502 \u2514\u2500\u2500 ${projectName}.Api/ # Web API controllers and configuration
|
|
117200
117205
|
\u251C\u2500\u2500 web/
|
|
117201
117206
|
\u2502 \u2514\u2500\u2500 ${projectName.toLowerCase()}-web/ # React frontend (Vite + TypeScript + Tailwind)
|
|
117202
|
-
\u251C\u2500\u2500 docker-images/ # Dockerfiles (backend + frontend)
|
|
117207
|
+
\u251C\u2500\u2500 docker-images/ # Dockerfiles + docker-compose (backend + frontend)
|
|
117203
117208
|
\u2514\u2500\u2500 tests/ # Unit and integration tests
|
|
117204
117209
|
\`\`\`
|
|
117205
117210
|
|
|
@@ -117316,6 +117321,7 @@ async function createFrontendStructure(config, state, dryRun) {
|
|
|
117316
117321
|
"eslint-plugin-react-refresh": "^0.4.24",
|
|
117317
117322
|
globals: "^16.5.0",
|
|
117318
117323
|
jsdom: "^28.0.0",
|
|
117324
|
+
msw: "^2.7.5",
|
|
117319
117325
|
typescript: "~5.9.3",
|
|
117320
117326
|
"typescript-eslint": "^8.46.4",
|
|
117321
117327
|
vite: "^7.2.4",
|
|
@@ -117734,6 +117740,19 @@ async function createDockerFiles(config, state, dryRun) {
|
|
|
117734
117740
|
logSafeWriteResult(dockerignoreRelPath, dockerignoreResult);
|
|
117735
117741
|
recordFile(state, "docker", dockerignoreRelPath, dockerignoreResult.hash);
|
|
117736
117742
|
}
|
|
117743
|
+
const dockerCompose = await loadTemplate("docker-compose.yml.template", projectName);
|
|
117744
|
+
const composeRelPath = "docker-images/docker-compose.yml";
|
|
117745
|
+
if (dryRun) {
|
|
117746
|
+
logger.info(`Would create ${composeRelPath}`);
|
|
117747
|
+
} else {
|
|
117748
|
+
const composeResult = await safeWriteFile(
|
|
117749
|
+
(0, import_path7.join)(projectDir, composeRelPath),
|
|
117750
|
+
dockerCompose,
|
|
117751
|
+
findKnownHash(state, "docker", composeRelPath)
|
|
117752
|
+
);
|
|
117753
|
+
logSafeWriteResult(composeRelPath, composeResult);
|
|
117754
|
+
recordFile(state, "docker", composeRelPath, composeResult.hash);
|
|
117755
|
+
}
|
|
117737
117756
|
logger.success("Docker configuration created");
|
|
117738
117757
|
}
|
|
117739
117758
|
function checkGitIdentity(cwd) {
|
|
@@ -118134,6 +118153,17 @@ var initCommand = new Command("init").description("Initialize a new SmartStack p
|
|
|
118134
118153
|
const ralphResult = await installRalphConfig({ projectPath: finalProjectDir });
|
|
118135
118154
|
if (ralphResult.success) {
|
|
118136
118155
|
logger.success("Ralph configuration created at .ralph/");
|
|
118156
|
+
const ralphFiles = [
|
|
118157
|
+
{ path: ".ralph/ralph.config.yaml", abs: ralphResult.configPath },
|
|
118158
|
+
{ path: ".ralph/.gitignore", abs: (0, import_path7.join)(finalProjectDir, ".ralph", ".gitignore") },
|
|
118159
|
+
{ path: ".ralph/README.md", abs: (0, import_path7.join)(finalProjectDir, ".ralph", "README.md") }
|
|
118160
|
+
];
|
|
118161
|
+
for (const rf of ralphFiles) {
|
|
118162
|
+
if (await import_fs_extra6.default.pathExists(rf.abs)) {
|
|
118163
|
+
const content = await import_fs_extra6.default.readFile(rf.abs);
|
|
118164
|
+
recordFile(state, "ralph", rf.path, computeHash(content));
|
|
118165
|
+
}
|
|
118166
|
+
}
|
|
118137
118167
|
} else {
|
|
118138
118168
|
logger.warning("Could not create Ralph configuration (non-critical)");
|
|
118139
118169
|
}
|
|
@@ -118168,6 +118198,7 @@ var initCommand = new Command("init").description("Initialize a new SmartStack p
|
|
|
118168
118198
|
` 3. Start dev server: ${source_default.cyan("npm run dev")}`,
|
|
118169
118199
|
"",
|
|
118170
118200
|
source_default.yellow("Docker:"),
|
|
118201
|
+
` Build & run: ${source_default.cyan("docker compose -f docker-images/docker-compose.yml up --build")}`,
|
|
118171
118202
|
` Build backend: ${source_default.cyan(`docker build -t smartstack-${projectNameLower}-backend:latest -f docker-images/Dockerfile.backend .`)}`,
|
|
118172
118203
|
` Build frontend: ${source_default.cyan(`docker build -t smartstack-${projectNameLower}-frontend:latest -f docker-images/Dockerfile.frontend .`)}`,
|
|
118173
118204
|
"",
|
|
@@ -125275,25 +125306,97 @@ async function syncClaudeSettings(projectDir, dryRun) {
|
|
|
125275
125306
|
}
|
|
125276
125307
|
return added;
|
|
125277
125308
|
}
|
|
125309
|
+
async function syncTestFrontendTemplates(frontendDir, dryRun) {
|
|
125310
|
+
const testFrontendDir = (0, import_path8.join)(TEMPLATES_DIR3, "test-frontend");
|
|
125311
|
+
if (!await import_fs_extra7.default.pathExists(testFrontendDir)) {
|
|
125312
|
+
logger.debug("test-frontend templates not found, skipping");
|
|
125313
|
+
return 0;
|
|
125314
|
+
}
|
|
125315
|
+
let synced = 0;
|
|
125316
|
+
const testFiles = [
|
|
125317
|
+
{ src: "vitest.config.ts", dest: "vitest.config.ts" },
|
|
125318
|
+
{ src: "setup.ts", dest: (0, import_path8.join)("src", "test", "setup.ts") },
|
|
125319
|
+
{ src: "test-utils.tsx", dest: (0, import_path8.join)("src", "test", "test-utils.tsx") },
|
|
125320
|
+
{ src: "msw/handlers.ts", dest: (0, import_path8.join)("src", "test", "msw", "handlers.ts") },
|
|
125321
|
+
{ src: "msw/server.ts", dest: (0, import_path8.join)("src", "test", "msw", "server.ts") }
|
|
125322
|
+
];
|
|
125323
|
+
for (const file of testFiles) {
|
|
125324
|
+
const destPath = (0, import_path8.join)(frontendDir, file.dest);
|
|
125325
|
+
if (await import_fs_extra7.default.pathExists(destPath)) continue;
|
|
125326
|
+
const srcPath = (0, import_path8.join)(testFrontendDir, file.src);
|
|
125327
|
+
if (!await import_fs_extra7.default.pathExists(srcPath)) continue;
|
|
125328
|
+
if (dryRun) {
|
|
125329
|
+
logger.warning(`[DRY RUN] Would create ${file.dest}`);
|
|
125330
|
+
} else {
|
|
125331
|
+
await import_fs_extra7.default.ensureDir((0, import_path8.dirname)(destPath));
|
|
125332
|
+
const content = await import_fs_extra7.default.readFile(srcPath, "utf-8");
|
|
125333
|
+
await import_fs_extra7.default.writeFile(destPath, content, "utf-8");
|
|
125334
|
+
logger.info(` ${source_default.green("+")} ${file.dest}`);
|
|
125335
|
+
}
|
|
125336
|
+
synced++;
|
|
125337
|
+
}
|
|
125338
|
+
return synced;
|
|
125339
|
+
}
|
|
125340
|
+
async function cleanResidualFiles(projectDir, baseNamespace, dryRun) {
|
|
125341
|
+
let cleaned = 0;
|
|
125342
|
+
const residuals = [
|
|
125343
|
+
(0, import_path8.join)(projectDir, "src", `${baseNamespace}.Api`, `${baseNamespace}.Api.http`)
|
|
125344
|
+
];
|
|
125345
|
+
for (const file of residuals) {
|
|
125346
|
+
if (await import_fs_extra7.default.pathExists(file)) {
|
|
125347
|
+
if (dryRun) {
|
|
125348
|
+
logger.warning(`[DRY RUN] Would remove residual: ${file}`);
|
|
125349
|
+
} else {
|
|
125350
|
+
await import_fs_extra7.default.remove(file);
|
|
125351
|
+
logger.info(` ${source_default.red("\u2212")} Removed residual: ${baseNamespace}.Api.http`);
|
|
125352
|
+
}
|
|
125353
|
+
cleaned++;
|
|
125354
|
+
}
|
|
125355
|
+
}
|
|
125356
|
+
return cleaned;
|
|
125357
|
+
}
|
|
125358
|
+
async function fixInitStateVersion(projectDir, cliVersion, dryRun) {
|
|
125359
|
+
const statePath = (0, import_path8.join)(projectDir, ".smartstack", "init-state.json");
|
|
125360
|
+
if (!await import_fs_extra7.default.pathExists(statePath)) return false;
|
|
125361
|
+
try {
|
|
125362
|
+
const state = await import_fs_extra7.default.readJson(statePath);
|
|
125363
|
+
if (state.cliVersion === "0.0.0") {
|
|
125364
|
+
if (dryRun) {
|
|
125365
|
+
logger.warning("[DRY RUN] Would fix cliVersion 0.0.0 in init-state.json");
|
|
125366
|
+
} else {
|
|
125367
|
+
state.cliVersion = cliVersion;
|
|
125368
|
+
await import_fs_extra7.default.writeJson(statePath, state, { spaces: 2 });
|
|
125369
|
+
logger.info(` ${source_default.green("+")} Fixed cliVersion: 0.0.0 \u2192 ${cliVersion}`);
|
|
125370
|
+
}
|
|
125371
|
+
return true;
|
|
125372
|
+
}
|
|
125373
|
+
} catch {
|
|
125374
|
+
}
|
|
125375
|
+
return false;
|
|
125376
|
+
}
|
|
125278
125377
|
async function syncDockerFiles(projectDir, baseNamespace, dryRun) {
|
|
125279
125378
|
const projectName = baseNamespace;
|
|
125280
|
-
const projectNameLower = projectName.toLowerCase();
|
|
125281
125379
|
let updated = 0;
|
|
125282
125380
|
const files = [
|
|
125283
125381
|
{
|
|
125284
125382
|
template: "Dockerfile.backend.template",
|
|
125285
|
-
dest: (0, import_path8.join)(projectDir, "
|
|
125286
|
-
label:
|
|
125383
|
+
dest: (0, import_path8.join)(projectDir, "docker-images", "Dockerfile.backend"),
|
|
125384
|
+
label: "docker-images/Dockerfile.backend"
|
|
125287
125385
|
},
|
|
125288
125386
|
{
|
|
125289
125387
|
template: "Dockerfile.frontend.template",
|
|
125290
|
-
dest: (0, import_path8.join)(projectDir, "
|
|
125291
|
-
label:
|
|
125388
|
+
dest: (0, import_path8.join)(projectDir, "docker-images", "Dockerfile.frontend"),
|
|
125389
|
+
label: "docker-images/Dockerfile.frontend"
|
|
125292
125390
|
},
|
|
125293
125391
|
{
|
|
125294
125392
|
template: "dockerignore.template",
|
|
125295
125393
|
dest: (0, import_path8.join)(projectDir, ".dockerignore"),
|
|
125296
125394
|
label: ".dockerignore"
|
|
125395
|
+
},
|
|
125396
|
+
{
|
|
125397
|
+
template: "docker-compose.yml.template",
|
|
125398
|
+
dest: (0, import_path8.join)(projectDir, "docker-images", "docker-compose.yml"),
|
|
125399
|
+
label: "docker-images/docker-compose.yml"
|
|
125297
125400
|
}
|
|
125298
125401
|
];
|
|
125299
125402
|
for (const file of files) {
|
|
@@ -125342,6 +125445,9 @@ var upgradeCommand = new Command("upgrade").description("Upgrade SmartStack pack
|
|
|
125342
125445
|
ralphInitialized: false,
|
|
125343
125446
|
ralphUpToDate: false,
|
|
125344
125447
|
dockerSynced: 0,
|
|
125448
|
+
testFrontendSynced: 0,
|
|
125449
|
+
residualsCleaned: 0,
|
|
125450
|
+
initStateFixed: false,
|
|
125345
125451
|
programCsIssues: []
|
|
125346
125452
|
};
|
|
125347
125453
|
if (dryRun) {
|
|
@@ -125525,6 +125631,14 @@ var upgradeCommand = new Command("upgrade").description("Upgrade SmartStack pack
|
|
|
125525
125631
|
} else {
|
|
125526
125632
|
logger.info(`Other npm packages: ${source_default.gray("skipped")} (use ${source_default.cyan("--all-packages")} to upgrade all)`);
|
|
125527
125633
|
}
|
|
125634
|
+
logger.info("Syncing test-frontend templates...");
|
|
125635
|
+
const testSynced = await syncTestFrontendTemplates(frontendDir, dryRun);
|
|
125636
|
+
result.testFrontendSynced = testSynced;
|
|
125637
|
+
if (testSynced > 0) {
|
|
125638
|
+
logger.success(`${testSynced} test template(s) deployed`);
|
|
125639
|
+
} else {
|
|
125640
|
+
logger.info(`Test templates ${source_default.green("\u2713")} up to date`);
|
|
125641
|
+
}
|
|
125528
125642
|
console.log();
|
|
125529
125643
|
}
|
|
125530
125644
|
logger.info("Checking for code migrations...");
|
|
@@ -125595,6 +125709,17 @@ var upgradeCommand = new Command("upgrade").description("Upgrade SmartStack pack
|
|
|
125595
125709
|
logger.info(`Dockerfiles ${source_default.green("\u2713")} up to date`);
|
|
125596
125710
|
}
|
|
125597
125711
|
console.log();
|
|
125712
|
+
const residualsCleaned = await cleanResidualFiles(projectDir, config.baseNamespace, dryRun);
|
|
125713
|
+
result.residualsCleaned = residualsCleaned;
|
|
125714
|
+
if (residualsCleaned > 0) {
|
|
125715
|
+
logger.success(`${residualsCleaned} residual file(s) cleaned`);
|
|
125716
|
+
console.log();
|
|
125717
|
+
}
|
|
125718
|
+
result.initStateFixed = await fixInitStateVersion(projectDir, nugetVersion, dryRun);
|
|
125719
|
+
if (result.initStateFixed) {
|
|
125720
|
+
logger.success("Fixed cliVersion in init-state.json");
|
|
125721
|
+
console.log();
|
|
125722
|
+
}
|
|
125598
125723
|
logger.info("Checking Ralph configuration...");
|
|
125599
125724
|
const ralphStatus = await checkRalphInstallation(projectDir);
|
|
125600
125725
|
if (ralphStatus.configExists) {
|
|
@@ -125638,7 +125763,7 @@ var upgradeCommand = new Command("upgrade").description("Upgrade SmartStack pack
|
|
|
125638
125763
|
logger.success(`Updated config version to ${source_default.cyan(nugetVersion)}`);
|
|
125639
125764
|
console.log();
|
|
125640
125765
|
}
|
|
125641
|
-
const totalChanged = result.nugetUpgraded + result.otherPkgUpdated + (result.npmUpgraded ? 1 : 0) + (result.npmOtherUpdated ? 1 : 0) + migrationSummary.totalApplied + result.configSynced + result.claudeSettingsSynced + result.dockerSynced + (result.ralphInitialized ? 1 : 0);
|
|
125766
|
+
const totalChanged = result.nugetUpgraded + result.otherPkgUpdated + (result.npmUpgraded ? 1 : 0) + (result.npmOtherUpdated ? 1 : 0) + migrationSummary.totalApplied + result.configSynced + result.claudeSettingsSynced + result.dockerSynced + result.testFrontendSynced + result.residualsCleaned + (result.initStateFixed ? 1 : 0) + (result.ralphInitialized ? 1 : 0);
|
|
125642
125767
|
const allUpToDate = totalChanged === 0 && result.nugetFailed === 0 && result.otherPkgFailed === 0;
|
|
125643
125768
|
const hasProgramIssues = result.programCsIssues.length > 0;
|
|
125644
125769
|
if (allUpToDate && !hasProgramIssues) {
|
|
@@ -125702,6 +125827,15 @@ var upgradeCommand = new Command("upgrade").description("Upgrade SmartStack pack
|
|
|
125702
125827
|
if (result.dockerSynced > 0) {
|
|
125703
125828
|
lines.push(` ${source_default.green("\u2713")} Docker: ${result.dockerSynced} Dockerfile(s) updated`);
|
|
125704
125829
|
}
|
|
125830
|
+
if (result.testFrontendSynced > 0) {
|
|
125831
|
+
lines.push(` ${source_default.green("\u2713")} Test templates: ${result.testFrontendSynced} file(s) deployed`);
|
|
125832
|
+
}
|
|
125833
|
+
if (result.residualsCleaned > 0) {
|
|
125834
|
+
lines.push(` ${source_default.green("\u2713")} Cleanup: ${result.residualsCleaned} residual file(s) removed`);
|
|
125835
|
+
}
|
|
125836
|
+
if (result.initStateFixed) {
|
|
125837
|
+
lines.push(` ${source_default.green("\u2713")} Init-state: cliVersion fixed`);
|
|
125838
|
+
}
|
|
125705
125839
|
if (result.ralphInitialized) {
|
|
125706
125840
|
lines.push(` ${source_default.green("\u2713")} Ralph: configuration initialized`);
|
|
125707
125841
|
}
|