hmgr 0.0.52 → 0.0.54
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/aenderungen.json +6 -0
- package/dist/cli/hilfe.js +4 -0
- package/dist/cli/main.js +22 -0
- package/dist/gui/main.js +75 -4
- package/dist/gui/preload.cjs +1 -0
- package/dist/gui/renderer/index.html +7 -1
- package/dist/gui/renderer/renderer.js +129 -32
- package/dist/gui/renderer/styles.css +2 -12
- package/dist/kern/anwendungsfaelle.js +9 -0
- package/package.json +1 -1
package/dist/aenderungen.json
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"fassung": 1,
|
|
3
3
|
"versionen": {
|
|
4
|
+
"0.0.54": [
|
|
5
|
+
"Der Dialog „Einhängen“ eines MCP-Servers hat jetzt ein Suchfeld. Tippen filtert die Orte nach Name und Pfad, so findest du ein Arbeitsverzeichnis ohne langes Scrollen."
|
|
6
|
+
],
|
|
7
|
+
"0.0.53": [
|
|
8
|
+
"MCP-Server stehen an der Ordnerkarte jetzt in derselben Tabelle wie die Skills, mit dem Zeichen des Harness davor. Ein Tooltip erklärt, warum ein Server für Hermes fehlt: Hermes liest MCP-Server nur im Home oder in einem Profil, nicht pro Ordner. `hmgr mcp list` sagt das am Ende ebenfalls."
|
|
9
|
+
],
|
|
4
10
|
"0.0.52": [
|
|
5
11
|
"Liegt ein Skill in einem Repo in mehreren Fassungen, je Werkzeug eine (etwa `.claude/skills` und `.hermes/skills`), verlinkt hmgr jetzt für jeden Harness die passende Fassung. Gibt es keine passende, nennt die Meldung die Pfade, und `hmgr link … --pfad` wählt einen aus."
|
|
6
12
|
],
|
package/dist/cli/hilfe.js
CHANGED
|
@@ -424,6 +424,10 @@ global (Scope user). Hermes kennt nur global, mcp_servers in seiner config.yaml
|
|
|
424
424
|
mit --ort profil:<name>); ein Projekt-Ziel ist bei Hermes ein Fehler, es kennt keine Projektebene für
|
|
425
425
|
MCPs. agents kennt MCP-Server gar nicht.
|
|
426
426
|
|
|
427
|
+
Hängt ein Eintrag an einem Arbeitsverzeichnis und ist ein aktiver Harness ohne Projektebene (Hermes) da,
|
|
428
|
+
endet mcp list mit einer Zeile, die sagt, dass dieser Harness den Eintrag dort nicht liest, und auf
|
|
429
|
+
--ort home oder --ort profil:<name> verweist.
|
|
430
|
+
|
|
427
431
|
Bei claude-code führt der Scope local die Server je Git-Repo, nicht je Unterordner (E91). Ein
|
|
428
432
|
Arbeitsverzeichnis, das in einem Repo liegt, ohne dessen Wurzel zu sein, bekommt deshalb kein mcp add,
|
|
429
433
|
mcp remove und mcp migrate: die Meldung nennt den Wurzelordner, dort gehören die Server hin (ist er
|
package/dist/cli/main.js
CHANGED
|
@@ -741,6 +741,28 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
|
|
|
741
741
|
for (const f of [...uebersicht.unbekannteGeteilteFundorte].sort((a, b) => nachName(a.name, b.name)))
|
|
742
742
|
console.log(` ${f.name} ${f.ziel.harness} ${beschreibeOrt(f.ziel.ort)} ${f.datei} · Scope ${f.scope}`);
|
|
743
743
|
}
|
|
744
|
+
// E120: hängt etwas an einem Arbeitsverzeichnis, erklärt eine Zeile, warum ein aktiver Harness
|
|
745
|
+
// ohne Ordner-MCP (Hermes) es dort nicht hat. Abgeleitet aus den Ebenen der Fähigkeit (E16).
|
|
746
|
+
const anOrdner = [
|
|
747
|
+
...uebersicht.katalog.flatMap((k) => [...k.eingehaengt, ...k.geteilteFundorte.map((g) => g.ziel)]),
|
|
748
|
+
...uebersicht.unbekannt.map((u) => u.ziel),
|
|
749
|
+
...uebersicht.unbekannteGeteilteFundorte.map((u) => u.ziel),
|
|
750
|
+
].some((z) => z.ort.art === 'arbeitsverzeichnis');
|
|
751
|
+
if (anOrdner) {
|
|
752
|
+
const aktive = await anwendungsfaelle.aktiveHarnesses();
|
|
753
|
+
const anzeigeNamen = { 'claude-code': 'Claude Code', hermes: 'Hermes', agents: 'Agents' };
|
|
754
|
+
for (const { harness, ebenen } of anwendungsfaelle.mcpEbenen()) {
|
|
755
|
+
if (!aktive.includes(harness) || ebenen.includes('arbeitsverzeichnis'))
|
|
756
|
+
continue;
|
|
757
|
+
const home = ebenen.includes('home');
|
|
758
|
+
const profil = ebenen.includes('profil');
|
|
759
|
+
if (!home && !profil)
|
|
760
|
+
continue;
|
|
761
|
+
const wo = home && profil ? 'im Home oder in einem Profil' : home ? 'im Home' : 'in einem Profil';
|
|
762
|
+
const orte = [...(home ? ['--ort home'] : []), ...(profil ? ['--ort profil:<name>'] : [])].join(' oder ');
|
|
763
|
+
console.log(`${anzeigeNamen[harness] ?? harness} liest MCP-Server nicht pro Ordner, nur ${wo} (${orte}).`);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
744
766
|
return 0;
|
|
745
767
|
}
|
|
746
768
|
if (unterkommando !== 'add' && unterkommando !== 'remove' && unterkommando !== 'migrate')
|
package/dist/gui/main.js
CHANGED
|
@@ -464,6 +464,7 @@ function registriereIpc() {
|
|
|
464
464
|
}));
|
|
465
465
|
// Plätze für den Einhängen-Dialog (F42): die Fähigkeit hängt am Adapter, nicht am Namen (E16),
|
|
466
466
|
// deshalb kommt die Liste unverändert aus dem Kern statt aus einer Harness-Fallunterscheidung hier.
|
|
467
|
+
ipcMain.handle('hmgr:mcpEbenen', async () => auffangen(async () => anwendungsfaelle.mcpEbenen()));
|
|
467
468
|
ipcMain.handle('hmgr:mcpPlaetze', async () => auffangen(async () => anwendungsfaelle.mcpPlaetze()));
|
|
468
469
|
ipcMain.handle('hmgr:mcpEinhaengen', async (_event, args) => auffangen(async () => mcpWirkungSerialisieren(await anwendungsfaelle.mcpEinhaengen({ name: args.name, ziel: zielAusIpc(args.harness, args.ort) }))));
|
|
469
470
|
ipcMain.handle('hmgr:mcpAushaengen', async (_event, args) => auffangen(async () => mcpWirkungSerialisieren(await anwendungsfaelle.mcpAushaengen({ name: args.name, ziel: zielAusIpc(args.harness, args.ort) }))));
|
|
@@ -997,7 +998,7 @@ function fensterOeffnen() {
|
|
|
997
998
|
streifenHarnesse = streifen[0]?.querySelector('.zeilenzeichen')?.getAttribute('aria-label') ?? null;
|
|
998
999
|
streifenText = streifen[0]?.querySelector('.bundlekopf')?.textContent?.replace(/\\s+/g, ' ').trim() ?? null;
|
|
999
1000
|
alleGruppeZeilen = Array.from(streifen[0]?.querySelectorAll('.linkliste li .name') ?? []).map(nurName).join(',');
|
|
1000
|
-
alleTabelleZeilen = Array.from(streifenKarte?.querySelectorAll('.linkliste li') ?? [])
|
|
1001
|
+
alleTabelleZeilen = Array.from(streifenKarte?.querySelectorAll('.linkliste:not(.mcpzeilen) li') ?? [])
|
|
1001
1002
|
.filter((li) => li.closest('.bundlegruppe') === null && li.querySelector('.name'))
|
|
1002
1003
|
.map((li) => nurName(li.querySelector('.name'))).join(',');
|
|
1003
1004
|
Array.from(streifen[0]?.querySelectorAll('.bundlekopf button') ?? [])
|
|
@@ -1045,6 +1046,17 @@ function fensterOeffnen() {
|
|
|
1045
1046
|
var mcpWahlTextFrei = null;
|
|
1046
1047
|
// E91: die Wahlzeile des Unterordners im Repo ist deaktiviert und trägt die Notiz.
|
|
1047
1048
|
var mcpUnterordnerGesperrt = null;
|
|
1049
|
+
var mcpSucheVorhanden = false;
|
|
1050
|
+
var mcpSucheLeerBeimOeffnen = false;
|
|
1051
|
+
var mcpSucheFokus = false;
|
|
1052
|
+
var mcpSucheZeilenGesamt = 0;
|
|
1053
|
+
var mcpSucheNurTreffer = false;
|
|
1054
|
+
var mcpSucheAndereVersteckt = false;
|
|
1055
|
+
var mcpSucheLeerhinweis = null;
|
|
1056
|
+
var mcpSucheLeerhinweisWeg = false;
|
|
1057
|
+
var mcpSucheAbgehakt = false;
|
|
1058
|
+
var mcpSucheEnterOffen = false;
|
|
1059
|
+
var mcpSucheNachNeuOeffnen = false;
|
|
1048
1060
|
try {
|
|
1049
1061
|
var mcpEinKnoepfe = Array.from(document.querySelectorAll('#mcpliste .mcpkopf button'))
|
|
1050
1062
|
.filter((b) => (b.textContent || '').indexOf('Einhängen') === 0);
|
|
@@ -1062,6 +1074,44 @@ function fensterOeffnen() {
|
|
|
1062
1074
|
mcpUnterordnerGesperrt = Array.from(document.querySelectorAll('#dm-orte .wahlzeile'))
|
|
1063
1075
|
.filter((z) => (z.textContent || '').indexOf('unterordner') > -1)
|
|
1064
1076
|
.map((z) => z.querySelector('input')?.disabled === true);
|
|
1077
|
+
// E122: Suchfeld im Dialog. Fokus, Filter, Leerhinweis, Abhaken beim Ausblenden,
|
|
1078
|
+
// Enter ohne Auswahl, Zustand nach erneutem Öffnen.
|
|
1079
|
+
var dmSuche = document.getElementById('dm-suche');
|
|
1080
|
+
mcpSucheVorhanden = dmSuche !== null;
|
|
1081
|
+
mcpSucheLeerBeimOeffnen = dmSuche?.value === '';
|
|
1082
|
+
mcpSucheFokus = document.activeElement?.id === 'dm-suche';
|
|
1083
|
+
var dmSetze = (wert) => {
|
|
1084
|
+
dmSuche.value = wert;
|
|
1085
|
+
dmSuche.dispatchEvent(new Event('input', { bubbles: true }));
|
|
1086
|
+
};
|
|
1087
|
+
var dmZeilen = () => Array.from(document.querySelectorAll('#dm-orte .wahlzeile'));
|
|
1088
|
+
mcpSucheZeilenGesamt = dmZeilen().length;
|
|
1089
|
+
dmSetze('unterordner');
|
|
1090
|
+
var dmSichtbar = dmZeilen().filter((z) => !z.hidden);
|
|
1091
|
+
mcpSucheNurTreffer = dmSichtbar.length > 0
|
|
1092
|
+
&& dmSichtbar.every((z) => (z.textContent || '').indexOf('unterordner') > -1);
|
|
1093
|
+
mcpSucheAndereVersteckt = dmZeilen().some((z) => z.hidden);
|
|
1094
|
+
dmSetze('zzzkeintreffer');
|
|
1095
|
+
mcpSucheLeerhinweis = document.querySelector('#dm-orte .leerhinweis')?.textContent ?? null;
|
|
1096
|
+
dmSetze('');
|
|
1097
|
+
mcpSucheLeerhinweisWeg = document.querySelector('#dm-orte .leerhinweis') === null
|
|
1098
|
+
&& dmZeilen().every((z) => !z.hidden);
|
|
1099
|
+
var dmFrei = dmZeilen().find((z) => z.querySelector('input')?.disabled === false);
|
|
1100
|
+
var dmFreiRadio = dmFrei?.querySelector('input');
|
|
1101
|
+
if (dmFreiRadio) {
|
|
1102
|
+
dmFreiRadio.checked = true;
|
|
1103
|
+
dmSetze('unterordner');
|
|
1104
|
+
mcpSucheAbgehakt = dmFrei.hidden === true && dmFreiRadio.checked === false;
|
|
1105
|
+
}
|
|
1106
|
+
dmSetze('');
|
|
1107
|
+
dmSuche.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
|
|
1108
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
1109
|
+
mcpSucheEnterOffen = document.getElementById('d-mcp')?.open === true;
|
|
1110
|
+
dmSetze('unterordner');
|
|
1111
|
+
document.querySelector('#d-mcp button[value="abbruch"]')?.click();
|
|
1112
|
+
await mcpWahlOeffnen(mcpEinKnoepfe[1]);
|
|
1113
|
+
mcpSucheNachNeuOeffnen = document.getElementById('dm-suche')?.value === ''
|
|
1114
|
+
&& dmZeilen().length > 0 && dmZeilen().every((z) => !z.hidden);
|
|
1065
1115
|
document.querySelector('#d-mcp button[value="abbruch"]')?.click();
|
|
1066
1116
|
} catch (fehler) {
|
|
1067
1117
|
mcpFehler = String(fehler);
|
|
@@ -1074,7 +1124,7 @@ function fensterOeffnen() {
|
|
|
1074
1124
|
// Seit E64 stehen im MCP-Abschnitt zwei Knopfarten nebeneinander (Entfernen und
|
|
1075
1125
|
// Übernehmen), deshalb wird hier nicht mehr der erste Knopf genommen, sondern der
|
|
1076
1126
|
// Entfernen-Knopf an seinem aria-label erkannt.
|
|
1077
|
-
var mcpZeilenKnoepfe = Array.from(document.querySelectorAll('#zielliste .
|
|
1127
|
+
var mcpZeilenKnoepfe = Array.from(document.querySelectorAll('#zielliste .mcpzeilen button'));
|
|
1078
1128
|
try {
|
|
1079
1129
|
var mcpAusKnopf = mcpZeilenKnoepfe.find(function (b) {
|
|
1080
1130
|
return (b.getAttribute('aria-label') || '').indexOf('aushängen') > -1;
|
|
@@ -1126,13 +1176,20 @@ function fensterOeffnen() {
|
|
|
1126
1176
|
var hermesKarte = karteMitKopftext('Hermes · Home');
|
|
1127
1177
|
var hermesMcpText = hermesKarte?.querySelector('.mcpkarteabschnitt')?.textContent
|
|
1128
1178
|
?.replace(/\\s+/g, ' ').trim() ?? null;
|
|
1129
|
-
var hermesMcpZeilenKnopfZahl = hermesKarte?.querySelectorAll('.
|
|
1179
|
+
var hermesMcpZeilenKnopfZahl = hermesKarte?.querySelectorAll('.mcpzeilen button').length ?? 0;
|
|
1130
1180
|
var hermesMcpKnopfVorhanden = mcpHinzuKnopfAn(hermesKarte) !== undefined;
|
|
1131
1181
|
var kundeXKarte = karteMitKopftext('kunde-x');
|
|
1132
1182
|
var kundeXMcpText = kundeXKarte?.querySelector('.mcpkarteabschnitt')?.textContent
|
|
1133
1183
|
?.replace(/\\s+/g, ' ').trim() ?? null;
|
|
1134
|
-
var kundeXMcpZeilenKnopfZahl = kundeXKarte?.querySelectorAll('.
|
|
1184
|
+
var kundeXMcpZeilenKnopfZahl = kundeXKarte?.querySelectorAll('.mcpzeilen button').length ?? 0;
|
|
1135
1185
|
var kundeXMcpKnopfVorhanden = mcpHinzuKnopfAn(kundeXKarte) !== undefined;
|
|
1186
|
+
// E120: Tabellenkopf des MCP-Abschnitts und die Zeile mail (Katalog, unter „Alle").
|
|
1187
|
+
var kundeXMcpKopf = Array.from(kundeXKarte?.querySelectorAll('.mcpkarteabschnitt .linkkopf .etikett') ?? [])
|
|
1188
|
+
.map((x) => x.textContent).join('|');
|
|
1189
|
+
var kundeXMailZeile = Array.from(kundeXKarte?.querySelectorAll('.mcpzeilen li') ?? [])
|
|
1190
|
+
.find((li) => (li.querySelector('.name')?.textContent || '') === 'mail');
|
|
1191
|
+
var kundeXMailQuelle = kundeXMailZeile?.querySelector('.quelle')?.textContent ?? null;
|
|
1192
|
+
var kundeXMailZeichenTitel = kundeXMailZeile?.querySelector('.zeilenzeichen')?.getAttribute('title') ?? null;
|
|
1136
1193
|
// Kartenkopf-Zahl (E71): der Kopf zählt Skills, gebündelt wie der Körper zeilt. An der
|
|
1137
1194
|
// Verzeichnis-Karte kunde-x hängen dieselben zwei Skills an zwei Harnesses, eine Summe
|
|
1138
1195
|
// über die Abschnitte ergäbe hier 4.
|
|
@@ -1359,6 +1416,17 @@ function fensterOeffnen() {
|
|
|
1359
1416
|
mcpWahlText,
|
|
1360
1417
|
mcpWahlTextFrei,
|
|
1361
1418
|
mcpUnterordnerGesperrt,
|
|
1419
|
+
mcpSucheVorhanden,
|
|
1420
|
+
mcpSucheLeerBeimOeffnen,
|
|
1421
|
+
mcpSucheFokus,
|
|
1422
|
+
mcpSucheZeilenGesamt,
|
|
1423
|
+
mcpSucheNurTreffer,
|
|
1424
|
+
mcpSucheAndereVersteckt,
|
|
1425
|
+
mcpSucheLeerhinweis,
|
|
1426
|
+
mcpSucheLeerhinweisWeg,
|
|
1427
|
+
mcpSucheAbgehakt,
|
|
1428
|
+
mcpSucheEnterOffen,
|
|
1429
|
+
mcpSucheNachNeuOeffnen,
|
|
1362
1430
|
mcpFehler,
|
|
1363
1431
|
dMcpAusOffenNachOeffnen,
|
|
1364
1432
|
dMcpAusOffenNachAbbrechen,
|
|
@@ -1373,6 +1441,9 @@ function fensterOeffnen() {
|
|
|
1373
1441
|
kundeXMcpText,
|
|
1374
1442
|
kundeXMcpZeilenKnopfZahl,
|
|
1375
1443
|
kundeXMcpKnopfVorhanden,
|
|
1444
|
+
kundeXMcpKopf,
|
|
1445
|
+
kundeXMailQuelle,
|
|
1446
|
+
kundeXMailZeichenTitel,
|
|
1376
1447
|
kundeXKopfZahl,
|
|
1377
1448
|
hermesKopfZahl,
|
|
1378
1449
|
hermesWarnzahl,
|
package/dist/gui/preload.cjs
CHANGED
|
@@ -100,6 +100,7 @@ contextBridge.exposeInMainWorld('hmgr', {
|
|
|
100
100
|
mcpUebersicht: () => ipcRenderer.invoke('hmgr:mcpUebersicht'),
|
|
101
101
|
/** Plätze für den Einhängen-Dialog (F42): kommt aus dem Kern, hängt an der Fähigkeit (E16). */
|
|
102
102
|
mcpPlaetze: () => ipcRenderer.invoke('hmgr:mcpPlaetze'),
|
|
103
|
+
mcpEbenen: () => ipcRenderer.invoke('hmgr:mcpEbenen'),
|
|
103
104
|
mcpEinhaengen: (args) => ipcRenderer.invoke('hmgr:mcpEinhaengen', args),
|
|
104
105
|
mcpAushaengen: (args) => ipcRenderer.invoke('hmgr:mcpAushaengen', args),
|
|
105
106
|
/** Übernehmen aus der geteilten .mcp.json in den privaten Scope (E64), nach Bestätigung im Renderer. */
|
|
@@ -573,7 +573,13 @@
|
|
|
573
573
|
<h3>Wohin soll <span id="dm-name">der Server</span>?</h3>
|
|
574
574
|
<p id="dm-text">Ein Ort je Einhängen. agents kennt keine MCP-Server und steht deshalb nicht zur Wahl.</p>
|
|
575
575
|
</div>
|
|
576
|
-
<div class="dkoerper"
|
|
576
|
+
<div class="dkoerper">
|
|
577
|
+
<div class="suche">
|
|
578
|
+
<svg viewBox="0 0 16 16" stroke-width="1.6" aria-hidden="true"><circle cx="7" cy="7" r="4.5"/><path d="M10.5 10.5 14.5 14.5"/></svg>
|
|
579
|
+
<input type="search" id="dm-suche" placeholder="Ort oder Pfad suchen" aria-label="Orte durchsuchen" spellcheck="false" autocomplete="off">
|
|
580
|
+
</div>
|
|
581
|
+
<div class="wahl" id="dm-orte"></div>
|
|
582
|
+
</div>
|
|
577
583
|
<div class="dfuss">
|
|
578
584
|
<button class="knopf leise" value="abbruch">Abbrechen</button>
|
|
579
585
|
<button class="knopf signal" value="los" id="dm-los">Einhängen</button>
|
|
@@ -339,6 +339,8 @@
|
|
|
339
339
|
// Kern (F42, E16): Grundlage für den MCP-Abschnitt und den „MCP hinzufügen …"-Knopf an den
|
|
340
340
|
// Ziel-Karten — nie am Harness-Namen entschieden, sondern an dieser Liste.
|
|
341
341
|
var MCP_PLAETZE = [];
|
|
342
|
+
// MCP-Ebenen je Harness (E120), aus der Fähigkeit am Adapter: Grundlage der Tooltip-Erklärung.
|
|
343
|
+
var MCP_EBENEN = [];
|
|
342
344
|
var quellenFilter = 'alle';
|
|
343
345
|
// Sortierung der Skills-Rubrik (E79, Richtung E81): hält für die Sitzung wie quellenFilter,
|
|
344
346
|
// übersteht also ladeAlles. SKILLS selbst bleibt unsortiert nach Datum, damit li.dataset.index
|
|
@@ -473,6 +475,7 @@
|
|
|
473
475
|
rufe(function () { return window.hmgr.mcpPlaetze(); }),
|
|
474
476
|
rufe(function () { return window.hmgr.bundles(); }),
|
|
475
477
|
rufe(function () { return window.hmgr.harnessHeime(); }),
|
|
478
|
+
rufe(function () { return window.hmgr.mcpEbenen(); }),
|
|
476
479
|
]);
|
|
477
480
|
// Alter Stand der Verzeichnis-Pfade, vor dem Überschreiben unten (E84 Teil 1): zielKarten()
|
|
478
481
|
// liest hier noch ZIELE/AKTIVE_HARNESSE von vor diesem Lauf. null heißt „kein Vergleich", der
|
|
@@ -495,6 +498,7 @@
|
|
|
495
498
|
BUNDLES.sort(function (a, b) { return a.name.localeCompare(b.name, 'de') || a.quelleText.localeCompare(b.quelleText, 'de'); });
|
|
496
499
|
BUNDLES_KAPUTT = ergebnisse[9].kaputte;
|
|
497
500
|
HARNESS_HEIME = ergebnisse[10] || [];
|
|
501
|
+
MCP_EBENEN = ergebnisse[11] || [];
|
|
498
502
|
STANDARD_REF = {};
|
|
499
503
|
SKILLS.forEach(function (s) { if (STANDARD_REF[s.quelleText] === undefined) STANDARD_REF[s.quelleText] = s.ref; });
|
|
500
504
|
|
|
@@ -1112,54 +1116,115 @@
|
|
|
1112
1116
|
return zeilen;
|
|
1113
1117
|
}
|
|
1114
1118
|
|
|
1115
|
-
/**
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1119
|
+
/** Quelle-Spalte und Beschreibung einer MCP-Zeile (E120, F142). */
|
|
1120
|
+
function mcpQuelleText(row) {
|
|
1121
|
+
if (row.art === 'katalog') return 'Katalog';
|
|
1122
|
+
if (row.art === 'fremd') return 'nicht im Katalog';
|
|
1123
|
+
return '.mcp.json des Projekts';
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
/** Tooltip an den Harness-Zeichen einer MCP-Zeile unter „Alle" (E120): wo der Server hier hängt und,
|
|
1127
|
+
je weiterem aktivem Harness des Orts, warum nicht. Der Grund kommt aus den MCP-Ebenen der
|
|
1128
|
+
Fähigkeit (MCP_EBENEN, E16), nie aus dem Harness-Namen. Ein Harness, der den Server hier haben
|
|
1129
|
+
könnte (Ebene arbeitsverzeichnis), bekommt keinen Satz: ein Grund wäre geraten (etwa fehlende
|
|
1130
|
+
CLI, E103). */
|
|
1131
|
+
function mcpZeichenTitel(name, hatHarnesse, teile) {
|
|
1132
|
+
var saetze = ['Hier hängt ' + name + ' für ' + hatHarnesse.map(harnessName).join(', ') + '.'];
|
|
1133
|
+
var gesehen = {};
|
|
1134
|
+
teile.forEach(function (t) {
|
|
1135
|
+
var h = t.ziel.harness;
|
|
1136
|
+
if (gesehen[h] || hatHarnesse.indexOf(h) > -1 || !harnessAktiv(h)) return;
|
|
1137
|
+
gesehen[h] = true;
|
|
1138
|
+
var f = MCP_EBENEN.find(function (x) { return x.harness === h; });
|
|
1139
|
+
if (!f) return;
|
|
1140
|
+
if (f.ebenen.indexOf('arbeitsverzeichnis') > -1) return;
|
|
1141
|
+
if (f.ebenen.length === 0) {
|
|
1142
|
+
saetze.push(harnessName(h) + ' kennt keine MCP-Server.');
|
|
1143
|
+
} else {
|
|
1144
|
+
saetze.push(harnessName(h) + ' liest MCP-Server nicht pro Ordner, nur im Home'
|
|
1145
|
+
+ (f.ebenen.indexOf('profil') > -1 ? ' oder in einem Profil' : '') + '.');
|
|
1146
|
+
}
|
|
1147
|
+
});
|
|
1148
|
+
return saetze.join(' ');
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
/** Der MCP-Abschnitt einer Ziel-Karte (E61-GUI-Nachtrag, E120): eine Tabelle mit denselben Spalten
|
|
1152
|
+
wie die Skill-Tabelle darüber. `ziele` ist ein Ziel (Harness-Chip) oder mehrere (Chip „Alle",
|
|
1153
|
+
`teile` gesetzt: dann stehen die Harness-Zeichen vor dem Namen). Nur, wenn dort etwas
|
|
1154
|
+
eingehängt ist oder der „hinzufügen"-Knopf ohnehin sichtbar wäre (mcpKannAn). Sperrnotiz (E91)
|
|
1155
|
+
und „Noch nichts eingehängt." bleiben eine Zeile über die Breite. */
|
|
1156
|
+
function mcpAbschnitt(ziele, teile) {
|
|
1157
|
+
var alle = teile !== undefined;
|
|
1158
|
+
if (!Array.isArray(ziele)) ziele = [ziele];
|
|
1159
|
+
var notizen = [];
|
|
1160
|
+
var zeilen = [];
|
|
1161
|
+
var kannAn = false;
|
|
1162
|
+
ziele.forEach(function (ziel) {
|
|
1163
|
+
var wurzel = mcpGitWurzel(ziel);
|
|
1164
|
+
if (wurzel !== null) { notizen.push(mcpWurzelNotiz(wurzel)); return; }
|
|
1165
|
+
if (mcpKannAn(ziel)) kannAn = true;
|
|
1166
|
+
mcpZeilenFuerZiel(ziel).forEach(function (row) { row.ziel = ziel; zeilen.push(row); });
|
|
1167
|
+
});
|
|
1168
|
+
if (zeilen.length === 0 && notizen.length === 0 && !kannAn) return null;
|
|
1169
|
+
zeilen.sort(function (a, b) {
|
|
1170
|
+
return a.name.localeCompare(b.name, 'de') || harnessName(a.ziel.harness).localeCompare(harnessName(b.ziel.harness), 'de');
|
|
1171
|
+
});
|
|
1127
1172
|
var abschnitt = e('div', 'mcpkarteabschnitt');
|
|
1128
|
-
abschnitt.appendChild(e('span', 'etikett', 'MCP'));
|
|
1129
1173
|
if (zeilen.length === 0) {
|
|
1130
|
-
abschnitt.appendChild(e('
|
|
1174
|
+
abschnitt.appendChild(e('span', 'etikett', 'MCP'));
|
|
1175
|
+
if (notizen.length === 0) abschnitt.appendChild(e('p', 'ohne mcpkarteleer', 'Noch nichts eingehängt.'));
|
|
1176
|
+
notizen.forEach(function (n) { abschnitt.appendChild(e('p', 'ohne mcpkarteleer', n)); });
|
|
1131
1177
|
return abschnitt;
|
|
1132
1178
|
}
|
|
1133
|
-
var
|
|
1179
|
+
var kopf = e('div', 'linkkopf');
|
|
1180
|
+
kopf.appendChild(e('span'));
|
|
1181
|
+
kopf.appendChild(e('span', 'etikett', 'MCP'));
|
|
1182
|
+
kopf.appendChild(e('span', 'etikett', 'Beschreibung'));
|
|
1183
|
+
kopf.appendChild(e('span', 'etikett', 'Quelle'));
|
|
1184
|
+
kopf.appendChild(e('span'));
|
|
1185
|
+
abschnitt.appendChild(kopf);
|
|
1186
|
+
var ul = e('ul', 'linkliste mcpzeilen');
|
|
1134
1187
|
zeilen.forEach(function (row) {
|
|
1188
|
+
var ziel = row.ziel;
|
|
1135
1189
|
var li = e('li');
|
|
1136
|
-
li.appendChild(e('span', '
|
|
1190
|
+
li.appendChild(e('span', 'repo'));
|
|
1191
|
+
var nameSpan = e('span', 'name');
|
|
1192
|
+
if (alle) {
|
|
1193
|
+
var hat = [];
|
|
1194
|
+
zeilen.forEach(function (r) {
|
|
1195
|
+
if (r.name === row.name && hat.indexOf(r.ziel.harness) === -1) hat.push(r.ziel.harness);
|
|
1196
|
+
});
|
|
1197
|
+
hat.sort(function (a, b) { return harnessName(a).localeCompare(harnessName(b), 'de'); });
|
|
1198
|
+
var zeichen = harnesseZeichenSammel([ziel.harness]);
|
|
1199
|
+
zeichen.title = mcpZeichenTitel(row.name, hat, teile);
|
|
1200
|
+
nameSpan.appendChild(zeichen);
|
|
1201
|
+
}
|
|
1202
|
+
nameSpan.appendChild(document.createTextNode(row.name));
|
|
1203
|
+
li.appendChild(nameSpan);
|
|
1204
|
+
var wasFeld = e('span', 'wasfeld');
|
|
1205
|
+
if (row.art === 'katalog' || row.art === 'geteilt') wasFeld.appendChild(e('span', 'was', row.beschreibung || ''));
|
|
1206
|
+
else if (row.art === 'fremd-geteilt') wasFeld.appendChild(e('span', 'was fehlt', 'nicht im Katalog'));
|
|
1207
|
+
li.appendChild(wasFeld);
|
|
1208
|
+
li.appendChild(e('span', 'quelle', mcpQuelleText(row)));
|
|
1137
1209
|
if (row.art === 'katalog') {
|
|
1138
|
-
li.appendChild(e('span', 'was', row.beschreibung || ''));
|
|
1139
1210
|
var weg = e('button', 'knopf leise klein', 'Entfernen');
|
|
1140
1211
|
weg.type = 'button';
|
|
1141
1212
|
weg.setAttribute('aria-label', row.name + ' aus ' + zielTitel({ ziel: ziel }) + ' aushängen');
|
|
1142
1213
|
weg.addEventListener('click', function () { frageMcpAus(row.eintrag, ziel); });
|
|
1143
1214
|
li.appendChild(weg);
|
|
1144
1215
|
} else if (row.art === 'geteilt' || row.art === 'fremd-geteilt') {
|
|
1145
|
-
// E64: der Vermerk nennt die Bedeutung („steht im Projekt, nicht bei dir"), nicht mehr bloß
|
|
1146
|
-
// den Dateinamen — und daneben steht der Weg, das zu ändern.
|
|
1147
|
-
li.appendChild(row.art === 'geteilt'
|
|
1148
|
-
? e('span', 'was', row.beschreibung || '')
|
|
1149
|
-
: e('span', 'was fehlt', 'nicht im Katalog'));
|
|
1150
|
-
li.appendChild(e('span', 'geteiltvermerk', 'in der .mcp.json des Projekts'));
|
|
1151
1216
|
var her = e('button', 'knopf leise klein', 'Übernehmen …');
|
|
1152
1217
|
her.type = 'button';
|
|
1153
1218
|
her.setAttribute('aria-label', row.name + ' aus der .mcp.json des Projekts in deine private Konfiguration übernehmen');
|
|
1154
1219
|
her.addEventListener('click', function () { frageMcpUebernahme(row.name, ziel, row.datei); });
|
|
1155
1220
|
li.appendChild(her);
|
|
1156
1221
|
} else {
|
|
1157
|
-
li.appendChild(e('span', 'was fehlt', 'nicht im Katalog'));
|
|
1158
1222
|
li.appendChild(e('span'));
|
|
1159
1223
|
}
|
|
1160
1224
|
ul.appendChild(li);
|
|
1161
1225
|
});
|
|
1162
1226
|
abschnitt.appendChild(ul);
|
|
1227
|
+
notizen.forEach(function (n) { abschnitt.appendChild(e('p', 'ohne mcpkarteleer', n)); });
|
|
1163
1228
|
return abschnitt;
|
|
1164
1229
|
}
|
|
1165
1230
|
|
|
@@ -1357,10 +1422,8 @@
|
|
|
1357
1422
|
if (mcpKnopfLeer) leer.appendChild(mcpKnopfLeer);
|
|
1358
1423
|
});
|
|
1359
1424
|
teil.appendChild(leer);
|
|
1360
|
-
verzMcpZiele
|
|
1361
|
-
|
|
1362
|
-
if (mcpAbschnLeer) teil.appendChild(mcpAbschnLeer);
|
|
1363
|
-
});
|
|
1425
|
+
var mcpAbschnLeer = mcpAbschnitt(verzMcpZiele, teile);
|
|
1426
|
+
if (mcpAbschnLeer) teil.appendChild(mcpAbschnLeer);
|
|
1364
1427
|
return teil;
|
|
1365
1428
|
}
|
|
1366
1429
|
|
|
@@ -1494,10 +1557,8 @@
|
|
|
1494
1557
|
|
|
1495
1558
|
// MCP-Abschnitt (E61-GUI-Nachtrag): auf Kartenebene unter „Alle", wie unter dem Harness-Chip,
|
|
1496
1559
|
// der an diesem Pfad MCP kann.
|
|
1497
|
-
verzMcpZiele
|
|
1498
|
-
|
|
1499
|
-
if (mcpAbschnAlle) teil.appendChild(mcpAbschnAlle);
|
|
1500
|
-
});
|
|
1560
|
+
var mcpAbschnAlle = mcpAbschnitt(verzMcpZiele, teile);
|
|
1561
|
+
if (mcpAbschnAlle) teil.appendChild(mcpAbschnAlle);
|
|
1501
1562
|
|
|
1502
1563
|
var fuss = e('div', 'zielfuss');
|
|
1503
1564
|
fuss.appendChild(alleSkillsKnopf(pfad, teile));
|
|
@@ -3636,6 +3697,7 @@
|
|
|
3636
3697
|
$('dm-text').textContent = 'Ein Ort je Einhängen. agents kennt keine MCP-Server und steht deshalb nicht zur Wahl.';
|
|
3637
3698
|
var box = $('dm-orte');
|
|
3638
3699
|
box.textContent = '';
|
|
3700
|
+
$('dm-suche').value = '';
|
|
3639
3701
|
// Die Plätze kommen aus dem Kern (F42, E16): die Fähigkeit hängt am Adapter, nicht am
|
|
3640
3702
|
// Harness-Namen, hier wird nicht selbst entschieden, wer welche Ebene kennt.
|
|
3641
3703
|
var plaetze = await rufe(function () { return window.hmgr.mcpPlaetze(); });
|
|
@@ -3650,6 +3712,7 @@
|
|
|
3650
3712
|
var schon = k.eingehaengt.some(function (z) { return zielKey(z) === zielKey(ziel); });
|
|
3651
3713
|
var aktiv = harnessAktiv(ziel.harness);
|
|
3652
3714
|
var label = e('label', 'wahlzeile');
|
|
3715
|
+
label.dataset.index = i;
|
|
3653
3716
|
var input = document.createElement('input');
|
|
3654
3717
|
input.type = 'radio';
|
|
3655
3718
|
input.name = 'mcport';
|
|
@@ -3681,7 +3744,41 @@
|
|
|
3681
3744
|
box.appendChild(label);
|
|
3682
3745
|
});
|
|
3683
3746
|
zeige($('d-mcp'));
|
|
3747
|
+
$('dm-suche').focus();
|
|
3748
|
+
}
|
|
3749
|
+
|
|
3750
|
+
/** E122: filtert die Wahlzeilen des Einhängen-Dialogs live. Die Zeilen bleiben stehen (der
|
|
3751
|
+
Radio-Wert ist der Index in mcpPlaetzeAuswahl), nicht passende werden nur ausgeblendet. Eine
|
|
3752
|
+
angehakte Zeile, die verschwindet, wird abgehakt: sonst ginge „Einhängen" an einen Ort, den
|
|
3753
|
+
niemand mehr sieht. */
|
|
3754
|
+
function filtereMcpOrte() {
|
|
3755
|
+
var begriff = $('dm-suche').value.trim();
|
|
3756
|
+
var suche = suchform(begriff);
|
|
3757
|
+
var box = $('dm-orte');
|
|
3758
|
+
var gezeigt = 0;
|
|
3759
|
+
box.querySelectorAll('.wahlzeile').forEach(function (label) {
|
|
3760
|
+
var ziel = mcpPlaetzeAuswahl[+label.dataset.index];
|
|
3761
|
+
var passt = true;
|
|
3762
|
+
if (suche) {
|
|
3763
|
+
var pfad = ziel.ort.art === 'arbeitsverzeichnis' ? ziel.ort.pfad : '';
|
|
3764
|
+
var text = suchform(zielTitel({ ziel: ziel }) + ' ' + mcpOrtSpur(ziel) + ' ' + pfad + ' ' + pfadKurz(pfad));
|
|
3765
|
+
passt = text.indexOf(suche) > -1;
|
|
3766
|
+
}
|
|
3767
|
+
label.hidden = !passt;
|
|
3768
|
+
if (passt) gezeigt++;
|
|
3769
|
+
else {
|
|
3770
|
+
var radio = label.querySelector('input');
|
|
3771
|
+
if (radio) radio.checked = false;
|
|
3772
|
+
}
|
|
3773
|
+
});
|
|
3774
|
+
var alt = box.querySelector('.leerhinweis');
|
|
3775
|
+
if (alt) alt.remove();
|
|
3776
|
+
if (suche && gezeigt === 0) {
|
|
3777
|
+
box.appendChild(e('p', 'leerhinweis', 'Kein Ort passt zu „' + begriff + '".'));
|
|
3778
|
+
}
|
|
3684
3779
|
}
|
|
3780
|
+
$('dm-suche').addEventListener('input', filtereMcpOrte);
|
|
3781
|
+
enterBestaetigt($('dm-suche'), $('dm-los'));
|
|
3685
3782
|
|
|
3686
3783
|
$('d-mcp').addEventListener('submit', function (ev) {
|
|
3687
3784
|
if (ev.submitter && ev.submitter.value === 'los') {
|
|
@@ -771,21 +771,11 @@ dialog::backdrop{background:rgba(9,45,37,.62)}
|
|
|
771
771
|
}
|
|
772
772
|
|
|
773
773
|
/* MCP an der Ziel-Karte (E61-GUI-Nachtrag), Gegenrichtung zur MCP-Ansicht (F46: die einzige Stelle,
|
|
774
|
-
die noch zeigt, wo ein Server hängt): eigener Abschnitt unter der Skill-Link-Tabelle,
|
|
775
|
-
|
|
774
|
+
die noch zeigt, wo ein Server hängt): eigener Abschnitt unter der Skill-Link-Tabelle, seit E120 mit
|
|
775
|
+
derselben Tabelle (linkkopf/linkliste) wie die Skills; flach in der Karte statt in einem eigenen Kasten. */
|
|
776
776
|
.mcpkarteabschnitt{margin-top:16px;padding-top:14px;border-top:1px solid var(--strich)}
|
|
777
777
|
.mcpkarteabschnitt > .etikett{display:block;margin-bottom:10px}
|
|
778
778
|
.mcpkarteleer{margin:0;color:var(--tinte-leise);font-style:italic}
|
|
779
|
-
.mcpkartezeilen{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px}
|
|
780
|
-
.mcpkartezeilen li{display:flex;flex-wrap:wrap;align-items:center;gap:5px 14px}
|
|
781
|
-
.mcpkartezeilen .name{font-family:var(--mono);font-size:16px;letter-spacing:-.012em;color:var(--tinte)}
|
|
782
|
-
.mcpkartezeilen .was{font-size:16px;color:var(--tinte-weich)}
|
|
783
|
-
.mcpkartezeilen .was.fehlt{color:var(--tinte-leise);font-style:italic}
|
|
784
|
-
.mcpkartezeilen .knopf{margin-left:auto}
|
|
785
|
-
.mcpkartezeilen .kein-weg{margin-left:auto;font-size:16px;color:var(--tinte-leise);text-align:right}
|
|
786
|
-
/* Wo ein Eintrag steht (E64): kein margin-left:auto, sonst teilte er sich den freien Platz mit dem
|
|
787
|
-
Übernehmen-Knopf und stünde in der Mitte statt beim Text. */
|
|
788
|
-
.mcpkartezeilen .geteiltvermerk{font-size:16px;color:var(--tinte-leise)}
|
|
789
779
|
/* Bundle-Gruppe an der Ziel-Karte (E69, F68): eine Einheit über ihren Skill-Zeilen, sichtbar
|
|
790
780
|
zusammengefasst durch eine linke Kante statt durch einen eigenen Kasten — die Zeilen darin sind
|
|
791
781
|
dieselbe Tabelle wie darunter und sollen mit ihr fluchten. */
|
|
@@ -578,6 +578,15 @@ export class Anwendungsfaelle {
|
|
|
578
578
|
}
|
|
579
579
|
return ziele;
|
|
580
580
|
}
|
|
581
|
+
/**
|
|
582
|
+
* Die MCP-Ebenen je Harness-Typ (E120), aus der Fähigkeit am Adapter, nie am Namen (E16): eine
|
|
583
|
+
* leere Liste heißt, der Harness kennt MCP-Server gar nicht (agents). Grundlage für die Erklärung,
|
|
584
|
+
* warum ein Server an einem Ort für einen Harness fehlt (GUI-Tooltip, Hinweis von `mcp list`).
|
|
585
|
+
* Unabhängig von Installation und Aktivierung; das entscheidet der Aufrufer.
|
|
586
|
+
*/
|
|
587
|
+
mcpEbenen() {
|
|
588
|
+
return this.p.harnesses.map((h) => ({ harness: h.name, ebenen: kannMcp(h) ? h.mcp.ebenen() : [] }));
|
|
589
|
+
}
|
|
581
590
|
/**
|
|
582
591
|
* Die Plätze für den Einhängen-Dialog der GUI (E61-Folgerunde, F42): dieselbe Liste wie in
|
|
583
592
|
* `mcpUebersicht`, aber roh, ohne den Abgleich mit Katalog-Einträgen. Die Fähigkeit hängt am
|