@cachly-dev/mcp-server 0.10.129 → 0.10.131
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 +2 -2
- package/dist/index.js +1 -7
- package/dist/packages/telegram-notify/client.js +2 -75
- package/dist/src/ambient-cli.js +7 -253
- package/dist/src/ambient-deps.js +1 -55
- package/dist/src/ambient-hooks.js +5 -278
- package/dist/src/ambient-ledger.js +6 -95
- package/dist/src/ambient-memory.js +1 -67
- package/dist/src/ambient-recall.js +1 -221
- package/dist/src/aussetzer.js +1 -225
- package/dist/src/auth.js +9 -140
- package/dist/src/autor-abzeichen.js +1 -56
- package/dist/src/autor.js +1 -136
- package/dist/src/bauabdruck.js +1 -93
- package/dist/src/bedeutung.js +2 -323
- package/dist/src/bench/cachly-bench.js +4 -249
- package/dist/src/bench/external-corpus.js +4 -135
- package/dist/src/bench/fixtures.js +1 -225
- package/dist/src/brain-export.js +16 -119
- package/dist/src/brain-watch-hook.js +8 -86
- package/dist/src/cachly-url.js +1 -21
- package/dist/src/ckg.js +1 -108
- package/dist/src/cls-hook.js +8 -94
- package/dist/src/confidence.js +1 -50
- package/dist/src/credentials.js +1 -85
- package/dist/src/deutsch.js +1 -223
- package/dist/src/doctor.js +2 -248
- package/dist/src/editor.js +1 -63
- package/dist/src/eingaenge-nachruesten.js +1 -290
- package/dist/src/eingaenge.js +2 -260
- package/dist/src/embeddings.js +13 -223
- package/dist/src/feldreparatur.js +3 -113
- package/dist/src/first-contact.js +4 -108
- package/dist/src/first-recall-proof.js +4 -41
- package/dist/src/funnel-milestones.js +2 -48
- package/dist/src/geliefert.js +1 -114
- package/dist/src/handlers/advanced.js +38 -537
- package/dist/src/handlers/brain.js +69 -4397
- package/dist/src/handlers/cache.js +59 -638
- package/dist/src/handlers/context.js +17 -182
- package/dist/src/handlers/fedbrain.js +40 -1436
- package/dist/src/handlers/instances.js +16 -201
- package/dist/src/handlers/roadmap.js +13 -175
- package/dist/src/handlers/share.js +19 -530
- package/dist/src/handlers/syndicate.js +38 -904
- package/dist/src/handlers/team.js +89 -1865
- package/dist/src/handlers/viz.js +3 -148
- package/dist/src/index.js +321 -4281
- package/dist/src/interferenz.js +1 -141
- package/dist/src/kostprobe.js +7 -125
- package/dist/src/lesson-preview.js +2 -133
- package/dist/src/namespace.js +1 -128
- package/dist/src/notifier.js +1 -6
- package/dist/src/rangfolge-stellschrauben.js +1 -0
- package/dist/src/rangfolge.js +1 -249
- package/dist/src/raumkorrektur.js +1 -197
- package/dist/src/recall-tiefe.js +1 -42
- package/dist/src/rerank.js +1 -154
- package/dist/src/resonanz.js +1 -140
- package/dist/src/search.js +1 -2104
- package/dist/src/seltenheitsbestand.js +1 -92
- package/dist/src/speicherlage.js +1 -84
- package/dist/src/spuren.js +1 -150
- package/dist/src/starter-corpus.js +1 -165
- package/dist/src/telemetry-types.js +0 -13
- package/dist/src/tools.js +10 -2465
- package/dist/src/toolspecs.js +1 -121
- package/dist/src/upgrade-nudge.js +1 -29
- package/dist/src/utils.js +1 -89
- package/dist/src/versuch.js +1 -264
- package/dist/src/vorspann.js +1 -146
- package/dist/src/wartung/vektoren-verdichten.js +1 -200
- package/dist/src/werkzeug-nutzung.js +1 -72
- package/dist/src/wertbeitrag.js +1 -203
- package/dist/src/wirkungsspur.js +1 -0
- package/glama.json +1 -1
- package/package.json +8 -7
- package/server.json +3 -3
- package/dist/index.d.ts +0 -1
- package/dist/index.js.map +0 -1
- package/dist/packages/telegram-notify/client.d.ts +0 -19
- package/dist/packages/telegram-notify/client.js.map +0 -1
- package/dist/src/ambient-cli.d.ts +0 -101
- package/dist/src/ambient-cli.js.map +0 -1
- package/dist/src/ambient-deps.d.ts +0 -26
- package/dist/src/ambient-deps.js.map +0 -1
- package/dist/src/ambient-hooks.d.ts +0 -137
- package/dist/src/ambient-hooks.js.map +0 -1
- package/dist/src/ambient-ledger.d.ts +0 -19
- package/dist/src/ambient-ledger.js.map +0 -1
- package/dist/src/ambient-memory.d.ts +0 -12
- package/dist/src/ambient-memory.js.map +0 -1
- package/dist/src/ambient-recall.d.ts +0 -127
- package/dist/src/ambient-recall.js.map +0 -1
- package/dist/src/aussetzer.d.ts +0 -156
- package/dist/src/aussetzer.js.map +0 -1
- package/dist/src/auth.d.ts +0 -43
- package/dist/src/auth.js.map +0 -1
- package/dist/src/autor-abzeichen.d.ts +0 -41
- package/dist/src/autor-abzeichen.js.map +0 -1
- package/dist/src/autor.d.ts +0 -101
- package/dist/src/autor.js.map +0 -1
- package/dist/src/bauabdruck-daten.generiert.json +0 -5
- package/dist/src/bauabdruck.d.ts +0 -38
- package/dist/src/bauabdruck.js.map +0 -1
- package/dist/src/bedeutung.d.ts +0 -168
- package/dist/src/bedeutung.js.map +0 -1
- package/dist/src/bench/cachly-bench.d.ts +0 -61
- package/dist/src/bench/cachly-bench.js.map +0 -1
- package/dist/src/bench/external-corpus.d.ts +0 -44
- package/dist/src/bench/external-corpus.js.map +0 -1
- package/dist/src/bench/fixtures.d.ts +0 -37
- package/dist/src/bench/fixtures.js.map +0 -1
- package/dist/src/brain-export.d.ts +0 -64
- package/dist/src/brain-export.js.map +0 -1
- package/dist/src/brain-watch-hook.d.ts +0 -21
- package/dist/src/brain-watch-hook.js.map +0 -1
- package/dist/src/cachly-url.d.ts +0 -68
- package/dist/src/cachly-url.js.map +0 -1
- package/dist/src/ckg.d.ts +0 -54
- package/dist/src/ckg.js.map +0 -1
- package/dist/src/cls-hook.d.ts +0 -15
- package/dist/src/cls-hook.js.map +0 -1
- package/dist/src/confidence.d.ts +0 -19
- package/dist/src/confidence.js.map +0 -1
- package/dist/src/credentials.d.ts +0 -37
- package/dist/src/credentials.js.map +0 -1
- package/dist/src/deutsch.d.ts +0 -98
- package/dist/src/deutsch.js.map +0 -1
- package/dist/src/doctor.d.ts +0 -47
- package/dist/src/doctor.js.map +0 -1
- package/dist/src/editor.d.ts +0 -9
- package/dist/src/editor.js.map +0 -1
- package/dist/src/eingaenge-nachruesten.d.ts +0 -41
- package/dist/src/eingaenge-nachruesten.js.map +0 -1
- package/dist/src/eingaenge.d.ts +0 -159
- package/dist/src/eingaenge.js.map +0 -1
- package/dist/src/embeddings.d.ts +0 -48
- package/dist/src/embeddings.js.map +0 -1
- package/dist/src/feldreparatur.d.ts +0 -58
- package/dist/src/feldreparatur.js.map +0 -1
- package/dist/src/first-contact.d.ts +0 -56
- package/dist/src/first-contact.js.map +0 -1
- package/dist/src/first-recall-proof.d.ts +0 -19
- package/dist/src/first-recall-proof.js.map +0 -1
- package/dist/src/funnel-milestones.d.ts +0 -5
- package/dist/src/funnel-milestones.js.map +0 -1
- package/dist/src/geliefert.d.ts +0 -63
- package/dist/src/geliefert.js.map +0 -1
- package/dist/src/handlers/advanced.d.ts +0 -6
- package/dist/src/handlers/advanced.js.map +0 -1
- package/dist/src/handlers/brain.d.ts +0 -41
- package/dist/src/handlers/brain.js.map +0 -1
- package/dist/src/handlers/cache.d.ts +0 -6
- package/dist/src/handlers/cache.js.map +0 -1
- package/dist/src/handlers/context.d.ts +0 -6
- package/dist/src/handlers/context.js.map +0 -1
- package/dist/src/handlers/fedbrain.d.ts +0 -18
- package/dist/src/handlers/fedbrain.js.map +0 -1
- package/dist/src/handlers/instances.d.ts +0 -33
- package/dist/src/handlers/instances.js.map +0 -1
- package/dist/src/handlers/roadmap.d.ts +0 -6
- package/dist/src/handlers/roadmap.js.map +0 -1
- package/dist/src/handlers/share.d.ts +0 -8
- package/dist/src/handlers/share.js.map +0 -1
- package/dist/src/handlers/syndicate.d.ts +0 -6
- package/dist/src/handlers/syndicate.js.map +0 -1
- package/dist/src/handlers/team.d.ts +0 -45
- package/dist/src/handlers/team.js.map +0 -1
- package/dist/src/handlers/viz.d.ts +0 -6
- package/dist/src/handlers/viz.js.map +0 -1
- package/dist/src/index.d.ts +0 -93
- package/dist/src/index.js.map +0 -1
- package/dist/src/interferenz.d.ts +0 -111
- package/dist/src/interferenz.js.map +0 -1
- package/dist/src/kostprobe.d.ts +0 -25
- package/dist/src/kostprobe.js.map +0 -1
- package/dist/src/lesson-preview.d.ts +0 -81
- package/dist/src/lesson-preview.js.map +0 -1
- package/dist/src/namespace.d.ts +0 -20
- package/dist/src/namespace.js.map +0 -1
- package/dist/src/notifier.d.ts +0 -5
- package/dist/src/notifier.js.map +0 -1
- package/dist/src/rangfolge.d.ts +0 -205
- package/dist/src/rangfolge.js.map +0 -1
- package/dist/src/raumkorrektur.d.ts +0 -100
- package/dist/src/raumkorrektur.js.map +0 -1
- package/dist/src/recall-tiefe.d.ts +0 -48
- package/dist/src/recall-tiefe.js.map +0 -1
- package/dist/src/rerank.d.ts +0 -48
- package/dist/src/rerank.js.map +0 -1
- package/dist/src/resonanz.d.ts +0 -85
- package/dist/src/resonanz.js.map +0 -1
- package/dist/src/search.d.ts +0 -153
- package/dist/src/search.js.map +0 -1
- package/dist/src/seltenheitsbestand.d.ts +0 -53
- package/dist/src/seltenheitsbestand.js.map +0 -1
- package/dist/src/speicherlage.d.ts +0 -51
- package/dist/src/speicherlage.js.map +0 -1
- package/dist/src/spuren.d.ts +0 -97
- package/dist/src/spuren.js.map +0 -1
- package/dist/src/starter-corpus.d.ts +0 -28
- package/dist/src/starter-corpus.js.map +0 -1
- package/dist/src/telemetry-types.d.ts +0 -87
- package/dist/src/telemetry-types.js.map +0 -1
- package/dist/src/tools.d.ts +0 -2933
- package/dist/src/tools.js.map +0 -1
- package/dist/src/toolspecs.d.ts +0 -43
- package/dist/src/toolspecs.js.map +0 -1
- package/dist/src/upgrade-nudge.d.ts +0 -15
- package/dist/src/upgrade-nudge.js.map +0 -1
- package/dist/src/utils.d.ts +0 -34
- package/dist/src/utils.js.map +0 -1
- package/dist/src/versuch.d.ts +0 -187
- package/dist/src/versuch.js.map +0 -1
- package/dist/src/vorspann.d.ts +0 -73
- package/dist/src/vorspann.js.map +0 -1
- package/dist/src/wartung/vektoren-verdichten.d.ts +0 -50
- package/dist/src/wartung/vektoren-verdichten.js.map +0 -1
- package/dist/src/werkzeug-nutzung.d.ts +0 -62
- package/dist/src/werkzeug-nutzung.js.map +0 -1
- package/dist/src/wertbeitrag.d.ts +0 -148
- package/dist/src/wertbeitrag.js.map +0 -1
package/dist/src/deutsch.js
CHANGED
|
@@ -1,223 +1 @@
|
|
|
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
|
|
1
|
+
function i(t){return t.replace(/ä/g,"ae").replace(/ö/g,"oe").replace(/ü/g,"ue").replace(/Ä/g,"ae").replace(/Ö/g,"oe").replace(/Ü/g,"ue").replace(/ß/g,"ss")}const o=["ungen","nisse","erne","ern","end","est","en","er","es","em","et","e","n","s"],l=4;function u(t){const e=i(t.toLowerCase());if(e.length<l+1)return e;for(const n of o)if(e.endsWith(n)&&e.length-n.length>=l)return e.slice(0,-n.length);return e}function g(t){const e=Math.max(t.lastIndexOf("ae"),t.lastIndexOf("oe"),t.lastIndexOf("ue"));if(e<=0)return null;const n=t.slice(e,e+2),r=n==="ae"?"a":n==="oe"?"o":"u",s=t.slice(0,e)+r+t.slice(e+2);return s===t?null:s}function h(t,e){const n=i(t.toLowerCase());if(n.length<10)return[];for(let r=4;r<=n.length-4;r++){const s=n.slice(r);if(s.length<4||!e.has(s))continue;const c=[s];let a=n.slice(0,r);return(a.endsWith("s")||a.endsWith("n"))&&(a=a.slice(0,-1)),a.length>=4&&c.push(a),c}return[]}const p=[["cache",["cache","zwischenspeicher"]],["zwischenspeicher",["cache"]],["arbeitsspeicher",["memory","ram"]],["platte",["disk","storage"]],["festplatte",["disk","storage"]],["plattenplatz",["disk","space"]],["spalte",["column"]],["tabelle",["table"]],["zeile",["row"]],["abfrage",["query"]],["zeilenschutz",["rls","row-level-security"]],["mandant",["tenant"]],["mandanten",["tenant","tenants"]],["wanderung",["migration"]],["prozess",["process"]],["zeitueberschreitung",["timeout"]],["ausfall",["outage","down"]],["abgewiesen",["refused","rejected"]],["abgelehnt",["refused","rejected"]],["verweigert",["denied","refused"]],["haengt",["hang","hangs","stuck"]],["haengen",["hang","stuck"]],["abhaengigkeit",["dependency"]],["abhaengigkeiten",["dependency","dependencies"]],["zugriff",["access"]],["freigeschaltet",["allowlist","permission","access"]],["freigabe",["permission","access","approval"]],["ausrollen",["deploy","deployment"]],["ausgerollt",["deploy","deployed"]],["abnahme",["acceptance","review"]],["quelldatei",["source","file"]],["datei",["file"]],["dateien",["file","files"]],["ordner",["directory","folder"]],["pfad",["path"]],["endung",["extension","suffix"]],["schluessel",["key","token","secret"]],["geheimnis",["secret"]],["test",["test"]],["tests",["test","tests"]],["browsertest",["e2e","playwright","test"]],["browsertests",["e2e","playwright","test"]],["pruefung",["check","test","validation"]],["gegenprobe",["counter-check","verification"]],["rauchtest",["smoke","smoketest"]],["tunnel",["tunnel","vpn","wireguard"]],["anfrage",["request"]],["anfragen",["request","requests"]],["antwort",["response"]],["erreichbar",["reachable","available"]],["abgesichert",["secured","protected"]],["sicherung",["backup"]],["sicherungen",["backup","backups"]],["naechtlich",["nightly"]],["naechtliche",["nightly"]],["aufraeumen",["cleanup","prune"]],["neustart",["restart","reboot"]],["angehalten",["stopped","halted"]],["ueberwachung",["monitor","monitoring"]],["warnung",["warning","alert"]],["alarm",["alert"]]];export{p as DEUTSCHE_FACHWOERTER,u as deutscherStamm,g as ohneRueckumlaut,i as ohneUmlaute,h as zerlegeKompositum};
|
package/dist/src/doctor.js
CHANGED
|
@@ -1,248 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
// The activation funnel dies silently: a missing JWT, an unreachable API, a
|
|
4
|
-
// half-installed hook set or a stale v1 shell hook all look identical from the
|
|
5
|
-
// editor ("the brain just doesn't answer"). doctor makes every link of the
|
|
6
|
-
// chain visible in one run: environment → credential → API → instance → hooks
|
|
7
|
-
// → ledger. Pure check functions with injected effects so the whole module is
|
|
8
|
-
// unit-testable; the CLI shell in index.ts only wires and prints.
|
|
9
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
10
|
-
import { resolve } from 'node:path';
|
|
11
|
-
import { AMBIENT_HOOK_VERSION } from './ambient-hooks.js';
|
|
12
|
-
import { netBalance, shouldBackoff } from './ambient-recall.js';
|
|
13
|
-
import { cachlyUrl } from './cachly-url.js';
|
|
14
|
-
const MIN_NODE_MAJOR = 18;
|
|
15
|
-
/** Node runtime new enough for fetch/AbortSignal (>= 18). */
|
|
16
|
-
export function checkNodeVersion(version = process.version) {
|
|
17
|
-
const major = Number(version.replace(/^v/, '').split('.')[0]);
|
|
18
|
-
if (Number.isFinite(major) && major >= MIN_NODE_MAJOR) {
|
|
19
|
-
return { name: 'Node.js', status: 'ok', detail: `${version}` };
|
|
20
|
-
}
|
|
21
|
-
return {
|
|
22
|
-
name: 'Node.js',
|
|
23
|
-
status: 'fail',
|
|
24
|
-
detail: `${version} — too old`,
|
|
25
|
-
hint: `cachly needs Node ${MIN_NODE_MAJOR}+ (built-in fetch). Install a current LTS from nodejs.org.`,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
/** Credential present and roughly the right shape (cky_… API key or JWT). */
|
|
29
|
-
export function checkCredential(jwt) {
|
|
30
|
-
if (!jwt) {
|
|
31
|
-
return {
|
|
32
|
-
name: 'Credential',
|
|
33
|
-
status: 'fail',
|
|
34
|
-
detail: 'CACHLY_JWT is not set',
|
|
35
|
-
hint: 'Run `npx @cachly-dev/mcp-server@latest autopilot` (browser sign-in) or export CACHLY_JWT=<cky_…>.',
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
const looksApiKey = jwt.startsWith('cky_');
|
|
39
|
-
const looksJwt = jwt.split('.').length === 3;
|
|
40
|
-
if (!looksApiKey && !looksJwt) {
|
|
41
|
-
return {
|
|
42
|
-
name: 'Credential',
|
|
43
|
-
status: 'warn',
|
|
44
|
-
detail: 'CACHLY_JWT is set but looks neither like a cky_… key nor a JWT',
|
|
45
|
-
hint: 'Re-copy the key from the dashboard (API Keys) — it may be truncated.',
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
return { name: 'Credential', status: 'ok', detail: looksApiKey ? 'API key (cky_…)' : 'JWT' };
|
|
49
|
-
}
|
|
50
|
-
/** API reachable at all (public /health — no auth involved). */
|
|
51
|
-
export async function checkApiReachable(apiUrl, fetchFn = fetch) {
|
|
52
|
-
try {
|
|
53
|
-
const res = await fetchFn(`${apiUrl}/health`, { signal: AbortSignal.timeout(5000) });
|
|
54
|
-
if (res.ok)
|
|
55
|
-
return { name: 'API', status: 'ok', detail: `${apiUrl} reachable` };
|
|
56
|
-
return {
|
|
57
|
-
name: 'API',
|
|
58
|
-
status: 'fail',
|
|
59
|
-
detail: `${apiUrl}/health returned HTTP ${res.status}`,
|
|
60
|
-
hint: `The API answered but is unhealthy — check ${cachlyUrl('/status', 'doctor')} or your CACHLY_API_URL.`,
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
catch {
|
|
64
|
-
return {
|
|
65
|
-
name: 'API',
|
|
66
|
-
status: 'fail',
|
|
67
|
-
detail: `${apiUrl} not reachable`,
|
|
68
|
-
hint: 'Check your network/proxy. Self-hosted: is CACHLY_API_URL correct and the API running?',
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
/** Credential actually accepted by the API (authenticated list call). */
|
|
73
|
-
export async function checkAuthAccepted(apiUrl, jwt, fetchFn = fetch) {
|
|
74
|
-
if (!jwt) {
|
|
75
|
-
return { name: 'Auth', status: 'fail', detail: 'skipped — no credential', hint: 'Fix the Credential check first.' };
|
|
76
|
-
}
|
|
77
|
-
try {
|
|
78
|
-
const res = await fetchFn(`${apiUrl}/api/v1/instances`, {
|
|
79
|
-
headers: { Authorization: `Bearer ${jwt}` },
|
|
80
|
-
signal: AbortSignal.timeout(5000),
|
|
81
|
-
});
|
|
82
|
-
if (res.ok)
|
|
83
|
-
return { name: 'Auth', status: 'ok', detail: 'credential accepted' };
|
|
84
|
-
if (res.status === 401 || res.status === 403) {
|
|
85
|
-
return {
|
|
86
|
-
name: 'Auth',
|
|
87
|
-
status: 'fail',
|
|
88
|
-
detail: `API rejected the credential (HTTP ${res.status})`,
|
|
89
|
-
hint: 'The key is expired or revoked. Create a new one in the dashboard, or re-run autopilot.',
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
return { name: 'Auth', status: 'warn', detail: `unexpected HTTP ${res.status} from /api/v1/instances` };
|
|
93
|
-
}
|
|
94
|
-
catch {
|
|
95
|
-
return { name: 'Auth', status: 'warn', detail: 'could not verify (network error)' };
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
/** Brain instance configured (env or auto-provisioned default). */
|
|
99
|
-
export function checkInstance(instanceId) {
|
|
100
|
-
if (!instanceId) {
|
|
101
|
-
return {
|
|
102
|
-
name: 'Instance',
|
|
103
|
-
status: 'warn',
|
|
104
|
-
detail: 'no CACHLY_BRAIN_INSTANCE_ID set and no default instance resolved',
|
|
105
|
-
hint: 'Run `npx @cachly-dev/mcp-server@latest init` in your project, or export CACHLY_BRAIN_INSTANCE_ID.',
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
const uuidish = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(instanceId);
|
|
109
|
-
return uuidish
|
|
110
|
-
? { name: 'Instance', status: 'ok', detail: instanceId.slice(0, 8) + '…' }
|
|
111
|
-
: {
|
|
112
|
-
name: 'Instance',
|
|
113
|
-
status: 'warn',
|
|
114
|
-
detail: `"${instanceId.slice(0, 24)}" does not look like an instance UUID`,
|
|
115
|
-
hint: 'Copy the instance ID from the dashboard (Instances → your brain).',
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
/** Read-only look at .claude/ in projectDir — never throws. */
|
|
119
|
-
export function inspectAmbientHooks(projectDir) {
|
|
120
|
-
const out = { settingsExists: false, wiredEvents: [], scriptFiles: [] };
|
|
121
|
-
try {
|
|
122
|
-
const settingsPath = resolve(projectDir, '.claude/settings.json');
|
|
123
|
-
out.settingsExists = existsSync(settingsPath);
|
|
124
|
-
if (out.settingsExists) {
|
|
125
|
-
const parsed = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
|
126
|
-
for (const [event, groups] of Object.entries(parsed.hooks ?? {})) {
|
|
127
|
-
// Normalise Windows backslash paths so the marker match and the path
|
|
128
|
-
// extraction below work on every platform (node fs accepts / on Windows).
|
|
129
|
-
const norm = (c) => (c ?? '').replace(/\\/g, '/');
|
|
130
|
-
const ours = (groups ?? []).some((g) => (g.hooks ?? []).some((h) => norm(h.command).includes('.claude/hooks/cachly-ambient-')));
|
|
131
|
-
if (ours) {
|
|
132
|
-
out.wiredEvents.push(event);
|
|
133
|
-
for (const g of groups ?? []) {
|
|
134
|
-
for (const h of g.hooks ?? []) {
|
|
135
|
-
const cmd = norm(h.command);
|
|
136
|
-
const m = cmd.match(/["']?([^"']*\.claude\/hooks\/cachly-ambient-[^"']+)["']?/);
|
|
137
|
-
if (!m)
|
|
138
|
-
continue;
|
|
139
|
-
const scriptPath = m[1].replace('$CLAUDE_PROJECT_DIR', projectDir);
|
|
140
|
-
const exists = existsSync(scriptPath);
|
|
141
|
-
let version = 'unknown';
|
|
142
|
-
if (exists) {
|
|
143
|
-
try {
|
|
144
|
-
const body = readFileSync(scriptPath, 'utf-8');
|
|
145
|
-
version = body.includes(AMBIENT_HOOK_VERSION) ? 'current' : 'stale';
|
|
146
|
-
}
|
|
147
|
-
catch { /* keep unknown */ }
|
|
148
|
-
}
|
|
149
|
-
out.scriptFiles.push({ path: scriptPath, exists, version });
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
catch { /* corrupt settings → report as not wired */ }
|
|
157
|
-
return out;
|
|
158
|
-
}
|
|
159
|
-
const AMBIENT_EVENTS = ['SessionStart', 'UserPromptSubmit', 'PreToolUse', 'Stop'];
|
|
160
|
-
/** Ambient hooks wired, scripts present, version current. */
|
|
161
|
-
export function checkHooks(inspection) {
|
|
162
|
-
if (!inspection.settingsExists || inspection.wiredEvents.length === 0) {
|
|
163
|
-
return {
|
|
164
|
-
name: 'Hooks',
|
|
165
|
-
status: 'warn',
|
|
166
|
-
detail: 'Ambient Recall hooks are not installed in this project',
|
|
167
|
-
hint: 'Run `npx @cachly-dev/mcp-server@latest init` here — memory then injects itself (no hooks = pull-only).',
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
const missingEvents = AMBIENT_EVENTS.filter((e) => !inspection.wiredEvents.includes(e));
|
|
171
|
-
const missingFiles = inspection.scriptFiles.filter((f) => !f.exists);
|
|
172
|
-
const stale = inspection.scriptFiles.filter((f) => f.exists && f.version === 'stale');
|
|
173
|
-
if (missingFiles.length > 0) {
|
|
174
|
-
return {
|
|
175
|
-
name: 'Hooks',
|
|
176
|
-
status: 'fail',
|
|
177
|
-
detail: `settings.json wires hooks whose script files are missing (${missingFiles.length})`,
|
|
178
|
-
hint: 'Re-run `npx @cachly-dev/mcp-server@latest init` to rewrite the scripts.',
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
if (stale.length > 0) {
|
|
182
|
-
return {
|
|
183
|
-
name: 'Hooks',
|
|
184
|
-
status: 'warn',
|
|
185
|
-
detail: `installed hooks are an older version (current: ${AMBIENT_HOOK_VERSION}); v1/v2 shell hooks never ran on native Windows`,
|
|
186
|
-
hint: 'Re-run `npx @cachly-dev/mcp-server@latest init` to upgrade in place.',
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
if (missingEvents.length > 0) {
|
|
190
|
-
return {
|
|
191
|
-
name: 'Hooks',
|
|
192
|
-
status: 'warn',
|
|
193
|
-
detail: `partial install — missing events: ${missingEvents.join(', ')}`,
|
|
194
|
-
hint: 'Re-run `npx @cachly-dev/mcp-server@latest init` to add the missing hooks.',
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
return { name: 'Hooks', status: 'ok', detail: `all 4 events wired, scripts ${AMBIENT_HOOK_VERSION}` };
|
|
198
|
-
}
|
|
199
|
-
/** Net-token ledger readable + backoff state. */
|
|
200
|
-
export function checkLedger(entries, ledgerPath) {
|
|
201
|
-
const bal = netBalance(entries);
|
|
202
|
-
const backing = shouldBackoff(entries);
|
|
203
|
-
if (entries.length === 0) {
|
|
204
|
-
return {
|
|
205
|
-
name: 'Ledger',
|
|
206
|
-
status: 'ok',
|
|
207
|
-
detail: `empty (${ledgerPath}) — fills up once ambient hooks inject`,
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
if (backing) {
|
|
211
|
-
return {
|
|
212
|
-
name: 'Ledger',
|
|
213
|
-
status: 'warn',
|
|
214
|
-
detail: `${entries.length} entries, net ${bal.net} tokens — auto-backoff ACTIVE, injection paused`,
|
|
215
|
-
hint: 'The agent has not reported prevented tokens lately. This self-heals; `ambient-stats` shows details.',
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
return {
|
|
219
|
-
name: 'Ledger',
|
|
220
|
-
status: 'ok',
|
|
221
|
-
detail: `${entries.length} entries, net ${bal.net >= 0 ? '+' : ''}${bal.net} tokens`,
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
const ICON = { ok: '✅', warn: '⚠️ ', fail: '❌' };
|
|
225
|
-
/** Render the report; deterministic, no colors (CI-friendly). */
|
|
226
|
-
export function renderDoctorReport(checks) {
|
|
227
|
-
const lines = ['', '🩺 cachly doctor', ''];
|
|
228
|
-
for (const c of checks) {
|
|
229
|
-
lines.push(` ${ICON[c.status]} ${c.name.padEnd(11)} ${c.detail}`);
|
|
230
|
-
if (c.hint && c.status !== 'ok')
|
|
231
|
-
lines.push(` ↳ ${c.hint}`);
|
|
232
|
-
}
|
|
233
|
-
const fails = checks.filter((c) => c.status === 'fail').length;
|
|
234
|
-
const warns = checks.filter((c) => c.status === 'warn').length;
|
|
235
|
-
lines.push('');
|
|
236
|
-
lines.push(fails > 0
|
|
237
|
-
? ` ${fails} problem${fails > 1 ? 's' : ''} to fix${warns ? `, ${warns} warning${warns > 1 ? 's' : ''}` : ''}.`
|
|
238
|
-
: warns > 0
|
|
239
|
-
? ` No blockers — ${warns} warning${warns > 1 ? 's' : ''}.`
|
|
240
|
-
: ' Everything looks healthy. Your brain is wired.');
|
|
241
|
-
lines.push('');
|
|
242
|
-
return lines.join('\n');
|
|
243
|
-
}
|
|
244
|
-
/** Exit code contract: 1 only on hard failures (warnings stay 0 for CI use). */
|
|
245
|
-
export function doctorExitCode(checks) {
|
|
246
|
-
return checks.some((c) => c.status === 'fail') ? 1 : 0;
|
|
247
|
-
}
|
|
248
|
-
//# sourceMappingURL=doctor.js.map
|
|
1
|
+
import{existsSync as m,readFileSync as p}from"node:fs";import{resolve as y}from"node:path";import{AMBIENT_HOOK_VERSION as c}from"./ambient-hooks.js";import{netBalance as g,shouldBackoff as A}from"./ambient-recall.js";import{cachlyUrl as $}from"./cachly-url.js";const k=18;function H(t=process.version){const e=Number(t.replace(/^v/,"").split(".")[0]);return Number.isFinite(e)&&e>=k?{name:"Node.js",status:"ok",detail:`${t}`}:{name:"Node.js",status:"fail",detail:`${t} \u2014 too old`,hint:`cachly needs Node ${k}+ (built-in fetch). Install a current LTS from nodejs.org.`}}function P(t){if(!t)return{name:"Credential",status:"fail",detail:"CACHLY_JWT is not set",hint:"Run `npx @cachly-dev/mcp-server@latest autopilot` (browser sign-in) or export CACHLY_JWT=<cky_\u2026>."};const e=t.startsWith("cky_"),s=t.split(".").length===3;return!e&&!s?{name:"Credential",status:"warn",detail:"CACHLY_JWT is set but looks neither like a cky_\u2026 key nor a JWT",hint:"Re-copy the key from the dashboard (API Keys) \u2014 it may be truncated."}:{name:"Credential",status:"ok",detail:e?"API key (cky_\u2026)":"JWT"}}async function R(t,e=fetch){try{const s=await e(`${t}/health`,{signal:AbortSignal.timeout(5e3)});return s.ok?{name:"API",status:"ok",detail:`${t} reachable`}:{name:"API",status:"fail",detail:`${t}/health returned HTTP ${s.status}`,hint:`The API answered but is unhealthy \u2014 check ${$("/status","doctor")} or your CACHLY_API_URL.`}}catch{return{name:"API",status:"fail",detail:`${t} not reachable`,hint:"Check your network/proxy. Self-hosted: is CACHLY_API_URL correct and the API running?"}}}async function L(t,e,s=fetch){if(!e)return{name:"Auth",status:"fail",detail:"skipped \u2014 no credential",hint:"Fix the Credential check first."};try{const a=await s(`${t}/api/v1/instances`,{headers:{Authorization:`Bearer ${e}`},signal:AbortSignal.timeout(5e3)});return a.ok?{name:"Auth",status:"ok",detail:"credential accepted"}:a.status===401||a.status===403?{name:"Auth",status:"fail",detail:`API rejected the credential (HTTP ${a.status})`,hint:"The key is expired or revoked. Create a new one in the dashboard, or re-run autopilot."}:{name:"Auth",status:"warn",detail:`unexpected HTTP ${a.status} from /api/v1/instances`}}catch{return{name:"Auth",status:"warn",detail:"could not verify (network error)"}}}function S(t){return t?/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(t)?{name:"Instance",status:"ok",detail:t.slice(0,8)+"\u2026"}:{name:"Instance",status:"warn",detail:`"${t.slice(0,24)}" does not look like an instance UUID`,hint:"Copy the instance ID from the dashboard (Instances \u2192 your brain)."}:{name:"Instance",status:"warn",detail:"no CACHLY_BRAIN_INSTANCE_ID set and no default instance resolved",hint:"Run `npx @cachly-dev/mcp-server@latest init` in your project, or export CACHLY_BRAIN_INSTANCE_ID."}}function j(t){const e={settingsExists:!1,wiredEvents:[],scriptFiles:[]};try{const s=y(t,".claude/settings.json");if(e.settingsExists=m(s),e.settingsExists){const a=JSON.parse(p(s,"utf-8"));for(const[n,l]of Object.entries(a.hooks??{})){const u=o=>(o??"").replace(/\\/g,"/");if((l??[]).some(o=>(o.hooks??[]).some(r=>u(r.command).includes(".claude/hooks/cachly-ambient-")))){e.wiredEvents.push(n);for(const o of l??[])for(const r of o.hooks??[]){const h=u(r.command).match(/["']?([^"']*\.claude\/hooks\/cachly-ambient-[^"']+)["']?/);if(!h)continue;const i=h[1].replace("$CLAUDE_PROJECT_DIR",t),d=m(i);let f="unknown";if(d)try{f=p(i,"utf-8").includes(c)?"current":"stale"}catch{}e.scriptFiles.push({path:i,exists:d,version:f})}}}}}catch{}return e}const v=["SessionStart","UserPromptSubmit","PreToolUse","Stop"];function J(t){if(!t.settingsExists||t.wiredEvents.length===0)return{name:"Hooks",status:"warn",detail:"Ambient Recall hooks are not installed in this project",hint:"Run `npx @cachly-dev/mcp-server@latest init` here \u2014 memory then injects itself (no hooks = pull-only)."};const e=v.filter(n=>!t.wiredEvents.includes(n)),s=t.scriptFiles.filter(n=>!n.exists),a=t.scriptFiles.filter(n=>n.exists&&n.version==="stale");return s.length>0?{name:"Hooks",status:"fail",detail:`settings.json wires hooks whose script files are missing (${s.length})`,hint:"Re-run `npx @cachly-dev/mcp-server@latest init` to rewrite the scripts."}:a.length>0?{name:"Hooks",status:"warn",detail:`installed hooks are an older version (current: ${c}); v1/v2 shell hooks never ran on native Windows`,hint:"Re-run `npx @cachly-dev/mcp-server@latest init` to upgrade in place."}:e.length>0?{name:"Hooks",status:"warn",detail:`partial install \u2014 missing events: ${e.join(", ")}`,hint:"Re-run `npx @cachly-dev/mcp-server@latest init` to add the missing hooks."}:{name:"Hooks",status:"ok",detail:`all 4 events wired, scripts ${c}`}}function O(t,e){const s=g(t),a=A(t);return t.length===0?{name:"Ledger",status:"ok",detail:`empty (${e}) \u2014 fills up once ambient hooks inject`}:a?{name:"Ledger",status:"warn",detail:`${t.length} entries, net ${s.net} tokens \u2014 auto-backoff ACTIVE, injection paused`,hint:"The agent has not reported prevented tokens lately. This self-heals; `ambient-stats` shows details."}:{name:"Ledger",status:"ok",detail:`${t.length} entries, net ${s.net>=0?"+":""}${s.net} tokens`}}const b={ok:"\u2705",warn:"\u26A0\uFE0F ",fail:"\u274C"};function F(t){const e=["","\u{1FA7A} cachly doctor",""];for(const n of t)e.push(` ${b[n.status]} ${n.name.padEnd(11)} ${n.detail}`),n.hint&&n.status!=="ok"&&e.push(` \u21B3 ${n.hint}`);const s=t.filter(n=>n.status==="fail").length,a=t.filter(n=>n.status==="warn").length;return e.push(""),e.push(s>0?` ${s} problem${s>1?"s":""} to fix${a?`, ${a} warning${a>1?"s":""}`:""}.`:a>0?` No blockers \u2014 ${a} warning${a>1?"s":""}.`:" Everything looks healthy. Your brain is wired."),e.push(""),e.join(`
|
|
2
|
+
`)}function Y(t){return t.some(e=>e.status==="fail")?1:0}export{R as checkApiReachable,L as checkAuthAccepted,P as checkCredential,J as checkHooks,S as checkInstance,O as checkLedger,H as checkNodeVersion,Y as doctorExitCode,j as inspectAmbientHooks,F as renderDoctorReport};
|
package/dist/src/editor.js
CHANGED
|
@@ -1,63 +1 @@
|
|
|
1
|
-
|
|
2
|
-
//
|
|
3
|
-
// The evening funnel report showed `unknown: 345` vs `claude: 96` / `vscode: 25`
|
|
4
|
-
// — the largest bucket was unattributed. The old detector only checked four
|
|
5
|
-
// env vars (CURSOR_TRACE_ID, WINDSURF_SESSION_ID, GITHUB_COPILOT_WORKSPACE,
|
|
6
|
-
// CLAUDE_CODE_ENTRYPOINT), so every other host — VS Code running the server as
|
|
7
|
-
// a native MCP stdio child, JetBrains, Zed, plain terminals — fell through to
|
|
8
|
-
// "unknown". This widens detection to the stable signals each host actually
|
|
9
|
-
// sets, ordered most-specific first, and stays a pure function of the env so it
|
|
10
|
-
// is exhaustively unit-testable.
|
|
11
|
-
/**
|
|
12
|
-
* Best-effort host detection. Order matters: forks of VS Code (Cursor,
|
|
13
|
-
* Windsurf) also set TERM_PROGRAM=vscode, so their fork-specific signals are
|
|
14
|
-
* checked BEFORE the generic vscode fallback.
|
|
15
|
-
*/
|
|
16
|
-
export function detectEditor(env = process.env) {
|
|
17
|
-
const has = (k) => typeof env[k] === 'string' && env[k] !== '';
|
|
18
|
-
// ── Claude Code ─────────────────────────────────────────────────────────
|
|
19
|
-
// CLAUDE_CODE_ENTRYPOINT is the long-standing signal; CLAUDECODE=1 is set by
|
|
20
|
-
// newer builds. Either identifies the Claude Code host.
|
|
21
|
-
if (has('CLAUDE_CODE_ENTRYPOINT') || env.CLAUDECODE === '1')
|
|
22
|
-
return 'claude';
|
|
23
|
-
// ── VS Code forks (must precede the generic vscode check) ────────────────
|
|
24
|
-
if (has('CURSOR_TRACE_ID') || env.TERM_PROGRAM === 'cursor')
|
|
25
|
-
return 'cursor';
|
|
26
|
-
if (has('WINDSURF_SESSION_ID') || env.TERM_PROGRAM === 'windsurf')
|
|
27
|
-
return 'windsurf';
|
|
28
|
-
// ── GitHub Copilot (agent workspace) ─────────────────────────────────────
|
|
29
|
-
if (has('GITHUB_COPILOT_WORKSPACE') || has('COPILOT_AGENT_ID'))
|
|
30
|
-
return 'copilot';
|
|
31
|
-
// ── Zed ──────────────────────────────────────────────────────────────────
|
|
32
|
-
if (env.TERM_PROGRAM === 'zed' || has('ZED_TERM'))
|
|
33
|
-
return 'zed';
|
|
34
|
-
// ── JetBrains (IntelliJ/PyCharm/GoLand/… integrated terminal) ────────────
|
|
35
|
-
if (env.TERMINAL_EMULATOR === 'JetBrains-JediTerm' ||
|
|
36
|
-
has('__INTELLIJ_COMMAND_HISTFILE__') ||
|
|
37
|
-
has('IDEA_INITIAL_DIRECTORY')) {
|
|
38
|
-
return 'jetbrains';
|
|
39
|
-
}
|
|
40
|
-
// ── VS Code (generic — after the forks above) ────────────────────────────
|
|
41
|
-
// TERM_PROGRAM=vscode covers the integrated terminal; the macOS bundle id
|
|
42
|
-
// and VSCODE_* handshake vars cover the native MCP stdio child (no terminal).
|
|
43
|
-
if (env.TERM_PROGRAM === 'vscode' ||
|
|
44
|
-
has('VSCODE_PID') ||
|
|
45
|
-
has('VSCODE_CWD') ||
|
|
46
|
-
has('VSCODE_IPC_HOOK') ||
|
|
47
|
-
has('VSCODE_IPC_HOOK_CLI') ||
|
|
48
|
-
has('VSCODE_GIT_IPC_HANDLE') ||
|
|
49
|
-
isVSCodeBundle(env.__CFBundleIdentifier)) {
|
|
50
|
-
return 'vscode';
|
|
51
|
-
}
|
|
52
|
-
return 'unknown';
|
|
53
|
-
}
|
|
54
|
-
/** macOS sets __CFBundleIdentifier to the launching app's bundle id. */
|
|
55
|
-
function isVSCodeBundle(bundle) {
|
|
56
|
-
if (!bundle)
|
|
57
|
-
return false;
|
|
58
|
-
return (bundle === 'com.microsoft.VSCode' ||
|
|
59
|
-
bundle === 'com.microsoft.VSCodeInsiders' ||
|
|
60
|
-
bundle === 'com.visualstudio.code.oss' ||
|
|
61
|
-
bundle.startsWith('com.microsoft.VSCode'));
|
|
62
|
-
}
|
|
63
|
-
//# sourceMappingURL=editor.js.map
|
|
1
|
+
function i(r=process.env){const _=o=>typeof r[o]=="string"&&r[o]!=="";return _("CLAUDE_CODE_ENTRYPOINT")||r.CLAUDECODE==="1"?"claude":_("CURSOR_TRACE_ID")||r.TERM_PROGRAM==="cursor"?"cursor":_("WINDSURF_SESSION_ID")||r.TERM_PROGRAM==="windsurf"?"windsurf":_("GITHUB_COPILOT_WORKSPACE")||_("COPILOT_AGENT_ID")?"copilot":r.TERM_PROGRAM==="zed"||_("ZED_TERM")?"zed":r.TERMINAL_EMULATOR==="JetBrains-JediTerm"||_("__INTELLIJ_COMMAND_HISTFILE__")||_("IDEA_INITIAL_DIRECTORY")?"jetbrains":r.TERM_PROGRAM==="vscode"||_("VSCODE_PID")||_("VSCODE_CWD")||_("VSCODE_IPC_HOOK")||_("VSCODE_IPC_HOOK_CLI")||_("VSCODE_GIT_IPC_HANDLE")||t(r.__CFBundleIdentifier)?"vscode":"unknown"}function t(r){return r?r==="com.microsoft.VSCode"||r==="com.microsoft.VSCodeInsiders"||r==="com.visualstudio.code.oss"||r.startsWith("com.microsoft.VSCode"):!1}export{i as detectEditor};
|