iobroker.eos-admin 7.9.96 → 7.9.98

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 (47) hide show
  1. package/INSTALL_TEST_V7.9.98.md +39 -0
  2. package/MERGE_UPDATE_README_V7.9.98.md +29 -0
  3. package/NEXOWATT_EOS_BUILD_INFO.json +20 -18
  4. package/PUBLISH_STABLE_V7.9.98.md +33 -0
  5. package/README.md +16 -6
  6. package/README_STABILITY_V7.9.98.md +22 -0
  7. package/RELEASE_ACCEPTANCE_V7.9.98.md +48 -0
  8. package/RELEASE_NOTES_V7.9.98.md +32 -0
  9. package/adminWww/assets/Intro-DkwRiz1n-v84.js +1 -1
  10. package/adminWww/assets/bootstrap-COulQZax-v84.js +3 -3
  11. package/adminWww/assets/index-D2ymscJA-v84.js +1 -1
  12. package/adminWww/css/eos-ems-overview.css +21 -0
  13. package/adminWww/css/nexowatt-native-shell.css +174 -40
  14. package/adminWww/index.html +15 -15
  15. package/adminWww/js/eos-account-management.js +26 -13
  16. package/adminWww/js/eos-assistant.js +1 -1
  17. package/adminWww/js/eos-ems-overview.js +136 -39
  18. package/adminWww/js/eos-role-bootstrap.js +7 -7
  19. package/adminWww/js/eos-role-ui.js +2 -2
  20. package/adminWww/js/nexowatt-native-shell.js +9 -2
  21. package/adminWww/static/js/nexowatt-stable-login.js +28 -62
  22. package/adminWww/static/js/nexowatt-stable-v98.js +33 -0
  23. package/build/lib/web.js +112 -79
  24. package/build/main.js +1 -1
  25. package/io-package.json +15 -5
  26. package/package.json +14 -12
  27. package/tools/nexowatt-account-management-selftest.cjs +16 -57
  28. package/tools/nexowatt-account-password-flow-selftest.cjs +186 -0
  29. package/tools/nexowatt-clean-legacy-runtime.cjs +33 -10
  30. package/tools/nexowatt-login-layout-selftest.cjs +12 -81
  31. package/tools/nexowatt-merge-update-selftest.cjs +3 -1
  32. package/tools/nexowatt-modern-ui-selftest.cjs +2 -2
  33. package/tools/nexowatt-password-write-selftest.cjs +48 -0
  34. package/tools/nexowatt-runtime-cleanup-selftest.cjs +9 -1
  35. package/tools/nexowatt-stable-v98-selftest.cjs +14 -0
  36. package/tools/nexowatt-sync-release-version.cjs +42 -1
  37. package/tools/nexowatt-ui-overview-runtime-selftest.cjs +11 -11
  38. package/tools/nexowatt-validate-package.cjs +20 -11
  39. package/tools/nexowatt-version-sync-selftest.cjs +18 -1
  40. package/INSTALL_TEST_V7.9.96.md +0 -11
  41. package/MERGE_UPDATE_README_V7.9.96.md +0 -5
  42. package/PUBLISH_STABLE_V7.9.96.md +0 -10
  43. package/README_STABILITY_V7.9.96.md +0 -11
  44. package/RELEASE_ACCEPTANCE_V7.9.96.md +0 -10
  45. package/RELEASE_NOTES_V7.9.96.md +0 -12
  46. package/adminWww/static/js/nexowatt-stable-v96.js +0 -82
  47. package/tools/nexowatt-stable-v96-selftest.cjs +0 -13
