hmgr 0.0.19 → 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/cli/hilfe.js CHANGED
@@ -31,7 +31,7 @@ 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
37
  doctor Fehlende Arbeitsverzeichnisse finden und Vergessen anbieten
@@ -446,6 +446,8 @@ Häufige Fälle:
446
446
 
447
447
  Siehe auch: hmgr help dir, hmgr help link, hmgr help update, hmgr help harness`;
448
448
  const UPDATE = `hmgr update
449
+ hmgr update <skill>
450
+ hmgr update --quelle <teilstring>
449
451
 
450
452
  Holt für jeden Checkout unter ~/.hmgr den neuesten Stand seines Refs und zieht bei Harnesses mit
451
453
  Plugin-Fähigkeit deren Plugins nach (E14). Die Links zeigen weiter auf dieselben Pfade und müssen
@@ -484,10 +486,21 @@ aufgeräumter Checkout, ein Fehler), schreibt update denselben Eintrag auch in ~
484
486
  nicht im Verlauf: „claude plugin marketplace update" liefert keine Auskunft, ob sich etwas geändert
485
487
  hat, eine Zeile dazu wäre geschönt.
486
488
 
487
- Schalter: keine.
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>)
488
499
 
489
500
  Beispiel:
490
501
  hmgr update
502
+ hmgr update mein-skill
503
+ hmgr update --quelle mein-repo
491
504
 
492
505
  Häufige Fälle:
493
506
  „übersprungen … lokale Änderung (E15)": im Checkout liegt eine Änderung, die durch einen Link
package/dist/cli/main.js CHANGED
@@ -93,7 +93,7 @@ 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
99
  doctor: { werte: [], flaggen: [] },
@@ -715,8 +715,20 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
715
715
  return 0;
716
716
  }
717
717
  if (kommando === 'update') {
718
- restPruefen(schalterLesen(argv.slice(1), 'update').rest, 0, 'update');
719
- const { checkouts: liste, bundles, aufraeumen, doctor, } = await anwendungsfaelle.aktualisieren({ ausloeser: 'cli' });
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 }) });
720
732
  if (liste.length === 0)
721
733
  console.log('Keine Checkouts.');
722
734
  for (const { checkout, aktualisierung, geaenderteSkills } of liste) {
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
- async function aktualisierenLauf(ausloeser) {
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
- return window.hmgr.aktualisieren({ rueckfragen: ausloeser !== 'klick', ausloeser: ausloeser });
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).
@@ -3539,6 +3543,17 @@
3539
3543
  stift.appendChild(stiftSvg);
3540
3544
  stift.addEventListener('click', function () { oeffneQuelleUmbenennen(q); });
3541
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);
3542
3557
  var weg = e('button', 'knopf leise klein', 'Entfernen …');
3543
3558
  weg.type = 'button';
3544
3559
  weg.setAttribute('aria-label', q.name + ' entfernen');
@@ -1109,7 +1109,9 @@ export class Anwendungsfaelle {
1109
1109
  async bundleAbgleich(args) {
1110
1110
  const zustand = await this.p.zustand.lesen();
1111
1111
  const zielSchl = args?.ziel === undefined ? undefined : zielSchluessel(args.ziel);
1112
+ const quelleSchl = args?.quelle === undefined ? undefined : quelleSchluessel(args.quelle);
1112
1113
  const installationen = zustand.bundleInstallationen.filter((i) => (args?.bundle === undefined || i.bundle === args.bundle) &&
1114
+ (quelleSchl === undefined || quelleSchluessel(i.quelle) === quelleSchl) &&
1113
1115
  (zielSchl === undefined || zielSchluessel(Anwendungsfaelle.installationZiel(i)) === zielSchl));
1114
1116
  const ergebnis = [];
1115
1117
  for (const installation of installationen) {
@@ -1274,6 +1276,22 @@ export class Anwendungsfaelle {
1274
1276
  if ((await this.bindungFinden(ziel)) !== undefined)
1275
1277
  throw new ZeigerSchreibenGesperrt(ziel);
1276
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
+ }
1277
1295
  /** Skill über alle Quellen suchen. Mehrere Treffer sind nur mit Quellenhinweis erlaubt. */
1278
1296
  async skillFinden(name, quelleHinweis) {
1279
1297
  const zustand = await this.p.zustand.lesen();
@@ -1759,11 +1777,18 @@ export class Anwendungsfaelle {
1759
1777
  * ergeben hat: unveränderte oder übersprungene Checkouts und Bundles ohne Änderung erzeugen
1760
1778
  * nichts, ein leerer Lauf bleibt ganz aus dem Changelog. `ausloeser` steht mit im Eintrag, damit
1761
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.
1762
1784
  */
1763
1785
  async aktualisieren(args) {
1764
1786
  const rueckfragen = args?.rueckfragen ?? true;
1765
1787
  const ausloeser = args?.ausloeser ?? 'cli';
1766
- const bekannt = new Map((await this.p.zustand.lesen()).quellen.map((q) => [quelleSchluessel(q), q]));
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]));
1767
1792
  const checkouts = [];
1768
1793
  for (const checkout of await this.p.quellen.checkouts()) {
1769
1794
  const gefuehrt = bekannt.get(quelleSchluessel(checkout.quelle));
@@ -1805,7 +1830,7 @@ export class Anwendungsfaelle {
1805
1830
  }
1806
1831
  // Nach den Checkouts die Plugins nachziehen (E14).
1807
1832
  const pluginHarnesses = [];
1808
- for (const harness of await this.vorhandeneHarnesses()) {
1833
+ for (const harness of nurSchluessel !== undefined ? [] : await this.vorhandeneHarnesses()) {
1809
1834
  if (!kannPlugins(harness))
1810
1835
  continue;
1811
1836
  await harness.plugins.aktualisieren();
@@ -1814,9 +1839,13 @@ export class Anwendungsfaelle {
1814
1839
  // Bundles vor dem Aufräumen (E69, F64=O1): der Abgleich legt und entfernt Links, und erst
1815
1840
  // danach steht fest, in welchen Checkout noch ein Link zeigt. Ein Fehlschlag je Bundle steckt
1816
1841
  // in seinem Eintrag, er bricht den Lauf nicht ab — wie eine unerreichbare Quelle (E51).
1817
- const bundles = await this.bundleAbgleich();
1818
- const aufraeumen = await this.verwaisteAufraeumen(checkouts, rueckfragen);
1819
- const doctorErgebnis = await this.doctor({ rueckfragen });
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 });
1820
1849
  await this.verlaufVermerken(ausloeser, this.aktualisierungsEreignisse(checkouts, bundles, aufraeumen, doctorErgebnis));
1821
1850
  return { checkouts, pluginHarnesses, bundles, aufraeumen, doctor: doctorErgebnis };
1822
1851
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hmgr",
3
- "version": "0.0.19",
3
+ "version": "0.0.20",
4
4
  "description": "Harness Manager: Skills und Plugins für AI-Harnesses verwalten",
5
5
  "license": "MIT",
6
6
  "author": "Tim Kaufmann",