kimal3 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +43 -8
- package/dist/arbeitsplatz-dateien.js +84 -22
- package/dist/argumente.js +150 -0
- package/dist/befehle/arbeitsplatz.js +139 -17
- package/dist/befehle/kontext-fragen.js +17 -0
- package/dist/befehle/kontext-gemeinsam.js +17 -3
- package/dist/befehle/kontext-hoch.js +36 -3
- package/dist/befehle/kontext-runter.js +58 -7
- package/dist/befehle/skill-install.js +51 -17
- package/dist/befehle/werkbank.js +128 -17
- package/dist/befehle-katalog.js +14 -7
- package/dist/firmen-liste.js +4 -2
- package/dist/kimal3.js +20 -2
- package/dist/kontext-stand.js +304 -50
- package/dist/nachricht.js +87 -3
- package/package.json +1 -1
- package/skill/SKILL.md +44 -8
- package/skill/commands/k3.md +59 -18
- package/skill/commands/k3kontext.md +89 -0
- /package/skill/commands/{k3firma.md → k3analyse.md} +0 -0
|
@@ -173,19 +173,52 @@ export async function kontextHoch(argv) {
|
|
|
173
173
|
mitnimmt. Gemessen auf der Kundenstrecke am 2026-08-25.
|
|
174
174
|
*/
|
|
175
175
|
const zuSchreiben = merkzettelNachHoch(ergebnis.merkzettel, lokalerMerkzettel, FIRMEN_TEXTE.map((d) => d.pfad));
|
|
176
|
+
/*
|
|
177
|
+
🔴 **DIE ERFOLGSMELDUNG STEHT VOR DEM MERKZETTEL** (Review-Runde 4).
|
|
178
|
+
|
|
179
|
+
Sie stand darunter -- und fiel damit in genau dem Fall aus, in dem sie am
|
|
180
|
+
meisten gebraucht wird: Die Firma hat gespeichert, nur die lokale Datei
|
|
181
|
+
liess sich nicht schreiben. Der Mensch las eine Fehlermeldung und erfuhr
|
|
182
|
+
**nicht einmal, WAS oben angekommen ist**, obwohl der Vorgang gelungen war.
|
|
183
|
+
|
|
184
|
+
🔑 Die Reihenfolge ist die Wahrheit: Erst sagen, was passiert ist, dann,
|
|
185
|
+
was daneben schiefging. Was hochgeschickt wurde, haengt nicht daran, ob ein
|
|
186
|
+
Merkzettel auf der Platte landet.
|
|
187
|
+
*/
|
|
188
|
+
console.log(`✓ hochgeschickt: ${ergebnis.uebernommen.join(", ")}`);
|
|
176
189
|
const merkzettelSchreiben = schreibeMerkzettelDatei(ordner, zuSchreiben);
|
|
177
190
|
if (!merkzettelSchreiben.ok) {
|
|
178
|
-
|
|
191
|
+
/*
|
|
192
|
+
🔴 **ECHTE UMLAUTE -- das liest ein Kunde im Terminal** (Projektregel,
|
|
193
|
+
Review-Befund J2; dieselbe Begruendung steht in `kontext-fragen.ts:26`
|
|
194
|
+
und `kontext-gemeinsam.ts:72`). Hier stand die ASCII-Umschrift.
|
|
195
|
+
|
|
196
|
+
⚠️ Sie war nicht nur unschoen, sie hat etwas kaputt gemacht: Diese Zeile
|
|
197
|
+
ist ein NACHSCHLAGE-SCHLUESSEL. `SKILL.md` und `k3kontext.md` fuehren sie
|
|
198
|
+
woertlich in einer Tabelle "Was in der Meldung steht", damit Claude den
|
|
199
|
+
Fall erkennt -- und dieser Fall ist der teuerste ueberhaupt, weil er ein
|
|
200
|
+
ERFOLG ist, der wie ein Fehler aussieht. Wer nach dem Satz mit Umlauten
|
|
201
|
+
sucht und die Umschrift vorfindet, erkennt ihn nicht und faellt auf die
|
|
202
|
+
naechstbeste Zeile zurueck -- „du bist kein Admin".
|
|
203
|
+
*Ein Text, den eine Anleitung zitiert, ist eine Schnittstelle.*
|
|
204
|
+
|
|
205
|
+
🔬 Bewacht von `check:cli` -- aber **nur die Fassung in `k3kontext.md`**
|
|
206
|
+
(Review-Runde 5; hier stand, `SKILL.md` sei mitgedeckt, und das stimmte
|
|
207
|
+
nicht). In `SKILL.md` steht derselbe Satz ueber einen Zeilenumbruch
|
|
208
|
+
verteilt und ist durch eine `includes`-Pruefung ohnehin nicht erfassbar.
|
|
209
|
+
*Wer den Satz hier aendert, aendert ihn dort von Hand mit.*
|
|
210
|
+
*/
|
|
211
|
+
console.error("Die Firma hat deine Änderungen gespeichert — nur der lokale Merkzettel ließ sich nicht schreiben:");
|
|
179
212
|
console.error(merkzettelSchreiben.meldung);
|
|
180
213
|
return 1;
|
|
181
214
|
}
|
|
182
|
-
// US-3: WAS hochgeladen wurde, nicht nur "fertig"
|
|
215
|
+
// US-3: WAS hochgeladen wurde, nicht nur "fertig" -- die Zeile steht seit
|
|
216
|
+
// Runde 4 oben, vor der Merkzettel-Pruefung (Begruendung dort).
|
|
183
217
|
//
|
|
184
218
|
// 🔑 Der Erklaersatz darunter ist mit Fund F ersatzlos WEGGEFALLEN. Er
|
|
185
219
|
// benannte eine Ausnahme, die es nicht mehr gibt -- fuenf Texte, zwei
|
|
186
220
|
// Richtungen, kein Sonderfall zu lernen. Die Namen kommen aus der Antwort
|
|
187
221
|
// der Route (`uebernommen`), nicht aus einer zweiten Liste hier.
|
|
188
|
-
console.log(`✓ hochgeschickt: ${ergebnis.uebernommen.join(", ")}`);
|
|
189
222
|
return 0;
|
|
190
223
|
}
|
|
191
224
|
/** Prueft die Antwort-Form von POST, ohne `any`. */
|
|
@@ -2,7 +2,7 @@ import { zerlege } from "../argumente.js";
|
|
|
2
2
|
import { ruf } from "../api.js";
|
|
3
3
|
import { heuteAus } from "../nachricht.js";
|
|
4
4
|
import { istUnsichererPfad } from "../arbeitsplatz-dateien.js";
|
|
5
|
-
import { LEER, VERWALTETE_DATEIEN, alsMerkzettel, sicherungsOrdner, sicherungsZiel,
|
|
5
|
+
import { LEER, VERWALTETE_DATEIEN, alsMerkzettel, sicherungsOrdner, sicherungsZiel, lageAusMerkzetteln, ratNachUnberuehrt, } from "../kontext-stand.js";
|
|
6
6
|
import { leseEineDatei, leseMerkzettelDatei, schreibeMerkzettelDatei, schreibeVerwalteteDatei, sichereDatei, } from "../kontext-dateien.js";
|
|
7
7
|
import { ERLAUBT, absage, arbeitsplatzOderAbsage } from "./kontext-gemeinsam.js";
|
|
8
8
|
/**
|
|
@@ -85,6 +85,11 @@ export async function kontextRunter(argv) {
|
|
|
85
85
|
const lokalerMerkzettel = leseMerkzettelDatei(ordner);
|
|
86
86
|
const heute = heuteAus(new Date());
|
|
87
87
|
const geschrieben = [];
|
|
88
|
+
// Punkt A-1: die Teilmenge von `geschrieben`, bei der NICHT die Firma etwas
|
|
89
|
+
// geaendert hat, sondern wir unsere eigene Vorlage. Der Mensch soll den
|
|
90
|
+
// Unterschied lesen koennen -- sonst wundert er sich, warum sich eine Datei
|
|
91
|
+
// aendert, an der seine Firma nachweislich nichts getan hat.
|
|
92
|
+
const vorlageErneuert = [];
|
|
88
93
|
const gesicherte = [];
|
|
89
94
|
const unberuehrt = [];
|
|
90
95
|
for (const verwalteterPfad of VERWALTETE_DATEIEN) {
|
|
@@ -104,13 +109,26 @@ export async function kontextRunter(argv) {
|
|
|
104
109
|
console.error(lokalGelesen.meldung);
|
|
105
110
|
return 1;
|
|
106
111
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
112
|
+
/*
|
|
113
|
+
🔴 **DIE BEIDEN MERKZETTEL GEHEN ALS GANZES HINEIN -- Punkt A-1,
|
|
114
|
+
2026-08-26.** Hier standen vorher drei Zeilen, die den Eintrag, den
|
|
115
|
+
Firmenstand und den Vordruck-Abdruck einzeln aus den beiden Dateien
|
|
116
|
+
herausklaubten. Genau dieser Schritt war die Blindstelle: Der
|
|
117
|
+
Vordruck-Abdruck wurde nie herausgeklaubt, das Argument war optional,
|
|
118
|
+
und deshalb bekam ein Kunde mit einer bestehenden Datei Verbesserungen
|
|
119
|
+
an unserem Fragenkatalog NIE zu sehen -- der Befehl meldete stattdessen
|
|
120
|
+
„Dein Firmenkontext ist aktuell".
|
|
121
|
+
|
|
122
|
+
🔑 Die Zuordnung „was kommt aus welchem Merkzettel" wohnt jetzt in
|
|
123
|
+
`lageAusMerkzetteln` (`kontext-stand.ts`), wo `check:kontext` sie messen
|
|
124
|
+
kann. *Was gesichert sein muss, gehoert auf die reine Seite.*
|
|
125
|
+
*/
|
|
126
|
+
const lage = lageAusMerkzetteln({
|
|
127
|
+
pfad: verwalteterPfad,
|
|
110
128
|
lokalerInhalt: lokalGelesen.inhalt,
|
|
111
129
|
serverInhalt: serverDatei.inhalt,
|
|
112
|
-
|
|
113
|
-
|
|
130
|
+
lokal: lokalerMerkzettel,
|
|
131
|
+
vomServer: daten.merkzettel,
|
|
114
132
|
});
|
|
115
133
|
if (lage === "beides") {
|
|
116
134
|
// `lokalGelesen.inhalt` ist hier garantiert eine Zeichenkette:
|
|
@@ -130,13 +148,29 @@ export async function kontextRunter(argv) {
|
|
|
130
148
|
nebenVorhandener: sicherung.nebenVorhandener,
|
|
131
149
|
});
|
|
132
150
|
}
|
|
133
|
-
|
|
151
|
+
/*
|
|
152
|
+
🔴 **`vorlage-neuer` schreibt wie `server-neuer` -- und sichert bewusst
|
|
153
|
+
NICHT** (Punkt A-1, 2026-08-26). Diese Lage heisst: Die Datei steht noch
|
|
154
|
+
Zeichen fuer Zeichen so da, wie wir sie zuletzt geliefert haben (die
|
|
155
|
+
Pruefsumme im Merkzettel passt), die Firma hat nichts geaendert -- nur
|
|
156
|
+
WIR haben unsere Frage besser formuliert. Es gibt hier also nichts von
|
|
157
|
+
einem Menschen zu verlieren. Haette er die Datei angefasst, waere die
|
|
158
|
+
Lage `beides` und die Sicherung liefe eine Bedingung weiter oben.
|
|
159
|
+
|
|
160
|
+
⚠️ Bis zu diesem Punkt fiel `vorlage-neuer` durch ALLE drei `if`s: nicht
|
|
161
|
+
geschrieben, nicht gesichert, nicht gemeldet. Der Fall konnte bisher nie
|
|
162
|
+
entstehen, weil die Kette dahinter tot war -- ein Zweig, den niemand
|
|
163
|
+
vermisst hat, weil ihn niemand erreichen konnte.
|
|
164
|
+
*/
|
|
165
|
+
if (lage === "server-neuer" || lage === "beides" || lage === "vorlage-neuer") {
|
|
134
166
|
const geschriebenErg = schreibeVerwalteteDatei(ordner, verwalteterPfad, serverDatei.inhalt);
|
|
135
167
|
if (!geschriebenErg.ok) {
|
|
136
168
|
console.error(geschriebenErg.meldung);
|
|
137
169
|
return 1;
|
|
138
170
|
}
|
|
139
171
|
geschrieben.push(verwalteterPfad);
|
|
172
|
+
if (lage === "vorlage-neuer")
|
|
173
|
+
vorlageErneuert.push(verwalteterPfad);
|
|
140
174
|
}
|
|
141
175
|
if (lage === "lokal-geaendert") {
|
|
142
176
|
unberuehrt.push(verwalteterPfad);
|
|
@@ -155,6 +189,15 @@ export async function kontextRunter(argv) {
|
|
|
155
189
|
Firma, die diese Antwort tatsaechlich beantwortet hat (`waehleFirma` in
|
|
156
190
|
der Route), nicht aus dem Merkzettel-Feld selbst. Wer zu MEHREREN Firmen
|
|
157
191
|
gehoert, soll im Ordner von Firma A niemals lesen "B hat sich geaendert".
|
|
192
|
+
|
|
193
|
+
🔴 **Punkt A-1: MIT DIESER ZEILE HAELT DER MERKZETTEL DEN NEUEN
|
|
194
|
+
VORLAGEN-FINGERABDRUCK FEST.** `daten.merkzettel.dateien` kommt aus der
|
|
195
|
+
Antwort des Servers und traegt je Datei ihr `vorlage` (`alsMerkzettel`
|
|
196
|
+
verlangt es ausdruecklich). Waere es der LOKALE Merkzettel, staende hier
|
|
197
|
+
weiter der Abdruck von gestern -- und der naechste Lauf meldete denselben
|
|
198
|
+
Unterschied noch einmal, Tag fuer Tag. *Der Teil, den man leicht
|
|
199
|
+
uebersieht: Eine Verbesserung, die jeden Tag neu gemeldet wird, ist
|
|
200
|
+
dieselbe Sorte Fehlalarm wie eine, die nie ankommt.*
|
|
158
201
|
*/
|
|
159
202
|
const merkzettelZumSchreiben = { firma_id: daten.firma.id, dateien: daten.merkzettel.dateien };
|
|
160
203
|
const merkzettelSchreiben = schreibeMerkzettelDatei(ordner, merkzettelZumSchreiben);
|
|
@@ -191,6 +234,14 @@ export async function kontextRunter(argv) {
|
|
|
191
234
|
if (geschrieben.length > 0) {
|
|
192
235
|
console.log(`✓ aktualisiert: ${geschrieben.join(", ")}`);
|
|
193
236
|
}
|
|
237
|
+
// 🔴 Punkt A-1: Eine eigene Zeile, kein stilles Mitschreiben. „Aktualisiert"
|
|
238
|
+
// heisst fuer den Leser sonst automatisch „meine Firma hat etwas gesagt" --
|
|
239
|
+
// und dann sucht er in der App eine Aenderung, die es dort nicht gibt.
|
|
240
|
+
if (vorlageErneuert.length > 0) {
|
|
241
|
+
console.log(` Davon aus unserer verbesserten Vorlage: ${vorlageErneuert.join(", ")}`);
|
|
242
|
+
console.log(" Diese Dateien standen noch genau so da, wie wir sie geliefert hatten — es ist nichts\n" +
|
|
243
|
+
" von dir verloren gegangen. Hättest du darin etwas geändert, hätte ich vorher gesichert.");
|
|
244
|
+
}
|
|
194
245
|
// §8: Ein Fehlerfall darf nie denselben Namen tragen wie ein Erfolgsfall --
|
|
195
246
|
// "nichts geschrieben" heisst hier DREI verschiedene Dinge, und die Ausgabe
|
|
196
247
|
// muss sie unterscheiden, nicht nur die Rueckgabe (alle drei geben 0).
|
|
@@ -4,22 +4,21 @@ import { fileURLToPath } from "node:url";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { STEMPEL_MARKE } from "../nachricht.js";
|
|
6
6
|
import { eigeneVersion } from "../version.js";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const VERALTETE_BEFEHLE = [];
|
|
7
|
+
export const VERALTETE_BEFEHLE = [
|
|
8
|
+
/*
|
|
9
|
+
🔴 **Der ERSTE Eintrag ueberhaupt** (2026-08-28). `/k3firma` heisst jetzt
|
|
10
|
+
`/k3analyse`, weil der Befehl Zahlen holt und daraus eine Frage beantwortet
|
|
11
|
+
-- das ist eine Auswertung, und der alte Name sagte nur, WORUEBER sie geht.
|
|
12
|
+
Ohne diese Zeile staenden beide Dateien nebeneinander und taeten dasselbe;
|
|
13
|
+
nur wuerde `k3firma.md` nie wieder gepflegt.
|
|
14
|
+
|
|
15
|
+
⚠️ Damit laeuft `raeumeVeralteteAuf` zum ersten Mal scharf. Der Kommentar
|
|
16
|
+
an der Funktion sagt es selbst: Die Schleife ist nie gelaufen. Deshalb
|
|
17
|
+
gehoert zu diesem Eintrag eine Rot-Probe in BEIDE Richtungen -- eine Datei
|
|
18
|
+
MIT unserer Marke muss verschwinden, eine OHNE muss liegen bleiben.
|
|
19
|
+
*/
|
|
20
|
+
{ alt: "k3firma.md", ersetztDurch: "k3analyse.md" },
|
|
21
|
+
];
|
|
23
22
|
/**
|
|
24
23
|
* Woran wir unsere eigenen Befehlsdateien erkennen.
|
|
25
24
|
*
|
|
@@ -344,7 +343,42 @@ function slashBefehleInstallieren() {
|
|
|
344
343
|
console.error(`Die Slash-Befehle liessen sich nicht alle schreiben: ${String(fehler)}`);
|
|
345
344
|
gestoert = true;
|
|
346
345
|
}
|
|
347
|
-
|
|
346
|
+
/*
|
|
347
|
+
🔴 **NUR aufraeumen, wenn das Schreiben durchlief** (Review-Runde 2,
|
|
348
|
+
2026-08-28). Der Aufruf stand ausserhalb des `try` und lief deshalb auch
|
|
349
|
+
nach einem Fehler -- mit einer boesen Folge: `k3firma.md` wird geloescht,
|
|
350
|
+
obwohl `k3analyse.md` womoeglich nie geschrieben wurde. Der Mensch haette
|
|
351
|
+
danach **keinen von beiden** Befehlen.
|
|
352
|
+
|
|
353
|
+
⚠️ Und der Fall ist naeher, als er klingt: Die Dateien werden alphabetisch
|
|
354
|
+
kopiert, `k3analyse.md` ist die ZWEITE. Ein Rechteproblem oder eine volle
|
|
355
|
+
Platte genau dort genuegt.
|
|
356
|
+
|
|
357
|
+
🔑 Die sichere Richtung ist eindeutig: Lieber traegt jemand den alten
|
|
358
|
+
Befehl eine Runde laenger mit sich herum, als dass er ohne dasteht. Ein
|
|
359
|
+
zweiter Lauf holt beides nach -- der Rueckgabewert sagt ihm das ohnehin.
|
|
360
|
+
*/
|
|
361
|
+
/*
|
|
362
|
+
🔴 **Nachgeschaerft in Runde 3.** Die erste Fassung hiess `if (!gestoert)`
|
|
363
|
+
und deckte nur EINE der drei Arten ab, auf die eine Datei nicht landet:
|
|
364
|
+
`gestoert` (eine Ausnahme beim Kopieren) -- aber nicht `unlesbar` und nicht
|
|
365
|
+
`uebersprungen` (dort liegt eine Datei OHNE unsere Marke, die wir bewusst
|
|
366
|
+
stehen lassen). In beiden Faellen waere `k3firma.md` geloescht worden,
|
|
367
|
+
obwohl `k3analyse.md` nie geschrieben wurde.
|
|
368
|
+
|
|
369
|
+
🔑 Die Bedingung trifft jetzt die Absicht direkt: **Ein alter Name wird nur
|
|
370
|
+
entfernt, wenn sein Ersatz wirklich liegt.** Steht kein Ersatz in der
|
|
371
|
+
Tabelle, gilt der Eintrag als ersatzlos gestrichen und darf immer weg.
|
|
372
|
+
*/
|
|
373
|
+
/*
|
|
374
|
+
⚠️ **Beide Schreibweisen, genau wie `raeumeVeralteteAuf`** (Review-Runde 4).
|
|
375
|
+
`VERALTETE_BEFEHLE` nimmt `"k3alt"` UND `"k3alt.md"`; `geschrieben` traegt
|
|
376
|
+
immer den Dateinamen. Ohne die Angleichung schluege der Vergleich fehl, und
|
|
377
|
+
ein Eintrag ohne `.md` bliebe fuer immer liegen.
|
|
378
|
+
*/
|
|
379
|
+
const alsDatei = (n) => (n.endsWith(".md") ? n : `${n}.md`);
|
|
380
|
+
const ersatzLiegt = VERALTETE_BEFEHLE.filter((e) => e.ersetztDurch === null || geschrieben.includes(alsDatei(e.ersetztDurch))).map((e) => e.alt);
|
|
381
|
+
raeumeVeralteteAuf(zielOrdner, ersatzLiegt);
|
|
348
382
|
return {
|
|
349
383
|
geschrieben: geschrieben.map((n) => n.replace(/\.md$/, "")),
|
|
350
384
|
uebersprungen: uebersprungen.map((n) => n.replace(/\.md$/, "")),
|
package/dist/befehle/werkbank.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { existsSync, statSync } from "node:fs";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
|
-
import { dateienSchreiben, istUnsichererOrdnername, vorlageHolen, werkbankOrdner, } from "../arbeitsplatz-dateien.js";
|
|
3
|
+
import { FIRMEN_OPTIONEN, dateienSchreiben, istUnsichererOrdnername, vorlageHolen, werkbankOrdner, } from "../arbeitsplatz-dateien.js";
|
|
4
|
+
import { alsBefehlszeile, alsWort, trenneNamenUndOptionen, zerlege } from "../argumente.js";
|
|
4
5
|
import { werkbankOrdnerAus, werkbankUmbenennen } from "../werkbank-name.js";
|
|
6
|
+
import { FIRMEN_CLAUDE_MD, MERKZETTEL_PFAD, firmenAbgleich, firmennameAusClaudeMd, leseMerkzettel, } from "../kontext-stand.js";
|
|
7
|
+
import { leseEineDatei, leseMerkzettelDatei } from "../kontext-dateien.js";
|
|
5
8
|
/**
|
|
6
9
|
* Legt **nur eine Werkbank** an — in einem Firmen-Ordner, der schon steht.
|
|
7
10
|
*
|
|
@@ -54,7 +57,7 @@ import { werkbankOrdnerAus, werkbankUmbenennen } from "../werkbank-name.js";
|
|
|
54
57
|
* darf ein lokaler Befehl nicht überschreiben.
|
|
55
58
|
*/
|
|
56
59
|
const HILFE = `
|
|
57
|
-
kimal3 werkbank neu [dein-vorname]
|
|
60
|
+
kimal3 werkbank neu [dein-vorname] [--firma "Name" | --firma-id "…"]
|
|
58
61
|
|
|
59
62
|
Legt eine eigene Werkbank in einem bestehenden Firmen-Ordner an.
|
|
60
63
|
Die Firmenebene (kontext/, CLAUDE.md, README.md) wird NICHT angefasst.
|
|
@@ -63,6 +66,12 @@ const HILFE = `
|
|
|
63
66
|
wird "werkbank-sabine". Ohne Angabe steht dort der Name,
|
|
64
67
|
den der Server aus deiner Anmelde-Adresse gebildet hat.
|
|
65
68
|
|
|
69
|
+
--firma "Name" Noetig, wenn du zu mehreren Firmen gehoerst.
|
|
70
|
+
Die Absage nennt dir die Namen als fertige Befehle.
|
|
71
|
+
|
|
72
|
+
--firma-id "…" Fuer den Fall, dass zwei deiner Firmen GLEICH heissen.
|
|
73
|
+
Auch diese Absage nennt dir fertige Befehle.
|
|
74
|
+
|
|
66
75
|
🔴 Bricht ab, wenn der Zielordner schon existiert und NICHT leer ist.
|
|
67
76
|
|
|
68
77
|
Du hast noch gar keinen Firmen-Ordner?
|
|
@@ -94,7 +103,7 @@ const HILFE = `
|
|
|
94
103
|
* Eingestaendnis, dass man es nicht weiss -- hier weiss man es.*
|
|
95
104
|
*/
|
|
96
105
|
function hinweisFuer(ordnerName) {
|
|
97
|
-
const ziel = ordnerName
|
|
106
|
+
const ziel = alsWort(ordnerName);
|
|
98
107
|
return (" Ist das DEINE Werkbank? Dann steht sie schon -- geh einfach hinein:\n" +
|
|
99
108
|
` cd ${ziel}\n` +
|
|
100
109
|
" Bist du es nicht, nimm deinen eigenen Vornamen:\n" +
|
|
@@ -116,37 +125,58 @@ export async function werkbankNeu(argv) {
|
|
|
116
125
|
`werkbank-werkbank-sabine` zu bauen. *Alte Anleitungen ueberleben laenger
|
|
117
126
|
als der Code, den sie beschreiben.*
|
|
118
127
|
*/
|
|
119
|
-
|
|
128
|
+
/*
|
|
129
|
+
🔴 **Erst schneiden, dann zerlegen** -- wortgleich zum Zwilling in
|
|
130
|
+
`arbeitsplatz.ts` (Punkt A-3, 2026-08-26). Dieser Befehl hat ein Wort OHNE
|
|
131
|
+
`--` (den Vornamen), und `zerlege` lehnt genau das ab.
|
|
132
|
+
*/
|
|
133
|
+
const { woerter, optionen: optionsArgv } = trenneNamenUndOptionen(argv);
|
|
134
|
+
const nameArg = woerter[0];
|
|
120
135
|
if (nameArg !== undefined && nameArg.trim() === "") {
|
|
121
136
|
console.error(`Ein leerer Name ist kein gueltiger Name.\n${HILFE}`);
|
|
122
137
|
return 1;
|
|
123
138
|
}
|
|
124
|
-
if (
|
|
125
|
-
console.error(`Die Option „${nameArg}" kenne ich nicht.\n${HILFE}`);
|
|
126
|
-
return 1;
|
|
127
|
-
}
|
|
128
|
-
if (argv.length > 1) {
|
|
139
|
+
if (woerter.length > 1) {
|
|
129
140
|
/*
|
|
130
141
|
🔴 **Der Vorschlag darf keine Optionen einsammeln** (Review-Runde 5 zu
|
|
131
142
|
PR #25). Hier stand `argv.join("-")` -- aus `werkbank neu sabine --force`
|
|
132
|
-
wurde damit der Rat `werkbank neu sabine---force`.
|
|
133
|
-
Zeilen hoeher sieht nur `argv[0]`.
|
|
143
|
+
wurde damit der Rat `werkbank neu sabine---force`.
|
|
134
144
|
*Ein Rat, der ein falsches Kommando erzeugt, ist schlimmer als keiner* --
|
|
135
145
|
dieselbe Klasse wie die Absagen aus Runde 1 und 2, nur kleiner.
|
|
136
146
|
|
|
137
147
|
Deshalb: Sieht irgendein Wort wie eine Option aus, gibt es gar keinen
|
|
138
148
|
Vorschlag. Ein Mensch, der `--force` tippt, sucht keine Schreibhilfe fuer
|
|
139
149
|
seinen Vornamen.
|
|
150
|
+
|
|
151
|
+
⚠️ Seit dem 2026-08-26 stehen die `--`-Optionen schon gar nicht mehr in
|
|
152
|
+
`woerter` (der Schnitt oben). Der Filter bleibt trotzdem: Er faengt das
|
|
153
|
+
EINFACHE `-` (`-force`), das kein Schnitt-Zeichen ist.
|
|
140
154
|
*/
|
|
141
|
-
const
|
|
142
|
-
|
|
155
|
+
const einfacheWoerter = woerter.filter((w) => !w.startsWith("-"));
|
|
156
|
+
/*
|
|
157
|
+
🔴 **Die getippten Optionen reisen mit** (Review-Befund 3, 2026-08-26).
|
|
158
|
+
Ohne sie riet die Zeile zu einem Befehl, der bei einem Menschen in zwei
|
|
159
|
+
Firmen sofort wieder in dieselbe Absage laeuft -- s. `alsBefehlszeile`.
|
|
160
|
+
*/
|
|
161
|
+
const optionsAnhang = optionsArgv.length === 0 ? "" : ` ${alsBefehlszeile(optionsArgv)}`;
|
|
162
|
+
const vorschlag = einfacheWoerter.length === woerter.length
|
|
143
163
|
? `Besteht dein Name aus mehreren Woertern? Dann schreib ihn zusammen:\n` +
|
|
144
|
-
` kimal3 werkbank neu ${
|
|
164
|
+
` kimal3 werkbank neu ${einfacheWoerter.join("-")}${optionsAnhang}\n`
|
|
145
165
|
: "";
|
|
146
|
-
console.error(`Mit „${
|
|
166
|
+
console.error(`Mit „${woerter[1]}" kann ich hier nichts anfangen -- nur EIN Name ist erlaubt.\n` +
|
|
147
167
|
`${vorschlag}${HILFE}`);
|
|
148
168
|
return 1;
|
|
149
169
|
}
|
|
170
|
+
// 🔑 Erst NACH den Namens-Absagen -- s. Zwilling in `arbeitsplatz.ts`.
|
|
171
|
+
const zerlegt = zerlege(optionsArgv, FIRMEN_OPTIONEN);
|
|
172
|
+
if (!zerlegt.ok) {
|
|
173
|
+
console.error(`${zerlegt.meldung}\n${HILFE}`);
|
|
174
|
+
return 1;
|
|
175
|
+
}
|
|
176
|
+
const wunsch = {
|
|
177
|
+
firma: zerlegt.werte.optionen.firma,
|
|
178
|
+
firmaId: zerlegt.werte.optionen["firma-id"],
|
|
179
|
+
};
|
|
150
180
|
// `null` heisst: nach dem Umschreiben blieb kein Zeichen uebrig, das in einem
|
|
151
181
|
// Ordnernamen stehen darf. Ein Mensch hat hier getippt und verdient eine
|
|
152
182
|
// Antwort -- der Server schweigt im selben Fall und bleibt beim Vordruck.
|
|
@@ -161,7 +191,17 @@ export async function werkbankNeu(argv) {
|
|
|
161
191
|
return 1;
|
|
162
192
|
}
|
|
163
193
|
}
|
|
164
|
-
|
|
194
|
+
/*
|
|
195
|
+
🔴 **HIER ENTSCHEIDET SICH, OB UEBERHAUPT ETWAS ENTSTEHT** (Punkt A-3) --
|
|
196
|
+
dieselbe Stelle wie beim Zwilling: Bei mehreren Firmen ohne Angabe kommt
|
|
197
|
+
`409`, dieser Aufruf endet mit `1`, und `dateienSchreiben` weiter unten
|
|
198
|
+
wird nie erreicht.
|
|
199
|
+
*/
|
|
200
|
+
// 🔑 Der getippte Vorname reist in der Absage mit -- s. Zwilling.
|
|
201
|
+
const befehlsname = nameArg === undefined
|
|
202
|
+
? "werkbank neu"
|
|
203
|
+
: `werkbank neu ${alsWort(nameArg)}`;
|
|
204
|
+
const holen = await vorlageHolen(befehlsname, wunsch);
|
|
165
205
|
if (!holen.ok)
|
|
166
206
|
return holen.wert;
|
|
167
207
|
const daten = holen.daten;
|
|
@@ -305,6 +345,77 @@ export async function werkbankNeu(argv) {
|
|
|
305
345
|
console.error(" verschiedene Firmenordner mit verschiedenen Regeln darin.");
|
|
306
346
|
return 1;
|
|
307
347
|
}
|
|
348
|
+
/*
|
|
349
|
+
🔴 **STEHT DIE GELIEFERTE FIRMA UEBERHAUPT HIER?** (Befund 1 der zweiten
|
|
350
|
+
Review-Runde, 2026-08-27.)
|
|
351
|
+
|
|
352
|
+
Bis hierher ist geprueft, dass NEBEN uns eine Firmenebene liegt -- aber
|
|
353
|
+
nicht, ob es DIE Firma ist, deren Namen die Lieferung gleich in die
|
|
354
|
+
`werkbank-<name>/CLAUDE.md` schreibt. Seit A-11 ist das keine Kosmetik
|
|
355
|
+
mehr: Dort stand frueher fuer jede Firma derselbe Platzhalter, jetzt steht
|
|
356
|
+
dort ein Name, den Claude bei jedem Start liest. Die ganze Fallgeschichte
|
|
357
|
+
haengt an `firmenAbgleich` in `../kontext-stand.js`.
|
|
358
|
+
|
|
359
|
+
🔑 **Der Vergleich laeuft ueber die IDs im Merkzettel** -- der des Ordners,
|
|
360
|
+
in dem wir stehen, gegen den, der gerade geliefert wurde. Beide Seiten
|
|
361
|
+
kennen ihre Firma aus derselben Quelle, es wird nichts geraten.
|
|
362
|
+
|
|
363
|
+
🔴 **UND ER STEHT VOR `dateienSchreiben`.** Ein Abbruch hier hinterlaesst
|
|
364
|
+
keine halbe Werkbank -- dieselbe Haltung wie in `kontextHoch`
|
|
365
|
+
(„ich schicke nichts Halbes hoch“).
|
|
366
|
+
*/
|
|
367
|
+
const inhaltAus = (pfad) => daten.dateien.find((d) => d.pfad === pfad)?.inhalt ?? null;
|
|
368
|
+
const hierGelesen = leseEineDatei(process.cwd(), FIRMEN_CLAUDE_MD);
|
|
369
|
+
const abgleich = firmenAbgleich({
|
|
370
|
+
id: leseMerkzettelDatei(process.cwd()).firma_id,
|
|
371
|
+
name: firmennameAusClaudeMd(hierGelesen.ok ? hierGelesen.inhalt : null),
|
|
372
|
+
}, {
|
|
373
|
+
id: leseMerkzettel(inhaltAus(MERKZETTEL_PFAD)).firma_id,
|
|
374
|
+
name: firmennameAusClaudeMd(inhaltAus(FIRMEN_CLAUDE_MD)),
|
|
375
|
+
});
|
|
376
|
+
/*
|
|
377
|
+
🔴 **DER VERDACHT WARNT, ER SPERRT NICHT** (Befund 1 der vierten
|
|
378
|
+
Review-Runde). Steht der Name nur deshalb anders da, weil jemand die
|
|
379
|
+
`CLAUDE.md` seiner Firma bearbeitet hat -- was er ausdruecklich darf --,
|
|
380
|
+
waere eine Absage falsch UND ausweglos. Die Zeile hier sagt, was sie
|
|
381
|
+
sieht, und laesst den Menschen entscheiden.
|
|
382
|
+
*/
|
|
383
|
+
if (abgleich.art === "zweifel") {
|
|
384
|
+
console.error(`Achtung: Dieser Ordner nennt als Firma „${abgleich.hier}",`);
|
|
385
|
+
console.error(`du hast aber „${abgleich.gewaehlt}" gewaehlt.`);
|
|
386
|
+
console.error("Ich lege die Werkbank trotzdem an -- vielleicht heisst die Firma bei euch");
|
|
387
|
+
console.error("nur anders geschrieben. Stimmt es nicht, loesch den neuen Ordner wieder.");
|
|
388
|
+
console.error("");
|
|
389
|
+
}
|
|
390
|
+
if (abgleich.art === "andere-firma") {
|
|
391
|
+
/*
|
|
392
|
+
🔴 **ZWEI LAGEN, ZWEI SAETZE** (Befund 3 der dritten Review-Runde). Hier
|
|
393
|
+
stand ein Rueckfall `?? "die genannte Firma"`, und der war erreichbar:
|
|
394
|
+
Wer zu genau EINER Firma gehoert, tippt gar kein `--firma`. Steht er im
|
|
395
|
+
Ordner einer anderen Firma, las er woertlich *„Dieser Ordner gehoert zu
|
|
396
|
+
einer ANDEREN Firma als ‚die genannte Firma'."* -- ein Satz, der nichts
|
|
397
|
+
benennt und wie ein Fehler im Programm aussieht.
|
|
398
|
+
*Ein Platzhalter in einer Meldung ist ein Satz, den niemand geschrieben
|
|
399
|
+
hat.*
|
|
400
|
+
*/
|
|
401
|
+
const genannt = wunsch.firma ?? wunsch.firmaId;
|
|
402
|
+
if (genannt === undefined) {
|
|
403
|
+
console.error("Dieser Ordner gehoert zu einer anderen Firma als der, zu der du gehoerst.");
|
|
404
|
+
console.error("Ich lege hier keine Werkbank an, die einen fremden Firmennamen traegt --");
|
|
405
|
+
console.error("sie wuerde Claude bei jedem Start die falsche Firma nennen.");
|
|
406
|
+
console.error("");
|
|
407
|
+
console.error(" Deine Werkbank gehoert in den Ordner DEINER Firma. Geh dorthin und");
|
|
408
|
+
console.error(" versuch es dort noch einmal.");
|
|
409
|
+
return 1;
|
|
410
|
+
}
|
|
411
|
+
console.error(`Dieser Ordner gehoert zu einer ANDEREN Firma als „${genannt}".`);
|
|
412
|
+
console.error("Ich lege hier keine Werkbank an, die einen fremden Firmennamen traegt --");
|
|
413
|
+
console.error("sie wuerde Claude bei jedem Start die falsche Firma nennen.");
|
|
414
|
+
console.error("");
|
|
415
|
+
console.error(` Soll die Werkbank fuer „${genannt}" sein? Dann gehoert sie in DEREN Ordner.`);
|
|
416
|
+
console.error(" Soll sie fuer die Firma hier sein? Dann nimm deren Namen.");
|
|
417
|
+
return 1;
|
|
418
|
+
}
|
|
308
419
|
/*
|
|
309
420
|
🔑 Der Zielordner ist der Werkbank-Name -- entweder der, den der Server
|
|
310
421
|
schon gesetzt hat (`werkbank`, aus der Anmelde-Adresse gebildet), oder der
|
|
@@ -351,7 +462,7 @@ export async function werkbankNeu(argv) {
|
|
|
351
462
|
console.log(" Die Firmenebene ist unberuehrt geblieben.");
|
|
352
463
|
console.log("");
|
|
353
464
|
console.log(" Weiter geht's:");
|
|
354
|
-
console.log(` cd ${ordnerName
|
|
465
|
+
console.log(` cd ${alsWort(ordnerName)}`);
|
|
355
466
|
console.log(" claude");
|
|
356
467
|
console.log(' dann "Lass uns einrichten" tippen');
|
|
357
468
|
return 0;
|
package/dist/befehle-katalog.js
CHANGED
|
@@ -42,7 +42,13 @@ export const BEFEHLE = [
|
|
|
42
42
|
tippen: "! kimal3 skill install",
|
|
43
43
|
terminal: "kimal3 skill install",
|
|
44
44
|
details: [
|
|
45
|
-
|
|
45
|
+
// ⚠️ KEINE Anzahl hier (Review-Runde 5): Hier stand „deine vier
|
|
46
|
+
// Slash-Befehle“, und die Zahl war ab `/k3kontext` falsch — auf der
|
|
47
|
+
// Pro-Seite UND in der Terminal-Hilfe, denn dieser Text wird an beiden
|
|
48
|
+
// Stellen ausgegeben. Dieselbe Lehre wie bei „13 Pruefungen“ in
|
|
49
|
+
// `check:arbeitsplatz`: Eine Anzahl im Fliesstext ist eine Behauptung,
|
|
50
|
+
// die verrottet. Welche es sind, sagt `/k3` beim Laufen.
|
|
51
|
+
"Der Befehl, der aus den anderen erst etwas macht: Er legt 🤖 Claudes Anleitung ab (den „Skill“) und 🧑 deine Slash-Befehle.",
|
|
46
52
|
"Er läuft NICHT automatisch — einmal nach der Installation, und nach jedem Update noch einmal. Sonst arbeitet Claude weiter mit der alten Anleitung.",
|
|
47
53
|
"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
54
|
],
|
|
@@ -108,10 +114,10 @@ export const BEFEHLE = [
|
|
|
108
114
|
},
|
|
109
115
|
{
|
|
110
116
|
befehl: "kimal3 kontext fragen",
|
|
111
|
-
beschreibung: "
|
|
112
|
-
wer: "
|
|
113
|
-
|
|
114
|
-
tippen: "
|
|
117
|
+
beschreibung: "Die Fragen über deine Firma beantworten — Claude führt dich durch",
|
|
118
|
+
wer: "claude",
|
|
119
|
+
ausloeser: "beantworten wir die Fragen über meine Firma",
|
|
120
|
+
tippen: "/k3kontext",
|
|
115
121
|
terminal: "kimal3 kontext fragen",
|
|
116
122
|
details: [
|
|
117
123
|
"Liest die fünf Dateien in kontext/ und gibt jede Frage aus, unter der noch nichts steht — mit Datei, Frage und Hinweis. Sind alle beantwortet, sagt er das in einem Satz.",
|
|
@@ -128,7 +134,8 @@ export const BEFEHLE = [
|
|
|
128
134
|
terminal: "kimal3 kontext hoch",
|
|
129
135
|
details: [
|
|
130
136
|
"Schickt alle fünf Firmen-Texte an deine Firma — die Dateien in kontext/ (kurzprofil.md, firma.md, marke.md, systeme.md, sicherheit.md). Damit kommen sie beim nächsten kontext runter auch bei den Kolleginnen und Kollegen an.",
|
|
131
|
-
"🔴 Nur der Firmen-Admin darf das. Bist du keiner,
|
|
137
|
+
"🔴 Nur der Firmen-Admin darf das. Bist du keiner, sagt er es dir — dann gib deine Ergänzung an den Admin weiter, ein zweiter Versuch ändert daran nichts.",
|
|
138
|
+
"⚠️ Klappt etwas nicht, zählt die MELDUNG, nicht die Zahl dahinter: Dieselbe 1 steht für „du bist kein Admin“, „hier steht kein Arbeitsplatz“, „jemand anderes hat inzwischen geändert“ (Ausweg --ueberschreiben) und mehreres mehr. Sie steht sogar unter einer Meldung, die mit „Die Firma hat deine Änderungen gespeichert“ beginnt und nur sagt, dass eine Datei auf deiner Platte nicht geschrieben werden konnte — DAS ist ein Erfolg: alles ist oben angekommen. Lies den Satz, nicht die Zahl.",
|
|
132
139
|
"Sieht eine der fünf Dateien nicht mehr aus wie ihre Frageliste — etwa weil etwas Fremdes darüberkopiert wurde —, bricht er ab und schickt gar nichts, auch die vier anderen nicht. kimal3 kontext runter holt die Datei zurück.",
|
|
133
140
|
"Geklappt hat es, wenn er „✓ hochgeschickt“ mit den Dateinamen meldet.",
|
|
134
141
|
],
|
|
@@ -162,7 +169,7 @@ export const BEFEHLE = [
|
|
|
162
169
|
beschreibung: "Die Daten deiner Firma holen, damit Claude sie auswerten kann",
|
|
163
170
|
wer: "claude",
|
|
164
171
|
ausloeser: "werte meine Firma aus",
|
|
165
|
-
tippen: "/
|
|
172
|
+
tippen: "/k3analyse <deine Frage>",
|
|
166
173
|
terminal: 'kimal3 firma daten --firma "Nordwind Handel GmbH"',
|
|
167
174
|
details: [
|
|
168
175
|
"Holt Kennzahlen, Menschen und Projekte deiner Firma — auswerten tut Claude. Frag einfach los: „Welche drei Projekte bringen den meisten messbaren Ertrag?“",
|
package/dist/firmen-liste.js
CHANGED
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
* Die Firmen-Auswahl, die eine Absage dem Menschen anbietet.
|
|
3
3
|
*
|
|
4
4
|
* 🔑 Eine reine Rechnung, damit `check:cli` sie ohne Server pruefen kann --
|
|
5
|
-
* dieselbe Ueberlegung wie bei `fehler.ts`.
|
|
5
|
+
* dieselbe Ueberlegung wie bei `fehler.ts`. `alsWort` unten ist ebenfalls eine
|
|
6
|
+
* reine Rechnung, der Import bricht das also nicht.
|
|
6
7
|
*/
|
|
8
|
+
import { alsWort } from "./argumente.js";
|
|
7
9
|
/**
|
|
8
10
|
* Aus den Namen der eigenen Firmen die Zeilen bauen, die unter „Deine Firmen:"
|
|
9
11
|
* stehen.
|
|
@@ -42,7 +44,7 @@ export function firmenZeilen(namen) {
|
|
|
42
44
|
// Fertiger Befehl statt blosser Liste: Der naechste Schritt ist dann
|
|
43
45
|
// Kopieren statt Abtippen -- und ein Name mit Leerzeichen braucht
|
|
44
46
|
// Anfuehrungszeichen, an die sonst niemand denkt.
|
|
45
|
-
zeilen.push(` kimal3 firma daten --firma
|
|
47
|
+
zeilen.push(` kimal3 firma daten --firma ${alsWort(name, true)}`);
|
|
46
48
|
}
|
|
47
49
|
else {
|
|
48
50
|
zeilen.push(` „${name}" — kommt ${wieOft}× vor und ist über den Namen nicht wählbar.`);
|
package/dist/kimal3.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { existsSync, readFileSync } from "node:fs";
|
|
15
15
|
import { BASIS_URL, leseAnmeldung } from "./anmeldung.js";
|
|
16
|
-
import { gemerkterHinweis, NichtAngemeldet } from "./api.js";
|
|
16
|
+
import { gemerkterHinweis, lokalerKontextStandJetzt, NichtAngemeldet } from "./api.js";
|
|
17
17
|
import { leseGesehen, merkeGesehen } from "./gesehen.js";
|
|
18
18
|
import { formatiere, heuteAus, skillMeldung, skillZustand, sollZeigen, } from "./nachricht.js";
|
|
19
19
|
import { eigeneVersion } from "./version.js";
|
|
@@ -99,8 +99,26 @@ function hinweisText() {
|
|
|
99
99
|
if (eigene === null)
|
|
100
100
|
return null;
|
|
101
101
|
const heute = heuteAus(new Date());
|
|
102
|
+
/*
|
|
103
|
+
🔴 HIER, UND NICHT FRUEHER (offener Punkt A-4). Diese Zeile liest den
|
|
104
|
+
Merkzettel auf der Platte in genau dem Augenblick, in dem der Hinweis
|
|
105
|
+
ausgegeben werden soll -- also NACH dem Befehl.
|
|
106
|
+
|
|
107
|
+
Genau darin lag der Fehler: Den Stand, den der Server fuer seinen
|
|
108
|
+
Hinweis vergleicht, schickt die CLI im Kopf mit, und der wird VOR dem
|
|
109
|
+
Netzaufruf gelesen (`kontextStandKopf` in `api.ts`). Direkt nach
|
|
110
|
+
`kimal3 kontext runter` stand deshalb "Dein Firmenkontext ist aktuell."
|
|
111
|
+
und darunter der Rat, `kimal3 kontext runter` auszufuehren. Der zweite
|
|
112
|
+
Aufruf schwieg dann von selbst -- die Meldung kam schlicht einen Aufruf
|
|
113
|
+
zu spaet.
|
|
114
|
+
|
|
115
|
+
🔑 `sollZeigen` VERLANGT diesen Wert (kein optionales Argument): Wer ihn
|
|
116
|
+
hier vergisst, bekommt einen Uebersetzungsfehler statt einer Rechnung,
|
|
117
|
+
die niemand mehr benutzt.
|
|
118
|
+
*/
|
|
119
|
+
const standJetzt = lokalerKontextStandJetzt();
|
|
102
120
|
const h = gemerkterHinweis();
|
|
103
|
-
if (h && sollZeigen(h, eigene, leseGesehen(), heute)) {
|
|
121
|
+
if (h && sollZeigen(h, eigene, leseGesehen(), heute, standJetzt)) {
|
|
104
122
|
// Hoechstens EIN Hinweis je Aufruf -- zwei sind eine Wand.
|
|
105
123
|
return { text: formatiere(h), kennung: h.id, tag: heute };
|
|
106
124
|
}
|