hmgr 0.0.51 → 0.0.52

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.
@@ -51,6 +51,9 @@ export class Agents {
51
51
  if (ort.art === 'arbeitsverzeichnis' && (await istGitRepo(ort.pfad)))
52
52
  await gitignoreEintragen(ort.pfad, GITIGNORE_ZEILE);
53
53
  }
54
+ quellOrdner() {
55
+ return `${AGENTS_VERZEICHNIS}/${SKILLS_ORDNER}`;
56
+ }
54
57
  folgtLinks() {
55
58
  return true;
56
59
  }
@@ -681,6 +681,9 @@ export class ClaudeCode {
681
681
  if (ort.art === 'arbeitsverzeichnis' && (await istGitRepo(ort.pfad)))
682
682
  await gitignoreEintragen(ort.pfad, GITIGNORE_ZEILE);
683
683
  }
684
+ quellOrdner() {
685
+ return `${CLAUDE_VERZEICHNIS}/${SKILLS_ORDNER}`;
686
+ }
684
687
  folgtLinks() {
685
688
  return true;
686
689
  }
@@ -289,6 +289,9 @@ export class Hermes {
289
289
  await mkdir(hermesHome, { recursive: true });
290
290
  await writeFile(pfad, doc.toString());
291
291
  }
292
+ quellOrdner() {
293
+ return `${HERMES_VERZEICHNIS}/${EIGENER_ORDNER}`;
294
+ }
292
295
  folgtLinks() {
293
296
  return true;
294
297
  }
