@atlashub/smartstack-cli 3.0.0 → 3.2.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.
Files changed (33) hide show
  1. package/.documentation/agents.html +1 -371
  2. package/.documentation/cli-commands.html +1 -1
  3. package/.documentation/commands.html +1 -1
  4. package/.documentation/efcore.html +1 -1
  5. package/.documentation/gitflow.html +1 -1
  6. package/.documentation/hooks.html +27 -66
  7. package/.documentation/index.html +166 -166
  8. package/.documentation/init.html +6 -7
  9. package/.documentation/installation.html +1 -1
  10. package/.documentation/prd-json-v2.0.0.md +396 -0
  11. package/.documentation/ralph-loop.html +1 -9
  12. package/.documentation/test-web.html +15 -39
  13. package/.documentation/testing-ba-e2e.md +462 -0
  14. package/dist/index.js +23 -16
  15. package/dist/index.js.map +1 -1
  16. package/package.json +6 -2
  17. package/templates/agents/gitflow/merge.md +56 -6
  18. package/templates/agents/gitflow/pr.md +70 -9
  19. package/templates/project/appsettings.json.template +8 -2
  20. package/templates/skills/business-analyse/SKILL.md +34 -17
  21. package/templates/skills/business-analyse/html/ba-interactive.html +147 -84
  22. package/templates/skills/business-analyse/questionnaire.md +20 -15
  23. package/templates/skills/business-analyse/steps/step-00-init.md +80 -57
  24. package/templates/skills/business-analyse/steps/step-03-specify.md +57 -0
  25. package/templates/skills/business-analyse/steps/step-05-handoff.md +480 -14
  26. package/templates/skills/business-analyse/steps/step-06-extract.md +131 -3
  27. package/templates/skills/gitflow/steps/step-pr.md +17 -5
  28. package/templates/skills/ralph-loop/SKILL.md +158 -33
  29. package/templates/skills/ralph-loop/steps/step-01-task.md +160 -18
  30. package/templates/skills/ralph-loop/steps/step-02-execute.md +408 -23
  31. package/templates/skills/ralph-loop/steps/step-03-commit.md +82 -0
  32. package/templates/skills/ralph-loop/steps/step-04-check.md +305 -9
  33. package/templates/skills/ralph-loop/steps/step-05-report.md +115 -0
