kimal3 0.2.9 → 0.3.0

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 (67) hide show
  1. package/README.md +135 -0
  2. package/dist/api.js +16 -7
  3. package/dist/arbeitsplatz-dateien.js +62 -30
  4. package/dist/argumente.js +25 -97
  5. package/dist/befehle/arbeitsplatz.js +51 -68
  6. package/dist/befehle/firma-daten.js +24 -26
  7. package/dist/befehle/kontext-fragen.js +62 -44
  8. package/dist/befehle/kontext-gemeinsam.js +86 -43
  9. package/dist/befehle/kontext-hoch.js +40 -46
  10. package/dist/befehle/kontext-runter.js +70 -51
  11. package/dist/befehle/login.js +23 -9
  12. package/dist/befehle/logout.js +9 -4
  13. package/dist/befehle/projekt-liste.js +24 -29
  14. package/dist/befehle/projekt-neu.js +25 -31
  15. package/dist/befehle/skill-install.js +78 -49
  16. package/dist/befehle/skill-tausch.js +28 -0
  17. package/dist/befehle/wache.js +12 -6
  18. package/dist/befehle/werkbank.js +118 -88
  19. package/dist/befehle-katalog-en.js +185 -0
  20. package/dist/befehle-katalog.js +10 -49
  21. package/dist/befehlswoerter.js +69 -0
  22. package/dist/einstellungen-mischen.js +2 -2
  23. package/dist/einstellungen-schreiben.js +8 -5
  24. package/dist/fehler.js +5 -5
  25. package/dist/firmen-liste.js +42 -5
  26. package/dist/format.js +41 -0
  27. package/dist/fragen-lesen.js +3 -3
  28. package/dist/hilfe.js +24 -0
  29. package/dist/kimal3.js +77 -71
  30. package/dist/kontext-dateien.js +30 -23
  31. package/dist/kontext-hoch-zeile.js +5 -3
  32. package/dist/kontext-rat.js +151 -0
  33. package/dist/kontext-stand.js +68 -210
  34. package/dist/nachricht.js +39 -15
  35. package/dist/projekt-neu-firma.js +9 -9
  36. package/dist/projekt-zeilen.js +40 -54
  37. package/dist/slash-befehle.js +36 -0
  38. package/dist/sprache.js +114 -0
  39. package/dist/texte/allgemein.js +99 -0
  40. package/dist/texte/arbeitsplatz.js +135 -0
  41. package/dist/texte/kontext-hoch.js +128 -0
  42. package/dist/texte/kontext.js +171 -0
  43. package/dist/texte/projekte.js +126 -0
  44. package/dist/texte/skill.js +87 -0
  45. package/dist/texte/wache.js +36 -0
  46. package/dist/texte/werkbank.js +161 -0
  47. package/dist/wache-rechnung.js +27 -40
  48. package/dist/wache-schalter.js +40 -5
  49. package/dist/werkbank-name.js +28 -10
  50. package/dist/wort.js +98 -0
  51. package/package.json +27 -27
  52. package/skill/SKILL.md +18 -10
  53. package/skill/commands/k3.md +1 -1
  54. package/skill/commands/k3feierabend.md +99 -97
  55. package/skill/commands/k3kontext.md +2 -2
  56. package/skill/commands/k3kurs.md +6 -5
  57. package/skill/commands/k3start.md +2 -1
  58. package/skill/en/SKILL.md +451 -0
  59. package/skill/en/commands/k3.md +106 -0
  60. package/skill/en/commands/k3analyse.md +59 -0
  61. package/skill/en/commands/k3context.md +92 -0
  62. package/skill/en/commands/k3course.md +54 -0
  63. package/skill/en/commands/k3list.md +26 -0
  64. package/skill/en/commands/k3project.md +50 -0
  65. package/skill/en/commands/k3start.md +47 -0
  66. package/skill/en/commands/k3wrapup.md +99 -0
  67. package/dist/zz-kaputt.js +0 -1
@@ -1,8 +1,14 @@
1
1
  import { feld } from "../api.js";
2
2
  import { alsWort } from "../argumente.js";
3
3
  import { schlussFehler } from "../fehler.js";
