iobroker.eos-admin 7.9.93 → 7.9.95

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 (45) hide show
  1. package/INSTALL_TEST_V7.9.95.md +15 -0
  2. package/NEXOWATT_EOS_BUILD_INFO.json +23 -18
  3. package/NEXOWATT_EOS_STABLE_7.9.94.md +16 -0
  4. package/{PUBLISH_STABLE_V7.9.93.md → PUBLISH_STABLE_V7.9.95.md} +2 -5
  5. package/README_STABILITY_V7.9.95.md +12 -0
  6. package/RELEASE_ACCEPTANCE_V7.9.95.md +11 -0
  7. package/RELEASE_NOTES_V7.9.95.md +12 -0
  8. package/adminWww/assets/Adapters-B5_jQ7DE-v84.js +1 -1
  9. package/adminWww/css/nexowatt-native-shell.css +4 -156
  10. package/adminWww/index.html +13 -11
  11. package/adminWww/js/eos-account-management.js +1 -1
  12. package/adminWww/js/eos-assistant.js +5 -556
  13. package/adminWww/js/eos-basic-settings.js +1 -1
  14. package/adminWww/js/eos-branding-sanitizer.js +1 -3
  15. package/adminWww/js/eos-native-security.js +1 -1
  16. package/adminWww/js/eos-policy-client.js +1 -1
  17. package/adminWww/js/eos-role-bootstrap.js +2 -2
  18. package/adminWww/js/eos-role-ui.js +1 -1
  19. package/adminWww/js/nexowatt-native-shell.js +1 -1
  20. package/adminWww/static/js/nexowatt-stable-login.js +79 -0
  21. package/build/lib/chat/assistantKnowledge.js +6 -21
  22. package/build/lib/chat/chatOrchestrator.js +38 -33
  23. package/build/lib/chat/mcpClientManager.js +1 -1
  24. package/build/lib/nexowattStableAuth.js +74 -0
  25. package/build/lib/web.js +24 -7
  26. package/build/main.js +123 -308
  27. package/io-package.json +20 -16
  28. package/package.json +23 -32
  29. package/INSTALL_TEST_V7.9.93.md +0 -12
  30. package/README_STABILITY_V7.9.93.md +0 -15
  31. package/RELEASE_ACCEPTANCE_V7.9.93.md +0 -15
  32. package/RELEASE_NOTES_V7.9.93.md +0 -10
  33. package/tools/nexowatt-account-management-selftest.cjs +0 -61
  34. package/tools/nexowatt-clean-legacy-runtime.cjs +0 -147
  35. package/tools/nexowatt-ensure-release-defaults.cjs +0 -72
  36. package/tools/nexowatt-generate-eos-admin-repo-entry.cjs +0 -37
  37. package/tools/nexowatt-generate-repo-entry.cjs +0 -3
  38. package/tools/nexowatt-internal-reserve-selftest.cjs +0 -57
  39. package/tools/nexowatt-login-layout-selftest.cjs +0 -62
  40. package/tools/nexowatt-modern-ui-selftest.cjs +0 -50
  41. package/tools/nexowatt-patch-repo.cjs +0 -54
  42. package/tools/nexowatt-publish-channel-guard.cjs +0 -58
  43. package/tools/nexowatt-release-defaults-selftest.cjs +0 -29
  44. package/tools/nexowatt-runtime-cleanup-selftest.cjs +0 -47
  45. package/tools/nexowatt-validate-package.cjs +0 -246
package/build/main.js CHANGED
@@ -164,6 +164,79 @@ let lastRepoUpdate;
164
164
  let objects = {};
165
165
  const secret = 'Zgfr56gFe87jJOM'; // Will be generated by first start
166
166
  let systemLanguage = 'en';
