kimal3 0.1.4 → 0.1.5
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 +1 -0
- package/dist/befehle/arbeitsplatz.js +284 -0
- package/dist/befehle-katalog.js +13 -0
- package/dist/kimal3.js +3 -0
- package/package.json +1 -1
- package/skill/SKILL.md +157 -125
package/README.md
CHANGED
|
@@ -35,6 +35,7 @@ auf und bestätigst den Code dort in deinem eingeloggten Konto — so wie bei `g
|
|
|
35
35
|
kimal3 Zeigt, ob dieser Rechner angemeldet ist
|
|
36
36
|
kimal3 login Diesen Rechner mit deinem Konto verbinden
|
|
37
37
|
kimal3 skill install Claude beibringen, dieses Werkzeug zu benutzen — und dir die /k3-Befehle geben
|
|
38
|
+
kimal3 arbeitsplatz neu Deine KI-Arbeitsplatz-Vorlage als Ordner anlegen
|
|
38
39
|
kimal3 projekt neu … Ein Projekt ins Erfolgsprofil eintragen
|
|
39
40
|
kimal3 projekt liste Deine eingetragenen Projekte anzeigen
|
|
40
41
|
kimal3 firma daten Die Daten deiner Firma holen, damit Claude sie auswerten kann
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
import { feld, ruf } from "../api.js";
|
|
4
|
+
import { schlussFehler } from "../fehler.js";
|
|
5
|
+
/**
|
|
6
|
+
* Holt die KI-Arbeitsplatz-Vorlage vom Server und legt sie lokal an --
|
|
7
|
+
* `CLAUDE.md`, Takt-Befehle, die Werkbank fuer eigene Projekte.
|
|
8
|
+
*
|
|
9
|
+
* 🔑 **Warum dieser Befehl NICHTS interpretiert** (wie `firma daten`): Die
|
|
10
|
+
* Vorlage entsteht an EINER Stelle (`arbeitsplatz/vorlage/…` im Repo, gebaut
|
|
11
|
+
* zu `src/lib/arbeitsplatz/vorlage-daten.ts`) und wird von dort an ZWEI Wegen
|
|
12
|
+
* ausgeliefert -- Download auf `/pro` und hier ueber die CLI. Wuerde dieser
|
|
13
|
+
* Befehl die Struktur selbst zusammenbauen, gaebe es zwei Wahrheiten ueber
|
|
14
|
+
* denselben Ordner, und sie liefen beim naechsten Aendern der Vorlage
|
|
15
|
+
* auseinander.
|
|
16
|
+
*/
|
|
17
|
+
const HILFE = `
|
|
18
|
+
kimal3 arbeitsplatz neu [ordnername]
|
|
19
|
+
|
|
20
|
+
Holt deine KI-Arbeitsplatz-Vorlage und legt sie hier als Ordner an.
|
|
21
|
+
|
|
22
|
+
ordnername Optional. Ohne Angabe heisst der Ordner wie in der Vorlage.
|
|
23
|
+
|
|
24
|
+
🔴 Bricht ab, wenn der Zielordner schon existiert und NICHT leer ist --
|
|
25
|
+
eigene Arbeit wird dadurch nie versehentlich ueberschrieben.
|
|
26
|
+
`;
|
|
27
|
+
export async function arbeitsplatzNeu(argv) {
|
|
28
|
+
// ⚠️ VOR dem Lesen des Ordnernamens, wie bei `projekt neu` und
|
|
29
|
+
// `firma daten`: `--help` ist ein Schalter, kein Wert, der geprueft
|
|
30
|
+
// werden muesste.
|
|
31
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
32
|
+
console.log(HILFE);
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
const ordnerArg = argv[0];
|
|
36
|
+
// 🔴 R2-2: Ein LEERES Argument ist kein "kein Argument" -- `?? daten.wurzel`
|
|
37
|
+
// greift nur bei `undefined`, ein leerer String bleibt stehen und `resolve("")`
|
|
38
|
+
// ist das aktuelle Verzeichnis. Wer "Ordner anlegen, hinein wechseln, Befehl
|
|
39
|
+
// tippen" macht, packt die Vorlage sonst versehentlich ins cwd.
|
|
40
|
+
if (ordnerArg !== undefined && ordnerArg.trim() === "") {
|
|
41
|
+
console.error(`Ein leerer Ordnername ist kein gueltiger Name.\n${HILFE}`);
|
|
42
|
+
return 1;
|
|
43
|
+
}
|
|
44
|
+
if (ordnerArg !== undefined && ordnerArg.startsWith("--")) {
|
|
45
|
+
console.error(`Die Option „${ordnerArg}" kenne ich nicht.\n${HILFE}`);
|
|
46
|
+
return 1;
|
|
47
|
+
}
|
|
48
|
+
if (argv.length > 1) {
|
|
49
|
+
console.error(`Mit „${argv[1]}" kann ich hier nichts anfangen -- nur EIN Ordnername ist erlaubt.\n${HILFE}`);
|
|
50
|
+
return 1;
|
|
51
|
+
}
|
|
52
|
+
const antwort = await ruf("/api/cli/arbeitsplatz", { methode: "GET", mitAusweis: true });
|
|
53
|
+
if (antwort.status === 200) {
|
|
54
|
+
// 🔴 Ein `200` mit unlesbarem Rumpf ist KEIN Erfolg -- dieselbe Wache wie
|
|
55
|
+
// bei `firma daten`. `ruf` verschluckt Parse-Fehler zu `null`.
|
|
56
|
+
const daten = alsArbeitsplatzAntwort(antwort.koerper);
|
|
57
|
+
if (daten === null) {
|
|
58
|
+
console.error("Die Antwort war nicht lesbar. Bitte gleich noch einmal.");
|
|
59
|
+
return 3;
|
|
60
|
+
}
|
|
61
|
+
return dateienAnlegen(daten, ordnerArg);
|
|
62
|
+
}
|
|
63
|
+
const meldung = feld(antwort.koerper, "meldung") ?? "Das hat nicht geklappt.";
|
|
64
|
+
// 402 VOR 401: Beide heissen "kommst hier nicht rein", verlangen aber
|
|
65
|
+
// Gegenteiliges. Wer sie zusammenwirft, raet `kimal3 login` -- und der
|
|
66
|
+
// meldet sich dann erfolgreich an, ohne dass es etwas aendert.
|
|
67
|
+
if (antwort.status === 402) {
|
|
68
|
+
console.error(meldung);
|
|
69
|
+
return 4;
|
|
70
|
+
}
|
|
71
|
+
if (antwort.status === 401) {
|
|
72
|
+
console.error(`${meldung} Bitte \`kimal3 login\` ausführen.`);
|
|
73
|
+
return 2;
|
|
74
|
+
}
|
|
75
|
+
// 🔑 Den Rest entscheidet `schlussFehler` fuer alle Befehle gemeinsam --
|
|
76
|
+
// insbesondere die `404` (die App kennt die Route noch nicht) und `429`/
|
|
77
|
+
// `408` (ueberlastet, wiederholbar).
|
|
78
|
+
const schluss = schlussFehler(antwort.status, meldung);
|
|
79
|
+
console.error(schluss.text);
|
|
80
|
+
return schluss.wert;
|
|
81
|
+
}
|
|
82
|
+
/** Prueft die Antwort-Form, ohne `any` -- eine falsche Form ist unlesbar, keine Ausnahme. */
|
|
83
|
+
function alsArbeitsplatzAntwort(koerper) {
|
|
84
|
+
if (!koerper || typeof koerper !== "object")
|
|
85
|
+
return null;
|
|
86
|
+
const wurzel = koerper.wurzel;
|
|
87
|
+
const dateienRoh = koerper.dateien;
|
|
88
|
+
if (typeof wurzel !== "string" || wurzel.trim() === "")
|
|
89
|
+
return null;
|
|
90
|
+
if (!Array.isArray(dateienRoh))
|
|
91
|
+
return null;
|
|
92
|
+
const dateien = [];
|
|
93
|
+
for (const eintrag of dateienRoh) {
|
|
94
|
+
if (!eintrag || typeof eintrag !== "object")
|
|
95
|
+
return null;
|
|
96
|
+
const pfad = eintrag.pfad;
|
|
97
|
+
const inhalt = eintrag.inhalt;
|
|
98
|
+
if (typeof pfad !== "string" || pfad.trim() === "")
|
|
99
|
+
return null;
|
|
100
|
+
if (typeof inhalt !== "string")
|
|
101
|
+
return null;
|
|
102
|
+
dateien.push({ pfad, inhalt });
|
|
103
|
+
}
|
|
104
|
+
return { wurzel, dateien };
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* 🔴 **Nie ueberschreiben** -- die wichtigste Eigenschaft dieses Befehls.
|
|
108
|
+
* Angelegt wird nur, wenn am Zielort NICHTS liegt oder ein LEERER Ordner.
|
|
109
|
+
*
|
|
110
|
+
* Genauer, weil hier zwei verschiedene Absagen stecken:
|
|
111
|
+
* - Zielort ist eine **Datei** (auch eine leere): Abbruch. An einer Datei kann
|
|
112
|
+
* kein Ordner entstehen, ohne sie zu loeschen -- und geloescht wird nichts.
|
|
113
|
+
* - Zielort ist ein **Ordner mit Inhalt**: Abbruch.
|
|
114
|
+
* - Zielort ist ein **leerer Ordner** oder gibt es nicht: los geht's.
|
|
115
|
+
*
|
|
116
|
+
* ⚠️ **Hier stand "eine leere Datei ... ist kein Hindernis"** (Review-Runde 4 zu
|
|
117
|
+
* PR #24) -- das war nie wahr. Wer `touch Mein-KI-Arbeitsplatz` gemacht hat oder
|
|
118
|
+
* wessen Editor eine leere Datei dieses Namens liegen liess, bekam den Abbruch,
|
|
119
|
+
* waehrend der Kommentar Durchlass versprach.
|
|
120
|
+
* *Die Prueffrage aus CLAUDE.md: Beschreibt das ein Verhalten, das jemand WILL --
|
|
121
|
+
* oder nur eines, das PASSIERT?* Hier wollte niemand das Beschriebene; der Code
|
|
122
|
+
* war richtig und der Satz darueber falsch.
|
|
123
|
+
*/
|
|
124
|
+
function dateienAnlegen(daten, ordnerArg) {
|
|
125
|
+
// 🔴 B-7: eine leere Lieferung ist ein FEHLERFALL, kein Erfolg mit null
|
|
126
|
+
// Dateien -- sonst meldet der Befehl "✓ 0 Dateien angelegt." und legt dabei
|
|
127
|
+
// nicht einmal einen Ordner an. Derselbe Rueckgabewert wie bei anderen
|
|
128
|
+
// unlesbaren Antworten (3): der Nutzer hat hier nichts falsch gemacht.
|
|
129
|
+
if (daten.dateien.length === 0) {
|
|
130
|
+
console.error("Die Antwort enthielt keine einzige Datei -- das ist kein gueltiges Ergebnis.");
|
|
131
|
+
console.error("Bitte gleich noch einmal versuchen.");
|
|
132
|
+
return 3;
|
|
133
|
+
}
|
|
134
|
+
const ordnerName = ordnerArg ?? daten.wurzel;
|
|
135
|
+
// 🔴 R2-1: `daten.wurzel` kommt genauso ROH vom Server wie jeder `datei.pfad`
|
|
136
|
+
// -- dieselbe Gefahr (manipulierte Antwort, z. B. ueber ein umgebogenes
|
|
137
|
+
// `KIMAL3_URL`), dieselbe Bremse. Nur wenn KEIN eigener Ordnername uebergeben
|
|
138
|
+
// wurde, fliesst `daten.wurzel` ueberhaupt in den Zielpfad ein -- aber geprueft
|
|
139
|
+
// wird sie immer, damit hier nie zwischen "gerade unbenutzt" und "sicher"
|
|
140
|
+
// verwechselt wird.
|
|
141
|
+
if (istUnsichererPfad(daten.wurzel)) {
|
|
142
|
+
console.error(`Die Antwort enthaelt einen unsicheren Ordnernamen: „${daten.wurzel}". Bitte melden.`);
|
|
143
|
+
return 3;
|
|
144
|
+
}
|
|
145
|
+
const ziel = resolve(ordnerName);
|
|
146
|
+
/*
|
|
147
|
+
🔴 Diese drei Aufrufe brauchen ein eigenes Netz (Review-Runde 3). Sie lagen
|
|
148
|
+
ausserhalb jedes `try`: Ist der Zielordner vorhanden, aber nicht lesbar
|
|
149
|
+
(fremder Besitzer, gesperrte Netzfreigabe -- EACCES), flog `readdirSync`
|
|
150
|
+
bis in den Auffang-Block von `kimal3.ts` durch. Der druckt dann
|
|
151
|
+
„kimal3 ist gerade nicht erreichbar." und gibt 3 zurueck.
|
|
152
|
+
|
|
153
|
+
Das ist gleich doppelt falsch: Der Mensch sucht den Fehler beim Server,
|
|
154
|
+
obwohl er auf seiner eigenen Platte sitzt -- und 3 heisst fuer Claude laut
|
|
155
|
+
SKILL.md „gleich noch einmal versuchen", was hier nie helfen kann.
|
|
156
|
+
*Ein Fehlerfall darf nie denselben Namen tragen wie ein anderer.*
|
|
157
|
+
*/
|
|
158
|
+
try {
|
|
159
|
+
if (existsSync(ziel)) {
|
|
160
|
+
if (!statSync(ziel).isDirectory()) {
|
|
161
|
+
console.error(`„${ordnerName}" gibt es schon -- als DATEI, nicht als Ordner.`);
|
|
162
|
+
console.error("Gib einen anderen Namen an: kimal3 arbeitsplatz neu <anderer-name>");
|
|
163
|
+
return 1;
|
|
164
|
+
}
|
|
165
|
+
/*
|
|
166
|
+
⚠️ **Betriebssystem-Krimskrams zaehlt nicht als Inhalt** (Review-Runde 5).
|
|
167
|
+
`readdirSync` zaehlte vorher ALLES. Wer den Ordner angelegt und ihn nur
|
|
168
|
+
einmal im Finder (`.DS_Store`) oder Explorer (`desktop.ini`) geoeffnet
|
|
169
|
+
hat, bekam "gibt es schon und ist nicht leer" fuer einen Ordner, der fuer
|
|
170
|
+
ihn leer AUSSIEHT -- und keine Chance zu verstehen, warum. *Ein Grund, den
|
|
171
|
+
der Mensch nicht sehen kann, ist keine Begruendung, sondern eine Absage.*
|
|
172
|
+
|
|
173
|
+
Bewusst eine geschlossene Liste und kein "alles, was mit Punkt anfaengt":
|
|
174
|
+
Eine `.env` oder ein `.git` IST Inhalt, und den fassen wir nicht an.
|
|
175
|
+
*/
|
|
176
|
+
const OS_KRIMSKRAMS = [".DS_Store", "desktop.ini", "Thumbs.db"];
|
|
177
|
+
const echterInhalt = readdirSync(ziel).filter((n) => !OS_KRIMSKRAMS.includes(n));
|
|
178
|
+
if (echterInhalt.length > 0) {
|
|
179
|
+
console.error(`Der Ordner „${ordnerName}" gibt es schon und ist nicht leer.`);
|
|
180
|
+
console.error("Ich fasse ihn nicht an -- so geht nie versehentlich eigene Arbeit verloren.");
|
|
181
|
+
console.error("Gib einen anderen Namen an: kimal3 arbeitsplatz neu <anderer-name>");
|
|
182
|
+
return 1;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
catch (fehler) {
|
|
187
|
+
console.error(`Ich komme an den Ordner „${ordnerName}" nicht heran.`);
|
|
188
|
+
console.error(`Grund: ${fehler instanceof Error ? fehler.message : String(fehler)}`);
|
|
189
|
+
console.error("Das liegt an diesem Rechner, nicht am Server -- Rechte pruefen oder");
|
|
190
|
+
console.error("einen anderen Namen angeben: kimal3 arbeitsplatz neu <anderer-name>");
|
|
191
|
+
return 1;
|
|
192
|
+
}
|
|
193
|
+
// 🔴 B-6: ALLE Pfade pruefen, BEVOR die erste Datei geschrieben wird. Wuerde
|
|
194
|
+
// erst waehrend des Schreibens geprueft, koennte ein unsicherer Pfad mitten
|
|
195
|
+
// in der Liste einen halb beschriebenen Ordner hinterlassen -- der naechste
|
|
196
|
+
// Versuch liefe dann in die "nicht leer"-Absage oben, ohne dass der Nutzer
|
|
197
|
+
// je erfaehrt, dass der Ordner unvollstaendig ist.
|
|
198
|
+
for (const datei of daten.dateien) {
|
|
199
|
+
if (istUnsichererPfad(datei.pfad)) {
|
|
200
|
+
console.error(`Die Antwort enthaelt einen unsicheren Pfad: „${datei.pfad}". Bitte melden.`);
|
|
201
|
+
return 3;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
try {
|
|
205
|
+
for (const datei of daten.dateien) {
|
|
206
|
+
const ort = join(ziel, ...datei.pfad.split("/"));
|
|
207
|
+
mkdirSync(dirname(ort), { recursive: true });
|
|
208
|
+
// 🔑 B-2-Folge: Platzhalter wie [DATUM] fuellt seit PR #24 der SERVER
|
|
209
|
+
// (`src/lib/arbeitsplatz/ausliefern.ts`), fuer beide Auslieferungswege
|
|
210
|
+
// gleichzeitig -- Download auf `/pro` UND diese CLI. Wuerde die CLI
|
|
211
|
+
// zusaetzlich selbst ersetzen, gaebe es wieder zwei Wahrheiten ueber
|
|
212
|
+
// denselben Inhalt (genau das war der urspruengliche Befund). Die CLI
|
|
213
|
+
// schreibt den Inhalt deshalb hier UNVERAENDERT auf die Platte.
|
|
214
|
+
writeFileSync(ort, datei.inhalt, "utf8");
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
catch (fehler) {
|
|
218
|
+
/*
|
|
219
|
+
🔴 **Hier stand `return 3` (Review-Runde 5 zu PR #24).** `3` heisst laut
|
|
220
|
+
`cli/skill/SKILL.md` "voruebergehende Stoerung -- gleich noch einmal
|
|
221
|
+
versuchen". Ein voller Datentraeger oder ein EACCES ist aber keine
|
|
222
|
+
Server-Stoerung, und der zweite Versuch kann gar nicht mehr gutgehen:
|
|
223
|
+
Der Zielordner EXISTIERT jetzt und ist nicht leer, also faellt der Lauf
|
|
224
|
+
oben in die Nicht-leer-Wache und endet mit `1` = "Eingabe passt nicht".
|
|
225
|
+
Claude sagt dem Menschen dann, sein Ordnername sei falsch -- und der
|
|
226
|
+
wahre Grund (Platte voll) kommt nie an.
|
|
227
|
+
|
|
228
|
+
Dieselbe Begruendung steht 40 Zeilen weiter oben schon einmal, beim
|
|
229
|
+
`readdirSync`-catch. *Ein Fehler, der einmal verstanden und
|
|
230
|
+
aufgeschrieben wurde, ist im Nachbar-catch trotzdem wieder neu.*
|
|
231
|
+
*/
|
|
232
|
+
console.error(`Schreiben fehlgeschlagen: ${fehler instanceof Error ? fehler.message : String(fehler)}`);
|
|
233
|
+
console.error(`Der Ordner „${ordnerName}" ist dadurch UNVOLLSTAENDIG -- er darf geloescht werden.`);
|
|
234
|
+
console.error("Das liegt an diesem Rechner, nicht am Server -- Platz und Rechte pruefen.");
|
|
235
|
+
return 1;
|
|
236
|
+
}
|
|
237
|
+
console.log(`✓ ${daten.dateien.length} ${daten.dateien.length === 1 ? "Datei" : "Dateien"} angelegt.`);
|
|
238
|
+
console.log(` ${ziel}`);
|
|
239
|
+
console.log("");
|
|
240
|
+
console.log(" Weiter geht's:");
|
|
241
|
+
const werkbank = werkbankOrdner(daten.dateien);
|
|
242
|
+
const cdZiel = werkbank !== null ? `${ordnerName}/${werkbank}` : ordnerName;
|
|
243
|
+
console.log(` cd ${cdZiel.includes(" ") ? `"${cdZiel}"` : cdZiel}`);
|
|
244
|
+
console.log(" claude");
|
|
245
|
+
console.log(' dann "Lass uns einrichten" tippen');
|
|
246
|
+
return 0;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* 🔴 R2-3: Der Name der Werkbank stand hier vorher FEST getippt
|
|
250
|
+
* (`meine-werkbank`) -- eine zweite Wahrheit ueber den Aufbau der Vorlage,
|
|
251
|
+
* genau das, wogegen der Kopfkommentar dieser Datei argumentiert. Wird der
|
|
252
|
+
* Werkbank-Ordner in `arbeitsplatz/vorlage/` umbenannt, bleibt
|
|
253
|
+
* `check:arbeitsplatz` gruen -- die CLI wuerde weiter in einen Ordner
|
|
254
|
+
* schicken, den es nicht mehr gibt.
|
|
255
|
+
*
|
|
256
|
+
* Stattdessen wird der Name aus der GELIEFERTEN Dateiliste abgeleitet: Der
|
|
257
|
+
* Werkbank-Ordner ist der Unterordner mit einer EIGENEN `CLAUDE.md` direkt
|
|
258
|
+
* darin (Pfad `<ordner>/CLAUDE.md`, genau zwei Teile) -- das ist die Stelle,
|
|
259
|
+
* an die `README.md` und diese Meldung Menschen schicken, um dort `claude`
|
|
260
|
+
* zu starten. Aendert sich der Name in der Vorlage, aendert sich diese
|
|
261
|
+
* Meldung automatisch mit.
|
|
262
|
+
*/
|
|
263
|
+
function werkbankOrdner(dateien) {
|
|
264
|
+
for (const datei of dateien) {
|
|
265
|
+
const teile = datei.pfad.split("/");
|
|
266
|
+
if (teile.length === 2 && teile[1] === "CLAUDE.md") {
|
|
267
|
+
return teile[0];
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Ein `..`-Segment oder ein absoluter Pfad duerften das Ziel verlassen.
|
|
274
|
+
*
|
|
275
|
+
* 🔴 B-8: Zerlegt an `/` UND `\` -- eine fehlerhafte oder manipulierte
|
|
276
|
+
* Server-Antwort koennte sonst mit `..\..\boese.md` durchkommen. `join()`
|
|
277
|
+
* trennt unter Windows auch am Backslash, dieser Schutz muss also beide
|
|
278
|
+
* Trenner kennen wie `join()` selbst.
|
|
279
|
+
*/
|
|
280
|
+
function istUnsichererPfad(pfad) {
|
|
281
|
+
if (pfad.startsWith("/") || /^[a-zA-Z]:/.test(pfad))
|
|
282
|
+
return true;
|
|
283
|
+
return pfad.split(/[\\/]/).some((teil) => teil === "..");
|
|
284
|
+
}
|
package/dist/befehle-katalog.js
CHANGED
|
@@ -47,6 +47,19 @@ export const BEFEHLE = [
|
|
|
47
47
|
"Geklappt hat es, wenn er „Skill angelegt“ meldet und die Slash-Befehle aufzählt. Beides kennt Claude ab der NÄCHSTEN Sitzung — die laufende einmal neu starten.",
|
|
48
48
|
],
|
|
49
49
|
},
|
|
50
|
+
{
|
|
51
|
+
befehl: "kimal3 arbeitsplatz neu",
|
|
52
|
+
beschreibung: "Deine KI-Arbeitsplatz-Vorlage als Ordner anlegen",
|
|
53
|
+
wer: "du",
|
|
54
|
+
rhythmus: "einmal pro Arbeitsplatz",
|
|
55
|
+
tippen: "! kimal3 arbeitsplatz neu",
|
|
56
|
+
terminal: "kimal3 arbeitsplatz neu",
|
|
57
|
+
details: [
|
|
58
|
+
"Holt die Vorlage von deinem Pro-Konto und legt sie hier als echten Ordner an — CLAUDE.md, Takt-Befehle, die Werkbank für deine Projekte. Dasselbe Paket, das auch als Download auf /pro liegt.",
|
|
59
|
+
"Ohne Angabe heißt der Ordner wie in der Vorlage. Brauchst du mehrere (z. B. je Firma), gib einen eigenen Namen mit: kimal3 arbeitsplatz neu <name>.",
|
|
60
|
+
"Gibt es den Zielordner schon und ist er nicht leer, bricht der Befehl ab, statt etwas zu überschreiben — deine Arbeit ist sicher. Geklappt hat es, wenn er die Zahl der angelegten Dateien nennt.",
|
|
61
|
+
],
|
|
62
|
+
},
|
|
50
63
|
{
|
|
51
64
|
befehl: "kimal3 projekt neu …",
|
|
52
65
|
beschreibung: "Ein Projekt ins Erfolgsprofil eintragen",
|
package/dist/kimal3.js
CHANGED
|
@@ -15,6 +15,7 @@ import { readFileSync } from "node:fs";
|
|
|
15
15
|
import { BASIS_URL, leseAnmeldung } from "./anmeldung.js";
|
|
16
16
|
import { NichtAngemeldet } from "./api.js";
|
|
17
17
|
import { hilfeText } from "./befehle-katalog.js";
|
|
18
|
+
import { arbeitsplatzNeu } from "./befehle/arbeitsplatz.js";
|
|
18
19
|
import { firmaDaten } from "./befehle/firma-daten.js";
|
|
19
20
|
import { login } from "./befehle/login.js";
|
|
20
21
|
import { logout } from "./befehle/logout.js";
|
|
@@ -123,6 +124,8 @@ async function haupt() {
|
|
|
123
124
|
return firmaDaten(argv.slice(2));
|
|
124
125
|
if (wort === "skill install")
|
|
125
126
|
return skillInstall();
|
|
127
|
+
if (argv[0] === "arbeitsplatz" && argv[1] === "neu")
|
|
128
|
+
return arbeitsplatzNeu(argv.slice(2));
|
|
126
129
|
console.error(`Den Befehl „${wort}" kenne ich nicht.\n${HILFE}`);
|
|
127
130
|
return 1;
|
|
128
131
|
}
|
package/package.json
CHANGED
package/skill/SKILL.md
CHANGED
|
@@ -1,125 +1,157 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: kimal3
|
|
3
|
-
description: Projekte ins kimal3-Erfolgsprofil eintragen oder auflisten — und
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# kimal3 — Projekte ins Erfolgsprofil eintragen
|
|
7
|
-
|
|
8
|
-
> **`kimal3` nicht gefunden?** Zwei Gründe, und sie brauchen verschiedene Antworten:
|
|
9
|
-
> die globale Installation fehlt (`npm install -g kimal3`) — **oder** sie ist da, aber diese
|
|
10
|
-
> Sitzung kennt den Suchpfad noch nicht, dann hilft nur ein Neustart von Claude.
|
|
11
|
-
|
|
12
|
-
## Wann
|
|
13
|
-
Sobald der Mensch sagt, ein Projekt sei fertig, oder ausdrücklich bittet, es einzutragen.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
##
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
Die
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
1
|
+
---
|
|
2
|
+
name: kimal3
|
|
3
|
+
description: Projekte ins kimal3-Erfolgsprofil eintragen oder auflisten, Firmendaten auswerten — und den KI-Arbeitsplatz-Ordner anlegen. Sobald ein KI-Projekt fertig ist, jemand danach fragt, oder jemand seinen Arbeitsplatz einrichten will.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# kimal3 — Projekte ins Erfolgsprofil eintragen
|
|
7
|
+
|
|
8
|
+
> **`kimal3` nicht gefunden?** Zwei Gründe, und sie brauchen verschiedene Antworten:
|
|
9
|
+
> die globale Installation fehlt (`npm install -g kimal3`) — **oder** sie ist da, aber diese
|
|
10
|
+
> Sitzung kennt den Suchpfad noch nicht, dann hilft nur ein Neustart von Claude.
|
|
11
|
+
|
|
12
|
+
## Wann
|
|
13
|
+
Sobald der Mensch sagt, ein Projekt sei fertig, oder ausdrücklich bittet, es einzutragen.
|
|
14
|
+
**Oder** wenn er seinen KI-Arbeitsplatz anlegen will — dann s. „Den Arbeitsplatz anlegen".
|
|
15
|
+
|
|
16
|
+
## Den Arbeitsplatz anlegen (`kimal3 arbeitsplatz neu`)
|
|
17
|
+
|
|
18
|
+
**Wann:** Der Mensch will „seinen KI-Arbeitsplatz", „den Ordner", „die Struktur" — oder ist
|
|
19
|
+
frisch bei Pro und weiß nicht, wo er anfangen soll.
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
kimal3 arbeitsplatz neu # legt Mein-KI-Arbeitsplatz/ an
|
|
23
|
+
kimal3 arbeitsplatz neu <name> # eigener Ordnername
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Was dabei entsteht:** ein Firmen-Ordner mit Regeln für Marke, Systeme und Sicherheit, darin
|
|
27
|
+
eine Werkbank zum Arbeiten und ein Beispiel-Projekt zum Ansehen.
|
|
28
|
+
|
|
29
|
+
🔑 **Er überschreibt nie etwas.** Ist der Zielordner vorhanden und nicht leer, bricht er ab
|
|
30
|
+
(Rückgabewert 1) — dann einen anderen Namen anbieten, **nicht** überreden.
|
|
31
|
+
|
|
32
|
+
**Danach:** in die Werkbank wechseln und **jeden Platzhalter in eckigen Klammern** gemeinsam
|
|
33
|
+
ausfüllen — `[FIRMA]` und `[NAME]` sind nur die häufigsten, es sind zehn verschiedene. Sie
|
|
34
|
+
stehen absichtlich noch drin — frag nach, statt zu raten. `[DATUM]` ist schon gefüllt.
|
|
35
|
+
|
|
36
|
+
🔑 **Zuerst die zwei Dateien, die bei JEDEM Start mitladen** (`CLAUDE.md` der Firma und der
|
|
37
|
+
Werkbank) — dort kostet ein leerer Vordruck jede Sitzung. Der Rest (`kontext/firma.md`) kann
|
|
38
|
+
warten, bis er gebraucht wird.
|
|
39
|
+
|
|
40
|
+
⚠️ **Nicht nach dieser Liste suchen, sondern nach eckigen Klammern.** Hier stand bis zum
|
|
41
|
+
2026-08-19 eine Aufzählung mit einem Platzhalter, den es gar nicht gab — „Rolle“ ist eine
|
|
42
|
+
Beschriftung, kein Vordruck — und ohne sieben, die es gab. *Eine abgetippte Liste veraltet in dem Moment, in dem die Vorlage wächst.*
|
|
43
|
+
|
|
44
|
+
⚠️ **Nicht die Vorlage „aufräumen".** Das Beispiel-Projekt trägt oben groß, dass kein Code
|
|
45
|
+
darin liegt. Nichts davon ausführen und nicht versuchen, es lauffähig zu machen.
|
|
46
|
+
|
|
47
|
+
## Erst nachsehen, dann schreiben
|
|
48
|
+
`kimal3 projekt liste` — steht es schon da, **nicht** noch einmal eintragen.
|
|
49
|
+
|
|
50
|
+
## Eintragen
|
|
51
|
+
`kimal3 projekt neu --titel "…" [--stunden 6] [--ergebnis 1200] [--symbol bot]`
|
|
52
|
+
Alle Optionen: `kimal3 projekt neu --help`
|
|
53
|
+
|
|
54
|
+
## 🔑 Zahlen nie erfinden
|
|
55
|
+
Zeitersparnis, Umsatz und Ergebnis sind Behauptungen über die Wirklichkeit eines Menschen — und
|
|
56
|
+
sie stehen anschließend **öffentlich** auf einer Seite mit seinem Namen. Ist eine Zahl nicht
|
|
57
|
+
genannt worden: **fragen** oder das Feld weglassen. Niemals schätzen.
|
|
58
|
+
|
|
59
|
+
## Nicht angemeldet?
|
|
60
|
+
Dem Menschen `kimal3 login` zeigen und ihn selbst bestätigen lassen. Die Anmeldung **nie**
|
|
61
|
+
selbst versuchen — sie braucht einen Menschen, der im Browser bestätigt.
|
|
62
|
+
|
|
63
|
+
## Kein Pro-Zugang (Rückgabewert 4)
|
|
64
|
+
Die Meldung enthält bereits die Adresse. Dem Menschen **die Meldung zeigen** und den Befehl
|
|
65
|
+
**nicht wiederholen** — ein zweiter Versuch ändert nichts und wirkt wie ein Fehler im Werkzeug.
|
|
66
|
+
Auch **nicht** `kimal3 login` vorschlagen: Der Mensch *ist* angemeldet, ihm fehlt das Konto.
|
|
67
|
+
|
|
68
|
+
## Vorübergehende Störung (Rückgabewert 3)
|
|
69
|
+
Server nicht erreichbar — oder das Konto ließ sich gerade nicht prüfen. Das ist **kein**
|
|
70
|
+
endgültiges Nein: **einmal** wiederholen ist richtig. Klappt es wieder nicht, dem Menschen die
|
|
71
|
+
Meldung zeigen und es dabei belassen.
|
|
72
|
+
|
|
73
|
+
🔴 **Hierher gehört auch: „Diese Version der App kennt den Befehl noch nicht."** Dann ist die
|
|
74
|
+
Eingabe des Menschen **richtig** und die App zu alt — meist im Fenster zwischen einer neuen
|
|
75
|
+
CLI-Version und dem fertigen Deployment. **Sag ausdrücklich, dass er nichts falsch gemacht hat**,
|
|
76
|
+
und schlag vor, es in ein paar Minuten erneut zu versuchen. Rate ihm **nicht**, den Befehl,
|
|
77
|
+
Namen oder Schreibweisen zu prüfen — dort liegt der Fehler nicht.
|
|
78
|
+
|
|
79
|
+
## Firma auswerten (`kimal3 firma daten`)
|
|
80
|
+
|
|
81
|
+
Liefert die Firmendaten als JSON: Kennzahlen, Menschen, Projekte. **Nur auf ausdrücklichen
|
|
82
|
+
Wunsch abrufen** — es sind personenbezogene Daten von Kolleginnen und Kollegen.
|
|
83
|
+
|
|
84
|
+
`kimal3 firma daten` · bei mehreren Firmen: `kimal3 firma daten --firma "Name"`.
|
|
85
|
+
🔴 **Bricht der Befehl mit mehreren Firmen ab, WÄHLST DU NICHT** — du legst dem Menschen die
|
|
86
|
+
Liste vor und lässt ihn entscheiden. Auch dann nicht, wenn eine Firma offensichtlich die
|
|
87
|
+
gemeinte ist: leer, verschrieben, „TEst". *Der Abbruch IST die Mehrdeutigkeit — sie ist schon
|
|
88
|
+
festgestellt, du beurteilst sie nicht neu.* Wer hier auswählt, zeigt einem Menschen die
|
|
89
|
+
personenbezogenen Daten einer Belegschaft, nach der er nicht gefragt hat.
|
|
90
|
+
|
|
91
|
+
⚠️ Hier stand bis zum 2026-08-18 „nimm einen davon, statt zu raten" — und genau dieser Satz hat
|
|
92
|
+
den Fehler ausgelöst. Er war gegen *Raten* gemeint und übersah, dass **Auswählen sich anders
|
|
93
|
+
anfühlt als Raten, aber dasselbe Ergebnis hat**. (Befund von Dennis im Live-Durchlauf.)
|
|
94
|
+
|
|
95
|
+
**Voraussetzung, die du nennen musst, sobald jemand das für seine echte Firma nutzen will:**
|
|
96
|
+
Die Daten laufen durch das Claude-Konto der Firma. Dafür braucht es ein kommerzielles Konto
|
|
97
|
+
(Team/Enterprise/API) mit Auftragsverarbeitungsvertrag — dort wird nicht mit Kundendaten
|
|
98
|
+
trainiert. Und: Werden **Leistungen von Beschäftigten** ausgewertet, ist das in Deutschland
|
|
99
|
+
mitbestimmungspflichtig. Das entscheidet die Firma, nicht dieses Werkzeug.
|
|
100
|
+
|
|
101
|
+
### Regeln beim Auswerten
|
|
102
|
+
- **Zahlen nie erfinden** — hier doppelt. Für Summen die mitgelieferten `kennzahlen` nehmen;
|
|
103
|
+
rechnest du selbst etwas aus, sag dazu, dass du es gerechnet hast.
|
|
104
|
+
- `stand` ist der Tag der Abfrage. Bei älteren Daten nicht so tun, als wären sie von heute.
|
|
105
|
+
- **Ehemalige nicht verschweigen, aber kennzeichnen** (`ehemalig: true`). Ihre Projekte laufen
|
|
106
|
+
weiter — eine Automatisierung hört nicht auf zu wirken, weil der Mensch gegangen ist.
|
|
107
|
+
- `laeuft: false` heißt „noch nicht live". Solche Projekte haben noch nichts gebracht; ihre
|
|
108
|
+
Zahlen sind Erwartung, keine Bilanz. Wirf sie nie mit dem Laufenden in eine Summe.
|
|
109
|
+
- `abteilung: "Ohne Abteilung"` ist ein echter Wert, kein fehlender.
|
|
110
|
+
⚠️ Steht dort **„unbekannt"** und `abteilungen_bekannt: false`, ließen sich die Abteilungen
|
|
111
|
+
gerade nicht laden — dann **keine** Aussage über Abteilungen treffen, auch keine verneinende.
|
|
112
|
+
- 🔴 **Für „pro Kopf" gilt `mitglieder_aktiv`, nicht `personen.length`** — aber nur
|
|
113
|
+
**firmenweit**. In `personen` stehen nur Menschen mit Erfolgsprofil; hat erst die Hälfte eines
|
|
114
|
+
angelegt, verdoppelt die falsche Zahl jedes Ergebnis. Weichen beide ab, sag dazu, auf welche du
|
|
115
|
+
dich beziehst.
|
|
116
|
+
🔴 **Je Abteilung gibt es KEINE verlässliche Kopfzahl.** `mitglieder_aktiv` ist firmenweit und
|
|
117
|
+
für einen Abteilungsvergleich unbrauchbar — sie ist für beide Seiten dieselbe. Vergleiche
|
|
118
|
+
Abteilungen deshalb über **Summen** (Projekte, Zeitersparnis, Ergebnis). Musst du doch pro Kopf
|
|
119
|
+
rechnen, sag ausdrücklich dazu, dass du über die Menschen **mit Erfolgsprofil** gerechnet hast.
|
|
120
|
+
⚠️ **Und hat eine Abteilung keinen aktiven Menschen mehr, ist „pro Kopf" dort nicht definiert —
|
|
121
|
+
sag das, statt zu teilen.** Der Fall ist echt: Eine Abteilung, deren Projekte weiterlaufen,
|
|
122
|
+
während der letzte Mensch gegangen ist, hat kein Kopfzahl-Problem, sondern ein Betreuungsproblem.
|
|
123
|
+
**Das ist die Aussage, die zählt** — nenne sie, statt eine Zahl zu erzwingen.
|
|
124
|
+
📌 `mitglieder_gesamt` zählt **Ehemalige mit** — es ist die Zahl aller Mitgliedschaften, nicht
|
|
125
|
+
die Belegschaft von heute.
|
|
126
|
+
⚠️ **Und es ist NICHT die Zahl der Team-Karten auf `/firma`.** Genau das stand hier und war
|
|
127
|
+
falsch: Die Karten zeigen nur Menschen **mit** Erfolgsprofil. Wer eine Mitgliedschaft ohne
|
|
128
|
+
Profil hat, zählt in `mitglieder_gesamt` mit und erscheint als keine Karte. **Willst du sagen,
|
|
129
|
+
wie viele Karten dort stehen, ist das `personen.length`** — und weichen die beiden Zahlen ab,
|
|
130
|
+
sag dazu, welche du meinst.
|
|
131
|
+
- Zwei Menschen mit demselben Namen erscheinen als „Lena Meyer" und „Lena Meyer (2)". Das ist
|
|
132
|
+
kein Tippfehler, sondern die Unterscheidung — behandle sie als zwei Personen.
|
|
133
|
+
- ⚖️ **Umsatz und Ergebnis nicht in einen Topf, wenn du Abteilungen vergleichst.**
|
|
134
|
+
`umsatz_monat_eur` gibt es nur, wo Umsatz entsteht — Support oder Buchhaltung sparen Kosten und
|
|
135
|
+
erzeugen keinen Umsatz. Deren `0` ist die Natur der Arbeit, kein Versagen. Wer die Gesamtsumme
|
|
136
|
+
vergleicht, erklärt umsatznahe Abteilungen automatisch zu den besseren. Stell **Ergebnis und
|
|
137
|
+
Zeitersparnis** nebeneinander und nenne den Umsatz getrennt.
|
|
138
|
+
|
|
139
|
+
### Fragen, die sich lohnen
|
|
140
|
+
- „Welche drei Projekte bringen den meisten messbaren Ertrag — und welche Abteilung hat am
|
|
141
|
+
längsten nichts Neues geliefert?"
|
|
142
|
+
- „Vergleiche Vertrieb und Support: Projekte, Zeitersparnis, Ergebnis."
|
|
143
|
+
- „Was würdest du als Geschäftsführung als Nächstes automatisieren, gemessen an dem, was bisher
|
|
144
|
+
funktioniert hat — und was davon lässt sich auf andere Abteilungen übertragen?"
|
|
145
|
+
|
|
146
|
+
## Rückgabewerte
|
|
147
|
+
`0` erledigt · `1` **Wiederholen hilft nicht — LIES DIE MELDUNG** · `2` Anmeldung fehlt ·
|
|
148
|
+
`3` vorübergehende Störung, einmal wiederholen · `4` angemeldet, aber kein Pro-Zugang —
|
|
149
|
+
**nicht** wiederholen
|
|
150
|
+
|
|
151
|
+
🔴 **Die `1` hat mehrere Gründe, und sie verlangen Verschiedenes:** „wähl eine Firma", „leg
|
|
152
|
+
zuerst ein Erfolgsprofil an", „die Eingabe passt nicht", „das Paket ist unvollständig". **Gib
|
|
153
|
+
niemals einen Standard-Rat auf die Zahl allein** — die Meldung nennt jedes Mal, was zu tun ist.
|
|
154
|
+
|
|
155
|
+
⚠️ Hier stand kurzzeitig „dann ist `npm install -g kimal3` der Weg". Das hätte bei „du gehörst
|
|
156
|
+
zu zwei Firmen" eine Neuinstallation empfohlen — für einen völlig normalen Fall. *Ein
|
|
157
|
+
Rückgabewert sagt, OB man es noch einmal versuchen soll; WAS zu tun ist, steht im Text.*
|