4
+ import { befehlIn, schalterIn } from "../befehlswoerter.js";
5
+ import { sprache } from "../sprache.js";
6
+ import { ALLGEMEIN_TEXTE } from "../texte/allgemein.js";
7
+ import { KONTEXT_TEXTE } from "../texte/kontext.js";
4
8
  import { BASIS_URL } from "../anmeldung.js";
5
9
  import { findeArbeitsplatz } from "../kontext-dateien.js";
10
+ import { ORDNER_NAMEN } from "../kontext-stand.js";
11
+ import { angeboteneFirmen } from "../firmen-liste.js";
6
12
  /**
7
13
  * Was `kontext runter` (`kontext-runter.ts`) und `kontext hoch`
8
14
  * (`kontext-hoch.ts`) TEILEN -- die `--firma`/`--firma-id`-Optionen und die
@@ -35,28 +41,56 @@ import { findeArbeitsplatz } from "../kontext-dateien.js";
35
41
  * stderr, der Aufrufer gibt nur noch `1` zurueck.
36
42
  */
37
43
  export function arbeitsplatzOderAbsage() {
38
- const ordner = findeArbeitsplatz(process.cwd());
39
- if (ordner !== null)
40
- return ordner;
41
- /*
42
- 🔴 **ECHTE UMLAUTE** -- dieselbe Begruendung wie bei `fremdeDateiAbsage`
43
- zwanzig Zeilen tiefer und in `kontext-fragen.ts:26`: Das hier liest ein
44
- Kunde im Terminal. Bis Review-Runde 4 stand hier die ASCII-Umschrift,
45
- waehrend die Schwesterfunktion in DERSELBEN Datei Umlaute setzte und es im
46
- Kommentar begruendete -- eine Datei, zwei Schreibweisen.
47
-
48
- ⚠️ Der Umlaut-Fix an `kontext-hoch.ts` (Runde 3) hat diesen Zwilling
49
- stehen lassen, und die Wache schlug nicht an: Sie prueft den zitierten
50
- Ausschnitt „Hier steht kein KI-Arbeitsplatz", und der traegt zufaellig
51
- keinen Umlaut. *Eine Wache deckt den Satz, den sie kennt -- nicht die
52
- Regel dahinter.*
53
- */
54
- console.error("Hier steht kein KI-Arbeitsplatz — ich suche von hier aufwärts nach einem");
55
- console.error("Ordner, der `kontext/` UND `CLAUDE.md` enthält.");
56
- console.error("");
57
- console.error(" Wechsle in deinen Arbeitsplatz-Ordner und versuch es dort noch einmal.");
44
+ const fund = findeArbeitsplatz(process.cwd());
45
+ if (fund.art === "gefunden")
46
+ return { pfad: fund.pfad, sprache: fund.sprache };
47
+ arbeitsplatzAbsageZeilen(fund, sprache()).forEach((z) => console.error(z));
58
48
  return null;
59
49
  }
