@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.
- package/.documentation/agents.html +1 -371
- package/.documentation/cli-commands.html +1 -1
- package/.documentation/commands.html +1 -1
- package/.documentation/efcore.html +1 -1
- package/.documentation/gitflow.html +1 -1
- package/.documentation/hooks.html +27 -66
- package/.documentation/index.html +166 -166
- package/.documentation/init.html +6 -7
- package/.documentation/installation.html +1 -1
- package/.documentation/prd-json-v2.0.0.md +396 -0
- package/.documentation/ralph-loop.html +1 -9
- package/.documentation/test-web.html +15 -39
- package/.documentation/testing-ba-e2e.md +462 -0
- package/dist/index.js +23 -16
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
- package/templates/agents/gitflow/merge.md +56 -6
- package/templates/agents/gitflow/pr.md +70 -9
- package/templates/project/appsettings.json.template +8 -2
- package/templates/skills/business-analyse/SKILL.md +34 -17
- package/templates/skills/business-analyse/html/ba-interactive.html +147 -84
- package/templates/skills/business-analyse/questionnaire.md +20 -15
- package/templates/skills/business-analyse/steps/step-00-init.md +80 -57
- package/templates/skills/business-analyse/steps/step-03-specify.md +57 -0
- package/templates/skills/business-analyse/steps/step-05-handoff.md +480 -14
- package/templates/skills/business-analyse/steps/step-06-extract.md +131 -3
- package/templates/skills/gitflow/steps/step-pr.md +17 -5
- package/templates/skills/ralph-loop/SKILL.md +158 -33
- package/templates/skills/ralph-loop/steps/step-01-task.md +160 -18
- package/templates/skills/ralph-loop/steps/step-02-execute.md +408 -23
- package/templates/skills/ralph-loop/steps/step-03-commit.md +82 -0
- package/templates/skills/ralph-loop/steps/step-04-check.md +305 -9
- 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
|
-
|
|
44467
|
+
import_crypto2.default.randomFillSync(rnds8Pool);
|
|
44468
44468
|
poolPtr = 0;
|
|
44469
44469
|
}
|
|
44470
44470
|
return rnds8Pool.slice(poolPtr, poolPtr += 16);
|
|
44471
44471
|
}
|
|
44472
|
-
var
|
|
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
|
-
|
|
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
|
|
44681
|
+
return import_crypto3.default.createHash("md5").update(bytes).digest();
|
|
44682
44682
|
}
|
|
44683
|
-
var
|
|
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
|
-
|
|
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
|
|
44736
|
+
return import_crypto4.default.createHash("sha1").update(bytes).digest();
|
|
44737
44737
|
}
|
|
44738
|
-
var
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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);
|