@atlashub/smartstack-cli 4.23.0 → 4.25.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 (27) hide show
  1. package/package.json +1 -1
  2. package/templates/skills/ba-generate-html/html/ba-interactive.html +950 -1055
  3. package/templates/skills/ba-generate-html/html/src/scripts/01-data-init.js +1 -2
  4. package/templates/skills/ba-generate-html/html/src/scripts/02-navigation.js +0 -1
  5. package/templates/skills/ba-generate-html/html/src/scripts/03-render-cadrage.js +0 -39
  6. package/templates/skills/ba-generate-html/html/src/scripts/05-render-specs.js +0 -1
  7. package/templates/skills/ba-generate-html/html/src/scripts/07-render-handoff.js +0 -1
  8. package/templates/skills/ba-generate-html/html/src/scripts/08-editing.js +133 -135
  9. package/templates/skills/ba-generate-html/html/src/scripts/10-comments.js +199 -199
  10. package/templates/skills/ba-generate-html/html/src/scripts/11-review-panel.js +165 -166
  11. package/templates/skills/ba-generate-html/html/src/styles/05-modules.css +444 -454
  12. package/templates/skills/ba-generate-html/html/src/template.html +0 -49
  13. package/templates/skills/ba-generate-html/references/data-build.md +176 -182
  14. package/templates/skills/ba-generate-html/references/data-mapping.md +295 -301
  15. package/templates/skills/ba-generate-html/steps/step-01-collect.md +1 -1
  16. package/templates/skills/ba-generate-html/steps/step-02-build-data.md +0 -9
  17. package/templates/skills/derive-prd/SKILL.md +9 -9
  18. package/templates/skills/derive-prd/references/acceptance-criteria.md +166 -116
  19. package/templates/skills/derive-prd/references/entity-domain-mapping.md +5 -5
  20. package/templates/skills/derive-prd/references/handoff-file-templates.md +12 -12
  21. package/templates/skills/derive-prd/references/handoff-mappings.md +13 -14
  22. package/templates/skills/derive-prd/references/handoff-seeddata-generation.md +1 -1
  23. package/templates/skills/derive-prd/references/readiness-scoring.md +41 -50
  24. package/templates/skills/derive-prd/schemas/handoff-schema.json +2 -2
  25. package/templates/skills/derive-prd/steps/step-00-validate.md +73 -52
  26. package/templates/skills/derive-prd/steps/step-01-transform.md +86 -43
  27. package/templates/skills/ba-generate-html/html/src/partials/cadrage-risks.html +0 -48
@@ -15,7 +15,6 @@ data.specComments = data.specComments || {};
15
15
  data.customRoles = data.customRoles || [];
16
16
  data.customActions = data.customActions || [];
17
17
  data.cadrage.criteria = data.cadrage.criteria || [];
18
- data.cadrage.risks = data.cadrage.risks || [];
19
18
  data.consolidation = data.consolidation || {};
20
19
  data.consolidation.e2eFlows = data.consolidation.e2eFlows || [];
21
20
 
