hmgr 0.0.2 → 0.0.3
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/README.md +2 -31
- package/dist/cli/hilfe.js +254 -0
- package/dist/cli/main.js +74 -46
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,34 +26,5 @@ npm run build
|
|
|
26
26
|
|
|
27
27
|
## Kommandos
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
source list Quellen zeigen
|
|
32
|
-
dir add <pfad> Arbeitsverzeichnis merken und an seinen Zeiger binden
|
|
33
|
-
dir forget <pfad> Arbeitsverzeichnis und Bindung vergessen, Links bleiben
|
|
34
|
-
dir list Arbeitsverzeichnisse mit ihrer Bindung zeigen
|
|
35
|
-
link <skill> Skill in ein Ziel verlinken
|
|
36
|
-
unlink <skill> Link entfernen
|
|
37
|
-
adopt [name] Fremde Links im Ziel durch eigene hmgr-Links ersetzen
|
|
38
|
-
plugin add <name> Plugin in ein Ziel legen (installieren oder Skills verlinken)
|
|
39
|
-
plugin remove <name> Plugin aus einem Ziel entfernen
|
|
40
|
-
plugin list Plugins der Marketplaces aller Quellen
|
|
41
|
-
sync [pfad] Ziel auf den Stand seines Zeigers bringen
|
|
42
|
-
update Alle Checkouts aktualisieren
|
|
43
|
-
status Ist-Zustand der Ziele
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Optionen:
|
|
47
|
-
|
|
48
|
-
```
|
|
49
|
-
--harness <name> claude-code, hermes oder agents, Standard claude-code
|
|
50
|
-
--ort home|dir:<pfad>|profil:<name> Standard home
|
|
51
|
-
--quelle <teilstring> Quelle bei mehrdeutigem Skill-Namen
|
|
52
|
-
--version <spanne> Versionseinschränkung nach Composer-Regeln, nur mit Zeiger
|
|
53
|
-
--composer <pfad> composer.json wählen, wenn mehrere in Frage kommen
|
|
54
|
-
--local Link nur ins Ziel legen, nicht in den Zeiger
|
|
55
|
-
--ersetzen fremden Eintrag am Ziel ersetzen
|
|
56
|
-
--probelauf bei adopt nur melden, nichts schreiben
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
`hmgr help` zeigt dieselbe Übersicht.
|
|
29
|
+
`hmgr --help` zeigt die Kommandos, `hmgr help <kommando>` Schalter, Beispiele
|
|
30
|
+
und Zusammenhänge.
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
// Hilfetexte der CLI. Nur Zeichenketten, keine Ausgabe: die macht main.ts (Terminal-I/O).
|
|
2
|
+
/** Ebene 1: Orientierung, je Kommando ein Einzeiler, Verweis auf die Kommando-Hilfe. */
|
|
3
|
+
export const HILFE = `hmgr verlinkt Skills aus Git-Quellen in die Verzeichnisse, aus denen ein Harness sie lädt:
|
|
4
|
+
claude-code, hermes oder agents. Welche Skills und Plugins zu einem Arbeitsverzeichnis gehören,
|
|
5
|
+
steht in seinem Zeiger, dem extra-Abschnitt einer composer.json.
|
|
6
|
+
|
|
7
|
+
Arbeitszyklus: Skill in seiner Quelle ändern, committen und pushen, dann hmgr update. Ein frisch
|
|
8
|
+
geklontes Vorhaben holt seinen Stand mit hmgr sync.
|
|
9
|
+
|
|
10
|
+
hmgr <kommando> [schalter]
|
|
11
|
+
|
|
12
|
+
source add <url|pfad> Quelle hinzufügen (URL wird geklont, Pfad bleibt Arbeitskopie)
|
|
13
|
+
source list Quellen zeigen
|
|
14
|
+
dir add <pfad> Arbeitsverzeichnis merken und an seinen Zeiger binden
|
|
15
|
+
dir forget <pfad> Arbeitsverzeichnis und Bindung vergessen, Links bleiben
|
|
16
|
+
dir list Arbeitsverzeichnisse mit ihrer Bindung zeigen
|
|
17
|
+
link <skill> Skill in ein Ziel verlinken
|
|
18
|
+
unlink <skill> Link entfernen
|
|
19
|
+
adopt [name] Fremde Links im Ziel durch eigene hmgr-Links ersetzen
|
|
20
|
+
plugin add <name> Plugin in ein Ziel legen (installieren oder Skills verlinken)
|
|
21
|
+
plugin remove <name> Plugin aus einem Ziel entfernen
|
|
22
|
+
plugin list Plugins der Marketplaces aller Quellen
|
|
23
|
+
sync [pfad] Ziel auf den Stand seines Zeigers bringen
|
|
24
|
+
update Alle Checkouts aktualisieren
|
|
25
|
+
status Ist-Zustand der Ziele
|
|
26
|
+
|
|
27
|
+
hmgr help <kommando> zeigt Schalter, Beispiele und Zusammenhänge.`;
|
|
28
|
+
const SOURCE = `hmgr source add <url|pfad>
|
|
29
|
+
hmgr source list
|
|
30
|
+
|
|
31
|
+
Eine Quelle ist ein Git-Repo mit Skills. source add prüft, ob sie erreichbar ist, liest ihre Skills
|
|
32
|
+
und ihren Marketplace und merkt sie unter ~/.hmgr. Erst danach kennt hmgr die Skill-Namen, mit
|
|
33
|
+
denen link und plugin add arbeiten. Eine URL wird geklont, ein Pfad bleibt die Arbeitskopie, die
|
|
34
|
+
dort schon liegt, und wird von hmgr nicht verändert.
|
|
35
|
+
|
|
36
|
+
Schalter: keine.
|
|
37
|
+
|
|
38
|
+
Beispiele:
|
|
39
|
+
hmgr source add https://github.com/tim/skills.git
|
|
40
|
+
hmgr source add ~/.skills/tim-skills
|
|
41
|
+
hmgr source list
|
|
42
|
+
|
|
43
|
+
Häufige Fälle:
|
|
44
|
+
„Skill … liegt in keiner Quelle": die Quelle fehlt, erst source add, dann link.
|
|
45
|
+
Neue Commits einer bekannten Quelle holt hmgr update, nicht source add.
|
|
46
|
+
|
|
47
|
+
Siehe auch: hmgr help link, hmgr help plugin, hmgr help update`;
|
|
48
|
+
const DIR = `hmgr dir add <pfad> [--composer <pfad>]
|
|
49
|
+
hmgr dir forget <pfad>
|
|
50
|
+
hmgr dir list
|
|
51
|
+
|
|
52
|
+
Ein Arbeitsverzeichnis ist ein Verzeichnis, in dem ein Harness gestartet wird. dir add merkt es und
|
|
53
|
+
bindet es an seinen Zeiger, also an die composer.json, in deren extra-Abschnitt Quellen, Skills und
|
|
54
|
+
Plugins des Vorhabens stehen. Ohne Zeiger bleibt das Verzeichnis gemerkt und jeder Link dort lokal
|
|
55
|
+
(E26). dir forget löst Bindung und Eintrag, die gelegten Links bleiben liegen.
|
|
56
|
+
|
|
57
|
+
Schalter:
|
|
58
|
+
--composer <pfad> composer.json wählen, wenn unter dem Verzeichnis mehrere in Frage kommen
|
|
59
|
+
|
|
60
|
+
Beispiele:
|
|
61
|
+
hmgr dir add ~/Code/site
|
|
62
|
+
hmgr dir add ~/Code/site --composer ~/Code/site/app/composer.json
|
|
63
|
+
hmgr dir list
|
|
64
|
+
|
|
65
|
+
Häufige Fälle:
|
|
66
|
+
„Mehrere composer.json unter …": eine mit --composer nennen, hmgr rät nicht.
|
|
67
|
+
link --ort dir:<pfad> merkt das Verzeichnis von selbst. dir add braucht es vorher nur, wenn die
|
|
68
|
+
composer.json mehrdeutig ist.
|
|
69
|
+
|
|
70
|
+
Siehe auch: hmgr help link, hmgr help sync`;
|
|
71
|
+
const LINK = `hmgr link <skill> [schalter]
|
|
72
|
+
|
|
73
|
+
Legt im Ziel einen Symlink auf den Skill an, der aus einer bekannten Quelle stammt, und trägt ihn
|
|
74
|
+
in den Zeiger des Ziels ein, damit hmgr sync ihn anderswo reproduzieren kann. Einen Zeiger gibt es
|
|
75
|
+
nur für ein Arbeitsverzeichnis mit composer.json, an Home und Profil bleibt jeder Link lokal.
|
|
76
|
+
|
|
77
|
+
Schalter:
|
|
78
|
+
--harness <name> claude-code, hermes oder agents, Standard claude-code
|
|
79
|
+
--ort <ort> home, dir:<pfad> oder profil:<name>, Standard home. profil kennt nur hermes
|
|
80
|
+
--quelle <teil> Teilstring der Quelle, wenn der Skill-Name in mehreren Quellen vorkommt
|
|
81
|
+
--version <spanne> Versionseinschränkung nach Composer-Regeln (etwa ^1.2) oder ein Tag- oder
|
|
82
|
+
Branchname. Nur mit Zeiger, also dir:<pfad> ohne --local (E33)
|
|
83
|
+
--composer <pfad> composer.json des Arbeitsverzeichnisses, wenn mehrere in Frage kommen
|
|
84
|
+
--local Link nur ins Ziel legen, nicht in den Zeiger
|
|
85
|
+
--ersetzen einen fremden Eintrag gleichen Namens am Ziel ersetzen
|
|
86
|
+
|
|
87
|
+
Beispiele:
|
|
88
|
+
hmgr link netzwerk
|
|
89
|
+
hmgr link netzwerk --harness hermes --ort profil:researcher
|
|
90
|
+
hmgr link tq-schema --ort dir:. --version ^2.0
|
|
91
|
+
|
|
92
|
+
Häufige Fälle:
|
|
93
|
+
„liegt in mehreren Quellen": mit --quelle <teilstring der URL oder des Pfads> entscheiden.
|
|
94
|
+
„liegt bereits ein fremder Eintrag": --ersetzen setzen oder vorher hmgr adopt <name>.
|
|
95
|
+
„gibt es keinen Zeiger": --version braucht ein Arbeitsverzeichnis mit composer.json und kein
|
|
96
|
+
--local. Ohne Zeiger den Link ohne --version legen.
|
|
97
|
+
|
|
98
|
+
Siehe auch: hmgr help unlink, hmgr help sync, hmgr help adopt`;
|
|
99
|
+
const UNLINK = `hmgr unlink <skill> [schalter]
|
|
100
|
+
|
|
101
|
+
Entfernt den Link aus dem Ziel und, wenn das Ziel an einen Zeiger gebunden ist, den Skill aus dem
|
|
102
|
+
Zeiger. Der Checkout unter ~/.hmgr bleibt liegen, Links anderer Ziele bleiben unberührt.
|
|
103
|
+
|
|
104
|
+
Schalter:
|
|
105
|
+
--harness <name> claude-code, hermes oder agents, Standard claude-code
|
|
106
|
+
--ort <ort> home, dir:<pfad> oder profil:<name>, Standard home. profil kennt nur hermes
|
|
107
|
+
--composer <pfad> composer.json des Arbeitsverzeichnisses, wenn mehrere in Frage kommen
|
|
108
|
+
--local nur den Link entfernen, den Eintrag im Zeiger stehen lassen
|
|
109
|
+
|
|
110
|
+
Beispiele:
|
|
111
|
+
hmgr unlink netzwerk
|
|
112
|
+
hmgr unlink netzwerk --ort dir:. --local
|
|
113
|
+
|
|
114
|
+
Häufige Fälle:
|
|
115
|
+
Bleibt der Skill im Zeiger stehen, legt hmgr sync ihn wieder an. Ohne --local räumt unlink
|
|
116
|
+
beides ab.
|
|
117
|
+
|
|
118
|
+
Siehe auch: hmgr help link, hmgr help sync`;
|
|
119
|
+
const ADOPT = `hmgr adopt [name] [schalter]
|
|
120
|
+
|
|
121
|
+
Ersetzt fremde Symlinks im Ziel durch eigene hmgr-Links: hmgr liest, aus welcher Git-Arbeitskopie
|
|
122
|
+
ein Link stammt, nimmt deren remote.origin.url als Quelle, legt einen Checkout am selben Branch an
|
|
123
|
+
und verlinkt den Skill daraus. Ohne Namen laufen alle fremden Einträge des Ziels durch, mit Namen
|
|
124
|
+
nur dieser eine. Was sich nicht auflösen lässt, bleibt liegen und wird mit Grund gemeldet.
|
|
125
|
+
|
|
126
|
+
Schalter:
|
|
127
|
+
--harness <name> claude-code, hermes oder agents, Standard claude-code
|
|
128
|
+
--ort <ort> home, dir:<pfad> oder profil:<name>, Standard home. profil kennt nur hermes
|
|
129
|
+
--composer <pfad> composer.json des Arbeitsverzeichnisses, wenn mehrere in Frage kommen
|
|
130
|
+
--local Übernahme nicht in den Zeiger schreiben
|
|
131
|
+
--probelauf nur melden, nichts schreiben
|
|
132
|
+
|
|
133
|
+
Beispiele:
|
|
134
|
+
hmgr adopt --probelauf
|
|
135
|
+
hmgr adopt netzwerk --ort dir:.
|
|
136
|
+
|
|
137
|
+
Häufige Fälle:
|
|
138
|
+
„kein Symlink": der Eintrag ist ein echtes Verzeichnis, hmgr fasst ihn nicht an.
|
|
139
|
+
„liegt in keiner Git-Arbeitskopie" oder „ohne remote.origin.url": die Quelle ist nicht
|
|
140
|
+
bestimmbar. Mit hmgr source add <url> eine Quelle nennen und mit hmgr link --ersetzen verlinken.
|
|
141
|
+
„ohne Branch (detached HEAD)": in der Arbeitskopie einen Branch auschecken, dann erneut adopt.
|
|
142
|
+
„Pfad ist in der Quelle kein Skill": im Repo liegt an der Stelle keine SKILL.md.
|
|
143
|
+
|
|
144
|
+
Siehe auch: hmgr help link, hmgr help status`;
|
|
145
|
+
const PLUGIN = `hmgr plugin add <name> [schalter]
|
|
146
|
+
hmgr plugin remove <name> [schalter]
|
|
147
|
+
hmgr plugin list
|
|
148
|
+
|
|
149
|
+
Ein Plugin ist ein Bündel aus einem Marketplace, also aus einer Quelle mit
|
|
150
|
+
.claude-plugin/marketplace.json. Hat der Harness die Plugin-Fähigkeit (claude-code), lässt hmgr das
|
|
151
|
+
Plugin von dessen CLI installieren, sonst verlinkt es die flache Skill-Liste des Plugins samt
|
|
152
|
+
seinen Abhängigkeiten. In den Zeiger kommt das Plugin, nicht seine Einzelskills. plugin list zeigt
|
|
153
|
+
die Marketplaces aller bekannten Quellen mit ihren Plugins.
|
|
154
|
+
|
|
155
|
+
Schalter (add und remove):
|
|
156
|
+
--harness <name> claude-code, hermes oder agents, Standard claude-code
|
|
157
|
+
--ort <ort> home, dir:<pfad> oder profil:<name>, Standard home. profil kennt nur hermes
|
|
158
|
+
--composer <pfad> composer.json des Arbeitsverzeichnisses, wenn mehrere in Frage kommen
|
|
159
|
+
--local Plugin nicht in den Zeiger schreiben
|
|
160
|
+
--quelle <teil> nur bei add: Quelle eingrenzen, wenn der Name in mehreren Marketplaces steht
|
|
161
|
+
|
|
162
|
+
Beispiele:
|
|
163
|
+
hmgr plugin list
|
|
164
|
+
hmgr plugin add superpowers --ort dir:.
|
|
165
|
+
hmgr plugin remove superpowers
|
|
166
|
+
|
|
167
|
+
Häufige Fälle:
|
|
168
|
+
„Keine Quelle mit Marketplace": erst hmgr source add <url> der Quelle mit der marketplace.json.
|
|
169
|
+
„liegt in keinem Marketplace der bekannten Quellen": Namen mit hmgr plugin list prüfen.
|
|
170
|
+
„liegt in mehreren Marketplaces": mit --quelle <teilstring> entscheiden.
|
|
171
|
+
„braucht …, das im selben Marketplace nicht steht": die Abhängigkeit fehlt im Marketplace, das
|
|
172
|
+
kann nur die Quelle beheben.
|
|
173
|
+
|
|
174
|
+
Siehe auch: hmgr help source, hmgr help sync`;
|
|
175
|
+
const SYNC = `hmgr sync [pfad]
|
|
176
|
+
|
|
177
|
+
Bringt ein Arbeitsverzeichnis auf den Stand seines Zeigers: fehlende Quellen übernehmen, fehlende
|
|
178
|
+
Links legen, Links auf einen anderen Ref umlegen, Plugins herstellen. Ohne Pfad gilt das aktuelle
|
|
179
|
+
Verzeichnis. Das ist der Befehl nach einem frischen Clone eines Vorhabens und nach jeder Änderung
|
|
180
|
+
am Zeiger. Eigene Links, die im Zeiger fehlen, werden als abweichend gemeldet und nicht entfernt,
|
|
181
|
+
fremde Einträge bleiben unberührt.
|
|
182
|
+
|
|
183
|
+
Schalter: keine.
|
|
184
|
+
|
|
185
|
+
Beispiele:
|
|
186
|
+
hmgr sync
|
|
187
|
+
hmgr sync ~/Code/site
|
|
188
|
+
|
|
189
|
+
Häufige Fälle:
|
|
190
|
+
„Kein Zeiger unter …, nichts zu tun": im Verzeichnis liegt keine composer.json. Mit
|
|
191
|
+
hmgr dir add <pfad> --composer <pfad> eine nennen.
|
|
192
|
+
„steht nicht im Zeiger": den Link mit hmgr link <skill> --ort dir:<pfad> eintragen oder mit
|
|
193
|
+
hmgr unlink <skill> --ort dir:<pfad> --local entfernen.
|
|
194
|
+
„Kein Harness auf diesem Rechner": weder ~/.claude noch ~/.hermes noch ~/.agents ist angelegt.
|
|
195
|
+
|
|
196
|
+
Siehe auch: hmgr help dir, hmgr help link, hmgr help update`;
|
|
197
|
+
const UPDATE = `hmgr update
|
|
198
|
+
|
|
199
|
+
Holt für jeden Checkout unter ~/.hmgr den neuesten Stand seines Refs und zieht bei Harnesses mit
|
|
200
|
+
Plugin-Fähigkeit deren Plugins nach (E14). Die Links zeigen weiter auf dieselben Pfade und müssen
|
|
201
|
+
nicht erneuert werden. Ein Checkout mit lokaler Änderung wird übersprungen und gemeldet (E15),
|
|
202
|
+
damit nichts verloren geht. Lokale Quellen haben keinen Checkout und bleiben unberührt.
|
|
203
|
+
|
|
204
|
+
So wird eine Änderung an einem Skill überall wirksam: in der Quelle committen und pushen, dann
|
|
205
|
+
hmgr update.
|
|
206
|
+
|
|
207
|
+
Schalter: keine.
|
|
208
|
+
|
|
209
|
+
Beispiel:
|
|
210
|
+
hmgr update
|
|
211
|
+
|
|
212
|
+
Häufige Fälle:
|
|
213
|
+
„übersprungen … lokale Änderung (E15)": im Checkout liegt eine Änderung, die durch einen Link
|
|
214
|
+
hindurch gemacht wurde. Dort committen und pushen, dann erneut hmgr update.
|
|
215
|
+
„Keine Checkouts": es gibt nur lokale Quellen oder noch keinen Link.
|
|
216
|
+
|
|
217
|
+
Siehe auch: hmgr help sync, hmgr help status`;
|
|
218
|
+
const STATUS = `hmgr status
|
|
219
|
+
|
|
220
|
+
Liest den Ist-Zustand vom Dateisystem: je Ziel eines vorhandenen Harness die Einträge mit Quelle
|
|
221
|
+
und Ref, davor die Versionseinschränkung, falls der Zeiger eine nennt. Fremde Einträge und Links
|
|
222
|
+
ohne bekannte Quelle sind eigens gekennzeichnet, dazu kommen die Plugins des Ziels. Am Ende stehen
|
|
223
|
+
die Harnesses, die auf diesem Rechner nicht liegen.
|
|
224
|
+
|
|
225
|
+
Schalter: keine.
|
|
226
|
+
|
|
227
|
+
Beispiel:
|
|
228
|
+
hmgr status
|
|
229
|
+
|
|
230
|
+
Häufige Fälle:
|
|
231
|
+
„fremd": der Eintrag stammt nicht von hmgr. hmgr adopt <name> übernimmt ihn.
|
|
232
|
+
„Link ohne bekannte Quelle": der Link zeigt in einen hmgr-Checkout, dessen Quelle nicht mehr im
|
|
233
|
+
Zustand steht. Mit hmgr source add <url> die Quelle wieder eintragen.
|
|
234
|
+
„Nicht vorhanden": der Harness hat sein Verzeichnis auf diesem Rechner nicht angelegt, hmgr
|
|
235
|
+
überspringt seine Ziele.
|
|
236
|
+
|
|
237
|
+
Siehe auch: hmgr help adopt, hmgr help sync`;
|
|
238
|
+
/** Ebene 2, je Kommandofamilie ein Text. Unterkommandos teilen sich die Hilfe ihrer Familie. */
|
|
239
|
+
const THEMEN = new Map([
|
|
240
|
+
['source', SOURCE],
|
|
241
|
+
['dir', DIR],
|
|
242
|
+
['link', LINK],
|
|
243
|
+
['unlink', UNLINK],
|
|
244
|
+
['adopt', ADOPT],
|
|
245
|
+
['plugin', PLUGIN],
|
|
246
|
+
['sync', SYNC],
|
|
247
|
+
['update', UPDATE],
|
|
248
|
+
['status', STATUS],
|
|
249
|
+
['help', HILFE],
|
|
250
|
+
]);
|
|
251
|
+
/** Hilfetext zu einem Kommando, undefined für ein unbekanntes Thema. */
|
|
252
|
+
export function hilfeText(thema) {
|
|
253
|
+
return THEMEN.get(thema);
|
|
254
|
+
}
|
package/dist/cli/main.js
CHANGED
|
@@ -15,6 +15,7 @@ import { GitQuellen } from "../adapter/git.js";
|
|
|
15
15
|
import { quelleAlsText, quelleAusText } from "../adapter/quelle-text.js";
|
|
16
16
|
import { TerminalRueckfrage } from "../adapter/terminal.js";
|
|
17
17
|
import { ZustandJson } from "../adapter/zustand-json.js";
|
|
18
|
+
import { HILFE, hilfeText } from "./hilfe.js";
|
|
18
19
|
export function umgebungLesen(env = process.env) {
|
|
19
20
|
const home = env.HOME ?? homedir();
|
|
20
21
|
return { home, hmgrHome: env.HMGR_HOME ?? path.join(home, '.hmgr') };
|
|
@@ -35,9 +36,9 @@ export function bauen(umgebung, optionen = {}) {
|
|
|
35
36
|
};
|
|
36
37
|
return { anwendungsfaelle: new Anwendungsfaelle(ports), ports };
|
|
37
38
|
}
|
|
38
|
-
/** Schalter ohne Wert. Alles andere braucht einen. */
|
|
39
|
-
const FLAGGEN = new Set(['ersetzen', 'local', 'lokal', 'probelauf']);
|
|
40
|
-
function schalterLesen(args) {
|
|
39
|
+
/** Schalter ohne Wert. Alles andere braucht einen. `help` steht hier, damit --help nie greift. */
|
|
40
|
+
const FLAGGEN = new Set(['ersetzen', 'local', 'lokal', 'probelauf', 'help']);
|
|
41
|
+
function schalterLesen(args, kommando) {
|
|
41
42
|
const rest = [];
|
|
42
43
|
const werte = new Map();
|
|
43
44
|
const flaggen = new Set();
|
|
@@ -54,7 +55,8 @@ function schalterLesen(args) {
|
|
|
54
55
|
}
|
|
55
56
|
const wert = args[++i];
|
|
56
57
|
if (wert === undefined)
|
|
57
|
-
throw new Error(`Schalter --${name} braucht einen Wert`
|
|
58
|
+
throw new Error(`Schalter --${name} braucht einen Wert, etwa --${name} <wert>. ` +
|
|
59
|
+
`${kommando === undefined ? 'hmgr --help' : `hmgr help ${kommando}`} zeigt die Schalter.`);
|
|
58
60
|
werte.set(name, wert);
|
|
59
61
|
}
|
|
60
62
|
return { rest, werte, flaggen };
|
|
@@ -69,31 +71,6 @@ function ortLesen(text) {
|
|
|
69
71
|
return { art: 'profil', name: roh.slice(7) };
|
|
70
72
|
throw new Error(`Unbekannter Ort „${roh}", erwartet home, dir:<pfad> oder profil:<name>`);
|
|
71
73
|
}
|
|
72
|
-
const HILFE = `hmgr <kommando>
|
|
73
|
-
|
|
74
|
-
source add <url|pfad> Quelle hinzufügen (URL wird geklont, Pfad bleibt Arbeitskopie)
|
|
75
|
-
source list Quellen zeigen
|
|
76
|
-
dir add <pfad> Arbeitsverzeichnis merken und an seinen Zeiger binden
|
|
77
|
-
dir forget <pfad> Arbeitsverzeichnis und Bindung vergessen, Links bleiben
|
|
78
|
-
dir list Arbeitsverzeichnisse mit ihrer Bindung zeigen
|
|
79
|
-
link <skill> Skill in ein Ziel verlinken
|
|
80
|
-
unlink <skill> Link entfernen
|
|
81
|
-
adopt [name] Fremde Links im Ziel durch eigene hmgr-Links ersetzen
|
|
82
|
-
plugin add <name> Plugin in ein Ziel legen (installieren oder Skills verlinken)
|
|
83
|
-
plugin remove <name> Plugin aus einem Ziel entfernen
|
|
84
|
-
plugin list Plugins der Marketplaces aller Quellen
|
|
85
|
-
sync [pfad] Ziel auf den Stand seines Zeigers bringen
|
|
86
|
-
update Alle Checkouts aktualisieren
|
|
87
|
-
status Ist-Zustand der Ziele
|
|
88
|
-
|
|
89
|
-
--harness <name> claude-code, hermes oder agents, Standard claude-code
|
|
90
|
-
--ort home|dir:<pfad>|profil:<name> Standard home
|
|
91
|
-
--quelle <teilstring> Quelle bei mehrdeutigem Skill-Namen
|
|
92
|
-
--version <spanne> Versionseinschränkung nach Composer-Regeln, nur mit Zeiger (E33)
|
|
93
|
-
--composer <pfad> composer.json wählen, wenn mehrere in Frage kommen
|
|
94
|
-
--local Link nur ins Ziel legen, nicht in den Zeiger
|
|
95
|
-
--ersetzen fremden Eintrag am Ziel ersetzen
|
|
96
|
-
--probelauf bei adopt nur melden, nichts schreiben`;
|
|
97
74
|
/** Klartext für den Grund, aus dem ein fremder Eintrag liegen bleibt (B12). */
|
|
98
75
|
const UEBERNAHME_GRUND = {
|
|
99
76
|
'kein-link': 'kein Symlink',
|
|
@@ -105,16 +82,36 @@ const UEBERNAHME_GRUND = {
|
|
|
105
82
|
export async function ausfuehren(argv, umgebung, optionen = {}) {
|
|
106
83
|
const { anwendungsfaelle, ports } = bauen(umgebung, optionen);
|
|
107
84
|
const kommando = argv[0];
|
|
108
|
-
|
|
85
|
+
// Hilfe zuerst: --help ist überall eine Flagge, damit kein Kommando sie als Wert liest.
|
|
86
|
+
if (kommando === undefined) {
|
|
109
87
|
console.log(HILFE);
|
|
110
|
-
return
|
|
88
|
+
return 1;
|
|
89
|
+
}
|
|
90
|
+
if (kommando === 'help' || kommando === '--help' || kommando === '-h') {
|
|
91
|
+
const thema = argv[1];
|
|
92
|
+
if (thema === undefined || thema.startsWith('-')) {
|
|
93
|
+
console.log(HILFE);
|
|
94
|
+
return 0;
|
|
95
|
+
}
|
|
96
|
+
const text = hilfeText(thema);
|
|
97
|
+
if (text === undefined)
|
|
98
|
+
throw new Error(`Unbekanntes Hilfe-Thema „${thema}". hmgr --help zeigt alle Kommandos.`);
|
|
99
|
+
console.log(text);
|
|
100
|
+
return 0;
|
|
101
|
+
}
|
|
102
|
+
if (argv.slice(1).includes('--help')) {
|
|
103
|
+
const text = hilfeText(kommando);
|
|
104
|
+
if (text === undefined)
|
|
105
|
+
throw new Error(`Unbekanntes Kommando „${kommando}". hmgr --help zeigt alle Kommandos.`);
|
|
106
|
+
console.log(text);
|
|
107
|
+
return 0;
|
|
111
108
|
}
|
|
112
109
|
if (kommando === 'source') {
|
|
113
110
|
const unterkommando = argv[1];
|
|
114
111
|
if (unterkommando === 'add') {
|
|
115
112
|
const text = argv[2];
|
|
116
113
|
if (text === undefined)
|
|
117
|
-
throw new Error('source add braucht eine URL oder einen Pfad');
|
|
114
|
+
throw new Error('source add braucht eine URL oder einen Pfad, etwa hmgr source add https://example.com/skills.git');
|
|
118
115
|
const quelle = quelleAusText(text);
|
|
119
116
|
const { skills, marketplace } = await anwendungsfaelle.quelleHinzufuegen(quelle);
|
|
120
117
|
console.log(`Quelle ${quelleAlsText(quelle)} (${quelle.art}), ${skills.length} Skills:`);
|
|
@@ -137,15 +134,15 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
|
|
|
137
134
|
console.log(`${quelle.art} ${quelleAlsText(quelle)}`);
|
|
138
135
|
return 0;
|
|
139
136
|
}
|
|
140
|
-
throw new Error('source add <url|pfad> oder source list
|
|
137
|
+
throw new Error(`${unterkommando === undefined ? 'source braucht ein Unterkommando' : `Unbekanntes Unterkommando „${unterkommando}" für source`}: source add <url|pfad> oder source list. hmgr help source zeigt Beispiele.`);
|
|
141
138
|
}
|
|
142
139
|
if (kommando === 'dir') {
|
|
143
|
-
const { rest, werte } = schalterLesen(argv.slice(1));
|
|
140
|
+
const { rest, werte } = schalterLesen(argv.slice(1), 'dir');
|
|
144
141
|
const unterkommando = rest[0];
|
|
145
142
|
if (unterkommando === 'add') {
|
|
146
143
|
const pfad = rest[1];
|
|
147
144
|
if (pfad === undefined)
|
|
148
|
-
throw new Error('dir add braucht einen Pfad');
|
|
145
|
+
throw new Error('dir add braucht einen Pfad, etwa hmgr dir add .');
|
|
149
146
|
const composer = werte.get('composer');
|
|
150
147
|
const ergebnis = composer === undefined
|
|
151
148
|
? await anwendungsfaelle.arbeitsverzeichnisHinzufuegen(pfad)
|
|
@@ -160,7 +157,7 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
|
|
|
160
157
|
if (unterkommando === 'forget') {
|
|
161
158
|
const pfad = rest[1];
|
|
162
159
|
if (pfad === undefined)
|
|
163
|
-
throw new Error('dir forget braucht einen Pfad');
|
|
160
|
+
throw new Error('dir forget braucht einen Pfad. hmgr dir list zeigt die gemerkten Arbeitsverzeichnisse.');
|
|
164
161
|
await anwendungsfaelle.arbeitsverzeichnisVergessen(pfad);
|
|
165
162
|
console.log(`Arbeitsverzeichnis ${path.resolve(pfad)} vergessen, die Links bleiben liegen.`);
|
|
166
163
|
return 0;
|
|
@@ -175,13 +172,14 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
|
|
|
175
172
|
}
|
|
176
173
|
return 0;
|
|
177
174
|
}
|
|
178
|
-
throw new Error('dir add <pfad>, dir forget <pfad> oder dir list
|
|
175
|
+
throw new Error(`${unterkommando === undefined ? 'dir braucht ein Unterkommando' : `Unbekanntes Unterkommando „${unterkommando}" für dir`}: dir add <pfad>, dir forget <pfad> oder dir list. hmgr help dir zeigt Beispiele.`);
|
|
179
176
|
}
|
|
180
177
|
if (kommando === 'link' || kommando === 'unlink') {
|
|
181
|
-
const { rest, werte, flaggen } = schalterLesen(argv.slice(1));
|
|
178
|
+
const { rest, werte, flaggen } = schalterLesen(argv.slice(1), kommando);
|
|
182
179
|
const skill = rest[0];
|
|
183
180
|
if (skill === undefined)
|
|
184
|
-
throw new Error(`${kommando} braucht einen Skill-Namen`
|
|
181
|
+
throw new Error(`${kommando} braucht einen Skill-Namen, etwa hmgr ${kommando} <skill>. ` +
|
|
182
|
+
'hmgr status zeigt die verlinkten Skills, hmgr source add <url|pfad> die Skills einer Quelle.');
|
|
185
183
|
const ziel = { harness: werte.get('harness') ?? 'claude-code', ort: ortLesen(werte.get('ort')) };
|
|
186
184
|
const lokal = flaggen.has('local') || flaggen.has('lokal');
|
|
187
185
|
if (ziel.ort.art === 'arbeitsverzeichnis') {
|
|
@@ -214,7 +212,7 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
|
|
|
214
212
|
return 0;
|
|
215
213
|
}
|
|
216
214
|
if (kommando === 'adopt') {
|
|
217
|
-
const { rest, werte, flaggen } = schalterLesen(argv.slice(1));
|
|
215
|
+
const { rest, werte, flaggen } = schalterLesen(argv.slice(1), 'adopt');
|
|
218
216
|
const ziel = { harness: werte.get('harness') ?? 'claude-code', ort: ortLesen(werte.get('ort')) };
|
|
219
217
|
const probelauf = flaggen.has('probelauf');
|
|
220
218
|
const name = rest[0];
|
|
@@ -253,7 +251,7 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
|
|
|
253
251
|
return 0;
|
|
254
252
|
}
|
|
255
253
|
if (kommando === 'plugin') {
|
|
256
|
-
const { rest, werte, flaggen } = schalterLesen(argv.slice(1));
|
|
254
|
+
const { rest, werte, flaggen } = schalterLesen(argv.slice(1), 'plugin');
|
|
257
255
|
const unterkommando = rest[0];
|
|
258
256
|
if (unterkommando === 'list') {
|
|
259
257
|
const marketplaces = await anwendungsfaelle.marketplaces();
|
|
@@ -272,10 +270,10 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
|
|
|
272
270
|
return 0;
|
|
273
271
|
}
|
|
274
272
|
if (unterkommando !== 'add' && unterkommando !== 'remove')
|
|
275
|
-
throw new Error('plugin add <name>, plugin remove <name> oder plugin list
|
|
273
|
+
throw new Error(`${unterkommando === undefined ? 'plugin braucht ein Unterkommando' : `Unbekanntes Unterkommando „${unterkommando}" für plugin`}: plugin add <name>, plugin remove <name> oder plugin list. hmgr help plugin zeigt Beispiele.`);
|
|
276
274
|
const name = rest[1];
|
|
277
275
|
if (name === undefined)
|
|
278
|
-
throw new Error(`plugin ${unterkommando} braucht einen Plugin-Namen
|
|
276
|
+
throw new Error(`plugin ${unterkommando} braucht einen Plugin-Namen. hmgr plugin list zeigt die Plugins der bekannten Quellen.`);
|
|
279
277
|
const ziel = { harness: werte.get('harness') ?? 'claude-code', ort: ortLesen(werte.get('ort')) };
|
|
280
278
|
const lokal = flaggen.has('local') || flaggen.has('lokal');
|
|
281
279
|
if (ziel.ort.art === 'arbeitsverzeichnis') {
|
|
@@ -302,7 +300,7 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
|
|
|
302
300
|
return 0;
|
|
303
301
|
}
|
|
304
302
|
if (kommando === 'sync') {
|
|
305
|
-
const { rest } = schalterLesen(argv.slice(1));
|
|
303
|
+
const { rest } = schalterLesen(argv.slice(1), 'sync');
|
|
306
304
|
const ergebnis = await anwendungsfaelle.abgleich(rest[0]);
|
|
307
305
|
if (ergebnis.zeigerPfad !== undefined)
|
|
308
306
|
console.log(`Zeiger ${ergebnis.zeigerPfad}`);
|
|
@@ -360,7 +358,7 @@ export async function ausfuehren(argv, umgebung, optionen = {}) {
|
|
|
360
358
|
console.log(`Nicht vorhanden: ${fehlend.join(', ')}`);
|
|
361
359
|
return 0;
|
|
362
360
|
}
|
|
363
|
-
throw new Error(`Unbekanntes Kommando „${kommando}"
|
|
361
|
+
throw new Error(`Unbekanntes Kommando „${kommando}". hmgr --help zeigt alle Kommandos.`);
|
|
364
362
|
}
|
|
365
363
|
function beschreibeOrt(ort) {
|
|
366
364
|
if (ort.art === 'home')
|
|
@@ -382,13 +380,43 @@ function istModellFehler(fehler) {
|
|
|
382
380
|
fehler instanceof PluginUnbekannt ||
|
|
383
381
|
fehler instanceof AbhaengigkeitFehlt);
|
|
384
382
|
}
|
|
383
|
+
/**
|
|
384
|
+
* Der nächste Schritt zu einem Fehler aus dem Kern. Die Fehlertexte selbst bleiben, wie das Modell
|
|
385
|
+
* sie schreibt, die Handlungsanweisung gehört an die CLI, weil sie Kommandos nennt.
|
|
386
|
+
*/
|
|
387
|
+
function naechsterSchritt(fehler) {
|
|
388
|
+
if (fehler instanceof SkillMehrdeutig)
|
|
389
|
+
return `Quelle eingrenzen: hmgr link ${fehler.name} --quelle <teilstring einer der genannten Quellen>`;
|
|
390
|
+
if (fehler instanceof SkillUnbekannt)
|
|
391
|
+
return 'Erst die Quelle hinzufügen: hmgr source add <url|pfad>. hmgr source list zeigt die bekannten Quellen.';
|
|
392
|
+
if (fehler instanceof NameBelegt)
|
|
393
|
+
return `Entweder mit --ersetzen überschreiben oder den fremden Eintrag mit hmgr adopt ${fehler.skillName} übernehmen.`;
|
|
394
|
+
if (fehler instanceof PluginMehrdeutig)
|
|
395
|
+
return 'Quelle eingrenzen: --quelle <teilstring der URL oder des Pfads>. hmgr plugin list zeigt die Marketplaces.';
|
|
396
|
+
if (fehler instanceof PluginUnbekannt)
|
|
397
|
+
return 'hmgr plugin list zeigt die Plugins der bekannten Quellen. Fehlt der Marketplace, erst hmgr source add <url>.';
|
|
398
|
+
if (fehler instanceof AbhaengigkeitFehlt)
|
|
399
|
+
return 'Die Abhängigkeit steht in keinem Plugin desselben Marketplace, das kann nur die Quelle beheben.';
|
|
400
|
+
if (fehler instanceof KeinPassenderRef)
|
|
401
|
+
return 'hmgr update holt neue Tags der Quelle. Sonst einen vorhandenen Tag- oder Branchnamen als --version nennen.';
|
|
402
|
+
if (fehler instanceof HarnessNichtVorhanden)
|
|
403
|
+
return 'Der Harness legt sein Verzeichnis beim ersten Start an. hmgr status zeigt, welche Harnesses hier liegen.';
|
|
404
|
+
if (fehler instanceof OrtNichtUnterstuetzt)
|
|
405
|
+
return 'profil:<name> kennt nur hermes, claude-code und agents kennen home und dir:<pfad>.';
|
|
406
|
+
const text = fehler instanceof Error ? fehler.message : '';
|
|
407
|
+
if (text.startsWith('Unbekannter Harness'))
|
|
408
|
+
return 'Bekannt sind claude-code, hermes und agents.';
|
|
409
|
+
return undefined;
|
|
410
|
+
}
|
|
385
411
|
export async function main(argv, umgebung) {
|
|
386
412
|
try {
|
|
387
413
|
return await ausfuehren(argv, umgebung);
|
|
388
414
|
}
|
|
389
415
|
catch (fehler) {
|
|
390
416
|
const text = fehler instanceof Error ? fehler.message : String(fehler);
|
|
391
|
-
|
|
417
|
+
const kopf = istModellFehler(fehler) ? text : `Fehler: ${text}`;
|
|
418
|
+
const schritt = naechsterSchritt(fehler);
|
|
419
|
+
console.error(schritt === undefined ? kopf : `${kopf}\n${schritt}`);
|
|
392
420
|
return 1;
|
|
393
421
|
}
|
|
394
422
|
}
|