hmgr 0.0.38 → 0.0.39

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/gui/main.js CHANGED
@@ -416,8 +416,11 @@ function registriereIpc() {
416
416
  }));
417
417
  // MCP-Ansicht (E61-Folgerunde): Whitelisting und der F39-Vermerk je Karte stehen in mcp-ansicht.ts
418
418
  // (rein, ohne Electron, wie oeffnen.ts und icons.ts), damit sie testbar sind. Der Main-Prozess
419
- // ruft nur noch auf und liefert die eigene Prozess-Umgebung für die F39-Prüfung.
420
- ipcMain.handle('hmgr:mcpUebersicht', async () => auffangen(async () => mcpUebersichtSerialisieren(await anwendungsfaelle.mcpUebersicht(), process.env)));
419
+ // ruft nur noch auf; die F39-Lage je Welt (lokal, WSL-Distro) kommt aus dem Kern (E107).
420
+ ipcMain.handle('hmgr:mcpUebersicht', async () => auffangen(async () => {
421
+ const uebersicht = await anwendungsfaelle.mcpUebersicht();
422
+ return mcpUebersichtSerialisieren(uebersicht, await anwendungsfaelle.mcpVariablenLage(uebersicht));
423
+ }));
421
424
  // Plätze für den Einhängen-Dialog (F42): die Fähigkeit hängt am Adapter, nicht am Namen (E16),
422
425
  // deshalb kommt die Liste unverändert aus dem Kern statt aus einer Harness-Fallunterscheidung hier.
423
426
  ipcMain.handle('hmgr:mcpPlaetze', async () => auffangen(async () => anwendungsfaelle.mcpPlaetze()));
@@ -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 { variablenVerweise, } from "../kern/anwendungsfaelle.js";
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
- * F39 an der Katalog-Karte: dieselbe Prüf-Funktion wie beim tatsächlichen Einhängen
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
- fehlendeVariablen: mcpFehlendeVariablen(k.eintrag, umgebung),
22
+ variablenWelten: lage.get(k.eintrag.name) ?? [],
32
23
  })),
33
24
  unbekannt: uebersicht.unbekannt,
34
25
  unbekannteGeteilteFundorte: uebersicht.unbekannteGeteilteFundorte,
@@ -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, fehlendeVariablen }, dazu
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.
@@ -3071,13 +3071,11 @@
3071
3071
  return a;
3072
3072
  }
3073
3073
 