@@ -151,7 +150,6 @@ document.addEventListener('DOMContentLoaded', function() {
151
150
  }
152
151
  renderStakeholders();
153
152
  renderScope();
154
- renderRisks();
155
153
  renderCriteria();
156
154
  renderModules();
157
155
  renderDependencies();
@@ -163,4 +161,5 @@ document.addEventListener('DOMContentLoaded', function() {
163
161
  updateDepSelects();
164
162
  initInlineComments();
165
163
  renderReviewPanel();
164
+ showSection(currentSectionId);
166
165
  });
@@ -113,7 +113,6 @@ function buildCadrageItems() {
113
113
  return renderNavItem('cadrage-context', 'Contexte') +
114
114
  renderNavItem('cadrage-stakeholders', 'Parties prenantes', data.cadrage.stakeholders.length) +
115
115
  renderNavItem('cadrage-scope', 'Perimetre fonctionnel') +
116
- (isVibeCoding ? '' : renderNavItem('cadrage-risks', 'Risques et hypotheses', data.cadrage.risks.length)) +
117
116
  renderNavItem('cadrage-success', 'Criteres de reussite');
118
117
  }
119
118
 
@@ -144,45 +144,6 @@ function renderCriteria() {
144
144
  `).join('');
145
145
  }
146
146
 
147
- /* ============================================
148
- RISKS
149
- ============================================ */
150
- function addRisk() {
151
- const desc = document.getElementById('risk-desc').value.trim();
152
- if (!desc) return;
153
-
154
- data.cadrage.risks.push({
155
- description: desc,
156
- probability: document.getElementById('risk-probability').value,
157
- impact: document.getElementById('risk-impact').value,
158
- mitigation: document.getElementById('risk-mitigation').value.trim()
159
- });
160
-
161
- renderRisks();
162
- toggleForm('addRiskForm');
163
- clearForm('addRiskForm');
164
- autoSave();
165
- }
166
-
167
- function renderRisks() {
168
- const list = document.getElementById('risksList');
169
- list.innerHTML = data.cadrage.risks.map((r, i) => {
170
- const level = (r.probability === 'high' && r.impact === 'high') ? 'critical'
171
- : (r.probability === 'low' && r.impact === 'low') ? 'low' : 'medium';
172
- return `
173
- <div class="risk-item">
174
- <div class="risk-level risk-${level}"></div>
175
- <div>
176
- <div class="risk-text">${r.description}</div>
177
- ${r.mitigation ? '<div style="font-size:0.75rem;color:var(--text-muted);margin-top:0.25rem;">Prevention : ' + r.mitigation + '</div>' : ''}
178
- </div>
179
- <div class="risk-probability">${formatLevel(r.probability)}</div>
180
- <div class="risk-impact">${formatLevel(r.impact)}</div>
181
- </div>
182
- `;
183
- }).join('');
184
- }
185
-
186
147
  /* ============================================
187
148
  CONTEXT RENDERING (merged problem/current/vision)
188
149
  ============================================ */
@@ -487,7 +487,6 @@ function renderWireframeMockup(code, wf, i) {
487
487
  </div>
488
488
  `;
489
489
  }
490
- }
491
490
 
