hmgr 0.0.18 → 0.0.20
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/composer.js +4 -0
- package/dist/cli/hilfe.js +38 -4
- package/dist/cli/main.js +38 -3
- package/dist/gui/main.js +34 -0
- package/dist/gui/renderer/renderer.js +20 -2
- package/dist/kern/anwendungsfaelle.js +70 -7
- package/package.json +1 -1
package/dist/adapter/composer.js
CHANGED
|
@@ -92,4 +92,8 @@ export class ComposerZeiger {
|
|
|
92
92
|
daten.scripts = scripts;
|
|
93
93
|
await writeFile(pfad, `${JSON.stringify(daten, null, 4)}\n`);
|
|
94
94
|
}
|
|
95
|
+
async verzeichnisExistiert(pfad) {
|
|
96
|
+
const info = await stat(pfad).catch(() => undefined);
|
|
97
|
+
return info !== undefined && info.isDirectory();
|
|
98
|
+
}
|
|
95
99
|
}
|
package/dist/cli/hilfe.js
CHANGED
|
@@ -31,9 +31,10 @@ hmgr <kommando> [schalter]
|
|
|
31
31
|
mcp migrate <name> MCP-Server aus der geteilten .mcp.json in den privaten Scope übernehmen
|
|
32
32
|
mcp list Katalog-Einträge zeigen, mit wo sie eingehängt sind
|
|
33
33
|
sync [pfad] Ziel auf den Stand seines Zeigers bringen
|
|
34
|
-
update Alle Checkouts aktualisieren
|
|
34
|
+
update Alle Checkouts aktualisieren, mit <skill> oder --quelle nur eine Quelle
|
|
35
35
|
status Ist-Zustand der Ziele
|
|
36
36
|
log Verlauf der letzten Läufe (Changelog)
|
|
37
|
+
doctor Fehlende Arbeitsverzeichnisse finden und Vergessen anbieten
|
|
37
38
|
harness list Harness-Typen mit Stand aktiv/inaktiv und vorhanden
|
|
38
39
|
harness enable <name> Harness-Typ aktivieren, hmgr richtet ihn künftig ein
|
|
39
40
|
harness disable <name> Harness-Typ deaktivieren, mit Angebot zum Säubern
|
|
@@ -118,7 +119,7 @@ Häufige Fälle:
|
|
|
118
119
|
link --ort dir:<pfad> merkt das Verzeichnis von selbst. dir add braucht es vorher nur, wenn die
|
|
119
120
|
composer.json mehrdeutig ist.
|
|
120
121
|
|
|
121
|
-
Siehe auch: hmgr help link, hmgr help sync, hmgr help harness`;
|
|
122
|
+
Siehe auch: hmgr help link, hmgr help sync, hmgr help harness, hmgr help doctor`;
|
|
122
123
|
const LINK = `hmgr link <skill> [schalter]
|
|
123
124
|
|
|
124
125
|
Legt im Ziel einen Symlink auf den Skill an, der aus einer bekannten Quelle stammt, und trägt ihn
|
|
@@ -445,6 +446,8 @@ Häufige Fälle:
|
|
|
445
446
|
|
|
446
447
|
Siehe auch: hmgr help dir, hmgr help link, hmgr help update, hmgr help harness`;
|
|
447
448
|
const UPDATE = `hmgr update
|
|
449
|
+
hmgr update <skill>
|
|
450
|
+
hmgr update --quelle <teilstring>
|
|
448
451
|
|
|
449
452
|
Holt für jeden Checkout unter ~/.hmgr den neuesten Stand seines Refs und zieht bei Harnesses mit
|
|
450
453
|
Plugin-Fähigkeit deren Plugins nach (E14). Die Links zeigen weiter auf dieselben Pfade und müssen
|
|
@@ -483,10 +486,21 @@ aufgeräumter Checkout, ein Fehler), schreibt update denselben Eintrag auch in ~
|
|
|
483
486
|
nicht im Verlauf: „claude plugin marketplace update" liefert keine Auskunft, ob sich etwas geändert
|
|
484
487
|
hat, eine Zeile dazu wäre geschönt.
|
|
485
488
|
|
|
486
|
-
|
|
489
|
+
Eingeschränkter Lauf (E89): hmgr update <skill> zieht nur die Quelle nach, in der der Skill liegt
|
|
490
|
+
(liegt der Skill in mehreren Quellen, bricht update ab, dann --quelle nutzen). hmgr update --quelle <teilstring> nimmt ein Stück
|
|
491
|
+
von URL, Pfad oder Anzeigenamen der Quelle, Groß- und Kleinschreibung egal; passt keine oder
|
|
492
|
+
mehr als eine, bricht update mit der Liste ab. Beides zusammen geht nicht. Der Lauf umfasst die
|
|
493
|
+
Checkouts dieser Quelle und die Bundles, deren Definition in ihr liegt. Es entfallen: Plugins,
|
|
494
|
+
Aufräumen verwaister Checkouts, der Check auf fehlende Arbeitsverzeichnisse (doctor) sowie alle
|
|
495
|
+
übrigen Quellen und Bundles. Der Verlaufseintrag entsteht wie im vollen Lauf.
|
|
496
|
+
|
|
497
|
+
Schalter:
|
|
498
|
+
--quelle <teilstring> Nur diese Quelle nachziehen (statt <skill>)
|
|
487
499
|
|
|
488
500
|
Beispiel:
|
|
489
501
|
hmgr update
|
|
502
|
+
hmgr update mein-skill
|
|
503
|
+
hmgr update --quelle mein-repo
|
|
490
504
|
|
|
491
505
|
Häufige Fälle:
|
|
492
506
|
„übersprungen … lokale Änderung (E15)": im Checkout liegt eine Änderung, die durch einen Link
|
|
@@ -495,7 +509,7 @@ Häufige Fälle:
|
|
|
495
509
|
„liegen lassen … ohne Bestätigung nicht gelöscht": die Frage kam ohne Ja zurück, etwa in einer
|
|
496
510
|
Pipe oder einem Composer-Script. In einem Terminal erneut hmgr update aufrufen.
|
|
497
511
|
|
|
498
|
-
Siehe auch: hmgr help sync, hmgr help status, hmgr help log`;
|
|
512
|
+
Siehe auch: hmgr help sync, hmgr help status, hmgr help log, hmgr help doctor`;
|
|
499
513
|
const LOG = `hmgr log
|
|
500
514
|
|
|
501
515
|
Zeigt den Verlauf der letzten Läufe aus ~/.hmgr/verlauf.json (E80), neueste zuerst: dieselbe Datei,
|
|
@@ -521,6 +535,25 @@ Häufige Fälle:
|
|
|
521
535
|
„Noch keine Ereignisse": entweder frisch installiert, oder jeder bisherige Lauf war ohne Fund.
|
|
522
536
|
|
|
523
537
|
Siehe auch: hmgr help update, hmgr help status`;
|
|
538
|
+
const DOCTOR = `hmgr doctor
|
|
539
|
+
|
|
540
|
+
Prüft, ob jedes gemerkte Arbeitsverzeichnis (hmgr dir add) noch auf der Platte existiert (E88): ein
|
|
541
|
+
umbenanntes oder woanders neu geklontes Projekt hinterlässt sonst für immer einen toten Pfad im
|
|
542
|
+
Zustand, den nur hmgr dir forget von Hand entfernt. Bei einem Fund fragt doctor wie hmgr update
|
|
543
|
+
einmal für alle Funde, ob sie vergessen werden sollen; ohne Bestätigung bleiben sie gemeldet, aber
|
|
544
|
+
gemerkt. Anders als update holt doctor nichts aus dem Netz und schreibt keinen Eintrag in den
|
|
545
|
+
Verlauf — ein reiner Konsolen-Check, kein Lauf im E80-Sinn.
|
|
546
|
+
|
|
547
|
+
Schalter: keine.
|
|
548
|
+
|
|
549
|
+
Beispiel:
|
|
550
|
+
hmgr doctor
|
|
551
|
+
|
|
552
|
+
Häufige Fälle:
|
|
553
|
+
„liegen lassen … ohne Bestätigung nicht vergessen": die Frage kam ohne Ja zurück. In einem
|
|
554
|
+
Terminal erneut hmgr doctor aufrufen, oder hmgr dir forget <pfad> gezielt.
|
|
555
|
+
|
|
556
|
+
Siehe auch: hmgr help update, hmgr help dir`;
|
|
524
557
|
const STATUS = `hmgr status
|
|
525
558
|
|
|
526
559
|
Liest den Ist-Zustand vom Dateisystem: je Ziel eines vorhandenen, aktiven Harness die Einträge mit Quelle
|
|
@@ -648,6 +681,7 @@ const THEMEN = new Map([
|
|
|
648
681
|
['update', UPDATE],
|
|
649
682
|
['status', STATUS],
|
|
650
683
|
['log', LOG],
|
|
684
|
+
['doctor', DOCTOR],
|
|
651
685
|
['harness', HARNESS],
|
|
652
686
|
['help', HILFE],
|
|
653
687
|
]);
|
package/dist/cli/main.js
CHANGED
|
@@ -93,9 +93,10 @@ const SCHALTER = {
|
|
|
93
93
|
bundle: { werte: ['harness', 'ort', 'composer', 'quelle'], flaggen: [] },
|
|
94
94
|
mcp: { werte: ['harness', 'ort'], flaggen: [] },
|
|
95
95
|
sync: { werte: [], flaggen: [] },
|
|
96
|
-
update: { werte: [], flaggen: [] },
|
|
96
|
+
update: { werte: ['quelle'], flaggen: [] },
|
|
97
97
|
status: { werte: [], flaggen: [] },
|
|
98
98
|
log: { werte: [], flaggen: [] },
|
|
99
|
+
doctor: { werte: [], flaggen: [] },
|
|
99
100
|
harness: { werte: ['profil'], flaggen: [] },
|
|
100
101
|
};
|
|
101
102
|
/**
|
|
@@ -714,8 +715,20 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
|
|
|
714
715
|
return 0;
|
|
715
716
|
}
|
|
716
717
|
if (kommando === 'update') {
|
|
717
|
-
|
|
718
|
-
|
|
718
|
+
const { rest: updateRest, werte: updateWerte } = schalterLesen(argv.slice(1), 'update');
|
|
719
|
+
restPruefen(updateRest, 1, 'update');
|
|
720
|
+
const updateSkill = updateRest[0];
|
|
721
|
+
const updateHinweis = updateWerte.get('quelle');
|
|
722
|
+
if (updateSkill !== undefined && updateHinweis !== undefined)
|
|
723
|
+
throw new Error('update nimmt entweder einen Skill oder --quelle, nicht beides. hmgr help update zeigt die Verwendung.');
|
|
724
|
+
// Eingeschränkter Lauf (E89): nur die Quelle des Skills bzw. die genannte, ohne Plugins,
|
|
725
|
+
// Aufräumen und doctor.
|
|
726
|
+
const nurQuelle = updateSkill !== undefined
|
|
727
|
+
? (await anwendungsfaelle.skillFinden(updateSkill)).quelle
|
|
728
|
+
: updateHinweis !== undefined
|
|
729
|
+
? await anwendungsfaelle.quelleZuHinweis(updateHinweis)
|
|
730
|
+
: undefined;
|
|
731
|
+
const { checkouts: liste, bundles, aufraeumen, doctor, } = await anwendungsfaelle.aktualisieren({ ausloeser: 'cli', ...(nurQuelle === undefined ? {} : { quelle: nurQuelle }) });
|
|
719
732
|
if (liste.length === 0)
|
|
720
733
|
console.log('Keine Checkouts.');
|
|
721
734
|
for (const { checkout, aktualisierung, geaenderteSkills } of liste) {
|
|
@@ -751,6 +764,13 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
|
|
|
751
764
|
const geloescht = aufraeumen.verwaiste.filter((v) => v.geloescht).length;
|
|
752
765
|
console.log(`${aufraeumen.verwaiste.length} verwaist, ${geloescht} gelöscht, ${aufraeumen.verwaiste.length - geloescht} liegen geblieben.`);
|
|
753
766
|
}
|
|
767
|
+
// Fehlende Arbeitsverzeichnisse (E88): was es auf der Platte nicht mehr gibt.
|
|
768
|
+
for (const pfad of doctor.fehlendeArbeitsverzeichnisse) {
|
|
769
|
+
if (doctor.vergessen.includes(pfad))
|
|
770
|
+
console.log(` vergessen Arbeitsverzeichnis ${pfad} (nicht mehr auf der Platte)`);
|
|
771
|
+
else
|
|
772
|
+
console.log(` liegen lassen Arbeitsverzeichnis ${pfad} (nicht mehr auf der Platte, ohne Bestätigung nicht vergessen)`);
|
|
773
|
+
}
|
|
754
774
|
// Zuletzt hmgr selbst (E77): wer schon aktualisiert, will auch wissen, dass sein hmgr alt ist.
|
|
755
775
|
// Verglichen wird die eigene Version (E72) gegen npm, gemeldet wird nur — installiert wird
|
|
756
776
|
// nichts. Offline oder Registry unerreichbar heißt keine Zeile, still: der Lauf selbst ist
|
|
@@ -809,6 +829,19 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
|
|
|
809
829
|
}
|
|
810
830
|
return 0;
|
|
811
831
|
}
|
|
832
|
+
if (kommando === 'doctor') {
|
|
833
|
+
restPruefen(schalterLesen(argv.slice(1), 'doctor').rest, 0, 'doctor');
|
|
834
|
+
const { fehlendeArbeitsverzeichnisse, vergessen } = await anwendungsfaelle.doctor();
|
|
835
|
+
if (fehlendeArbeitsverzeichnisse.length === 0)
|
|
836
|
+
console.log('Keine fehlenden Arbeitsverzeichnisse.');
|
|
837
|
+
for (const pfad of fehlendeArbeitsverzeichnisse) {
|
|
838
|
+
if (vergessen.includes(pfad))
|
|
839
|
+
console.log(` vergessen ${pfad}`);
|
|
840
|
+
else
|
|
841
|
+
console.log(` liegen lassen ${pfad} (ohne Bestätigung nicht vergessen)`);
|
|
842
|
+
}
|
|
843
|
+
return 0;
|
|
844
|
+
}
|
|
812
845
|
if (kommando === 'harness') {
|
|
813
846
|
const schalter = schalterLesen(argv.slice(1), 'harness');
|
|
814
847
|
unterkommandoPruefen('harness', schalter);
|
|
@@ -1042,6 +1075,8 @@ function verlaufEreignisZeile(ereignis) {
|
|
|
1042
1075
|
}
|
|
1043
1076
|
if (ereignis.art === 'aufgeraeumt')
|
|
1044
1077
|
return `Checkout ${ereignis.checkout} aufgeräumt`;
|
|
1078
|
+
if (ereignis.art === 'arbeitsverzeichnis-vergessen')
|
|
1079
|
+
return `Arbeitsverzeichnis ${ereignis.pfad} vergessen (nicht mehr auf der Platte)`;
|
|
1045
1080
|
if (ereignis.art === 'fehler')
|
|
1046
1081
|
return `Fehler ${ereignis.betrifft}: ${ereignis.fehler}`;
|
|
1047
1082
|
if (ereignis.art === 'hmgr-installiert')
|
package/dist/gui/main.js
CHANGED
|
@@ -676,6 +676,34 @@ function fensterOeffnen() {
|
|
|
676
676
|
if (verlaufBloecke > 0) break;
|
|
677
677
|
}
|
|
678
678
|
var verlaufText = document.getElementById('verlauf')?.textContent?.replace(/\\s+/g, ' ').trim() ?? null;
|
|
679
|
+
// Nachziehen je Quelle (E89): das Fixture hat im skills-repo einen neuen Upstream-Commit
|
|
680
|
+
// (fixtureAufbauen), den erst ein Lauf für diese Quelle holt. Erst der Knopf der
|
|
681
|
+
// anderen Quelle (kaputt-repo, ohne Checkout): der Verlauf bleibt, wie er ist, obwohl
|
|
682
|
+
// das skills-repo hinterherhinkt. Dann der Knopf des skills-repo: ein neuer Block, der
|
|
683
|
+
// nur diese Quelle nennt.
|
|
684
|
+
var nachziehenFehler = null;
|
|
685
|
+
var nachziehenKnopfZahl = document.querySelectorAll('#quellenliste .nachziehen').length;
|
|
686
|
+
var nachziehenBloeckeStart = document.querySelectorAll('#verlauf .block').length;
|
|
687
|
+
var nachziehenBloeckeNachAnderer = -1;
|
|
688
|
+
var nachziehenBloeckeNachEigener = -1;
|
|
689
|
+
var nachziehenErsterBlock = null;
|
|
690
|
+
try {
|
|
691
|
+
var nachziehenLauf = async (label) => {
|
|
692
|
+
var knopf = document.querySelector('#quellenliste button[aria-label="' + label + '"]');
|
|
693
|
+
if (!knopf) throw new Error('Knopf fehlt: ' + label);
|
|
694
|
+
knopf.click();
|
|
695
|
+
for (var w = 0; w < 100; w++) {
|
|
696
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
697
|
+
if (!document.getElementById('updatestart').disabled) break;
|
|
698
|
+
}
|
|
699
|
+
return document.querySelectorAll('#verlauf .block').length;
|
|
700
|
+
};
|
|
701
|
+
nachziehenBloeckeNachAnderer = await nachziehenLauf('kaputt-repo nachziehen');
|
|
702
|
+
nachziehenBloeckeNachEigener = await nachziehenLauf('skills-repo nachziehen');
|
|
703
|
+
nachziehenErsterBlock = document.querySelector('#verlauf .block')?.textContent?.replace(/\\s+/g, ' ').trim() ?? null;
|
|
704
|
+
} catch (fehler) {
|
|
705
|
+
nachziehenFehler = String(fehler);
|
|
706
|
+
}
|
|
679
707
|
// E60: Beschreibung in der Ziel-Tabelle (nicht nur im Katalog), „manuell" entfällt,
|
|
680
708
|
// Zahnrad statt Sonne am Einstellungen-Knopf.
|
|
681
709
|
var zielBeschreibung = document.querySelector('#zielliste .linkliste .was')?.textContent ?? null;
|
|
@@ -1149,6 +1177,12 @@ function fensterOeffnen() {
|
|
|
1149
1177
|
verlaufVorhanden,
|
|
1150
1178
|
verlaufText,
|
|
1151
1179
|
verlaufBloecke,
|
|
1180
|
+
nachziehenFehler,
|
|
1181
|
+
nachziehenKnopfZahl,
|
|
1182
|
+
nachziehenBloeckeStart,
|
|
1183
|
+
nachziehenBloeckeNachAnderer,
|
|
1184
|
+
nachziehenBloeckeNachEigener,
|
|
1185
|
+
nachziehenErsterBlock,
|
|
1152
1186
|
zielsucheVorhanden,
|
|
1153
1187
|
zielzahlNachSuche,
|
|
1154
1188
|
zielKartenNachSucheZahl,
|
|
@@ -2629,7 +2629,9 @@
|
|
|
2629
2629
|
standText();
|
|
2630
2630
|
}
|
|
2631
2631
|
|
|
2632
|
-
|
|
2632
|
+
// Mit `quelle` (E89, Knopf „Nachziehen" der Quellenliste) läuft nur diese Quelle, sonst alles.
|
|
2633
|
+
// Bericht, Stand-Zeile und Verlauf sind dieselben wie beim Kringel.
|
|
2634
|
+
async function aktualisierenLauf(ausloeser, quelle) {
|
|
2633
2635
|
var knopf = $('updatestart');
|
|
2634
2636
|
if (knopf.disabled) return;
|
|
2635
2637
|
knopf.disabled = true;
|
|
@@ -2637,7 +2639,9 @@
|
|
|
2637
2639
|
standLaeuft = true;
|
|
2638
2640
|
standText();
|
|
2639
2641
|
var lauf = rufe(function () {
|
|
2640
|
-
|
|
2642
|
+
var args = { rueckfragen: ausloeser !== 'klick', ausloeser: ausloeser };
|
|
2643
|
+
if (quelle) args.quelle = quelle;
|
|
2644
|
+
return window.hmgr.aktualisieren(args);
|
|
2641
2645
|
});
|
|
2642
2646
|
// Jeder Lauf prüft auch hmgr selbst (E80): angestoßen, nicht abgewartet — ein Fund meldet sich
|
|
2643
2647
|
// später von sich aus in der Seitenleiste (onSelbstUpdate).
|
|
@@ -2754,6 +2758,9 @@
|
|
|
2754
2758
|
} else if (ereignis.art === 'aufgeraeumt') {
|
|
2755
2759
|
li.appendChild(e('span', 'marke-ok', 'aufgeräumt'));
|
|
2756
2760
|
li.appendChild(e('span', 'pfad', ereignis.checkout));
|
|
2761
|
+
} else if (ereignis.art === 'arbeitsverzeichnis-vergessen') {
|
|
2762
|
+
li.appendChild(e('span', 'marke-ok', 'vergessen'));
|
|
2763
|
+
li.appendChild(e('span', 'pfad', ereignis.pfad));
|
|
2757
2764
|
} else if (ereignis.art === 'fehler') {
|
|
2758
2765
|
li.appendChild(e('span', 'marke-aus', 'fehlgeschlagen'));
|
|
2759
2766
|
li.appendChild(e('span', 'pfad', ereignis.betrifft + ': ' + ereignis.fehler));
|
|
@@ -3536,6 +3543,17 @@
|
|
|
3536
3543
|
stift.appendChild(stiftSvg);
|
|
3537
3544
|
stift.addEventListener('click', function () { oeffneQuelleUmbenennen(q); });
|
|
3538
3545
|
knoepfe.appendChild(stift);
|
|
3546
|
+
// Nur diese Quelle nachziehen (E89): wie der Kringel in der Update-Ansicht, aber ohne
|
|
3547
|
+
// Plugins, Aufräumen und übrige Quellen. Der Renderer kennt nur Text und Art (E54), die
|
|
3548
|
+
// Quelle für den Kern baut er daraus.
|
|
3549
|
+
var nachziehen = e('button', 'knopf leise klein nachziehen', 'Nachziehen');
|
|
3550
|
+
nachziehen.type = 'button';
|
|
3551
|
+
nachziehen.setAttribute('aria-label', q.name + ' nachziehen');
|
|
3552
|
+
nachziehen.addEventListener('click', function () {
|
|
3553
|
+
var quelle = q.art === 'lokal' ? { art: 'lokal', pfad: q.text } : { art: 'git', url: q.text };
|
|
3554
|
+
aktualisierenLauf('klick', quelle);
|
|
3555
|
+
});
|
|
3556
|
+
knoepfe.appendChild(nachziehen);
|
|
3539
3557
|
var weg = e('button', 'knopf leise klein', 'Entfernen …');
|
|
3540
3558
|
weg.type = 'button';
|
|
3541
3559
|
weg.setAttribute('aria-label', q.name + ' entfernen');
|
|
@@ -14,6 +14,17 @@ export function aufraeumFrage(checkouts) {
|
|
|
14
14
|
const pfade = checkouts.map((c) => ` ${c.pfad}`).join('\n');
|
|
15
15
|
return `${kopf}\n${pfade}\nLöschen?`;
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Frage vor dem Vergessen fehlender Arbeitsverzeichnisse (E88), eine für alle Funde — Analogie zu
|
|
19
|
+
* `aufraeumFrage`.
|
|
20
|
+
*/
|
|
21
|
+
export function doctorFrage(pfade) {
|
|
22
|
+
const kopf = pfade.length === 1
|
|
23
|
+
? 'Ein Arbeitsverzeichnis gibt es auf der Platte nicht mehr:'
|
|
24
|
+
: `${pfade.length} Arbeitsverzeichnisse gibt es auf der Platte nicht mehr:`;
|
|
25
|
+
const zeilen = pfade.map((p) => ` ${p}`).join('\n');
|
|
26
|
+
return `${kopf}\n${zeilen}\nVergessen?`;
|
|
27
|
+
}
|
|
17
28
|
function arbeitsverzeichnisZiel(harness, pfad) {
|
|
18
29
|
return { harness, ort: { art: 'arbeitsverzeichnis', pfad } };
|
|
19
30
|
}
|
|
@@ -1098,7 +1109,9 @@ export class Anwendungsfaelle {
|
|
|
1098
1109
|
async bundleAbgleich(args) {
|
|
1099
1110
|
const zustand = await this.p.zustand.lesen();
|
|
1100
1111
|
const zielSchl = args?.ziel === undefined ? undefined : zielSchluessel(args.ziel);
|
|
1112
|
+
const quelleSchl = args?.quelle === undefined ? undefined : quelleSchluessel(args.quelle);
|
|
1101
1113
|
const installationen = zustand.bundleInstallationen.filter((i) => (args?.bundle === undefined || i.bundle === args.bundle) &&
|
|
1114
|
+
(quelleSchl === undefined || quelleSchluessel(i.quelle) === quelleSchl) &&
|
|
1102
1115
|
(zielSchl === undefined || zielSchluessel(Anwendungsfaelle.installationZiel(i)) === zielSchl));
|
|
1103
1116
|
const ergebnis = [];
|
|
1104
1117
|
for (const installation of installationen) {
|
|
@@ -1205,6 +1218,26 @@ export class Anwendungsfaelle {
|
|
|
1205
1218
|
zustand.bindungen = zustand.bindungen.filter((b) => !(b.ziel.ort.art === 'arbeitsverzeichnis' && b.ziel.ort.pfad === verzeichnis));
|
|
1206
1219
|
await this.p.zustand.schreiben(zustand);
|
|
1207
1220
|
}
|
|
1221
|
+
/**
|
|
1222
|
+
* Arbeitsverzeichnisse erkennen, die es auf der Platte nicht mehr gibt, und ihr Vergessen anbieten
|
|
1223
|
+
* (E88). `rueckfragen: false` (GUI-Automatik, Smoke) meldet nur, fragt nicht und vergisst nichts —
|
|
1224
|
+
* dieselbe Weiche wie bei `verwaisteAufraeumen`.
|
|
1225
|
+
*/
|
|
1226
|
+
async doctor(args) {
|
|
1227
|
+
const rueckfragen = args?.rueckfragen ?? true;
|
|
1228
|
+
const zustand = await this.p.zustand.lesen();
|
|
1229
|
+
const fehlend = [];
|
|
1230
|
+
for (const pfad of zustand.arbeitsverzeichnisse)
|
|
1231
|
+
if (!(await this.p.zeiger.verzeichnisExistiert(pfad)))
|
|
1232
|
+
fehlend.push(pfad);
|
|
1233
|
+
if (fehlend.length === 0 || !rueckfragen)
|
|
1234
|
+
return { fehlendeArbeitsverzeichnisse: fehlend, vergessen: [] };
|
|
1235
|
+
if (!(await this.p.rueckfrage.bestaetigen(doctorFrage(fehlend))))
|
|
1236
|
+
return { fehlendeArbeitsverzeichnisse: fehlend, vergessen: [] };
|
|
1237
|
+
for (const pfad of fehlend)
|
|
1238
|
+
await this.arbeitsverzeichnisVergessen(pfad);
|
|
1239
|
+
return { fehlendeArbeitsverzeichnisse: fehlend, vergessen: [...fehlend] };
|
|
1240
|
+
}
|
|
1208
1241
|
/**
|
|
1209
1242
|
* Mehrere composer.json unter einem Verzeichnis (E26): hmgr rät nicht, es fragt. Bleibt die Frage
|
|
1210
1243
|
* ohne Antwort, weil niemand antworten kann oder die Eingabe keine der Kandidaten trifft, gilt
|
|
@@ -1243,6 +1276,22 @@ export class Anwendungsfaelle {
|
|
|
1243
1276
|
if ((await this.bindungFinden(ziel)) !== undefined)
|
|
1244
1277
|
throw new ZeigerSchreibenGesperrt(ziel);
|
|
1245
1278
|
}
|
|
1279
|
+
/**
|
|
1280
|
+
* Die eine geführte Quelle zu einem Teilstring (E89, `hmgr update --quelle`): verglichen wird mit
|
|
1281
|
+
* Schreibweise (URL/Pfad), Schlüssel und Anzeigenamen, Groß- und Kleinschreibung egal. Kein Treffer
|
|
1282
|
+
* und mehrere Treffer sind Fehler, mit der Liste, aus der sich der Nutzer eingrenzen kann.
|
|
1283
|
+
*/
|
|
1284
|
+
async quelleZuHinweis(hinweis) {
|
|
1285
|
+
const quellen = (await this.p.zustand.lesen()).quellen;
|
|
1286
|
+
const klein = hinweis.toLowerCase();
|
|
1287
|
+
const treffer = quellen.filter((q) => [quelleAlsText(q), quelleSchluessel(q), q.name ?? ''].some((t) => t.toLowerCase().includes(klein)));
|
|
1288
|
+
const zeilen = (liste) => liste.map((q) => ` ${quelleAlsText(q)}${q.name === undefined ? '' : ` (${q.name})`}`).join('\n');
|
|
1289
|
+
if (treffer.length === 1)
|
|
1290
|
+
return treffer[0];
|
|
1291
|
+
if (treffer.length === 0)
|
|
1292
|
+
throw new Error(`Keine Quelle passt auf „${hinweis}".${quellen.length === 0 ? '' : `\nBekannte Quellen:\n${zeilen(quellen)}`}`);
|
|
1293
|
+
throw new Error(`Mehrere Quellen passen auf „${hinweis}", bitte eingrenzen:\n${zeilen(treffer)}`);
|
|
1294
|
+
}
|
|
1246
1295
|
/** Skill über alle Quellen suchen. Mehrere Treffer sind nur mit Quellenhinweis erlaubt. */
|
|
1247
1296
|
async skillFinden(name, quelleHinweis) {
|
|
1248
1297
|
const zustand = await this.p.zustand.lesen();
|
|
@@ -1728,11 +1777,18 @@ export class Anwendungsfaelle {
|
|
|
1728
1777
|
* ergeben hat: unveränderte oder übersprungene Checkouts und Bundles ohne Änderung erzeugen
|
|
1729
1778
|
* nichts, ein leerer Lauf bleibt ganz aus dem Changelog. `ausloeser` steht mit im Eintrag, damit
|
|
1730
1779
|
* der Verlauf zeigt, ob ein Fund vom automatischen Lauf, einem Klick oder der CLI kam.
|
|
1780
|
+
*
|
|
1781
|
+
* Mit `quelle` (E89) läuft nur diese geführte Quelle: ihre Checkouts, ihr Katalog-Fetch und die
|
|
1782
|
+
* Bundle-Installationen, deren Definition in ihr liegt. Plugins, Aufräumen verwaister Checkouts
|
|
1783
|
+
* und doctor entfallen (leere Ergebnisse), weil sie den Gesamtbestand betreffen.
|
|
1731
1784
|
*/
|
|
1732
1785
|
async aktualisieren(args) {
|
|
1733
1786
|
const rueckfragen = args?.rueckfragen ?? true;
|
|
1734
1787
|
const ausloeser = args?.ausloeser ?? 'cli';
|
|
1735
|
-
const
|
|
1788
|
+
const nurSchluessel = args?.quelle === undefined ? undefined : quelleSchluessel(args.quelle);
|
|
1789
|
+
const bekannt = new Map((await this.p.zustand.lesen()).quellen
|
|
1790
|
+
.filter((q) => nurSchluessel === undefined || quelleSchluessel(q) === nurSchluessel)
|
|
1791
|
+
.map((q) => [quelleSchluessel(q), q]));
|
|
1736
1792
|
const checkouts = [];
|
|
1737
1793
|
for (const checkout of await this.p.quellen.checkouts()) {
|
|
1738
1794
|
const gefuehrt = bekannt.get(quelleSchluessel(checkout.quelle));
|
|
@@ -1774,7 +1830,7 @@ export class Anwendungsfaelle {
|
|
|
1774
1830
|
}
|
|
1775
1831
|
// Nach den Checkouts die Plugins nachziehen (E14).
|
|
1776
1832
|
const pluginHarnesses = [];
|
|
1777
|
-
for (const harness of await this.vorhandeneHarnesses()) {
|
|
1833
|
+
for (const harness of nurSchluessel !== undefined ? [] : await this.vorhandeneHarnesses()) {
|
|
1778
1834
|
if (!kannPlugins(harness))
|
|
1779
1835
|
continue;
|
|
1780
1836
|
await harness.plugins.aktualisieren();
|
|
@@ -1783,17 +1839,22 @@ export class Anwendungsfaelle {
|
|
|
1783
1839
|
// Bundles vor dem Aufräumen (E69, F64=O1): der Abgleich legt und entfernt Links, und erst
|
|
1784
1840
|
// danach steht fest, in welchen Checkout noch ein Link zeigt. Ein Fehlschlag je Bundle steckt
|
|
1785
1841
|
// in seinem Eintrag, er bricht den Lauf nicht ab — wie eine unerreichbare Quelle (E51).
|
|
1786
|
-
const bundles = await this.bundleAbgleich();
|
|
1787
|
-
const aufraeumen =
|
|
1788
|
-
|
|
1789
|
-
|
|
1842
|
+
const bundles = await this.bundleAbgleich(args?.quelle === undefined ? undefined : { quelle: args.quelle });
|
|
1843
|
+
const aufraeumen = nurSchluessel !== undefined
|
|
1844
|
+
? { verwaiste: [], gefragt: false }
|
|
1845
|
+
: await this.verwaisteAufraeumen(checkouts, rueckfragen);
|
|
1846
|
+
const doctorErgebnis = nurSchluessel !== undefined
|
|
1847
|
+
? { fehlendeArbeitsverzeichnisse: [], vergessen: [] }
|
|
1848
|
+
: await this.doctor({ rueckfragen });
|
|
1849
|
+
await this.verlaufVermerken(ausloeser, this.aktualisierungsEreignisse(checkouts, bundles, aufraeumen, doctorErgebnis));
|
|
1850
|
+
return { checkouts, pluginHarnesses, bundles, aufraeumen, doctor: doctorErgebnis };
|
|
1790
1851
|
}
|
|
1791
1852
|
/**
|
|
1792
1853
|
* Ereignisse eines Aktualisieren-Laufs für den Verlauf (E80): Plugins bleiben draußen, weil sich
|
|
1793
1854
|
* eine Änderung dort nicht messen lässt (`claude plugin marketplace update` liefert keine
|
|
1794
1855
|
* Auskunft) — die bisherige Zeile „Plugins aktualisiert" war deshalb geschönt.
|
|
1795
1856
|
*/
|
|
1796
|
-
aktualisierungsEreignisse(checkouts, bundles, aufraeumen) {
|
|
1857
|
+
aktualisierungsEreignisse(checkouts, bundles, aufraeumen, doctorErgebnis) {
|
|
1797
1858
|
const ereignisse = [];
|
|
1798
1859
|
for (const { checkout, aktualisierung, geaenderteSkills } of checkouts) {
|
|
1799
1860
|
if (aktualisierung.ergebnis === 'aktualisiert')
|
|
@@ -1827,6 +1888,8 @@ export class Anwendungsfaelle {
|
|
|
1827
1888
|
for (const verwaist of aufraeumen.verwaiste)
|
|
1828
1889
|
if (verwaist.geloescht)
|
|
1829
1890
|
ereignisse.push({ art: 'aufgeraeumt', checkout: `${quelleAlsText(verwaist.checkout.quelle)} @ ${verwaist.checkout.ref}` });
|
|
1891
|
+
for (const pfad of doctorErgebnis.vergessen)
|
|
1892
|
+
ereignisse.push({ art: 'arbeitsverzeichnis-vergessen', pfad });
|
|
1830
1893
|
return ereignisse;
|
|
1831
1894
|
}
|
|
1832
1895
|
/** Neuen Eintrag vorn anfügen, nur wenn Ereignisse da sind (E80). Kappen übernimmt der Adapter. */
|