3074
- /** F39: die Prüf-Funktion ist dieselbe wie beim tatsächlichen Einhängen, hier aber nur gegen die
3075
- Prozess-Umgebung von hmgr (der Main-Prozess liefert `fehlendeVariablen` schon fertig mit der
3076
- Übersicht, ohne den ortsbezogenen .env-Abgleich, der bleibt dem Einhängen selbst vorbehalten
3077
- und kommt dann als `warnung` zurück). Wiederverwendet die bestehende .ruhezeile-Optik. */
3078
- function mcpWarnZeile(fehlend) {
3079
- var mehrzahl = fehlend.length > 1;
3080
- var namen = fehlend.map(function (v) { return '${' + v + '}'; }).join(', ');
3074
+ /** F39 (E107): der Main-Prozess liefert je Karte `variablenWelten`, die Befunde je Welt (lokal oder
3075
+ WSL-Distro), geprüft gegen dieselbe Umgebungsquelle wie das Einhängen — ohne den ortsbezogenen
3076
+ .env-Abgleich, der bleibt dem Einhängen selbst vorbehalten und kommt dann als `warnung` zurück.
3077
+ Je Welt mit Befund eine Zeile, Welten ohne Befund keine. Wiederverwendet die .ruhezeile-Optik. */
3078
+ function mcpWarnZeile(text) {
3081
3079
  var rz = e('div', 'ruhezeile');
3082
3080
  var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
3083
3081
  svg.setAttribute('viewBox', '0 0 16 16');
@@ -3085,12 +3083,35 @@
3085
3083
  svg.setAttribute('aria-hidden', 'true');
3086
3084
  svg.innerHTML = '<circle cx="8" cy="8" r="6.5"/><path d="M8 4.5v4M8 10.5v.5"/>';
3087
3085
  rz.appendChild(svg);
3088
- rz.appendChild(e('p', null, namen + (mehrzahl ? ' sind' : ' ist') + ' in der Umgebung von hmgr nicht gesetzt. Ob '
3089
- + (mehrzahl ? 'die Variablen' : 'die Variable') + ' beim Start des Harness gesetzt ' + (mehrzahl ? 'sind' : 'ist')
3090
- + ', kann hmgr nicht wissen.'));
3086
+ rz.appendChild(e('p', null, text));
3091
3087
  return rz;
3092
3088
  }
3093
3089
 
3090
+ function mcpWarnZeilen(welten) {
3091
+ var mehrere = welten.some(function (w) { return w.distro !== undefined; });
3092
+ var zeilen = [];
3093
+ welten.forEach(function (w) {
3094
+ if (w.ungeprueft) {
3095
+ zeilen.push(mcpWarnZeile('hmgr konnte die Umgebung von WSL ' + w.distro + ' nicht lesen, die Verweise sind ungeprüft.'));
3096
+ return;
3097
+ }
3098
+ if (w.fehlend.length === 0) return;
3099
+ var mz = w.fehlend.length > 1;
3100
+ var namen = w.fehlend.map(function (v) { return '${' + v + '}'; }).join(', ');
3101
+ var verb = mz ? ' sind' : ' ist';
3102
+ if (w.distro !== undefined) {
3103
+ zeilen.push(mcpWarnZeile(namen + verb + ' in WSL ' + w.distro + ' nicht gesetzt (Login-Shell, interaktiv).'));
3104
+ } else if (mehrere) {
3105
+ zeilen.push(mcpWarnZeile(namen + verb + ' in Windows nicht gesetzt.'));
3106
+ } else {
3107
+ zeilen.push(mcpWarnZeile(namen + verb + ' in der Umgebung von hmgr nicht gesetzt. Ob '
3108
+ + (mz ? 'die Variablen' : 'die Variable') + ' beim Start des Harness gesetzt ' + (mz ? 'sind' : 'ist')
3109
+ + ', kann hmgr nicht wissen.'));
3110
+ }
3111
+ });
3112
+ return zeilen;
3113
+ }
3114
+
3094
3115
  /** Notizen sind das Langsame am Eintrag (entwurf/gui.html): zugeklappt, öffnen sich nur, wenn
3095
3116
  jemand sie sucht. Der Wortlaut bleibt, wie er in der mcp.yaml steht, Zeilenumbrüche
3096
3117
  eingeschlossen (weiss-raum: pre-line in styles.css). */
@@ -3135,7 +3156,7 @@
3135
3156
  konf.appendChild(e('span', 'mono', mcpKonfigWortlaut(eintrag.konfig)));
3136
3157
  kEl.appendChild(konf);
3137
3158
 
3138
- if (k.fehlendeVariablen.length > 0) kEl.appendChild(mcpWarnZeile(k.fehlendeVariablen));
3159
+ mcpWarnZeilen(k.variablenWelten).forEach(function (z) { kEl.appendChild(z); });
3139
3160
  if (eintrag.notizen) kEl.appendChild(mcpNotizenBlock(eintrag.notizen));
3140
3161
 
3141
3162
  return kEl;
@@ -394,6 +394,67 @@ export class Anwendungsfaelle {
394
394
  throw new McpUnbekannt(mcpName);
395
395
  return eintrag;
396
396
  }
397
+ /**
398
+ * Die Umgebung einer Welt (E107): ohne `distro` die Prozess-Umgebung, sonst die einer im Terminal
399
+ * der Distro gestarteten claude (E104). `undefined`, wenn die Distro-Umgebung nicht lesbar ist.
400
+ * Einzige Stelle dafür, geteilt von Einhängen-Warnung und Kartenhinweis.
401
+ */
402
+ async mcpUmgebungDerWelt(distro) {
403
+ if (distro === undefined)
404
+ return this.p.umgebung.variablen();
405
+ return await this.p.wsl.variablen(distro).catch(() => undefined);
406
+ }
407
+ /**
408
+ * F39 an der Katalog-Karte (E107): je Eintrag mit `${VAR}`-Verweisen die Welten, gegen die zu
409
+ * prüfen ist, jeweils mit Befund. Welten: die der Ziele, an denen der Eintrag eingehängt ist; sonst
410
+ * die der Ziele, an denen er einhängbar wäre (`ortBedienbar`, ohne Git-Wurzel-Ermittlung). Je Distro
411
+ * höchstens ein Aufruf je Lauf; ohne Verweise im Katalog wird nichts befragt. Die `.env`-Zusatzdatei
412
+ * (Hermes) bleibt dem Einhängen vorbehalten. Einträge ohne Verweise fehlen in der Map.
413
+ */
414
+ async mcpVariablenLage(uebersicht) {
415
+ const ergebnis = new Map();
416
+ const ue = uebersicht ?? (await this.mcpUebersicht());
417
+ const mitVerweisen = ue.katalog.filter((k) => variablenVerweise(k.eintrag.konfig).length > 0);
418
+ if (mitVerweisen.length === 0)
419
+ return ergebnis;
420
+ let moegliche;
421
+ const umgebungen = new Map();
422
+ for (const k of mitVerweisen) {
423
+ let welten = k.eingehaengt.map((z) => wslDistroVonOrt(z.ort));
424
+ if (welten.length === 0) {
425
+ if (moegliche === undefined) {
426
+ moegliche = [];
427
+ for (const ziel of await this.mcpZiele()) {
428
+ const mcp = this.harnessMitMcp(ziel.harness).mcp;
429
+ if (mcp.ortBedienbar !== undefined && !(await mcp.ortBedienbar(ziel.ort)))
430
+ continue;
431
+ moegliche.push(wslDistroVonOrt(ziel.ort));
432
+ }
433
+ }
434
+ welten = moegliche;
435
+ }
436
+ const verweise = variablenVerweise(k.eintrag.konfig);
437
+ const befunde = [];
438
+ // Lokale Welt zuerst, dann die Distros in der Reihenfolge ihres Auftretens.
439
+ const eindeutig = [...new Set(welten)].sort((a, b) => (a === undefined ? -1 : b === undefined ? 1 : 0));
440
+ for (const distro of eindeutig) {
441
+ let env = umgebungen.get(distro);
442
+ if (env === undefined) {
443
+ env = this.mcpUmgebungDerWelt(distro);
444
+ umgebungen.set(distro, env);
445
+ }
446
+ const umgebung = await env;
447
+ if (umgebung === undefined)
448
+ befunde.push({ distro: distro, ungeprueft: true });
449
+ else {
450
+ const fehlend = verweise.filter((v) => umgebung[v] === undefined);
451
+ befunde.push(distro === undefined ? { fehlend } : { distro, fehlend });
452
+ }
453
+ }
454
+ ergebnis.set(k.eintrag.name, befunde);
455
+ }
456
+ return ergebnis;
457
+ }
397
458
  /**
398
459
  * F39: fehlende `${VAR}`-Verweise als Warnung, nie als Abbruch. Geprüft wird gegen die eigene
399
460
  * Prozess-Umgebung und, wenn die Fähigkeit eine `.env`-Datei nennt (Hermes), zusätzlich gegen sie.
@@ -404,17 +465,10 @@ export class Anwendungsfaelle {
404
465
  return undefined;
405
466
  // Ein WSL-Ziel startet claude in der Distro mit deren Umgebung, nicht mit der von Windows (E104).
406
467
  const distro = wslDistroVonOrt(ort);
407
- let prozessEnv;
408
- if (distro === undefined) {
409
- prozessEnv = this.p.umgebung.variablen();
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;
468
+ const prozessEnv = await this.mcpUmgebungDerWelt(distro);
469
+ if (prozessEnv === undefined) {
470
+ return (`hmgr konnte die Umgebung der WSL-Distro ${distro} nicht lesen; die Verweise ` +
471
+ `${verweise.map((v) => '${' + v + '}').join(', ')} sind deshalb ungeprüft.`);
418
472
  }
419
473
  const envPfad = faehig.mcp.envDatei?.(ort);
420
474
  const zusatzEnv = envPfad === undefined ? {} : await this.p.umgebung.envDatei(envPfad);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hmgr",
3
- "version": "0.0.38",
3
+ "version": "0.0.39",
4
4
  "description": "Harness Manager: Skills und Plugins für AI-Harnesses verwalten",
5
5
  "license": "MIT",
6
6
  "author": "Tim Kaufmann",