@@ -41,16 +41,23 @@ if (pkg.scripts['test:eos-version-sync'] !== 'node tools/nexowatt-version-sync-s
41
41
  if (pkg.scripts['verify:eos-merge'] !== 'node tools/nexowatt-merge-update-selftest.cjs') fail('merge update selftest script is missing or incorrect');
42
42
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-version-sync-selftest.cjs')) fail('version sync selftest is not part of check:eos-stability');
43
43
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-merge-update-selftest.cjs')) fail('merge update selftest is not part of check:eos-stability');
44
- if (pkg.scripts['check:eos-stable-v96'] !== 'node tools/nexowatt-stable-v96-selftest.cjs') fail('stable v96 selftest script is missing or incorrect');
44
+ if (pkg.scripts['check:eos-stable-v98'] !== 'node tools/nexowatt-stable-v98-selftest.cjs') fail('stable v98 selftest script is missing or incorrect');
45
45
  if (!pkg.scripts.prepublishOnly?.startsWith('npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run check:eos-publish-channel')) fail('prepublishOnly must synchronize versions and normalize release defaults before the publish channel guard');
46
46
  if (pkg.scripts['precheck:eos-package'] !== 'npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run clean:eos-runtime') fail('precheck:eos-package must synchronize versions, normalize release defaults and clean stale runtime files');
47
47
  if (pkg.scripts['precheck:eos-stability'] !== 'npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run clean:eos-runtime') fail('precheck:eos-stability must synchronize versions, normalize release defaults and clean stale runtime files');
48
48
  if (pkg.scripts['test:eos-publish-channel'] !== 'node tools/nexowatt-publish-channel-selftest.cjs') fail('publish channel selftest script is missing');
49
49
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-publish-channel-selftest.cjs')) fail('stability check must execute the publish channel selftest');
50
50
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-release-defaults-selftest.cjs')) fail('stability check must execute the release-default selftest');
51
+ if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-password-write-selftest.cjs')) fail('password-write selftest is not part of check:eos-stability');
52
+ if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-account-password-flow-selftest.cjs')) fail('account-password flow selftest is not part of check:eos-stability');
51
53
  if (io.native?.auth !== true) fail('fresh sales installations must default to authenticated access');
52
54
  if (io.native?.eosHideLegacyBackupFromNonAdmins !== true) fail('internal BackItUp reserve must default to Admin/Service visibility');
53
55
  if (io.native?.nexowattHideLegacyBackupFromNonAdmins !== true) fail('NexoWatt backup visibility compatibility flag must default to true');
56
+ for (const key of ['description', 'files', 'scripts', 'nexowattReleasePolicy']) {
57
+ if (JSON.stringify(pkgLock.packages?.['']?.[key]) !== JSON.stringify(pkg[key])) {
58
+ fail(`package-lock root ${key} must match package.json`);
59
+ }
60
+ }
54
61
  for (const [label, value] of [
55
62
  ['io-package common.version', io.common?.version],
56
63
  ['io-package top-level version', io.version],
@@ -110,14 +117,14 @@ for (const file of [
110
117
  'LICENSE',
111
118
  'NEXOWATT_PROPRIETARY_LICENSE.md',
112
119
  'THIRD_PARTY_NOTICES.md',
113
- 'README_STABILITY_V7.9.96.md',
114
- 'RELEASE_NOTES_V7.9.96.md',
115
- 'PUBLISH_STABLE_V7.9.96.md',
116
- 'INSTALL_TEST_V7.9.96.md',
117
- 'RELEASE_ACCEPTANCE_V7.9.96.md',
120
+ 'README_STABILITY_V7.9.98.md',
121
+ 'RELEASE_NOTES_V7.9.98.md',
122
+ 'PUBLISH_STABLE_V7.9.98.md',
123
+ 'INSTALL_TEST_V7.9.98.md',
124
+ 'RELEASE_ACCEPTANCE_V7.9.98.md',
118
125
  'MERGE_UPDATE.ps1',
119
126
  'MERGE_UPDATE.cmd',
120
- 'MERGE_UPDATE_README_V7.9.96.md',
127
+ 'MERGE_UPDATE_README_V7.9.98.md',
121
128
  'tools/nexowatt-patch-built-frontend.cjs',
122
129
  'tools/nexowatt-native-shell-selftest.cjs',
123
130
  'tools/nexowatt-clean-legacy-runtime.cjs',
@@ -135,12 +142,14 @@ for (const file of [
135
142
  'tools/nexowatt-sync-release-version.cjs',
136
143
  'tools/nexowatt-version-sync-selftest.cjs',
137
144
  'tools/nexowatt-merge-update-selftest.cjs',
138
- 'tools/nexowatt-stable-v96-selftest.cjs',
145
+ 'tools/nexowatt-stable-v98-selftest.cjs',
146
+ 'tools/nexowatt-password-write-selftest.cjs',
147
+ 'tools/nexowatt-account-password-flow-selftest.cjs',
139
148
  'tools/nexowatt-ems-overview-selftest.cjs',
140
149
  'tools/nexowatt-ui-overview-runtime-selftest.cjs',
141
150
  'adminWww/js/eos-ems-overview.js',
142
151
  'adminWww/css/eos-ems-overview.css',
143
- 'adminWww/static/js/nexowatt-stable-v96.js',
152
+ 'adminWww/static/js/nexowatt-stable-v98.js',
144
153
  'src-admin/src/components/Intro/NexoWattEmsOverview.tsx',
145
154
  'tools/nexowatt-publish-channel-guard.cjs',
146
155
  'tools/nexowatt-publish-channel-selftest.cjs',
@@ -183,7 +192,7 @@ if (!index.includes(`eos-account-management.js?v=${shellTag}`)) fail('account ma
183
192
  if (!index.includes(`eos-assistant.js?v=${shellTag}`)) fail('EOS Assist cache key mismatch');
184
193
  if (!index.includes(`eos-ems-overview.js?v=${shellTag}`)) fail('EMS overview cache key mismatch');
185
194
  if (!index.includes(`eos-ems-overview.css?v=${shellTag}`)) fail('EMS overview CSS cache key mismatch');
186
- if (!index.includes(`nexowatt-stable-v96.js?v=${shellTag}`)) fail('stable v96 cache key mismatch');
195
+ if (!index.includes(`nexowatt-stable-v98.js?v=${shellTag}`)) fail('stable v98 cache key mismatch');
187
196
  if (index.indexOf(`eos-manual-write-policy.js?v=${shellTag}`) > index.indexOf(`hostInit-${runtime}.js?v=${runtimeNumber}`)) fail('manual-write policy must load before the React runtime');
188
197
  if (!index.includes('class="eos-native-shell"')) fail('native NexoWatt shell class missing');
189
198
  for (const legacy of ['eos-branding.js', 'eos-security-ui.js', 'eos-console-quiet.js', 'eos-objects-state-tools.js']) {
@@ -232,7 +241,7 @@ if (accountManagement.includes("launcher.className = 'eos-account-management-lau
232
241
  if (accountManagement.includes('new MutationObserver')) fail('account-management runtime adds a second broad DOM observer');
233
242
  if (read('src-admin/public/js/eos-account-management.js') !== accountManagement) fail('account-management source/build drift');
234
243
  const roleBootstrap = read('adminWww/js/eos-role-bootstrap.js');
235
- if (!roleBootstrap.includes('installIntegratedFirstLogin') || !roleBootstrap.includes('v96 compact normal-login first activation')) fail('compact integrated first-login is incomplete');
244
+ if (!roleBootstrap.includes('installIntegratedFirstLogin') || !roleBootstrap.includes('v98 compact normal-login first activation')) fail('compact integrated first-login is incomplete');
236
245
  if (/data-eos-account=|selector\.innerHTML/.test(roleBootstrap)) fail('login role buttons must not enlarge the normal login card');
237
246
  if (!roleBootstrap.includes('nexowatt/account/passwordless-status') || !roleBootstrap.includes('eligibility.allowed')) fail('server-checked first-login eligibility is incomplete');
238
247
  if (roleBootstrap.includes('installPasswordlessFirstLoginLauncher')) fail('old first-login launcher remains active');
@@ -24,7 +24,19 @@ try {
24
24
  const currentPkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
25
25
  const version = currentPkg.version;
26
26
  writeJson('package.json', currentPkg);
27
- writeJson('package-lock.json', { name: currentPkg.name, version: '7.9.92', packages: { '': { version: '7.9.92' } } });
27
+ writeJson('package-lock.json', {
28
+ name: currentPkg.name,
29
+ version: '7.9.92',
30
+ packages: {
31
+ '': {
32
+ version: '7.9.92',
33
+ description: 'stale description',
34
+ files: ['README_STABILITY_V7.9.92.md'],
35
+ scripts: { 'check:eos-stable-v92': 'node stale.js' },
36
+ nexowattReleasePolicy: { distTag: 'latest', purpose: 'stale 7.9.92 policy' },
37
+ },
38
+ },
39
+ });
28
40
  writeJson('io-package.json', {
29
41
  version: '7.9.92',
30
42
  common: {
@@ -75,6 +87,11 @@ try {
75
87
  ]) {
76
88
  if (actual !== version) fail(`${label} was not synchronized: ${actual}`);
77
89
  }
90
+ for (const key of ['description', 'files', 'scripts', 'nexowattReleasePolicy']) {
91
+ if (JSON.stringify(lock.packages[''][key]) !== JSON.stringify(currentPkg[key])) {
92
+ fail(`package-lock root ${key} was not synchronized`);
93
+ }
94
+ }
78
95
  if (io.common.meta !== `${expectedBase}/io-package.json`) fail('io-package URL was not synchronized');
79
96
  if (entry.meta !== `${expectedBase}/io-package.json`) fail('repository entry URL was not synchronized');
80
97
  if (!fs.existsSync(path.join(temp, build.repositoryEntry))) fail('current repository entry was not created');
@@ -1,11 +0,0 @@
1
- # Installationstest 7.9.96
2
-
3
- ```bash
4
- cd /opt/iobroker
5
- iobroker stop eos-admin.0
6
- npm install --no-save --omit=dev iobroker.eos-admin@7.9.96
7
- iobroker upload eos-admin
8
- iobroker restart eos-admin.0
9
- ```
10
-
11
- Danach Browser-Cache vollständig neu laden und Admin-, Installateur- sowie Endkundenanmeldung prüfen.
@@ -1,5 +0,0 @@
1
- # NexoWatt EOS Admin 7.9.96 – Merge-Update
2
-
3
- Die flache Merge-ZIP direkt in den bestehenden Repository-Ordner entpacken und alle Dateien ersetzen. Anschließend unter Windows `MERGE_UPDATE.cmd`, in PowerShell `./MERGE_UPDATE.ps1` oder unter Linux `./MERGE_UPDATE.sh` starten.
4
-
5
- Die Prüfung übernimmt die Inhalte der bereitgestellten EMS-Live-Diagnose-Merge idempotent, synchronisiert sämtliche Versionsdateien auf `7.9.96`, bereinigt alte Runtime-Dateien und führt Paket-, Stabilitäts- sowie npm-Pack-Dry-Run aus. Sie veröffentlicht niemals automatisch.
@@ -1,10 +0,0 @@
1
- # Veröffentlichung 7.9.96
2
-
3
- ```powershell
4
- npm login
5
- npm whoami
6
- npm run check:eos-package
7
- npm run check:eos-stability
8
- npm publish --dry-run --tag latest
9
- npm publish --tag latest
10
- ```
@@ -1,11 +0,0 @@
1
- # NexoWatt EOS Admin 7.9.96 – Stabilität
2
-
3
- Diese Version übernimmt den vollständigen Stand 7.9.95 sowie die EMS-LIVE-DIAGNOSE-Merge-Dateien. Sie korrigiert die Anmeldekarte, die erste persönliche Kennwortvergabe und die rollenabhängige Übersicht.
4
-
5
- - Native Admin-Übersicht für Admin, Installateur und Endkunde
6
- - Read-only EMS-Kachel aus `nexowatt-ui.*.info.adminOverview.*`
7
- - Technische Details für Admin/Installateur, reduzierte Erklärung für Endkunden
8
- - Größere Login-Karte ohne interne Scrollbalken
9
- - Erstkennwort `nexowatt` führt zwingend zur persönlichen Kennwortvergabe
10
- - Interner Admin und interne BackItUp-Reserve bleiben für Nicht-Admins verborgen
11
- - EOS Assist bleibt deaktiviert
@@ -1,10 +0,0 @@
1
- # Release-Abnahme 7.9.96
2
-
3
- - [ ] Login ohne Innen-Scrollbalken bei 1920×1080 und 1366×768
4
- - [ ] Falsches Passwort bleibt vollständig sichtbar
5
- - [ ] Erstlogin `user`/`installer`/`guest` mit `nexowatt` öffnet persönliche Kennwortvergabe
6
- - [ ] Native Übersicht erscheint für alle drei Rollen
7
- - [ ] EMS-Kachel liest UI-Adapter-Werte und kennzeichnet offline/veraltet nach 20 Sekunden
8
- - [ ] Endkunde sieht reduzierte Erklärung, Installateur technische Details
9
- - [ ] Admin/BackItUp-Notfallreserve bleibt für Nicht-Admins verborgen
10
- - [ ] Keine Schreiboperation aus der EMS-Kachel
@@ -1,12 +0,0 @@
1
- # Release Notes 7.9.96
2
-
3
- ## Behoben
4
-
5
- 1. Die Login-Karte skaliert ohne horizontale oder vertikale Innen-Scrollbalken und zeigt Fehlermeldungen vollständig.
6
- 2. Installateur und Endkunde erhalten die native Übersicht statt der separaten Aktionskachel-Überlagerung.
7
- 3. Der Fehler `claim is not defined` im Ablauf der persönlichen Erstkennwortvergabe wurde korrigiert.
8
- 4. Die UI-Adapter-Diagnose wird als read-only EMS-Kachel in der Übersicht angezeigt.
9
-
10
- ## EMS-Vertrag
11
-
12
- Die Kachel liest `nexowatt-ui.*.info.adminOverview.*` und `system.adapter.nexowatt-ui.*.alive`. Sie schreibt keine Datenpunkte und besitzt keine Regelhoheit.
@@ -1,82 +0,0 @@
1
- (() => {
2
- 'use strict';
3
- const VERSION = 'v96-spacious-login-first-password-fix';
4
- const MANAGED_USERS = new Set(['installer', 'guest', 'user']);
5
- const ASSIST_TEXT = /EOS\s*Assist/i;
6
- const normalizeUser = value => String(value || '').trim().toLowerCase().replace(/^system\.user\./, '');
7
- const styleId = 'nexowatt-stable-v96-style';
8
-
9
- const ensureStyle = () => {
10
- if (document.getElementById(styleId)) return;
11
- const style = document.createElement('style');
12
- style.id = styleId;
13
- style.textContent = `
14
- html.eos-login,html.eos-login body{margin:0!important;overflow-x:hidden!important;overflow-y:auto!important}
15
- html.eos-login main.MuiPaper-root{box-sizing:border-box!important}
16
- html.eos-login main.MuiPaper-root::before{width:min(520px,calc(100vw - 24px))!important;min-height:590px!important;height:min(640px,calc(100dvh - 24px))!important}
17
- html.eos-login .eos-login-card-modern,
18
- html.eos-login main.MuiPaper-root > .MuiPaper-root:has(#username),
19
- html.eos-login main.MuiPaper-root > .MuiPaper-root:has(#password),
20
- html.eos-login [data-nw-login-card="true"]{
21
- width:min(460px,calc(100vw - 56px))!important;
22
- min-height:540px!important;
23
- height:auto!important;
24
- max-width:460px!important;
25
- max-height:none!important;
26
- padding:34px 36px 32px!important;
27
- overflow:visible!important;
28
- box-sizing:border-box!important
29
- }
30
- html.eos-login .MuiAlert-root,html.eos-login [role="alert"]{position:static!important;width:100%!important;max-width:100%!important;max-height:none!important;overflow:visible!important;white-space:normal!important;overflow-wrap:anywhere!important;flex-shrink:0!important}
31
- html.eos-login .eos-login-card-modern *,html.eos-login [data-nw-login-card="true"] *{box-sizing:border-box;max-width:100%}
32
- html.eos-assist-disabled .eos-assist-root,html.eos-assist-disabled .eos-assist-header-root,[data-eos-assist-root]{display:none!important}
33
- @media(max-width:560px){html.eos-login .eos-login-card-modern,html.eos-login main.MuiPaper-root > .MuiPaper-root:has(#username),html.eos-login main.MuiPaper-root > .MuiPaper-root:has(#password),html.eos-login [data-nw-login-card="true"]{width:calc(100vw - 38px)!important;max-width:none!important;min-height:0!important;padding:26px 22px!important}}
34
- @media(max-height:690px){html.eos-login .eos-login-card-modern,html.eos-login main.MuiPaper-root > .MuiPaper-root:has(#username),html.eos-login main.MuiPaper-root > .MuiPaper-root:has(#password),html.eos-login [data-nw-login-card="true"]{min-height:0!important}}
35
- `;
36
- document.head.appendChild(style);
37
- };
38
-
39
- const findCard = (username, password) => username?.closest?.('.MuiPaper-root,form,main,section')
40
- || password?.closest?.('.MuiPaper-root,form,main,section');
41
- const findSubmit = card => card?.querySelector?.('button[type="submit"]')
42
- || Array.from(card?.querySelectorAll?.('button') || []).find(button => /anmelden|login|sign in|aanmelden/i.test(button.textContent || ''));
43
-
44
- const apply = () => {
45
- ensureStyle();
46
- document.documentElement.classList.add('eos-assist-disabled');
47
- document.querySelectorAll('.eos-assist-root,.eos-assist-header-root,[data-eos-assist-root],.eos-passwordless-launcher')
48
- .forEach(element => element.remove());
49
- const username = document.querySelector('input#username,input[name="username"]');
50
- const password = document.querySelector('input#password,input[name="password"]');
51
- const name = normalizeUser(username?.value);
52
- const pass = String(password?.value || '');
53
- const card = findCard(username, password);
54
- const submit = findSubmit(card);
55
- if (submit && MANAGED_USERS.has(name) && !pass) {
56
- submit.disabled = true;
57
- submit.classList.add('Mui-disabled');
58
- submit.setAttribute('aria-disabled', 'true');
59
- }
60
- document.querySelectorAll('body *').forEach(element => {
61
- if (element.children.length) return;
62
- const value = element.textContent || '';
63
- if (/\[iobroker\.eos-admin@[^\]]+\]/i.test(value)) element.textContent = value.replace(/\[iobroker\.eos-admin@[^\]]+\]/ig, '[NexoWatt]');
64
- if (ASSIST_TEXT.test(value) && element.closest?.('.eos-assist-root,.eos-assist-header-root')) element.closest('.eos-assist-root,.eos-assist-header-root')?.remove();
65
- });
66
- };
67
-
68
- let scheduled = false;
69
- const schedule = () => {
70
- if (scheduled) return;
71
- scheduled = true;
72
- queueMicrotask(() => { scheduled = false; apply(); });
73
- };
74
- const start = () => {
75
- apply();
76
- new MutationObserver(schedule).observe(document.documentElement, { subtree: true, childList: true, characterData: true });
77
- document.addEventListener('input', schedule, true);
78
- document.addEventListener('change', schedule, true);
79
- };
80
- document.readyState === 'loading' ? document.addEventListener('DOMContentLoaded', start, { once: true }) : start();
81
- window.NEXOWATT_EOS_STABLE_V96 = { version: VERSION, refresh: apply };
82
- })();
@@ -1,13 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
- const fs=require('node:fs');const path=require('node:path');const root=path.resolve(__dirname,'..');const read=rel=>fs.readFileSync(path.join(root,rel),'utf8');const must=(ok,msg)=>{if(!ok){console.error(`[NexoWatt EOS stable v96] ${msg}`);process.exit(1)}};
4
- const pkg=JSON.parse(read('package.json'));const io=JSON.parse(read('io-package.json'));const info=JSON.parse(read('NEXOWATT_EOS_BUILD_INFO.json'));const css=read('adminWww/css/nexowatt-native-shell.css');const boot=read('adminWww/js/eos-role-bootstrap.js');const role=read('adminWww/js/eos-role-ui.js');const stable=read('adminWww/static/js/nexowatt-stable-v96.js');const index=read('adminWww/index.html');
5
- must(pkg.version==='7.9.96'&&io.version==='7.9.96'&&io.common.version==='7.9.96'&&info.version==='7.9.96','version drift');
6
- must(info.shellCacheVersion===96&&info.shellCacheTag==='96','shell cache is not v96');
7
- must(css.includes('width: min(460px, calc(100vw - 56px)) !important')&&css.includes('overflow: visible !important'),'spacious login override missing');
8
- must(!/showFirstLoginPassword[\s\S]{0,5000}form\.elements\.username\.value = claim\.userName/.test(boot),'undefined claim variable remains in first-password flow');
9
- must(boot.includes('form.elements.username.value = userName;')&&boot.includes('controller.abort(), 8000'),'first-password repair incomplete');
10
- must(role.includes('never cover the real Admin Intro')&&!role.includes('overview.innerHTML = `'),'old action-tile overview remains');
11
- must(stable.includes("VERSION = 'v96-spacious-login-first-password-fix'")&&stable.includes('width:min(460px'),'stable v96 login runtime incomplete');
12
- must(index.includes('nexowatt-stable-v96.js?v=96'),'stable v96 runtime not loaded');
13
- console.log('[NexoWatt EOS stable v96] OK');