hmgr 0.0.24 → 0.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/gui/main.js +3 -1
- package/dist/kern/anwendungsfaelle.js +35 -7
- package/dist/kern/begrenzung.js +27 -0
- package/package.json +1 -1
package/dist/gui/main.js
CHANGED
|
@@ -187,7 +187,9 @@ function registriereIpc() {
|
|
|
187
187
|
// Ebenfalls nur für die Anzeige (E68): der Renderer leitet daraus den Pfadtrenner ab, mit dem er
|
|
188
188
|
// eigene Anzeigepfade zusammensetzt („~/.claude.json" bzw. „~\.claude.json").
|
|
189
189
|
ipcMain.handle('hmgr:plattform', async () => auffangen(async () => process.platform));
|
|
190
|
-
|
|
190
|
+
// Ohne Plugin-Abfrage (E93): der Renderer liest `plugins` aus dem Ziel-Zustand nirgends, und die
|
|
191
|
+
// Abfrage kostet einen claude-Prozess je Ziel.
|
|
192
|
+
ipcMain.handle('hmgr:istZustand', async () => auffangen(async () => (await anwendungsfaelle.istZustand({ plugins: false })).map(zielZustandSerialisieren)));
|
|
191
193
|
ipcMain.handle('hmgr:marketplaces', async () => auffangen(async () => (await anwendungsfaelle.marketplaces()).map((m) => ({
|
|
192
194
|
quelleText: quelleAlsText(m.quelle),
|
|
193
195
|
name: m.name,
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
// Anwendungsfälle. Pfade werden hier nur als Zeichenketten normalisiert, gelesen wird über die Ports.
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { AbhaengigkeitFehlt, BundleMehrdeutig, BundleMitgliederFehlen, BundleNamenskonflikte, BundleNichtInstalliert, BundleUnbekannt, EinschraenkungOhneZeiger, FremderEintragUnbekannt, HarnessInaktiv, HarnessNichtVorhanden, HarnessTypUnbekannt, HeimAdresseUngueltig, HeimBereitsVorhanden, HeimFaehigkeitFehlt, HeimNurUnterWindows, HeimUnbekannt, KeinPassenderRef, McpEbeneNichtUnterstuetzt, McpFaehigkeitFehlt, McpOrtUnterGitWurzel, McpUebernahmeNichtMoeglich, McpUnbekannt, OrtNichtUnterstuetzt, PluginMehrdeutig, PluginUnbekannt, QuelleAufraeumenLokaleAenderungen, QuelleNameBelegt, QuelleUnbekannt, SkillMehrdeutig, SkillOrdnerBereitsVerwaltet, SkillOrdnerFaehigkeitFehlt, SkillOrdnerNichtVerwaltet, SkillUnbekannt, ZeigerMehrdeutig, ZeigerSchreibenGesperrt, bundleSchluessel, heimAdresseAlsText, heimAdresseZerlegen, marketplaceUrl, pluginSchluessel, pluginSchluesselZerlegen, quelleAlsText, quelleMitNamen, quelleName, quelleNameAbleiten, quelleNameFrei, quelleSchluessel, zielSchluessel, } from "./modell.js";
|
|
4
|
+
import { mitBegrenzung } from "./begrenzung.js";
|
|
4
5
|
import { passenderRef } from "./version.js";
|
|
5
6
|
import { kannIstRegistriert, kannMcp, kannPlugins, kannProfile, kannSkillOrdner, kannZurueckbauen, kannZusaetzlicheHeime, } from "../ports/harness.js";
|
|
7
|
+
/** So viele `plugin list`-Prozesse laufen im Ist-Zustand höchstens gleichzeitig (E93). */
|
|
8
|
+
const PLUGIN_ABFRAGEN_GLEICHZEITIG = 6;
|
|
6
9
|
/**
|
|
7
10
|
* Frage vor dem Löschen, eine für alle Kandidaten (E28). Der Kern formuliert sie fertig, der
|
|
8
11
|
* Adapter stellt sie: Anzahl und Pfade, damit der Nutzer sieht, worüber er entscheidet.
|
|
@@ -2314,8 +2317,13 @@ export class Anwendungsfaelle {
|
|
|
2314
2317
|
gruende.set(name, zeiger?.skills.has(name) === true ? { art: 'zeiger' } : { art: 'manuell' });
|
|
2315
2318
|
return gruende;
|
|
2316
2319
|
}
|
|
2317
|
-
/**
|
|
2318
|
-
|
|
2320
|
+
/**
|
|
2321
|
+
* Ist-Zustand: alle Ziele der vorhandenen Harnesses, aus dem Dateisystem gelesen.
|
|
2322
|
+
* `plugins: false` lässt die Plugin-Abfrage aus (E93): sie ist ein Prozess je Ziel und für die
|
|
2323
|
+
* GUI, die das Feld nicht zeigt, nur Wartezeit. Dann fehlt `plugins` an allen Ziel-Zuständen.
|
|
2324
|
+
*/
|
|
2325
|
+
async istZustand(optionen = {}) {
|
|
2326
|
+
const mitPlugins = optionen.plugins !== false;
|
|
2319
2327
|
const zustand = await this.p.zustand.lesen();
|
|
2320
2328
|
// Je Identität die Quelle, unter deren Schreibweise sie geführt wird (E36, E48), für die
|
|
2321
2329
|
// Übernahme-Prognose. Bleibt über den ganzen Lauf gleich, die Prognose verändert nichts.
|
|
@@ -2340,6 +2348,8 @@ export class Anwendungsfaelle {
|
|
|
2340
2348
|
return funde;
|
|
2341
2349
|
};
|
|
2342
2350
|
const ergebnis = [];
|
|
2351
|
+
// Zielliste einmal bilden: Vorabruf der Plugins und Hauptschleife gehen über dieselben Ziele.
|
|
2352
|
+
const plan = [];
|
|
2343
2353
|
for (const harness of await this.vorhandeneHarnesses()) {
|
|
2344
2354
|
const ziele = [...this.homeZiele(harness)];
|
|
2345
2355
|
if (harness.orte().includes('profil') && kannProfile(harness))
|
|
@@ -2348,14 +2358,32 @@ export class Anwendungsfaelle {
|
|
|
2348
2358
|
if (harness.orte().includes('arbeitsverzeichnis'))
|
|
2349
2359
|
for (const pfad of zustand.arbeitsverzeichnisse)
|
|
2350
2360
|
ziele.push(arbeitsverzeichnisZiel(harness.name, pfad));
|
|
2361
|
+
plan.push({ harness, ziele });
|
|
2362
|
+
}
|
|
2363
|
+
// Installierte Plugins je Ziel vorab, mit begrenzter Parallelität (E93): `claude plugin list`
|
|
2364
|
+
// ist ein Prozess je Ziel (cwd-gebunden, kein Sammelaufruf), nacheinander dauert das bei vielen
|
|
2365
|
+
// Arbeitsverzeichnissen Sekunden. Plugins nur am primären Homedir (E78): die claude-CLI dieses
|
|
2366
|
+
// Rechners kennt die Plugin-Konfiguration einer WSL-Distro nicht, ihre user-Liste gehörte zum
|
|
2367
|
+
// Windows-Home.
|
|
2368
|
+
const pluginListen = new Map();
|
|
2369
|
+
if (mitPlugins) {
|
|
2370
|
+
const abfragen = [];
|
|
2371
|
+
for (const { harness, ziele } of plan)
|
|
2372
|
+
if (kannPlugins(harness))
|
|
2373
|
+
for (const ziel of ziele)
|
|
2374
|
+
if (!(ziel.ort.art === 'home' && ziel.ort.heim !== undefined))
|
|
2375
|
+
abfragen.push({
|
|
2376
|
+
schluessel: zielSchluessel(ziel),
|
|
2377
|
+
abruf: () => harness.plugins.installierte(ziel).catch(() => []),
|
|
2378
|
+
});
|
|
2379
|
+
const listen = await mitBegrenzung(PLUGIN_ABFRAGEN_GLEICHZEITIG, abfragen.map((a) => a.abruf));
|
|
2380
|
+
abfragen.forEach((a, i) => pluginListen.set(a.schluessel, listen[i]));
|
|
2381
|
+
}
|
|
2382
|
+
for (const { harness, ziele } of plan) {
|
|
2351
2383
|
for (const ziel of ziele) {
|
|
2352
2384
|
const verzeichnis = harness.zielVerzeichnis(ziel.ort);
|
|
2353
2385
|
const eintraege = await this.p.ziele.eintraege(ziel, verzeichnis).catch(() => []);
|
|
2354
|
-
|
|
2355
|
-
// Plugin-Konfiguration einer WSL-Distro nicht, ihre user-Liste gehörte zum Windows-Home.
|
|
2356
|
-
const plugins = kannPlugins(harness) && !(ziel.ort.art === 'home' && ziel.ort.heim !== undefined)
|
|
2357
|
-
? await harness.plugins.installierte(ziel).catch(() => [])
|
|
2358
|
-
: undefined;
|
|
2386
|
+
const plugins = pluginListen.get(zielSchluessel(ziel));
|
|
2359
2387
|
const zeiger = await this.zeigerFuerZiel(ziel);
|
|
2360
2388
|
const istRegistriert = kannIstRegistriert(harness) ? await harness.istRegistriert(ziel.ort) : false;
|
|
2361
2389
|
// Fähigkeit am Typwächter, nicht am Namen (E16), und nur an Orten, die sie kennt.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Führt Aufgaben mit höchstens `grenze` gleichzeitig laufenden aus (E93). Die Ergebnisse stehen
|
|
3
|
+
* in der Reihenfolge der Aufgaben, nicht der Fertigstellung. Kein Fehlerschutz: wirft eine
|
|
4
|
+
* Aufgabe, bricht der Aufruf mit diesem Fehler ab und startet keine weiteren Aufgaben. Aufrufer,
|
|
5
|
+
* die einzelne Ausfälle hinnehmen wollen, setzen das `.catch` in der Aufgabe selbst.
|
|
6
|
+
*/
|
|
7
|
+
export async function mitBegrenzung(grenze, aufgaben) {
|
|
8
|
+
if (!Number.isInteger(grenze) || grenze < 1)
|
|
9
|
+
throw new RangeError(`Grenze muss eine ganze Zahl ab 1 sein, war ${grenze}`);
|
|
10
|
+
const ergebnisse = new Array(aufgaben.length);
|
|
11
|
+
let naechste = 0;
|
|
12
|
+
let abgebrochen = false;
|
|
13
|
+
const arbeiter = async () => {
|
|
14
|
+
while (!abgebrochen && naechste < aufgaben.length) {
|
|
15
|
+
const index = naechste++;
|
|
16
|
+
try {
|
|
17
|
+
ergebnisse[index] = await aufgaben[index]();
|
|
18
|
+
}
|
|
19
|
+
catch (fehler) {
|
|
20
|
+
abgebrochen = true;
|
|
21
|
+
throw fehler;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
await Promise.all(Array.from({ length: Math.min(grenze, aufgaben.length) }, arbeiter));
|
|
26
|
+
return ergebnisse;
|
|
27
|
+
}
|