kimal3 0.1.0 → 0.1.2
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 +79 -74
- package/dist/anmeldung.js +1 -1
- package/dist/api.js +6 -9
- package/dist/argumente.js +35 -7
- package/dist/befehle/firma-daten.js +113 -0
- package/dist/befehle/projekt-liste.js +90 -9
- package/dist/befehle/projekt-neu.js +8 -2
- package/dist/befehle/skill-install.js +271 -6
- package/dist/befehle-katalog.js +112 -0
- package/dist/fehler.js +66 -0
- package/dist/firmen-liste.js +52 -0
- package/dist/kimal3.js +52 -13
- package/dist/projekt-zeilen.js +253 -0
- package/package.json +27 -13
- package/skill/SKILL.md +125 -39
- package/skill/commands/k3.md +44 -0
- package/skill/commands/k3firma.md +57 -0
- package/skill/commands/k3liste.md +26 -0
- package/skill/commands/k3projekt.md +44 -0
|
@@ -1,22 +1,61 @@
|
|
|
1
|
-
import { copyFileSync, existsSync, mkdirSync } from "node:fs";
|
|
1
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Namen, die frueher einmal ausgeliefert wurden und heute nicht mehr.
|
|
7
|
+
*
|
|
8
|
+
* 🔑 **Wofuer das da ist** (Review-Befund, 2026-08-18): Die Befehle landen im
|
|
9
|
+
* GEMEINSAMEN Ordner `~/.claude/commands/` und werden dort nur ueberschrieben,
|
|
10
|
+
* nie entfernt. Wird ein Befehl spaeter umbenannt oder gestrichen, ueberlebt
|
|
11
|
+
* die alte Datei jedes `skill install` und bietet weiter Anweisungen an, die
|
|
12
|
+
* auf einen nicht mehr vorhandenen Unterbefehl zeigen. `SKILL.md` kann das
|
|
13
|
+
* nicht passieren -- es ist EINE Datei, die ueberschrieben wird.
|
|
14
|
+
*
|
|
15
|
+
* ⚠️ Warum eine Liste und nicht "alles loeschen, was wir nicht ausliefern":
|
|
16
|
+
* Der Ordner gehoert dem Menschen. Ein `k3*.md`, das er selbst angelegt hat,
|
|
17
|
+
* duerfen wir nicht wegraeumen. **Wer einen Befehl umbenennt oder entfernt,
|
|
18
|
+
* traegt den alten Namen hier ein** -- sonst bleibt er beim Nutzer stehen.
|
|
19
|
+
*/
|
|
20
|
+
const VERALTETE_BEFEHLE = [];
|
|
21
|
+
/**
|
|
22
|
+
* Woran wir unsere eigenen Befehlsdateien erkennen.
|
|
23
|
+
*
|
|
24
|
+
* Steht die Marke nicht drin, hat ein Mensch die Datei geschrieben -- dann
|
|
25
|
+
* wird sie NICHT ueberschrieben, sondern uebersprungen und gemeldet.
|
|
26
|
+
*/
|
|
27
|
+
const MARKE = "kimal3:erzeugt";
|
|
28
|
+
/**
|
|
29
|
+
* Legt das Skill UND die Slash-Befehle GLOBAL ab, damit Claude dieses Werkzeug
|
|
30
|
+
* ueberall kennt -- und damit der Mensch es auch selbst ausloesen kann.
|
|
31
|
+
*
|
|
32
|
+
* 🔑 **Warum zwei Ziele und nicht eins** (Entscheidung Dennis, 2026-08-18):
|
|
33
|
+
* Das Skill ist der Ausloeser fuer CLAUDE ("das Projekt ist fertig" -> Claude
|
|
34
|
+
* erkennt die Absicht). Die Slash-Befehle sind der Ausloeser fuer den
|
|
35
|
+
* MENSCHEN ("/k3firma …" -> er muss sich keinen Satz merken). Das eine ist
|
|
36
|
+
* wahrscheinlich, das andere sicher. Wer nur das Skill installiert, laesst den
|
|
37
|
+
* sicheren Weg weg.
|
|
7
38
|
*
|
|
8
39
|
* Der Pfad zur eigenen Datei kommt ueber `import.meta.url` und NICHT ueber
|
|
9
40
|
* `process.cwd()` — die Quelle liegt im installierten Paket, das Ziel im
|
|
10
41
|
* Ordner des Menschen. Wer beides verwechselt, kopiert eine Datei auf sich
|
|
11
42
|
* selbst.
|
|
12
43
|
*
|
|
13
|
-
* `dist/befehle/skill-install.js` -> zwei Ebenen hoch -> `skill
|
|
44
|
+
* `dist/befehle/skill-install.js` -> zwei Ebenen hoch -> `skill/…`.
|
|
14
45
|
*/
|
|
15
46
|
export async function skillInstall() {
|
|
16
47
|
const quelle = fileURLToPath(new URL("../../skill/SKILL.md", import.meta.url));
|
|
17
48
|
if (!existsSync(quelle)) {
|
|
18
|
-
|
|
19
|
-
|
|
49
|
+
/*
|
|
50
|
+
🔴 **`1`, nicht `3`** (Review-Befund, 2026-08-18). Ein unvollstaendiges
|
|
51
|
+
Paket wird durch Wiederholen nie vollstaendig. `3` heisst laut SKILL.md
|
|
52
|
+
ausdruecklich "einmal wiederholen" -- Claude liest die ZAHL, nicht den
|
|
53
|
+
Text, und wuerde einen Rat geben, der garantiert nicht hilft. Genau der
|
|
54
|
+
Fehlertyp, den dieser Zweig bei B-5, B-7 und L-7 behoben hat.
|
|
55
|
+
*/
|
|
56
|
+
console.error("Das Skill liegt nicht im Paket. Bitte kimal3 neu installieren:");
|
|
57
|
+
console.error(" npm install -g kimal3");
|
|
58
|
+
return 1;
|
|
20
59
|
}
|
|
21
60
|
// 🔑 GLOBAL, nicht projektlokal (Fund von Dennis, 2026-08-13).
|
|
22
61
|
// Gemessen: In ~/.claude/skills liegen 34 Skills, im Projekt selbst kein
|
|
@@ -39,6 +78,232 @@ export async function skillInstall() {
|
|
|
39
78
|
}
|
|
40
79
|
console.log(gabEsSchon ? "✓ Skill aktualisiert." : "✓ Skill angelegt.");
|
|
41
80
|
console.log(` ${ziel}`);
|
|
42
|
-
|
|
81
|
+
const namen = slashBefehleInstallieren();
|
|
82
|
+
if (namen === "kaputt") {
|
|
83
|
+
/*
|
|
84
|
+
⚠️ **Was hier zaehlt, ist die TEILWIRKUNG** (Review-Runde 2, 2026-08-18):
|
|
85
|
+
Das Skill steht oben bereits als angelegt gemeldet. Ohne diesen Satz
|
|
86
|
+
liest der Mensch ein "✓" und danach einen Fehler und weiss nicht, was
|
|
87
|
+
nun gilt. *Ein halber Erfolg ist weder ein Erfolg noch ein Totalausfall
|
|
88
|
+
-- er ist ein eigener Zustand und braucht einen eigenen Satz.*
|
|
89
|
+
*/
|
|
90
|
+
console.error(" Das Skill ist installiert, die Slash-Befehle sind es NICHT.");
|
|
91
|
+
return 1;
|
|
92
|
+
}
|
|
93
|
+
const { geschrieben, uebersprungen, unlesbar, gestoert } = namen;
|
|
94
|
+
if (geschrieben.length > 0) {
|
|
95
|
+
console.log(`✓ ${geschrieben.length} Slash-Befehle: ${geschrieben.map((n) => `/${n}`).join(" · ")}`);
|
|
96
|
+
console.log(` ${join(homedir(), ".claude", "commands")}`);
|
|
97
|
+
}
|
|
98
|
+
// ⚠️ Uebersprungene Dateien gehoeren in die AUSGABE, nicht nur in die Logik.
|
|
99
|
+
// Ein Mensch, dem stillschweigend ein Befehl fehlt, sucht den Fehler bei
|
|
100
|
+
// sich. (Review-Runde 2, 2026-08-18.)
|
|
101
|
+
if (uebersprungen.length > 0) {
|
|
102
|
+
console.log(`⚠ ${uebersprungen.length} übersprungen: ${uebersprungen.map((n) => `/${n}`).join(" · ")}`);
|
|
103
|
+
console.log(" Dort liegt bereits eine Datei, die nicht von kimal3 stammt —");
|
|
104
|
+
console.log(" sie bleibt unangetastet. Wer die kimal3-Fassung will, benennt");
|
|
105
|
+
console.log(" die eigene um und führt den Befehl erneut aus.");
|
|
106
|
+
}
|
|
107
|
+
// 🔴 Ein LESEFEHLER bekommt einen eigenen Satz (Review-Runde 6): Er sieht
|
|
108
|
+
// aus wie Fremdbesitz, ist aber keiner -- und der Rat "benenn deine Datei
|
|
109
|
+
// um" waere hier falsch.
|
|
110
|
+
if (unlesbar.length > 0) {
|
|
111
|
+
console.log(`⚠ ${unlesbar.length} nicht lesbar: ${unlesbar.map((n) => `/${n}`).join(" · ")}`);
|
|
112
|
+
console.log(" Diese Dateien liessen sich nicht öffnen — vielleicht sind sie");
|
|
113
|
+
console.log(" gerade in Benutzung. Sie wurden nicht angefasst; ein zweiter");
|
|
114
|
+
console.log(" Versuch gleich kann klappen.");
|
|
115
|
+
}
|
|
116
|
+
/*
|
|
117
|
+
🔴 **Kein Slash-Befehl installiert ist kein Erfolg** (Review-Runde 5,
|
|
118
|
+
2026-08-18). Liegen im Ordner lauter fremde `k3*.md`, landet ALLES in
|
|
119
|
+
`uebersprungen`, `geschrieben` ist leer -- und der Lauf endete trotzdem
|
|
120
|
+
auf `0`. Laut der eigenen Tabelle in `SKILL.md` heisst `0` "erledigt".
|
|
121
|
+
|
|
122
|
+
*Ein Fehlerfall darf nie denselben Namen tragen wie ein Erfolgsfall.*
|
|
123
|
+
|
|
124
|
+
⚠️ Die Zahl haengt am GRUND (Review-Runde 6): War der Ordner nur belegt,
|
|
125
|
+
ist der Zustand stabil -> `1`. Ging das Schreiben schief oder war eine
|
|
126
|
+
Datei nicht lesbar, kann ein zweiter Versuch helfen -> `3`.
|
|
127
|
+
*/
|
|
128
|
+
if (geschrieben.length === 0) {
|
|
129
|
+
const wiederholbar = gestoert || unlesbar.length > 0;
|
|
130
|
+
console.error(" Es wurde KEIN Slash-Befehl installiert.");
|
|
131
|
+
console.error(" Das Skill selbst ist installiert und funktioniert.");
|
|
132
|
+
return wiederholbar ? 3 : 1;
|
|
133
|
+
}
|
|
134
|
+
/*
|
|
135
|
+
⚠️ **Eine unvollstaendige Installation als solche melden** (Review-Runde 6).
|
|
136
|
+
Scheitert `copyFileSync` bei Datei 3 von 4, sind zwei Befehle da -- der
|
|
137
|
+
Lauf ist weder gelungen noch gescheitert. Frueher warf der `catch` die
|
|
138
|
+
Teilwirkung weg und meldete alles als misslungen.
|
|
139
|
+
*/
|
|
140
|
+
if (gestoert) {
|
|
141
|
+
console.error(" Nicht alle Slash-Befehle konnten geschrieben werden.");
|
|
142
|
+
console.error(" Die oben genannten stehen; ein zweiter Lauf holt den Rest.");
|
|
143
|
+
return 3;
|
|
144
|
+
}
|
|
145
|
+
/*
|
|
146
|
+
⚠️ **Nicht auf einen Befehl verweisen, den wir gerade NICHT installiert
|
|
147
|
+
haben** (Review-Runde 3, 2026-08-18, gemessen). Mit einer fremden
|
|
148
|
+
`k3.md` im Ordner stand hier woertlich "Tipp /k3 in Claude Code" --
|
|
149
|
+
ausgerechnet der eine Befehl, den der Lauf soeben abgelehnt hatte.
|
|
150
|
+
*Ein Hinweis auf etwas, das es nicht gibt, sieht aus wie ein Fehler des
|
|
151
|
+
Menschen.*
|
|
152
|
+
*/
|
|
153
|
+
if (geschrieben.includes("k3")) {
|
|
154
|
+
console.log(" Tipp /k3 in Claude Code. (Taucht nichts auf, einmal neu starten.)");
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
console.log(` Tipp /${geschrieben[0]} in Claude Code. (Taucht nichts auf, einmal neu starten.)`);
|
|
158
|
+
}
|
|
43
159
|
return 0;
|
|
44
160
|
}
|
|
161
|
+
/**
|
|
162
|
+
* Kopiert die Slash-Befehle nach `~/.claude/commands/`.
|
|
163
|
+
*
|
|
164
|
+
* ⚠️ **FLACH, nicht in einen Unterordner** — und das ist keine Bequemlichkeit:
|
|
165
|
+
* Ein Unterordner `kimal3/` macht aus `/k3firma` ein `/kimal3:k3firma`. Dann
|
|
166
|
+
* findet man die Familie nicht mehr, indem man `/k3` tippt, und genau das war
|
|
167
|
+
* die Anforderung (Dennis, 2026-08-18): einmal `/k3` eingeben und alles sehen.
|
|
168
|
+
* Der gemeinsame Namensanfang ERSETZT hier den Ordner.
|
|
169
|
+
*
|
|
170
|
+
* Rueckgabe: die Namen ohne `.md` — oder `"kaputt"` (Paket unvollstaendig,
|
|
171
|
+
* Wiederholen hilft NIE) bzw. `"stoerung"` (Schreiben ging schief, Wiederholen
|
|
172
|
+
* kann helfen). *Zwei Fehlerfaelle, die Gegenteiliges verlangen, duerfen nicht
|
|
173
|
+
* denselben Namen tragen.*
|
|
174
|
+
*/
|
|
175
|
+
function slashBefehleInstallieren() {
|
|
176
|
+
const quellOrdner = fileURLToPath(new URL("../../skill/commands", import.meta.url));
|
|
177
|
+
if (!existsSync(quellOrdner)) {
|
|
178
|
+
console.error("Die Slash-Befehle liegen nicht im Paket. Bitte kimal3 neu installieren.");
|
|
179
|
+
return "kaputt";
|
|
180
|
+
}
|
|
181
|
+
const dateien = readdirSync(quellOrdner).filter((n) => n.endsWith(".md")).sort();
|
|
182
|
+
if (dateien.length === 0) {
|
|
183
|
+
console.error("Im Paket liegt kein einziger Slash-Befehl. Bitte kimal3 neu installieren.");
|
|
184
|
+
return "kaputt";
|
|
185
|
+
}
|
|
186
|
+
const zielOrdner = join(homedir(), ".claude", "commands");
|
|
187
|
+
const geschrieben = [];
|
|
188
|
+
const uebersprungen = [];
|
|
189
|
+
const unlesbar = [];
|
|
190
|
+
let gestoert = false;
|
|
191
|
+
try {
|
|
192
|
+
mkdirSync(zielOrdner, { recursive: true });
|
|
193
|
+
for (const datei of dateien) {
|
|
194
|
+
const ziel = join(zielOrdner, datei);
|
|
195
|
+
/*
|
|
196
|
+
🔴 **Fremde Dateien NICHT ueberschreiben** (Review-Runde 2, 2026-08-18).
|
|
197
|
+
Der Ordner gehoert dem Menschen. Der Kommentar bei VERALTETE_BEFEHLE
|
|
198
|
+
argumentiert, dass wir eine selbstgeschriebene `k3*.md` nicht loeschen
|
|
199
|
+
duerfen -- *Ueberschreiben zerstoert sie genauso gruendlich*, nur
|
|
200
|
+
unauffaelliger.
|
|
201
|
+
|
|
202
|
+
Woran wir unsere eigenen erkennen: an der Marke `kimal3:erzeugt`. Ein
|
|
203
|
+
blosser Inhaltsvergleich taugt nicht -- eine AELTERE Fassung von uns
|
|
204
|
+
unterscheidet sich auch, und die soll ja gerade ersetzt werden.
|
|
205
|
+
*/
|
|
206
|
+
if (existsSync(ziel)) {
|
|
207
|
+
const vorhanden = leseWennMoeglich(ziel);
|
|
208
|
+
/*
|
|
209
|
+
⚠️ **Ein LESEFEHLER ist kein Fremdbesitz** (Review-Runde 6,
|
|
210
|
+
2026-08-18). Vorher wurde ein gescheitertes `readFileSync` zu einem
|
|
211
|
+
leeren Text -- dann fehlt die Marke zwangslaeufig, und der Mensch las
|
|
212
|
+
"dort liegt eine Datei, die nicht von kimal3 stammt" fuer eine Datei,
|
|
213
|
+
die kimal3 selbst geschrieben hat. *Ein Fehlerfall unter dem Namen
|
|
214
|
+
eines anderen, zum vierten Mal in diesem Zweig.*
|
|
215
|
+
*/
|
|
216
|
+
if (vorhanden === null) {
|
|
217
|
+
unlesbar.push(datei);
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
if (!vorhanden.includes(MARKE)) {
|
|
221
|
+
uebersprungen.push(datei);
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
copyFileSync(join(quellOrdner, datei), ziel);
|
|
226
|
+
geschrieben.push(datei);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
catch (fehler) {
|
|
230
|
+
/*
|
|
231
|
+
⚠️ **Die Teilwirkung ueberlebt den Fehler** (Review-Runde 6, 2026-08-18).
|
|
232
|
+
Vorher warf dieser `catch` alles weg und meldete "stoerung" -- auch wenn
|
|
233
|
+
zwei von vier Befehlen bereits geschrieben waren. Der Mensch hoerte "die
|
|
234
|
+
Slash-Befehle sind NICHT installiert", waehrend die Haelfte dastand.
|
|
235
|
+
`geschrieben` und `uebersprungen` sind ausserhalb des `try` deklariert,
|
|
236
|
+
genau dafuer.
|
|
237
|
+
*/
|
|
238
|
+
console.error(`Die Slash-Befehle liessen sich nicht alle schreiben: ${String(fehler)}`);
|
|
239
|
+
gestoert = true;
|
|
240
|
+
}
|
|
241
|
+
raeumeVeralteteAuf(zielOrdner, VERALTETE_BEFEHLE);
|
|
242
|
+
return {
|
|
243
|
+
geschrieben: geschrieben.map((n) => n.replace(/\.md$/, "")),
|
|
244
|
+
uebersprungen: uebersprungen.map((n) => n.replace(/\.md$/, "")),
|
|
245
|
+
unlesbar: unlesbar.map((n) => n.replace(/\.md$/, "")),
|
|
246
|
+
gestoert,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
/** Liest eine Datei — `null`, wenn sie sich nicht lesen laesst. */
|
|
250
|
+
function leseWennMoeglich(pfad) {
|
|
251
|
+
try {
|
|
252
|
+
return readFileSync(pfad, "utf8");
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Entfernt Befehlsdateien, die frueher einmal ausgeliefert wurden.
|
|
260
|
+
*
|
|
261
|
+
* 🔴 **Warum das eine eigene, exportierte Funktion ist** (Review-Runde 3,
|
|
262
|
+
* 2026-08-18): `VERALTETE_BEFEHLE` ist leer, also ist diese Schleife noch nie
|
|
263
|
+
* gelaufen -- und `check:cli` "belegte" sie nur ueber eine Textsuche. Genau
|
|
264
|
+
* die Falle aus der Projekt-Notiz *wache-am-echten-fehlerfall-pruefen*.
|
|
265
|
+
* Mit dem Zielordner als Parameter laesst sie sich gegen einen Wegwerf-Ordner
|
|
266
|
+
* mit einer echten Datei fahren.
|
|
267
|
+
*
|
|
268
|
+
* 🔴 **Und sie loescht NUR eigene Dateien** (Review-Runde 6, 2026-08-18).
|
|
269
|
+
* Vorher entfernte sie blind, was auf der Liste stand -- waehrend die
|
|
270
|
+
* Kopierschleife siebzig Zeilen hoeher genau solche Dateien verschont und dem
|
|
271
|
+
* Menschen sagt "sie bleibt unangetastet". *Zwei Haelften desselben Befehls
|
|
272
|
+
* mit gegensaetzlicher Haltung zum selben Ordner.* Wird `/k3liste` spaeter
|
|
273
|
+
* umbenannt, verloere ein Mensch mit eigener `k3liste.md` sie ohne Rueckfrage.
|
|
274
|
+
*
|
|
275
|
+
* Gibt zurueck, was wirklich entfernt wurde -- eine Behauptung waere hier
|
|
276
|
+
* genau das Falsche.
|
|
277
|
+
*/
|
|
278
|
+
export function raeumeVeralteteAuf(zielOrdner, veraltet) {
|
|
279
|
+
const entfernt = [];
|
|
280
|
+
for (const eintrag of veraltet) {
|
|
281
|
+
/*
|
|
282
|
+
🔴 **Beide Schreibweisen annehmen** (Review-Runde 5, 2026-08-18). Der
|
|
283
|
+
Doc-Block sagt "wer einen Befehl umbenennt, traegt den alten NAMEN hier
|
|
284
|
+
ein" -- gejoint wird aber ein DATEIname. Wer `"k3alt"` eintraegt, bekam
|
|
285
|
+
keinen Fehler: nichts wird entfernt, nichts gemeldet.
|
|
286
|
+
*/
|
|
287
|
+
const alt = eintrag.endsWith(".md") ? eintrag : `${eintrag}.md`;
|
|
288
|
+
const weg = join(zielOrdner, alt);
|
|
289
|
+
try {
|
|
290
|
+
if (!existsSync(weg))
|
|
291
|
+
continue;
|
|
292
|
+
const inhalt = leseWennMoeglich(weg);
|
|
293
|
+
if (inhalt === null || !inhalt.includes(MARKE)) {
|
|
294
|
+
// Nicht von uns (oder nicht lesbar) -> nicht anfassen. Still, weil es
|
|
295
|
+
// der Normalfall ist, dass dort gar nichts liegt.
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
rmSync(weg);
|
|
299
|
+
entfernt.push(alt);
|
|
300
|
+
console.log(` (veralteten Befehl /${alt.replace(/\.md$/, "")} entfernt)`);
|
|
301
|
+
}
|
|
302
|
+
catch {
|
|
303
|
+
// Bewusst still: Die Befehle sind installiert. Eine liegengebliebene
|
|
304
|
+
// alte Datei ist ein Schoenheitsfehler, kein Grund, den Erfolg zu
|
|
305
|
+
// widerrufen. (Review-Runde 2.)
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return entfernt;
|
|
309
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alle Befehle, die `kimal3` kennt — als DATEN, nicht als Fliesstext.
|
|
3
|
+
*
|
|
4
|
+
* 🔑 Warum das eine eigene Datei ist (Spec US-5, 2026-08-18): Die Liste wird an
|
|
5
|
+
* ZWEI Orten angezeigt — in der Terminal-Hilfe und im aktiven Pro-Bereich der
|
|
6
|
+
* App. Zwei handgeschriebene Listen sind die "dieselbe Zahl an zwei Tueren"-
|
|
7
|
+
* Falle: Der naechste Befehl erschiene in einer und fehlte in der anderen.
|
|
8
|
+
* Genau so war die `check:`-Prueferliste in CLAUDE.md monatelang unvollstaendig.
|
|
9
|
+
*
|
|
10
|
+
* ⚠️ DIESE DATEI IMPORTIERT NICHTS, und das ist Absicht: Die CLI baut mit
|
|
11
|
+
* NodeNext (Import-Pfade enden auf `.js`), die App mit dem Bundler. Eine Datei
|
|
12
|
+
* ohne eigene Importe liest sich aus beiden Welten ohne Uebersetzung.
|
|
13
|
+
*
|
|
14
|
+
* ⚠️ Der Katalog beschreibt, WAS ES GIBT — nicht, wer es darf. Die Pro-Schranke
|
|
15
|
+
* sitzt in der Route und im Befehl, nicht hier.
|
|
16
|
+
*/
|
|
17
|
+
export const BEFEHLE = [
|
|
18
|
+
{
|
|
19
|
+
befehl: "kimal3 login",
|
|
20
|
+
beschreibung: "Diesen Rechner mit deinem Konto verbinden",
|
|
21
|
+
wer: "du",
|
|
22
|
+
rhythmus: "einmal pro Rechner",
|
|
23
|
+
beispiel: "kimal3 login",
|
|
24
|
+
details: [
|
|
25
|
+
"Der Befehl zeigt dir eine Adresse und einen kurzen Code. Die Adresse im Browser öffnen, den Code eintippen, fertig — das Terminal merkt die Bestätigung von selbst. Zehn Minuten hast du dafür Zeit.",
|
|
26
|
+
"Danach musst du dich NICHT bei jedem Start neu anmelden: Der Ausweis liegt als Datei in deinem Benutzerordner und übersteht IDE-Neustarts, Rechner-Neustarts und Updates. Bei jedem Aufruf wird er im Hintergrund aufgefrischt, ohne dass du etwas merkst.",
|
|
27
|
+
"Gelegentlich reißt diese Kette trotzdem — dann sagt ein Befehl „Bitte kimal3 login ausführen\". Das ist kein Fehler, sondern der Normalfall nach längerer Pause: einmal wiederholen und weitermachen.",
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
befehl: "kimal3 logout",
|
|
32
|
+
beschreibung: "Verbindung wieder aufheben",
|
|
33
|
+
wer: "du",
|
|
34
|
+
rhythmus: "nur wenn nötig",
|
|
35
|
+
beispiel: "kimal3 logout",
|
|
36
|
+
details: [
|
|
37
|
+
"Hebt die Verbindung dieses einen Rechners auf. Für den Alltag brauchst du ihn nicht.",
|
|
38
|
+
"Sinnvoll ist er, wenn du auf einem fremden oder geteilten Rechner gearbeitet hast — oder wenn ein Gerät abhandenkommt. Deine anderen Rechner bleiben angemeldet.",
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
befehl: "kimal3 projekt neu …",
|
|
43
|
+
beschreibung: "Ein Projekt ins Erfolgsprofil eintragen",
|
|
44
|
+
wer: "claude",
|
|
45
|
+
ausloeser: "trag das als Projekt ein",
|
|
46
|
+
beispiel: 'kimal3 projekt neu --titel "Angebots-Generator" --stunden 4 --ergebnis 1200',
|
|
47
|
+
details: [
|
|
48
|
+
"Wenn du in Claude etwas fertig gebaut hast und sagst „trag das als Projekt ein\", stellt Claude den Befehl selbst zusammen — mit Titel, Zeitersparnis, Ergebnis und allem, was ihr gerade besprochen habt. Das ist der bequeme Weg, weil Claude die Zahlen schon kennt.",
|
|
49
|
+
"Selbst tippen kannst du ihn genauso. Pflicht ist nur --titel; alles andere ist freiwillig. Die vollständige Liste aller Angaben zeigt: kimal3 projekt neu --help",
|
|
50
|
+
"Das Projekt landet in deinem Erfolgsprofil und ist damit Teil deines nachprüfbaren Nachweises.",
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
befehl: "kimal3 projekt liste",
|
|
55
|
+
beschreibung: "Deine eingetragenen Projekte anzeigen",
|
|
56
|
+
wer: "claude",
|
|
57
|
+
ausloeser: "zeig meine Projekte",
|
|
58
|
+
beispiel: "kimal3 projekt liste",
|
|
59
|
+
details: [
|
|
60
|
+
"Zeigt, was schon in deinem Erfolgsprofil steht.",
|
|
61
|
+
"Wofür es wirklich da ist: Claude schaut hier VOR dem Eintragen nach. Ohne diesen Blick stünde dasselbe Projekt irgendwann zweimal auf einer öffentlichen Seite, die deinen Namen trägt.",
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
befehl: "kimal3 firma daten",
|
|
66
|
+
beschreibung: "Die Daten deiner Firma holen, damit Claude sie auswerten kann",
|
|
67
|
+
wer: "claude",
|
|
68
|
+
ausloeser: "werte meine Firma aus",
|
|
69
|
+
beispiel: 'kimal3 firma daten --firma "Nordwind Handel GmbH"',
|
|
70
|
+
details: [
|
|
71
|
+
"Holt Kennzahlen, Menschen und Projekte deiner Firma und gibt sie an Claude weiter. Die Auswertung macht dann Claude — frag einfach los: „Welche drei Projekte bringen den meisten messbaren Ertrag?\" oder „Was sollten wir als Nächstes automatisieren?\"",
|
|
72
|
+
"Gehörst du zu mehreren Firmen, fragt der Befehl nach — er wählt nie still eine aus.",
|
|
73
|
+
"⚠️ Es sind personenbezogene Daten von Kolleginnen und Kollegen. Für den Einsatz in einer echten Firma braucht es ein kommerzielles Claude-Konto mit Auftragsverarbeitungsvertrag; werden Leistungen von Beschäftigten ausgewertet, ist das in Deutschland mitbestimmungspflichtig.",
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
befehl: "kimal3 skill install",
|
|
78
|
+
beschreibung: "Claude beibringen, dieses Werkzeug zu benutzen — und dir die /k3-Befehle geben",
|
|
79
|
+
wer: "du",
|
|
80
|
+
rhythmus: "einmal — und nach jedem Update",
|
|
81
|
+
beispiel: "kimal3 skill install",
|
|
82
|
+
details: [
|
|
83
|
+
"Das ist der Befehl, der aus den anderen erst etwas macht. Er legt ZWEI Dinge in deinem Claude-Ordner ab: eine Anleitung für Claude (das „Skill\") und vier Slash-Befehle für dich.",
|
|
84
|
+
"🤖 Die Anleitung sorgt dafür, dass Claude von selbst weiß, dass es kimal3 gibt — du sagst „das Projekt ist fertig\", er trägt es ein.",
|
|
85
|
+
"🧑 Die Slash-Befehle sind dein eigener Griff: Tipp /k3 in Claude Code, und du siehst die ganze Familie — /k3 · /k3projekt · /k3liste · /k3firma. Damit musst du dir keinen Satz merken.",
|
|
86
|
+
"Er läuft NICHT automatisch. Einmal nach der Installation ausführen — und noch einmal nach jedem Update des Werkzeugs, sonst arbeitet Claude weiter mit der alten Anleitung.",
|
|
87
|
+
"Woran du merkst, dass es geklappt hat: Der Befehl meldet „Skill angelegt\" (oder „aktualisiert\") und zählt die Slash-Befehle auf. Beides kennt Claude ab der NÄCHSTEN Sitzung — die laufende muss also einmal neu gestartet werden.",
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
];
|
|
91
|
+
/**
|
|
92
|
+
* Die Terminal-Hilfe, gebaut aus dem Katalog.
|
|
93
|
+
*
|
|
94
|
+
* Die Spalten richten sich an der laengsten Befehlszeile aus — von Hand
|
|
95
|
+
* gesetzte Leerzeichen waeren beim naechsten laengeren Befehl krumm.
|
|
96
|
+
*
|
|
97
|
+
* 📌 Sie nimmt bewusst NUR `befehl` und `beschreibung`: Im Terminal ist eine
|
|
98
|
+
* Uebersicht gefragt, kein Handbuch. Die langen `details` haben ihren Platz auf
|
|
99
|
+
* `/pro`, wo man sie auf- und zuklappen kann — `--help` je Befehl bleibt der
|
|
100
|
+
* Weg im Terminal.
|
|
101
|
+
*/
|
|
102
|
+
export function hilfeText() {
|
|
103
|
+
const breite = Math.max(...BEFEHLE.map((b) => b.befehl.length));
|
|
104
|
+
const zeilen = BEFEHLE.map((b) => ` ${b.befehl.padEnd(breite + 2)}${b.beschreibung}`).join("\n");
|
|
105
|
+
return `
|
|
106
|
+
kimal3 — trag deine KI-Projekte dort ein, wo sie entstehen.
|
|
107
|
+
|
|
108
|
+
${zeilen}
|
|
109
|
+
|
|
110
|
+
Mehr zu einem Befehl: kimal3 projekt neu --help
|
|
111
|
+
`;
|
|
112
|
+
}
|
package/dist/fehler.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Der gemeinsame Schluss aller Befehle: Was tun mit einer Absage, die kein
|
|
3
|
+
* Befehl fuer sich beantworten kann?
|
|
4
|
+
*
|
|
5
|
+
* 🔑 **Warum das hier wohnt und nicht in `api.ts`:** Es ist eine reine
|
|
6
|
+
* Rechnung -- Zahl und Text rein, Zahl und Text raus, kein Netz, keine Datei.
|
|
7
|
+
* Damit ist sie in `check:cli` messbar, ohne einen Server zu starten. `api.ts`
|
|
8
|
+
* zieht ueber `anmeldung.ts` das Dateisystem nach; wer von dort importiert,
|
|
9
|
+
* kann die Rechnung nicht mehr allein pruefen.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* ⚠️ **404 ist KEIN Eingabefehler** (QA-Befund B-7, 2026-08-18).
|
|
13
|
+
*
|
|
14
|
+
* Vorher endeten alle drei Befehle auf `status >= 500 ? 3 : 1`. Eine `404`
|
|
15
|
+
* fiel damit auf die `1` -- und `1` heisst laut `skill/SKILL.md` ausdruecklich
|
|
16
|
+
* *"Eingabe passt nicht"*. Antwortet die App aber mit `404`, war die Eingabe
|
|
17
|
+
* fehlerfrei: Die **App** kennt den Befehl noch nicht. Claude folgte der
|
|
18
|
+
* Betriebsanleitung und erklaerte dem Menschen, seine Eingabe stimme nicht --
|
|
19
|
+
* woraufhin der Firmenname, Schreibweise und `--firma` prueft und nichts davon
|
|
20
|
+
* hilft.
|
|
21
|
+
*
|
|
22
|
+
* 🔴 **Gemessen am 2026-08-18:** `/api/cli/firma` antwortete auf
|
|
23
|
+
* `kimal3-app.vercel.app` mit `404`, waehrend `/api/cli/projekt` mit `200`
|
|
24
|
+
* antwortete -- der Befehl war veroeffentlicht, die Route noch nicht
|
|
25
|
+
* ausgeliefert. Genau so sieht der Fall im Alltag aus: im Fenster zwischen
|
|
26
|
+
* `npm publish` und fertigem Deployment, bei einem Rueckbau, und bei jedem
|
|
27
|
+
* neuen Befehl.
|
|
28
|
+
*
|
|
29
|
+
* *Ein Fehlerfall darf nie denselben Namen tragen wie ein anderer, der
|
|
30
|
+
* Gegenteiliges verlangt.* Deshalb bekommt die `404` den `3`-Topf: dort steht
|
|
31
|
+
* bereits "nochmal versuchen kann helfen" -- und ein paar Minuten spaeter ist
|
|
32
|
+
* das Deployment durch.
|
|
33
|
+
*/
|
|
34
|
+
export function schlussFehler(status, meldung) {
|
|
35
|
+
if (status === 404) {
|
|
36
|
+
return {
|
|
37
|
+
text: "Diese Version der App kennt den Befehl noch nicht. " +
|
|
38
|
+
"Hast du gerade aktualisiert, versuch es in ein paar Minuten noch einmal.",
|
|
39
|
+
wert: 3,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/*
|
|
43
|
+
🔴 **`408` und `429` gehoeren AUCH in den 3-Topf** (Review-Runde 3,
|
|
44
|
+
2026-08-18). Vorher fiel alles unter 500 auf die `1` -- und die heisst seit
|
|
45
|
+
Runde 2 ausdruecklich "Wiederholen hilft nicht".
|
|
46
|
+
|
|
47
|
+
Beide Zahlen sagen aber genau das Gegenteil: `429` schickt eine
|
|
48
|
+
Vercel-Firewall oder ein Supabase-Rate-Limit, `408` ist eine
|
|
49
|
+
Zeitueberschreitung. Bei beiden ist **Warten die Loesung**, und bei beiden
|
|
50
|
+
kommt der Rumpf oft als HTML -- dann steht dort nicht einmal eine Meldung,
|
|
51
|
+
sondern nur "Das hat nicht geklappt.".
|
|
52
|
+
|
|
53
|
+
*Genau die Form von B-7, nur mit einer anderen Zahl:* Der Mensch hat nichts
|
|
54
|
+
falsch gemacht, das Werkzeug rät ihm trotzdem, es sein zu lassen.
|
|
55
|
+
*/
|
|
56
|
+
if (status === 408 || status === 429) {
|
|
57
|
+
return {
|
|
58
|
+
text: "Der Server ist gerade überlastet oder hat zu lange gebraucht. " +
|
|
59
|
+
"Versuch es in einem Moment noch einmal.",
|
|
60
|
+
wert: 3,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// Alles Uebrige: ein Aussetzer des Servers ist wiederholbar, alles andere
|
|
64
|
+
// ist die Absage, die der Server selbst formuliert hat.
|
|
65
|
+
return { text: meldung, wert: status >= 500 ? 3 : 1 };
|
|
66
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Die Firmen-Auswahl, die eine Absage dem Menschen anbietet.
|
|
3
|
+
*
|
|
4
|
+
* 🔑 Eine reine Rechnung, damit `check:cli` sie ohne Server pruefen kann --
|
|
5
|
+
* dieselbe Ueberlegung wie bei `fehler.ts`.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Aus den Namen der eigenen Firmen die Zeilen bauen, die unter „Deine Firmen:"
|
|
9
|
+
* stehen.
|
|
10
|
+
*
|
|
11
|
+
* ⚠️ **Ein doppelter Name bekommt KEINEN Befehl** (QA-Befund B-5, 2026-08-18).
|
|
12
|
+
* Vorher wurde jeder Name stumpf zu einer kopierfertigen Zeile -- bei zwei
|
|
13
|
+
* gleichnamigen Firmen also **zweimal derselbe Befehl**. Wer ihn ausfuehrte,
|
|
14
|
+
* bekam dieselbe Absage, die erneut denselben Befehl anbot: eine Sackgasse
|
|
15
|
+
* ohne Ausweg.
|
|
16
|
+
*
|
|
17
|
+
* *Ein Vorschlag, der garantiert wieder scheitert, ist schlimmer als gar
|
|
18
|
+
* keiner -- er sieht aus wie ein Ausweg und kostet den Menschen den Versuch.*
|
|
19
|
+
*
|
|
20
|
+
* 🔑 **Nur der mehrdeutige Name verliert seinen Befehl, nicht die ganze
|
|
21
|
+
* Liste.** Wer zu „Nordwind", „Nordwind" und „Suedwind" gehoert, kann
|
|
22
|
+
* „Suedwind" weiterhin waehlen. Dieselbe Lehre steckt schon in der Route
|
|
23
|
+
* (Review-Befund Runde 2): *Eine Sperre, die mehr sperrt als das Mehrdeutige,
|
|
24
|
+
* verlangt vom Menschen etwas, das er nicht tun kann.*
|
|
25
|
+
*
|
|
26
|
+
* ⚠️ Was hier NICHT geloest wird: An die Daten einer doppelt benannten Firma
|
|
27
|
+
* kommt man ueber die CLI weiterhin nicht. Das braeuchte eine Auswahl ueber
|
|
28
|
+
* die ID statt ueber den Namen -- eine eigene Entscheidung, keine Fussnote.
|
|
29
|
+
* Diese Funktion sorgt nur dafuer, dass niemand mehr einen Ausweg vorgespielt
|
|
30
|
+
* bekommt, den es nicht gibt.
|
|
31
|
+
*/
|
|
32
|
+
export function firmenZeilen(namen) {
|
|
33
|
+
const anzahl = (name) => namen.filter((n) => n === name).length;
|
|
34
|
+
const gesehen = new Set();
|
|
35
|
+
const zeilen = [];
|
|
36
|
+
for (const name of namen) {
|
|
37
|
+
if (gesehen.has(name))
|
|
38
|
+
continue;
|
|
39
|
+
gesehen.add(name);
|
|
40
|
+
const wieOft = anzahl(name);
|
|
41
|
+
if (wieOft === 1) {
|
|
42
|
+
// Fertiger Befehl statt blosser Liste: Der naechste Schritt ist dann
|
|
43
|
+
// Kopieren statt Abtippen -- und ein Name mit Leerzeichen braucht
|
|
44
|
+
// Anfuehrungszeichen, an die sonst niemand denkt.
|
|
45
|
+
zeilen.push(` kimal3 firma daten --firma "${name}"`);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
zeilen.push(` „${name}" — kommt ${wieOft}× vor und ist über den Namen nicht wählbar.`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return zeilen;
|
|
52
|
+
}
|
package/dist/kimal3.js
CHANGED
|
@@ -11,29 +11,26 @@
|
|
|
11
11
|
* `kimal3 login`, bei 4 hilft genau das nicht. Wer beide auf dieselbe Zahl
|
|
12
12
|
* legt, laesst Claude den falschen Rat geben.
|
|
13
13
|
*/
|
|
14
|
-
import {
|
|
14
|
+
import { readFileSync } from "node:fs";
|
|
15
|
+
import { BASIS_URL, leseAnmeldung } from "./anmeldung.js";
|
|
15
16
|
import { NichtAngemeldet } from "./api.js";
|
|
17
|
+
import { hilfeText } from "./befehle-katalog.js";
|
|
18
|
+
import { firmaDaten } from "./befehle/firma-daten.js";
|
|
16
19
|
import { login } from "./befehle/login.js";
|
|
17
20
|
import { logout } from "./befehle/logout.js";
|
|
18
21
|
import { projektListe } from "./befehle/projekt-liste.js";
|
|
19
22
|
import { projektNeu } from "./befehle/projekt-neu.js";
|
|
20
23
|
import { skillInstall } from "./befehle/skill-install.js";
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
kimal3 projekt neu … Ein Projekt ins Erfolgsprofil eintragen
|
|
27
|
-
kimal3 projekt liste Deine eingetragenen Projekte anzeigen
|
|
28
|
-
kimal3 skill install Claude beibringen, dieses Werkzeug zu benutzen
|
|
29
|
-
|
|
30
|
-
Mehr zu einem Befehl: kimal3 projekt neu --help
|
|
31
|
-
`;
|
|
24
|
+
// 📌 Kein handgeschriebener Block mehr (2026-08-18): Die Liste wohnt in
|
|
25
|
+
// `befehle-katalog.ts` und wird von dort AUCH im Pro-Bereich der App angezeigt.
|
|
26
|
+
// Zwei Listen ueber dieselben Befehle driften — die eine bekaeme den naechsten
|
|
27
|
+
// Befehl, die andere nicht, und keiner der beiden Orte wuesste davon.
|
|
28
|
+
const HILFE = hilfeText();
|
|
32
29
|
/**
|
|
33
30
|
* Hilfe plus Zustand.
|
|
34
31
|
*
|
|
35
32
|
* ⚠️ Bewusst KEIN automatischer Login (Frage von Dennis, 2026-08-13, am selben
|
|
36
|
-
* Abend nochmals bestaetigt): Wer `
|
|
33
|
+
* Abend nochmals bestaetigt): Wer `kimal3` tippt, um sich das Ding
|
|
37
34
|
* anzusehen, bekaeme sonst unvermittelt einen Anmelde-Vorgang samt Browser.
|
|
38
35
|
* Und was taete der zweite Aufruf, wenn man schon angemeldet ist? Es gaebe
|
|
39
36
|
* zwei Wege zum selben Ergebnis, einer davon unerwartet.
|
|
@@ -42,6 +39,38 @@ const HILFE = `
|
|
|
42
39
|
* ⚠️ Und KEIN Netzaufruf: Wer nur die Hilfe sehen will, soll nicht auf einen
|
|
43
40
|
* Server warten. Ob die Anmeldung noch gilt, klaert der naechste echte Befehl.
|
|
44
41
|
*/
|
|
42
|
+
/**
|
|
43
|
+
* Welche Version bin ich — und mit wem rede ich?
|
|
44
|
+
*
|
|
45
|
+
* ⚠️ **Die Zahl wird GELESEN, nicht abgetippt** (QA-Befund B-8, 2026-08-18).
|
|
46
|
+
* Stuende sie hier als Text, sagte die CLI nach dem naechsten `npm version`
|
|
47
|
+
* die alte Nummer -- dieselbe Zahl an zwei Tueren mit zwei Werten, genau das
|
|
48
|
+
* Muster, das in diesem Projekt schon zweimal zugeschlagen hat.
|
|
49
|
+
*
|
|
50
|
+
* 🔑 **Warum die Gegenstelle mit dazugehoert:** Der Fall, fuer den man diese
|
|
51
|
+
* Auskunft braucht, ist ein **Versatz** zwischen CLI und App (B-7). Dann
|
|
52
|
+
* helfen erst beide Angaben zusammen: welche CLI laeuft -- und gegen welche
|
|
53
|
+
* App sie spricht. Eine Version allein beantwortet die Frage nur halb.
|
|
54
|
+
*
|
|
55
|
+
* 📌 `../package.json` stimmt aus `dist/` **und** aus `src/`: Beide liegen
|
|
56
|
+
* eine Ebene unter `cli/`.
|
|
57
|
+
*/
|
|
58
|
+
function versionsZeilen() {
|
|
59
|
+
let version = "unbekannt";
|
|
60
|
+
try {
|
|
61
|
+
const roh = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
62
|
+
if (roh && typeof roh === "object" && "version" in roh) {
|
|
63
|
+
const v = roh.version;
|
|
64
|
+
if (typeof v === "string")
|
|
65
|
+
version = v;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Kein Absturz, wenn die Datei fehlt: "unbekannt" ist eine ehrliche
|
|
70
|
+
// Antwort, ein Stapelabzug waere keine.
|
|
71
|
+
}
|
|
72
|
+
return ` kimal3 ${version}\n spricht mit ${BASIS_URL}`;
|
|
73
|
+
}
|
|
45
74
|
function zustandsZeile() {
|
|
46
75
|
const a = leseAnmeldung();
|
|
47
76
|
return a
|
|
@@ -56,6 +85,11 @@ async function haupt() {
|
|
|
56
85
|
console.log(zustandsZeile() + "\n");
|
|
57
86
|
return 0;
|
|
58
87
|
}
|
|
88
|
+
if (wort === "--version" || wort === "-v" || wort === "version") {
|
|
89
|
+
console.log(versionsZeilen());
|
|
90
|
+
console.log(zustandsZeile() + "\n");
|
|
91
|
+
return 0;
|
|
92
|
+
}
|
|
59
93
|
if (wort === "login")
|
|
60
94
|
return login();
|
|
61
95
|
if (wort === "logout")
|
|
@@ -64,6 +98,11 @@ async function haupt() {
|
|
|
64
98
|
return projektNeu(argv.slice(2));
|
|
65
99
|
if (wort === "projekt liste")
|
|
66
100
|
return projektListe();
|
|
101
|
+
// ⚠️ Praefix-Vergleich wie bei `projekt neu` und NICHT `wort === "firma daten"`:
|
|
102
|
+
// `wort` enthaelt die Optionen mit, `firma daten --firma X` fiele bei einem
|
|
103
|
+
// Gleichheits-Vergleich durch und meldete "Den Befehl kenne ich nicht".
|
|
104
|
+
if (argv[0] === "firma" && argv[1] === "daten")
|
|
105
|
+
return firmaDaten(argv.slice(2));
|
|
67
106
|
if (wort === "skill install")
|
|
68
107
|
return skillInstall();
|
|
69
108
|
console.error(`Den Befehl „${wort}" kenne ich nicht.\n${HILFE}`);
|