50
+ /**
51
+ * Die Zeilen der Absage, wenn kein (eindeutiger) Arbeitsplatz da ist -- als reine Rechnung mit der
52
+ * Sprache als Pflichtwert, damit `check:cli` beide Sprachen misst (Teil 3, Task 10).
53
+ *
54
+ * 🔴 **ECHTE UMLAUTE** -- dieselbe Begruendung wie bei `fremdeDateiAbsage`
55
+ * weiter unten und in `kontext-fragen.ts`: Das hier liest ein Kunde im
56
+ * Terminal. Bis Review-Runde 4 stand hier die ASCII-Umschrift, waehrend die
57
+ * Schwesterfunktion in DERSELBEN Datei Umlaute setzte -- eine Datei, zwei
58
+ * Schreibweisen. ⚠️ Der Umlaut-Fix an `kontext-hoch.ts` (Runde 3) hat diesen
59
+ * Zwilling stehen lassen, und die Wache schlug nicht an: Sie prueft den
60
+ * zitierten Ausschnitt „Hier steht kein KI-Arbeitsplatz", und der traegt
61
+ * zufaellig keinen Umlaut. *Eine Wache deckt den Satz, den sie kennt -- nicht
62
+ * die Regel dahinter.*
63
+ */
64
+ export function arbeitsplatzAbsageZeilen(fund, s) {
65
+ const t = KONTEXT_TEXTE[s];
66
+ // Spec 3.2: zwei Namen nebeneinander -- melden, nicht still einen waehlen, und nichts schreiben.
67
+ if (fund.art === "beide")
68
+ return [t.bothFolders1(fund.pfad), t.bothFolders2, "", t.bothFolders3];
69
+ return [t.noWorkplace1, t.noWorkplace2, "", t.noWorkplace3];
70
+ }
71
+ /**
72
+ * US-13: Der Ordner hat die alte Sprache, die Firma inzwischen eine andere.
73
+ * Nichts schreiben (sonst stuenden zwei Sprachen nebeneinander), den Weg nennen.
74
+ * ⚠️ ECHTE UMLAUTE -- das liest ein Kunde.
75
+ * `firmenname` (aus der Antwort des Servers) kommt als `--firma "…"` in den Rat, damit
76
+ * `arbeitsplatz neu` bei mehreren Firmen nicht gleich zurueckfragt (Final-Review, Fund 3);
77
+ * `null` (aelterer Server ohne Namen) -> der Rat ohne `--firma`, wie bisher.
78
+ */
79
+ export function fremdeSpracheAbsage(ordner, firma, firmenname) {
80
+ fremdeSpracheZeilen(ordner, firma, firmenname, sprache()).forEach((z) => console.error(z));
81
+ }
82
+ /** Die Zeilen von `fremdeSpracheAbsage` -- rein, Sprache des Menschen als Pflichtwert (`check:cli`). */
83
+ export function fremdeSpracheZeilen(ordner, firma, firmenname, s) {
84
+ const t = KONTEXT_TEXTE[s];
85
+ return [
86
+ t.languageChanged1(firma, ordner, ORDNER_NAMEN[ordner].kontext),
87
+ t.languageChanged2,
88
+ "",
89
+ t.languageChanged3,
90
+ t.languageChangedCommand(befehlIn("arbeitsplatz neu", s), schalterIn("firma", s), firmenname === null ? null : alsWort(firmenname, true)), // kein-anzeigetext: Befehlsschlüssel
91
+ t.languageChanged4,
92
+ ];
93
+ }
60
94
  /**
61
95
  * Was ein Mensch liest, wenn eine der fuenf Dateien keine einzige ihrer Fragen
62
96
  * mehr traegt -- **woertlich dieselben Zeilen fuer `kontext hoch` und
@@ -65,7 +99,7 @@ export function arbeitsplatzOderAbsage() {
65
99
  * 🔴 **WARUM SIE GETEILT WIRD.** `kontext fragen` zaehlte eine solche Datei
66
100
  * vorher stillschweigend mit NULL Fragen und liess sie aus beiden Summen
67
101
  * fallen. Gemessen mit der ausgelieferten `README.md` als `kontext/marke.md`:
68
- * „12 von 12 Fragen" statt 17, „Die Marke" nirgends genannt -- und nach zwoelf
102
+ * „12 von 12 Fragen" statt der vollen Zahl, „Die Marke" nirgends genannt -- und nach zwoelf
69
103
  * Antworten meldete der Befehl `✓ Alle 12 Fragen … sind beantwortet`, waehrend
70
104
  * `kontext hoch` einen Schritt spaeter auf genau dieser Datei abbrach.
71
105
  * *Der lesende Befehl gab die beruhigende Auskunft, der schreibende
@@ -82,10 +116,13 @@ export function arbeitsplatzOderAbsage() {
82
116
  * 🔑 ECHTE UMLAUTE -- das hier liest ein Kunde im Terminal. Die ASCII-Umschrift
83
117
  * dieses Ordners gilt nur fuer Kommentare.
84
118
  */
