@cachly-dev/mcp-server 0.10.123 → 0.10.125

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.
Files changed (85) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +7 -0
  3. package/dist/index.js.map +1 -0
  4. package/dist/src/aussetzer.d.ts +67 -0
  5. package/dist/src/aussetzer.js +82 -0
  6. package/dist/src/aussetzer.js.map +1 -0
  7. package/dist/src/autor-abzeichen.d.ts +41 -0
  8. package/dist/src/autor-abzeichen.js +56 -0
  9. package/dist/src/autor-abzeichen.js.map +1 -0
  10. package/dist/src/autor.d.ts +101 -0
  11. package/dist/src/autor.js +136 -0
  12. package/dist/src/autor.js.map +1 -0
  13. package/dist/src/bauabdruck-daten.generiert.json +5 -0
  14. package/dist/src/bauabdruck.d.ts +38 -0
  15. package/dist/src/bauabdruck.js +93 -0
  16. package/dist/src/bauabdruck.js.map +1 -0
  17. package/dist/src/bedeutung.d.ts +175 -0
  18. package/dist/src/bedeutung.js +254 -0
  19. package/dist/src/bedeutung.js.map +1 -0
  20. package/dist/src/brain-export.d.ts +24 -0
  21. package/dist/src/brain-export.js +31 -1
  22. package/dist/src/brain-export.js.map +1 -1
  23. package/dist/src/deutsch.d.ts +98 -0
  24. package/dist/src/deutsch.js +223 -0
  25. package/dist/src/deutsch.js.map +1 -0
  26. package/dist/src/eingaenge-nachruesten.d.ts +41 -0
  27. package/dist/src/eingaenge-nachruesten.js +290 -0
  28. package/dist/src/eingaenge-nachruesten.js.map +1 -0
  29. package/dist/src/eingaenge.d.ts +135 -0
  30. package/dist/src/eingaenge.js +228 -0
  31. package/dist/src/eingaenge.js.map +1 -0
  32. package/dist/src/geliefert.d.ts +63 -0
  33. package/dist/src/geliefert.js +114 -0
  34. package/dist/src/geliefert.js.map +1 -0
  35. package/dist/src/handlers/advanced.js +7 -3
  36. package/dist/src/handlers/advanced.js.map +1 -1
  37. package/dist/src/handlers/brain.d.ts +19 -0
  38. package/dist/src/handlers/brain.js +492 -48
  39. package/dist/src/handlers/brain.js.map +1 -1
  40. package/dist/src/handlers/instances.d.ts +24 -0
  41. package/dist/src/handlers/instances.js +49 -1
  42. package/dist/src/handlers/instances.js.map +1 -1
  43. package/dist/src/handlers/team.js +105 -0
  44. package/dist/src/handlers/team.js.map +1 -1
  45. package/dist/src/index.d.ts +20 -0
  46. package/dist/src/index.js +282 -36
  47. package/dist/src/index.js.map +1 -1
  48. package/dist/src/lesson-preview.d.ts +81 -0
  49. package/dist/src/lesson-preview.js +133 -0
  50. package/dist/src/lesson-preview.js.map +1 -0
  51. package/dist/src/rangfolge.d.ts +169 -0
  52. package/dist/src/rangfolge.js +214 -0
  53. package/dist/src/rangfolge.js.map +1 -0
  54. package/dist/src/raumkorrektur.d.ts +100 -0
  55. package/dist/src/raumkorrektur.js +197 -0
  56. package/dist/src/raumkorrektur.js.map +1 -0
  57. package/dist/src/recall-tiefe.d.ts +48 -0
  58. package/dist/src/recall-tiefe.js +42 -0
  59. package/dist/src/recall-tiefe.js.map +1 -0
  60. package/dist/src/rerank.d.ts +0 -14
  61. package/dist/src/rerank.js +39 -2
  62. package/dist/src/rerank.js.map +1 -1
  63. package/dist/src/search.d.ts +56 -17
  64. package/dist/src/search.js +335 -73
  65. package/dist/src/search.js.map +1 -1
  66. package/dist/src/seltenheitsbestand.d.ts +53 -0
  67. package/dist/src/seltenheitsbestand.js +92 -0
  68. package/dist/src/seltenheitsbestand.js.map +1 -0
  69. package/dist/src/spuren.d.ts +97 -0
  70. package/dist/src/spuren.js +150 -0
  71. package/dist/src/spuren.js.map +1 -0
  72. package/dist/src/tools.js +1 -1
  73. package/dist/src/tools.js.map +1 -1
  74. package/dist/src/vorspann.d.ts +73 -0
  75. package/dist/src/vorspann.js +146 -0
  76. package/dist/src/vorspann.js.map +1 -0
  77. package/dist/src/werkzeug-nutzung.d.ts +62 -0
  78. package/dist/src/werkzeug-nutzung.js +72 -0
  79. package/dist/src/werkzeug-nutzung.js.map +1 -0
  80. package/dist/src/wertbeitrag.d.ts +57 -0
  81. package/dist/src/wertbeitrag.js +73 -0
  82. package/dist/src/wertbeitrag.js.map +1 -0
  83. package/glama.json +1 -1
  84. package/package.json +12 -4
  85. package/server.json +2 -2
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Deutsch für die Suche: Umlaute, Wortformen, zusammengesetzte Wörter.
3
+ *
4
+ * ── Warum es dieses Modul gibt ───────────────────────────────────────────────
5
+ *
6
+ * Gemessen am 19.08.2026 an 498 echten Lektionen mit 20 Fragen in Alltags-
7
+ * deutsch: 2 Treffer. Sechs Fragen teilten mit der richtigen Antwort NICHT EIN
8
+ * EINZIGES Wort. Die Aufteilung nach Ursachen (src/bench/wortschatz-oder-
9
+ * menge.ts) zeigte: schon bei 20 Lektionen und null Ablenkern scheitern 14 von
10
+ * 20. Es ist also der Wortschatz, nicht die Menge.
11
+ *
12
+ * Die Suche hatte deutsche Stoppwörter und 35 deutsche Wortpaare. Was fehlte,
13
+ * waren drei Dinge — und alle drei sind an echten Fragen belegt:
14
+ *
15
+ * 1. UMLAUTE. Die Wortliste stand mit echten Umlauten (`lösung`,
16
+ * `überwachung`), Lektionen und Fragen schreiben oft `ae/oe/ue`. Damit
17
+ * fand `ueberwachung` den Eintrag `überwachung` nie. Zwei Schreibweisen
18
+ * desselben Wortes, und die Suche hielt sie für verschieden.
19
+ *
20
+ * 2. WORTFORM. `abhaengigkeiten` gegen `abhaengigkeit`, `prozesse` gegen
21
+ * `prozess`. Für sieben Sprachen gab es einen Stemmer, für Deutsch nicht.
22
+ *
23
+ * 3. ZUSAMMENGESETZTE WÖRTER. Das ist die deutsche Besonderheit und war die
24
+ * größte Lücke. `Arbeitsspeicher` enthält `speicher`, und `speicher` steht
25
+ * längst in der Wortliste — nur kam niemand dort an. Genauso
26
+ * `Zugriffsprotokoll` → `protokoll` → `log`, `Browsertests` → `test`.
27
+ *
28
+ * ── Die Entscheidung, die dieses Modul klein hält ────────────────────────────
29
+ *
30
+ * Für die Zerlegung braucht es ein Wörterbuch der Grundwörter. Es wäre nahe-
31
+ * liegend, dafür eine zweite Liste zu pflegen. Genau das ist die Fehlerklasse,
32
+ * die uns in diesem Haus am häufigsten trifft: eine Wahrheit an zwei Orten.
33
+ *
34
+ * Deshalb: die Wortliste IST das Wörterbuch. Wer ein Wortpaar einträgt, macht
35
+ * es damit automatisch als Grundwort für zusammengesetzte Wörter verfügbar.
36
+ * Eine Liste, zwei Wirkungen.
37
+ */
38
+ /**
39
+ * Schreibt Umlaute aus. Aus `ä` wird `ae`, aus `ß` wird `ss`.
40
+ *
41
+ * Beide Schreibweisen werden auf DIESELBE Form gebracht — nicht die eine in die
42
+ * andere übersetzt. Nur so ist `Lösung` dasselbe Wort wie `Loesung`, egal in
43
+ * welcher Richtung jemand tippt.
44
+ */
45
+ export function ohneUmlaute(wort) {
46
+ return wort
47
+ .replace(/ä/g, 'ae').replace(/ö/g, 'oe').replace(/ü/g, 'ue')
48
+ .replace(/Ä/g, 'ae').replace(/Ö/g, 'oe').replace(/Ü/g, 'ue')
49
+ .replace(/ß/g, 'ss');
50
+ }
51
+ /**
52
+ * Endungen, die im Deutschen Fall und Zahl anzeigen — von der längsten zur
53
+ * kürzesten, damit `-ungen` vor `-en` greift.
54
+ *
55
+ * Die Liste ist absichtlich kurz. Ein zu gieriger Stemmer verschmilzt Wörter,
56
+ * die nichts miteinander zu tun haben, und das ist schlimmer als eine Endung
57
+ * zu viel: falsche Treffer verdrängen richtige, fehlende Treffer nicht.
58
+ */
59
+ const ENDUNGEN = ['ungen', 'nisse', 'erne', 'ern', 'end', 'est', 'en', 'er', 'es', 'em', 'et', 'e', 'n', 's'];
60
+ /** Ab hier hört das Stammen auf — kürzere Reste sind meist keine Wörter mehr. */
61
+ const MINDESTLAENGE = 4;
62
+ /**
63
+ * Deutsche Wortform auf einen gemeinsamen Stamm bringen.
64
+ *
65
+ * Absichtlich zurückhaltend: eine Endung, nicht mehrere hintereinander. Bei
66
+ * `Abhaengigkeiten` reicht `-en`, und `Abhaengigkeit` ist genau die Form, die
67
+ * in den Lektionen steht.
68
+ */
69
+ export function deutscherStamm(wort) {
70
+ const w = ohneUmlaute(wort.toLowerCase());
71
+ if (w.length < MINDESTLAENGE + 1)
72
+ return w;
73
+ for (const endung of ENDUNGEN) {
74
+ if (w.endsWith(endung) && w.length - endung.length >= MINDESTLAENGE) {
75
+ return w.slice(0, -endung.length);
76
+ }
77
+ }
78
+ return w;
79
+ }
80
+ /**
81
+ * Die Rückumlautung: `eintraeg` → `eintrag`, `laeuft` → `lauft`.
82
+ *
83
+ * Das Deutsche verändert im Plural und in gebeugten Formen den Stammvokal
84
+ * (Eintrag → Einträge). Ohne diesen Schritt bleiben Einzahl und Mehrzahl zwei
85
+ * verschiedene Wörter.
86
+ *
87
+ * Nur die letzte Umlautstelle wird zurückgenommen. `Ueberpruefung` soll nicht
88
+ * zu `Uberprufung` werden — das Wort beginnt mit einem echten `ü`, das kein
89
+ * Umlaut einer Mehrzahl ist.
90
+ */
91
+ export function ohneRueckumlaut(stamm) {
92
+ const stelle = Math.max(stamm.lastIndexOf('ae'), stamm.lastIndexOf('oe'), stamm.lastIndexOf('ue'));
93
+ if (stelle <= 0)
94
+ return null; // <= 0: am Wortanfang steht ein echter Umlaut
95
+ const paar = stamm.slice(stelle, stelle + 2);
96
+ const einzeln = paar === 'ae' ? 'a' : paar === 'oe' ? 'o' : 'u';
97
+ const neu = stamm.slice(0, stelle) + einzeln + stamm.slice(stelle + 2);
98
+ return neu === stamm ? null : neu;
99
+ }
100
+ /**
101
+ * Zerlegt ein zusammengesetztes Wort in seine Bestandteile.
102
+ *
103
+ * `Arbeitsspeicher` → `speicher` (und `arbeit`)
104
+ * `Zugriffsprotokoll` → `protokoll` (und `zugriff`)
105
+ * `Browsertests` → `test` (und `browser`)
106
+ *
107
+ * Wie es arbeitet: Das Grundwort steht im Deutschen HINTEN. Also wird von
108
+ * hinten nach einem bekannten Wort gesucht. Der Rest davor wird ebenfalls
109
+ * zurückgegeben, wenn er lang genug ist — er trägt oft die eigentliche
110
+ * Bedeutung (`Arbeit` in `Arbeitsspeicher`).
111
+ *
112
+ * Das `s` in `Arbeits|speicher` ist eine Fuge und gehört zu keinem der beiden
113
+ * Teile. Es wird abgeschnitten.
114
+ *
115
+ * @param bekannt Grundwörter, gegen die geprüft wird. Das ist die Wortliste der
116
+ * Suche selbst — kein zweites Wörterbuch, das veralten kann.
117
+ */
118
+ export function zerlegeKompositum(wort, bekannt) {
119
+ const w = ohneUmlaute(wort.toLowerCase());
120
+ // Unter 10 Zeichen lohnt es nicht: `dienst` oder `fehler` sind schon Grund-
121
+ // wörter, und kurze Wörter zu zerlegen erzeugt vor allem Unsinn.
122
+ if (w.length < 10)
123
+ return [];
124
+ // Von hinten, längstes Grundwort zuerst — `zeitueberschreitung` soll nicht
125
+ // bei `zeit` stehenbleiben.
126
+ for (let schnitt = 4; schnitt <= w.length - 4; schnitt++) {
127
+ const hinten = w.slice(schnitt);
128
+ if (hinten.length < 4 || !bekannt.has(hinten))
129
+ continue;
130
+ const teile = [hinten];
131
+ let vorne = w.slice(0, schnitt);
132
+ if (vorne.endsWith('s') || vorne.endsWith('n'))
133
+ vorne = vorne.slice(0, -1); // Fugenlaut
134
+ if (vorne.length >= 4)
135
+ teile.push(vorne);
136
+ return teile;
137
+ }
138
+ return [];
139
+ }
140
+ /**
141
+ * Deutsche Fachwörter, die in unseren Lektionen und Fragen vorkommen.
142
+ *
143
+ * ── Woher diese Liste kommt ──────────────────────────────────────────────────
144
+ *
145
+ * Nicht aus dem Kopf. Jeder Eintrag stammt aus der Messung vom 19.08.2026: es
146
+ * sind die Wörter, die in echten Fragen standen und in der richtigen Antwort
147
+ * keinen Anschluss fanden (src/bench/wo-bricht-die-frage.ts nennt sie).
148
+ *
149
+ * Deshalb ist die Liste kurz und wird es bleiben. Sie wächst aus Messungen,
150
+ * nicht aus Vermutungen — wer etwas einträgt, soll die Frage nennen können, die
151
+ * ohne den Eintrag danebengeht.
152
+ */
153
+ export const DEUTSCHE_FACHWOERTER = [
154
+ // Speicher und Platte
155
+ ['cache', ['cache', 'zwischenspeicher']],
156
+ ['zwischenspeicher', ['cache']],
157
+ ['arbeitsspeicher', ['memory', 'ram']],
158
+ ['platte', ['disk', 'storage']],
159
+ ['festplatte', ['disk', 'storage']],
160
+ ['plattenplatz', ['disk', 'space']],
161
+ // Datenbank
162
+ ['spalte', ['column']],
163
+ ['tabelle', ['table']],
164
+ ['zeile', ['row']],
165
+ ['abfrage', ['query']],
166
+ ['zeilenschutz', ['rls', 'row-level-security']],
167
+ ['mandant', ['tenant']],
168
+ ['mandanten', ['tenant', 'tenants']],
169
+ ['wanderung', ['migration']],
170
+ // Laufzeit und Fehler
171
+ ['prozess', ['process']],
172
+ ['zeitueberschreitung', ['timeout']],
173
+ ['ausfall', ['outage', 'down']],
174
+ ['abgewiesen', ['refused', 'rejected']],
175
+ ['abgelehnt', ['refused', 'rejected']],
176
+ ['verweigert', ['denied', 'refused']],
177
+ ['haengt', ['hang', 'hangs', 'stuck']],
178
+ ['haengen', ['hang', 'stuck']],
179
+ ['abhaengigkeit', ['dependency']],
180
+ ['abhaengigkeiten', ['dependency', 'dependencies']],
181
+ ['zugriff', ['access']],
182
+ ['freigeschaltet', ['allowlist', 'permission', 'access']],
183
+ ['freigabe', ['permission', 'access', 'approval']],
184
+ // Bauen und Ausliefern
185
+ ['ausrollen', ['deploy', 'deployment']],
186
+ ['ausgerollt', ['deploy', 'deployed']],
187
+ ['abnahme', ['acceptance', 'review']],
188
+ ['quelldatei', ['source', 'file']],
189
+ ['datei', ['file']],
190
+ ['dateien', ['file', 'files']],
191
+ ['ordner', ['directory', 'folder']],
192
+ ['pfad', ['path']],
193
+ ['endung', ['extension', 'suffix']],
194
+ ['schluessel', ['key', 'token', 'secret']],
195
+ ['geheimnis', ['secret']],
196
+ // Prüfen
197
+ ['test', ['test']],
198
+ ['tests', ['test', 'tests']],
199
+ ['browsertest', ['e2e', 'playwright', 'test']],
200
+ ['browsertests', ['e2e', 'playwright', 'test']],
201
+ ['pruefung', ['check', 'test', 'validation']],
202
+ ['gegenprobe', ['counter-check', 'verification']],
203
+ ['rauchtest', ['smoke', 'smoketest']],
204
+ // Netz
205
+ ['tunnel', ['tunnel', 'vpn', 'wireguard']],
206
+ ['anfrage', ['request']],
207
+ ['anfragen', ['request', 'requests']],
208
+ ['antwort', ['response']],
209
+ ['erreichbar', ['reachable', 'available']],
210
+ ['abgesichert', ['secured', 'protected']],
211
+ // Betrieb
212
+ ['sicherung', ['backup']],
213
+ ['sicherungen', ['backup', 'backups']],
214
+ ['naechtlich', ['nightly']],
215
+ ['naechtliche', ['nightly']],
216
+ ['aufraeumen', ['cleanup', 'prune']],
217
+ ['neustart', ['restart', 'reboot']],
218
+ ['angehalten', ['stopped', 'halted']],
219
+ ['ueberwachung', ['monitor', 'monitoring']],
220
+ ['warnung', ['warning', 'alert']],
221
+ ['alarm', ['alert']],
222
+ ];
223
+ //# sourceMappingURL=deutsch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deutsch.js","sourceRoot":"","sources":["../../src/deutsch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Rüstet den vorhandenen Lektionsbestand mit Eingängen und Namensvektoren nach.
3
+ *
4
+ * ── Warum es dieses Werkzeug gibt ───────────────────────────────────────────
5
+ *
6
+ * Seit dem 20.08.2026 schreibt `learn_from_attempts` die Fehlertext-Eingänge
7
+ * beim Speichern mit. Die Lektionen, die vorher entstanden sind, haben keine —
8
+ * und ohne Nachrüstung wirkt die Verbesserung nur für alles, was ab heute
9
+ * gelernt wird. Bei 501 vorhandenen und wenigen neuen Lektionen je Woche wäre
10
+ * das praktisch keine Wirkung.
11
+ *
12
+ * ── Was es kostet ──────────────────────────────────────────────────────────
13
+ *
14
+ * Rund 1,3 Einbettungen je Lektion (nicht jede trägt einen Fehlertext).
15
+ * Gemessen am 20.08.: 1440 Einbettungen in 406 s mit Admin-Schlüssel, das sind
16
+ * 3,5 je Sekunde. Für 501 Lektionen also wenige Minuten.
17
+ *
18
+ * OHNE Admin-Schlüssel greift die Drosselung von 60 Anfragen je Minute
19
+ * (api/cmd/server/routes.go). Ein paralleler Lauf hat am 19.08. 563 mal
20
+ * HTTP 429 erzeugt, eine Wachhund-Warnung mit unserer eigenen Adresse
21
+ * ausgelöst und eine automatische Hochskalierung angestoßen. Deshalb die
22
+ * Notbremse.
23
+ *
24
+ * ── Was es NICHT tut ───────────────────────────────────────────────────────
25
+ *
26
+ * Es rührt die Lektionen selbst nicht an und schreibt keine Vektoren. Fällt es
27
+ * mittendrin aus, ist der Bestand in demselben Zustand wie vorher, nur mit
28
+ * weniger Eingängen — ein zweiter Lauf holt den Rest.
29
+ *
30
+ * Aufruf:
31
+ * REDIS_URL=... CACHLY_JWT=... CACHLY_ADMIN_KEY=... \
32
+ * npx tsx src/eingaenge-nachruesten.ts [--probe 20] [--parallel 6]
33
+ * npx tsx src/eingaenge-nachruesten.ts --selbstprobe
34
+ */
35
+ /**
36
+ * Wie viele Lektionen überhaupt einen Eingang bekommen könnten.
37
+ *
38
+ * Wird VOR dem ersten Netzaufruf gerechnet und gemeldet: wer die Zahl vorher
39
+ * kennt, merkt sofort, wenn am Ende viel weniger herauskommt.
40
+ */
41
+ export declare function wieVieleTragen(lektionen: Array<Record<string, unknown>>): number;
@@ -0,0 +1,290 @@
1
+ /**
2
+ * Rüstet den vorhandenen Lektionsbestand mit Eingängen und Namensvektoren nach.
3
+ *
4
+ * ── Warum es dieses Werkzeug gibt ───────────────────────────────────────────
5
+ *
6
+ * Seit dem 20.08.2026 schreibt `learn_from_attempts` die Fehlertext-Eingänge
7
+ * beim Speichern mit. Die Lektionen, die vorher entstanden sind, haben keine —
8
+ * und ohne Nachrüstung wirkt die Verbesserung nur für alles, was ab heute
9
+ * gelernt wird. Bei 501 vorhandenen und wenigen neuen Lektionen je Woche wäre
10
+ * das praktisch keine Wirkung.
11
+ *
12
+ * ── Was es kostet ──────────────────────────────────────────────────────────
13
+ *
14
+ * Rund 1,3 Einbettungen je Lektion (nicht jede trägt einen Fehlertext).
15
+ * Gemessen am 20.08.: 1440 Einbettungen in 406 s mit Admin-Schlüssel, das sind
16
+ * 3,5 je Sekunde. Für 501 Lektionen also wenige Minuten.
17
+ *
18
+ * OHNE Admin-Schlüssel greift die Drosselung von 60 Anfragen je Minute
19
+ * (api/cmd/server/routes.go). Ein paralleler Lauf hat am 19.08. 563 mal
20
+ * HTTP 429 erzeugt, eine Wachhund-Warnung mit unserer eigenen Adresse
21
+ * ausgelöst und eine automatische Hochskalierung angestoßen. Deshalb die
22
+ * Notbremse.
23
+ *
24
+ * ── Was es NICHT tut ───────────────────────────────────────────────────────
25
+ *
26
+ * Es rührt die Lektionen selbst nicht an und schreibt keine Vektoren. Fällt es
27
+ * mittendrin aus, ist der Bestand in demselben Zustand wie vorher, nur mit
28
+ * weniger Eingängen — ein zweiter Lauf holt den Rest.
29
+ *
30
+ * Aufruf:
31
+ * REDIS_URL=... CACHLY_JWT=... CACHLY_ADMIN_KEY=... \
32
+ * npx tsx src/eingaenge-nachruesten.ts [--probe 20] [--parallel 6]
33
+ * npx tsx src/eingaenge-nachruesten.ts --selbstprobe
34
+ */
35
+ import { Redis } from 'ioredis';
36
+ import { schreibeEingaenge, fehlertexteAus, eingangsText, EINGANG_PRAEFIX } from './eingaenge.js';
37
+ import { NAME_VEKTOR_PRAEFIX, VEKTOR_PRAEFIX, packe, textFuerNamensVektor, textFuerVektor, } from './bedeutung.js';
38
+ const LEKTION_PRAEFIX = 'cachly:lesson:best:';
39
+ /** Zählt die 429er. Bei zehn ist Schluss — lieber abgebrochen als ein Vorfall. */
40
+ class Notbremse {
41
+ grenze;
42
+ zaehler = 0;
43
+ constructor(grenze = 10) {
44
+ this.grenze = grenze;
45
+ }
46
+ melde429() { this.zaehler++; }
47
+ get gezogen() { return this.zaehler >= this.grenze; }
48
+ get stand() { return this.zaehler; }
49
+ }
50
+ /**
51
+ * Wie viele Lektionen überhaupt einen Eingang bekommen könnten.
52
+ *
53
+ * Wird VOR dem ersten Netzaufruf gerechnet und gemeldet: wer die Zahl vorher
54
+ * kennt, merkt sofort, wenn am Ende viel weniger herauskommt.
55
+ */
56
+ export function wieVieleTragen(lektionen) {
57
+ return lektionen.filter((l) => fehlertexteAus(eingangsText(l)).length > 0).length;
58
+ }
59
+ function selbstprobe() {
60
+ const proben = [];
61
+ const p = (was, ok) => { proben.push([was, ok]); };
62
+ const mit = { what_worked: 'Der Worker meldete "No space left on device".' };
63
+ const ohne = { what_worked: 'Wir haben die Reihenfolge der Schritte getauscht.' };
64
+ p('zählt nur Lektionen mit Fehlertext', wieVieleTragen([mit, ohne, mit]) === 2);
65
+ p('leerer Bestand ergibt null', wieVieleTragen([]) === 0);
66
+ const b = new Notbremse(3);
67
+ b.melde429();
68
+ b.melde429();
69
+ p('zwei von drei reichen nicht', !b.gezogen);
70
+ b.melde429();
71
+ p('drei ziehen die Bremse', b.gezogen);
72
+ let rot = 0;
73
+ for (const [was, ok] of proben) {
74
+ console.log(`${ok ? 'ok ' : 'ROT '} ${was}`);
75
+ if (!ok)
76
+ rot++;
77
+ }
78
+ console.log(rot === 0 ? 'Selbstprobe bestanden.' : `Selbstprobe ROT: ${rot} von ${proben.length}.`);
79
+ process.exit(rot === 0 ? 0 : 1);
80
+ }
81
+ async function main() {
82
+ const argv = process.argv.slice(2);
83
+ const flag = (n) => {
84
+ const i = argv.indexOf(`--${n}`);
85
+ return i !== -1 ? argv[i + 1] : undefined;
86
+ };
87
+ const url = process.env.CACHLY_REDIS_URL ?? process.env.REDIS_URL;
88
+ const API = process.env.CACHLY_API_URL ?? 'https://api.cachly.dev';
89
+ const JWT = process.env.CACHLY_JWT ?? '';
90
+ const ADMIN = process.env.CACHLY_ADMIN_KEY ?? '';
91
+ if (!url) {
92
+ console.error('NICHT GELAUFEN: CACHLY_REDIS_URL oder REDIS_URL fehlt.');
93
+ process.exit(2);
94
+ }
95
+ if (!JWT) {
96
+ console.error('NICHT GELAUFEN: CACHLY_JWT fehlt.');
97
+ process.exit(2);
98
+ }
99
+ const probe = Number(flag('probe') ?? '0');
100
+ const parallel = Number(flag('parallel') ?? (ADMIN ? '6' : '2'));
101
+ const bremse = new Notbremse(10);
102
+ const einbetten = async (text) => {
103
+ for (let versuch = 0; versuch < 4; versuch++) {
104
+ if (bremse.gezogen)
105
+ return null;
106
+ try {
107
+ const kopf = { 'Content-Type': 'application/json', Authorization: `Bearer ${JWT}` };
108
+ if (ADMIN)
109
+ kopf['X-Admin-Key'] = ADMIN;
110
+ const r = await fetch(`${API}/api/v1/embed`, {
111
+ method: 'POST', headers: kopf,
112
+ body: JSON.stringify({ text: text.slice(0, 2000) }),
113
+ signal: AbortSignal.timeout(60_000),
114
+ });
115
+ if (r.status === 429) {
116
+ bremse.melde429();
117
+ await new Promise((f) => setTimeout(f, 2000 * (versuch + 1)));
118
+ continue;
119
+ }
120
+ if (!r.ok)
121
+ return null;
122
+ const j = await r.json();
123
+ return j.embedding ?? j.data?.[0]?.embedding ?? null;
124
+ }
125
+ catch {
126
+ await new Promise((f) => setTimeout(f, 800 * (versuch + 1)));
127
+ }
128
+ }
129
+ return null;
130
+ };
131
+ const redis = new Redis(url, { maxRetriesPerRequest: 2, connectTimeout: 8000 });
132
+ try {
133
+ const schluessel = [];
134
+ let cursor = '0';
135
+ do {
136
+ const [next, gefunden] = await redis.scan(cursor, 'MATCH', `${LEKTION_PRAEFIX}*`, 'COUNT', 500);
137
+ cursor = next;
138
+ schluessel.push(...gefunden);
139
+ } while (cursor !== '0');
140
+ if (schluessel.length === 0) {
141
+ console.error(`NICHT GELAUFEN: keine Lektionen unter ${LEKTION_PRAEFIX}* — falsche Instanz?`);
142
+ process.exit(3);
143
+ }
144
+ const lektionen = [];
145
+ for (let i = 0; i < schluessel.length; i += 100) {
146
+ const block = schluessel.slice(i, i + 100);
147
+ const werte = await redis.mget(...block);
148
+ for (const [j, roh] of werte.entries()) {
149
+ if (!roh)
150
+ continue;
151
+ try {
152
+ const o = JSON.parse(roh);
153
+ const topic = typeof o.topic === 'string' && o.topic ? o.topic : block[j].slice(LEKTION_PRAEFIX.length);
154
+ if (topic)
155
+ lektionen.push({ topic, inhalt: o });
156
+ }
157
+ catch { /* eine kaputte Zeile ist ein Thema fuer doctor */ }
158
+ }
159
+ }
160
+ // Was schon da ist, wird übersprungen — ein zweiter Lauf ist billig.
161
+ const schonDa = async (praefix) => {
162
+ const menge = new Set();
163
+ let c = '0';
164
+ do {
165
+ const [next, gefunden] = await redis.scan(c, 'MATCH', `${praefix}*`, 'COUNT', 500);
166
+ c = next;
167
+ for (const k of gefunden)
168
+ menge.add(k.slice(praefix.length));
169
+ } while (c !== '0');
170
+ return menge;
171
+ };
172
+ let fertigNamen = 0;
173
+ const vorhanden = await schonDa(EINGANG_PRAEFIX);
174
+ const namenDa = await schonDa(NAME_VEKTOR_PRAEFIX);
175
+ const volltextDa = await schonDa(VEKTOR_PRAEFIX);
176
+ // ── Volltextvektoren ─────────────────────────────────────────────────────
177
+ //
178
+ // Gemessen am 20.08.2026 gegen die Produktion: `cachly:lesson:vec:*` war
179
+ // LEER — bei 506 Lektionen kein einziger Vektor. Damit lief der
180
+ // Bedeutungsabgleich dort nie: `vektorbestand.groesse === 0` steigt in
181
+ // brain.ts sofort aus und faellt auf den reinen Wortabgleich zurueck.
182
+ //
183
+ // Das ist die Grundlage von allem anderen. Ohne diese Vektoren nuetzen
184
+ // weder Namensvektoren noch Eingaenge etwas.
185
+ const ohneVolltext = lektionen.filter((l) => !volltextDa.has(l.topic));
186
+ console.log(`${volltextDa.size} Lektionen haben einen Volltextvektor, ${ohneVolltext.length} fehlen.`);
187
+ if (ohneVolltext.length > 0) {
188
+ let n = 0;
189
+ let fertigVoll = 0;
190
+ let naechsterVoll = 0;
191
+ const vollArbeiter = Array.from({ length: parallel }, async () => {
192
+ for (;;) {
193
+ const i = naechsterVoll++;
194
+ if (i >= ohneVolltext.length || bremse.gezogen)
195
+ return;
196
+ const v = await einbetten(textFuerVektor(ohneVolltext[i].inhalt));
197
+ if (v?.length) {
198
+ await redis.set(`${VEKTOR_PRAEFIX}${ohneVolltext[i].topic}`, packe(v));
199
+ n++;
200
+ }
201
+ if (++fertigVoll % 100 === 0)
202
+ console.log(` Volltext ${fertigVoll}/${ohneVolltext.length}`);
203
+ }
204
+ });
205
+ await Promise.all(vollArbeiter);
206
+ console.log(`${n} Volltextvektoren geschrieben.`);
207
+ }
208
+ // ── Namensvektoren zuerst ────────────────────────────────────────────────
209
+ //
210
+ // Sie sind die Voraussetzung dafür, dass der Sortierer aus rangfolge.ts
211
+ // überhaupt greifen kann: ohne sie ist `naeheThema` für jede Lektion -2,
212
+ // und ein Merkmal mit Gewicht 0,6 trägt dann nichts bei.
213
+ const ohneNamen = lektionen.filter((l) => !namenDa.has(l.topic));
214
+ console.log(`${namenDa.size} Lektionen haben einen Namensvektor, ${ohneNamen.length} fehlen.`);
215
+ if (ohneNamen.length > 0) {
216
+ let n = 0;
217
+ let naechsterName = 0;
218
+ const namensArbeiter = Array.from({ length: parallel }, async () => {
219
+ for (;;) {
220
+ const i = naechsterName++;
221
+ if (i >= ohneNamen.length || bremse.gezogen)
222
+ return;
223
+ const v = await einbetten(textFuerNamensVektor(ohneNamen[i].topic));
224
+ if (v?.length) {
225
+ await redis.set(`${NAME_VEKTOR_PRAEFIX}${ohneNamen[i].topic}`, packe(v));
226
+ n++;
227
+ }
228
+ if (++fertigNamen % 100 === 0)
229
+ console.log(` Namen ${fertigNamen}/${ohneNamen.length}`);
230
+ }
231
+ });
232
+ await Promise.all(namensArbeiter);
233
+ console.log(`${n} Namensvektoren geschrieben.`);
234
+ }
235
+ let offen = lektionen.filter((l) => !vorhanden.has(l.topic));
236
+ const koennten = wieVieleTragen(offen.map((l) => l.inhalt));
237
+ if (probe > 0)
238
+ offen = offen.slice(0, probe);
239
+ console.log(`${lektionen.length} Lektionen, ${vorhanden.size} haben schon Eingänge.`);
240
+ console.log(`${offen.length} offen, davon tragen ${koennten} einen Fehlertext.`);
241
+ console.log(ADMIN
242
+ ? `Admin-Schlüssel gesetzt — ${parallel} gleichzeitig, Notbremse bei 10x 429.`
243
+ : `KEIN Admin-Schlüssel — gedrosselt mit ${parallel} gleichzeitig. Das dauert.`);
244
+ let fertig = 0;
245
+ let geschrieben = 0;
246
+ let leer = 0;
247
+ const begonnen = Date.now();
248
+ let naechster = 0;
249
+ const arbeiter = Array.from({ length: parallel }, async () => {
250
+ for (;;) {
251
+ const i = naechster++;
252
+ if (i >= offen.length || bremse.gezogen)
253
+ return;
254
+ const l = offen[i];
255
+ try {
256
+ const n = await schreibeEingaenge(redis, l.topic, l.inhalt, einbetten);
257
+ if (n > 0)
258
+ geschrieben += n;
259
+ else
260
+ leer++;
261
+ }
262
+ catch {
263
+ leer++;
264
+ }
265
+ fertig++;
266
+ if (fertig % 50 === 0) {
267
+ const proSek = fertig / ((Date.now() - begonnen) / 1000);
268
+ console.log(` ${fertig}/${offen.length} (${proSek.toFixed(1)}/s, 429er: ${bremse.stand})`);
269
+ }
270
+ }
271
+ });
272
+ await Promise.all(arbeiter);
273
+ const dauer = ((Date.now() - begonnen) / 1000).toFixed(0);
274
+ console.log(`Fertig in ${dauer} s. ${geschrieben} Eingänge für ${offen.length - leer} Lektionen.`);
275
+ console.log(`${leer} Lektionen tragen keinen Fehlertext — die bleiben ohne Eingang.`);
276
+ if (bremse.gezogen) {
277
+ console.error(`NOTBREMSE: ${bremse.stand} mal HTTP 429 — abgebrochen. Ein zweiter Lauf holt den Rest.`);
278
+ process.exit(4);
279
+ }
280
+ }
281
+ finally {
282
+ redis.disconnect();
283
+ }
284
+ }
285
+ const direktGestartet = process.argv[1]?.replace(/\\/g, '/').endsWith('/eingaenge-nachruesten.ts');
286
+ if (direktGestartet && process.argv.includes('--selbstprobe'))
287
+ selbstprobe();
288
+ else if (direktGestartet)
289
+ void main();
290
+ //# sourceMappingURL=eingaenge-nachruesten.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eingaenge-nachruesten.js","sourceRoot":"","sources":["../../src/eingaenge-nachruesten.ts"],"names":[],"mappings":"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"}