hmgr 0.0.43 → 0.0.45

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.
@@ -1,6 +1,12 @@
1
1
  {
2
2
  "fassung": 1,
3
3
  "versionen": {
4
+ "0.0.45": [
5
+ "MCP-Server und die Listen in den Einstellungen (Harnesses, zusätzliche Homedirs) erscheinen jetzt alphabetisch sortiert, ebenso in hmgr mcp list."
6
+ ],
7
+ "0.0.44": [
8
+ "Läuft gerade eine Aktualisierung, zeigt hmgr ein im Terminal hinzugefügtes Verzeichnis trotzdem sofort an, statt bis zum Ende der Aktualisierung zu warten."
9
+ ],
4
10
  "0.0.43": [
5
11
  "Fügst du im Terminal ein Arbeitsverzeichnis hinzu (hmgr dir add oder link mit einem neuen Verzeichnis), kommt ein offenes hmgr-Fenster nach vorn und zeigt das Verzeichnis sofort an."
6
12
  ],
package/dist/cli/main.js CHANGED
@@ -702,7 +702,10 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
702
702
  const uebersicht = await anwendungsfaelle.mcpUebersicht();
703
703
  if (uebersicht.katalog.length === 0)
704
704
  console.log('Kein MCP im Katalog. hmgr help mcp zeigt das Format von ~/.hmgr/mcp.yaml.');
705
- for (const { eintrag, eingehaengt, geteilteFundorte } of uebersicht.katalog) {
705
+ // E113: alphabetisch nach Name (Kopie, die Lieferreihenfolge der Daten bleibt).
706
+ const nachName = (a, b) => a.localeCompare(b, 'de', { sensitivity: 'base' });
707
+ const katalogSortiert = [...uebersicht.katalog].sort((a, b) => nachName(a.eintrag.name, b.eintrag.name));
708
+ for (const { eintrag, eingehaengt, geteilteFundorte } of katalogSortiert) {
706
709
  console.log(`${eintrag.name} ${eintrag.beschreibung}`);
707
710
  if (eingehaengt.length === 0 && geteilteFundorte.length === 0)
708
711
  console.log(' nirgends eingehängt');
@@ -714,9 +717,9 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
714
717
  }
715
718
  if (uebersicht.unbekannt.length > 0 || uebersicht.unbekannteGeteilteFundorte.length > 0) {
716
719
  console.log('Nicht im Katalog, aber eingehängt (hmgr fasst sie nicht an):');
717
- for (const { ziel, name } of uebersicht.unbekannt)
720
+ for (const { ziel, name } of [...uebersicht.unbekannt].sort((a, b) => nachName(a.name, b.name)))
718
721
  console.log(` ${name} ${ziel.harness} ${beschreibeOrt(ziel.ort)}`);
719
- for (const f of uebersicht.unbekannteGeteilteFundorte)
722
+ for (const f of [...uebersicht.unbekannteGeteilteFundorte].sort((a, b) => nachName(a.name, b.name)))
720
723
  console.log(` ${f.name} ${f.ziel.harness} ${beschreibeOrt(f.ziel.ort)} ${f.datei} · Scope ${f.scope}`);
721
724
  }
722
725
  return 0;
package/dist/gui/main.js CHANGED
@@ -962,6 +962,8 @@ function fensterOeffnen() {
962
962
  document.querySelector('[data-ansicht="mcp"]')?.click();
963
963
  var mcpKartenText = document.getElementById('mcpliste')?.textContent
964
964
  ?.replace(/\\s+/g, ' ').trim() ?? null;
965
+ var mcpKartenNamen = Array.from(document.querySelectorAll('#mcpliste .mcpkopf > b'))
966
+ .map((b) => b.textContent).join(',');
965
967
  var mcpHeimLinkVorhanden = document.querySelector('#mcpliste .mcpkopf .qlink') !== null;
966
968
  var mcpWarnzeileVorhanden = document.querySelector('#mcpliste .mcp .ruhezeile') !== null;
967
969
  // F46: die Orte-Liste je Karte und der Fremdkasten der Ansicht sind ganz weg, nicht nur
@@ -1273,6 +1275,7 @@ function fensterOeffnen() {
1273
1275
  skillOrdnerFehler,
1274
1276
  navReihenfolge,
1275
1277
  mcpKartenText,
1278
+ mcpKartenNamen,
1276
1279
  mcpHeimLinkVorhanden,
1277
1280
  mcpWarnzeileVorhanden,
1278
1281
  mcpOrteVorhanden,
@@ -1374,7 +1377,7 @@ function fensterOeffnen() {
1374
1377
  // E110: CLI-Signal gegen die laufende GUI. Das Signal schreibt dieser Main-Prozess in das
1375
1378
  // Wegwerf-Home (der Renderer kann keine Dateien schreiben). Fall 1: ohne Dialog springt die
1376
1379
  // GUI aus einer anderen Ansicht zur Karte. Fall 2: mit offenem Dialog bleibt alles stehen,
1377
- // erst nach dem Schließen folgt der Sprung. Läuft nach der Neustart-Modal-Prüfung, weil der Fall
1380
+ // erst nach dem Schließen folgt der Sprung. Fall 3 (E112): bei laufendem Aktualisieren lädt das Signal trotzdem, der Watcher nicht. Läuft nach der Neustart-Modal-Prüfung, weil der Fall
1378
1381
  // offene Dialoge schließt.
1379
1382
  .then(async () => {
1380
1383
  const pfade = (process.env.HMGR_GUI_SMOKE_SIGNAL_PFADE ?? '').split('\n').filter((p) => p !== '');
@@ -1422,6 +1425,30 @@ function fensterOeffnen() {
1422
1425
  ergebnis.fall2NachWarten = await js(karteJs(pfad2));
1423
1426
  await js(`document.getElementById('d-einstellungen').close(); true`);
1424
1427
  ergebnis.fall2 = await warteAufSprung(pfad2);
1428
+ // Fall 3 (E112): ein Aktualisieren-Lauf läuft (so erkennt ihn der Renderer: der
1429
+ // Kringel ist gesperrt). Ein Watcher-/Fokus-Anstoß lädt nicht; das Signal lädt sofort
1430
+ // und springt trotzdem. Ein MutationObserver an der Zielliste belegt das Neuladen
1431
+ // (ladeAlles baut sie neu auf). Karte von Fall 1 vorher zuklappen, Ansicht wechseln.
1432
+ await js(`window.__e112Aenderungen = 0;
1433
+ window.__e112Beobachter = new MutationObserver(function (m) { window.__e112Aenderungen += m.length; });
1434
+ window.__e112Beobachter.observe(document.getElementById('zielliste'), { childList: true, subtree: true });
1435
+ document.getElementById('updatestart').disabled = true;
1436
+ document.querySelector('[data-ansicht="mcp"]').click(); true`);
1437
+ await js(`(function () {
1438
+ var k = Array.from(document.querySelectorAll('#zielliste .ziel.verzeichnis'))
1439
+ .find(function (x) { return x.dataset.verzKey === ${JSON.stringify(`dir:${pfad1}`)}; });
1440
+ var kopf = k.querySelector('.zielkopf');
1441
+ if (kopf.getAttribute('aria-expanded') === 'true') kopf.click();
1442
+ window.__e112Aenderungen = 0; return true; })()`);
1443
+ ergebnis.fall3Vorher = await js(karteJs(pfad1));
1444
+ fenster.webContents.send('hmgr:neuLadenAnstossen');
1445
+ await new Promise((r) => setTimeout(r, 1200));
1446
+ ergebnis.fall3WatcherAenderungen = await js(`window.__e112Aenderungen`);
1447
+ await signalSchreiben(umgebung.hmgrHome, { art: 'verzeichnis-zeigen', pfad: pfad1, zeit: Date.now() });
1448
+ ergebnis.fall3 = await warteAufSprung(pfad1);
1449
+ ergebnis.fall3Aenderungen = await js(`window.__e112Aenderungen`);
1450
+ ergebnis.fall3LaufNochGesperrt = await js(`document.getElementById('updatestart').disabled === true`);
1451
+ await js(`document.getElementById('updatestart').disabled = false; window.__e112Beobachter.disconnect(); true`);
1425
1452
  }
1426
1453
  catch (fehler) {
1427
1454
  ergebnis.fehler = String(fehler);
@@ -2797,14 +2797,13 @@
2797
2797
  var uhrzeit = new Date().toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' });
2798
2798
  standNachLauf(ergebnis, ausloeser, uhrzeit);
2799
2799
  await ladeVerlauf();
2800
- await ladeAlles();
2800
+ await ladeAllesNacheinander();
2801
2801
  } finally {
2802
2802
  standLaeuft = false;
2803
2803
  knopf.disabled = false;
2804
2804
  knopf.classList.remove('laeuft');
2805
2805
  // Scheiterte der Lauf, bliebe sonst „Prüft …" stehen.
2806
2806
  if ($('standtext').textContent === 'Prüft …') standText();
2807
- reloadWartendeFreigeben();
2808
2807
  }
2809
2808
  }
2810
2809
 
@@ -2884,20 +2883,14 @@
2884
2883
  // überholt. Fehler landen wie sonst über rufe() in der Meldungsleiste, kein stiller Absturz.
2885
2884
  var stillerReloadLaeuft = false;
2886
2885
  var stillerReloadVorgemerkt = false;
2887
- // Wer auf das Ende des Neuladens wartet (E110): die Auflöser werden frei, sobald weder ein
2888
- // stiller Reload noch ein Aktualisieren-Lauf (der mit ladeAlles endet) mehr läuft.
2889
- var reloadWartende = [];
2890
- function reloadWartendeFreigeben() {
2891
- if (stillerReloadLaeuft || stillerReloadVorgemerkt || $('updatestart').disabled) return;
2892
- var liste = reloadWartende;
2893
- reloadWartende = [];
2894
- liste.forEach(function (aufloeser) { aufloeser(); });
2895
- }
2896
- function stillerReloadAbwarten() {
2897
- return new Promise(function (aufloeser) {
2898
- reloadWartende.push(aufloeser);
2899
- void stillerReload();
2900
- });
2886
+ // Alle Neuaufbauten der stillen Wege, des Signals und des Laufendes (E112) laufen hintereinander,
2887
+ // nie gleichzeitig. Die Kette reißt nie: ein Fehler (rufe() hat ihn gemeldet) wird für die
2888
+ // Kette verschluckt, dem Aufrufer aber weitergereicht.
2889
+ var ladeKette = Promise.resolve();
2890
+ function ladeAllesNacheinander() {
2891
+ var lauf = ladeKette.then(function () { return ladeAlles(); });
2892
+ ladeKette = lauf.catch(function () {});
2893
+ return lauf;
2901
2894
  }
2902
2895
  async function stillerReload() {
2903
2896
  // Läuft gerade ein Aktualisieren-Lauf, wird nicht parallel geladen: er endet ohnehin mit
@@ -2909,7 +2902,7 @@
2909
2902
  }
2910
2903
  stillerReloadLaeuft = true;
2911
2904
  try {
2912
- await ladeAlles();
2905
+ await ladeAllesNacheinander();
2913
2906
  } catch (fehler) {
2914
2907
  // rufe() hat den Fehler schon gemeldet, hier bleibt nur: den Durchlauf nicht wiederholen.
2915
2908
  } finally {
@@ -2917,8 +2910,6 @@
2917
2910
  if (stillerReloadVorgemerkt) {
2918
2911
  stillerReloadVorgemerkt = false;
2919
2912
  void stillerReload();
2920
- } else {
2921
- reloadWartendeFreigeben();
2922
2913
  }
2923
2914
  }
2924
2915
  }
@@ -2939,9 +2930,11 @@
2939
2930
  zeigeAnsicht('ziele');
2940
2931
  springeZuVerzeichnis(pfad);
2941
2932
  }
2933
+ // Der Signalweg lädt sofort, auch während eines Aktualisieren-Laufs (E112); die Serialisierung
2934
+ // hält ihn von dessen Neuaufbau am Ende getrennt. Der Sprung folgt auch nach einem Fehler.
2942
2935
  window.hmgr.onVerzeichnisZeigen(function (pfad) {
2943
2936
  signalPfadVorgemerkt = pfad;
2944
- void stillerReloadAbwarten().then(signalSprungEinloesen);
2937
+ void ladeAllesNacheinander().catch(function () {}).then(signalSprungEinloesen);
2945
2938
  });
2946
2939
  // `close` bubbelt nicht, der Capture-Listener am Dokument sieht aber jeden geschlossenen Dialog.
2947
2940
  // Der Aufschub um einen Takt lässt einen unmittelbar folgenden Dialog zuerst aufgehen.
@@ -3363,7 +3356,12 @@
3363
3356
  var w = $('mcpliste');
3364
3357
  w.textContent = '';
3365
3358
  if (MCP_KATALOG.length === 0) w.appendChild(mcpEinladung());
3366
- else MCP_KATALOG.forEach(function (k) { w.appendChild(mcpKarte(k)); });
3359
+ else {
3360
+ // E113: Kopie nach Name, MCP_KATALOG selbst bleibt in Lieferreihenfolge (F105).
3361
+ MCP_KATALOG.slice().sort(function (a, b) {
3362
+ return a.eintrag.name.localeCompare(b.eintrag.name, 'de', { sensitivity: 'base' });
3363
+ }).forEach(function (k) { w.appendChild(mcpKarte(k)); });
3364
+ }
3367
3365
  $('navzahlmcp').textContent = MCP_KATALOG.length;
3368
3366
  }
3369
3367
 
@@ -3395,6 +3393,12 @@
3395
3393
  // Die Plätze kommen aus dem Kern (F42, E16): die Fähigkeit hängt am Adapter, nicht am
3396
3394
  // Harness-Namen, hier wird nicht selbst entschieden, wer welche Ebene kennt.
3397
3395
  var plaetze = await rufe(function () { return window.hmgr.mcpPlaetze(); });
3396
+ // E113: nach angezeigtem Titel (Harness · Ort), bei Gleichstand nach der Dateispur. Die Kopie
3397
+ // ist zugleich die Auswahlliste, damit der Radio-Index zur sortierten Reihenfolge passt.
3398
+ plaetze = plaetze.slice().sort(function (a, b) {
3399
+ return zielTitel({ ziel: a }).localeCompare(zielTitel({ ziel: b }), 'de', { sensitivity: 'base' })
3400
+ || mcpOrtSpur(a).localeCompare(mcpOrtSpur(b), 'de', { sensitivity: 'base' });
3401
+ });
3398
3402
  mcpPlaetzeAuswahl = plaetze;
3399
3403
  plaetze.forEach(function (ziel, i) {
3400
3404
  var schon = k.eingehaengt.some(function (z) { return zielKey(z) === zielKey(ziel); });
@@ -3529,7 +3533,13 @@
3529
3533
  box.appendChild(e('p', 'ohne', 'Noch kein Server im Katalog. hmgr liest ihn aus '
3530
3534
  + pfadSchreibweise('~/.hmgr/mcp.yaml') + ' und schreibt die Datei nie.'));
3531
3535
  }
3532
- MCP_KATALOG.forEach(function (k, i) {
3536
+ // E113: nach Name sortiert. Der Wert der Checkbox bleibt der Index in MCP_KATALOG (Lieferreihenfolge),
3537
+ // den die Auswertung beim Absenden dort nachschlägt.
3538
+ MCP_KATALOG.map(function (k, i) { return { k: k, i: i }; }).sort(function (a, b) {
3539
+ return a.k.eintrag.name.localeCompare(b.k.eintrag.name, 'de', { sensitivity: 'base' });
3540
+ }).forEach(function (p) {
3541
+ var k = p.k;
3542
+ var i = p.i;
3533
3543
  var schon = k.eingehaengt.some(function (z) { return zielKey(z) === zielKey(ziel); });
3534
3544
  var label = e('label', 'wahlzeile');
3535
3545
  var input = document.createElement('input');
@@ -3655,7 +3665,12 @@
3655
3665
  var eintrag = null;
3656
3666
  HARNESS_HEIME.forEach(function (x) { if (x.harness === h) eintrag = x; });
3657
3667
  if (!eintrag) return kasten;
3658
- eintrag.heime.forEach(function (heim) {
3668
+ // E113: das primäre Homedir (ohne Adresse) bleibt oben, die zusätzlichen folgen nach Adresse sortiert.
3669
+ var heimeSortiert = eintrag.heime.filter(function (x) { return !x.adresse; }).concat(
3670
+ eintrag.heime.filter(function (x) { return !!x.adresse; }).sort(function (a, b) {
3671
+ return a.adresse.localeCompare(b.adresse, 'de', { sensitivity: 'base' });
3672
+ }));
3673
+ heimeSortiert.forEach(function (heim) {
3659
3674
  var zeile = e('div', 'heimzeile');
3660
3675
  zeile.appendChild(e('span', 'heimart', heim.adresse ? heim.adresse : 'Homedir'));
3661
3676
  var pfad = e('code', 'heimpfad', pfadKurz(heim.pfad));
@@ -3775,7 +3790,10 @@
3775
3790
  var vorher = document.activeElement;
3776
3791
  var merk = vorher && vorher.dataset && ul.contains(vorher) ? vorher.dataset.harness : null;
3777
3792
  ul.textContent = '';
3778
- HARNESSE_ALLE.forEach(function (h) {
3793
+ // E113: Kopie nach Anzeigename, HARNESSE_ALLE bleibt in Lieferreihenfolge (F105).
3794
+ HARNESSE_ALLE.slice().sort(function (a, b) {
3795
+ return harnessName(a).localeCompare(harnessName(b), 'de', { sensitivity: 'base' });
3796
+ }).forEach(function (h) {
3779
3797
  var li = document.createElement('li');
3780
3798
  var label = e('label', 'harnessschalter');
3781
3799
  var input = document.createElement('input');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hmgr",
3
- "version": "0.0.43",
3
+ "version": "0.0.45",
4
4
  "description": "Harness Manager: Skills und Plugins für AI-Harnesses verwalten",
5
5
  "license": "MIT",
6
6
  "author": "Tim Kaufmann",