85
- export function fremdeDateiAbsage(pfad, titel, ankerPraefix, folge) {
86
- console.error(`„${pfad}" sieht nicht aus wie „${titel}". ${folge}`);
87
- console.error(` Ich finde darin keine einzige Frage dieser Datei (Zeilen wie \`<!-- k3:${ankerPraefix}… -->\`).`);
88
- console.error(" Hol sie mit `kimal3 kontext runter` zurück und trag deine Antworten dort ein.");
119
+ export function fremdeDateiAbsage(pfad, feld, ankerPraefix, folge) {
120
+ fremdeDateiZeilen(pfad, feld, ankerPraefix, folge, sprache()).forEach((z) => console.error(z));
121
+ }
122
+ /** Die Zeilen von `fremdeDateiAbsage` -- rein, Sprache des Menschen als Pflichtwert (`check:cli`). */
123
+ export function fremdeDateiZeilen(pfad, feld, ankerPraefix, folge, s) {
124
+ const t = KONTEXT_TEXTE[s];
125
+ return [t.fileNotLike(pfad, t.dateiTitel[feld], folge), t.noQuestionFound(ankerPraefix), t.fetchItBack];
89
126
  }
90
127
  /** `--firma`/`--firma-id` -- die einzigen Optionen, die beide Richtungen kennen. */
91
128
  export const ERLAUBT = ["firma", "firma-id"];
@@ -110,26 +147,28 @@ export const ERLAUBT = ["firma", "firma-id"];
110
147
  * den Ausweg (`--ueberschreiben`) -- sie kommt woertlich vom Server und wird
111
148
  * hier nur ausgegeben, nicht neu formuliert.
112
149
  */
113
- export function absage(antwort, befehl) {
114
- const meldung = feld(antwort.koerper, "meldung") ?? "Das hat nicht geklappt.";
150
+ export function absage(antwort, befehl, optionen) {
151
+ const s = sprache();
152
+ const t = ALLGEMEIN_TEXTE[s];
153
+ const meldung = feld(antwort.koerper, "meldung") ?? t.genericFailure;
115
154
  if (antwort.status === 402) {
116
155
  console.error(meldung);
117
156
  return 4;
118
157
  }
119
158
  if (antwort.status === 401) {
120
- console.error(`${meldung} Bitte \`kimal3 login\` ausführen.`);
159
+ console.error(`${meldung}${t.pleaseSignIn}`);
121
160
  return 2;
122
161
  }
123
162
  if (antwort.status === 409) {
124
163
  const grund = feld(antwort.koerper, "grund");
125
- if (grund === "veraltet") {
164
+ // Teil 2: `update-noetig` und `sprache-anders` (Task 14) kommen wie `veraltet` als fertiger
165
+ // Satz in der Kontosprache -- keine Firmenliste darunter, die mit der Lage nichts zu tun hat.
166
+ if (grund === "veraltet" || grund === "update-noetig" || grund === "sprache-anders") {
126
167
  console.error(meldung);
127
168
  return 1;
128
169
  }
129
170
  const koerper = antwort.koerper;
130
- const namen = Array.isArray(koerper?.firmen)
131
- ? koerper.firmen.filter((x) => typeof x === "string")
132
- : [];
171
+ const namen = angeboteneFirmen(koerper);
133
172
  console.error(meldung);
134
173
  const auswahl = Array.isArray(koerper.auswahl)
135
174
  ? koerper.auswahl.filter((x) => !!x &&
@@ -138,22 +177,22 @@ export function absage(antwort, befehl) {
138
177
  typeof x.name === "string")
139
178
  : [];
140
179
  if (auswahl.length > 0) {
141
- console.error("\n Diese beiden heissen gleich — nimm die ID:");
142
- firmenIdZeilenKontext(auswahl, befehl).forEach((z) => console.error(z));
180
+ console.error(t.sameNameUseId);
181
+ firmenIdZeilenKontext(auswahl, befehl, optionen, s).forEach((z) => console.error(z));
143
182
  }
144
183
  else {
145
- const zeilen = firmenZeilenKontext(namen, befehl);
184
+ const zeilen = firmenZeilenKontext(namen, befehl, optionen, s);
146
185
  if (zeilen.length > 0) {
147
- console.error("\n Deine Firmen:");
186
+ console.error(t.yourCompanies);
148
187
  zeilen.forEach((z) => console.error(z));
149
188
  }
150
189
  }
151
190
  if (grund === "keine-firma") {
152
- console.error(`\n Eine Firma anlegen: ${BASIS_URL}/firma/neu`);
191
+ console.error(t.createCompany(BASIS_URL));
153
192
  }
154
193
  return 1;
155
194
  }
156
- const schluss = schlussFehler(antwort.status, meldung);
195
+ const schluss = schlussFehler(antwort.status, meldung, s);
157
196
  console.error(schluss.text);
158
197
  return schluss.wert;
159
198
  }
@@ -161,7 +200,10 @@ export function absage(antwort, befehl) {
161
200
  * `firmenZeilen` aus `firmen-liste.ts`, nur mit dem richtigen Befehl in der
162
201
  * Zeile -- s. Kommentar an `absage`.
163
202
  */
164
- function firmenZeilenKontext(namen, befehl) {
203
+ export function firmenZeilenKontext(namen, befehl, optionen, s) {
204
+ const t = ALLGEMEIN_TEXTE[s];
205
+ // Befehl, schon getippte Optionen, dann der Firmen-Schalter -- in der Sprache des Satzes.
206
+ const vorne = `${befehlIn(befehl, s)}${optionen}`;
165
207
  const anzahl = (name) => namen.filter((n) => n === name).length;
166
208
  const gesehen = new Set();
167
209
  const zeilen = [];
@@ -171,15 +213,16 @@ function firmenZeilenKontext(namen, befehl) {
171
213
  gesehen.add(name);
172
214
  const wieOft = anzahl(name);
173
215
  if (wieOft === 1) {
174
- zeilen.push(` kimal3 ${befehl} --firma ${alsWort(name, true)}`);
216
+ zeilen.push(t.companyLine(vorne, schalterIn("firma", s), alsWort(name, true)));
175
217
  }
176
218
  else {
177
- zeilen.push(` „${name}" — kommt ${wieOft}× vor und ist über den Namen nicht wählbar.`);
219
+ zeilen.push(t.nameNotUnique(name, wieOft));
178
220
  }
179
221
  }
180
222
  return zeilen;
181
223
  }
182
224
  /** `firmenIdZeilen` aus `firmen-liste.ts`, nur mit dem richtigen Befehl. */
183
- function firmenIdZeilenKontext(auswahl, befehl) {
184
- return auswahl.map((f, i) => ` kimal3 ${befehl} --firma-id "${f.id}" # ${f.name} (${i + 1}.)`);
225
+ export function firmenIdZeilenKontext(auswahl, befehl, optionen, s) {
226
+ const vorne = `${befehlIn(befehl, s)}${optionen}`;
227
+ return auswahl.map((f, i) => ALLGEMEIN_TEXTE[s].companyIdLine(vorne, schalterIn("firma-id", s), f.id, f.name, i + 1));
185
228
  }
@@ -1,6 +1,9 @@
1
- import { zerlege } from "../argumente.js";
1
+ import { schalterOhneWert, zerlege } from "../argumente.js";
2
+ import { sprache } from "../sprache.js";
3
+ import { ALLGEMEIN_TEXTE } from "../texte/allgemein.js";
4
+ import { KONTEXT_HOCH_TEXTE } from "../texte/kontext-hoch.js";
2
5
  import { ruf } from "../api.js";
3
- import { FIRMEN_TEXTE, alsMerkzettel, bekannterStandAus, merkzettelNachHoch, } from "../kontext-stand.js";
6
+ import { firmenTexte, alsMerkzettel, bekannterStandAus, merkzettelNachHoch, } from "../kontext-stand.js";
4
7
  import { traegtFragenVon } from "../fragen-lesen.js";
5
8
  import { leseEineDatei, leseMerkzettelDatei, schreibeMerkzettelDatei } from "../kontext-dateien.js";
6
9
  import { ERLAUBT, absage, arbeitsplatzOderAbsage, fremdeDateiAbsage } from "./kontext-gemeinsam.js";
@@ -12,7 +15,7 @@ import { hochZeile } from "../kontext-hoch-zeile.js";
12
15
  `marke_md`). Fuer vier der fuenf Dateien war das richtig; die fuenfte,
13
16
  `kontext/kurzprofil.md`, fuellt `drei_saetze` und haette daraus `kurzprofil_md`
14
17
  bekommen -- ein Feld, das die Route nicht kennt. Die Zuordnung steht jetzt als
15
- Tabelle in `FIRMEN_TEXTE` (`../kontext-stand.js`), und dass sie mit `FELDER`
18
+ Tabelle in `firmenTexte` (`../kontext-stand.js`), und dass sie mit `FELDER`
16
19
  in der App uebereinstimmt, prueft `check:kontext`.
17
20
  */
18
21
  // 📌 `bekannterStandAus` wohnte hier (Fix-Runde 1, Review-Fund 1) und ist seit
@@ -21,25 +24,10 @@ import { hochZeile } from "../kontext-hoch-zeile.js";
21
24
  // von HIER haette `api.ts` in einen Kreisimport mit sich selbst gezwungen
22
25
  // (diese Datei importiert `ruf` aus `../api.js`). Die volle Begruendung der
23
26
  // Rechnung selbst steht jetzt dort.
24
- const HILFE_HOCH = `
25
- kimal3 kontext hoch [--firma "Name" | --firma-id "…"] [--ueberschreiben]
26
-
27
- Schickt deine lokalen Aenderungen an allen fuenf Firmen-Texten nach oben --
28
- fuer den Firmen-Admin. Nur wer Admin ist, darf das; die App entscheidet.
29
-
30
- Die fuenf sind die Dateien in kontext/: kurzprofil.md, firma.md, marke.md,
31
- systeme.md, sicherheit.md.
32
-
33
- Welche Fragen darin noch offen sind, zeigt "kimal3 kontext fragen".
34
-
35
- --firma "Name" Noetig, wenn du zu mehreren Firmen gehoerst.
36
- Die Absage nennt dir die Namen als fertige Befehle.
37
-
38
- --firma-id "…" Fuer den Fall, dass zwei deiner Firmen GLEICH heissen.
39
-
40
- --ueberschreiben Speichert auch dann, wenn die Firma inzwischen von
41
- jemand anderem geaendert wurde (§7d).
42
- `;
27
+ /** Die Hilfe von `kontext hoch` / `context upload` in der Sprache des Menschen. */
28
+ export function hilfe(s) {
29
+ return KONTEXT_HOCH_TEXTE[s].uploadHelp;
30
+ }
43
31
  /**
44
32
  * Schickt die fuenf Firmen-Texte des gefundenen Arbeitsplatzes nach oben --
45
33
  * die Gegenrichtung zu `kontextRunter` (`kontext-runter.ts`). Fundregel,
@@ -58,20 +46,21 @@ const HILFE_HOCH = `
58
46
  * 🔴 **Importiert bewusst KEIN `FELDER` aus `src/app/firma/kontext-felder.ts`.**
59
47
  * `cli/src/` ist ein eigenes Paket mit eigenem `tsconfig` und darf nichts aus
60
48
  * `src/` importieren (s. Kopf von `kontext-stand.ts`). Welche Datei welches
61
- * Feld fuellt, steht deshalb in `FIRMEN_TEXTE` -- und dass diese Tabelle mit
49
+ * Feld fuellt, steht deshalb in `firmenTexte` -- und dass diese Tabelle mit
62
50
  * `FELDER` uebereinstimmt, ist eine Pruefung in `check:kontext`.
63
51
  */
64
52
  export async function kontextHoch(argv) {
53
+ let s = sprache();
54
+ let t = KONTEXT_HOCH_TEXTE[s];
65
55
  if (argv.includes("--help") || argv.includes("-h")) {
66
- console.log(HILFE_HOCH);
56
+ console.log(hilfe(s));
67
57
  return 0;
68
58
  }
69
- const ueberschreiben = argv.includes("--ueberschreiben");
70
- // ⚠️ `zerlege` kennt keine Optionen ohne Wert -- `--ueberschreiben` wird
71
- // deshalb VOR der Zerlegung herausgefiltert, genau wie `--help`/`-h` oben
59
+ // ⚠️ `zerlege` kennt keine Optionen ohne Wert -- `--ueberschreiben` (englisch `--overwrite`)
60
+ // wird deshalb VOR der Zerlegung herausgefiltert, genau wie `--help`/`-h` oben
72
61
  // nie an `zerlege` gereicht werden.
73
- const ohneFlag = argv.filter((a) => a !== "--ueberschreiben");
74
- const zerlegt = zerlege(ohneFlag, ERLAUBT);
62
+ const { gesetzt: ueberschreiben, rest: ohneFlag } = schalterOhneWert(argv, "ueberschreiben");
63
+ const zerlegt = zerlege(ohneFlag, ERLAUBT, s);
75
64
  if (!zerlegt.ok) {
76
65
  console.error(zerlegt.meldung);
77
66
  return 1;
@@ -83,8 +72,8 @@ export async function kontextHoch(argv) {
83
72
  // (`bekannterStandAus`), nicht nur aus den Dateien, die gleich gelesen
84
73
  // werden. Die Firmenzeile traegt genau EIN `geaendert_am` fuer alle fuenf
85
74
  // Felder -- jeder nicht-leere Eintrag kennt es also, auch der der `CLAUDE.md`.
86
- const lokalerMerkzettel = leseMerkzettelDatei(ordner);
87
- const bekannterStand = bekannterStandAus(lokalerMerkzettel);
75
+ const lokalerMerkzettel = leseMerkzettelDatei(ordner.pfad);
76
+ const bekannterStand = bekannterStandAus(lokalerMerkzettel, ordner.sprache);
88
77
  /*
89
78
  ---- die fuenf Texte lesen ---------------------------------------------
90
79
 
@@ -95,15 +84,15 @@ export async function kontextHoch(argv) {
95
84
  benennen kann, ist teurer als ein Abbruch, der klar sagt, warum.*
96
85
  */
97
86
  const werte = {};
98
- for (const datei of FIRMEN_TEXTE) {
99
- const gelesen = leseEineDatei(ordner, datei.pfad);
87
+ for (const datei of firmenTexte(ordner.sprache)) {
88
+ const gelesen = leseEineDatei(ordner.pfad, datei.pfad);
100
89
  if (!gelesen.ok) {
101
90
  console.error(gelesen.meldung);
102
91
  return 1;
103
92
  }
104
93
  if (gelesen.inhalt === null) {
105
- console.error(`„${datei.pfad}" gibt es hier nicht -- ich schicke nichts Halbes hoch.`);
106
- console.error(" Erst `kimal3 kontext runter` ausfuehren, dann bearbeiten, dann noch einmal.");
94
+ console.error(t.uploadFileMissing(datei.pfad));
95
+ console.error(t.uploadFetchFirst);
107
96
  return 1;
108
97
  }
109
98
  /*
@@ -121,7 +110,7 @@ export async function kontextHoch(argv) {
121
110
  angelegt hat, weil `kontext runter` noch nie lief.
122
111
  */
123
112
  if (!traegtFragenVon(gelesen.inhalt, datei.ankerPraefix)) {
124
- fremdeDateiAbsage(datei.pfad, datei.titel, datei.ankerPraefix, "Nichts wurde gespeichert.");
113
+ fremdeDateiAbsage(datei.pfad, datei.feld, datei.ankerPraefix, t.nothingSaved);
125
114
  return 1;
126
115
  }
127
116
  werte[datei.feld] = gelesen.inhalt;
@@ -134,23 +123,28 @@ export async function kontextHoch(argv) {
134
123
  suche.set("firma", wunsch);
135
124
  if (wunschId !== undefined)
136
125
  suche.set("firma-id", wunschId);
137
- const pfad = suche.toString() ? `/api/cli/kontext?${suche.toString()}` : "/api/cli/kontext";
138
- const koerper = { stand: bekannterStand, ...werte };
126
+ const pfad = suche.toString() ? `/api/cli/kontext?${suche.toString()}` : "/api/cli/kontext"; // kein-anzeigetext: Pfad der Schnittstelle
127
+ // 🌐 Teil 2: Die Sprache des ORDNERS geht mit. Der Server haelt sie gegen die Firmensprache und
128
+ // sagt `sprache-anders` (409), statt deutsche Texte in eine englische Firma zu schreiben (US-13).
129
+ const koerper = { stand: bekannterStand, ...werte, sprache: ordner.sprache };
139
130
  if (ueberschreiben)
140
131
  koerper.ueberschreiben = true;
141
- const antwort = await ruf(pfad, { methode: "POST", mitAusweis: true, koerper });
132
+ const antwort = await ruf(pfad, { methode: "POST", mitAusweis: true, koerper }); // kein-anzeigetext: HTTP-Verb
133
+ // 🌐 Die Antwort kann die Kontosprache umgestellt haben (Spec 3.2, Schritt 3): Was ab hier gedruckt wird, in der neuen.
134
+ s = sprache();
135
+ t = KONTEXT_HOCH_TEXTE[s];
142
136
  if (antwort.status !== 200) {
143
- return absage(antwort, "kontext hoch");
137
+ return absage(antwort, "kontext hoch", ""); // kein-anzeigetext: Befehlsschlüssel
144
138
  }
145
139
  // 🔴 Ein `200` mit unlesbarem Rumpf ist KEIN Erfolg -- dasselbe Muster wie
146
140
  // in `kontextRunter` und in `firma-daten.ts`.
147
141
  if (antwort.koerper === null || typeof antwort.koerper !== "object") {
148
- console.error("Die Antwort war nicht lesbar. Bitte gleich noch einmal.");
142
+ console.error(ALLGEMEIN_TEXTE[s].unreadableAnswer);
149
143
  return 3;
150
144
  }
151
145
  const ergebnis = alsHochAntwort(antwort.koerper);
152
146
  if (ergebnis === null) {
153
- console.error("Die Antwort war nicht lesbar. Bitte gleich noch einmal.");
147
+ console.error(ALLGEMEIN_TEXTE[s].unreadableAnswer);
154
148
  return 3;
155
149
  }
156
150
  /*
@@ -173,7 +167,7 @@ export async function kontextHoch(argv) {
173
167
  CLAUDE.md" und riete zu `kontext hoch` -- dem Befehl, der sie gar nicht
174
168
  mitnimmt. Gemessen auf der Kundenstrecke am 2026-08-25.
175
169
  */
176
- const zuSchreiben = merkzettelNachHoch(ergebnis.merkzettel, lokalerMerkzettel, FIRMEN_TEXTE.map((d) => d.pfad));
170
+ const zuSchreiben = merkzettelNachHoch(ergebnis.merkzettel, lokalerMerkzettel, firmenTexte(ordner.sprache).map((d) => d.pfad), ordner.sprache);
177
171
  /*
178
172
  🔴 **DIE ERFOLGSMELDUNG STEHT VOR DEM MERKZETTEL** (Review-Runde 4).
179
173
 
@@ -186,8 +180,8 @@ export async function kontextHoch(argv) {
186
180
  was daneben schiefging. Was hochgeschickt wurde, haengt nicht daran, ob ein
187
181
  Merkzettel auf der Platte landet.
188
182
  */
189
- console.log(hochZeile(ergebnis.uebernommen));
190
- const merkzettelSchreiben = schreibeMerkzettelDatei(ordner, zuSchreiben);
183
+ console.log(hochZeile(ergebnis.uebernommen, s));
184
+ const merkzettelSchreiben = schreibeMerkzettelDatei(ordner.pfad, zuSchreiben);
191
185
  if (!merkzettelSchreiben.ok) {
192
186
  /*
193
187
  🔴 **ECHTE UMLAUTE -- das liest ein Kunde im Terminal** (Projektregel,
@@ -209,7 +203,7 @@ export async function kontextHoch(argv) {
209
203
  verteilt und ist durch eine `includes`-Pruefung ohnehin nicht erfassbar.
210
204
  *Wer den Satz hier aendert, aendert ihn dort von Hand mit.*
211
205
  */
212
- console.error("Die Firma hat deine Änderungen gespeichert — nur der lokale Merkzettel ließ sich nicht schreiben:");
206
+ console.error(t.savedButTracking);
213
207
  console.error(merkzettelSchreiben.meldung);
214
208
  // B-d (Dennis, 17.09.): Das ist ein ERFOLG -- die Firma hat gespeichert.
215
209
  // Der Rueckgabewert ist fuer Maschinen da, und fuer die ist "gespeichert"