492
491
  function toggleWireframeView(wireframeId, view) {
493
492
  const container = document.getElementById(wireframeId);
@@ -24,7 +24,6 @@ function renderHandoffStats() {
24
24
  <div class="stat-card"><div class="stat-value">${totalStakeholders}</div><div class="stat-label">Profils utilisateurs</div></div>
25
25
  <div class="stat-card"><div class="stat-value">${data.dependencies.length}</div><div class="stat-label">Dependances</div></div>
26
26
  <div class="stat-card"><div class="stat-value">${data.consolidation.e2eFlows.length}</div><div class="stat-label">Parcours bout en bout</div></div>
27
- ${isVibeCoding ? '' : `<div class="stat-card"><div class="stat-value">${data.cadrage.risks.length}</div><div class="stat-label">Risques identifies</div></div>`}
28
27
  `;
29
28
  }
30
29
 
@@ -1,135 +1,133 @@
1
- /* ============================================
2
- PERSISTENCE
3
- ============================================ */
4
- function autoSave() {
5
- data.metadata.lastModified = new Date().toISOString();
6
- localStorage.setItem(APP_KEY, JSON.stringify(data));
7
- }
8
-
9
- function saveToLocalStorage() {
10
- autoSave();
11
- showNotification('Modifications sauvegardees');
12
- }
13
-
14
- function resetToEmbedded() {
15
- if (!confirm('Reinitialiser toutes les donnees depuis la version d\'origine ? Vos modifications locales (commentaires, notes) seront perdues.')) return;
16
- localStorage.removeItem(APP_KEY);
17
- // Restore data from ORIGINAL_DATA
18
- Object.keys(data).forEach(k => delete data[k]);
19
- Object.assign(data, JSON.parse(JSON.stringify(ORIGINAL_DATA)));
20
- // Re-render everything
21
- initEditableFields();
22
- renderStakeholders();
23
- renderScope();
24
- renderRisks();
25
- renderCriteria();
26
- renderModules();
27
- renderDependencies();
28
- renderAllModuleSpecs();
29
- renderConsolidation();
30
- renderHandoff();
31
- renderE2EFlows();
32
- updateCounts();
33
- renderReviewPanel();
34
- showNotification('Donnees reinitialisees depuis la version d\'origine');
35
- }
36
-
37
- function loadFromLocalStorage() {
38
- const saved = localStorage.getItem(APP_KEY);
39
- if (!saved) return;
40
-
41
- try {
42
- const parsed = JSON.parse(saved);
43
-
44
- // Build fingerprint of embedded structural data to detect HTML regeneration
45
- const embeddedFingerprint = ORIGINAL_DATA.modules.map(m => m.code).sort().join(',')
46
- + '|' + (ORIGINAL_DATA.metadata?.createdAt || '')
47
- + '|' + ORIGINAL_DATA.modules.length;
48
- const cachedFingerprint = parsed._structureFingerprint || '';
49
-
50
- const structureChanged = embeddedFingerprint !== cachedFingerprint;
51
- const embeddedModuleCount = ORIGINAL_DATA.modules?.length || 0;
52
- const cachedModuleCount = (parsed.modules || []).length;
53
- const hasNewModules = embeddedModuleCount > cachedModuleCount;
54
- const embeddedModuleCodes = new Set(ORIGINAL_DATA.modules.map(m => m.code));
55
- const cachedModuleCodes = new Set((parsed.modules || []).map(m => m.code));
56
- const missingModules = [...embeddedModuleCodes].filter(c => !cachedModuleCodes.has(c));
57
-
58
- if (structureChanged || hasNewModules || missingModules.length > 0) {
59
- // HTML was regenerated or has new modules — keep embedded structural data
60
- // Only restore user-specific edits (comments, custom roles, notes)
61
- data.wireframeComments = parsed.wireframeComments || {};
62
- data.specComments = parsed.specComments || {};
63
- data.customRoles = parsed.customRoles || [];
64
- data.customActions = parsed.customActions || [];
65
- data.comments = parsed.comments || [];
66
-
67
- // Merge user-added notes per module (preserve existing module notes)
68
- for (const code of Object.keys(parsed.moduleSpecs || {})) {
69
- if (data.moduleSpecs[code] && parsed.moduleSpecs[code]?.notes) {
70
- data.moduleSpecs[code].notes = parsed.moduleSpecs[code].notes;
71
- }
72
- }
73
-
74
- // Save fresh embedded data with fingerprint
75
- data._structureFingerprint = embeddedFingerprint;
76
- autoSave();
77
- } else {
78
- // Cache matches current structure safe to restore user edits on cadrage/notes
79
- // IMPORTANT: Always keep embedded modules and moduleSpecs as structural source of truth
80
- // Only merge cadrage user-editable fields and notes
81
- if (parsed.cadrage) {
82
- // Merge cadrage context (user may have edited text fields)
83
- if (parsed.cadrage.context) {
84
- data.cadrage.context = { ...data.cadrage.context, ...parsed.cadrage.context };
85
- }
86
- // Merge scope only if user added items interactively
87
- if (parsed.cadrage.scope) {
88
- data.cadrage.scope = { ...data.cadrage.scope, ...parsed.cadrage.scope };
89
- }
90
- // Merge stakeholders and risks if user edited them
91
- if (parsed.cadrage.stakeholders) data.cadrage.stakeholders = parsed.cadrage.stakeholders;
92
- if (parsed.cadrage.risks) data.cadrage.risks = parsed.cadrage.risks;
93
- }
94
- data.dependencies = parsed.dependencies || data.dependencies;
95
- data.consolidation = { ...data.consolidation, ...(parsed.consolidation || {}) };
96
-
97
- // Merge moduleSpecs: keep embedded structure, overlay user-editable fields (notes, custom permissions)
98
- for (const code of Object.keys(data.moduleSpecs)) {
99
- const cached = parsed.moduleSpecs?.[code];
100
- if (cached) {
101
- // Preserve user notes
102
- if (cached.notes) data.moduleSpecs[code].notes = cached.notes;
103
- // Preserve user-added use cases/rules/entities (merged with embedded)
104
- // Only add items that don't exist in embedded (by name match)
105
- const embeddedUcNames = new Set((data.moduleSpecs[code].useCases || []).map(uc => uc.name));
106
- (cached.useCases || []).forEach(uc => {
107
- if (!embeddedUcNames.has(uc.name)) data.moduleSpecs[code].useCases.push(uc);
108
- });
109
- const embeddedBrNames = new Set((data.moduleSpecs[code].businessRules || []).map(br => br.name));
110
- (cached.businessRules || []).forEach(br => {
111
- if (!embeddedBrNames.has(br.name)) data.moduleSpecs[code].businessRules.push(br);
112
- });
113
- // Preserve user permissions edits
114
- if (cached.permissions) data.moduleSpecs[code].permissions = cached.permissions;
115
- }
116
- }
117
-
118
- data.wireframeComments = parsed.wireframeComments || {};
119
- data.specComments = parsed.specComments || {};
120
- data.customRoles = parsed.customRoles || [];
121
- data.customActions = parsed.customActions || [];
122
- data.comments = parsed.comments || [];
123
-
124
- // Update fingerprint
125
- data._structureFingerprint = embeddedFingerprint;
126
- autoSave();
127
- }
128
-
129
- // Restore editable fields
130
- document.querySelectorAll('.editable[data-field]').forEach(el => {
131
- const value = getNestedValue(data, 'cadrage.' + el.dataset.field);
132
- if (value) el.textContent = value;
133
- });
134
- } catch (e) { console.error('Error loading saved data:', e); }
135
- }
1
+ /* ============================================
2
+ PERSISTENCE
3
+ ============================================ */
4
+ function autoSave() {
5
+ data.metadata.lastModified = new Date().toISOString();
6
+ localStorage.setItem(APP_KEY, JSON.stringify(data));
7
+ }
8
+
9
+ function saveToLocalStorage() {
10
+ autoSave();
11
+ showNotification('Modifications sauvegardees');
12
+ }
13
+
14
+ function resetToEmbedded() {
15
+ if (!confirm('Reinitialiser toutes les donnees depuis la version d\'origine ? Vos modifications locales (commentaires, notes) seront perdues.')) return;
16
+ localStorage.removeItem(APP_KEY);
17
+ // Restore data from ORIGINAL_DATA
18
+ Object.keys(data).forEach(k => delete data[k]);
19
+ Object.assign(data, JSON.parse(JSON.stringify(ORIGINAL_DATA)));
20
+ // Re-render everything
21
+ initEditableFields();
22
+ renderStakeholders();
23
+ renderScope();
24
+ renderCriteria();
25
+ renderModules();
26
+ renderDependencies();
27
+ renderAllModuleSpecs();
28
+ renderConsolidation();
29
+ renderHandoff();
30
+ renderE2EFlows();
31
+ updateCounts();
32
+ renderReviewPanel();
33
+ showNotification('Donnees reinitialisees depuis la version d\'origine');
34
+ }
35
+
36
+ function loadFromLocalStorage() {
37
+ const saved = localStorage.getItem(APP_KEY);
38
+ if (!saved) return;
39
+
40
+ try {
41
+ const parsed = JSON.parse(saved);
42
+
43
+ // Build fingerprint of embedded structural data to detect HTML regeneration
44
+ const embeddedFingerprint = ORIGINAL_DATA.modules.map(m => m.code).sort().join(',')
45
+ + '|' + (ORIGINAL_DATA.metadata?.createdAt || '')
46
+ + '|' + ORIGINAL_DATA.modules.length;
47
+ const cachedFingerprint = parsed._structureFingerprint || '';
48
+
49
+ const structureChanged = embeddedFingerprint !== cachedFingerprint;
50
+ const embeddedModuleCount = ORIGINAL_DATA.modules?.length || 0;
51
+ const cachedModuleCount = (parsed.modules || []).length;
52
+ const hasNewModules = embeddedModuleCount > cachedModuleCount;
53
+ const embeddedModuleCodes = new Set(ORIGINAL_DATA.modules.map(m => m.code));
54
+ const cachedModuleCodes = new Set((parsed.modules || []).map(m => m.code));
55
+ const missingModules = [...embeddedModuleCodes].filter(c => !cachedModuleCodes.has(c));
56
+
57
+ if (structureChanged || hasNewModules || missingModules.length > 0) {
58
+ // HTML was regenerated or has new modules — keep embedded structural data
59
+ // Only restore user-specific edits (comments, custom roles, notes)
60
+ data.wireframeComments = parsed.wireframeComments || {};
61
+ data.specComments = parsed.specComments || {};
62
+ data.customRoles = parsed.customRoles || [];
63
+ data.customActions = parsed.customActions || [];
64
+ data.comments = parsed.comments || [];
65
+
66
+ // Merge user-added notes per module (preserve existing module notes)
67
+ for (const code of Object.keys(parsed.moduleSpecs || {})) {
68
+ if (data.moduleSpecs[code] && parsed.moduleSpecs[code]?.notes) {
69
+ data.moduleSpecs[code].notes = parsed.moduleSpecs[code].notes;
70
+ }
71
+ }
72
+
73
+ // Save fresh embedded data with fingerprint
74
+ data._structureFingerprint = embeddedFingerprint;
75
+ autoSave();
76
+ } else {
77
+ // Cache matches current structure — safe to restore user edits on cadrage/notes
78
+ // IMPORTANT: Always keep embedded modules and moduleSpecs as structural source of truth
79
+ // Only merge cadrage user-editable fields and notes
80
+ if (parsed.cadrage) {
81
+ // Merge cadrage context (user may have edited text fields)
82
+ if (parsed.cadrage.context) {
83
+ data.cadrage.context = { ...data.cadrage.context, ...parsed.cadrage.context };
84
+ }
85
+ // Merge scope only if user added items interactively
86
+ if (parsed.cadrage.scope) {
87
+ data.cadrage.scope = { ...data.cadrage.scope, ...parsed.cadrage.scope };
88
+ }
89
+ // Merge stakeholders if user edited them
90
+ if (parsed.cadrage.stakeholders) data.cadrage.stakeholders = parsed.cadrage.stakeholders;
91
+ }
92
+ data.dependencies = parsed.dependencies || data.dependencies;
93
+ data.consolidation = { ...data.consolidation, ...(parsed.consolidation || {}) };
94
+
95
+ // Merge moduleSpecs: keep embedded structure, overlay user-editable fields (notes, custom permissions)
96
+ for (const code of Object.keys(data.moduleSpecs)) {
97
+ const cached = parsed.moduleSpecs?.[code];
98
+ if (cached) {
99
+ // Preserve user notes
100
+ if (cached.notes) data.moduleSpecs[code].notes = cached.notes;
101
+ // Preserve user-added use cases/rules/entities (merged with embedded)
102
+ // Only add items that don't exist in embedded (by name match)
103
+ const embeddedUcNames = new Set((data.moduleSpecs[code].useCases || []).map(uc => uc.name));
104
+ (cached.useCases || []).forEach(uc => {
105
+ if (!embeddedUcNames.has(uc.name)) data.moduleSpecs[code].useCases.push(uc);
106
+ });
107
+ const embeddedBrNames = new Set((data.moduleSpecs[code].businessRules || []).map(br => br.name));
108
+ (cached.businessRules || []).forEach(br => {
109
+ if (!embeddedBrNames.has(br.name)) data.moduleSpecs[code].businessRules.push(br);
110
+ });
111
+ // Preserve user permissions edits
112
+ if (cached.permissions) data.moduleSpecs[code].permissions = cached.permissions;
113
+ }
114
+ }
115
+
116
+ data.wireframeComments = parsed.wireframeComments || {};
117
+ data.specComments = parsed.specComments || {};
118
+ data.customRoles = parsed.customRoles || [];
119
+ data.customActions = parsed.customActions || [];
120
+ data.comments = parsed.comments || [];
121
+
122
+ // Update fingerprint
123
+ data._structureFingerprint = embeddedFingerprint;
124
+ autoSave();
125
+ }
126
+
127
+ // Restore editable fields
128
+ document.querySelectorAll('.editable[data-field]').forEach(el => {
129
+ const value = getNestedValue(data, 'cadrage.' + el.dataset.field);
130
+ if (value) el.textContent = value;
131
+ });
132
+ } catch (e) { console.error('Error loading saved data:', e); }
133
+ }