@atlashub/smartstack-cli 4.41.0 → 4.43.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 (142) hide show
  1. package/.documentation/apex.html +2 -2
  2. package/.documentation/business-analyse.html +26 -27
  3. package/.documentation/commands.html +6 -6
  4. package/dist/index.js +24 -13
  5. package/dist/index.js.map +1 -1
  6. package/package.json +2 -2
  7. package/templates/agents/ba-reader.md +2 -2
  8. package/templates/agents/ba-writer.md +44 -9
  9. package/templates/hooks/stop-hook.sh +6 -6
  10. package/templates/ralph/README.md +1 -1
  11. package/templates/scripts/setup-ralph-loop.sh +2 -2
  12. package/templates/skills/_resources/context-digest-template.md +1 -1
  13. package/templates/skills/_shared.md +13 -13
  14. package/templates/skills/apex/SKILL.md +14 -7
  15. package/templates/skills/apex/_shared.md +1 -1
  16. package/templates/skills/apex/references/challenge-questions.md +46 -13
  17. package/templates/skills/apex/references/core-seed-data.md +4 -4
  18. package/templates/skills/apex/references/error-classification.md +3 -3
  19. package/templates/skills/apex/references/smartstack-api.md +1 -1
  20. package/templates/skills/apex/references/smartstack-layers.md +1 -1
  21. package/templates/skills/apex/steps/step-00-init.md +46 -8
  22. package/templates/skills/apex/steps/step-01-analyze.md +1 -1
  23. package/templates/skills/apex/steps/step-02-plan.md +1 -1
  24. package/templates/skills/apex/steps/step-03-execute.md +1 -1
  25. package/templates/skills/business-analyse/SKILL.md +83 -22
  26. package/templates/skills/business-analyse/_shared.md +12 -9
  27. package/templates/skills/business-analyse/questionnaire/02-stakeholders-scope.md +24 -9
  28. package/templates/skills/business-analyse/questionnaire/03-data-ui.md +33 -0
  29. package/templates/skills/business-analyse/questionnaire/04-risks-metrics.md +1 -1
  30. package/templates/skills/business-analyse/react/components.md +1 -22
  31. package/templates/skills/business-analyse/react/schema.md +1 -1
  32. package/templates/skills/business-analyse/references/acceptance-criteria.md +3 -3
  33. package/templates/skills/business-analyse/references/consolidation-structural-checks.md +1 -1
  34. package/templates/skills/business-analyse/references/detection-strategies.md +2 -2
  35. package/templates/skills/business-analyse/references/entity-architecture-decision.md +1 -1
  36. package/templates/skills/business-analyse/references/naming-conventions.md +6 -6
  37. package/templates/skills/business-analyse/references/robustness-checks.md +4 -4
  38. package/templates/skills/business-analyse/references/spec-auto-inference.md +2 -2
  39. package/templates/skills/business-analyse/references/validation-checklist.md +3 -3
  40. package/templates/skills/business-analyse/schemas/feature-schema.json +1 -1
  41. package/templates/skills/business-analyse/schemas/sections/handoff-schema.json +2 -2
  42. package/templates/skills/business-analyse/schemas/sections/specification-schema.json +3 -2
  43. package/templates/skills/business-analyse/steps/step-00-init.md +15 -5
  44. package/templates/skills/business-analyse/steps/step-01-cadrage.md +15 -6
  45. package/templates/skills/business-analyse/steps/step-02-structure.md +17 -1
  46. package/templates/skills/business-analyse/steps/step-03-specify.md +136 -26
  47. package/templates/skills/business-analyse/steps/step-04-consolidate.md +44 -8
  48. package/templates/skills/business-analyse/templates/tpl-handoff.md +5 -5
  49. package/templates/skills/business-analyse/templates/tpl-launch-displays.md +4 -4
  50. package/templates/skills/business-analyse/templates-frd.md +4 -4
  51. package/templates/skills/{ba-design-ui → business-analyse-design}/SKILL.md +9 -9
  52. package/templates/skills/{ba-design-ui → business-analyse-design}/steps/step-01-screens.md +9 -0
  53. package/templates/skills/{ba-design-ui → business-analyse-design}/steps/step-03-navigation.md +9 -2
  54. package/templates/skills/business-analyse-develop/SKILL.md +248 -0
  55. package/templates/skills/{ralph-loop → business-analyse-develop}/references/category-completeness.md +1 -1
  56. package/templates/skills/{ralph-loop → business-analyse-develop}/references/init-resume-recovery.md +8 -8
  57. package/templates/skills/{ralph-loop → business-analyse-develop}/references/multi-module-queue.md +1 -1
  58. package/templates/skills/business-analyse-develop/references/quality-gates.md +70 -0
  59. package/templates/skills/{ralph-loop → business-analyse-develop}/references/task-transform-legacy.md +1 -1
  60. package/templates/skills/{ralph-loop → business-analyse-develop}/steps/step-00-init.md +20 -4
  61. package/templates/skills/{ralph-loop → business-analyse-develop}/steps/step-01-task.md +3 -2
  62. package/templates/skills/business-analyse-develop/steps/step-01-v4-execute.md +131 -0
  63. package/templates/skills/business-analyse-develop/steps/step-02-v4-verify.md +156 -0
  64. package/templates/skills/{ralph-loop → business-analyse-develop}/steps/step-04-check.md +1 -1
  65. package/templates/skills/{ralph-loop → business-analyse-develop}/steps/step-05-report.md +1 -1
  66. package/templates/skills/{derive-prd → business-analyse-handoff}/SKILL.md +7 -7
  67. package/templates/skills/{derive-prd → business-analyse-handoff}/references/acceptance-criteria.md +5 -5
  68. package/templates/skills/{derive-prd → business-analyse-handoff}/references/handoff-file-templates.md +1 -1
  69. package/templates/skills/{derive-prd → business-analyse-handoff}/references/handoff-mappings.md +1 -1
  70. package/templates/skills/{derive-prd → business-analyse-handoff}/references/handoff-seeddata-generation.md +2 -2
  71. package/templates/skills/{derive-prd → business-analyse-handoff}/references/prd-generation.md +14 -14
  72. package/templates/skills/{derive-prd → business-analyse-handoff}/schemas/handoff-schema.json +2 -2
  73. package/templates/skills/{derive-prd → business-analyse-handoff}/steps/step-00-validate.md +7 -7
  74. package/templates/skills/{derive-prd → business-analyse-handoff}/steps/step-01-transform.md +50 -11
  75. package/templates/skills/{derive-prd → business-analyse-handoff}/steps/step-02-export.md +36 -16
  76. package/templates/skills/{ba-generate-html → business-analyse-html}/SKILL.md +4 -4
  77. package/templates/skills/{ba-generate-html → business-analyse-html}/html/ba-interactive.html +714 -286
  78. package/templates/skills/{ba-generate-html → business-analyse-html}/html/build-html.js +25 -3
  79. package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/01-data-init.js +54 -0
  80. package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/02-navigation.js +102 -12
  81. package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/03-render-cadrage.js +8 -7
  82. package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/04-render-modules.js +7 -7
  83. package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/05-render-specs.js +188 -85
  84. package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/06-render-consolidation.js +15 -14
  85. package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/06-render-mockups.js +19 -19
  86. package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/07-render-handoff.js +24 -4
  87. package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/08-editing.js +6 -2
  88. package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/09-export.js +27 -57
  89. package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/10-comments.js +67 -45
  90. package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/scripts/11-review-panel.js +15 -13
  91. package/templates/skills/business-analyse-html/html/src/styles/02-layout.css +216 -0
  92. package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/styles/05-modules.css +36 -0
  93. package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/template.html +22 -12
  94. package/templates/skills/{ba-generate-html → business-analyse-html}/references/data-build.md +1 -1
  95. package/templates/skills/{ba-generate-html → business-analyse-html}/references/data-mapping.md +5 -1
  96. package/templates/skills/{ba-generate-html → business-analyse-html}/references/output-modes.md +7 -7
  97. package/templates/skills/{ba-generate-html → business-analyse-html}/steps/step-01-collect.md +25 -1
  98. package/templates/skills/{ba-generate-html → business-analyse-html}/steps/step-02-build-data.md +33 -5
  99. package/templates/skills/{ba-generate-html → business-analyse-html}/steps/step-03-render.md +2 -2
  100. package/templates/skills/{ba-generate-html → business-analyse-html}/steps/step-04-verify.md +2 -2
  101. package/templates/skills/{ba-review → business-analyse-review}/SKILL.md +11 -10
  102. package/templates/skills/{ba-review → business-analyse-review}/references/review-data-mapping.md +2 -2
  103. package/templates/skills/business-analyse-review/steps/step-00-init.md +107 -0
  104. package/templates/skills/{ba-review → business-analyse-review}/steps/step-01-apply.md +19 -11
  105. package/templates/skills/business-analyse-status/SKILL.md +118 -0
  106. package/templates/skills/documentation/SKILL.md +2 -2
  107. package/templates/skills/sketch/SKILL.md +172 -0
  108. package/templates/skills/sketch/references/domain-heuristics.md +116 -0
  109. package/templates/skills/ba-generate-html/html/src/styles/02-layout.css +0 -101
  110. package/templates/skills/ralph-loop/SKILL.md +0 -240
  111. /package/templates/skills/{ba-design-ui → business-analyse-design}/steps/step-02-wireframes.md +0 -0
  112. /package/templates/skills/{ralph-loop → business-analyse-develop}/references/category-rules.md +0 -0
  113. /package/templates/skills/{ralph-loop → business-analyse-develop}/references/compact-loop.md +0 -0
  114. /package/templates/skills/{ralph-loop → business-analyse-develop}/references/module-transition.md +0 -0
  115. /package/templates/skills/{ralph-loop → business-analyse-develop}/references/parallel-execution.md +0 -0
  116. /package/templates/skills/{ralph-loop → business-analyse-develop}/references/section-splitting.md +0 -0
  117. /package/templates/skills/{ralph-loop → business-analyse-develop}/references/team-orchestration.md +0 -0
  118. /package/templates/skills/{ralph-loop → business-analyse-develop}/steps/step-02-execute.md +0 -0
  119. /package/templates/skills/{ralph-loop → business-analyse-develop}/steps/step-03-commit.md +0 -0
  120. /package/templates/skills/{derive-prd → business-analyse-handoff}/references/entity-domain-mapping.md +0 -0
  121. /package/templates/skills/{derive-prd → business-analyse-handoff}/references/readiness-scoring.md +0 -0
  122. /package/templates/skills/{derive-prd → business-analyse-handoff}/templates/tpl-progress.md +0 -0
  123. /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/cadrage-context.html +0 -0
  124. /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/cadrage-scope.html +0 -0
  125. /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/cadrage-stakeholders.html +0 -0
  126. /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/cadrage-success.html +0 -0
  127. /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/consol-datamodel.html +0 -0
  128. /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/consol-flows.html +0 -0
  129. /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/consol-interactions.html +0 -0
  130. /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/consol-permissions.html +0 -0
  131. /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/decomp-dependencies.html +0 -0
  132. /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/decomp-modules.html +0 -0
  133. /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/handoff-summary.html +0 -0
  134. /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/partials/module-spec-container.html +0 -0
  135. /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/styles/01-variables.css +0 -0
  136. /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/styles/03-navigation.css +0 -0
  137. /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/styles/04-cards.css +0 -0
  138. /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/styles/06-wireframes.css +0 -0
  139. /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/styles/07-comments.css +0 -0
  140. /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/styles/08-review-panel.css +0 -0
  141. /package/templates/skills/{ba-generate-html → business-analyse-html}/html/src/styles/09-mockups-html.css +0 -0
  142. /package/templates/skills/{ba-generate-html → business-analyse-html}/references/wireframe-svg-style-guide.md +0 -0
