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.
- package/README.md +135 -0
- package/dist/api.js +16 -7
- package/dist/arbeitsplatz-dateien.js +62 -30
- package/dist/argumente.js +25 -97
- package/dist/befehle/arbeitsplatz.js +51 -68
- package/dist/befehle/firma-daten.js +24 -26
- package/dist/befehle/kontext-fragen.js +62 -44
- package/dist/befehle/kontext-gemeinsam.js +86 -43
- package/dist/befehle/kontext-hoch.js +40 -46
- package/dist/befehle/kontext-runter.js +70 -51
- package/dist/befehle/login.js +23 -9
- package/dist/befehle/logout.js +9 -4
- package/dist/befehle/projekt-liste.js +24 -29
- package/dist/befehle/projekt-neu.js +25 -31
- package/dist/befehle/skill-install.js +78 -49
- package/dist/befehle/skill-tausch.js +28 -0
- package/dist/befehle/wache.js +12 -6
- package/dist/befehle/werkbank.js +118 -88
- package/dist/befehle-katalog-en.js +185 -0
- package/dist/befehle-katalog.js +10 -49
- package/dist/befehlswoerter.js +69 -0
- package/dist/einstellungen-mischen.js +2 -2
- package/dist/einstellungen-schreiben.js +8 -5
- package/dist/fehler.js +5 -5
- package/dist/firmen-liste.js +42 -5
- package/dist/format.js +41 -0
- package/dist/fragen-lesen.js +3 -3
- package/dist/hilfe.js +24 -0
- package/dist/kimal3.js +77 -71
- package/dist/kontext-dateien.js +30 -23
- package/dist/kontext-hoch-zeile.js +5 -3
- package/dist/kontext-rat.js +151 -0
- package/dist/kontext-stand.js +68 -210
- package/dist/nachricht.js +39 -15
- package/dist/projekt-neu-firma.js +9 -9
- package/dist/projekt-zeilen.js +40 -54
- package/dist/slash-befehle.js +36 -0
- package/dist/sprache.js +114 -0
- package/dist/texte/allgemein.js +99 -0
- package/dist/texte/arbeitsplatz.js +135 -0
- package/dist/texte/kontext-hoch.js +128 -0
- package/dist/texte/kontext.js +171 -0
- package/dist/texte/projekte.js +126 -0
- package/dist/texte/skill.js +87 -0
- package/dist/texte/wache.js +36 -0
- package/dist/texte/werkbank.js +161 -0
- package/dist/wache-rechnung.js +27 -40
- package/dist/wache-schalter.js +40 -5
- package/dist/werkbank-name.js +28 -10
- package/dist/wort.js +98 -0
- package/package.json +27 -27
- package/skill/SKILL.md +18 -10
- package/skill/commands/k3.md +1 -1
- package/skill/commands/k3feierabend.md +99 -97
- package/skill/commands/k3kontext.md +2 -2
- package/skill/commands/k3kurs.md +6 -5
- package/skill/commands/k3start.md +2 -1
- package/skill/en/SKILL.md +451 -0
- package/skill/en/commands/k3.md +106 -0
- package/skill/en/commands/k3analyse.md +59 -0
- package/skill/en/commands/k3context.md +92 -0
- package/skill/en/commands/k3course.md +54 -0
- package/skill/en/commands/k3list.md +26 -0
- package/skill/en/commands/k3project.md +50 -0
- package/skill/en/commands/k3start.md +47 -0
- package/skill/en/commands/k3wrapup.md +99 -0
- package/dist/zz-kaputt.js +0 -1
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
2
|
import { FIRMEN_OPTIONEN, dateienSchreiben, vorlageHolen, werkbankOrdner, istUnsichererOrdnername, } from "../arbeitsplatz-dateien.js";
|
|
3
3
|
import { alsBefehlszeile, alsWort, trenneNamenUndOptionen, zerlege } from "../argumente.js";
|
|
4
|
+
import { befehlIn } from "../befehlswoerter.js";
|
|
5
|
+
import { slashIn } from "../slash-befehle.js";
|
|
6
|
+
import { sprache } from "../sprache.js";
|
|
7
|
+
import { ARBEITSPLATZ_TEXTE } from "../texte/arbeitsplatz.js";
|
|
4
8
|
import { fragenAus, traegtFragenVon } from "../fragen-lesen.js";
|
|
5
|
-
import {
|
|
6
|
-
import { werkbankOrdnerAus, werkbankUmbenennen } from "../werkbank-name.js";
|
|
9
|
+
import { ORDNER_NAMEN, firmenTexte } from "../kontext-stand.js";
|
|
10
|
+
import { werkbankOrdnerAus, werkbankSpracheAus, werkbankUmbenennen } from "../werkbank-name.js";
|
|
7
11
|
/**
|
|
8
12
|
* Holt die KI-Arbeitsplatz-Vorlage vom Server und legt sie lokal an --
|
|
9
13
|
* `CLAUDE.md`, Takt-Befehle, die Werkbank fuer eigene Projekte.
|
|
@@ -25,32 +29,10 @@ import { werkbankOrdnerAus, werkbankUmbenennen } from "../werkbank-name.js";
|
|
|
25
29
|
* 🔁 Die Schreib-Maschinerie wohnt seit dem 2026-08-20 in
|
|
26
30
|
* `../arbeitsplatz-dateien.ts`, weil `werkbank neu` dieselbe braucht.
|
|
27
31
|
*/
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
die ganze Familie: Firmenebene, Werkbank, Beispielprojekt.
|
|
33
|
-
|
|
34
|
-
Der Ordner heisst IMMER "KI-Arbeitsplatz". Mehrere Firmen trennst du
|
|
35
|
-
ueber den Ordner darueber, z. B. Kunden/ARNO/KI-Arbeitsplatz.
|
|
36
|
-
|
|
37
|
-
dein-vorname Optional. Er benennt die WERKBANK darin -- aus "sabine"
|
|
38
|
-
wird "werkbank-sabine". Ohne Angabe steht dort der Name,
|
|
39
|
-
den der Server aus deiner Anmelde-Adresse gebildet hat.
|
|
40
|
-
|
|
41
|
-
--firma "Name" Noetig, wenn du zu mehreren Firmen gehoerst -- der
|
|
42
|
-
Firmenkontext kommt gleich mit in den Ordner.
|
|
43
|
-
Die Absage nennt dir die Namen als fertige Befehle.
|
|
44
|
-
|
|
45
|
-
--firma-id "…" Fuer den Fall, dass zwei deiner Firmen GLEICH heissen.
|
|
46
|
-
Auch diese Absage nennt dir fertige Befehle.
|
|
47
|
-
|
|
48
|
-
🔴 Bricht ab, wenn der Zielordner schon existiert und NICHT leer ist --
|
|
49
|
-
eigene Arbeit wird dadurch nie versehentlich ueberschrieben.
|
|
50
|
-
|
|
51
|
-
Du hast schon einen Firmen-Ordner und brauchst nur eine eigene Werkbank?
|
|
52
|
-
kimal3 werkbank neu <dein-vorname>
|
|
53
|
-
`;
|
|
32
|
+
/** Die Hilfe von `arbeitsplatz neu` / `workplace new` in der Sprache des Menschen. */
|
|
33
|
+
export function hilfe(s) {
|
|
34
|
+
return ARBEITSPLATZ_TEXTE[s].help;
|
|
35
|
+
}
|
|
54
36
|
/*
|
|
55
37
|
🔴 **Der Rat in den Absagen hat sich am 2026-08-20 UMGEDREHT** -- und das ist
|
|
56
38
|
der Kern der Umbenennung, nicht ihr Nebeneffekt.
|
|
@@ -85,17 +67,13 @@ const HILFE = `
|
|
|
85
67
|
* fest im Text, waere das eine zweite Wahrheit ueber den Aufbau — dieselbe, die
|
|
86
68
|
* Runde 3 zu PR #24 auf `/pro` gefunden hat.
|
|
87
69
|
*/
|
|
88
|
-
function hinweisFuer(ordnerName) {
|
|
89
|
-
|
|
90
|
-
return (" Steht dein Arbeitsplatz schon und dir fehlt nur die eigene Werkbank?\n" +
|
|
91
|
-
" Dann geh HINEIN und leg sie dort an:\n" +
|
|
92
|
-
` cd ${ziel}\n` +
|
|
93
|
-
" kimal3 werkbank neu <dein-vorname>");
|
|
70
|
+
function hinweisFuer(ordnerName, s) {
|
|
71
|
+
return ARBEITSPLATZ_TEXTE[s].adviceWorkbenchOnly(alsWort(ordnerName), befehlIn("werkbank neu", s)); // kein-anzeigetext: Befehlsschlüssel
|
|
94
72
|
}
|
|
95
|
-
export function fragenstandAus(dateien) {
|
|
73
|
+
export function fragenstandAus(dateien, sprache) {
|
|
96
74
|
let offen = 0;
|
|
97
75
|
let gesamt = 0;
|
|
98
|
-
for (const text of
|
|
76
|
+
for (const text of firmenTexte(sprache)) {
|
|
99
77
|
const geliefert = dateien.find((d) => d.pfad === text.pfad);
|
|
100
78
|
if (geliefert === undefined)
|
|
101
79
|
return { art: "unbekannt" };
|
|
@@ -114,8 +92,10 @@ export function fragenstandAus(dateien) {
|
|
|
114
92
|
return offen === 0 ? { art: "keine" } : { art: "offen", offen, gesamt };
|
|
115
93
|
}
|
|
116
94
|
export async function arbeitsplatzNeu(argv) {
|
|
95
|
+
let s = sprache();
|
|
96
|
+
let t = ARBEITSPLATZ_TEXTE[s];
|
|
117
97
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
118
|
-
console.log(
|
|
98
|
+
console.log(hilfe(s));
|
|
119
99
|
return 0;
|
|
120
100
|
}
|
|
121
101
|
/*
|
|
@@ -138,7 +118,7 @@ export async function arbeitsplatzNeu(argv) {
|
|
|
138
118
|
const { woerter, optionen: optionsArgv } = trenneNamenUndOptionen(argv);
|
|
139
119
|
const nameArg = woerter[0];
|
|
140
120
|
if (nameArg !== undefined && nameArg.trim() === "") {
|
|
141
|
-
console.error(
|
|
121
|
+
console.error(t.emptyName + hilfe(s));
|
|
142
122
|
return 1;
|
|
143
123
|
}
|
|
144
124
|
if (woerter.length > 1) {
|
|
@@ -166,20 +146,18 @@ export async function arbeitsplatzNeu(argv) {
|
|
|
166
146
|
*/
|
|
167
147
|
const optionsAnhang = optionsArgv.length === 0 ? "" : ` ${alsBefehlszeile(optionsArgv)}`;
|
|
168
148
|
const vorschlag = einfacheWoerter.length === woerter.length
|
|
169
|
-
?
|
|
170
|
-
` kimal3 arbeitsplatz neu ${einfacheWoerter.join("-")}${optionsAnhang}\n`
|
|
149
|
+
? t.nameSuggestion(befehlIn("arbeitsplatz neu", s), einfacheWoerter.join("-"), optionsAnhang) // kein-anzeigetext: Befehlsschlüssel
|
|
171
150
|
: "";
|
|
172
|
-
console.error(
|
|
173
|
-
`${vorschlag}${HILFE}`);
|
|
151
|
+
console.error(t.onlyOneName(woerter[1]) + vorschlag + hilfe(s));
|
|
174
152
|
return 1;
|
|
175
153
|
}
|
|
176
154
|
/*
|
|
177
155
|
🔑 Erst JETZT die Optionen -- nach den Namens-Absagen, damit ein Mensch mit
|
|
178
156
|
zwei Vornamen die Schreibhilfe bekommt und nicht eine Options-Meldung.
|
|
179
157
|
*/
|
|
180
|
-
const zerlegt = zerlege(optionsArgv, FIRMEN_OPTIONEN);
|
|
158
|
+
const zerlegt = zerlege(optionsArgv, FIRMEN_OPTIONEN, s);
|
|
181
159
|
if (!zerlegt.ok) {
|
|
182
|
-
console.error(`${zerlegt.meldung}\n${
|
|
160
|
+
console.error(`${zerlegt.meldung}\n${hilfe(s)}`);
|
|
183
161
|
return 1;
|
|
184
162
|
}
|
|
185
163
|
const wunsch = {
|
|
@@ -193,14 +171,14 @@ export async function arbeitsplatzNeu(argv) {
|
|
|
193
171
|
HIER ein Fehler, weil ein Mensch etwas getippt hat und eine Antwort verdient
|
|
194
172
|
-- der Server schweigt im selben Fall und bleibt beim Vordruck.
|
|
195
173
|
*/
|
|
196
|
-
|
|
174
|
+
// 🌐 Teil 2: Hier geht es nur um „bleibt etwas uebrig?" -- das Praefix ist egal. Welches es
|
|
175
|
+
// wird, sagt erst die Lieferung (die Werkbank vom Server traegt die Kontosprache), s. unten.
|
|
197
176
|
if (nameArg !== undefined) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
console.error(
|
|
201
|
-
console.error("Zeichen uebrig, die in keinem Ordnernamen stehen duerfen.");
|
|
177
|
+
if (werkbankOrdnerAus(nameArg, "de") === null) {
|
|
178
|
+
console.error(t.unusableName1(nameArg));
|
|
179
|
+
console.error(t.unusableName2);
|
|
202
180
|
console.error("");
|
|
203
|
-
console.error("
|
|
181
|
+
console.error(t.unusableName3(befehlIn("arbeitsplatz neu", s))); // kein-anzeigetext: Befehlsschlüssel
|
|
204
182
|
return 1;
|
|
205
183
|
}
|
|
206
184
|
}
|
|
@@ -218,12 +196,13 @@ export async function arbeitsplatzNeu(argv) {
|
|
|
218
196
|
hineinzuschreiben -- sonst hiesse seine Werkbank nach dem zweiten Versuch
|
|
219
197
|
anders als beim ersten gewollt, und niemand saehe, woran es lag.
|
|
220
198
|
*/
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
: `arbeitsplatz neu ${alsWort(nameArg)}`;
|
|
224
|
-
const holen = await vorlageHolen(befehlsname, wunsch);
|
|
199
|
+
// `null`: Der Ordner entsteht hier erst -- es gibt keine Firma, die man aus ihm lesen koennte.
|
|
200
|
+
const holen = await vorlageHolen("arbeitsplatz neu", nameArg === undefined ? "" : ` ${alsWort(nameArg)}`, wunsch, null); // kein-anzeigetext: Befehlsschlüssel
|
|
225
201
|
if (!holen.ok)
|
|
226
202
|
return holen.wert;
|
|
203
|
+
// 🌐 Die Antwort kann die Kontosprache umgestellt haben (Spec 3.2, Schritt 3): Was ab hier gedruckt wird, in der neuen.
|
|
204
|
+
s = sprache();
|
|
205
|
+
t = ARBEITSPLATZ_TEXTE[s];
|
|
227
206
|
const daten = holen.daten;
|
|
228
207
|
// 🔴 R2-1: `daten.wurzel` kommt genauso ROH vom Server wie jeder `datei.pfad`
|
|
229
208
|
// -- dieselbe Gefahr (manipulierte Antwort, z. B. ueber ein umgebogenes
|
|
@@ -243,7 +222,7 @@ export async function arbeitsplatzNeu(argv) {
|
|
|
243
222
|
// `resolve(".")` ist das aktuelle Verzeichnis, und in einem leeren Ordner
|
|
244
223
|
// waere die ganze Familie einfach dorthin gefallen.
|
|
245
224
|
if (istUnsichererOrdnername(daten.wurzel)) {
|
|
246
|
-
console.error(
|
|
225
|
+
console.error(t.unsafeFolderName(daten.wurzel));
|
|
247
226
|
return 3;
|
|
248
227
|
}
|
|
249
228
|
/*
|
|
@@ -286,22 +265,25 @@ export async function arbeitsplatzNeu(argv) {
|
|
|
286
265
|
auf dieselbe Wirklichkeit zu geben.
|
|
287
266
|
*/
|
|
288
267
|
if (werkbankVomServer === null) {
|
|
289
|
-
console.error(
|
|
290
|
-
console.error(
|
|
268
|
+
console.error(t.noWorkbank1);
|
|
269
|
+
console.error(t.noWorkbank2);
|
|
291
270
|
return 3;
|
|
292
271
|
}
|
|
272
|
+
// 🌐 Teil 2: Das Praefix der Lieferung ist die Kontosprache (`/pro` verspricht englischen
|
|
273
|
+
// Konten `workbench-sabine`). Ein getipptes fremdes Praefix wird ersetzt, nie verdoppelt.
|
|
274
|
+
const gewuenschteWerkbank = nameArg === undefined ? null : werkbankOrdnerAus(nameArg, werkbankSpracheAus(werkbankVomServer) ?? "de");
|
|
293
275
|
const dateien = gewuenschteWerkbank !== null
|
|
294
276
|
? werkbankUmbenennen(daten.dateien, werkbankVomServer, gewuenschteWerkbank)
|
|
295
277
|
: daten.dateien;
|
|
296
278
|
const ordnerName = daten.wurzel;
|
|
297
|
-
const wert = dateienSchreiben(dateien, ordnerName, hinweisFuer(ordnerName));
|
|
279
|
+
const wert = dateienSchreiben(dateien, ordnerName, hinweisFuer(ordnerName, s));
|
|
298
280
|
if (wert !== 0)
|
|
299
281
|
return wert;
|
|
300
282
|
// ⚠️ Der ABSOLUTE Pfad, nicht der eingegebene Name. Beim Umzug der
|
|
301
283
|
// Schreib-Maschinerie (2026-08-20) war das kurz ein relativer Name -- ein
|
|
302
284
|
// Rueckschritt: Der Mensch soll sehen, WO der Ordner gelandet ist, und genau
|
|
303
285
|
// das ist der Grund, warum hier `resolve()` steht und nicht `ordnerName`.
|
|
304
|
-
console.log(
|
|
286
|
+
console.log(t.filesCreated(dateien.length));
|
|
305
287
|
console.log(` ${resolve(ordnerName)}`);
|
|
306
288
|
/*
|
|
307
289
|
🔴 **Der Erfolgsfall muss sagen, was das Argument getan hat** (Review-Runde 5
|
|
@@ -318,19 +300,19 @@ export async function arbeitsplatzNeu(argv) {
|
|
|
318
300
|
dort, wo es geklappt hat, nicht nur dort, wo es schiefging.*
|
|
319
301
|
*/
|
|
320
302
|
if (gewuenschteWerkbank !== null) {
|
|
321
|
-
console.log(
|
|
303
|
+
console.log(t.workbenchNamed(gewuenschteWerkbank));
|
|
322
304
|
}
|
|
323
305
|
console.log("");
|
|
324
|
-
console.log(
|
|
306
|
+
console.log(t.nextStepsHeader);
|
|
325
307
|
// ⚠️ NACH dem Umbenennen ableiten, nicht davor -- sonst zeigte der Weg-Hinweis
|
|
326
308
|
// in die Werkbank, die der Server geschickt hat, statt in die, die auf der
|
|
327
309
|
// Platte liegt. *Eine Ableitung, die eine Zeile zu frueh gelesen wird, fuehrt
|
|
328
310
|
// zuverlaessig ins Leere.*
|
|
329
311
|
const werkbank = werkbankOrdner(dateien);
|
|
330
312
|
const cdZiel = werkbank !== null ? `${ordnerName}/${werkbank}` : ordnerName;
|
|
331
|
-
console.log(` cd ${alsWort(cdZiel)}`);
|
|
332
|
-
console.log(" claude");
|
|
333
|
-
console.log(
|
|
313
|
+
console.log(` cd ${alsWort(cdZiel)}`); // kein-anzeigetext: Befehlszeile zum Kopieren
|
|
314
|
+
console.log(" claude"); // kein-anzeigetext: Befehlszeile zum Kopieren
|
|
315
|
+
console.log(t.nextStepsSay);
|
|
334
316
|
/*
|
|
335
317
|
🔴 **HIER RISS DIE KETTE.**
|
|
336
318
|
Bis zum 2026-08-28 endete dieser Befehl immer mit denselben drei Zeilen: Der
|
|
@@ -371,12 +353,13 @@ export async function arbeitsplatzNeu(argv) {
|
|
|
371
353
|
daran nichts mehr aendern. Deshalb steht das hier ganz unten und kann nur
|
|
372
354
|
noch schweigen, nie abbrechen.
|
|
373
355
|
*/
|
|
374
|
-
|
|
356
|
+
// Die Wurzel kommt vom Server und sagt die Sprache des gemeinsamen Teils.
|
|
357
|
+
const stand = fragenstandAus(dateien, daten.wurzel === ORDNER_NAMEN.en.wurzel ? "en" : "de");
|
|
375
358
|
if (stand.art === "offen") {
|
|
376
359
|
console.log("");
|
|
377
|
-
console.log(
|
|
378
|
-
console.log(
|
|
379
|
-
console.log("
|
|
360
|
+
console.log(t.questionsOpen(stand.offen, stand.gesamt));
|
|
361
|
+
console.log(t.questionsAskedOneByOne);
|
|
362
|
+
console.log(` /${slashIn("k3kontext", sprache())}`); // kein-anzeigetext: Slash-Befehl aus SLASH_PAARE
|
|
380
363
|
}
|
|
381
364
|
return 0;
|
|
382
365
|
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { zerlege } from "../argumente.js";
|
|
2
|
+
import { sprache } from "../sprache.js";
|
|
3
|
+
import { ALLGEMEIN_TEXTE } from "../texte/allgemein.js";
|
|
4
|
+
import { PROJEKTE_TEXTE } from "../texte/projekte.js";
|
|
2
5
|
import { feld, ruf } from "../api.js";
|
|
3
6
|
import { schlussFehler } from "../fehler.js";
|
|
4
7
|
import { firmenIdZeilen, firmenZeilen } from "../firmen-liste.js";
|
|
@@ -17,29 +20,21 @@ const ERLAUBT = ["firma", "firma-id"];
|
|
|
17
20
|
* Ueberschrift dazudruckt, macht die Ausgabe als JSON unlesbar — alles fuer
|
|
18
21
|
* Menschen gehoert nach stderr (`console.error`).
|
|
19
22
|
*/
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
Holt die Daten deiner Firma als JSON: Kennzahlen, Menschen, Projekte.
|
|
24
|
-
Die Auswertung macht Claude daraus selbst.
|
|
25
|
-
|
|
26
|
-
--firma "Name" Noetig, wenn du zu mehreren Firmen gehoerst.
|
|
27
|
-
Die Absage nennt dir die Namen als fertige Befehle.
|
|
28
|
-
|
|
29
|
-
--firma-id "…" Fuer den Fall, dass zwei deiner Firmen GLEICH heissen.
|
|
30
|
-
Auch diese Absage nennt dir fertige Befehle -- du musst
|
|
31
|
-
nichts umbenennen und nichts nachschlagen.
|
|
32
|
-
`;
|
|
23
|
+
export function hilfe(s) {
|
|
24
|
+
return PROJEKTE_TEXTE[s].dataHelp;
|
|
25
|
+
}
|
|
33
26
|
export async function firmaDaten(argv) {
|
|
27
|
+
let s = sprache();
|
|
28
|
+
let a = ALLGEMEIN_TEXTE[s];
|
|
34
29
|
// ⚠️ VOR `zerlege`, genau wie bei `projekt neu`: Ein Schalter ist keine
|
|
35
30
|
// Option-mit-Wert, `--help` scheiterte dort sonst mit "fehlt ihr Wert".
|
|
36
31
|
// Die Terminal-Hilfe wirbt mit "Mehr zu einem Befehl: … --help" -- ein
|
|
37
32
|
// Befehl, der darauf mit einem Fehler antwortet, macht die Werbung zur Luege.
|
|
38
33
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
39
|
-
console.log(
|
|
34
|
+
console.log(hilfe(s));
|
|
40
35
|
return 0;
|
|
41
36
|
}
|
|
42
|
-
const zerlegt = zerlege(argv, ERLAUBT);
|
|
37
|
+
const zerlegt = zerlege(argv, ERLAUBT, s);
|
|
43
38
|
if (!zerlegt.ok) {
|
|
44
39
|
console.error(zerlegt.meldung);
|
|
45
40
|
return 1;
|
|
@@ -65,8 +60,11 @@ export async function firmaDaten(argv) {
|
|
|
65
60
|
suche.set("firma", wunsch);
|
|
66
61
|
if (wunschId !== undefined)
|
|
67
62
|
suche.set("firma-id", wunschId);
|
|
68
|
-
const pfad = suche.toString() ? `/api/cli/firma?${suche.toString()}` : "/api/cli/firma";
|
|
69
|
-
const antwort = await ruf(pfad, { methode: "GET", mitAusweis: true });
|
|
63
|
+
const pfad = suche.toString() ? `/api/cli/firma?${suche.toString()}` : "/api/cli/firma"; // kein-anzeigetext: Serverpfad
|
|
64
|
+
const antwort = await ruf(pfad, { methode: "GET", mitAusweis: true }); // kein-anzeigetext: HTTP-Methode
|
|
65
|
+
// 🌐 Die Antwort kann die Kontosprache umgestellt haben (Spec 3.2, Schritt 3): Was ab hier gedruckt wird, in der neuen.
|
|
66
|
+
s = sprache();
|
|
67
|
+
a = ALLGEMEIN_TEXTE[s];
|
|
70
68
|
if (antwort.status === 200) {
|
|
71
69
|
// 🔴 Ein `200` mit unlesbarem Rumpf ist KEIN Erfolg (Review-Befund Runde 1):
|
|
72
70
|
// `ruf` verschluckt Parse-Fehler zu `null`. Ein Zwischending im Netz --
|
|
@@ -75,13 +73,13 @@ export async function firmaDaten(argv) {
|
|
|
75
73
|
// Und die 0 ist die Schnittstelle: Claude liest sie als "erledigt" und
|
|
76
74
|
// haelt `null` fuer die Daten der Firma.
|
|
77
75
|
if (antwort.koerper === null || typeof antwort.koerper !== "object") {
|
|
78
|
-
console.error(
|
|
76
|
+
console.error(a.unreadableAnswer);
|
|
79
77
|
return 3;
|
|
80
78
|
}
|
|
81
79
|
console.log(JSON.stringify(antwort.koerper, null, 2));
|
|
82
80
|
return 0;
|
|
83
81
|
}
|
|
84
|
-
const meldung = feld(antwort.koerper, "meldung") ??
|
|
82
|
+
const meldung = feld(antwort.koerper, "meldung") ?? a.genericFailure;
|
|
85
83
|
// 402 VOR 401: Beide heissen "kommst hier nicht rein", verlangen aber
|
|
86
84
|
// Gegenteiliges. Wer sie zusammenwirft, raet dem Menschen `kimal3 login` --
|
|
87
85
|
// und der meldet sich dann erfolgreich an, ohne dass es etwas aendert.
|
|
@@ -90,7 +88,7 @@ export async function firmaDaten(argv) {
|
|
|
90
88
|
return 4;
|
|
91
89
|
}
|
|
92
90
|
if (antwort.status === 401) {
|
|
93
|
-
console.error(`${meldung}
|
|
91
|
+
console.error(`${meldung}${a.pleaseSignIn}`);
|
|
94
92
|
return 2;
|
|
95
93
|
}
|
|
96
94
|
if (antwort.status === 409) {
|
|
@@ -112,8 +110,8 @@ export async function firmaDaten(argv) {
|
|
|
112
110
|
typeof x.name === "string")
|
|
113
111
|
: [];
|
|
114
112
|
if (auswahl.length > 0) {
|
|
115
|
-
console.error(
|
|
116
|
-
firmenIdZeilen(auswahl).forEach((z) => console.error(z));
|
|
113
|
+
console.error(a.sameNameUseId);
|
|
114
|
+
firmenIdZeilen(auswahl, s).forEach((z) => console.error(z));
|
|
117
115
|
}
|
|
118
116
|
else {
|
|
119
117
|
// Die Namen als FERTIGE Befehle ausgeben, nicht als blosse Liste: Der
|
|
@@ -123,14 +121,14 @@ export async function firmaDaten(argv) {
|
|
|
123
121
|
// ⚠️ Welche Namen einen Befehl bekommen, entscheidet `firmenZeilen` (B-5):
|
|
124
122
|
// Ein doppelt vergebener Name bekommt KEINEN -- er waere ein Vorschlag,
|
|
125
123
|
// der garantiert wieder in derselben Absage endet.
|
|
126
|
-
const zeilen = firmenZeilen(namen);
|
|
124
|
+
const zeilen = firmenZeilen(namen, s);
|
|
127
125
|
if (zeilen.length > 0) {
|
|
128
|
-
console.error(
|
|
126
|
+
console.error(a.yourCompanies);
|
|
129
127
|
zeilen.forEach((z) => console.error(z));
|
|
130
128
|
}
|
|
131
129
|
}
|
|
132
130
|
if (grund === "keine-firma") {
|
|
133
|
-
console.error(
|
|
131
|
+
console.error(a.createCompany(BASIS_URL));
|
|
134
132
|
}
|
|
135
133
|
return 1;
|
|
136
134
|
}
|
|
@@ -141,7 +139,7 @@ export async function firmaDaten(argv) {
|
|
|
141
139
|
// 🔑 Den Rest entscheidet `schlussFehler` fuer alle Befehle gemeinsam --
|
|
142
140
|
// insbesondere die `404` (B-7), die hier frueher auf die `1` fiel und damit
|
|
143
141
|
// "Eingabe passt nicht" meldete, obwohl die Eingabe stimmte.
|
|
144
|
-
const schluss = schlussFehler(antwort.status, meldung);
|
|
142
|
+
const schluss = schlussFehler(antwort.status, meldung, s);
|
|
145
143
|
console.error(schluss.text);
|
|
146
144
|
return schluss.wert;
|
|
147
145
|
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ORDNER_NAMEN, firmenTexte } from "../kontext-stand.js";
|
|
2
|
+
import { sprache } from "../sprache.js";
|
|
3
|
+
import { KONTEXT_TEXTE } from "../texte/kontext.js";
|
|
4
|
+
import { KONTEXT_HOCH_TEXTE } from "../texte/kontext-hoch.js";
|
|
2
5
|
import { fragenAus, traegtFragenVon } from "../fragen-lesen.js";
|
|
3
6
|
import { leseEineDatei } from "../kontext-dateien.js";
|
|
4
7
|
import { arbeitsplatzOderAbsage, fremdeDateiAbsage } from "./kontext-gemeinsam.js";
|
|
@@ -17,7 +20,7 @@ import { arbeitsplatzOderAbsage, fremdeDateiAbsage } from "./kontext-gemeinsam.j
|
|
|
17
20
|
* wenn der Ausweis abgelaufen ist, und deshalb kann er nichts kaputt machen:
|
|
18
21
|
* **er liest, er schreibt nirgends.**
|
|
19
22
|
*
|
|
20
|
-
* ⚠️ **Die Reihenfolge ist die von `
|
|
23
|
+
* ⚠️ **Die Reihenfolge ist die von `firmenTexte`** -- dieselbe wie die der
|
|
21
24
|
* Felder im Formular auf `/firma/kontext`. Wer beides nebeneinander hat, findet
|
|
22
25
|
* dieselbe Frage an derselben Stelle.
|
|
23
26
|
*/
|
|
@@ -28,20 +31,9 @@ import { arbeitsplatzOderAbsage, fremdeDateiAbsage } from "./kontext-gemeinsam.j
|
|
|
28
31
|
Erfolgsausgabe derselben Datei Umlaute setzte: *eine Datei, zwei Schreibweisen,
|
|
29
32
|
und der Unterschied war nicht zu begruenden.*
|
|
30
33
|
*/
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
Zeigt, welche Fragen über deine Firma in kontext/ noch unbeantwortet sind —
|
|
35
|
-
mit Datei, Anker, Frage und Hinweis.
|
|
36
|
-
|
|
37
|
-
Der Befehl liest nur. Er braucht weder Netz noch Anmeldung und ändert nichts.
|
|
38
|
-
|
|
39
|
-
Antworten trägst du in die genannte Datei unter ihre Frage ein; danach
|
|
40
|
-
schickt "kimal3 kontext hoch" sie an die Firma (nur als Admin).
|
|
41
|
-
`;
|
|
42
|
-
/** `[optional]` hinter einer Frage, die keine Pflicht ist -- sonst nichts. */
|
|
43
|
-
function zusatz(frage) {
|
|
44
|
-
return frage.pflicht ? "" : " [optional]";
|
|
34
|
+
/** Die Hilfe von `kontext fragen` / `context questions` in der Sprache des Menschen. */
|
|
35
|
+
export function hilfe(s) {
|
|
36
|
+
return KONTEXT_HOCH_TEXTE[s].questionsHelp;
|
|
45
37
|
}
|
|
46
38
|
/*
|
|
47
39
|
⚠️ **Bewusst NICHT `async`, anders als die Nachbarn `kontextRunter` und
|
|
@@ -51,8 +43,10 @@ function zusatz(frage) {
|
|
|
51
43
|
Der Verteiler in `kimal3.ts` ist selbst `async` und nimmt beides.
|
|
52
44
|
*/
|
|
53
45
|
export function kontextFragen(argv) {
|
|
46
|
+
const s = sprache();
|
|
47
|
+
const t = KONTEXT_HOCH_TEXTE[s];
|
|
54
48
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
55
|
-
console.log(
|
|
49
|
+
console.log(hilfe(s));
|
|
56
50
|
return 0;
|
|
57
51
|
}
|
|
58
52
|
/*
|
|
@@ -63,12 +57,12 @@ export function kontextFragen(argv) {
|
|
|
63
57
|
🔴 Geprueft wird auf JEDES Argument, nicht nur auf solche mit `-` davor. Ein
|
|
64
58
|
stillschweigend geschlucktes `--firma "Nordwind"` waere schlimmer als eine
|
|
65
59
|
Absage -- der Mensch glaubte dann, er habe eine Firma ausgewaehlt -- und ein
|
|
66
|
-
verschlucktes `marke` genauso: Er saehe alle
|
|
60
|
+
verschlucktes `marke` genauso: Er saehe alle Fragen und hielte sie fuer
|
|
67
61
|
die einer Datei.
|
|
68
62
|
*/
|
|
69
63
|
if (argv.length > 0) {
|
|
70
|
-
console.error(
|
|
71
|
-
console.error(
|
|
64
|
+
console.error(t.noArguments(argv[0]));
|
|
65
|
+
console.error(t.readsFiles);
|
|
72
66
|
return 1;
|
|
73
67
|
}
|
|
74
68
|
const ordner = arbeitsplatzOderAbsage();
|
|
@@ -82,15 +76,16 @@ export function kontextFragen(argv) {
|
|
|
82
76
|
Abbruch, der sagt warum, als ein halber Stand, den niemand benennen kann.
|
|
83
77
|
*/
|
|
84
78
|
const gelesen = [];
|
|
85
|
-
|
|
86
|
-
|
|
79
|
+
const texte = firmenTexte(ordner.sprache);
|
|
80
|
+
for (const datei of texte) {
|
|
81
|
+
const antwort = leseEineDatei(ordner.pfad, datei.pfad);
|
|
87
82
|
if (!antwort.ok) {
|
|
88
83
|
console.error(antwort.meldung);
|
|
89
84
|
return 1;
|
|
90
85
|
}
|
|
91
86
|
if (antwort.inhalt === null) {
|
|
92
|
-
console.error(
|
|
93
|
-
console.error(
|
|
87
|
+
console.error(t.questionsFileMissing(datei.pfad));
|
|
88
|
+
console.error(t.questionsFetchFirst);
|
|
94
89
|
return 1;
|
|
95
90
|
}
|
|
96
91
|
/*
|
|
@@ -108,11 +103,24 @@ export function kontextFragen(argv) {
|
|
|
108
103
|
benennen, sind zwei Wahrheiten.
|
|
109
104
|
*/
|
|
110
105
|
if (!traegtFragenVon(antwort.inhalt, datei.ankerPraefix)) {
|
|
111
|
-
fremdeDateiAbsage(datei.pfad, datei.
|
|
106
|
+
fremdeDateiAbsage(datei.pfad, datei.feld, datei.ankerPraefix, t.cannotCount);
|
|
112
107
|
return 1;
|
|
113
108
|
}
|
|
114
|
-
gelesen.push({ pfad: datei.pfad,
|
|
109
|
+
gelesen.push({ pfad: datei.pfad, feld: datei.feld, fragen: fragenAus(antwort.inhalt) });
|
|
115
110
|
}
|
|
111
|
+
fragenZeilen(gelesen, ordner, s).forEach((z) => console.log(z));
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Was `kontext fragen` ausgibt -- als reine Rechnung mit der Sprache des Menschen als Pflichtwert, damit
|
|
116
|
+
* `check:cli` beide Sprachen und beide Zweige (alles beantwortet / noch offen) misst (Teil 3, Task 11).
|
|
117
|
+
* Jedes Element ist EINE `console.log`-Zeile (auch eines mit eingebautem Zeilenumbruch am Ende).
|
|
118
|
+
* ⚠️ Die Fragen, Ueberschriften und Hinweise stehen in den Dateien und kommen unveraendert durch.
|
|
119
|
+
*/
|
|
120
|
+
export function fragenZeilen(gelesen, ordner, s) {
|
|
121
|
+
const t = KONTEXT_HOCH_TEXTE[s];
|
|
122
|
+
const texte = firmenTexte(ordner.sprache);
|
|
123
|
+
const zeilen = [];
|
|
116
124
|
const gesamt = gelesen.reduce((summe, d) => summe + d.fragen.length, 0);
|
|
117
125
|
const offen = gelesen.reduce((summe, d) => summe + d.fragen.filter((f) => f.antwort === "").length, 0);
|
|
118
126
|
/*
|
|
@@ -127,25 +135,35 @@ export function kontextFragen(argv) {
|
|
|
127
135
|
deckt.*
|
|
128
136
|
*/
|
|
129
137
|
if (offen === 0) {
|
|
130
|
-
|
|
138
|
+
zeilen.push(t.allAnswered(gesamt));
|
|
131
139
|
/*
|
|
132
140
|
🔴 **DIE ZWEITE ZEILE BENENNT DIE LUECKE, STATT SIE ZU VERSTECKEN**
|
|
133
141
|
(Review-Befund J5). Gezaehlt wird, was in den fuenf Dateien steht. Wer den
|
|
134
142
|
Ankerkommentar EINER Frage loescht und sie unbeantwortet laesst, hat sie
|
|
135
143
|
hier nicht mehr -- `fragenAus` erkennt eine Frage am Anker (Ruling K-14),
|
|
136
|
-
die App zusaetzlich am Wortlaut. Dann stuende hier
|
|
137
|
-
die App
|
|
144
|
+
die App zusaetzlich am Wortlaut. Dann stuende hier eine Frage weniger,
|
|
145
|
+
als die App fuehrt -- und die App nennte sie weiter offen.
|
|
138
146
|
|
|
139
147
|
🔑 Der Ausweg gehoert in dieselbe Ausgabe wie die Zahl. *Eine Zahl, deren
|
|
140
148
|
Grenze man kennt, gehoert nicht ohne ihre Grenze hingeschrieben* -- sonst
|
|
141
149
|
liest ein Mensch „fertig" und die App widerspricht ihm morgen.
|
|
142
150
|
*/
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
151
|
+
zeilen.push(t.countedIs(ORDNER_NAMEN[ordner.sprache].kontext));
|
|
152
|
+
zeilen.push(t.countedHigher);
|
|
153
|
+
// 🔴 Hier stand „`kimal3 kontext runter` holt sie zurück" -- stimmt nur fuer
|
|
154
|
+
// eine FEHLENDE Datei. Eine selbst bearbeitete fasst `runter` nicht an
|
|
155
|
+
// (`lageFuerDatei` -> `lokal-geaendert`), Schlusspruefung 25.09.
|
|
156
|
+
// Und er NENNT die Datei nicht -- dieser Befehl weiss nicht, welche es ist
|
|
157
|
+
// (er zaehlt nur, was da ist). Deshalb der Weg, sie zu finden (Review 25.09.).
|
|
158
|
+
zeilen.push(t.whichFile);
|
|
159
|
+
// Teil 2: das Beispiel mit dem Dateinamen dieses Ordners (`firma.md` oder `company.md`).
|
|
160
|
+
const beispiel = texte[1].pfad.split("/")[1].replace(/\.md$/, "");
|
|
161
|
+
zeilen.push(t.renameIt(beispiel));
|
|
162
|
+
zeilen.push(t.renameThenFresh);
|
|
163
|
+
zeilen.push(t.renameCopyBack);
|
|
164
|
+
return zeilen;
|
|
147
165
|
}
|
|
148
|
-
|
|
166
|
+
zeilen.push(t.openCount(offen, gesamt));
|
|
149
167
|
/*
|
|
150
168
|
🔴 **WOHER die Pfade zählen** (Review-Befund 2, 2026-08-28). Die Zeilen
|
|
151
169
|
darunter nennen `kontext/marke.md` -- einen Pfad RELATIV zu dem Ordner, den
|
|
@@ -161,22 +179,22 @@ export function kontextFragen(argv) {
|
|
|
161
179
|
`kontext hoch` liest weiter die echten und schickt leere Antworten hoch.
|
|
162
180
|
*Ein Datenverlust, den niemand bemerkt, weil beide Seiten Erfolg melden.*
|
|
163
181
|
*/
|
|
164
|
-
|
|
165
|
-
|
|
182
|
+
zeilen.push(t.workplaceLine(ordner.pfad));
|
|
183
|
+
zeilen.push(t.pathsCountFromHere);
|
|
166
184
|
for (const datei of gelesen) {
|
|
167
185
|
const offeneDieserDatei = datei.fragen.filter((f) => f.antwort === "");
|
|
168
186
|
if (offeneDieserDatei.length === 0)
|
|
169
187
|
continue;
|
|
170
|
-
|
|
188
|
+
zeilen.push(t.fileHeading(datei.pfad, KONTEXT_TEXTE[s].dateiTitel[datei.feld]));
|
|
171
189
|
for (const frage of offeneDieserDatei) {
|
|
172
|
-
|
|
173
|
-
|
|
190
|
+
zeilen.push(t.anchorLine(frage.anker, !frage.pflicht));
|
|
191
|
+
zeilen.push(t.questionHeading(frage.ueberschrift));
|
|
174
192
|
if (frage.hinweis !== "")
|
|
175
|
-
|
|
176
|
-
|
|
193
|
+
zeilen.push(t.questionHint(frage.hinweis));
|
|
194
|
+
zeilen.push("");
|
|
177
195
|
}
|
|
178
196
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
return
|
|
197
|
+
zeilen.push(t.answerBelowHeading);
|
|
198
|
+
zeilen.push(t.thenAsAdmin);
|
|
199
|
+
return zeilen;
|
|
182
200
|
}
|