@atlashub/smartstack-cli 3.4.1 → 3.6.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 +160 -5
- package/dist/index.js.map +1 -1
- package/dist/mcp-entry.mjs +4 -3
- package/dist/mcp-entry.mjs.map +1 -1
- package/package.json +1 -1
- package/templates/skills/_shared.md +1 -1
- package/templates/skills/application/steps/step-04-backend.md +4 -4
- package/templates/skills/application/templates-backend.md +4 -4
- package/templates/skills/business-analyse/SKILL.md +26 -15
- package/templates/skills/business-analyse/_architecture.md +4 -4
- package/templates/skills/business-analyse/_elicitation.md +1 -1
- package/templates/skills/business-analyse/_module-loop.md +4 -4
- package/templates/skills/business-analyse/html/ba-interactive.html +39 -10
- package/templates/skills/business-analyse/questionnaire/06-security.md +1 -1
- package/templates/skills/business-analyse/questionnaire.md +2 -2
- package/templates/skills/business-analyse/react/components.md +1 -1
- package/templates/skills/business-analyse/react/schema.md +1 -1
- package/templates/skills/business-analyse/references/html-data-mapping.md +4 -3
- package/templates/skills/business-analyse/schemas/feature-schema.json +1 -1
- package/templates/skills/business-analyse/schemas/sections/analysis-schema.json +1 -1
- package/templates/skills/business-analyse/schemas/sections/metadata-schema.json +1 -0
- package/templates/skills/business-analyse/schemas/sections/specification-schema.json +1 -1
- package/templates/skills/business-analyse/steps/step-00-init.md +29 -0
- package/templates/skills/business-analyse/steps/step-01-cadrage.md +166 -6
- package/templates/skills/business-analyse/steps/step-02-decomposition.md +4 -4
- package/templates/skills/business-analyse/steps/{step-03a-specify.md → step-03a-data.md} +10 -359
- package/templates/skills/business-analyse/steps/step-03b-ui.md +414 -0
- package/templates/skills/business-analyse/steps/step-03c-compile.md +343 -0
- package/templates/skills/business-analyse/steps/{step-03b-compile.md → step-03d-validate.md} +26 -308
- package/templates/skills/business-analyse/steps/step-04-consolidation.md +2 -2
- package/templates/skills/business-analyse/steps/step-05a-handoff.md +49 -292
- package/templates/skills/business-analyse/steps/step-05b-mapping.md +302 -0
- package/templates/skills/business-analyse/steps/step-05c-deploy.md +296 -0
- package/templates/skills/business-analyse/steps/step-05d-html.md +326 -0
- package/templates/skills/business-analyse/templates/tpl-frd.md +1 -1
- package/templates/skills/business-analyse/templates/tpl-handoff.md +6 -6
- package/templates/skills/business-analyse/templates/tpl-launch-displays.md +1 -1
- package/templates/skills/business-analyse/templates/tpl-progress.md +1 -1
- package/templates/skills/controller/steps/step-03-generate.md +2 -1
- package/templates/skills/ralph-loop/SKILL.md +17 -2
- package/templates/skills/ralph-loop/references/core-seed-data.md +538 -0
- package/templates/skills/ralph-loop/steps/step-00-init.md +2 -0
- package/templates/skills/ralph-loop/steps/step-01-task.md +273 -7
- package/templates/skills/ralph-loop/steps/step-02-execute.md +39 -15
- package/templates/skills/ralph-loop/steps/step-04-check.md +87 -4
- package/templates/skills/business-analyse/steps/step-05b-deploy.md +0 -432
package/dist/index.js
CHANGED
|
@@ -116146,6 +116146,56 @@ function checkPrerequisites() {
|
|
|
116146
116146
|
return { dotnet: false, dotnetVersion: null };
|
|
116147
116147
|
}
|
|
116148
116148
|
}
|
|
116149
|
+
function isDockerAvailable() {
|
|
116150
|
+
try {
|
|
116151
|
+
const result = (0, import_child_process5.spawnSync)("docker", ["info"], { encoding: "utf-8", shell: true, timeout: 1e4, stdio: "pipe" });
|
|
116152
|
+
return result.status === 0;
|
|
116153
|
+
} catch {
|
|
116154
|
+
return false;
|
|
116155
|
+
}
|
|
116156
|
+
}
|
|
116157
|
+
async function setupMailPitContainer() {
|
|
116158
|
+
const check = (0, import_child_process5.spawnSync)("docker", ["ps", "-a", "--filter", "name=^mailpit$", "--format", "{{.Status}}"], {
|
|
116159
|
+
encoding: "utf-8",
|
|
116160
|
+
shell: true,
|
|
116161
|
+
timeout: 1e4
|
|
116162
|
+
});
|
|
116163
|
+
if (check.stdout?.trim()) {
|
|
116164
|
+
const status = check.stdout.trim();
|
|
116165
|
+
if (status.startsWith("Up")) {
|
|
116166
|
+
logger.success(`MailPit is already running`);
|
|
116167
|
+
} else {
|
|
116168
|
+
logger.info("Starting existing MailPit container...");
|
|
116169
|
+
(0, import_child_process5.spawnSync)("docker", ["start", "mailpit"], { encoding: "utf-8", shell: true, timeout: 15e3 });
|
|
116170
|
+
logger.success("MailPit started");
|
|
116171
|
+
}
|
|
116172
|
+
} else {
|
|
116173
|
+
logger.info("Starting MailPit container...");
|
|
116174
|
+
const run = (0, import_child_process5.spawnSync)("docker", [
|
|
116175
|
+
"run",
|
|
116176
|
+
"-d",
|
|
116177
|
+
"--name",
|
|
116178
|
+
"mailpit",
|
|
116179
|
+
"--restart",
|
|
116180
|
+
"unless-stopped",
|
|
116181
|
+
"-p",
|
|
116182
|
+
"8025:8025",
|
|
116183
|
+
"-p",
|
|
116184
|
+
"1025:1025",
|
|
116185
|
+
"axllent/mailpit"
|
|
116186
|
+
], { encoding: "utf-8", shell: true, timeout: 6e4 });
|
|
116187
|
+
if (run.status === 0) {
|
|
116188
|
+
logger.success("MailPit started successfully");
|
|
116189
|
+
} else {
|
|
116190
|
+
logger.warning(`Failed to start MailPit: ${run.stderr?.trim() || "unknown error"}`);
|
|
116191
|
+
logger.info("You can start it manually later:");
|
|
116192
|
+
logger.info(source_default.cyan(" docker run -d --name mailpit --restart unless-stopped -p 8025:8025 -p 1025:1025 axllent/mailpit"));
|
|
116193
|
+
return;
|
|
116194
|
+
}
|
|
116195
|
+
}
|
|
116196
|
+
logger.info(`SMTP server: ${source_default.cyan("localhost:1025")}`);
|
|
116197
|
+
logger.info(`Web interface: ${source_default.cyan("http://localhost:8025")}`);
|
|
116198
|
+
}
|
|
116149
116199
|
function validateCSharpNamespace(name) {
|
|
116150
116200
|
if (!name || name.trim().length === 0) {
|
|
116151
116201
|
return { valid: false, error: "Project name cannot be empty" };
|
|
@@ -116700,6 +116750,10 @@ EndGlobal
|
|
|
116700
116750
|
SystemTenantName: config.multiTenant.systemTenantName,
|
|
116701
116751
|
AutoAssignUsersToSystemTenant: config.multiTenant.autoAssignUsersToSystemTenant
|
|
116702
116752
|
};
|
|
116753
|
+
appSettings.Email.Provider = config.email.provider;
|
|
116754
|
+
if (config.email.provider === "Disabled") {
|
|
116755
|
+
appSettings.Email.Enabled = false;
|
|
116756
|
+
}
|
|
116703
116757
|
const appSettingsRelPath = `src/${projectName}.Api/appsettings.json`;
|
|
116704
116758
|
const appSettingsResult = await safeWriteFile(
|
|
116705
116759
|
(0, import_path6.join)(apiDir2, "appsettings.json"),
|
|
@@ -116718,7 +116772,7 @@ EndGlobal
|
|
|
116718
116772
|
}
|
|
116719
116773
|
},
|
|
116720
116774
|
Email: {
|
|
116721
|
-
Provider:
|
|
116775
|
+
Provider: config.email.provider
|
|
116722
116776
|
}
|
|
116723
116777
|
};
|
|
116724
116778
|
const appSettingsDevRelPath = `src/${projectName}.Api/appsettings.Development.json`;
|
|
@@ -116985,6 +117039,19 @@ Generated with [SmartStack CLI](https://atlashub.io/products/smartstack-cli)
|
|
|
116985
117039
|
const result7 = await safeWriteFile((0, import_path6.join)(projectDir, relPath7), readme, findKnownHash(state, "config", relPath7));
|
|
116986
117040
|
logSafeWriteResult(relPath7, result7);
|
|
116987
117041
|
recordFile(state, "config", relPath7, result7.hash);
|
|
117042
|
+
const claudeSettingsTemplatePath = (0, import_path6.join)(TEMPLATES_DIR2, "claude-settings.json.template");
|
|
117043
|
+
if (await import_fs_extra5.default.pathExists(claudeSettingsTemplatePath)) {
|
|
117044
|
+
await import_fs_extra5.default.ensureDir((0, import_path6.join)(projectDir, ".claude"));
|
|
117045
|
+
const claudeSettingsContent = await import_fs_extra5.default.readFile(claudeSettingsTemplatePath, "utf-8");
|
|
117046
|
+
const relPath8 = ".claude/settings.json";
|
|
117047
|
+
const result8 = await safeWriteFile(
|
|
117048
|
+
(0, import_path6.join)(projectDir, relPath8),
|
|
117049
|
+
claudeSettingsContent,
|
|
117050
|
+
findKnownHash(state, "config", relPath8)
|
|
117051
|
+
);
|
|
117052
|
+
logSafeWriteResult(relPath8, result8);
|
|
117053
|
+
recordFile(state, "config", relPath8, result8.hash);
|
|
117054
|
+
}
|
|
116988
117055
|
}
|
|
116989
117056
|
async function createFrontendStructure(config, state, dryRun) {
|
|
116990
117057
|
const { name } = config;
|
|
@@ -117672,6 +117739,10 @@ var initCommand = new Command("init").description("Initialize a new SmartStack p
|
|
|
117672
117739
|
systemTenantSlug: "default",
|
|
117673
117740
|
systemTenantName: "Default Workspace",
|
|
117674
117741
|
autoAssignUsersToSystemTenant: true
|
|
117742
|
+
},
|
|
117743
|
+
email: {
|
|
117744
|
+
provider: "Development",
|
|
117745
|
+
setupMailPit: false
|
|
117675
117746
|
}
|
|
117676
117747
|
};
|
|
117677
117748
|
} else {
|
|
@@ -117711,6 +117782,27 @@ var initCommand = new Command("init").description("Initialize a new SmartStack p
|
|
|
117711
117782
|
when: (answers2) => answers2.multiTenantEnabled
|
|
117712
117783
|
}
|
|
117713
117784
|
]);
|
|
117785
|
+
const emailAnswers = await lib_default.prompt([
|
|
117786
|
+
{
|
|
117787
|
+
type: "list",
|
|
117788
|
+
name: "emailProvider",
|
|
117789
|
+
message: "Email provider:",
|
|
117790
|
+
choices: [
|
|
117791
|
+
{ name: "Development (MailPit - local SMTP testing)", value: "Development" },
|
|
117792
|
+
{ name: "Mailgun", value: "Mailgun" },
|
|
117793
|
+
{ name: "Azure Communication Services", value: "AzureAcs" },
|
|
117794
|
+
{ name: "Disabled", value: "Disabled" }
|
|
117795
|
+
],
|
|
117796
|
+
default: "Development"
|
|
117797
|
+
},
|
|
117798
|
+
{
|
|
117799
|
+
type: "confirm",
|
|
117800
|
+
name: "setupMailPit",
|
|
117801
|
+
message: "Start MailPit Docker container for email testing?",
|
|
117802
|
+
default: true,
|
|
117803
|
+
when: (a) => a.emailProvider === "Development" && isDockerAvailable()
|
|
117804
|
+
}
|
|
117805
|
+
]);
|
|
117714
117806
|
config = {
|
|
117715
117807
|
name: finalProjectName,
|
|
117716
117808
|
nameLower: finalProjectName.toLowerCase(),
|
|
@@ -117724,6 +117816,10 @@ var initCommand = new Command("init").description("Initialize a new SmartStack p
|
|
|
117724
117816
|
systemTenantSlug: answers.systemTenantSlug || "default",
|
|
117725
117817
|
systemTenantName: answers.systemTenantName || "Default Workspace",
|
|
117726
117818
|
autoAssignUsersToSystemTenant: true
|
|
117819
|
+
},
|
|
117820
|
+
email: {
|
|
117821
|
+
provider: emailAnswers.emailProvider || "Development",
|
|
117822
|
+
setupMailPit: emailAnswers.setupMailPit ?? false
|
|
117727
117823
|
}
|
|
117728
117824
|
};
|
|
117729
117825
|
}
|
|
@@ -117741,6 +117837,8 @@ var initCommand = new Command("init").description("Initialize a new SmartStack p
|
|
|
117741
117837
|
logger.info(` B2C (User Tenants): ${config.multiTenant.enableB2C ? source_default.green("Enabled") : source_default.gray("Disabled")}`);
|
|
117742
117838
|
logger.info(` System Tenant: ${source_default.cyan(config.multiTenant.systemTenantSlug)} (${config.multiTenant.systemTenantName})`);
|
|
117743
117839
|
}
|
|
117840
|
+
const emailLabel = config.email.provider === "Development" ? `${source_default.green("Development")} (MailPit - SMTP :1025, Web :8025)` : config.email.provider === "Disabled" ? source_default.gray("Disabled") : source_default.cyan(config.email.provider);
|
|
117841
|
+
logger.info(`Email: ${emailLabel}`);
|
|
117744
117842
|
console.log();
|
|
117745
117843
|
try {
|
|
117746
117844
|
let cliVersion = "0.0.0";
|
|
@@ -117782,6 +117880,10 @@ var initCommand = new Command("init").description("Initialize a new SmartStack p
|
|
|
117782
117880
|
logger.info("Would create .ralph/ directory with configuration");
|
|
117783
117881
|
}
|
|
117784
117882
|
});
|
|
117883
|
+
if (config.email.setupMailPit && !dryRun) {
|
|
117884
|
+
console.log();
|
|
117885
|
+
await setupMailPitContainer();
|
|
117886
|
+
}
|
|
117785
117887
|
if (!dryRun) {
|
|
117786
117888
|
await saveInitState(finalProjectDir, state);
|
|
117787
117889
|
}
|
|
@@ -126219,9 +126321,11 @@ adminCommand.command("reset").description("Reset the localAdmin account password
|
|
|
126219
126321
|
logger.error(`No connection string found in ${(0, import_path10.basename)(selectedFile)}`);
|
|
126220
126322
|
process.exit(1);
|
|
126221
126323
|
}
|
|
126222
|
-
logger.info(`Using: ${source_default.cyan((0, import_path10.basename)(selectedFile))}`);
|
|
126223
126324
|
}
|
|
126224
126325
|
const adminEmail = options.email;
|
|
126326
|
+
const connInfo = parseConnectionString(connectionString);
|
|
126327
|
+
logger.info(`Server: ${source_default.cyan(connInfo.server)}`);
|
|
126328
|
+
logger.info(`Database: ${source_default.cyan(connInfo.database)}`);
|
|
126225
126329
|
if (!options.force) {
|
|
126226
126330
|
const { confirm } = await lib_default.prompt([
|
|
126227
126331
|
{
|
|
@@ -126237,7 +126341,6 @@ adminCommand.command("reset").description("Reset the localAdmin account password
|
|
|
126237
126341
|
}
|
|
126238
126342
|
}
|
|
126239
126343
|
const spinner = logger.spinner("Connecting to database...");
|
|
126240
|
-
const connInfo = parseConnectionString(connectionString);
|
|
126241
126344
|
const resetViaSqlCmd = async (sqlAuth) => {
|
|
126242
126345
|
const authLabel = sqlAuth ? "SQL Server Authentication" : "Windows Authentication";
|
|
126243
126346
|
spinner.text = `Using ${authLabel} (sqlcmd)...`;
|
|
@@ -126265,6 +126368,8 @@ adminCommand.command("reset").description("Reset the localAdmin account password
|
|
|
126265
126368
|
console.log(source_default.green.bold(" LOCAL ADMINISTRATOR PASSWORD RESET"));
|
|
126266
126369
|
console.log(source_default.green("\u2550".repeat(60)));
|
|
126267
126370
|
console.log();
|
|
126371
|
+
console.log(source_default.white(" Server: "), source_default.cyan(connInfo.server));
|
|
126372
|
+
console.log(source_default.white(" Database: "), source_default.cyan(connInfo.database));
|
|
126268
126373
|
console.log(source_default.white(" Email: "), source_default.cyan(email));
|
|
126269
126374
|
console.log(source_default.white(" Password: "), source_default.yellow.bold(password));
|
|
126270
126375
|
console.log();
|
|
@@ -126809,6 +126914,42 @@ function validateForPrdExtraction(feature) {
|
|
|
126809
126914
|
}
|
|
126810
126915
|
return errors;
|
|
126811
126916
|
}
|
|
126917
|
+
function validatePrdCompleteness(prd, feature) {
|
|
126918
|
+
const warnings = [];
|
|
126919
|
+
const ftc = prd.implementation.filesToCreate;
|
|
126920
|
+
const handoffFtc = feature.handoff?.filesToCreate;
|
|
126921
|
+
const categories = [
|
|
126922
|
+
{ key: "domain", label: "domain", check: () => !!feature.analysis?.entities?.length },
|
|
126923
|
+
{ key: "application", label: "application", check: () => !!feature.analysis?.entities?.length },
|
|
126924
|
+
{ key: "infrastructure", label: "infrastructure", check: () => !!feature.analysis?.entities?.length },
|
|
126925
|
+
{ key: "api", label: "api", check: () => !!feature.specification?.apiEndpoints?.length },
|
|
126926
|
+
{ key: "frontend", label: "frontend", check: () => !!(feature.specification?.uiWireframes?.length || feature.specification?.sections?.length) },
|
|
126927
|
+
{ key: "seedData", label: "seedData", check: () => !!(feature.specification?.seedDataCore?.length || feature.specification?.seedDataBusiness?.length) },
|
|
126928
|
+
{ key: "tests", label: "tests", check: () => !!feature.analysis?.entities?.length }
|
|
126929
|
+
];
|
|
126930
|
+
for (const cat of categories) {
|
|
126931
|
+
const prdCount = ftc[cat.key]?.length ?? 0;
|
|
126932
|
+
const handoffCount = handoffFtc?.[cat.key]?.length ?? 0;
|
|
126933
|
+
if (prdCount === 0 && handoffCount > 0) {
|
|
126934
|
+
warnings.push(`${cat.label}: 0 files in PRD but ${handoffCount} in feature.json handoff`);
|
|
126935
|
+
} else if (prdCount === 0 && cat.check()) {
|
|
126936
|
+
warnings.push(`${cat.label}: 0 files but feature.json has relevant data`);
|
|
126937
|
+
}
|
|
126938
|
+
}
|
|
126939
|
+
return warnings;
|
|
126940
|
+
}
|
|
126941
|
+
function getPrdFileCounts(prd) {
|
|
126942
|
+
const ftc = prd.implementation.filesToCreate;
|
|
126943
|
+
return {
|
|
126944
|
+
domain: ftc.domain?.length ?? 0,
|
|
126945
|
+
application: ftc.application?.length ?? 0,
|
|
126946
|
+
infrastructure: ftc.infrastructure?.length ?? 0,
|
|
126947
|
+
api: ftc.api?.length ?? 0,
|
|
126948
|
+
frontend: ftc.frontend?.length ?? 0,
|
|
126949
|
+
seedData: ftc.seedData?.length ?? 0,
|
|
126950
|
+
tests: ftc.tests?.length ?? 0
|
|
126951
|
+
};
|
|
126952
|
+
}
|
|
126812
126953
|
|
|
126813
126954
|
// src/commands/derive-prd.ts
|
|
126814
126955
|
function readSmartStackNamespace() {
|
|
@@ -126897,12 +127038,26 @@ Processing module: ${source_default.bold(moduleName)}`));
|
|
|
126897
127038
|
}
|
|
126898
127039
|
await import_fs_extra9.default.writeJson(outputPath, prd, { spaces: 2 });
|
|
126899
127040
|
totalGenerated++;
|
|
127041
|
+
const completenessWarnings = validatePrdCompleteness(prd, featureJson);
|
|
127042
|
+
if (completenessWarnings.length > 0) {
|
|
127043
|
+
console.log(source_default.yellow(` Completeness warnings:`));
|
|
127044
|
+
for (const w of completenessWarnings) {
|
|
127045
|
+
console.log(source_default.yellow(` - ${w}`));
|
|
127046
|
+
}
|
|
127047
|
+
if (options.strict) {
|
|
127048
|
+
console.log(source_default.red(` Skipping ${moduleName} \u2014 incomplete PRD (--strict mode)`));
|
|
127049
|
+
totalErrors++;
|
|
127050
|
+
continue;
|
|
127051
|
+
}
|
|
127052
|
+
}
|
|
126900
127053
|
const relOutput = (0, import_path11.relative)(process.cwd(), outputPath);
|
|
126901
127054
|
console.log(source_default.green(` Generated: ${relOutput}`));
|
|
126902
127055
|
console.log(source_default.gray(` UCs: ${prd.requirements.useCases.length} | FRs: ${prd.requirements.functionalRequirements.length} | BRs: ${prd.businessRules.length}`));
|
|
126903
127056
|
console.log(source_default.gray(` Endpoints: ${prd.architecture.apiEndpoints.length} | Sections: ${prd.architecture.sections.length}`));
|
|
126904
|
-
const
|
|
126905
|
-
|
|
127057
|
+
const counts = getPrdFileCounts(prd);
|
|
127058
|
+
const totalFiles = Object.values(counts).reduce((s, n) => s + n, 0);
|
|
127059
|
+
console.log(source_default.gray(` Files to create: ${totalFiles} (domain: ${counts.domain}, app: ${counts.application}, infra: ${counts.infrastructure}, api: ${counts.api}, frontend: ${counts.frontend}, seed: ${counts.seedData}, tests: ${counts.tests})`));
|
|
127060
|
+
console.log(source_default.gray(` BR mappings: ${prd.implementation.brToCodeMapping.length}`));
|
|
126906
127061
|
}
|
|
126907
127062
|
console.log();
|
|
126908
127063
|
if (totalErrors > 0) {
|