@@ -60,8 +60,28 @@ function resolvePartials(template) {
60
60
  return resolved;
61
61
  }
62
62
 
63
+ function minifyCss(css) {
64
+ return css
65
+ .replace(/\/\*[\s\S]*?\*\//g, '') // remove comments
66
+ .replace(/\s*([{}:;,>~+])\s*/g, '$1') // remove whitespace around symbols
67
+ .replace(/\s+/g, ' ') // collapse whitespace
68
+ .replace(/;\s*}/g, '}') // remove trailing semicolons
69
+ .trim();
70
+ }
71
+
72
+ function minifyJs(js) {
73
+ // Light minification — remove comments and collapse whitespace (no AST transform)
74
+ return js
75
+ .replace(/\/\*[\s\S]*?\*\//g, '') // remove block comments
76
+ .replace(/\/\/.*$/gm, '') // remove line comments
77
+ .replace(/^\s*\n/gm, '') // remove empty lines
78
+ .replace(/\n\s+/g, '\n') // reduce leading whitespace
79
+ .trim();
80
+ }
81
+
63
82
  function build() {
64
- console.log('[build-html] Starting build...');
83
+ const doMinify = process.argv.includes('--minify');
84
+ console.log('[build-html] Starting build...' + (doMinify ? ' (minified)' : ''));
65
85
 
66
86
  // Read template
67
87
  if (!fs.existsSync(TEMPLATE_FILE)) {
@@ -80,12 +100,14 @@ function build() {
80
100
  // Read and concatenate CSS files
81
101
  const cssFiles = readSortedFiles(STYLES_DIR, '.css');
82
102
  console.log(`[build-html] CSS files: ${cssFiles.map(f => f.name).join(', ')}`);
83
- const css = cssFiles.map(f => `/* --- ${f.name} --- */\n${f.content}`).join('\n\n');
103
+ let css = cssFiles.map(f => `/* --- ${f.name} --- */\n${f.content}`).join('\n\n');
104
+ if (doMinify) css = minifyCss(css);
84
105
 
85
106
  // Read and concatenate JS files
86
107
  const jsFiles = readSortedFiles(SCRIPTS_DIR, '.js');
87
108
  console.log(`[build-html] JS files: ${jsFiles.map(f => f.name).join(', ')}`);
88
- const js = jsFiles.map(f => `/* --- ${f.name} --- */\n${f.content}`).join('\n\n');
109
+ let js = jsFiles.map(f => `/* --- ${f.name} --- */\n${f.content}`).join('\n\n');
110
+ if (doMinify) js = minifyJs(js);
89
111
 
90
112
  // Inject into template
91
113
  template = template.replace('<!-- CSS_PLACEHOLDER -->', css);
@@ -73,8 +73,23 @@ data.moduleSpecs = data.moduleSpecs || {};
73
73
  if (!data.moduleSpecs[m.code].screens) {
74
74
  data.moduleSpecs[m.code].screens = [];
75
75
  }
76
+ // Ensure sections have initialized arrays for hierarchical data
77
+ m.anticipatedSections.forEach(function(section) {
78
+ section.useCases = section.useCases || [];
79
+ section.businessRules = section.businessRules || [];
80
+ section.resources = section.resources || [];
81
+ section.permission = section.permission || '';
82
+ section.route = section.route || '';
83
+ });
76
84
  });
77
85
 
86
+ // Detect if modules use section-level specs (hierarchical mode)
87
+ function hasHierarchicalSpecs(mod) {
88
+ return (mod.anticipatedSections || []).some(function(s) {
89
+ return (s.useCases && s.useCases.length > 0) || (s.businessRules && s.businessRules.length > 0);
90
+ });
91
+ }
92
+
78
93
  // Defensive: normalize stakeholder tasks (string → array)
79
94
  (data.cadrage.stakeholders || []).forEach(function(s) {
80
95
  if (typeof s.tasks === 'string') {
@@ -146,6 +161,45 @@ function formatModuleType(t) {
146
161
  return { 'data-centric': 'Données', 'workflow': 'Processus', 'reporting': 'Rapports', 'integration': 'Intégration', 'full-module': 'Complet' }[t] || t;
147
162
  }
148
163
 
164
+ function escapeHtml(s) {
165
+ if (s == null) return '';
166
+ var d = document.createElement('div');
167
+ d.textContent = String(s);
168
+ return d.innerHTML;
169
+ }
170
+
171
+ function computeProgress() {
172
+ var totalModules = data.modules.length;
173
+ var modulesWithUC = 0, modulesWithBR = 0, modulesWithEntities = 0, modulesWithWireframes = 0;
174
+ var totalUCs = 0, totalBRs = 0, totalEntities = 0;
175
+
176
+ data.modules.forEach(function(m) {
177
+ var spec = data.moduleSpecs[m.code] || {};
178
+ var ucs = (spec.useCases || []).length;
179
+ var brs = (spec.businessRules || []).length;
180
+ var ents = (spec.entities || []).length;
181
+ var wfs = (EMBEDDED_ARTIFACTS?.wireframes?.[m.code] || []).length + (spec.screens || []).length;
182
+ totalUCs += ucs; totalBRs += brs; totalEntities += ents;
183
+ if (ucs > 0) modulesWithUC++;
184
+ if (brs > 0) modulesWithBR++;
185
+ if (ents > 0) modulesWithEntities++;
186
+ if (wfs > 0) modulesWithWireframes++;
187
+ });
188
+
189
+ var checks = [];
190
+ if (totalModules > 0) checks.push({ done: true, label: 'Modules définis (' + totalModules + ')' });
191
+ checks.push({ done: modulesWithUC === totalModules && totalModules > 0, label: 'Cas d\'utilisation (' + modulesWithUC + '/' + totalModules + ' modules)' });
192
+ checks.push({ done: modulesWithBR === totalModules && totalModules > 0, label: 'Règles métier (' + modulesWithBR + '/' + totalModules + ' modules)' });
193
+ checks.push({ done: modulesWithEntities === totalModules && totalModules > 0, label: 'Données (' + modulesWithEntities + '/' + totalModules + ' modules)' });
194
+ checks.push({ done: modulesWithWireframes === totalModules && totalModules > 0, label: 'Maquettes (' + modulesWithWireframes + '/' + totalModules + ' modules)' });
195
+ checks.push({ done: data.cadrage.stakeholders.length > 0, label: 'Parties prenantes (' + data.cadrage.stakeholders.length + ')' });
196
+ checks.push({ done: (data.cadrage.scope.inscope || []).length > 0, label: 'Périmètre défini' });
197
+
198
+ var doneCount = checks.filter(function(c) { return c.done; }).length;
199
+ var pct = checks.length > 0 ? Math.round(doneCount / checks.length * 100) : 0;
200
+ return { checks: checks, doneCount: doneCount, total: checks.length, pct: pct, totalUCs: totalUCs, totalBRs: totalBRs, totalEntities: totalEntities };
201
+ }
202
+
149
203
  /* ============================================
150
204
  INITIALIZATION
151
205
  ============================================ */
@@ -156,35 +156,34 @@ function renderModuleNavItem(mod) {
156
156
  var html = '<div class="nav-module" data-group-id="' + groupId + '">';
157
157
 
158
158
  // Module header (clickable to expand + navigate to module spec)
159
+ var totalItems = ucCount + brCount + entCount;
159
160
  html += '<a class="nav-item nav-module-header" onclick="toggleNavGroup(\'' + groupId + '\');showSection(\'module-spec-' + code + '\')" data-section="module-spec-' + code + '">';
160
161
  html += '<span class="nav-chevron ' + (collapsed ? '' : 'expanded') + '">&#9656;</span> ';
161
162
  html += (mod.name || mod.code);
163
+ if (totalItems > 0) html += ' <span class="nav-badge">' + totalItems + '</span>';
162
164
  html += '</a>';
163
165
 
164
- // Children: tabs
166
+ // Children: sections/resources (navigable sub-tree)
167
+ // Tab-level items (UC, BR, Données, etc.) are NOT shown here — they are accessed
168
+ // via the tab bar in the module content area to avoid redundancy.
165
169
  html += '<div class="nav-children"' + (collapsed ? ' style="display:none;"' : '') + '>';
166
- html += renderModuleTabNavItem(code, 'uc', 'Cas d\'utilisation', ucCount);
167
- html += renderModuleTabNavItem(code, 'br', 'Règles métier', brCount);
168
- html += renderModuleTabNavItem(code, 'ent', 'Données', entCount);
169
- html += renderModuleTabNavItem(code, 'perm', 'Droits d\'accès');
170
- html += renderModuleTabNavItem(code, 'mock', 'Maquettes');
171
- html += renderModuleTabNavItem(code, 'struct', 'Structure', sections.length);
172
-
173
- // Children: sections/resources (deeper tree)
174
170
  if (sections.length > 0) {
175
171
  sections.forEach(function(section) {
176
172
  var resources = section.resources || [];
173
+ var sectionUCs = (section.useCases || []).length;
174
+ var sectionBRs = (section.businessRules || []).length;
175
+ var contentCount = sectionUCs + sectionBRs + resources.length;
177
176
  html += '<div class="nav-section-item">';
178
177
  html += '<a class="nav-item nav-section-link" onclick="showSection(\'module-spec-' + code + '\');switchTab(\'' + code + '\',\'struct\')" data-section="module-struct-' + code + '-' + section.code + '">';
179
- html += '<span class="nav-icon nav-icon-section">&#9655;</span> ' + section.code;
180
- if (resources.length > 0) html += ' <span class="nav-badge">' + resources.length + '</span>';
178
+ html += '<span class="nav-icon nav-icon-section">&#9655;</span> ' + escapeHtml(section.code || section.name || '');
179
+ if (contentCount > 0) html += ' <span class="nav-badge">' + contentCount + '</span>';
181
180
  html += '</a>';
182
181
  if (resources.length > 0) {
183
182
  html += '<div class="nav-children nav-resources">';
184
183
  resources.forEach(function(res) {
185
184
  var resName = typeof res === 'string' ? res : (res.code || res.name || '');
186
185
  html += '<a class="nav-item nav-resource-link">';
187
- html += '<span class="nav-icon nav-icon-resource">&#8226;</span> ' + resName;
186
+ html += '<span class="nav-icon nav-icon-resource">&#8226;</span> ' + escapeHtml(resName);
188
187
  html += '</a>';
189
188
  });
190
189
  html += '</div>';
@@ -250,3 +249,94 @@ function highlightActiveNavItem() {
250
249
  var navItem = document.querySelector('#sidebarNav [data-section="' + currentSectionId + '"]');
251
250
  if (navItem) navItem.classList.add('active');
252
251
  }
252
+
253
+ /* ---------- Mobile Sidebar ---------- */
254
+
255
+ function toggleMobileSidebar() {
256
+ var sidebar = document.getElementById('sidebarAside');
257
+ var overlay = document.getElementById('sidebarOverlay');
258
+ if (!sidebar) return;
259
+ var isOpen = sidebar.classList.contains('mobile-open');
260
+ sidebar.classList.toggle('mobile-open', !isOpen);
261
+ if (overlay) overlay.classList.toggle('visible', !isOpen);
262
+ }
263
+
264
+ /* ---------- Search / Filter ---------- */
265
+
266
+ var _searchTimer;
267
+ function filterNavItems(query) {
268
+ clearTimeout(_searchTimer);
269
+ _searchTimer = setTimeout(function() { doFilterNavItems(query); }, 200);
270
+ }
271
+
272
+ function doFilterNavItems(query) {
273
+ var q = (query || '').toLowerCase().trim();
274
+ var nav = document.getElementById('sidebarNav');
275
+ if (!nav) return;
276
+
277
+ // Clear previous highlights
278
+ nav.querySelectorAll('.search-highlight').forEach(function(el) {
279
+ el.outerHTML = el.textContent;
280
+ });
281
+
282
+ if (!q) {
283
+ // Show all items
284
+ nav.querySelectorAll('.nav-item, .nav-group, .nav-module, .nav-section-item').forEach(function(el) {
285
+ el.classList.remove('search-hidden');
286
+ });
287
+ return;
288
+ }
289
+
290
+ // Filter nav items
291
+ var allItems = nav.querySelectorAll('.nav-item');
292
+ var visibleSections = new Set();
293
+
294
+ allItems.forEach(function(item) {
295
+ var text = item.textContent.toLowerCase();
296
+ if (text.includes(q)) {
297
+ item.classList.remove('search-hidden');
298
+ // Show parent groups
299
+ var parent = item.parentElement;
300
+ while (parent && parent.id !== 'sidebarNav') {
301
+ parent.classList.remove('search-hidden');
302
+ if (parent.querySelector(':scope > .nav-children')) {
303
+ var children = parent.querySelector(':scope > .nav-children');
304
+ if (children) children.style.display = '';
305
+ }
306
+ parent = parent.parentElement;
307
+ }
308
+ // Track section for content search
309
+ var sectionId = item.dataset.section;
310
+ if (sectionId) visibleSections.add(sectionId);
311
+ } else {
312
+ item.classList.add('search-hidden');
313
+ }
314
+ });
315
+
316
+ // Hide groups that have no visible children
317
+ nav.querySelectorAll('.nav-group, .nav-module').forEach(function(group) {
318
+ var visibleChildren = group.querySelectorAll('.nav-item:not(.search-hidden)');
319
+ if (visibleChildren.length === 0) {
320
+ group.classList.add('search-hidden');
321
+ } else {
322
+ group.classList.remove('search-hidden');
323
+ }
324
+ });
325
+
326
+ // Also search in section content and show matching sections
327
+ document.querySelectorAll('.section').forEach(function(section) {
328
+ var text = section.textContent.toLowerCase();
329
+ if (text.includes(q) && !visibleSections.has(section.id)) {
330
+ // Unhide corresponding nav item
331
+ var navItem = nav.querySelector('[data-section="' + section.id + '"]');
332
+ if (navItem) {
333
+ navItem.classList.remove('search-hidden');
334
+ var parent = navItem.parentElement;
335
+ while (parent && parent.id !== 'sidebarNav') {
336
+ parent.classList.remove('search-hidden');
337
+ parent = parent.parentElement;
338
+ }
339
+ }
340
+ }
341
+ });
342
+ }
@@ -42,23 +42,24 @@ function renderStakeholders() {
42
42
  grid.innerHTML = data.cadrage.stakeholders.map((s, i) => `
43
43
  <div class="stakeholder-card">
44
44
  <div style="display:flex;justify-content:space-between;align-items:start;">
45
- <div class="stakeholder-role">${s.role}</div>
45
+ <div class="stakeholder-role">${escapeHtml(s.role)}</div>
46
46
  <button class="btn btn-sm" onclick="removeStakeholder(${i})" style="opacity:0.5;font-size:0.7rem;">Supprimer</button>
47
47
  </div>
48
- <div class="stakeholder-function">${s.function || ''}</div>
48
+ <div class="stakeholder-function">${escapeHtml(s.function || '')}</div>
49
49
  <ul class="stakeholder-tasks">
50
- ${(Array.isArray(s.tasks) ? s.tasks : typeof s.tasks === 'string' ? s.tasks.split(',').map(t => t.trim()).filter(Boolean) : []).map(t => '<li>' + t + '</li>').join('')}
50
+ ${(Array.isArray(s.tasks) ? s.tasks : typeof s.tasks === 'string' ? s.tasks.split(',').map(t => t.trim()).filter(Boolean) : []).map(t => '<li>' + escapeHtml(t) + '</li>').join('')}
51
51
  </ul>
52
52
  <div class="stakeholder-meta">
53
53
  <span>${formatFrequency(s.frequency)}</span>
54
54
  <span>${formatAccess(s.access)}</span>
55
55
  </div>
56
- ${s.frustrations ? '<div style="font-size:0.8rem;color:var(--warning);margin-top:0.5rem;font-style:italic;">' + s.frustrations + '</div>' : ''}
56
+ ${s.frustrations ? '<div style="font-size:0.8rem;color:var(--warning);margin-top:0.5rem;font-style:italic;">' + escapeHtml(s.frustrations) + '</div>' : ''}
57
57
  </div>
58
58
  `).join('');
59
59
  }
60
60
 
61
61
  function removeStakeholder(index) {
62
+ if (!confirm('Supprimer ce profil utilisateur ?')) return;
62
63
  data.cadrage.stakeholders.splice(index, 1);
63
64
  renderStakeholders();
64
65
  updateCounts();
@@ -89,12 +90,12 @@ function renderScope() {
89
90
  <div class="uc-item">
90
91
  <div class="uc-header">
91
92
  <span class="priority priority-${p}">${formatPriority(p)}</span>
92
- <span class="uc-title">${item.name}</span>
93
+ <span class="uc-title">${escapeHtml(item.name)}</span>
93
94
  <div class="uc-actions">
94
95
  <button class="btn btn-sm" onclick="removeScopeItem('${p}',${i})">Supprimer</button>
95
96
  </div>
96
97
  </div>
97
- ${item.description ? '<div class="uc-detail">' + item.description + '</div>' : ''}
98
+ ${item.description ? '<div class="uc-detail">' + escapeHtml(item.description) + '</div>' : ''}
98
99
  </div>
99
100
  `).join('');
100
101
  });
@@ -139,7 +140,7 @@ function renderCriteria() {
139
140
  container.innerHTML = criteria.map((c, i) => `
140
141
  <div class="uc-item" style="display:flex;align-items:center;gap:0.75rem;">
141
142
  <input type="checkbox" ${c.validated ? 'checked' : ''} onchange="toggleCriterion(${i})" style="cursor:pointer;width:18px;height:18px;flex-shrink:0;">
142
- <span style="flex:1;${c.validated ? 'text-decoration:line-through;color:var(--text-muted);' : ''}">${c.text}</span>
143
+ <span style="flex:1;${c.validated ? 'text-decoration:line-through;color:var(--text-muted);' : ''}">${escapeHtml(c.text)}</span>
143
144
  <button class="btn btn-sm" onclick="removeCriterion(${i})" style="opacity:0.5;flex-shrink:0;">&#10005;</button>
144
145
  </div>
145
146
  `).join('');
@@ -55,10 +55,10 @@ function renderModules() {
55
55
  <div class="module-card" onclick="showSection('module-spec-${m.code}')">
56
56
  <button class="module-card-remove" onclick="event.stopPropagation();removeModule(${i})">&#10005;</button>
57
57
  <div class="module-card-header">
58
- <span class="module-card-code">${m.name}</span>
58
+ <span class="module-card-code">${escapeHtml(m.name)}</span>
59
59
  <span class="module-card-type">${formatModuleType(m.featureType)}</span>
60
60
  </div>
61
- <div class="module-card-desc">${m.description || ''}</div>
61
+ <div class="module-card-desc">${escapeHtml(m.description || '')}</div>
62
62
  <div class="module-card-meta">
63
63
  <span>${(m.entities || []).length} données</span>
64
64
  <span>${(data.moduleSpecs[m.code]?.useCases || []).length} cas d'utilisation</span>
@@ -115,10 +115,10 @@ function renderDependencies() {
115
115
  const toName = data.modules.find(m => m.code === d.to)?.name || d.to;
116
116
  return `
117
117
  <div class="interaction-item">
118
- <span style="font-weight:600;color:var(--text-bright);">${fromName}</span>
118
+ <span style="font-weight:600;color:var(--text-bright);">${escapeHtml(fromName)}</span>
119
119
  <span class="interaction-arrow">&#8594;</span>
120
- <span style="font-weight:600;color:var(--text-bright);">${toName}</span>
121
- <span style="flex:1;font-size:0.8rem;color:var(--text-muted);">${d.description || ''}</span>
120
+ <span style="font-weight:600;color:var(--text-bright);">${escapeHtml(toName)}</span>
121
+ <span style="flex:1;font-size:0.8rem;color:var(--text-muted);">${escapeHtml(d.description || '')}</span>
122
122
  <button class="btn btn-sm" onclick="removeDependency(${i})" style="opacity:0.5;">Supprimer</button>
123
123
  </div>
124
124
  `;
@@ -147,7 +147,7 @@ function renderDepGraph() {
147
147
  <div class="dep-layer-modules">
148
148
  ${layer.map(code => {
149
149
  const m = data.modules.find(mod => mod.code === code);
150
- return `<div class="dep-module">${m ? (m.name || m.code) : code}</div>`;
150
+ return `<div class="dep-module">${escapeHtml(m ? (m.name || m.code) : code)}</div>`;
151
151
  }).join('')}
152
152
  </div>
153
153
  </div>
@@ -195,7 +195,7 @@ function renderProcessingOrder() {
195
195
  return `
196
196
  <div class="process-step">
197
197
  <div class="process-step-number">Étape ${i + 1}</div>
198
- <div class="process-step-label">${m ? (m.name || m.code) : code}</div>
198
+ <div class="process-step-label">${escapeHtml(m ? (m.name || m.code) : code)}</div>
199
199
  </div>
200
200
  ${i < order.length - 1 ? '<div class="process-arrow">&#8594;</div>' : ''}
201
201
  `;