hmgr 0.0.38 → 0.0.41
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.
- package/dist/adapter/aenderungen-json.js +31 -0
- package/dist/aenderungen.json +8 -0
- package/dist/cli/hilfe.js +4 -0
- package/dist/cli/main.js +14 -1
- package/dist/gui/main.js +36 -2
- package/dist/gui/mcp-ansicht.js +4 -13
- package/dist/gui/preload.cjs +2 -0
- package/dist/gui/renderer/renderer.js +75 -20
- package/dist/gui/renderer/styles.css +7 -0
- package/dist/kern/anwendungsfaelle.js +102 -12
- package/dist/ports/aenderungen.js +3 -0
- package/package.json +2 -2
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Die Änderungsliste als mitgelieferte JSON-Datei dist/aenderungen.json (E108). Der Adapter liegt in
|
|
2
|
+
// dist/adapter/, die Datei eine Ebene höher; im Quellbaum (node src/cli/main.ts) gibt es sie nicht,
|
|
3
|
+
// dann ist die Liste leer. Fehlende oder kaputte Datei ist nie ein Fehler.
|
|
4
|
+
import { readFile } from 'node:fs/promises';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { ohneBom } from "./datei-text.js";
|
|
7
|
+
export class AenderungenJson {
|
|
8
|
+
pfad;
|
|
9
|
+
constructor(pfad = fileURLToPath(new URL('../aenderungen.json', import.meta.url))) {
|
|
10
|
+
this.pfad = pfad;
|
|
11
|
+
}
|
|
12
|
+
async lesen() {
|
|
13
|
+
const roh = await readFile(this.pfad, 'utf8').catch(() => undefined);
|
|
14
|
+
if (roh === undefined)
|
|
15
|
+
return {};
|
|
16
|
+
try {
|
|
17
|
+
const daten = JSON.parse(ohneBom(roh));
|
|
18
|
+
if (typeof daten.versionen !== 'object' || daten.versionen === null || Array.isArray(daten.versionen))
|
|
19
|
+
return {};
|
|
20
|
+
const ergebnis = {};
|
|
21
|
+
for (const [version, commits] of Object.entries(daten.versionen)) {
|
|
22
|
+
if (Array.isArray(commits))
|
|
23
|
+
ergebnis[version] = commits.filter((c) => typeof c === 'string');
|
|
24
|
+
}
|
|
25
|
+
return ergebnis;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
package/dist/cli/hilfe.js
CHANGED
|
@@ -564,6 +564,10 @@ Fehler zu einer Quelle oder einem Bundle, dazu hmgr-Ereignisse: ein Versionsspru
|
|
|
564
564
|
(GUI oder CLI, erkannt beim Start bzw. bei jedem CLI-Aufruf) oder ein gefundenes Update, das noch
|
|
565
565
|
nicht installiert ist. Plugins stehen nicht im Verlauf (siehe hmgr help update).
|
|
566
566
|
|
|
567
|
+
Unter einem „installiert"-Eintrag von hmgr stehen die Änderungen: je Version seit der zuvor
|
|
568
|
+
vermerkten die Nummer und darunter die Änderungen als kurze Sätze (E108). Einträge ohne bekannte Vorversion
|
|
569
|
+
zeigen nur die eigene Version, ohne mitgelieferte Änderungsliste entfällt der Abschnitt.
|
|
570
|
+
|
|
567
571
|
Der Verlauf ist je Rechner: mehrere Maschinen führen ihre eigene Datei, es gibt kein Zusammenführen.
|
|
568
572
|
|
|
569
573
|
Schalter: keine.
|
package/dist/cli/main.js
CHANGED
|
@@ -22,6 +22,7 @@ import { TerminalRueckfrage } from "../adapter/terminal.js";
|
|
|
22
22
|
import { ProzessUmgebung } from "../adapter/umgebung.js";
|
|
23
23
|
import { ZustandJson } from "../adapter/zustand-json.js";
|
|
24
24
|
import { VerlaufJson } from "../adapter/verlauf-json.js";
|
|
25
|
+
import { AenderungenJson } from "../adapter/aenderungen-json.js";
|
|
25
26
|
import { HILFE, hilfeText } from "./hilfe.js";
|
|
26
27
|
export function umgebungLesen(env = process.env) {
|
|
27
28
|
const home = env.HOME ?? homedir();
|
|
@@ -104,6 +105,7 @@ export function bauen(umgebung, optionen = {}) {
|
|
|
104
105
|
variablen: async (distro) => await new WslBruecke(distro, wslUmgebungAusfuehren).variablen(),
|
|
105
106
|
},
|
|
106
107
|
verlauf,
|
|
108
|
+
aenderungen: optionen.aenderungen ?? new AenderungenJson(),
|
|
107
109
|
};
|
|
108
110
|
return { anwendungsfaelle: new Anwendungsfaelle(ports), ports };
|
|
109
111
|
}
|
|
@@ -858,8 +860,15 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
|
|
|
858
860
|
console.log('Noch keine Ereignisse.');
|
|
859
861
|
for (const eintrag of eintraege) {
|
|
860
862
|
console.log(verlaufZeitpunkt(eintrag.zeit));
|
|
861
|
-
for (const ereignis of eintrag.ereignisse)
|
|
863
|
+
for (const ereignis of eintrag.ereignisse) {
|
|
862
864
|
console.log(` ${verlaufEreignisZeile(ereignis)}`);
|
|
865
|
+
// Unter einem Versionssprung die Commits der neuen Version(en), eingerückt (E108).
|
|
866
|
+
if (ereignis.art === 'hmgr-installiert') {
|
|
867
|
+
const aenderungen = await anwendungsfaelle.hmgrAenderungen(ereignis.vorher, ereignis.version);
|
|
868
|
+
for (const zeile of aenderungsZeilen(aenderungen))
|
|
869
|
+
console.log(zeile);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
863
872
|
}
|
|
864
873
|
return 0;
|
|
865
874
|
}
|
|
@@ -1091,6 +1100,10 @@ function verlaufZeitpunkt(iso) {
|
|
|
1091
1100
|
return (`${zwei(datum.getDate())}.${zwei(datum.getMonth() + 1)}.${datum.getFullYear()} ` +
|
|
1092
1101
|
`${zwei(datum.getHours())}:${zwei(datum.getMinutes())}`);
|
|
1093
1102
|
}
|
|
1103
|
+
/** Je Version die Nummer und darunter ihre Commit-Betreffs, tiefer eingerückt als die Ereigniszeile (E108). */
|
|
1104
|
+
function aenderungsZeilen(aenderungen) {
|
|
1105
|
+
return aenderungen.flatMap((a) => [` ${a.version}`, ...a.commits.map((c) => ` ${c}`)]);
|
|
1106
|
+
}
|
|
1094
1107
|
/** Eine Ereigniszeile im Verlauf (E80), eingerückt unter der Kopfzeile ihres Laufs. */
|
|
1095
1108
|
function verlaufEreignisZeile(ereignis) {
|
|
1096
1109
|
if (ereignis.art === 'checkout') {
|
package/dist/gui/main.js
CHANGED
|
@@ -11,6 +11,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
11
11
|
import { stat } from 'node:fs/promises';
|
|
12
12
|
import { fileURLToPath } from 'node:url';
|
|
13
13
|
import { bauen, umgebungLesen } from "../cli/main.js";
|
|
14
|
+
import { AenderungenJson } from "../adapter/aenderungen-json.js";
|
|
14
15
|
import { quelleAlsText, quelleAusText } from "../adapter/quelle-text.js";
|
|
15
16
|
import { paketVersion } from "../adapter/paket-version.js";
|
|
16
17
|
import { infoPlistPfad, MeldungsPuffer, neuereVersionAufPlatte } from "./selbst-update.js";
|
|
@@ -129,6 +130,11 @@ const rueckfrage = new GuiRueckfrage();
|
|
|
129
130
|
const { anwendungsfaelle, ports } = bauen(umgebung, {
|
|
130
131
|
rueckfrage,
|
|
131
132
|
...(smoketest ? { claudeAusfuehrer: smoketestClaudeAusfuehrer } : {}),
|
|
133
|
+
// Nur der Smoke-Test biegt die Änderungsliste auf eine Fixture-Datei um (E108); sonst die
|
|
134
|
+
// mitgelieferte dist/aenderungen.json.
|
|
135
|
+
...(smoketest && process.env.HMGR_GUI_SMOKE_AENDERUNGEN !== undefined
|
|
136
|
+
? { aenderungen: new AenderungenJson(process.env.HMGR_GUI_SMOKE_AENDERUNGEN) }
|
|
137
|
+
: {}),
|
|
132
138
|
});
|
|
133
139
|
/**
|
|
134
140
|
* Wer den laufenden Aktualisieren-Lauf ausgelöst hat (E80): der Renderer reicht es bei jedem Aufruf
|
|
@@ -329,6 +335,8 @@ function registriereIpc() {
|
|
|
329
335
|
}));
|
|
330
336
|
// Changelog der letzten Läufe (E80), neueste zuerst.
|
|
331
337
|
ipcMain.handle('hmgr:verlauf', async () => auffangen(async () => anwendungsfaelle.verlauf()));
|
|
338
|
+
// Änderungen (Commit-Betreffs) der Versionen eines hmgr-Versionssprungs (E108).
|
|
339
|
+
ipcMain.handle('hmgr:hmgrAenderungen', async (_event, vorher, version) => auffangen(async () => anwendungsfaelle.hmgrAenderungen(vorher, version)));
|
|
332
340
|
// E77: der Prüfen-Knopf stößt zusätzlich zum Quellen-Lauf die Prüfung auf hmgr selbst an. Kein
|
|
333
341
|
// `handle`, sondern `send`/`on`: der Renderer wartet auf nichts, das Ergebnis kommt später von
|
|
334
342
|
// sich aus über 'hmgr:selbstUpdate'.
|
|
@@ -416,8 +424,11 @@ function registriereIpc() {
|
|
|
416
424
|
}));
|
|
417
425
|
// MCP-Ansicht (E61-Folgerunde): Whitelisting und der F39-Vermerk je Karte stehen in mcp-ansicht.ts
|
|
418
426
|
// (rein, ohne Electron, wie oeffnen.ts und icons.ts), damit sie testbar sind. Der Main-Prozess
|
|
419
|
-
// ruft nur noch auf
|
|
420
|
-
ipcMain.handle('hmgr:mcpUebersicht', async () => auffangen(async () =>
|
|
427
|
+
// ruft nur noch auf; die F39-Lage je Welt (lokal, WSL-Distro) kommt aus dem Kern (E107).
|
|
428
|
+
ipcMain.handle('hmgr:mcpUebersicht', async () => auffangen(async () => {
|
|
429
|
+
const uebersicht = await anwendungsfaelle.mcpUebersicht();
|
|
430
|
+
return mcpUebersichtSerialisieren(uebersicht, await anwendungsfaelle.mcpVariablenLage(uebersicht));
|
|
431
|
+
}));
|
|
421
432
|
// Plätze für den Einhängen-Dialog (F42): die Fähigkeit hängt am Adapter, nicht am Namen (E16),
|
|
422
433
|
// deshalb kommt die Liste unverändert aus dem Kern statt aus einer Harness-Fallunterscheidung hier.
|
|
423
434
|
ipcMain.handle('hmgr:mcpPlaetze', async () => auffangen(async () => anwendungsfaelle.mcpPlaetze()));
|
|
@@ -709,6 +720,23 @@ function fensterOeffnen() {
|
|
|
709
720
|
verlaufBloecke = document.querySelectorAll('#verlauf .block').length;
|
|
710
721
|
if (verlaufBloecke > 0) break;
|
|
711
722
|
}
|
|
723
|
+
// E108: die Änderungslisten kommen nach dem Verlauf per IPC; warten, bis jeder Platz
|
|
724
|
+
// entweder sein details hat oder (ohne Daten) entfernt ist.
|
|
725
|
+
for (var wartezeit2 = 0; wartezeit2 < 2000; wartezeit2 += 100) {
|
|
726
|
+
if (document.querySelector('#verlauf .aenderungen-platz:empty') === null) break;
|
|
727
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
728
|
+
}
|
|
729
|
+
var aenderungenDetails = document.querySelectorAll('#verlauf details.aenderungen').length;
|
|
730
|
+
var aenderungenElement = document.querySelector('#verlauf details.aenderungen');
|
|
731
|
+
var aenderungenSummary = aenderungenElement?.querySelector('summary')?.textContent?.trim() ?? null;
|
|
732
|
+
var aenderungenOffenVorher = aenderungenElement?.open ?? null;
|
|
733
|
+
aenderungenElement?.querySelector('summary')?.click();
|
|
734
|
+
var aenderungenOffenNachher = aenderungenElement?.open ?? null;
|
|
735
|
+
var aenderungenGruppen = aenderungenElement?.querySelectorAll('.aenderungen-version').length ?? 0;
|
|
736
|
+
var aenderungenText = Array.prototype.map.call(
|
|
737
|
+
aenderungenElement?.querySelectorAll('.aenderungen-version') ?? [],
|
|
738
|
+
(g) => g.textContent.replace(/\\s+/g, ' ').trim(),
|
|
739
|
+
).join(' ');
|
|
712
740
|
var verlaufText = document.getElementById('verlauf')?.textContent?.replace(/\\s+/g, ' ').trim() ?? null;
|
|
713
741
|
// Nachziehen je Quelle (E89): das Fixture hat im skills-repo einen neuen Upstream-Commit
|
|
714
742
|
// (fixtureAufbauen), den erst ein Lauf für diese Quelle holt. Erst der Knopf der
|
|
@@ -1292,6 +1320,12 @@ function fensterOeffnen() {
|
|
|
1292
1320
|
verlaufVorhanden,
|
|
1293
1321
|
verlaufText,
|
|
1294
1322
|
verlaufBloecke,
|
|
1323
|
+
aenderungenDetails,
|
|
1324
|
+
aenderungenSummary,
|
|
1325
|
+
aenderungenOffenVorher,
|
|
1326
|
+
aenderungenOffenNachher,
|
|
1327
|
+
aenderungenGruppen,
|
|
1328
|
+
aenderungenText,
|
|
1295
1329
|
nachziehenFehler,
|
|
1296
1330
|
nachziehenKnopfZahl,
|
|
1297
1331
|
nachziehenBloeckeStart,
|
package/dist/gui/mcp-ansicht.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// MCP-Ansicht der GUI (E61-Folgerunde): reine Umformung von Kern-Daten in IPC-taugliche, gewhiteliste
|
|
2
2
|
// Objekte, ohne Electron — testbar wie oeffnen.ts und icons.ts. Der eigentliche IPC-Handler in
|
|
3
3
|
// main.ts ruft diese Funktionen nur noch auf.
|
|
4
|
-
import {
|
|
4
|
+
import {} from "../kern/anwendungsfaelle.js";
|
|
5
5
|
/** Katalog-Eintrag über IPC: die bekannten Felder, nichts ungefiltert durchgereicht (E40 R3). */
|
|
6
6
|
export function mcpEintragSerialisieren(eintrag) {
|
|
7
7
|
return {
|
|
@@ -12,23 +12,14 @@ export function mcpEintragSerialisieren(eintrag) {
|
|
|
12
12
|
konfig: eintrag.konfig,
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
|
-
/**
|
|
16
|
-
|
|
17
|
-
* (`variablenVerweise`), hier aber nur gegen die übergebene Umgebung geprüft — ohne den
|
|
18
|
-
* ortsbezogenen `.env`-Abgleich, der ist ortsspezifisch und bleibt dem eigentlichen Einhängen
|
|
19
|
-
* vorbehalten (kommt von dort als `warnung` zurück).
|
|
20
|
-
*/
|
|
21
|
-
export function mcpFehlendeVariablen(eintrag, umgebung) {
|
|
22
|
-
return variablenVerweise(eintrag.konfig).filter((name) => !(name in umgebung) || umgebung[name] === undefined);
|
|
23
|
-
}
|
|
24
|
-
/** Übersicht über IPC (E61-Folgerunde): Katalog-Einträge whitelisted, dazu der F39-Vermerk je Karte. */
|
|
25
|
-
export function mcpUebersichtSerialisieren(uebersicht, umgebung) {
|
|
15
|
+
/** Übersicht über IPC (E61-Folgerunde): Katalog-Einträge whitelisted, dazu je Karte die F39-Befunde je Welt (E107, `variablenWelten`). */
|
|
16
|
+
export function mcpUebersichtSerialisieren(uebersicht, lage) {
|
|
26
17
|
return {
|
|
27
18
|
katalog: uebersicht.katalog.map((k) => ({
|
|
28
19
|
eintrag: mcpEintragSerialisieren(k.eintrag),
|
|
29
20
|
eingehaengt: k.eingehaengt,
|
|
30
21
|
geteilteFundorte: k.geteilteFundorte,
|
|
31
|
-
|
|
22
|
+
variablenWelten: lage.get(k.eintrag.name) ?? [],
|
|
32
23
|
})),
|
|
33
24
|
unbekannt: uebersicht.unbekannt,
|
|
34
25
|
unbekannteGeteilteFundorte: uebersicht.unbekannteGeteilteFundorte,
|
package/dist/gui/preload.cjs
CHANGED
|
@@ -35,6 +35,8 @@ contextBridge.exposeInMainWorld('hmgr', {
|
|
|
35
35
|
aktualisieren: (args) => ipcRenderer.invoke('hmgr:aktualisieren', args),
|
|
36
36
|
/** Changelog der letzten Läufe (E80), neueste zuerst. */
|
|
37
37
|
verlauf: () => ipcRenderer.invoke('hmgr:verlauf'),
|
|
38
|
+
/** Commit-Betreffs der Versionen zwischen `vorher` (exklusiv) und `version` (E108), neueste zuerst. */
|
|
39
|
+
hmgrAenderungen: (vorher, version) => ipcRenderer.invoke('hmgr:hmgrAenderungen', vorher, version),
|
|
38
40
|
/** Installiert das geladene GUI-Update und startet neu (E80), Gegenstück zum Neustart-Knopf. */
|
|
39
41
|
neuStarten: () => {
|
|
40
42
|
ipcRenderer.send('hmgr:neuStarten');
|
|
@@ -323,7 +323,7 @@
|
|
|
323
323
|
// Homedirs je Harness (E78): je Eintrag { harness, heime: [{ adresse?, pfad, eingestellt }],
|
|
324
324
|
// kannZusaetzliche }. Grundlage der Homedir-Zeilen in den Einstellungen.
|
|
325
325
|
var HARNESS_HEIME = [];
|
|
326
|
-
// MCP-Katalog (E61-Folgerunde): je Eintrag { eintrag, eingehaengt,
|
|
326
|
+
// MCP-Katalog (E61-Folgerunde): je Eintrag { eintrag, eingehaengt, variablenWelten }, dazu
|
|
327
327
|
// Einträge in Harness-Konfigurationen, die nicht im Katalog stehen (nur genannt). Seit F46 nur
|
|
328
328
|
// noch Grundlage für den MCP-Abschnitt der Ziel-Karten (mcpZeilenFuerZiel), die MCP-Ansicht selbst
|
|
329
329
|
// zeigt keine Fundorte mehr.
|
|
@@ -2927,6 +2927,12 @@
|
|
|
2927
2927
|
} else if (ereignis.art === 'hmgr-installiert') {
|
|
2928
2928
|
li.appendChild(e('span', 'marke-ok', 'installiert'));
|
|
2929
2929
|
li.appendChild(e('span', 'pfad', (ereignis.paket === 'gui' ? 'hmgr-GUI ' : 'hmgr ') + ereignis.version));
|
|
2930
|
+
// E108: die Commits der Versionen seit der zuvor installierten, zum Ausklappen unter der Zeile.
|
|
2931
|
+
// Der Platzhalter hält die Stelle, das details kommt nach dem Aufbau des Verlaufs hinein.
|
|
2932
|
+
var aenderungenPlatz = e('div', 'aenderungen-platz');
|
|
2933
|
+
aenderungenPlatz.dataset.vorher = ereignis.vorher || '';
|
|
2934
|
+
aenderungenPlatz.dataset.version = ereignis.version;
|
|
2935
|
+
li.appendChild(aenderungenPlatz);
|
|
2930
2936
|
} else if (ereignis.art === 'gui-update-geladen') {
|
|
2931
2937
|
li.appendChild(e('span', 'marke-ok', 'geladen'));
|
|
2932
2938
|
li.appendChild(e('span', 'pfad', 'GUI-Update ' + ereignis.version));
|
|
@@ -2965,6 +2971,29 @@
|
|
|
2965
2971
|
block.appendChild(ul);
|
|
2966
2972
|
box.appendChild(block);
|
|
2967
2973
|
});
|
|
2974
|
+
// E108: die Änderungslisten nachladen, nachdem der Verlauf steht. Ein Fehler lässt nur den
|
|
2975
|
+
// jeweiligen Abschnitt weg, nie den Verlauf.
|
|
2976
|
+
var plaetze = Array.prototype.slice.call(box.querySelectorAll('.aenderungen-platz'));
|
|
2977
|
+
await Promise.all(plaetze.map(async function (platz) {
|
|
2978
|
+
var versionen = await window.hmgr.hmgrAenderungen(platz.dataset.vorher || undefined, platz.dataset.version)
|
|
2979
|
+
.then(function (r) { return r && r.ok ? r.daten : []; }, function () { return []; });
|
|
2980
|
+
if (versionen.length === 0) { platz.remove(); return; }
|
|
2981
|
+
var zahl = versionen.reduce(function (summe, v) { return summe + v.commits.length; }, 0);
|
|
2982
|
+
var d = e('details', 'notizen aenderungen');
|
|
2983
|
+
var s = e('summary');
|
|
2984
|
+
s.appendChild(keilIcon());
|
|
2985
|
+
s.appendChild(document.createTextNode('Änderungen (' + zahl + ')'));
|
|
2986
|
+
d.appendChild(s);
|
|
2987
|
+
versionen.forEach(function (v) {
|
|
2988
|
+
var gruppe = e('div', 'aenderungen-version');
|
|
2989
|
+
gruppe.appendChild(e('b', null, v.version));
|
|
2990
|
+
var liste = e('ul');
|
|
2991
|
+
v.commits.forEach(function (commit) { liste.appendChild(e('li', null, commit)); });
|
|
2992
|
+
gruppe.appendChild(liste);
|
|
2993
|
+
d.appendChild(gruppe);
|
|
2994
|
+
});
|
|
2995
|
+
platz.appendChild(d);
|
|
2996
|
+
}));
|
|
2968
2997
|
}
|
|
2969
2998
|
|
|
2970
2999
|
/* ================= PLUGINS ================= */
|
|
@@ -3071,13 +3100,11 @@
|
|
|
3071
3100
|
return a;
|
|
3072
3101
|
}
|
|
3073
3102
|
|
|
3074
|
-
/** F39:
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
function mcpWarnZeile(
|
|
3079
|
-
var mehrzahl = fehlend.length > 1;
|
|
3080
|
-
var namen = fehlend.map(function (v) { return '${' + v + '}'; }).join(', ');
|
|
3103
|
+
/** F39 (E107): der Main-Prozess liefert je Karte `variablenWelten`, die Befunde je Welt (lokal oder
|
|
3104
|
+
WSL-Distro), geprüft gegen dieselbe Umgebungsquelle wie das Einhängen — ohne den ortsbezogenen
|
|
3105
|
+
.env-Abgleich, der bleibt dem Einhängen selbst vorbehalten und kommt dann als `warnung` zurück.
|
|
3106
|
+
Je Welt mit Befund eine Zeile, Welten ohne Befund keine. Wiederverwendet die .ruhezeile-Optik. */
|
|
3107
|
+
function mcpWarnZeile(text) {
|
|
3081
3108
|
var rz = e('div', 'ruhezeile');
|
|
3082
3109
|
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
3083
3110
|
svg.setAttribute('viewBox', '0 0 16 16');
|
|
@@ -3085,19 +3112,37 @@
|
|
|
3085
3112
|
svg.setAttribute('aria-hidden', 'true');
|
|
3086
3113
|
svg.innerHTML = '<circle cx="8" cy="8" r="6.5"/><path d="M8 4.5v4M8 10.5v.5"/>';
|
|
3087
3114
|
rz.appendChild(svg);
|
|
3088
|
-
rz.appendChild(e('p', null,
|
|
3089
|
-
+ (mehrzahl ? 'die Variablen' : 'die Variable') + ' beim Start des Harness gesetzt ' + (mehrzahl ? 'sind' : 'ist')
|
|
3090
|
-
+ ', kann hmgr nicht wissen.'));
|
|
3115
|
+
rz.appendChild(e('p', null, text));
|
|
3091
3116
|
return rz;
|
|
3092
3117
|
}
|
|
3093
3118
|
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3119
|
+
function mcpWarnZeilen(welten) {
|
|
3120
|
+
var mehrere = welten.some(function (w) { return w.distro !== undefined; });
|
|
3121
|
+
var zeilen = [];
|
|
3122
|
+
welten.forEach(function (w) {
|
|
3123
|
+
if (w.ungeprueft) {
|
|
3124
|
+
zeilen.push(mcpWarnZeile('hmgr konnte die Umgebung von WSL ' + w.distro + ' nicht lesen, die Verweise sind ungeprüft.'));
|
|
3125
|
+
return;
|
|
3126
|
+
}
|
|
3127
|
+
if (w.fehlend.length === 0) return;
|
|
3128
|
+
var mz = w.fehlend.length > 1;
|
|
3129
|
+
var namen = w.fehlend.map(function (v) { return '${' + v + '}'; }).join(', ');
|
|
3130
|
+
var verb = mz ? ' sind' : ' ist';
|
|
3131
|
+
if (w.distro !== undefined) {
|
|
3132
|
+
zeilen.push(mcpWarnZeile(namen + verb + ' in WSL ' + w.distro + ' nicht gesetzt (Login-Shell, interaktiv).'));
|
|
3133
|
+
} else if (mehrere) {
|
|
3134
|
+
zeilen.push(mcpWarnZeile(namen + verb + ' in Windows nicht gesetzt.'));
|
|
3135
|
+
} else {
|
|
3136
|
+
zeilen.push(mcpWarnZeile(namen + verb + ' in der Umgebung von hmgr nicht gesetzt. Ob '
|
|
3137
|
+
+ (mz ? 'die Variablen' : 'die Variable') + ' beim Start des Harness gesetzt ' + (mz ? 'sind' : 'ist')
|
|
3138
|
+
+ ', kann hmgr nicht wissen.'));
|
|
3139
|
+
}
|
|
3140
|
+
});
|
|
3141
|
+
return zeilen;
|
|
3142
|
+
}
|
|
3143
|
+
|
|
3144
|
+
/** Der Aufklapp-Keil in einer summary (dreht sich per CSS beim Öffnen). */
|
|
3145
|
+
function keilIcon() {
|
|
3101
3146
|
var pfeil = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
3102
3147
|
pfeil.setAttribute('viewBox', '0 0 16 16');
|
|
3103
3148
|
pfeil.setAttribute('class', 'keil');
|
|
@@ -3107,7 +3152,17 @@
|
|
|
3107
3152
|
pfeil.setAttribute('stroke-linejoin', 'round');
|
|
3108
3153
|
pfeil.setAttribute('aria-hidden', 'true');
|
|
3109
3154
|
pfeil.innerHTML = '<path d="M4.3 2.5 7.8 6 4.3 9.5"/>';
|
|
3110
|
-
|
|
3155
|
+
return pfeil;
|
|
3156
|
+
}
|
|
3157
|
+
|
|
3158
|
+
/** Notizen sind das Langsame am Eintrag (entwurf/gui.html): zugeklappt, öffnen sich nur, wenn
|
|
3159
|
+
jemand sie sucht. Der Wortlaut bleibt, wie er in der mcp.yaml steht, Zeilenumbrüche
|
|
3160
|
+
eingeschlossen (weiss-raum: pre-line in styles.css). */
|
|
3161
|
+
function mcpNotizenBlock(text) {
|
|
3162
|
+
var d = document.createElement('details');
|
|
3163
|
+
d.className = 'notizen';
|
|
3164
|
+
var s = document.createElement('summary');
|
|
3165
|
+
s.appendChild(keilIcon());
|
|
3111
3166
|
s.appendChild(document.createTextNode('Notizen'));
|
|
3112
3167
|
d.appendChild(s);
|
|
3113
3168
|
d.appendChild(e('p', null, text));
|
|
@@ -3135,7 +3190,7 @@
|
|
|
3135
3190
|
konf.appendChild(e('span', 'mono', mcpKonfigWortlaut(eintrag.konfig)));
|
|
3136
3191
|
kEl.appendChild(konf);
|
|
3137
3192
|
|
|
3138
|
-
|
|
3193
|
+
mcpWarnZeilen(k.variablenWelten).forEach(function (z) { kEl.appendChild(z); });
|
|
3139
3194
|
if (eintrag.notizen) kEl.appendChild(mcpNotizenBlock(eintrag.notizen));
|
|
3140
3195
|
|
|
3141
3196
|
return kEl;
|
|
@@ -490,6 +490,13 @@ img.hsymbol{border-radius:3px}
|
|
|
490
490
|
.block .marke-ok{color:var(--emaille-hoch);font-weight:700}
|
|
491
491
|
.block .marke-aus{color:var(--messing-tief);font-weight:700}
|
|
492
492
|
.block .pfad{color:var(--tinte-weich)}
|
|
493
|
+
/* E108: Änderungen unter „hmgr X installiert", aufklappbar wie die Notizen der MCP-Karte. */
|
|
494
|
+
.block .aenderungen-platz{grid-column:1 / -1}
|
|
495
|
+
.block .aenderungen-platz:empty{display:none}
|
|
496
|
+
.aenderungen{margin-top:0}
|
|
497
|
+
.aenderungen .aenderungen-version{margin-top:9px;padding-left:13px;border-left:2px solid var(--strich);font-size:16px;color:var(--tinte-weich)}
|
|
498
|
+
.block .aenderungen ul{margin-top:4px;gap:4px;font-size:16px}
|
|
499
|
+
.block .aenderungen li{display:block}
|
|
493
500
|
|
|
494
501
|
.markt{margin-bottom:26px}
|
|
495
502
|
.marktkopf{display:flex;flex-wrap:wrap;gap:8px 16px;align-items:baseline;margin-bottom:12px;padding-bottom:10px;border-bottom:2px solid var(--tinte)}
|
|
@@ -6,6 +6,17 @@ import { passenderRef } from "./version.js";
|
|
|
6
6
|
import { kannIstRegistriert, kannMcp, kannPlugins, kannProfile, kannSkillOrdner, kannZurueckbauen, kannZusaetzlicheHeime, } from "../ports/harness.js";
|
|
7
7
|
/** So viele `plugin list`-Prozesse laufen im Ist-Zustand höchstens gleichzeitig (E93). */
|
|
8
8
|
const PLUGIN_ABFRAGEN_GLEICHZEITIG = 6;
|
|
9
|
+
/** „0.0.39" → [0, 0, 39]; alles andere (Vorabversion, Text) → undefined. */
|
|
10
|
+
function versionZerlegen(version) {
|
|
11
|
+
const t = /^(\d+)\.(\d+)\.(\d+)$/.exec(version);
|
|
12
|
+
return t === null ? undefined : [Number(t[1]), Number(t[2]), Number(t[3])];
|
|
13
|
+
}
|
|
14
|
+
function versionVergleichen(a, b) {
|
|
15
|
+
for (let i = 0; i < 3; i++)
|
|
16
|
+
if (a[i] !== b[i])
|
|
17
|
+
return a[i] - b[i];
|
|
18
|
+
return 0;
|
|
19
|
+
}
|
|
9
20
|
/**
|
|
10
21
|
* Die Welt eines Orts als Text für Bericht und Verlauf (E101), in der Schreibweise von `--ort`:
|
|
11
22
|
* „home" für die Installation dieses Rechners, „wsl:<distro>" für die einer Distro.
|
|
@@ -394,6 +405,67 @@ export class Anwendungsfaelle {
|
|
|
394
405
|
throw new McpUnbekannt(mcpName);
|
|
395
406
|
return eintrag;
|
|
396
407
|
}
|
|
408
|
+
/**
|
|
409
|
+
* Die Umgebung einer Welt (E107): ohne `distro` die Prozess-Umgebung, sonst die einer im Terminal
|
|
410
|
+
* der Distro gestarteten claude (E104). `undefined`, wenn die Distro-Umgebung nicht lesbar ist.
|
|
411
|
+
* Einzige Stelle dafür, geteilt von Einhängen-Warnung und Kartenhinweis.
|
|
412
|
+
*/
|
|
413
|
+
async mcpUmgebungDerWelt(distro) {
|
|
414
|
+
if (distro === undefined)
|
|
415
|
+
return this.p.umgebung.variablen();
|
|
416
|
+
return await this.p.wsl.variablen(distro).catch(() => undefined);
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* F39 an der Katalog-Karte (E107): je Eintrag mit `${VAR}`-Verweisen die Welten, gegen die zu
|
|
420
|
+
* prüfen ist, jeweils mit Befund. Welten: die der Ziele, an denen der Eintrag eingehängt ist; sonst
|
|
421
|
+
* die der Ziele, an denen er einhängbar wäre (`ortBedienbar`, ohne Git-Wurzel-Ermittlung). Je Distro
|
|
422
|
+
* höchstens ein Aufruf je Lauf; ohne Verweise im Katalog wird nichts befragt. Die `.env`-Zusatzdatei
|
|
423
|
+
* (Hermes) bleibt dem Einhängen vorbehalten. Einträge ohne Verweise fehlen in der Map.
|
|
424
|
+
*/
|
|
425
|
+
async mcpVariablenLage(uebersicht) {
|
|
426
|
+
const ergebnis = new Map();
|
|
427
|
+
const ue = uebersicht ?? (await this.mcpUebersicht());
|
|
428
|
+
const mitVerweisen = ue.katalog.filter((k) => variablenVerweise(k.eintrag.konfig).length > 0);
|
|
429
|
+
if (mitVerweisen.length === 0)
|
|
430
|
+
return ergebnis;
|
|
431
|
+
let moegliche;
|
|
432
|
+
const umgebungen = new Map();
|
|
433
|
+
for (const k of mitVerweisen) {
|
|
434
|
+
let welten = k.eingehaengt.map((z) => wslDistroVonOrt(z.ort));
|
|
435
|
+
if (welten.length === 0) {
|
|
436
|
+
if (moegliche === undefined) {
|
|
437
|
+
moegliche = [];
|
|
438
|
+
for (const ziel of await this.mcpZiele()) {
|
|
439
|
+
const mcp = this.harnessMitMcp(ziel.harness).mcp;
|
|
440
|
+
if (mcp.ortBedienbar !== undefined && !(await mcp.ortBedienbar(ziel.ort)))
|
|
441
|
+
continue;
|
|
442
|
+
moegliche.push(wslDistroVonOrt(ziel.ort));
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
welten = moegliche;
|
|
446
|
+
}
|
|
447
|
+
const verweise = variablenVerweise(k.eintrag.konfig);
|
|
448
|
+
const befunde = [];
|
|
449
|
+
// Lokale Welt zuerst, dann die Distros in der Reihenfolge ihres Auftretens.
|
|
450
|
+
const eindeutig = [...new Set(welten)].sort((a, b) => (a === undefined ? -1 : b === undefined ? 1 : 0));
|
|
451
|
+
for (const distro of eindeutig) {
|
|
452
|
+
let env = umgebungen.get(distro);
|
|
453
|
+
if (env === undefined) {
|
|
454
|
+
env = this.mcpUmgebungDerWelt(distro);
|
|
455
|
+
umgebungen.set(distro, env);
|
|
456
|
+
}
|
|
457
|
+
const umgebung = await env;
|
|
458
|
+
if (umgebung === undefined)
|
|
459
|
+
befunde.push({ distro: distro, ungeprueft: true });
|
|
460
|
+
else {
|
|
461
|
+
const fehlend = verweise.filter((v) => umgebung[v] === undefined);
|
|
462
|
+
befunde.push(distro === undefined ? { fehlend } : { distro, fehlend });
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
ergebnis.set(k.eintrag.name, befunde);
|
|
466
|
+
}
|
|
467
|
+
return ergebnis;
|
|
468
|
+
}
|
|
397
469
|
/**
|
|
398
470
|
* F39: fehlende `${VAR}`-Verweise als Warnung, nie als Abbruch. Geprüft wird gegen die eigene
|
|
399
471
|
* Prozess-Umgebung und, wenn die Fähigkeit eine `.env`-Datei nennt (Hermes), zusätzlich gegen sie.
|
|
@@ -404,17 +476,10 @@ export class Anwendungsfaelle {
|
|
|
404
476
|
return undefined;
|
|
405
477
|
// Ein WSL-Ziel startet claude in der Distro mit deren Umgebung, nicht mit der von Windows (E104).
|
|
406
478
|
const distro = wslDistroVonOrt(ort);
|
|
407
|
-
|
|
408
|
-
if (
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
else {
|
|
412
|
-
const distroEnv = await this.p.wsl.variablen(distro).catch(() => undefined);
|
|
413
|
-
if (distroEnv === undefined) {
|
|
414
|
-
return (`hmgr konnte die Umgebung der WSL-Distro ${distro} nicht lesen; die Verweise ` +
|
|
415
|
-
`${verweise.map((v) => '${' + v + '}').join(', ')} sind deshalb ungeprüft.`);
|
|
416
|
-
}
|
|
417
|
-
prozessEnv = distroEnv;
|
|
479
|
+
const prozessEnv = await this.mcpUmgebungDerWelt(distro);
|
|
480
|
+
if (prozessEnv === undefined) {
|
|
481
|
+
return (`hmgr konnte die Umgebung der WSL-Distro ${distro} nicht lesen; die Verweise ` +
|
|
482
|
+
`${verweise.map((v) => '${' + v + '}').join(', ')} sind deshalb ungeprüft.`);
|
|
418
483
|
}
|
|
419
484
|
const envPfad = faehig.mcp.envDatei?.(ort);
|
|
420
485
|
const zusatzEnv = envPfad === undefined ? {} : await this.p.umgebung.envDatei(envPfad);
|
|
@@ -1988,6 +2053,31 @@ export class Anwendungsfaelle {
|
|
|
1988
2053
|
async verlauf() {
|
|
1989
2054
|
return (await this.p.verlauf.lesen()).eintraege;
|
|
1990
2055
|
}
|
|
2056
|
+
/**
|
|
2057
|
+
* Die Änderungen (Commit-Betreffs) der Versionen, die ein Sprung von `vorher` auf `version`
|
|
2058
|
+
* mitbrachte (E108): alle Versionen V mit vorher < V ≤ version, neueste zuerst. Ohne `vorher`
|
|
2059
|
+
* nur `version` selbst. Versionen ohne Eintrag in der Liste (oder ohne Commits) fehlen im
|
|
2060
|
+
* Ergebnis; eine nicht als x.y.z lesbare Version ergibt eine leere Liste.
|
|
2061
|
+
*/
|
|
2062
|
+
async hmgrAenderungen(vorher, version) {
|
|
2063
|
+
const bis = versionZerlegen(version);
|
|
2064
|
+
if (bis === undefined)
|
|
2065
|
+
return [];
|
|
2066
|
+
const ab = vorher === undefined ? undefined : versionZerlegen(vorher);
|
|
2067
|
+
const liste = await this.p.aenderungen.lesen();
|
|
2068
|
+
const treffer = [];
|
|
2069
|
+
for (const [v, commits] of Object.entries(liste)) {
|
|
2070
|
+
const zahlen = versionZerlegen(v);
|
|
2071
|
+
if (zahlen === undefined || commits.length === 0)
|
|
2072
|
+
continue;
|
|
2073
|
+
const imBereich = vorher === undefined
|
|
2074
|
+
? versionVergleichen(zahlen, bis) === 0
|
|
2075
|
+
: ab !== undefined && versionVergleichen(zahlen, ab) > 0 && versionVergleichen(zahlen, bis) <= 0;
|
|
2076
|
+
if (imBereich)
|
|
2077
|
+
treffer.push({ zahlen, eintrag: { version: v, commits } });
|
|
2078
|
+
}
|
|
2079
|
+
return treffer.sort((a, b) => versionVergleichen(b.zahlen, a.zahlen)).map((t) => t.eintrag);
|
|
2080
|
+
}
|
|
1991
2081
|
/**
|
|
1992
2082
|
* Merkt die installierte Version eines hmgr-Pakets (GUI oder CLI) und schreibt bei einem
|
|
1993
2083
|
* Versionssprung einen Verlaufseintrag (E80). Der erste Aufruf ohne gemerkte Version merkt nur,
|
|
@@ -2006,7 +2096,7 @@ export class Anwendungsfaelle {
|
|
|
2006
2096
|
const eintrag = {
|
|
2007
2097
|
zeit: new Date().toISOString(),
|
|
2008
2098
|
ausloeser,
|
|
2009
|
-
ereignisse: [{ art: 'hmgr-installiert', paket, version }],
|
|
2099
|
+
ereignisse: [{ art: 'hmgr-installiert', paket, version, vorher: bisher }],
|
|
2010
2100
|
};
|
|
2011
2101
|
await this.p.verlauf.schreiben({ gemerkt, eintraege: [eintrag, ...daten.eintraege] });
|
|
2012
2102
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hmgr",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.41",
|
|
4
4
|
"description": "Harness Manager: Skills und Plugins für AI-Harnesses verwalten",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Tim Kaufmann",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
21
|
"dev": "node src/cli/main.ts",
|
|
22
|
-
"build": "tsc -p tsconfig.build.json && node scripts/copy-gui-assets.mjs",
|
|
22
|
+
"build": "tsc -p tsconfig.build.json && node scripts/copy-gui-assets.mjs && node scripts/aenderungen-erzeugen.mjs",
|
|
23
23
|
"gui": "npm run build && electron dist/gui/main.js",
|
|
24
24
|
"gui:smoke": "npm run build && node scripts/gui-smoke-test.ts",
|
|
25
25
|
"gui:app": "npm run build && electron-builder --mac --arm64",
|