167
+
168
+ const EOS_STABLE_INITIAL_PASSWORD = 'nexowatt';
169
+ const EOS_STABLE_ACCOUNTS = [
170
+ { user: 'installer', role: 'installer' },
171
+ { user: 'guest', role: 'customer' },
172
+ { user: 'user', role: 'customer' },
173
+ ];
174
+
175
+ async function ensureEosStableGroupMembership(adapter, user, role) {
176
+ const candidateGroups = role === 'installer'
177
+ ? ['system.group.installer', 'system.group.installateur', 'system.group.installers']
178
+ : ['system.group.endkunde', 'system.group.endkunden'];
179
+ const userId = `system.user.${user}`;
180
+ for (const groupId of candidateGroups) {
181
+ const group = await adapter.getForeignObjectAsync(groupId);
182
+ if (!group) {
183
+ continue;
184
+ }
185
+ const members = Array.isArray(group.common?.members) ? [...group.common.members] : [];
186
+ if (!members.includes(userId)) {
187
+ members.push(userId);
188
+ await adapter.extendForeignObjectAsync(groupId, { common: { members } }, { user: 'system.user.admin' });
189
+ }
190
+ }
191
+ }
192
+
193
+ async function ensureEosStableInitialAccounts(adapter) {
194
+ for (const account of EOS_STABLE_ACCOUNTS) {
195
+ const id = `system.user.${account.user}`;
196
+ let object = await adapter.getForeignObjectAsync(id);
197
+ let created = false;
198
+ if (!object) {
199
+ await adapter.setForeignObjectAsync(id, {
200
+ type: 'user',
201
+ common: { name: account.user, enabled: true, password: '' },
202
+ native: {},
203
+ }, { user: 'system.user.admin' });
204
+ object = await adapter.getForeignObjectAsync(id);
205
+ created = true;
206
+ }
207
+ if (!object) {
208
+ adapter.log.error(`Cannot prepare EOS account ${account.user}`);
209
+ continue;
210
+ }
211
+ const eosNative = object.native || {};
212
+ const resetRequested = eosNative.nexowattResetRequested === true || eosNative.eosResetRequested === true;
213
+ const passwordMissing = !object.common?.password;
214
+ const pendingFirstLogin = eosNative.nexowattPasswordChangeRequired === true || eosNative.eosPasswordChangeRequired === true || eosNative.nexowattFirstLoginPending === true || eosNative.eosFirstLoginRequired === true;
215
+ const stableCredentialMissing = eosNative.nexowattStableInitialCredentialVersion !== 1;
216
+ if (created || passwordMissing || resetRequested || (pendingFirstLogin && stableCredentialMissing)) {
217
+ await adapter.setPasswordAsync(account.user, EOS_STABLE_INITIAL_PASSWORD, { user: 'system.user.admin' });
218
+ await adapter.extendForeignObjectAsync(id, {
219
+ native: {
220
+ ...eosNative,
221
+ nexowattManaged: true,
222
+ nexowattRole: account.role,
223
+ nexowattPasswordChangeRequired: true,
224
+ eosPasswordChangeRequired: true,
225
+ nexowattFirstLoginPending: true,
226
+ eosFirstLoginRequired: true,
227
+ nexowattInitialPasswordApplied: true,
228
+ nexowattInitialPasswordVersion: 1,
229
+ nexowattStableInitialCredentialVersion: 1,
230
+ nexowattResetRequested: false,
231
+ eosResetRequested: false,
232
+ },
233
+ }, { user: 'system.user.admin' });
234
+ adapter.log.info(`Prepared EOS ${account.role} account ${account.user} for mandatory first password change`);
235
+ }
236
+ await ensureEosStableGroupMembership(adapter, account.user, account.role);
237
+ }
238
+ }
239
+
167
240
  class Admin extends adapter_core_1.Adapter {
168
241
  /** secret used for the socket connection */
169
242
  secret;
@@ -174,13 +247,8 @@ class Admin extends adapter_core_1.Adapter {
174
247
  timerNews;
175
248
  _tasks;
176
249
  changedPasswords = [];
177
- /** Legacy in-process chat connection kept for compatibility with existing admin messages. */
250
+ /** In-process ioBroker.mcp connection backing the chat helper. Created on first chat message. */
178
251
  mcpChat = null;
179
- /** Role-scoped, read-only MCP connections used by the header EOS Assist. */
180
- eosAssistMcpChats = new Map();
181
- /** Per-user throttling and concurrency guard for provider calls. */
182
- eosAssistLastRequestAt = new Map();
183
- eosAssistInFlight = new Set();
184
252
  /** Periodic guard that keeps EOS safety policy applied even if object events are missed. */
185
253
  eosSecurityTimer = null;
186
254
  /** Debounce timer for object-change triggered safety checks. */
@@ -287,6 +355,7 @@ class Admin extends adapter_core_1.Adapter {
287
355
  systemLanguage = systemConfig.common.language;
288
356
  }
289
357
  adapter_core_1.I18n.init(__dirname, systemLanguage).catch(e => this.log.error(`Cannot init i18n: ${e}`));
358
+ await ensureEosStableInitialAccounts(this);
290
359
  if (!systemConfig.native.secret) {
291
360
  (0, node_crypto_1.randomBytes)(24, (_ex, buf) => {
292
361
  this.secret = buf.toString('hex');
@@ -321,300 +390,6 @@ class Admin extends adapter_core_1.Adapter {
321
390
  });
322
391
  return this.mcpChat;
323
392
  }
324
- /** Return a read-only MCP connection whose tool calls run under the authenticated user's ACL. */
325
- getEosAssistMcp(userId) {
326
- const key = `${userId}:${systemLanguage}`;
327
- let manager = this.eosAssistMcpChats.get(key);
328
- if (!manager) {
329
- manager = new mcpClientManager_1.McpClientManager(this, {
330
- defaultUser: userId,
331
- language: systemLanguage,
332
- allowSetState: false,
333
- allowObjectChange: false,
334
- });
335
- this.eosAssistMcpChats.set(key, manager);
336
- }
337
- return manager;
338
- }
339
- normalizeEosAssistSettings(value) {
340
- const native = value && typeof value === 'object' && !Array.isArray(value)
341
- ? value
342
- : {};
343
- const allowed = ['openai', 'anthropic', 'gemini', 'deepseek', 'custom'];
344
- const rawProvider = typeof native.provider === 'string' ? native.provider : 'anthropic';
345
- const provider = allowed.includes(rawProvider) ? rawProvider : 'anthropic';
346
- return {
347
- provider,
348
- model: typeof native.model === 'string' ? native.model.trim().substring(0, 200) : '',
349
- credentialId: typeof native.credentialId === 'string' ? native.credentialId.trim().substring(0, 300) : '',
350
- baseUrl: typeof native.baseUrl === 'string' ? native.baseUrl.trim().replace(/\/+$/, '').substring(0, 500) : '',
351
- allowSelfSignedCerts: native.allowSelfSignedCerts === true,
352
- };
353
- }
354
- isEosAssistConfigured(settings) {
355
- if (!settings.model) {
356
- return false;
357
- }
358
- return settings.provider === 'custom'
359
- ? !!(settings.baseUrl || settings.credentialId)
360
- : !!settings.credentialId;
361
- }
362
- async readEosAssistSettings() {
363
- const object = await this.getForeignObjectAsync('system.ai');
364
- return this.normalizeEosAssistSettings(object?.native);
365
- }
366
- sanitizeEosAssistVisibleText(value) {
367
- const text = String(value || '');
368
- // Preserve technical IDs and commands inside code spans while keeping product prose NexoWatt-only.
369
- return text
370
- .split(/(```[\s\S]*?```|`[^`\n]*`)/g)
371
- .map((part, index) => (index % 2 ? part : part.replace(/\bioBroker\b/gi, 'NexoWatt EOS')))
372
- .join('');
373
- }
374
- normalizeEosAssistMessages(value) {
375
- if (!Array.isArray(value)) {
376
- return [];
377
- }
378
- const messages = [];
379
- let total = 0;
380
- for (const entry of value.slice(-24)) {
381
- if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
382
- continue;
383
- }
384
- const record = entry;
385
- const role = record.role === 'assistant' ? 'assistant' : record.role === 'user' ? 'user' : null;
386
- if (!role || typeof record.content !== 'string') {
387
- continue;
388
- }
389
- const content = record.content.trim().substring(0, 6_000);
390
- if (!content) {
391
- continue;
392
- }
393
- total += content.length;
394
- if (total > 30_000) {
395
- break;
396
- }
397
- messages.push({ role, content });
398
- }
399
- return messages;
400
- }
401
- async getEosAssistStatus(socketClient, callback) {
402
- const userId = socketClient?._acl?.user;
403
- if (!userId) {
404
- callback?.({ error: 'Nicht angemeldet.', code: 'notAuthenticated' });
405
- return;
406
- }
407
- const role = this.getEosCachedRole(userId);
408
- if (this.eosPasswordSetupRequired.has(userId)) {
409
- callback?.({ error: 'Die persönliche Passwortvergabe muss zuerst abgeschlossen werden.', code: 'passwordSetupRequired' });
410
- return;
411
- }
412
- try {
413
- const settings = await this.readEosAssistSettings();
414
- const credentials = role === 'admin' ? await (0, credentials_1.listAiCredentials)(this) : [];
415
- callback?.({
416
- success: true,
417
- user: userId.replace(/^system\.user\./, ''),
418
- role,
419
- configured: this.isEosAssistConfigured(settings),
420
- canConfigure: role === 'admin',
421
- settings: role === 'admin' ? settings : undefined,
422
- credentials,
423
- });
424
- }
425
- catch (error) {
426
- callback?.({ error: error instanceof Error ? error.message : String(error), code: 'statusFailed' });
427
- }
428
- }
429
- async saveEosAssistSettings(socketClient, payload, callback) {
430
- const userId = socketClient?._acl?.user;
431
- if (!userId || this.getEosCachedRole(userId) !== 'admin') {
432
- callback?.({ error: 'Diese Einstellung ist nur für Admin / NexoWatt Service verfügbar.', code: 'permissionDenied' });
433
- return;
434
- }
435
- const settings = this.normalizeEosAssistSettings(payload);
436
- if (!settings.model) {
437
- callback?.({ error: 'Bitte ein Modell eintragen.', code: 'invalidSettings' });
438
- return;
439
- }
440
- if (settings.provider === 'custom') {
441
- if (!settings.baseUrl && !settings.credentialId) {
442
- callback?.({ error: 'Für einen lokalen/individuellen Anbieter wird eine Basis-URL oder ein Zugang benötigt.', code: 'invalidSettings' });
443
- return;
444
- }
445
- if (settings.baseUrl && !/^https?:\/\//i.test(settings.baseUrl)) {
446
- callback?.({ error: 'Die Basis-URL muss mit http:// oder https:// beginnen.', code: 'invalidSettings' });
447
- return;
448
- }
449
- }
450
- else if (!settings.credentialId) {
451
- callback?.({ error: 'Bitte einen gespeicherten KI-Zugang auswählen.', code: 'invalidSettings' });
452
- return;
453
- }
454
- try {
455
- const current = await this.getForeignObjectAsync('system.ai');
456
- const next = {
457
- ...(current || {}),
458
- _id: 'system.ai',
459
- type: 'config',
460
- common: {
461
- ...(current?.common || {}),
462
- name: 'EOS Assist Einstellungen',
463
- expert: true,
464
- },
465
- native: {
466
- ...(current?.native || {}),
467
- ...settings,
468
- },
469
- };
470
- await this.setForeignObjectAsync('system.ai', next);
471
- callback?.({ success: true, configured: true, settings });
472
- }
473
- catch (error) {
474
- callback?.({ error: error instanceof Error ? error.message : String(error), code: 'saveFailed' });
475
- }
476
- }
477
- async testEosAssistSettings(socketClient, payload, callback) {
478
- const userId = socketClient?._acl?.user;
479
- if (!userId || this.getEosCachedRole(userId) !== 'admin') {
480
- callback?.({ error: 'Der Verbindungstest ist nur für Admin / NexoWatt Service verfügbar.', code: 'permissionDenied' });
481
- return;
482
- }
483
- const settings = this.normalizeEosAssistSettings(payload);
484
- if (settings.provider === 'custom' && settings.baseUrl && !/^https?:\/\//i.test(settings.baseUrl)) {
485
- callback?.({ error: 'Die Basis-URL muss mit http:// oder https:// beginnen.', code: 'invalidSettings' });
486
- return;
487
- }
488
- try {
489
- const apiKey = settings.credentialId ? await (0, credentials_1.resolveAiKey)(this, settings.credentialId) : '';
490
- if (settings.provider !== 'custom' && !apiKey) {
491
- callback?.({ error: 'Der ausgewählte Zugang enthält keinen verwendbaren API-Schlüssel.', code: 'credentialMissing' });
492
- return;
493
- }
494
- const models = await (0, llmProvider_1.listModels)({
495
- provider: settings.provider,
496
- apiKey,
497
- baseUrl: settings.baseUrl || undefined,
498
- allowSelfSignedCerts: settings.allowSelfSignedCerts,
499
- });
500
- callback?.({ success: true, models, count: models.length });
501
- }
502
- catch (error) {
503
- callback?.({ error: error instanceof Error ? error.message : String(error), code: 'connectionFailed' });
504
- }
505
- }
506
- async processEosAssistSocketRequest(socketClient, payload, callback) {
507
- const userId = socketClient?._acl?.user;
508
- if (!userId) {
509
- callback?.({ error: 'Nicht angemeldet.', code: 'notAuthenticated' });
510
- return;
511
- }
512
- const role = this.getEosCachedRole(userId);
513
- if (this.eosPasswordSetupRequired.has(userId)) {
514
- callback?.({ error: 'Die persönliche Passwortvergabe muss zuerst abgeschlossen werden.', code: 'passwordSetupRequired' });
515
- return;
516
- }
517
- const now = Date.now();
518
- const previous = this.eosAssistLastRequestAt.get(userId) || 0;
519
- if (now - previous < 1_500) {
520
- callback?.({ error: 'Bitte einen Moment warten, bevor die nächste Frage gesendet wird.', code: 'rateLimited' });
521
- return;
522
- }
523
- if (this.eosAssistInFlight.has(userId)) {
524
- callback?.({ error: 'EOS Assist bearbeitet bereits eine Frage.', code: 'busy' });
525
- return;
526
- }
527
- const record = payload && typeof payload === 'object' && !Array.isArray(payload)
528
- ? payload
529
- : {};
530
- const messages = this.normalizeEosAssistMessages(record.messages);
531
- if (!messages.some(message => message.role === 'user')) {
532
- callback?.({ error: 'Bitte eine Frage eingeben.', code: 'emptyQuestion' });
533
- return;
534
- }
535
- this.eosAssistLastRequestAt.set(userId, now);
536
- this.eosAssistInFlight.add(userId);
537
- try {
538
- const settings = await this.readEosAssistSettings();
539
- if (!this.isEosAssistConfigured(settings)) {
540
- callback?.({
541
- error: 'EOS Assist ist noch nicht durch Admin / NexoWatt Service konfiguriert.',
542
- code: 'notConfigured',
543
- canConfigure: role === 'admin',
544
- role,
545
- });
546
- return;
547
- }
548
- const apiKey = settings.credentialId ? await (0, credentials_1.resolveAiKey)(this, settings.credentialId) : '';
549
- if (settings.provider !== 'custom' && !apiKey) {
550
- callback?.({
551
- error: 'Der konfigurierte KI-Zugang enthält keinen verwendbaren API-Schlüssel.',
552
- code: 'credentialMissing',
553
- canConfigure: role === 'admin',
554
- });
555
- return;
556
- }
557
- const orchestrator = new chatOrchestrator_1.ChatOrchestrator(this.getEosAssistMcp(userId), this);
558
- const uiContextRecord = record.uiContext && typeof record.uiContext === 'object' && !Array.isArray(record.uiContext)
559
- ? record.uiContext
560
- : {};
561
- const result = await orchestrator.run({
562
- provider: settings.provider,
563
- model: settings.model,
564
- apiKey,
565
- baseUrl: settings.baseUrl || undefined,
566
- messages,
567
- language: systemLanguage,
568
- allowSelfSignedCerts: settings.allowSelfSignedCerts,
569
- maxToolRounds: 10,
570
- mode: 'read',
571
- uiContext: {
572
- hash: typeof uiContextRecord.hash === 'string' ? uiContextRecord.hash.substring(0, 500) : '',
573
- },
574
- accessRole: role,
575
- });
576
- const content = this.sanitizeEosAssistVisibleText(result.content);
577
- const newMessages = result.newMessages
578
- .filter(message => message.role === 'assistant' && typeof message.content === 'string')
579
- .map(message => ({ ...message, content: this.sanitizeEosAssistVisibleText(message.content) }));
580
- callback?.({
581
- success: true,
582
- status: 'done',
583
- content,
584
- newMessages,
585
- steps: result.steps.map(step => ({
586
- ...step,
587
- result: this.sanitizeEosAssistVisibleText(step.result),
588
- })),
589
- clientActions: result.clientActions || [],
590
- role,
591
- });
592
- }
593
- catch (error) {
594
- callback?.({
595
- error: error instanceof Error ? error.message : String(error),
596
- code: 'assistFailed',
597
- canConfigure: role === 'admin',
598
- });
599
- }
600
- finally {
601
- this.eosAssistInFlight.delete(userId);
602
- }
603
- }
604
- installEosAssistSocketCommands(socketAdmin) {
605
- socketAdmin.addCommandHandler('eosAssistStatus', (socketClient, _payload, callback) => {
606
- void this.getEosAssistStatus(socketClient, callback);
607
- });
608
- socketAdmin.addCommandHandler('eosAssistSaveSettings', (socketClient, payload, callback) => {
609
- void this.saveEosAssistSettings(socketClient, payload, callback);
610
- });
611
- socketAdmin.addCommandHandler('eosAssistTestSettings', (socketClient, payload, callback) => {
612
- void this.testEosAssistSettings(socketClient, payload, callback);
613
- });
614
- socketAdmin.addCommandHandler('eosAssist', (socketClient, payload, callback) => {
615
- void this.processEosAssistSocketRequest(socketClient, payload, callback);
616
- });
617
- }
618
393
  /**
619
394
  * Some message was sent to this instance over the message box. Used by email, pushover, text2speech, ...
620
395
  * Using this method requires the "common.messagebox" property to be set to true in io-package.json
@@ -708,8 +483,55 @@ class Admin extends adapter_core_1.Adapter {
708
483
  });
709
484
  return;
710
485
  }
486
+
487
+ else if (obj.command === 'eos:completeFirstLogin') {
488
+ const message = obj.message || {};
489
+ const user = String(message.user || '').replace(/^system\\.user\\./, '').trim().toLowerCase();
490
+ const password = String(message.password || '');
491
+ if (!['installer', 'guest', 'user'].includes(user) || !password) {
492
+ if (obj.callback) {
493
+ this.sendTo(obj.from, obj.command, { error: 'Ungültige Anfrage' }, obj.callback);
494
+ }
495
+ return;
496
+ }
497
+ void this.checkPasswordAsync(user, password)
498
+ .then(async (result) => {
499
+ const valid = Array.isArray(result) ? result[0] === true : !!result;
500
+ if (!valid) {
501
+ throw new Error('Das neue Passwort konnte nicht bestätigt werden');
502
+ }
503
+ const id = `system.user.${user}`;
504
+ const account = await this.getForeignObjectAsync(id);
505
+ if (!account) {
506
+ throw new Error('Benutzerkonto nicht gefunden');
507
+ }
508
+ const eosNative = account.native || {};
509
+ await this.extendForeignObjectAsync(id, {
510
+ native: {
511
+ ...eosNative,
512
+ nexowattPasswordChangeRequired: false,
513
+ eosPasswordChangeRequired: false,
514
+ nexowattFirstLoginPending: false,
515
+ eosFirstLoginRequired: false,
516
+ nexowattPasswordChangedAt: new Date().toISOString(),
517
+ },
518
+ }, { user: 'system.user.admin' });
519
+ if (obj.callback) {
520
+ this.sendTo(obj.from, obj.command, { success: true }, obj.callback);
521
+ }
522
+ })
523
+ .catch((error) => {
524
+ if (obj.callback) {
525
+ this.sendTo(obj.from, obj.command, { error: error.message }, obj.callback);
526
+ }
527
+ });
528
+ return;
529
+ }
530
+
711
531
  else if (obj.command.startsWith('chat:')) {
712
- this.processChatMessage(obj).catch(error => this.log.error(`Error by chat processing: ${error}`));
532
+ if (obj.callback) {
533
+ this.sendTo(obj.from, obj.command, { error: 'EOS Assist ist in dieser Stable-Version vorübergehend deaktiviert.' }, obj.callback);
534
+ }
713
535
  return;
714
536
  }
715
537
  else if (webServer?.processMessage(obj)) {
@@ -1059,12 +881,6 @@ class Admin extends adapter_core_1.Adapter {
1059
881
  void this.mcpChat.close();
1060
882
  this.mcpChat = null;
1061
883
  }
1062
- for (const manager of this.eosAssistMcpChats.values()) {
1063
- void manager.close();
1064
- }
1065
- this.eosAssistMcpChats.clear();
1066
- this.eosAssistLastRequestAt.clear();
1067
- this.eosAssistInFlight.clear();
1068
884
  try {
1069
885
  this.log.info(`terminating http${this.config.secure ? 's' : ''} server on port ${this.config.port}`);
1070
886
  socket?.close();
@@ -2357,7 +2173,6 @@ class Admin extends adapter_core_1.Adapter {
2357
2173
  }
2358
2174
  socket = new socket_classes_1.SocketAdmin(settings, this, objects);
2359
2175
  this.installEosSocketCommandGuard(socket);
2360
- this.installEosAssistSocketCommands(socket);
2361
2176
  socket.start(server, ws_server_1.SocketIO, { store, oauth2Only: true, noBasicAuth: this.config.noBasicAuth });
2362
2177
  // subscribe to all object changes
2363
2178
  socket.subscribe('objectChange', '*');
package/io-package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "eos-admin",
4
- "version": "7.9.93",
4
+ "version": "7.9.95",
5
5
  "titleLang": {
6
6
  "en": "NexoWatt EOS Admin",
7
7
  "de": "NexoWatt EOS Admin",
@@ -18,15 +18,15 @@
18
18
  "connectionType": "local",
19
19
  "dataSource": "push",
20
20
  "news": {
21
- "7.9.93": {
22
- "de": "Testkandidat 7.9.93 entfernt den unnötigen Scrollbalken aus der kompakten Anmeldung, zeigt in der Modulinstallation NexoWatt als sichtbaren Herausgeber und ersetzt die statischen EOS-Assist-Texte durch einen authentifizierten, rollenabhängigen und schreibgeschützten Systemassistenten. EOS Assist kann – nach einmaliger Konfiguration durch Admin/Service – reale Module, Dienste, Einstellungen, Geräte, Datenpunkte, Struktur, Logs, Historie und Sicherungsstatus über die freigegebenen Systemwerkzeuge prüfen. Technische Paketkennungen bleiben intern kompatibel.",
23
- "en": "Test candidate 7.9.93 removes the unnecessary scrollbar from the compact login, shows NexoWatt as the visible publisher in module installation, and replaces static EOS Assist texts with an authenticated, role-aware, read-only system assistant. Once configured by Admin/Service, EOS Assist can inspect real modules, services, settings, devices, datapoints, structure, logs, history and backup status through the permitted system tools. Technical package identifiers remain internally compatible.",
24
- "nl": "Testkandidaat 7.9.93 verwijdert de overbodige schuifbalk uit de compacte aanmelding, toont NexoWatt als zichtbare uitgever bij module-installatie en vervangt statische EOS Assist-teksten door een geauthenticeerde, rolafhankelijke en alleen-lezen systeemassistent. Na eenmalige configuratie door Admin/Service kan EOS Assist echte modules, diensten, instellingen, apparaten, datapunten, structuur, logs, historie en back-upstatus controleren via de toegestane systeemtools. Technische pakket-ID’s blijven intern compatibel."
21
+ "7.9.95": {
22
+ "de": "Stable 7.9.95 macht den Release-Ordner mergesicher: Die flache Update-ZIP kann direkt über einen bestehenden Arbeitsordner entpackt werden. Vor Paketprüfung und npm-Veröffentlichung werden package.json, io-package.json, beide Lockdateien, die Frontend-Version, Build-Informationen und der aktuelle Repository-Eintrag automatisch auf dieselbe Version gebracht. Dadurch wird insbesondere ein stehen gebliebenes io-package.json aus 7.9.92/7.9.94 automatisch repariert. Die Funktionen aus 7.9.94 bleiben unverändert.",
23
+ "en": "Stable 7.9.95 makes the release folder merge-safe: the flat update ZIP can be extracted directly over an existing working directory. Before package validation and npm publishing, package.json, io-package.json, both lockfiles, the frontend version, build information and the current repository entry are synchronized automatically. In particular, a stale io-package.json from 7.9.92/7.9.94 is repaired automatically. Functional behavior from 7.9.94 remains unchanged.",
24
+ "nl": "Stable 7.9.95 maakt de releasemap merge-veilig: de vlakke update-ZIP kan direct over een bestaande werkmap worden uitgepakt. Vóór pakketcontrole en npm-publicatie worden package.json, io-package.json, beide lockbestanden, de frontendversie, buildinformatie en de actuele repositoryvermelding automatisch op dezelfde versie gezet. Een achtergebleven io-package.json uit 7.9.92/7.9.94 wordt daardoor automatisch hersteld. De functies uit 7.9.94 blijven ongewijzigd."
25
25
  },
26
- "7.9.92": {
27
- "de": "Stable 7.9.92 korrigiert die Release-Vorbereitung: Vor Paketprüfung und npm-Veröffentlichung werden die verbindlichen Verkaufsstandardwerte für Authentifizierung, Port 8081 sowie die ausschließlich für Admin/Service sichtbaren internen Admin- und BackItUp-Notfallreserven automatisch normalisiert. Dadurch kann ein gemischter lokaler Arbeitsordner die Sicherheitsprüfung nicht mehr durch einen fehlenden Standardwert abbrechen. Rollen-, Login-, Übersichts- und Dienstefilter aus 7.9.91 bleiben unverändert.",
28
- "en": "Stable 7.9.92 hardens release preparation: before package validation and npm publishing, the mandatory sales defaults for authentication, port 8081 and the Admin/Service-only internal admin and BackItUp emergency reserves are normalized automatically. A mixed local working tree can therefore no longer abort the security check merely because a required default value is missing. Role, login, overview and service filtering from 7.9.91 remain unchanged.",
29
- "nl": "Stable 7.9.92 verhardt de releasevoorbereiding: vóór pakketcontrole en npm-publicatie worden de verplichte verkoopstandaarden voor authenticatie, poort 8081 en de uitsluitend voor Admin/Service zichtbare interne admin- en BackItUp-noodreserve automatisch genormaliseerd. Een gemengde lokale werkmap kan de veiligheidscontrole daardoor niet meer laten stoppen door een ontbrekende standaardwaarde. Rollen-, login-, overzichts- en dienstenfilters uit 7.9.91 blijven ongewijzigd."
26
+ "7.9.94": {
27
+ "de": "Stable-Kandidat 7.9.94: Standardkonten installer, guest und user verwenden bei der Ersteinrichtung das Startpasswort nexowatt und müssen nach der ersten erfolgreichen Anmeldung sofort ein persönliches Passwort vergeben. Die passwortlose Aktivierung ist deaktiviert. Die Login-Karte bleibt auch bei Fehlermeldungen vollständig bedienbar. EOS Assist ist für diese Stable-Version vollständig deaktiviert, bis die neue lesende Systemassistenz separat freigegeben ist. Deutsche Sicherheitstexte und sichtbare Herstellerangaben wurden bereinigt.",
28
+ "en": "Stable candidate 7.9.94: the standard installer, guest and user accounts use the initial password nexowatt during commissioning and must set a personal password immediately after the first successful sign-in. Passwordless activation is disabled. The login card remains fully usable when an error is shown. EOS Assist is completely disabled in this stable version until the redesigned read-only system assistant is released separately. German security texts and visible publisher information were cleaned up.",
29
+ "nl": "Stable-kandidaat 7.9.94: de standaardaccounts installer, guest en user gebruiken bij de eerste ingebruikname het startwachtwoord nexowatt en moeten na de eerste succesvolle aanmelding direct een persoonlijk wachtwoord instellen. Activering zonder wachtwoord is uitgeschakeld. De aanmeldkaart blijft ook bij foutmeldingen volledig bedienbaar. EOS Assist is in deze stable-versie volledig uitgeschakeld totdat de vernieuwde alleen-lezen systeemassistent apart is vrijgegeven."
30
30
  },
31
31
  "7.9.90": {
32
32
  "de": "Stable 7.9.90 korrigiert die produktive Rollenoberfläche: Die Übersichtskacheln sind für Installateur und Gast/Endkunde zuverlässig bedienbar. Interner Admin und interne BackItUp-Notfallreserve werden in Dienste auch bei verzögert gerenderten Tabellen ausschließlich für Admin/Service angezeigt. Die Erstanmeldung prüft serverseitig, ob Installer, Guest oder User noch keinen persönlichen Zugang besitzen: Nur dann wird die normale Anmeldeschaltfläche bei leerem Passwort aktiv und öffnet die verpflichtende Passwortvergabe; nach abgeschlossener Aktivierung bleibt sie ohne Passwort gesperrt. NexoWatt Sicherung bleibt für freigegebene Rollen erreichbar, EOS Assist im Header und Standardport 8081 bleiben unverändert.",
@@ -319,7 +319,7 @@
319
319
  "icon": "admin.svg",
320
320
  "messagebox": true,
321
321
  "enabled": true,
322
- "extIcon": "https://unpkg.com/iobroker.eos-admin@7.9.93/admin/admin.svg",
322
+ "extIcon": "https://unpkg.com/iobroker.eos-admin@7.9.95/admin/admin.svg",
323
323
  "keywords": [
324
324
  "NexoWatt",
325
325
  "EOS",
@@ -330,7 +330,7 @@
330
330
  "licensed"
331
331
  ],
332
332
  "compact": true,
333
- "readme": "https://unpkg.com/iobroker.eos-admin@7.9.93/README.md",
333
+ "readme": "https://unpkg.com/iobroker.eos-admin@7.9.95/README.md",
334
334
  "authors": [
335
335
  "NexoWatt"
336
336
  ],
@@ -398,7 +398,7 @@
398
398
  "nondeletable": false,
399
399
  "allowAdapterUpdate": true,
400
400
  "allowAdapterDelete": false,
401
- "meta": "https://unpkg.com/iobroker.eos-admin@7.9.93/io-package.json",
401
+ "meta": "https://unpkg.com/iobroker.eos-admin@7.9.95/io-package.json",
402
402
  "npmPackage": "iobroker.eos-admin",
403
403
  "packetName": "iobroker.eos-admin",
404
404
  "publisher": "NexoWatt"
@@ -506,7 +506,7 @@
506
506
  ],
507
507
  "eosAdminOnlyGroup": "system.group.administrator",
508
508
  "eosApplyAdminOnlyAclToProtectedAdapters": false,
509
- "eosAssistantEnabled": true,
509
+ "eosAssistantEnabled": false,
510
510
  "eosAssistantAdminOnly": false,
511
511
  "eosStrictProtectedAdapterAcl": false,
512
512
  "eosInstallerGroups": [
@@ -531,11 +531,15 @@
531
531
  "eosRequireFirstLoginPassword": true,
532
532
  "eosFirstLoginPasswordMinLength": 10,
533
533
  "eosAutoAssignDefaultRoleUsers": true,
534
- "eosPasswordlessFirstLogin": true,
534
+ "eosPasswordlessFirstLogin": false,
535
535
  "eosPasswordlessFirstLoginPrivateNetworkOnly": true,
536
536
  "eosPasswordClaimTtlMinutes": 10,
537
537
  "eosHideLegacyBackupFromNonAdmins": true,
538
- "nexowattHideLegacyBackupFromNonAdmins": true
538
+ "nexowattHideLegacyBackupFromNonAdmins": true,
539
+ "eosAllowPasswordlessFirstLogin": false,
540
+ "eosRequireFirstLoginPasswordChange": true,
541
+ "eosAutoAssignStandardAccounts": true,
542
+ "eosAssistEnabled": false
539
543
  },
540
544
  "notifications": [
541
545
  {
@@ -1103,5 +1107,5 @@
1103
1107
  }
1104
1108
  }
1105
1109
  },
1106
- "version": "7.9.93"
1110
+ "version": "7.9.95"
1107
1111
  }