@@ -0,0 +1,462 @@
1
+ # Business Analyse E2E Testing Infrastructure
2
+
3
+ ## Vue d'ensemble
4
+
5
+ Infrastructure de tests E2E pour valider le pipeline complet **Business Analyse → Handoff → PRD extraction → Ralph Loop**.
6
+
7
+ **Garanties :**
8
+ - ✅ Validation déterministe du handoff
9
+ - ✅ Extraction programmatique prd.json (zéro hallucination)
10
+ - ✅ Reproductibilité parfaite
11
+ - ✅ Couverture complète des cas d'usage
12
+
13
+ ---
14
+
15
+ ## Architecture
16
+
17
+ ```
18
+ tests/ba/
19
+ ├── fixtures/ # Test data (feature.json examples)
20
+ │ ├── simple-feature.json # Module simple (Orders, 1 entity, 2 UCs, 3 BRs)
21
+ │ ├── medium-feature.json # Module medium (Invoices, lifecycle, 4 entities, 6 UCs)
22
+ │ ├── complex-application.json # Application multi-modules (3 modules, dépendances)
23
+ │ └── complex-app/ # Modules référencés par complex-application.json
24
+ │ ├── Customers/
25
+ │ ├── Products/
26
+ │ └── Orders/
27
+
28
+ └── e2e/ # Test suites E2E
29
+ ├── handoff-validation.test.ts # Validation handoff section
30
+ ├── prd-extraction-simple.test.ts # Extraction module simple
31
+ ├── prd-extraction-medium.test.ts # Extraction module lifecycle
32
+ └── full-pipeline.test.ts # Pipeline complet BA → Ralph Loop
33
+ ```
34
+
35
+ ---
36
+
37
+ ## Fixtures
38
+
39
+ ### simple-feature.json
40
+
41
+ **Module:** Orders
42
+ **Complexité:** Basique CRUD
43
+ **Contenu:**
44
+ - 1 entity (Order)
45
+ - 2 use cases (Create, List)
46
+ - 3 business rules (2 validation, 1 calculation)
47
+ - 2 API endpoints
48
+ - 4 permissions
49
+ - 7 file categories
50
+
51
+ **Use case:** Tester extraction basique sans lifecycle.
52
+
53
+ ### medium-feature.json
54
+
55
+ **Module:** Invoices
56
+ **Complexité:** Workflow avec lifecycle
57
+ **Contenu:**
58
+ - 4 entities (Invoice, InvoiceLine, Customer, Payment)
59
+ - 6 use cases (Create, Issue, Pay, List, View, Cancel)
60
+ - 6 business rules (2 validation, 2 workflow, 2 calculation)
61
+ - 3 API endpoints (dont 2 transitions)
62
+ - 1 lifecycle (4 états: draft → issued → paid, cancelled)
63
+ - 2 seedData business (InvoiceStatus, PaymentMethod)
64
+
65
+ **Use case:** Tester extraction avec lifecycle states et transitions.
66
+
67
+ ### complex-application.json + modules
68
+
69
+ **Application:** SalesManagement
70
+ **Complexité:** Multi-modules avec dépendances
71
+ **Contenu:**
72
+ - 3 modules: Customers, Products, Orders
73
+ - Dependency graph: Orders → Customers + Products
74
+ - 4 application roles (admin, manager, salesperson, viewer)
75
+
76
+ **Use case:** Tester mode `--application` et génération multi-prd.json.
77
+
78
+ ---
79
+
80
+ ## Tests E2E
81
+
82
+ ### 1. handoff-validation.test.ts
83
+
84
+ **Objectif:** Valider la fonction `validateForPrdExtraction()`.
85
+
86
+ **Scénarios:**
87
+ - ✅ Feature complet simple passe validation
88
+ - ✅ Feature complet medium passe validation
89
+ - ❌ Feature sans `metadata.application` échoue
90
+ - ❌ Feature sans `metadata.module` échoue
91
+ - ❌ Feature avec `status !== "handed-off|approved|consolidated"` échoue
92
+ - ❌ Feature sans use cases échoue
93
+ - ❌ Feature sans business rules échoue
94
+ - ❌ Feature sans `filesToCreate` échoue
95
+ - ✅ Feature avec status "approved" passe
96
+ - ✅ Feature avec status "consolidated" passe
97
+ - ✅ Medium feature a lifecycle défini (4 états)
98
+ - ✅ Medium feature a 7 catégories de fichiers
99
+ - ✅ BR to code mappings complets
100
+ - ✅ CORE seedData obligatoire (NavigationModule, Permission)
101
+
102
+ ### 2. prd-extraction-simple.test.ts
103
+
104
+ **Objectif:** Tester extraction prd.json pour module simple.
105
+
106
+ **Scénarios:**
107
+ - Extraction complète sans erreur
108
+ - Metadata projet (application, module, namespace)
109
+ - Use cases (2) avec actor, permission, steps, linkedRules
110
+ - Functional requirements (3) avec priority, linkedUCs
111
+ - Business rules (3) avec category, statement, priority
112
+ - Entities (1) avec attributes, type
113
+ - API endpoints (2) avec method, route, permission, linkedUC
114
+ - Permission matrix (4 permissions) avec scope
115
+ - Sections (1) avec resources
116
+ - FilesToCreate (7 catégories)
117
+ - BrToCodeMapping (2 mappings) avec targetFile, targetMethod, implementationType
118
+ - SeedData (core + business)
119
+ - Implementation strategy ("module-by-module")
120
+ - Source traceability (extractedAt, featureJsonPath)
121
+
122
+ ### 3. prd-extraction-medium.test.ts
123
+
124
+ **Objectif:** Tester extraction prd.json avec lifecycle.
125
+
126
+ **Scénarios:**
127
+ - Extraction complète avec lifecycle
128
+ - Multiple entities (4) avec relationships
129
+ - Lifecycle states (4) avec allowedTransitions
130
+ - Lifecycle transitions (2) avec action, permission, guards
131
+ - Terminal states (2: paid, cancelled)
132
+ - Workflow business rules (2) mappés au code
133
+ - Calculation business rules (2) avec formulas
134
+ - Multiple use cases (6) incluant transitions
135
+ - Transition API endpoints (2: /issue, /pay)
136
+ - Multiple seedData business entities (2)
137
+ - Multiple domain files (4 entities)
138
+ - Integration tests en plus des unit tests
139
+ - BR mappings complets pour critical rules
140
+
141
+ ### 4. full-pipeline.test.ts
142
+
143
+ **Objectif:** Tester pipeline complet BA → Ralph Loop.
144
+
145
+ **Scénarios:**
146
+
147
+ **Simple Module Pipeline:**
148
+ 1. Load feature.json (status = "handed-off")
149
+ 2. Validate handoff section complet
150
+ 3. Extract prd.json déterministe
151
+ 4. Write prd.json to .ralph/
152
+ 5. Read back prd.json (verify integrity)
153
+ 6. Verify all required sections for Ralph Loop
154
+ 7. Verify prd.json meets Ralph Loop requirements (7 categories, BR mappings, CORE seedData)
155
+
156
+ **Medium Module Pipeline with Lifecycle:**
157
+ 1. Load medium feature with lifecycle
158
+ 2. Validate handoff including lifecycle
159
+ 3. Extract prd.json with lifecycle preserved
160
+ 4. Verify lifecycle transitions mapped to BR
161
+ 5. Verify lifecycle states match seedData
162
+ 6. Write prd.json to .ralph/
163
+
164
+ **Reproducibility Test:**
165
+ - Multiple extractions = identical prd.json (sans timestamp)
166
+
167
+ **Error Handling:**
168
+ - Missing optional namespace handled gracefully
169
+ - Empty arrays handled gracefully
170
+
171
+ **Integration with Ralph Loop:**
172
+ - All required information present (entities, UCs, BRs, endpoints, permissions, filesToCreate, BR mappings, CORE seedData)
173
+ - Use cases linked to API endpoints
174
+ - Business rules linked to use cases
175
+
176
+ ---
177
+
178
+ ## Exécution des Tests
179
+
180
+ ### Installation
181
+
182
+ ```bash
183
+ # Les dépendances de test sont déjà installées (vitest, @vitest/coverage-v8)
184
+ npm install
185
+ ```
186
+
187
+ ### Commandes
188
+
189
+ ```bash
190
+ # Exécuter tous les tests BA E2E
191
+ npm run test:ba
192
+
193
+ # Exécuter tests BA E2E en mode watch (développement)
194
+ npm run test:ba:watch
195
+
196
+ # Exécuter tests BA E2E avec couverture
197
+ npm run test:ba:coverage
198
+
199
+ # Exécuter TOUS les tests (MCP + BA)
200
+ npm run test:all
201
+ ```
202
+
203
+ ### Filtrage des Tests
204
+
205
+ ```bash
206
+ # Exécuter un seul fichier de test
207
+ npx vitest run tests/ba/e2e/handoff-validation.test.ts
208
+
209
+ # Exécuter tests contenant "lifecycle" dans le nom
210
+ npx vitest run --grep lifecycle
211
+
212
+ # Exécuter tests en mode watch avec filtrage
213
+ npx vitest --grep extraction
214
+ ```
215
+
216
+ ### Couverture de Code
217
+
218
+ ```bash
219
+ npm run test:ba:coverage
220
+
221
+ # Rapport généré dans: coverage/
222
+ # Ouvrir: coverage/index.html
223
+ ```
224
+
225
+ ---
226
+
227
+ ## Ajouter de Nouveaux Tests
228
+
229
+ ### 1. Créer une Nouvelle Fixture
230
+
231
+ Créer `tests/ba/fixtures/my-feature.json` :
232
+
233
+ ```json
234
+ {
235
+ "id": "FEAT-TEST-XXX",
236
+ "version": "5.0.0",
237
+ "status": "handed-off",
238
+ "metadata": {
239
+ "application": "MyApp",
240
+ "module": "MyModule",
241
+ "context": "business"
242
+ },
243
+ "discovery": { ... },
244
+ "analysis": {
245
+ "businessRules": [...],
246
+ "entities": [...]
247
+ },
248
+ "specification": {
249
+ "useCases": [...],
250
+ "functionalRequirements": [...],
251
+ "apiEndpoints": [...],
252
+ "permissionMatrix": { ... },
253
+ "sections": [...],
254
+ "seedDataCore": [...]
255
+ },
256
+ "handoff": {
257
+ "implementationStrategy": "module-by-module",
258
+ "filesToCreate": {
259
+ "domain": [...],
260
+ "application": [...],
261
+ "infrastructure": [...],
262
+ "api": [...],
263
+ "frontend": [...],
264
+ "seedData": [...],
265
+ "tests": [...]
266
+ },
267
+ "brToCodeMapping": [...]
268
+ }
269
+ }
270
+ ```
271
+
272
+ **Checklist fixture valide:**
273
+ - ✅ `status` = "handed-off" | "approved" | "consolidated"
274
+ - ✅ `metadata.application` et `metadata.module` présents
275
+ - ✅ `specification.useCases[]` non vide
276
+ - ✅ `analysis.businessRules[]` non vide
277
+ - ✅ `handoff.filesToCreate` avec 7 catégories
278
+ - ✅ `specification.seedDataCore` avec NavigationModule + Permission
279
+
280
+ ### 2. Créer un Nouveau Test
281
+
282
+ Créer `tests/ba/e2e/my-test.test.ts` :
283
+
284
+ ```typescript
285
+ import { describe, it, expect } from 'vitest';
286
+ import { extractPrd, validateForPrdExtraction } from '../../../src/utils/prd-extractor.js';
287
+ import type { ModuleFeatureJson } from '../../../src/types/feature-json.js';
288
+ import fs from 'fs-extra';
289
+ import { join } from 'path';
290
+
291
+ describe('My Test Suite', () => {
292
+ const fixturesDir = join(__dirname, '../fixtures');
293
+
294
+ it('should validate my scenario', async () => {
295
+ const feature = await fs.readJson(join(fixturesDir, 'my-feature.json')) as ModuleFeatureJson;
296
+ const errors = validateForPrdExtraction(feature);
297
+
298
+ expect(errors).toEqual([]);
299
+ });
300
+
301
+ it('should extract prd.json correctly', () => {
302
+ const feature = await fs.readJson(join(fixturesDir, 'my-feature.json')) as ModuleFeatureJson;
303
+ const prd = extractPrd(feature, 'my-feature.json', 'MyCompany.MyApp');
304
+
305
+ expect(prd.version).toBe('2.0.0');
306
+ expect(prd.project.module).toBe('MyModule');
307
+ // ... more assertions
308
+ });
309
+ });
310
+ ```
311
+
312
+ ### 3. Exécuter le Nouveau Test
313
+
314
+ ```bash
315
+ npx vitest run tests/ba/e2e/my-test.test.ts
316
+ ```
317
+
318
+ ---
319
+
320
+ ## Intégration CI/CD
321
+
322
+ ### Azure Pipelines
323
+
324
+ Ajouter dans `azure-pipelines.yml` :
325
+
326
+ ```yaml
327
+ - stage: Test
328
+ jobs:
329
+ - job: UnitTests
330
+ steps:
331
+ - task: Npm@1
332
+ inputs:
333
+ command: 'custom'
334
+ customCommand: 'run test:ba'
335
+ displayName: 'Run BA E2E Tests'
336
+
337
+ - task: PublishTestResults@2
338
+ inputs:
339
+ testResultsFormat: 'JUnit'
340
+ testResultsFiles: '**/test-results.xml'
341
+ displayName: 'Publish Test Results'
342
+
343
+ - task: PublishCodeCoverageResults@1
344
+ inputs:
345
+ codeCoverageTool: 'Cobertura'
346
+ summaryFileLocation: '**/coverage/cobertura-coverage.xml'
347
+ displayName: 'Publish Code Coverage'
348
+ ```
349
+
350
+ ### GitHub Actions
351
+
352
+ ```yaml
353
+ name: Tests
354
+ on: [push, pull_request]
355
+
356
+ jobs:
357
+ test:
358
+ runs-on: ubuntu-latest
359
+ steps:
360
+ - uses: actions/checkout@v3
361
+ - uses: actions/setup-node@v3
362
+ with:
363
+ node-version: '18'
364
+ - run: npm install
365
+ - run: npm run test:ba
366
+ - name: Upload coverage
367
+ uses: codecov/codecov-action@v3
368
+ with:
369
+ files: ./coverage/coverage-final.json
370
+ ```
371
+
372
+ ---
373
+
374
+ ## Métriques de Qualité
375
+
376
+ ### Objectifs de Couverture
377
+
378
+ | Fichier | Couverture Cible |
379
+ |---------|-----------------|
380
+ | `src/utils/prd-extractor.ts` | 100% |
381
+ | `src/commands/derive-prd.ts` | 90% |
382
+ | `templates/skills/business-analyse/**/*.md` | N/A (documentation) |
383
+
384
+ ### KPIs Tests
385
+
386
+ - **Total tests:** ~60 scénarios
387
+ - **Temps d'exécution:** < 10s
388
+ - **Fixtures:** 3 (simple/medium/complex)
389
+ - **Couverture code:** > 95% sur extraction pipeline
390
+
391
+ ---
392
+
393
+ ## Dépannage
394
+
395
+ ### Erreur: "Cannot find module '...'"
396
+
397
+ **Cause:** Imports relatifs incorrects ou TypeScript non compilé.
398
+
399
+ **Solution:**
400
+ ```bash
401
+ npm run build
402
+ npm run test:ba
403
+ ```
404
+
405
+ ### Erreur: "Feature status is X"
406
+
407
+ **Cause:** Fixture a `status !== "handed-off"`.
408
+
409
+ **Solution:** Mettre `status: "handed-off"` dans la fixture.
410
+
411
+ ### Erreur: "No use cases found"
412
+
413
+ **Cause:** `specification.useCases[]` est vide dans la fixture.
414
+
415
+ **Solution:** Ajouter au moins 1 use case dans la fixture.
416
+
417
+ ### Tests timeouts
418
+
419
+ **Cause:** Tests E2E dépassent 30s.
420
+
421
+ **Solution:** Augmenter `testTimeout` dans `vitest.ba.config.ts` :
422
+
423
+ ```typescript
424
+ export default defineConfig({
425
+ test: {
426
+ testTimeout: 60000, // 60s
427
+ },
428
+ });
429
+ ```
430
+
431
+ ---
432
+
433
+ ## Roadmap
434
+
435
+ ### Phase 1 ✅ (Implémenté)
436
+ - Infrastructure Vitest
437
+ - 3 fixtures (simple/medium/complex)
438
+ - 4 test suites (handoff-validation, prd-extraction x2, full-pipeline)
439
+ - Scripts npm
440
+ - Documentation
441
+
442
+ ### Phase 2 (Futur)
443
+ - Tests pour mode `--application` (extraction multi-modules)
444
+ - Tests pour mode `--strict`
445
+ - Tests pour cross-module dependencies
446
+ - Performance benchmarks (extraction < 100ms)
447
+ - Tests pour ba-interactive.html extraction
448
+
449
+ ### Phase 3 (Futur)
450
+ - Tests E2E Ralph Loop integration (mock Ralph Loop server)
451
+ - Tests pour step-05-handoff.md (génération handoff)
452
+ - Tests pour derive-prd CLI (end-to-end avec fs.existsSync)
453
+ - Tests pour validation schema (feature-schema.json)
454
+
455
+ ---
456
+
457
+ ## Voir aussi
458
+
459
+ - [prd-json v2.0.0 Reference](./prd-json-v2.0.0.md)
460
+ - [Feature JSON Schema](../templates/skills/business-analyse/schemas/feature-schema.json)
461
+ - [Business Analyse Skill](../templates/skills/business-analyse/SKILL.md)
462
+ - [Ralph Loop Documentation](../templates/skills/ralph-loop/SKILL.md)
package/dist/index.js CHANGED
@@ -44464,16 +44464,16 @@ var require_chainedTokenCredential = __commonJS({
44464
44464
  // node_modules/uuid/dist/esm-node/rng.js
44465
44465
  function rng() {
44466
44466
  if (poolPtr > rnds8Pool.length - 16) {
44467
- import_crypto4.default.randomFillSync(rnds8Pool);
44467
+ import_crypto2.default.randomFillSync(rnds8Pool);
44468
44468
  poolPtr = 0;
44469
44469
  }
44470
44470
  return rnds8Pool.slice(poolPtr, poolPtr += 16);
44471
44471
  }
44472
- var import_crypto4, rnds8Pool, poolPtr;
44472
+ var import_crypto2, rnds8Pool, poolPtr;
44473
44473
  var init_rng = __esm({
44474
44474
  "node_modules/uuid/dist/esm-node/rng.js"() {
44475
44475
  "use strict";
44476
- import_crypto4 = __toESM(require("crypto"));
44476
+ import_crypto2 = __toESM(require("crypto"));
44477
44477
  rnds8Pool = new Uint8Array(256);
44478
44478
  poolPtr = rnds8Pool.length;
44479
44479
  }
@@ -44678,13 +44678,13 @@ function md5(bytes) {
44678
44678
  } else if (typeof bytes === "string") {
44679
44679
  bytes = Buffer.from(bytes, "utf8");
44680
44680
  }
44681
- return import_crypto5.default.createHash("md5").update(bytes).digest();
44681
+ return import_crypto3.default.createHash("md5").update(bytes).digest();
44682
44682
  }
44683
- var import_crypto5, md5_default;
44683
+ var import_crypto3, md5_default;
44684
44684
  var init_md5 = __esm({
44685
44685
  "node_modules/uuid/dist/esm-node/md5.js"() {
44686
44686
  "use strict";
44687
- import_crypto5 = __toESM(require("crypto"));
44687
+ import_crypto3 = __toESM(require("crypto"));
44688
44688
  md5_default = md5;
44689
44689
  }
44690
44690
  });
@@ -44733,13 +44733,13 @@ function sha1(bytes) {
44733
44733
  } else if (typeof bytes === "string") {
44734
44734
  bytes = Buffer.from(bytes, "utf8");
44735
44735
  }
44736
- return import_crypto6.default.createHash("sha1").update(bytes).digest();
44736
+ return import_crypto4.default.createHash("sha1").update(bytes).digest();
44737
44737
  }
44738
- var import_crypto6, sha1_default;
44738
+ var import_crypto4, sha1_default;
44739
44739
  var init_sha1 = __esm({
44740
44740
  "node_modules/uuid/dist/esm-node/sha1.js"() {
44741
44741
  "use strict";
44742
- import_crypto6 = __toESM(require("crypto"));
44742
+ import_crypto4 = __toESM(require("crypto"));
44743
44743
  sha1_default = sha1;
44744
44744
  }
44745
44745
  });
@@ -115955,7 +115955,6 @@ var import_fs_extra5 = __toESM(require_lib());
115955
115955
  var import_path6 = require("path");
115956
115956
  var import_os3 = require("os");
115957
115957
  var import_child_process5 = require("child_process");
115958
- var import_crypto2 = require("crypto");
115959
115958
 
115960
115959
  // src/lib/file-tracker.ts
115961
115960
  var import_crypto = require("crypto");
@@ -116689,11 +116688,11 @@ EndGlobal
116689
116688
  throw new Error(`Template not found: ${templatePath}`);
116690
116689
  }
116691
116690
  let appSettingsContent = await import_fs_extra5.default.readFile(templatePath, "utf-8");
116692
- const randomSecret = (0, import_crypto2.randomBytes)(32).toString("hex");
116693
- appSettingsContent = appSettingsContent.replace(/\{\{ProjectName\}\}/g, projectName).replace(/\{\{GenerateRandomSecret\}\}/g, randomSecret).replace(/\{\{ProjectDomain\}\}/g, `${projectName.toLowerCase()}.app`).replace(/\{\{ProjectNameLower\}\}/g, projectName.toLowerCase());
116691
+ appSettingsContent = appSettingsContent.replace(/\{\{ProjectName\}\}/g, projectName).replace(/\{\{ProjectDomain\}\}/g, `${projectName.toLowerCase()}.app`).replace(/\{\{ProjectNameLower\}\}/g, projectName.toLowerCase());
116694
116692
  const appSettings = JSON.parse(appSettingsContent);
116695
116693
  appSettings.MultiTenant = {
116696
116694
  Enabled: config.multiTenant.enabled,
116695
+ EnableB2B: config.multiTenant.enableB2B,
116697
116696
  EnableB2C: config.multiTenant.enableB2C,
116698
116697
  SystemTenantSlug: config.multiTenant.systemTenantSlug,
116699
116698
  SystemTenantName: config.multiTenant.systemTenantName,
@@ -117426,7 +117425,7 @@ async function initializeGit(config, dryRun) {
117426
117425
  execCommand(`git commit -m "${commitMsg}"`, projectDir, dryRun);
117427
117426
  }
117428
117427
  }
117429
- var initCommand = new Command("init").description("Initialize a new SmartStack project").argument("[name]", "Project name (optional, uses current folder if not provided)").option("--dry-run", "Show what would be created without actually creating").option("-y, --yes", "Skip prompts and use defaults").option("--skip-mcp-check", "Skip MCP servers verification").option("--multi-tenant", "Enable multi-tenant mode").option("--b2c", "Enable B2C (user tenant management)").option("--preview", "Use preview/prerelease versions (NuGet --prerelease + npm @next)").option("--here", "Initialize in current directory (use folder name as project name)").action(async (name, options) => {
117428
+ var initCommand = new Command("init").description("Initialize a new SmartStack project").argument("[name]", "Project name (optional, uses current folder if not provided)").option("--dry-run", "Show what would be created without actually creating").option("-y, --yes", "Skip prompts and use defaults").option("--skip-mcp-check", "Skip MCP servers verification").option("--multi-tenant", "Enable multi-tenant mode").option("--b2b", "Enable B2B (organisation management)").option("--b2c", "Enable B2C (user tenant management)").option("--preview", "Use preview/prerelease versions (NuGet --prerelease + npm @next)").option("--here", "Initialize in current directory (use folder name as project name)").action(async (name, options) => {
117430
117429
  logger.header("SmartStack Project Initialization");
117431
117430
  if (!options.skipMcpCheck) {
117432
117431
  logger.info("Checking MCP servers...");
@@ -117666,6 +117665,7 @@ var initCommand = new Command("init").description("Initialize a new SmartStack p
117666
117665
  projectDir: finalProjectDir,
117667
117666
  multiTenant: {
117668
117667
  enabled: options.multiTenant ?? true,
117668
+ enableB2B: options.b2b ?? true,
117669
117669
  enableB2C: options.b2c ?? true,
117670
117670
  systemTenantSlug: "default",
117671
117671
  systemTenantName: "Default Workspace",
@@ -117680,6 +117680,13 @@ var initCommand = new Command("init").description("Initialize a new SmartStack p
117680
117680
  message: "Enable multi-tenant mode?",
117681
117681
  default: true
117682
117682
  },
117683
+ {
117684
+ type: "confirm",
117685
+ name: "enableB2B",
117686
+ message: "Enable B2B (organisation management)?",
117687
+ default: true,
117688
+ when: (answers2) => answers2.multiTenantEnabled
117689
+ },
117683
117690
  {
117684
117691
  type: "confirm",
117685
117692
  name: "enableB2C",
@@ -117710,6 +117717,7 @@ var initCommand = new Command("init").description("Initialize a new SmartStack p
117710
117717
  projectDir: finalProjectDir,
117711
117718
  multiTenant: {
117712
117719
  enabled: answers.multiTenantEnabled ?? true,
117720
+ enableB2B: answers.enableB2B ?? true,
117713
117721
  enableB2C: answers.enableB2C ?? true,
117714
117722
  systemTenantSlug: answers.systemTenantSlug || "default",
117715
117723
  systemTenantName: answers.systemTenantName || "Default Workspace",
@@ -117727,6 +117735,7 @@ var initCommand = new Command("init").description("Initialize a new SmartStack p
117727
117735
  logger.info(`Preview mode: ${config.preview ? source_default.yellow("Enabled (prerelease)") : source_default.gray("Disabled (stable)")}`);
117728
117736
  logger.info(`Multi-Tenant: ${config.multiTenant.enabled ? source_default.green("Enabled") : source_default.gray("Disabled")}`);
117729
117737
  if (config.multiTenant.enabled) {
117738
+ logger.info(` B2B (Organisations): ${config.multiTenant.enableB2B ? source_default.green("Enabled") : source_default.gray("Disabled")}`);
117730
117739
  logger.info(` B2C (User Tenants): ${config.multiTenant.enableB2C ? source_default.green("Enabled") : source_default.gray("Disabled")}`);
117731
117740
  logger.info(` System Tenant: ${source_default.cyan(config.multiTenant.systemTenantSlug)} (${config.multiTenant.systemTenantName})`);
117732
117741
  }
@@ -124550,7 +124559,6 @@ var glob = Object.assign(glob_, {
124550
124559
  glob.glob = glob;
124551
124560
 
124552
124561
  // src/lib/config-sync.ts
124553
- var import_crypto3 = require("crypto");
124554
124562
  function addMissingKeys(target, template, prefix = "") {
124555
124563
  const added = [];
124556
124564
  for (const key of Object.keys(template)) {
@@ -124570,8 +124578,7 @@ function addMissingKeys(target, template, prefix = "") {
124570
124578
  return added;
124571
124579
  }
124572
124580
  function resolveTemplatePlaceholders(content, projectName) {
124573
- const secret = (0, import_crypto3.randomBytes)(32).toString("hex");
124574
- return content.replace(/\{\{ProjectName\}\}/g, projectName).replace(/\{\{GenerateRandomSecret\}\}/g, secret).replace(/\{\{ProjectDomain\}\}/g, `${projectName.toLowerCase()}.app`).replace(/\{\{ProjectNameLower\}\}/g, projectName.toLowerCase());
124581
+ return content.replace(/\{\{ProjectName\}\}/g, projectName).replace(/\{\{ProjectDomain\}\}/g, `${projectName.toLowerCase()}.app`).replace(/\{\{ProjectNameLower\}\}/g, projectName.toLowerCase());
124575
124582
  }
124576
124583
  function isPlainObject(value) {
124577
124584
  return typeof value === "object" && value !== null && !Array.isArray(value);