@@ -1,6 +1,9 @@
1
1
  {
2
2
  "fassung": 1,
3
3
  "versionen": {
4
+ "0.0.52": [
5
+ "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
+ ],
4
7
  "0.0.51": [
5
8
  "Ein gelöschter Projektordner, an dem noch ein Bundle hing, wird beim Aktualisieren nicht mehr neu angelegt. `hmgr doctor` findet solche Ordner jetzt und bietet an, sie samt ihren Bundles zu vergessen."
6
9
  ],
package/dist/cli/hilfe.js CHANGED
@@ -147,6 +147,7 @@ Schalter:
147
147
  --ort <ort> home, wsl:<distro>, dir:<pfad> oder profil:<name>, Standard home. profil
148
148
  kennt nur hermes, wsl:<distro> nur claude-code unter Windows (E78)
149
149
  --quelle <teil> Teilstring der Quelle, wenn der Skill-Name in mehreren Quellen vorkommt
150
+ --pfad <skill-pfad> Skill-Ordner in der Quelle, wenn der Name dort mehrfach vorkommt (E121)
150
151
  --version <spanne> Versionseinschränkung nach Composer-Regeln (etwa ^1.2) oder ein Tag- oder
151
152
  Branchname. Nur mit Zeiger, also dir:<pfad> ohne --local (E33)
152
153
  --composer <pfad> composer.json des Arbeitsverzeichnisses, wenn mehrere in Frage kommen
@@ -155,11 +156,15 @@ Schalter:
155
156
 
156
157
  Beispiele:
157
158
  hmgr link netzwerk
159
+ hmgr link impeccable --pfad plugin/skills/impeccable
158
160
  hmgr link netzwerk --harness hermes --ort profil:researcher
159
161
  hmgr link tq-schema --ort dir:. --version ^2.0
160
162
 
161
163
  Häufige Fälle:
162
164
  „liegt in mehreren Quellen": mit --quelle <teilstring der URL oder des Pfads> entscheiden.
165
+ „liegt in der Quelle … mehrfach": mit --pfad einen der genannten Pfade wählen. Liegt genau
166
+ eine Fassung im Skill-Ordner des Harness (claude-code .claude/skills, hermes .hermes/skills,
167
+ agents .agents/skills), nimmt hmgr sie von selbst und fragt nicht nach.
163
168
  „liegt bereits ein fremder Eintrag": --ersetzen setzen oder vorher hmgr adopt <name>.
164
169
  „gibt es keinen Zeiger": --version braucht ein Arbeitsverzeichnis mit composer.json und kein
165
170
  --local. Ohne Zeiger den Link ohne --version legen.
package/dist/cli/main.js CHANGED
@@ -121,7 +121,7 @@ const SCHALTER = {
121
121
  source: { werte: ['name'], flaggen: [] },
122
122
  dir: { werte: ['composer'], flaggen: [] },
123
123
  link: {
124
- werte: ['harness', 'ort', 'composer', 'quelle', 'version'],
124
+ werte: ['harness', 'ort', 'composer', 'quelle', 'version', 'pfad'],
125
125
  flaggen: ['local', 'lokal', 'ersetzen'],
126
126
  },
127
127
  unlink: { werte: ['harness', 'ort', 'composer'], flaggen: ['local', 'lokal'] },
@@ -507,10 +507,12 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
507
507
  }
508
508
  const quelle = werte.get('quelle');
509
509
  const version = werte.get('version');
510
+ const pfad = werte.get('pfad');
510
511
  const link = await anwendungsfaelle.linkLegen({
511
512
  skill,
512
513
  ziel,
513
514
  ...(quelle === undefined ? {} : { quelle }),
515
+ ...(pfad === undefined ? {} : { pfad }),
514
516
  ...(version === undefined ? {} : { version }),
515
517
  ersetzen: flaggen.has('ersetzen'),
516
518
  lokal,
@@ -1320,7 +1322,9 @@ function istModellFehler(fehler) {
1320
1322
  */
1321
1323
  function naechsterSchritt(fehler) {
1322
1324
  if (fehler instanceof SkillMehrdeutig)
1323
- return `Quelle eingrenzen: hmgr link ${fehler.name} --quelle <teilstring einer der genannten Quellen>`;
1325
+ return fehler.nurEineQuelle
1326
+ ? `Fassung wählen: hmgr link ${fehler.name} --pfad <einer der genannten Pfade>`
1327
+ : `Quelle eingrenzen: hmgr link ${fehler.name} --quelle <teilstring einer der genannten Quellen>`;
1324
1328
  if (fehler instanceof SkillUnbekannt)
1325
1329
  return 'Erst die Quelle hinzufügen: hmgr source add <url|pfad>. hmgr source list zeigt die bekannten Quellen.';
1326
1330
  if (fehler instanceof NameBelegt)
package/dist/gui/main.js CHANGED
@@ -228,6 +228,7 @@ function registriereIpc() {
228
228
  ...(skill.eigenerKontext === undefined ? {} : { eigenerKontext: skill.eigenerKontext }),
229
229
  ...(skill.argumentHinweis === undefined ? {} : { argumentHinweis: skill.argumentHinweis }),
230
230
  ...(skill.geaendert === undefined ? {} : { geaendert: skill.geaendert }),
231
+ ...(skill.jeHarness === undefined ? {} : { jeHarness: skill.jeHarness }),
231
232
  quelleText: quelleAlsText(eintrag.quelle),
232
233
  quelleName: quelleName(eintrag.quelle),
233
234
  quelleSchluessel: quelleSchluessel(eintrag.quelle),
@@ -886,6 +887,8 @@ function fensterOeffnen() {
886
887
  var dskBundleBoxSichtbar = false;
887
888
  var dskBundleText = null;
888
889
  var dskBundleZuVorher = null, dskBundleKoerperText = null;
890
+ // E121: ein Name mit mehreren Fassungen in der Quelle steht einmal, mit Vermerk statt Pfad.
891
+ var dskMehrfachAnzahl = null, dskMehrfachText = null;
889
892
  // Aufklappbereich je Zeile (E92): zu vor dem Klick, danach sichtbar mit der ungekürzten
890
893
  // Beschreibung; die Checkbox bleibt unberührt, der Dialog offen.
891
894
  var dskKoerperVorher = null;
@@ -920,6 +923,10 @@ function fensterOeffnen() {
920
923
  dskAufklapp?.click();
921
924
  dskKoerper?.querySelector('p')?.click();
922
925
  dskAufklappFreiAngehakt = dskEingabe?.checked ?? null;
926
+ var dskMehrfach = Array.from(document.querySelectorAll('#dsk-liste .wahlzeile'))
927
+ .filter((z) => z.querySelector('b')?.textContent === 'zmehrfach');
928
+ dskMehrfachAnzahl = dskMehrfach.length;
929
+ dskMehrfachText = dskMehrfach[0]?.querySelector('.mono')?.textContent ?? null;
923
930
  dskBundleBoxSichtbar = document.getElementById('dsk-bundlebox')?.hidden === false;
924
931
  dskBundleText = document.querySelector('#dsk-bundles .wahlzeile')?.textContent
925
932
  ?.replace(/\\s+/g, ' ').trim() ?? null;
@@ -1283,6 +1290,8 @@ function fensterOeffnen() {
1283
1290
  katalogDetails,
1284
1291
  katalogMarkenWarnend,
1285
1292
  dskMarken,
1293
+ dskMehrfachAnzahl,
1294
+ dskMehrfachText,
1286
1295
  dskKoerperVorher,
1287
1296
  dskKoerperNachher,
1288
1297
  dskKoerperText,
@@ -813,7 +813,7 @@
813
813
  /** Skill zu einem Mitglied einer Definition aus dem Skill-Katalog (E114 L1): gleiche Quelle, gleicher
814
814
  Pfad. null, wenn die Quelle (noch) nicht eingerichtet oder nicht lesbar ist. */
815
815
  function bundleMitgliedSkill(m) {
816
- return SKILLS.filter(function (s) { return s.quelleSchluessel === m.quelleSchluessel && s.pfad === m.pfad; })[0] || null;
816
+ return SKILLS.filter(function (s) { return s.quelleSchluessel === m.quelleSchluessel && (s.pfad === m.pfad || (s.jeHarness || []).indexOf(m.pfad) > -1); })[0] || null;
817
817
  }
818
818
 
819
819
  /** Skill eines nicht verlinkten Mitglieds über seinen Namen, gesucht unter den Mitgliedern der
@@ -2274,7 +2274,8 @@
2274
2274
  // Skill-Ordner berührt. Nicht der Pull-Zeitpunkt — der steht als „Zuletzt geprüft" in der
2275
2275
  // Update-Ansicht und wäre für alle Skills einer Quelle derselbe.
2276
2276
  var geaendert = datumDeutsch(skill.geaendert);
2277
- var nachRef = ' · Ref ' + skill.ref + (geaendert ? ' · geändert ' + geaendert : '');
2277
+ var nachRef = ' · Ref ' + skill.ref + (geaendert ? ' · geändert ' + geaendert : '')
2278
+ + (skill.jeHarness ? ' · ' + JE_HARNESS_VERMERK : '');
2278
2279
  if (herkunftQuelle) {
2279
2280
  herkunft.appendChild(quelleLinkElement(herkunftQuelle));
2280
2281
  herkunft.appendChild(e('b', null, nachRef));
@@ -2341,7 +2342,8 @@
2341
2342
  var sichtbar = 0;
2342
2343
  document.querySelectorAll('#katalog .zeile').forEach(function (li) {
2343
2344
  var skill = SKILLS[+li.dataset.index];
2344
- var passtSuche = !suche || suchform(skill.name).indexOf(suche) > -1 || suchform(skill.pfad).indexOf(suche) > -1;
2345
+ var passtSuche = !suche || suchform(skill.name).indexOf(suche) > -1 || suchform(skill.pfad).indexOf(suche) > -1
2346
+ || (skill.jeHarness || []).some(function (p) { return suchform(p).indexOf(suche) > -1; });
2345
2347
  var passtFilter = quellenFilter === 'alle' || skill.quelleSchluessel === quellenFilter;
2346
2348
  var an = passtSuche && passtFilter;
2347
2349
  li.hidden = !an;
@@ -2581,9 +2583,13 @@
2581
2583
  /** Quelle · [Pfad ·] Ref für eine Skill-Karte im „Skills hinzufügen"-Dialog (F106): der Pfad
2582
2584
  unterscheidet Skills, die unter demselben Namen mehrfach im selben Repo liegen (z. B. je
2583
2585
  Harness ein eigener Ordner). Ein Wurzel-Skill hat pfad === '' und zeigt kein Pfad-Segment. */
2586
+ var JE_HARNESS_VERMERK = 'je Harness eigene Fassung';
2587
+
2584
2588
  function skillQuelleBeschriftung(skill) {
2585
2589
  var teile = [skill.quelleName];
2586
- if (skill.pfad) teile.push(skill.pfad);
2590
+ // Mehrfach in der Quelle, je Harness eine eigene Fassung (E121): der Kern löst beim Verlinken auf.
2591
+ if (skill.jeHarness) teile.push(JE_HARNESS_VERMERK);
2592
+ else if (skill.pfad) teile.push(skill.pfad);
2587
2593
  teile.push('Ref ' + skill.ref);
2588
2594
  return teile.join(' · ');
2589
2595
  }
@@ -861,10 +861,10 @@ export class Anwendungsfaelle {
861
861
  ergebnis.push({
862
862
  quelle,
863
863
  ref,
864
- skills: skills.map((skill) => {
864
+ skills: this.fassungenZusammenfassen(skills.map((skill) => {
865
865
  const geaendert = daten.get(skill.pfad);
866
866
  return geaendert === undefined ? skill : { ...skill, geaendert };
867
- }),
867
+ })),
868
868
  });
869
869
  }
870
870
  catch (fehler) {
@@ -873,6 +873,39 @@ export class Anwendungsfaelle {
873
873
  }
874
874
  return ergebnis;
875
875
  }
876
+ /**
877
+ * Katalog-Zusammenfassung (E121): Ein Name, der in einer Quelle mehrfach vorkommt und mindestens
878
+ * einmal unmittelbar in einem Harness-Skill-Ordner liegt, erscheint einmal, mit `jeHarness`. Als
879
+ * Vertreter dient die Fassung im ersten passenden Harness-Ordner (Reihenfolge der Harnesses),
880
+ * sonst die erste. Alle anderen Namen bleiben unverändert, ebenso die Reihenfolge.
881
+ */
882
+ fassungenZusammenfassen(skills) {
883
+ const ordner = this.p.harnesses.map((h) => `${h.quellOrdner()}/`);
884
+ const direkt = (s, o) => s.pfad.startsWith(o) && !s.pfad.slice(o.length).includes('/');
885
+ const gruppen = new Map();
886
+ for (const s of skills)
887
+ gruppen.set(s.name, [...(gruppen.get(s.name) ?? []), s]);
888
+ const ergebnis = [];
889
+ for (const s of skills) {
890
+ const gruppe = gruppen.get(s.name);
891
+ if (gruppe.length < 2 || !gruppe.some((g) => ordner.some((o) => direkt(g, o)))) {
892
+ ergebnis.push(s);
893
+ continue;
894
+ }
895
+ if (gruppe[0] !== s)
896
+ continue; // Vertreter steht an der Stelle der ersten Fassung
897
+ let vertreter = gruppe[0];
898
+ for (const o of ordner) {
899
+ const treffer = gruppe.find((g) => direkt(g, o));
900
+ if (treffer !== undefined) {
901
+ vertreter = treffer;
902
+ break;
903
+ }
904
+ }
905
+ ergebnis.push({ ...vertreter, jeHarness: gruppe.map((g) => g.pfad) });
906
+ }
907
+ return ergebnis;
908
+ }
876
909
  /** Alle Marketplaces der bekannten Quellen, für `hmgr plugin list`. */
877
910
  async marketplaces() {
878
911
  const zustand = await this.p.zustand.lesen();
@@ -1566,7 +1599,7 @@ export class Anwendungsfaelle {
1566
1599
  throw new Error(`Mehrere Quellen passen auf „${hinweis}", bitte eingrenzen:\n${zeilen(treffer)}`);
1567
1600
  }
1568
1601
  /** Skill über alle Quellen suchen. Mehrere Treffer sind nur mit Quellenhinweis erlaubt. */
1569
- async skillFinden(name, quelleHinweis) {
1602
+ async skillFinden(name, quelleHinweis, wahl = {}) {
1570
1603
  const zustand = await this.p.zustand.lesen();
1571
1604
  const funde = [];
1572
1605
  for (const quelle of zustand.quellen) {
@@ -1574,16 +1607,33 @@ export class Anwendungsfaelle {
1574
1607
  continue;
1575
1608
  const ref = await this.p.quellen.standardRef(quelle);
1576
1609
  const skills = await this.p.quellen.skills(quelle, ref);
1577
- for (const skill of skills)
1578
- if (skill.name === name)
1579
- funde.push({ quelle, ref, skill });
1610
+ for (const skill of Anwendungsfaelle.skillTreffer(skills, name, wahl))
1611
+ funde.push({ quelle, ref, skill });
1580
1612
  }
1581
1613
  if (funde.length === 0)
1582
1614
  throw new SkillUnbekannt(name);
1583
1615
  if (funde.length > 1)
1584
- throw new SkillMehrdeutig(name, funde.map((f) => f.quelle));
1616
+ throw new SkillMehrdeutig(name, funde.map((f) => ({ quelle: f.quelle, pfad: f.skill.pfad })));
1585
1617
  return funde[0];
1586
1618
  }
1619
+ /**
1620
+ * Die Skills einer Quelle zu einem Namen (E121). Mit `pfad` zählt nur der Skill mit genau diesem
1621
+ * Pfad. Sonst gewinnt bei mehreren Fassungen die eine, die unmittelbar im Skill-Ordner des
1622
+ * Harness liegt (`<quellOrdner>/<ordner>`, eine Ebene); gibt es keine solche oder mehrere,
1623
+ * bleiben alle, und der Aufrufer meldet die Mehrdeutigkeit.
1624
+ */
1625
+ static skillTreffer(skills, name, wahl) {
1626
+ const gleichnamig = skills.filter((s) => s.name === name);
1627
+ if (wahl.pfad !== undefined) {
1628
+ const pfad = wahl.pfad.replace(/^\.?\/+|\/+$/g, '');
1629
+ return gleichnamig.filter((s) => s.pfad === pfad);
1630
+ }
1631
+ if (gleichnamig.length < 2 || wahl.quellOrdner === undefined)
1632
+ return gleichnamig;
1633
+ const praefix = `${wahl.quellOrdner}/`;
1634
+ const direkt = gleichnamig.filter((s) => s.pfad.startsWith(praefix) && !s.pfad.slice(praefix.length).includes('/'));
1635
+ return direkt.length === 1 ? direkt : gleichnamig;
1636
+ }
1587
1637
  /** Checkout anlegen oder erweitern, Ziel vorbereiten, Link setzen. Ohne Zeiger-Arbeit. */
1588
1638
  async linkAnlegen(harness, ziel, fund, ersetzen) {
1589
1639
  if (!harness.orte().includes(ziel.ort.art))
@@ -1627,8 +1677,12 @@ export class Anwendungsfaelle {
1627
1677
  if (!harness.orte().includes(args.ziel.ort.art))
1628
1678
  throw new OrtNichtUnterstuetzt(harness.name, args.ziel.ort.art);
1629
1679
  const version = args.version;
1680
+ const wahl = {
1681
+ quellOrdner: harness.quellOrdner(),
1682
+ ...(args.pfad === undefined ? {} : { pfad: args.pfad }),
1683
+ };
1630
1684
  if (version === undefined) {
1631
- const fund = await this.skillFinden(args.skill, args.quelle);
1685
+ const fund = await this.skillFinden(args.skill, args.quelle, wahl);
1632
1686
  const ergebnis = await this.linkAusFund(harness, args.ziel, fund, args.ersetzen, args.lokal);
1633
1687
  return Anwendungsfaelle.hinweisAnhaengen(ergebnis, await this.bundleMitgliedZurueckholen(args.ziel, fund));
1634
1688
  }
@@ -1640,7 +1694,7 @@ export class Anwendungsfaelle {
1640
1694
  // Eine Versionseinschränkung schreibt immer geteilt (siehe EinschraenkungOhneZeiger oben), das
1641
1695
  // trifft die Sperre also ausnahmslos, solange sie steht (E57).
1642
1696
  await this.zeigerSchreibenPruefen(args.ziel, args.lokal);
1643
- const fund = await this.fundAusZeiger(args.skill, version, args.quelle);
1697
+ const fund = await this.fundAusZeiger(args.skill, version, args.quelle, wahl);
1644
1698
  const link = await this.linkAnlegen(harness, args.ziel, fund, args.ersetzen);
1645
1699
  await this.zeigerErgaenzen(zeigerPfad, fund, version);
1646
1700
  const hinweis = await this.harnessHinweis(harness, args.ziel.ort);
@@ -1957,9 +2011,9 @@ export class Anwendungsfaelle {
1957
2011
  * gilt der Text als genauer Ref-Name gegen alle Refs, damit Tags und Branches ohne
1958
2012
  * Versions-Schema erreichbar bleiben. Nie auf den Standard-Ref ausweichen (B8).
1959
2013
  */
1960
- async fundAusZeiger(name, einschraenkung, quelleHinweis) {
2014
+ async fundAusZeiger(name, einschraenkung, quelleHinweis, wahl = {}) {
1961
2015
  if (einschraenkung === null)
1962
- return await this.skillFinden(name, quelleHinweis);
2016
+ return await this.skillFinden(name, quelleHinweis, wahl);
1963
2017
  const zustand = await this.p.zustand.lesen();
1964
2018
  const quellen = zustand.quellen.filter((q) => quellePasst(q, quelleHinweis));
1965
2019
  for (const quelle of quellen) {
@@ -1968,7 +2022,7 @@ export class Anwendungsfaelle {
1968
2022
  const ref = passenderRef(tags, einschraenkung);
1969
2023
  if (ref === null)
1970
2024
  continue;
1971
- const skill = (await this.p.quellen.skills(quelle, ref)).find((s) => s.name === name);
2025
+ const skill = Anwendungsfaelle.skillTreffer(await this.p.quellen.skills(quelle, ref), name, wahl)[0];
1972
2026
  if (skill)
1973
2027
  return { quelle, ref, skill };
1974
2028
  }
@@ -1976,7 +2030,7 @@ export class Anwendungsfaelle {
1976
2030
  const refs = await this.p.quellen.refs(quelle).catch(() => []);
1977
2031
  if (!refs.includes(einschraenkung))
1978
2032
  continue;
1979
- const skill = (await this.p.quellen.skills(quelle, einschraenkung)).find((s) => s.name === name);
2033
+ const skill = Anwendungsfaelle.skillTreffer(await this.p.quellen.skills(quelle, einschraenkung), name, wahl)[0];
1980
2034
  if (skill)
1981
2035
  return { quelle, ref: einschraenkung, skill };
1982
2036
  }
@@ -2053,7 +2107,7 @@ export class Anwendungsfaelle {
2053
2107
  }
2054
2108
  for (const [name, einschraenkung] of zeiger.skills) {
2055
2109
  try {
2056
- const fund = await this.fundAusZeiger(name, einschraenkung);
2110
+ const fund = await this.fundAusZeiger(name, einschraenkung, undefined, { quellOrdner: harness.quellOrdner() });
2057
2111
  const gefunden = eintraege.find((e) => e.art === 'link' && e.link.name === name);
2058
2112
  // Ein eigener Link auf einen anderen Ref weicht ab und wird umgelegt (E33). Das trifft
2059
2113
  // die Einschränkung, die inzwischen einen höheren Tag findet.
@@ -338,10 +338,24 @@ export class LinkAnlegenFehlgeschlagen extends Error {
338
338
  export class SkillMehrdeutig extends Error {
339
339
  name;
340
340
  quellen;
341
- constructor(name, quellen) {
342
- super(`Skill „${name}" liegt in mehreren Quellen: ${quellen.map(quelleSchluessel).join(', ')}`);
341
+ funde;
342
+ /** Die Mehrdeutigkeit kommt aus einer einzigen Quelle: `--pfad` hilft, nicht `--quelle` (E121). */
343
+ nurEineQuelle;
344
+ constructor(name, funde) {
345
+ const quellen = [];
346
+ for (const f of funde)
347
+ if (!quellen.some((q) => quelleSchluessel(q) === quelleSchluessel(f.quelle)))
348
+ quellen.push(f.quelle);
349
+ const zeilen = funde
350
+ .map((f) => ` ${quelleSchluessel(f.quelle)}: ${f.pfad === '' ? '(Repo-Wurzel)' : f.pfad}`)
351
+ .join('\n');
352
+ super(quellen.length === 1
353
+ ? `Skill „${name}" liegt in der Quelle ${quelleSchluessel(quellen[0])} mehrfach:\n${zeilen}`
354
+ : `Skill „${name}" liegt in mehreren Quellen:\n${zeilen}`);
343
355
  this.name = name;
344
356
  this.quellen = quellen;
357
+ this.funde = funde;
358
+ this.nurEineQuelle = quellen.length === 1;
345
359
  }
346
360
  }
347
361
  export class SkillUnbekannt extends Error {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hmgr",
3
- "version": "0.0.51",
3
+ "version": "0.0.52",
4
4
  "description": "Harness Manager: Skills und Plugins für AI-Harnesses verwalten",
5
5
  "license": "MIT",
6
6
  "author": "Tim Kaufmann",