kimal3 0.2.6 โ†’ 0.2.7

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/kimal3.js CHANGED
@@ -32,6 +32,119 @@ import { projektListe } from "./befehle/projekt-liste.js";
32
32
  import { projektNeu } from "./befehle/projekt-neu.js";
33
33
  import { skillDatei, skillInstall } from "./befehle/skill-install.js";
34
34
  import { wache, wacheSchalten } from "./befehle/wache.js";
35
+ /** Eine Meldung pro Programmlauf -- s. "Einmal-Riegel" im Block darunter. */
36
+ let schonGemeldet = false;
37
+ /**
38
+ * Die gekappte Leitung macht keinen Laerm mehr (D-27).
39
+ *
40
+ * ๐Ÿ”ด WARUM DAS HIER STEHT UND NICHT IN `endeMitHinweis`: Ein Schreibfehler auf
41
+ * STDOUT/STDERR kommt NICHT als Wurf zurueck, den ein try/catch faengt --
42
+ * er kommt als `'error'`-EREIGNIS auf dem Kanal selbst. Ohne angemeldeten
43
+ * Empfaenger behandelt Node ein unbehandeltes `'error'`-Ereignis als
44
+ * Programmabbruch, egal WELCHE Zeile gerade schreibt. Und geschrieben wird
45
+ * schon lange vor `endeMitHinweis` -- `haupt()` gibt bei `--version`, `--help`
46
+ * und jedem Befehl selbst aus. Der Empfaenger muss deshalb angemeldet sein,
47
+ * BEVOR die erste Zeile faellt: hier, auf Modulebene, noch vor jedem Aufruf.
48
+ *
49
+ * Gemessen (`npm run check:cli-live`, Fall a): Leitet ein Kunde
50
+ * `kimal3 --version | head -1`, schliesst `head` die Leitung, sobald es seine
51
+ * eine Zeile hat -- der naechste Schreibversuch von kimal3 trifft auf einen
52
+ * toten Empfaenger. Ohne diesen Empfaenger hier wirft das eine rote
53
+ * Stapelspur auf den Bildschirm, fuer einen Befehl, der laengst fertig war.
54
+ *
55
+ * โš ๏ธ EPIPE SCHLUCKEN, ABER NICHT ALLES (Technische Notiz der Aufgabe): Eine
56
+ * gekappte Leitung ist kein Fehler, den man MELDEN koennte -- der Empfaenger
57
+ * ist weg, niemand liest eine Meldung. Jeder ANDERE Kanalfehler ist einer und
58
+ * darf nicht stillschweigend verschwinden -- sonst truege ein Fehlerfall
59
+ * denselben Namen wie ein Erfolgsfall (vgl. die Regel zu `bestaetigungen-
60
+ * Aktivieren` in der Projekt-CLAUDE.md). Deshalb wird der Rueckgabewert auf 1
61
+ * gesetzt -- und die Meldung geht, wenn ueberhaupt, auf den FEHLERkanal.
62
+ *
63
+ * ๐Ÿ”ด UND DIE MELDUNG GEHT NIE IN DEN DATENKANAL -- die Ungleichheit der zwei
64
+ * Kanaele IST der Bauplan, keine Ausnahme (Befund W-1a der Gesamt-Durchsicht,
65
+ * 2026-09-12). Hier stand vorher "sag es auf dem JEWEILS ANDEREN Kanal", und
66
+ * das war fuer einen der zwei Faelle falsch:
67
+ * ยท Bricht der DATENkanal (stdout), darf auf dem Fehlerkanal gemeldet
68
+ * werden -- der ist genau dafuer da.
69
+ * ยท Bricht der FEHLERkanal (stderr), wird NIRGENDS gemeldet. Auf stdout
70
+ * liegt die Maschinenform: das JSON von `firma daten` und die JSON-Huelle
71
+ * von `wache --hook`, die Claude Code parst. Ein deutscher Satz
72
+ * mittendrin macht `JSON.parse` ueber die ganze Ausgabe unmoeglich -- und
73
+ * genau das verbietet US-1 ("nie mittendrin") schon fuer den
74
+ * Update-Hinweis in `endeMitHinweis`. Dann ist der Rueckgabewert die
75
+ * ehrliche Auskunft; der Datenkanal ist keine Protokollzeile wert.
76
+ * Gemessen vor der Reparatur: `quatschbefehl` mit nur-lesbarem stderr legte
77
+ * `kimal3: Ausgabekanal-Fehler -- EBADF ...` auf stdout.
78
+ *
79
+ * ๐Ÿ”ด UND EIN EINMAL-RIEGEL, DAMIT DAS PROGRAMM UEBERHAUPT ENDET (Befund W-1b,
80
+ * dieselbe Durchsicht): Solange beide Empfaenger einander anschrieben, erzeugte
81
+ * jeder Schreibversuch das naechste `'error'`-Ereignis auf dem anderen Kanal --
82
+ * bei ZWEI kaputten Kanaelen (eine volle Platte genuegt:
83
+ * `kimal3 firma daten > a.json 2> b.txt` -> ENOSPC auf beiden) endete das
84
+ * Programm damit NIE. Gemessen: nach 8 Sekunden noch da, musste abgeschossen
85
+ * werden; dieselbe Lage ohne die Empfaenger endete in 36 ms. Und die
86
+ * 2-Sekunden-Notbremse half nicht: Sie wird erst IN `endeMitHinweis` gestellt
87
+ * und vom Ereignis-Pingpong ausgehungert. `schonGemeldet` schneidet das ab --
88
+ * eine Meldung pro Programmlauf, mehr braucht niemand.
89
+ *
90
+ * ๐Ÿ”‘ KEIN `process.exit` HIER (Constraint 2): Nur `exitCode` wird gesetzt --
91
+ * das Programm endet von selbst, sobald kein Ereignis mehr nachkommt, und
92
+ * genau dafuer sorgt der Einmal-Riegel.
93
+ *
94
+ * Registriert wird das genau EINMAL pro Kanal, hier -- nicht an jeder
95
+ * einzelnen Schreibstelle. `console.log`/`console.error` UND die zwei
96
+ * direkten `process.stdout.write`/`process.stderr.write`-Aufrufe in
97
+ * `endeMitHinweis` schreiben alle auf DIESELBEN zwei Stream-Objekte
98
+ * (`process.stdout`, `process.stderr` sind pro Prozess EINMALIG vorhanden);
99
+ * ein Empfaenger auf dem Stream selbst deckt deshalb jede Schreibstelle im
100
+ * ganzen Programm ab, auch die in den einzelnen `befehle/*.ts`-Dateien.
101
+ */
102
+ /**
103
+ * @param meldenAuf Wohin die Meldung darf -- oder `null` fuer "nirgends".
104
+ * `null` steht fuer den Fehlerkanal selbst: Ist ER kaputt, bleibt nur der
105
+ * Rueckgabewert, denn der Datenkanal gehoert der Maschinenform.
106
+ */
107
+ function gegenUnbehandelteKanalfehlerAbsichern(kanal, meldenAuf) {
108
+ kanal.on("error", (fehler) => {
109
+ if (fehler.code === "EPIPE")
110
+ return;
111
+ /*
112
+ ๐Ÿ”ด NUR SETZEN, WENN NOCH KEIN FEHLSCHLAG VERMERKT IST (Befund des
113
+ Koordinators, Fix-Runde 1). Ein Kanalfehler kann auftreten, WAEHREND
114
+ gerade eine viel genauere Fehlermeldung geschrieben wird -- der
115
+ `.catch`-Zweig am Dateiende setzt `process.exitCode = 2` ("bitte
116
+ einloggen") bzw. `3` ("nicht erreichbar") direkt NACH dem
117
+ `console.error`-Aufruf, der den Kanalfehler ueberhaupt erst ausloest.
118
+ Ein bedingungsloses `process.exitCode = 1` hier ueberschreibt diese
119
+ genauere Zahl mit der ungenaueren -- gemessen (Koordinator): Ausweis
120
+ fehlt, `projekt liste`, Fehlerkanal nur zum Lesen geoeffnet -> `2` geht
121
+ verloren, es bleibt nur `1`. Das ist derselbe Fehler wie bei
122
+ `bestaetigungenAktivieren` in der Projekt-CLAUDE.md: Ein Fehlerfall darf
123
+ nicht in einen anderen zusammenfallen, denn die Seite (hier: Claude)
124
+ kann nur unterscheiden, was der Rueckgabewert noch unterscheidet.
125
+
126
+ Deshalb: Nur ein UNDEFINIERTER oder ein ERFOLGREICHER (`0`) Stand gilt
127
+ als "noch kein Fehlschlag vermerkt" -- ausdruecklich BEIDE pruefen,
128
+ nicht nur auf `0`, denn `process.exitCode` ist am Programmanfang
129
+ `undefined`, nicht `0`. Jede bereits gesetzte Zahl ungleich `0`
130
+ (`1`, `2`, `3`, `4`) ist die genauere Auskunft und bleibt stehen.
131
+ */
132
+ if (process.exitCode === undefined || process.exitCode === 0)
133
+ process.exitCode = 1;
134
+ if (meldenAuf === null || schonGemeldet)
135
+ return;
136
+ schonGemeldet = true;
137
+ try {
138
+ meldenAuf.write(`kimal3: Ausgabekanal-Fehler -- ${fehler.message}\n`);
139
+ }
140
+ catch {
141
+ // Auch der Fehlerkanal kann kaputt sein -- dann bleibt wenigstens der
142
+ // Rueckgabewert (oben gesetzt) die ehrliche Auskunft.
143
+ }
144
+ });
145
+ }
146
+ gegenUnbehandelteKanalfehlerAbsichern(process.stdout, process.stderr);
147
+ gegenUnbehandelteKanalfehlerAbsichern(process.stderr, null);
35
148
  // ๐Ÿ“Œ Kein handgeschriebener Block mehr (2026-08-18): Die Liste wohnt in
36
149
  // `befehle-katalog.ts` und wird von dort AUCH im Pro-Bereich der App angezeigt.
37
150
  // Zwei Listen ueber dieselben Befehle driften โ€” die eine bekaeme den naechsten
@@ -0,0 +1 @@
1
+ export const x = "das ist keine Zahl";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kimal3",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "description": "Trag deine KI-Projekte dort ein, wo sie entstehen: im Terminal.",
5
5
  "type": "module",
6
6
  "bin": {