hmgr 0.0.49 → 0.0.50
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.
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
import { mkdir, readFile } from 'node:fs/promises';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
+
import { bundleSchluessel, pfadVereinheitlichen, zielSchluessel } from "../kern/modell.js";
|
|
5
6
|
import { ZUSTAND_FASSUNG, leererZustand, } from "../ports/zustand.js";
|
|
6
7
|
import { atomarSchreiben } from "./atomar-schreiben.js";
|
|
7
8
|
import { ohneBom } from "./datei-text.js";
|
|
8
9
|
/** Der gelesene Text als Zustand. Fehlende Felder bekommen den Wert, der dem Bestand entspricht. */
|
|
9
|
-
function deuten(roh) {
|
|
10
|
+
function deuten(roh, plattform) {
|
|
10
11
|
const daten = JSON.parse(ohneBom(roh));
|
|
11
|
-
|
|
12
|
+
const zustand = {
|
|
12
13
|
// Fehlt das Feld (state.json vor E69), ist es die erste Fassung: alles ohne Bundles.
|
|
13
14
|
// Geschrieben wird danach in der aktuellen Fassung, ein Rückweg ist nicht vorgesehen.
|
|
14
15
|
fassung: typeof daten.fassung === 'number' ? daten.fassung : 1,
|
|
@@ -25,17 +26,48 @@ function deuten(roh) {
|
|
|
25
26
|
// Fehlt das Feld (state.json vor E78), gilt: jeder Harness hat nur sein Standard-Homedir.
|
|
26
27
|
harnessHeime: (daten.harnessHeime ?? []),
|
|
27
28
|
};
|
|
29
|
+
return plattform === 'darwin' ? inNfc(zustand, plattform) : zustand;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Pfade von Arbeitsverzeichnissen und Zielen in NFC (E118). Dubletten, die dabei entstehen, werden
|
|
33
|
+
* zusammengelegt, der erste Eintrag gewinnt: bei den Arbeitsverzeichnissen der erste Pfad, bei
|
|
34
|
+
* Bindungen und Bundle-Installationen der erste Eintrag zum selben Zielschlüssel (der zweite fällt
|
|
35
|
+
* weg, auch mit seinem Zeigerpfad bzw. seiner Skill-Liste). Geschrieben wird erst beim nächsten Speichern.
|
|
36
|
+
*/
|
|
37
|
+
function inNfc(zustand, plattform) {
|
|
38
|
+
const nfc = (pfad) => pfadVereinheitlichen(pfad, plattform);
|
|
39
|
+
const ortNfc = (ort) => (ort.art === 'arbeitsverzeichnis' ? { ...ort, pfad: nfc(ort.pfad) } : ort);
|
|
40
|
+
const ersteJe = (liste, schluessel) => {
|
|
41
|
+
const gesehen = new Set();
|
|
42
|
+
return liste.filter((eintrag) => {
|
|
43
|
+
const s = schluessel(eintrag);
|
|
44
|
+
if (gesehen.has(s))
|
|
45
|
+
return false;
|
|
46
|
+
gesehen.add(s);
|
|
47
|
+
return true;
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
return {
|
|
51
|
+
...zustand,
|
|
52
|
+
arbeitsverzeichnisse: ersteJe(zustand.arbeitsverzeichnisse.map(nfc), (p) => p),
|
|
53
|
+
bindungen: ersteJe(zustand.bindungen.map((b) => ({ ...b, ziel: { ...b.ziel, ort: ortNfc(b.ziel.ort) } })), (b) => zielSchluessel(b.ziel)),
|
|
54
|
+
bundleInstallationen: ersteJe(zustand.bundleInstallationen.map((b) => ({ ...b, ort: ortNfc(b.ort) })), (b) => `${zielSchluessel({ harness: b.harness, ort: b.ort })}|${bundleSchluessel({ name: b.bundle, quelle: b.quelle })}`),
|
|
55
|
+
harnessHeime: zustand.harnessHeime.map((h) => (h.pfad === undefined ? h : { ...h, pfad: nfc(h.pfad) })),
|
|
56
|
+
};
|
|
28
57
|
}
|
|
29
58
|
export class ZustandJson {
|
|
30
59
|
pfad;
|
|
31
|
-
|
|
60
|
+
plattform;
|
|
61
|
+
/** `plattform` steht für `process.platform`; unter darwin bringt das Lesen Pfade in NFC (E118). */
|
|
62
|
+
constructor(pfad, plattform = process.platform) {
|
|
32
63
|
this.pfad = pfad;
|
|
64
|
+
this.plattform = plattform;
|
|
33
65
|
}
|
|
34
66
|
async lesen() {
|
|
35
67
|
const roh = await readFile(this.pfad, 'utf8').catch(() => undefined);
|
|
36
68
|
if (roh === undefined)
|
|
37
69
|
return leererZustand();
|
|
38
|
-
return deuten(roh);
|
|
70
|
+
return deuten(roh, this.plattform);
|
|
39
71
|
}
|
|
40
72
|
/**
|
|
41
73
|
* Derselbe Zustand, synchron gelesen (E78). Nötig für die Auflösung der Homedirs: sie hängt an
|
|
@@ -45,7 +77,7 @@ export class ZustandJson {
|
|
|
45
77
|
*/
|
|
46
78
|
lesenSync() {
|
|
47
79
|
try {
|
|
48
|
-
return deuten(readFileSync(this.pfad, 'utf8'));
|
|
80
|
+
return deuten(readFileSync(this.pfad, 'utf8'), this.plattform);
|
|
49
81
|
}
|
|
50
82
|
catch {
|
|
51
83
|
return leererZustand();
|
package/dist/aenderungen.json
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"fassung": 1,
|
|
3
3
|
"versionen": {
|
|
4
|
+
"0.0.50": [
|
|
5
|
+
"Die Suche in hmgr findet jetzt auch Ordner und Skills mit Umlauten, etwa „döring“. Unter macOS legt hmgr denselben Ordner nicht mehr doppelt an, wenn er einmal aus dem Finder und einmal getippt hinzugefügt wird."
|
|
6
|
+
],
|
|
4
7
|
"0.0.49": [
|
|
5
8
|
"MCP-Server in Projektordnern mit Umlauten im Namen (etwa „Döring“) erscheinen jetzt in hmgr. Bisher fehlten sie dort, obwohl Claude Code sie benutzte. Dasselbe gilt für Plugins in solchen Ordnern."
|
|
6
9
|
],
|
package/dist/cli/main.js
CHANGED
|
@@ -6,7 +6,7 @@ import { homedir } from 'node:os';
|
|
|
6
6
|
import { pathToFileURL } from 'node:url';
|
|
7
7
|
import { checkoutGruppen, quellenAnzeigeName, sammelZeile, sopsGrundText, sopsZeile, verlaufZeitpunkt, } from "./verlauf-anzeige.js";
|
|
8
8
|
import { Anwendungsfaelle, pluginWeltText, } from "../kern/anwendungsfaelle.js";
|
|
9
|
-
import { AbhaengigkeitFehlt, BundleDateiFehler, BundleMehrdeutig, BundleMitgliederFehlen, BundleNamenskonflikte, BundleNichtInstalliert, BundleUnbekannt, EinschraenkungOhneZeiger, HarnessInaktiv, HarnessNichtVorhanden, HarnessTypUnbekannt, HeimAdresseUngueltig, HeimBereitsVorhanden, HeimFaehigkeitFehlt, HeimNurUnterWindows, ClaudeCliNichtErreichbar, HeimUnbekannt, KeinPassenderRef, LinkAnlegenFehlgeschlagen, McpAbweichenderEintrag, McpEbeneNichtUnterstuetzt, McpFaehigkeitFehlt, McpKatalogFehler, McpNichtInGeteilterDatei, McpNurGeteilterFundort, McpOrtUnterGitWurzel, McpUebernahmeNichtMoeglich, McpUebernahmeUnvollstaendig, McpUnbekannt, NameBelegt, OrtNichtUnterstuetzt, PluginMehrdeutig, PluginUnbekannt, QuelleAufraeumenLokaleAenderungen, QuelleNameBelegt, QuelleUnbekannt, SkillMehrdeutig, SkillOrdnerBereitsVerwaltet, SkillOrdnerFaehigkeitFehlt, SkillOrdnerNichtVerwaltet, SkillOrdnerUngueltig, SkillUnbekannt, ZeigerMehrdeutig, WslBrueckeFehlgeschlagen, ZeigerSchreibenGesperrt, heimAdresseAlsText, heimAdresseZerlegen, wslDistroVonOrt, wslUncZerlegen, pluginSchluessel, quelleName, quelleSchluessel, } from "../kern/modell.js";
|
|
9
|
+
import { AbhaengigkeitFehlt, BundleDateiFehler, BundleMehrdeutig, BundleMitgliederFehlen, BundleNamenskonflikte, BundleNichtInstalliert, BundleUnbekannt, EinschraenkungOhneZeiger, HarnessInaktiv, HarnessNichtVorhanden, HarnessTypUnbekannt, HeimAdresseUngueltig, HeimBereitsVorhanden, HeimFaehigkeitFehlt, HeimNurUnterWindows, ClaudeCliNichtErreichbar, HeimUnbekannt, KeinPassenderRef, LinkAnlegenFehlgeschlagen, McpAbweichenderEintrag, McpEbeneNichtUnterstuetzt, McpFaehigkeitFehlt, McpKatalogFehler, McpNichtInGeteilterDatei, McpNurGeteilterFundort, McpOrtUnterGitWurzel, McpUebernahmeNichtMoeglich, McpUebernahmeUnvollstaendig, McpUnbekannt, NameBelegt, OrtNichtUnterstuetzt, PluginMehrdeutig, PluginUnbekannt, QuelleAufraeumenLokaleAenderungen, QuelleNameBelegt, QuelleUnbekannt, SkillMehrdeutig, SkillOrdnerBereitsVerwaltet, SkillOrdnerFaehigkeitFehlt, SkillOrdnerNichtVerwaltet, SkillOrdnerUngueltig, SkillUnbekannt, ZeigerMehrdeutig, WslBrueckeFehlgeschlagen, ZeigerSchreibenGesperrt, heimAdresseAlsText, heimAdresseZerlegen, wslDistroVonOrt, wslUncZerlegen, pfadVereinheitlichen, pluginSchluessel, quelleName, quelleSchluessel, } from "../kern/modell.js";
|
|
10
10
|
import { Agents } from "../adapter/agents.js";
|
|
11
11
|
import { ClaudeCode, claudeAusfuehrer } from "../adapter/claude-code.js";
|
|
12
12
|
import { Hermes } from "../adapter/hermes.js";
|
|
@@ -37,10 +37,11 @@ export function umgebungLesen(env = process.env) {
|
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
39
|
export function bauen(umgebung, optionen = {}) {
|
|
40
|
-
const zustand = new ZustandJson(path.join(umgebung.hmgrHome, 'state.json'));
|
|
41
40
|
const verlauf = new VerlaufJson(umgebung.hmgrHome);
|
|
42
41
|
const wurzel = path.join(umgebung.hmgrHome, 'checkouts');
|
|
43
42
|
const umgebungPort = optionen.umgebung ?? new ProzessUmgebung();
|
|
43
|
+
// Das Lesen bringt Pfade unter macOS in NFC (E118), darum braucht der Adapter die Plattform.
|
|
44
|
+
const zustand = new ZustandJson(path.join(umgebung.hmgrHome, 'state.json'), umgebungPort.plattform());
|
|
44
45
|
// Homedirs aus dem Zustand (E78): das primäre lässt sich umstellen (F89), dazu kommen
|
|
45
46
|
// zusätzliche in einer WSL-Distro (F87). `wsl:`-Heime fallen außerhalb von Windows heraus.
|
|
46
47
|
const heime = new ZustandHeime(zustand, umgebung.home, umgebungPort.plattform());
|
|
@@ -237,14 +238,15 @@ function unterkommandoPruefen(kommando, schalter) {
|
|
|
237
238
|
/**
|
|
238
239
|
* `--ort` deuten. Ein zusätzliches Homedir (E78, F87) heißt nach seiner Adresse: `--ort wsl:Ubuntu`,
|
|
239
240
|
* auch in der ausgeschriebenen Form `--ort home:wsl:Ubuntu`. Beides ergibt denselben Ort, damit
|
|
240
|
-
* niemand raten muss, ob das `home:` davor gehört.
|
|
241
|
+
* niemand raten muss, ob das `home:` davor gehört. Ein `dir:`-Pfad kommt unter macOS in NFC (E118),
|
|
242
|
+
* damit er mit den gemerkten Arbeitsverzeichnissen übereinstimmt.
|
|
241
243
|
*/
|
|
242
|
-
function ortLesen(text) {
|
|
244
|
+
function ortLesen(text, plattform) {
|
|
243
245
|
const roh = text ?? 'home';
|
|
244
246
|
if (roh === 'home')
|
|
245
247
|
return { art: 'home' };
|
|
246
248
|
if (roh.startsWith('dir:'))
|
|
247
|
-
return { art: 'arbeitsverzeichnis', pfad: path.resolve(roh.slice(4)) };
|
|
249
|
+
return { art: 'arbeitsverzeichnis', pfad: pfadVereinheitlichen(path.resolve(roh.slice(4)), plattform) };
|
|
248
250
|
if (roh.startsWith('profil:'))
|
|
249
251
|
return { art: 'profil', name: roh.slice(7) };
|
|
250
252
|
const heim = heimAdresseZerlegen(roh.startsWith('home:') ? roh.slice(5) : roh);
|
|
@@ -479,7 +481,7 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
|
|
|
479
481
|
if (skill === undefined)
|
|
480
482
|
throw new Error(`${kommando} braucht einen Skill-Namen, etwa hmgr ${kommando} <skill>. ` +
|
|
481
483
|
'hmgr status zeigt die verlinkten Skills, hmgr source add <url|pfad> die Skills einer Quelle.');
|
|
482
|
-
const ziel = { harness: werte.get('harness') ?? 'claude-code', ort: ortLesen(werte.get('ort')) };
|
|
484
|
+
const ziel = { harness: werte.get('harness') ?? 'claude-code', ort: ortLesen(werte.get('ort'), ports.umgebung.plattform()) };
|
|
483
485
|
const lokal = flaggen.has('local') || flaggen.has('lokal');
|
|
484
486
|
if (ziel.ort.art === 'arbeitsverzeichnis') {
|
|
485
487
|
// Verzeichnis merken und binden, damit status es wiederfindet und der Zeiger bekannt ist (E21).
|
|
@@ -520,7 +522,7 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
|
|
|
520
522
|
if (kommando === 'adopt') {
|
|
521
523
|
const { rest, werte, flaggen } = schalterLesen(argv.slice(1), 'adopt');
|
|
522
524
|
restPruefen(rest, 1, 'adopt');
|
|
523
|
-
const ziel = { harness: werte.get('harness') ?? 'claude-code', ort: ortLesen(werte.get('ort')) };
|
|
525
|
+
const ziel = { harness: werte.get('harness') ?? 'claude-code', ort: ortLesen(werte.get('ort'), ports.umgebung.plattform()) };
|
|
524
526
|
const probelauf = flaggen.has('probelauf');
|
|
525
527
|
const name = rest[0];
|
|
526
528
|
if (ziel.ort.art === 'arbeitsverzeichnis' && !probelauf) {
|
|
@@ -586,7 +588,7 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
|
|
|
586
588
|
const name = rest[1];
|
|
587
589
|
if (name === undefined)
|
|
588
590
|
throw new Error(`plugin ${unterkommando} braucht einen Plugin-Namen. hmgr plugin list zeigt die Plugins der bekannten Quellen.`);
|
|
589
|
-
const ziel = { harness: werte.get('harness') ?? 'claude-code', ort: ortLesen(werte.get('ort')) };
|
|
591
|
+
const ziel = { harness: werte.get('harness') ?? 'claude-code', ort: ortLesen(werte.get('ort'), ports.umgebung.plattform()) };
|
|
590
592
|
const lokal = flaggen.has('local') || flaggen.has('lokal');
|
|
591
593
|
if (ziel.ort.art === 'arbeitsverzeichnis') {
|
|
592
594
|
const composer = werte.get('composer');
|
|
@@ -654,7 +656,7 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
|
|
|
654
656
|
const name = rest[1];
|
|
655
657
|
if (name === undefined && unterkommando !== 'sync')
|
|
656
658
|
throw new Error(`bundle ${unterkommando} braucht einen Bundle-Namen. hmgr bundle list zeigt die Bundles der bekannten Quellen.`);
|
|
657
|
-
const ziel = { harness: werte.get('harness') ?? 'claude-code', ort: ortLesen(werte.get('ort')) };
|
|
659
|
+
const ziel = { harness: werte.get('harness') ?? 'claude-code', ort: ortLesen(werte.get('ort'), ports.umgebung.plattform()) };
|
|
658
660
|
if (ziel.ort.art === 'arbeitsverzeichnis') {
|
|
659
661
|
// Wie bei link: Verzeichnis merken und binden, damit status es wiederfindet (E21).
|
|
660
662
|
const composer = werte.get('composer');
|
|
@@ -742,7 +744,7 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
|
|
|
742
744
|
const name = rest[1];
|
|
743
745
|
if (name === undefined)
|
|
744
746
|
throw new Error(`mcp ${unterkommando} braucht einen MCP-Namen. hmgr mcp list zeigt die Katalog-Einträge.`);
|
|
745
|
-
const ziel = { harness: werte.get('harness') ?? 'claude-code', ort: ortLesen(werte.get('ort')) };
|
|
747
|
+
const ziel = { harness: werte.get('harness') ?? 'claude-code', ort: ortLesen(werte.get('ort'), ports.umgebung.plattform()) };
|
|
746
748
|
// Übernehmen (E64): der Name muss nicht im Katalog stehen, der Block kommt aus der geteilten Datei.
|
|
747
749
|
if (unterkommando === 'migrate') {
|
|
748
750
|
const ergebnis = await anwendungsfaelle.mcpUebernehmen({ name, ziel });
|
|
@@ -25,6 +25,9 @@
|
|
|
25
25
|
var PLATTFORM = '';
|
|
26
26
|
/** Trenner einer Plattform, wie `process.platform` sie nennt. Rein, nur für die Anzeige. */
|
|
27
27
|
function plattformTrenner(plattform) { return plattform === 'win32' ? '\\' : '/'; }
|
|
28
|
+
/** Vergleichsform für alle Suchfelder (E118): NFC und kleingeschrieben. Pfade aus Finder oder
|
|
29
|
+
Nextcloud kommen oft in NFD (Umlaut als Buchstabe plus Punkte), getippt wird NFC. */
|
|
30
|
+
function suchform(text) { return String(text).normalize('NFC').toLowerCase(); }
|
|
28
31
|
/**
|
|
29
32
|
* Kürzt einen absoluten Pfad auf ~, wenn er mit dem Home-Verzeichnis beginnt. Grenze ist einer
|
|
30
33
|
* der beiden Trenner (E68): unter Windows steht dort „\", und der Rest des Pfads bleibt wörtlich
|
|
@@ -1651,17 +1654,17 @@
|
|
|
1651
1654
|
Suche nach „~/.claude" nichts, weil im rohen Pfad der volle Home-Pfad steht. In
|
|
1652
1655
|
Kleinschreibung, leerer Suchbegriff heißt „alles". */
|
|
1653
1656
|
function zielKartePasstZuSuche(z) {
|
|
1654
|
-
var s = zielsuche.trim()
|
|
1657
|
+
var s = suchform(zielsuche.trim());
|
|
1655
1658
|
if (!s) return true;
|
|
1656
|
-
var text = (zielTitel(z) + ' ' + (z.verzeichnis || '') + ' ' + pfadKurz(z.verzeichnis || ''))
|
|
1659
|
+
var text = suchform(zielTitel(z) + ' ' + (z.verzeichnis || '') + ' ' + pfadKurz(z.verzeichnis || ''));
|
|
1657
1660
|
return text.indexOf(s) > -1;
|
|
1658
1661
|
}
|
|
1659
1662
|
/** Ob eine Verzeichnis-Karte zum aktuellen Suchbegriff passt (E84 Teil 2): voller Pfad oder
|
|
1660
1663
|
gekürzte Schreibweise (pfadKurz). */
|
|
1661
1664
|
function verzKartePasstZuSuche(pfad) {
|
|
1662
|
-
var s = zielsuche.trim()
|
|
1665
|
+
var s = suchform(zielsuche.trim());
|
|
1663
1666
|
if (!s) return true;
|
|
1664
|
-
return pfad
|
|
1667
|
+
return suchform(pfad).indexOf(s) > -1 || suchform(pfadKurz(pfad)).indexOf(s) > -1;
|
|
1665
1668
|
}
|
|
1666
1669
|
|
|
1667
1670
|
function baueZiele() {
|
|
@@ -2334,11 +2337,11 @@
|
|
|
2334
2337
|
}
|
|
2335
2338
|
|
|
2336
2339
|
function filtereSkills() {
|
|
2337
|
-
var suche = $('suchfeld').value.trim()
|
|
2340
|
+
var suche = suchform($('suchfeld').value.trim());
|
|
2338
2341
|
var sichtbar = 0;
|
|
2339
2342
|
document.querySelectorAll('#katalog .zeile').forEach(function (li) {
|
|
2340
2343
|
var skill = SKILLS[+li.dataset.index];
|
|
2341
|
-
var passtSuche = !suche || skill.name
|
|
2344
|
+
var passtSuche = !suche || suchform(skill.name).indexOf(suche) > -1 || suchform(skill.pfad).indexOf(suche) > -1;
|
|
2342
2345
|
var passtFilter = quellenFilter === 'alle' || skill.quelleSchluessel === quellenFilter;
|
|
2343
2346
|
var an = passtSuche && passtFilter;
|
|
2344
2347
|
li.hidden = !an;
|
|
@@ -2464,15 +2467,15 @@
|
|
|
2464
2467
|
$('dsk-bilanz').textContent = zahlwort(n, 'ausgewählt', 'ausgewählt');
|
|
2465
2468
|
}
|
|
2466
2469
|
function filtereDskListe() {
|
|
2467
|
-
var suche = $('dsk-suche').value.trim()
|
|
2470
|
+
var suche = suchform($('dsk-suche').value.trim());
|
|
2468
2471
|
document.querySelectorAll('#dsk-liste .wahlzeile').forEach(function (label) {
|
|
2469
2472
|
var skill = SKILLS[+label.dataset.index];
|
|
2470
|
-
label.hidden = !!suche && skill.name
|
|
2473
|
+
label.hidden = !!suche && suchform(skill.name).indexOf(suche) === -1;
|
|
2471
2474
|
});
|
|
2472
2475
|
// Die Suche gilt auch für Bundles (E69): sonst bliebe die Sektion bei jeder Eingabe voll stehen.
|
|
2473
2476
|
document.querySelectorAll('#dsk-bundles .wahlzeile').forEach(function (label) {
|
|
2474
2477
|
var bundle = BUNDLES[+label.dataset.index];
|
|
2475
|
-
label.hidden = !!suche && bundle.name
|
|
2478
|
+
label.hidden = !!suche && suchform(bundle.name).indexOf(suche) === -1;
|
|
2476
2479
|
});
|
|
2477
2480
|
}
|
|
2478
2481
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Anwendungsfälle. Pfade werden hier nur als Zeichenketten normalisiert, gelesen wird über die Ports.
|
|
2
2
|
import path from 'node:path';
|
|
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, wslDistroVonOrt, wslUncBilden, wslUncZerlegen, marketplaceUrl, pluginSchluessel, pluginSchluesselZerlegen, quelleAlsText, quelleMitNamen, quelleName, quelleNameAbleiten, quelleNameFrei, quelleSchluessel, zielSchluessel, } from "./modell.js";
|
|
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, wslDistroVonOrt, wslUncBilden, wslUncZerlegen, marketplaceUrl, pfadVereinheitlichen, pluginSchluessel, pluginSchluesselZerlegen, quelleAlsText, quelleMitNamen, quelleName, quelleNameAbleiten, quelleNameFrei, quelleSchluessel, zielSchluessel, } from "./modell.js";
|
|
4
4
|
import { mitBegrenzung } from "./begrenzung.js";
|
|
5
5
|
import { passenderRef } from "./version.js";
|
|
6
6
|
import { kannIstRegistriert, kannMcp, kannPlugins, kannProfile, kannSkillOrdner, kannZurueckbauen, kannZusaetzlicheHeime, } from "../ports/harness.js";
|
|
@@ -199,6 +199,10 @@ export class Anwendungsfaelle {
|
|
|
199
199
|
static heimeAufraeumen(zustand) {
|
|
200
200
|
zustand.harnessHeime = zustand.harnessHeime.filter((h) => (h.pfad !== undefined && h.pfad.length > 0) || h.zusaetzliche.length > 0);
|
|
201
201
|
}
|
|
202
|
+
/** Verzeichnispfad in der gemerkten Schreibweise (E118): unter macOS NFC, sonst unverändert. */
|
|
203
|
+
pfadNfc(pfad) {
|
|
204
|
+
return pfadVereinheitlichen(pfad, this.p.umgebung.plattform());
|
|
205
|
+
}
|
|
202
206
|
/**
|
|
203
207
|
* Primäres Homedir umstellen (E78, F89): hmgr merkt sich den neuen Pfad und zeigt ab dann ihn.
|
|
204
208
|
* Was am alten Ort liegt, bleibt unberührt liegen — dasselbe Verhalten wie beim Deaktivieren
|
|
@@ -207,7 +211,7 @@ export class Anwendungsfaelle {
|
|
|
207
211
|
*/
|
|
208
212
|
async harnessHeimSetzen(harnessName, pfad) {
|
|
209
213
|
this.harness(harnessName); // wirft HarnessTypUnbekannt bei unbekanntem Namen
|
|
210
|
-
const aufgeloest = path.resolve(pfad);
|
|
214
|
+
const aufgeloest = this.pfadNfc(path.resolve(pfad));
|
|
211
215
|
const zustand = await this.p.zustand.lesen();
|
|
212
216
|
Anwendungsfaelle.heimEintrag(zustand, harnessName).pfad = aufgeloest;
|
|
213
217
|
await this.p.zustand.schreiben(zustand);
|
|
@@ -1330,7 +1334,7 @@ export class Anwendungsfaelle {
|
|
|
1330
1334
|
* es sei denn, der Nutzer nennt eine composer.json. Nie Zufall.
|
|
1331
1335
|
*/
|
|
1332
1336
|
async arbeitsverzeichnisHinzufuegen(pfad, composerPfad) {
|
|
1333
|
-
const verzeichnis = path.resolve(pfad);
|
|
1337
|
+
const verzeichnis = this.pfadNfc(path.resolve(pfad));
|
|
1334
1338
|
let zeigerPfad;
|
|
1335
1339
|
let hinweis;
|
|
1336
1340
|
// Eine schon gemerkte Bindung gewinnt, sonst würde ein zweiter Aufruf erneut mehrdeutig werden.
|
|
@@ -1375,7 +1379,7 @@ export class Anwendungsfaelle {
|
|
|
1375
1379
|
}
|
|
1376
1380
|
/** Arbeitsverzeichnis vergessen: Verzeichnis und Bindungen weg, die Links bleiben liegen (E26). */
|
|
1377
1381
|
async arbeitsverzeichnisVergessen(pfad) {
|
|
1378
|
-
const verzeichnis = path.resolve(pfad);
|
|
1382
|
+
const verzeichnis = this.pfadNfc(path.resolve(pfad));
|
|
1379
1383
|
const zustand = await this.p.zustand.lesen();
|
|
1380
1384
|
zustand.arbeitsverzeichnisse = zustand.arbeitsverzeichnisse.filter((p) => p !== verzeichnis);
|
|
1381
1385
|
zustand.bindungen = zustand.bindungen.filter((b) => !(b.ziel.ort.art === 'arbeitsverzeichnis' && b.ziel.ort.pfad === verzeichnis));
|
|
@@ -1959,7 +1963,7 @@ export class Anwendungsfaelle {
|
|
|
1959
1963
|
* fehlende Links legen, Abweichungen melden. Ohne Zeiger oder ohne Harness passiert nichts.
|
|
1960
1964
|
*/
|
|
1961
1965
|
async abgleich(pfad) {
|
|
1962
|
-
const verzeichnis = path.resolve(pfad ?? process.cwd());
|
|
1966
|
+
const verzeichnis = this.pfadNfc(path.resolve(pfad ?? process.cwd()));
|
|
1963
1967
|
const ergebnis = { gelegt: [], vorhanden: [], abweichend: [], fehler: [], hinweise: [] };
|
|
1964
1968
|
const zustand = await this.p.zustand.lesen();
|
|
1965
1969
|
// Zeiger nach E26: erst die gemerkte Bindung, dann die Suche im Verzeichnis.
|
package/dist/kern/modell.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
// Begriffe aus CONTEXT.md. Nur Werte und Regeln, keine Pfade zu Dateien außerhalb des Modells.
|
|
2
2
|
import { ortSchluessel, urlOrt } from "./quelle-ort.js";
|
|
3
|
+
/**
|
|
4
|
+
* Pfad eines Arbeitsverzeichnisses oder Ziels in der Schreibweise, die hmgr merkt (E118): unter
|
|
5
|
+
* macOS (APFS) sind NFC und NFD desselben Ordnernamens derselbe Ordner, `realpath` gibt aber die
|
|
6
|
+
* übergebene Schreibweise zurück; also immer NFC. Anderswo sind beide Schreibweisen verschiedene
|
|
7
|
+
* Namen, der Pfad bleibt, wie er ist. `plattform` ist `process.platform`, im Kern aus der Umgebung.
|
|
8
|
+
*/
|
|
9
|
+
export function pfadVereinheitlichen(pfad, plattform) {
|
|
10
|
+
return plattform === 'darwin' ? pfad.normalize('NFC') : pfad;
|
|
11
|
+
}
|
|
3
12
|
/**
|
|
4
13
|
* Identität eines Bundles (E69): Quelle der Definition plus Name. Zwei Quellen dürfen denselben
|
|
5
14
|
* Bundle-Namen führen, mehrdeutig wird es erst beim Suchen, wie bei Skills (E12).
|