kimal3 0.2.10 → 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 +23 -19
- package/dist/argumente.js +25 -97
- package/dist/befehle/arbeitsplatz.js +50 -68
- package/dist/befehle/firma-daten.js +24 -26
- package/dist/befehle/kontext-fragen.js +57 -47
- package/dist/befehle/kontext-gemeinsam.js +84 -40
- 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 +98 -87
- 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 +8 -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 +64 -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/werkbank-name.js +28 -10
- package/dist/wort.js +98 -0
- package/package.json +2 -2
- package/skill/SKILL.md +9 -9
- package/skill/commands/k3.md +1 -1
- package/skill/commands/k3feierabend.md +99 -97
- package/skill/commands/k3kontext.md +1 -1
- 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
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { skillTauschNoetig } from "../nachricht.js";
|
|
4
|
+
import { skillQuelle } from "../slash-befehle.js";
|
|
5
|
+
import { mitStempel, skillDatei, slashBefehleInstallieren } from "./skill-install.js";
|
|
6
|
+
export function stelleSkillUm(s) {
|
|
7
|
+
let vorhanden = null;
|
|
8
|
+
try {
|
|
9
|
+
vorhanden = readFileSync(skillDatei(), "utf8");
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
/* keine (lesbare) Datei: nichts umzustellen */
|
|
13
|
+
}
|
|
14
|
+
if (!skillTauschNoetig(vorhanden, s))
|
|
15
|
+
return "nichts";
|
|
16
|
+
try {
|
|
17
|
+
const quelle = fileURLToPath(new URL(`../../${skillQuelle(s).skill}`, import.meta.url)); // kein-anzeigetext: Paketpfad
|
|
18
|
+
writeFileSync(skillDatei(), mitStempel(readFileSync(quelle, "utf8"), s), "utf8");
|
|
19
|
+
const namen = slashBefehleInstallieren(s, true);
|
|
20
|
+
if (namen === "kaputt")
|
|
21
|
+
return "unvollstaendig";
|
|
22
|
+
const komplett = !namen.gestoert && namen.uebersprungen.length === 0 && namen.unlesbar.length === 0;
|
|
23
|
+
return komplett ? "umgestellt" : "unvollstaendig";
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return "unvollstaendig";
|
|
27
|
+
}
|
|
28
|
+
}
|
package/dist/befehle/wache.js
CHANGED
|
@@ -4,6 +4,8 @@ import { lokalerKontextStandJetzt } from "../api.js";
|
|
|
4
4
|
import { leseGesehen, merkeGesehen } from "../gesehen.js";
|
|
5
5
|
import { heuteAus, sollZeigen, skillZustand } from "../nachricht.js";
|
|
6
6
|
import { eigeneVersion } from "../version.js";
|
|
7
|
+
import { WACHE_TEXTE } from "../texte/wache.js";
|
|
8
|
+
import { KONTO_KOPF, SPRACH_KOPF, sprache, uebernimmKontosprache } from "../sprache.js";
|
|
7
9
|
import { leseWacheDatei, merkeLauf, merkeSitzung, schonFuerDieseSitzung, setzeWache, sitzungJetzt, sollHeuteLaufen, } from "../wache-schalter.js";
|
|
8
10
|
import { alsHookAusgabe, laufErledigt, wacheAntwortAusHttp, wacheBefunde, wacheBlock, } from "../wache-rechnung.js";
|
|
9
11
|
import { skillDatei } from "./skill-install.js";
|
|
@@ -84,7 +86,7 @@ function skillIstVeraltet() {
|
|
|
84
86
|
return false;
|
|
85
87
|
const datei = skillDatei();
|
|
86
88
|
const inhalt = existsSync(datei) ? readFileSync(datei, "utf8") : null;
|
|
87
|
-
return skillZustand(inhalt, eigene) === "veraltet";
|
|
89
|
+
return skillZustand(inhalt, eigene, sprache()) === "veraltet";
|
|
88
90
|
}
|
|
89
91
|
/**
|
|
90
92
|
* Der eine Anruf beim eigenen Server -- Zugang pruefen, Nachricht abholen.
|
|
@@ -114,10 +116,12 @@ async function frageServer(schluessel, heute) {
|
|
|
114
116
|
// (live gemessen 17.09.). Faellt die Version aus, geht der Kopf nicht mit.
|
|
115
117
|
const version = eigeneVersion();
|
|
116
118
|
const antwort = await fetch(`${BASIS_URL}/api/cli/wache`, {
|
|
117
|
-
method: "POST",
|
|
118
|
-
headers: { Authorization: `Bearer ${schluessel}`, ...(version ? { "X-Kimal3-Version": version } : {}) },
|
|
119
|
+
method: "POST", // kein-anzeigetext: HTTP-Methode
|
|
120
|
+
headers: { Authorization: `Bearer ${schluessel}`, [SPRACH_KOPF]: sprache(), ...(version ? { "X-Kimal3-Version": version } : {}) }, // kein-anzeigetext: HTTP-Kopf
|
|
119
121
|
signal: AbortSignal.timeout(ZEITGRENZE_MS),
|
|
120
122
|
});
|
|
123
|
+
// 🌐 Die Wache baut ihre Zeilen NACH dieser Antwort -- eine neue Kontosprache gilt schon dafuer (L-5).
|
|
124
|
+
uebernimmKontosprache(antwort.headers.get(KONTO_KOPF));
|
|
121
125
|
const koerper = await antwort.json().catch(() => null);
|
|
122
126
|
const { zugangGilt, hinweis, bekannt } = wacheAntwortAusHttp(antwort.status, koerper);
|
|
123
127
|
if (!hinweis)
|
|
@@ -205,13 +209,15 @@ export async function wache(alsHook) {
|
|
|
205
209
|
frageServer(anmeldung.schluessel, heute),
|
|
206
210
|
neuesteVonNpm(ZEITGRENZE_MS),
|
|
207
211
|
]);
|
|
212
|
+
// 🌐 Erst jetzt gelesen: eine Kontosprache aus der Antwort gilt schon (L-5); bei 401 und ohne
|
|
213
|
+
// Netz traegt der Merkzettel sie (L-7, L-8).
|
|
208
214
|
const befunde = wacheBefunde({
|
|
209
215
|
zugangGilt: vomServer.zugangGilt,
|
|
210
216
|
nachricht: vomServer.hinweis?.text ?? null,
|
|
211
217
|
eigeneVersion: eigeneVersion(),
|
|
212
218
|
neuesteVersion: vonNpm,
|
|
213
219
|
skillVeraltet: skillIstVeraltet(),
|
|
214
|
-
});
|
|
220
|
+
}, sprache());
|
|
215
221
|
const zeilen = befunde.map((b) => b.zeile);
|
|
216
222
|
// 🔴 VOR der Ausgabe -- sonst spricht die Wache bei einem Fehler in der
|
|
217
223
|
// Ausgabe morgen wieder und uebermorgen wieder.
|
|
@@ -231,7 +237,7 @@ export async function wache(alsHook) {
|
|
|
231
237
|
merkeLauf(heute);
|
|
232
238
|
if (zeilen.length === 0)
|
|
233
239
|
return 0;
|
|
234
|
-
console.log(alsHook ? alsHookAusgabe(zeilen) : wacheBlock(zeilen));
|
|
240
|
+
console.log(alsHook ? alsHookAusgabe(zeilen, sprache()) : wacheBlock(zeilen));
|
|
235
241
|
// Erst NACH dem Drucken vermerken, dass die Nachricht heute schon lief --
|
|
236
242
|
// dieselbe Reihenfolge wie beim Update-Kanal in kimal3.ts. Daran haengt
|
|
237
243
|
// ihr Einmal-am-Tag, NICHT am Lauf-Stempel: Beim wiederholten Lauf kommt
|
|
@@ -253,6 +259,6 @@ export async function wache(alsHook) {
|
|
|
253
259
|
*/
|
|
254
260
|
export function wacheSchalten(an) {
|
|
255
261
|
setzeWache(an);
|
|
256
|
-
console.log(an ?
|
|
262
|
+
console.log(an ? WACHE_TEXTE[sprache()].watchOn : WACHE_TEXTE[sprache()].watchOff);
|
|
257
263
|
return 0;
|
|
258
264
|
}
|
package/dist/befehle/werkbank.js
CHANGED
|
@@ -2,8 +2,12 @@ import { existsSync, statSync } from "node:fs";
|
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { FIRMEN_OPTIONEN, dateienSchreiben, istUnsichererOrdnername, vorlageHolen, werkbankOrdner, } from "../arbeitsplatz-dateien.js";
|
|
4
4
|
import { alsBefehlszeile, alsWort, trenneNamenUndOptionen, zerlege } from "../argumente.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { befehlIn, schalterIn } from "../befehlswoerter.js";
|
|
6
|
+
import { sprache } from "../sprache.js";
|
|
7
|
+
import { ARBEITSPLATZ_TEXTE } from "../texte/arbeitsplatz.js";
|
|
8
|
+
import { WERKBANK_TEXTE } from "../texte/werkbank.js";
|
|
9
|
+
import { werkbankOrdnerAus, werkbankSpracheAus, werkbankUmbenennen } from "../werkbank-name.js";
|
|
10
|
+
import { FIRMEN_CLAUDE_MD, MERKZETTEL_PFAD, ORDNER_NAMEN, firmenAbgleich, firmennameAusClaudeMd, leseMerkzettel, } from "../kontext-stand.js";
|
|
7
11
|
import { leseEineDatei, leseMerkzettelDatei } from "../kontext-dateien.js";
|
|
8
12
|
/**
|
|
9
13
|
* Legt **nur eine Werkbank** an — in einem Firmen-Ordner, der schon steht.
|
|
@@ -56,29 +60,10 @@ import { leseEineDatei, leseMerkzettelDatei } from "../kontext-dateien.js";
|
|
|
56
60
|
* verwalten (s. `WEITER-HIER.md`, Entscheidungen). Was dann von außen kommt,
|
|
57
61
|
* darf ein lokaler Befehl nicht überschreiben.
|
|
58
62
|
*/
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
Die Firmenebene (kontext/, CLAUDE.md, README.md) wird NICHT angefasst.
|
|
64
|
-
|
|
65
|
-
dein-vorname Optional. Der Ordner traegt deinen Namen -- aus "sabine"
|
|
66
|
-
wird "werkbank-sabine". Ohne Angabe steht dort der Name,
|
|
67
|
-
den der Server aus deiner Anmelde-Adresse gebildet hat.
|
|
68
|
-
|
|
69
|
-
--firma "Name" Nur noetig, wenn du zu mehreren Firmen gehoerst UND dieser
|
|
70
|
-
Ordner seine Firma nicht eindeutig nennt -- sonst nehme
|
|
71
|
-
ich die Firma des Ordners und sage dir das.
|
|
72
|
-
Die Absage nennt dir die Namen als fertige Befehle.
|
|
73
|
-
|
|
74
|
-
--firma-id "…" Fuer den Fall, dass zwei deiner Firmen GLEICH heissen.
|
|
75
|
-
Auch diese Absage nennt dir fertige Befehle.
|
|
76
|
-
|
|
77
|
-
🔴 Bricht ab, wenn der Zielordner schon existiert und NICHT leer ist.
|
|
78
|
-
|
|
79
|
-
Du hast noch gar keinen Firmen-Ordner?
|
|
80
|
-
kimal3 arbeitsplatz neu <dein-vorname>
|
|
81
|
-
`;
|
|
63
|
+
/** Die Hilfe von `werkbank neu` / `workbench new` in der Sprache des Menschen. */
|
|
64
|
+
export function hilfe(s) {
|
|
65
|
+
return WERKBANK_TEXTE[s].help;
|
|
66
|
+
}
|
|
82
67
|
/**
|
|
83
68
|
* 🔴 **Review-Runde 2 zu PR #25 — und es ist DERSELBE Fehler wie in Runde 1,
|
|
84
69
|
* nur eine Datei weiter.** Hier stand:
|
|
@@ -104,16 +89,14 @@ const HILFE = `
|
|
|
104
89
|
* fuellen muss, obwohl die Antwort danebensteht. *Ein Platzhalter ist ein
|
|
105
90
|
* Eingestaendnis, dass man es nicht weiss -- hier weiss man es.*
|
|
106
91
|
*/
|
|
107
|
-
function hinweisFuer(ordnerName) {
|
|
108
|
-
|
|
109
|
-
return (" Ist das DEINE Werkbank? Dann steht sie schon -- geh einfach hinein:\n" +
|
|
110
|
-
` cd ${ziel}\n` +
|
|
111
|
-
" Bist du es nicht, nimm deinen eigenen Vornamen:\n" +
|
|
112
|
-
" kimal3 werkbank neu <dein-vorname>");
|
|
92
|
+
function hinweisFuer(ordnerName, s) {
|
|
93
|
+
return WERKBANK_TEXTE[s].adviceOwnWorkbench(alsWort(ordnerName), befehlIn("werkbank neu", s)); // kein-anzeigetext: Befehlsschlüssel
|
|
113
94
|
}
|
|
114
95
|
export async function werkbankNeu(argv) {
|
|
96
|
+
let s = sprache();
|
|
97
|
+
let t = WERKBANK_TEXTE[s];
|
|
115
98
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
116
|
-
console.log(
|
|
99
|
+
console.log(hilfe(s));
|
|
117
100
|
return 0;
|
|
118
101
|
}
|
|
119
102
|
/*
|
|
@@ -135,7 +118,7 @@ export async function werkbankNeu(argv) {
|
|
|
135
118
|
const { woerter, optionen: optionsArgv } = trenneNamenUndOptionen(argv);
|
|
136
119
|
const nameArg = woerter[0];
|
|
137
120
|
if (nameArg !== undefined && nameArg.trim() === "") {
|
|
138
|
-
console.error(
|
|
121
|
+
console.error(t.emptyName + hilfe(s));
|
|
139
122
|
return 1;
|
|
140
123
|
}
|
|
141
124
|
if (woerter.length > 1) {
|
|
@@ -162,17 +145,15 @@ export async function werkbankNeu(argv) {
|
|
|
162
145
|
*/
|
|
163
146
|
const optionsAnhang = optionsArgv.length === 0 ? "" : ` ${alsBefehlszeile(optionsArgv)}`;
|
|
164
147
|
const vorschlag = einfacheWoerter.length === woerter.length
|
|
165
|
-
?
|
|
166
|
-
` kimal3 werkbank neu ${einfacheWoerter.join("-")}${optionsAnhang}\n`
|
|
148
|
+
? t.nameSuggestion(befehlIn("werkbank neu", s), einfacheWoerter.join("-"), optionsAnhang) // kein-anzeigetext: Befehlsschlüssel
|
|
167
149
|
: "";
|
|
168
|
-
console.error(
|
|
169
|
-
`${vorschlag}${HILFE}`);
|
|
150
|
+
console.error(t.onlyOneName(woerter[1]) + vorschlag + hilfe(s));
|
|
170
151
|
return 1;
|
|
171
152
|
}
|
|
172
153
|
// 🔑 Erst NACH den Namens-Absagen -- s. Zwilling in `arbeitsplatz.ts`.
|
|
173
|
-
const zerlegt = zerlege(optionsArgv, FIRMEN_OPTIONEN);
|
|
154
|
+
const zerlegt = zerlege(optionsArgv, FIRMEN_OPTIONEN, s);
|
|
174
155
|
if (!zerlegt.ok) {
|
|
175
|
-
console.error(`${zerlegt.meldung}\n${
|
|
156
|
+
console.error(`${zerlegt.meldung}\n${hilfe(s)}`);
|
|
176
157
|
return 1;
|
|
177
158
|
}
|
|
178
159
|
const wunsch = {
|
|
@@ -182,14 +163,13 @@ export async function werkbankNeu(argv) {
|
|
|
182
163
|
// `null` heisst: nach dem Umschreiben blieb kein Zeichen uebrig, das in einem
|
|
183
164
|
// Ordnernamen stehen darf. Ein Mensch hat hier getippt und verdient eine
|
|
184
165
|
// Antwort -- der Server schweigt im selben Fall und bleibt beim Vordruck.
|
|
185
|
-
|
|
166
|
+
// 🌐 Teil 2: nur „bleibt etwas uebrig?" -- das Praefix kommt erst aus der Lieferung, s. unten.
|
|
186
167
|
if (nameArg !== undefined) {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
console.error(
|
|
190
|
-
console.error("Zeichen uebrig, die in keinem Ordnernamen stehen duerfen.");
|
|
168
|
+
if (werkbankOrdnerAus(nameArg, "de") === null) {
|
|
169
|
+
console.error(t.unusableName1(nameArg));
|
|
170
|
+
console.error(t.unusableName2);
|
|
191
171
|
console.error("");
|
|
192
|
-
console.error("
|
|
172
|
+
console.error(t.unusableName3(befehlIn("werkbank neu", s))); // kein-anzeigetext: Befehlsschlüssel
|
|
193
173
|
return 1;
|
|
194
174
|
}
|
|
195
175
|
}
|
|
@@ -200,9 +180,6 @@ export async function werkbankNeu(argv) {
|
|
|
200
180
|
wird nie erreicht.
|
|
201
181
|
*/
|
|
202
182
|
// 🔑 Der getippte Vorname reist in der Absage mit -- s. Zwilling.
|
|
203
|
-
const befehlsname = nameArg === undefined
|
|
204
|
-
? "werkbank neu"
|
|
205
|
-
: `werkbank neu ${alsWort(nameArg)}`;
|
|
206
183
|
/*
|
|
207
184
|
🔑 **Die Firma dieses Ordners** -- Kennung aus dem Merkzettel, Name aus der
|
|
208
185
|
Firmen-`CLAUDE.md`. `vorlageHolen` nimmt sie nur, wenn der Server wegen
|
|
@@ -214,9 +191,13 @@ export async function werkbankNeu(argv) {
|
|
|
214
191
|
id: leseMerkzettelDatei(process.cwd()).firma_id,
|
|
215
192
|
name: firmennameAusClaudeMd(hierGelesen.ok ? hierGelesen.inhalt : null),
|
|
216
193
|
};
|
|
217
|
-
const holen = await vorlageHolen(
|
|
194
|
+
const holen = await vorlageHolen("werkbank neu", // kein-anzeigetext: Befehlsschlüssel
|
|
195
|
+
nameArg === undefined ? "" : ` ${alsWort(nameArg)}`, wunsch, ordnerFirma);
|
|
218
196
|
if (!holen.ok)
|
|
219
197
|
return holen.wert;
|
|
198
|
+
// 🌐 Die Antwort kann die Kontosprache umgestellt haben (Spec 3.2, Schritt 3): Was ab hier gedruckt wird, in der neuen.
|
|
199
|
+
s = sprache();
|
|
200
|
+
t = WERKBANK_TEXTE[s];
|
|
220
201
|
const daten = holen.daten;
|
|
221
202
|
const werkbank = werkbankOrdner(daten.dateien);
|
|
222
203
|
/*
|
|
@@ -263,14 +244,17 @@ export async function werkbankNeu(argv) {
|
|
|
263
244
|
ist kein Grund, sie hier falsch zu benennen.
|
|
264
245
|
*/
|
|
265
246
|
if (werkbank !== null && istUnsichererOrdnername(werkbank)) {
|
|
266
|
-
console.error(
|
|
247
|
+
console.error(t.unsafeFolderName(werkbank));
|
|
267
248
|
return 3;
|
|
268
249
|
}
|
|
269
250
|
if (werkbank === null) {
|
|
270
|
-
console.error(
|
|
271
|
-
console.error(
|
|
251
|
+
console.error(t.noWorkbank1);
|
|
252
|
+
console.error(t.noWorkbank2);
|
|
272
253
|
return 3;
|
|
273
254
|
}
|
|
255
|
+
// 🌐 Teil 2: Das Praefix der gelieferten Werkbank ist die Kontosprache; ein getipptes fremdes
|
|
256
|
+
// Praefix wird ersetzt, nie verdoppelt (`workbench-jens` bei deutschem Konto -> `werkbank-jens`).
|
|
257
|
+
const gewuenschteWerkbank = nameArg === undefined ? null : werkbankOrdnerAus(nameArg, werkbankSpracheAus(werkbank) ?? "de");
|
|
274
258
|
/*
|
|
275
259
|
🔑 **Die Prüfung, ob wir überhaupt in einer Firma stehen** -- und sie ist
|
|
276
260
|
keine Förmlichkeit: In `<werkbank>/.claude/settings.json` steht
|
|
@@ -317,17 +301,28 @@ export async function werkbankNeu(argv) {
|
|
|
317
301
|
Eine kaputte Lieferung ist keine falsche Eingabe.
|
|
318
302
|
*/
|
|
319
303
|
if (firmenOrdner.length === 0) {
|
|
320
|
-
console.error(
|
|
321
|
-
console.error(
|
|
322
|
-
console.error(
|
|
304
|
+
console.error(t.noCompanyLevel1);
|
|
305
|
+
console.error(t.noCompanyLevel2);
|
|
306
|
+
console.error(t.noCompanyLevel3);
|
|
323
307
|
return 3;
|
|
324
308
|
}
|
|
309
|
+
/*
|
|
310
|
+
🔴 **Teil-2-Rest Minor 7: Der Firmen-Ordner steht da, nur in der Sprache von frueher.** Alter
|
|
311
|
+
deutscher Ordner (`kontext/`), Firma inzwischen englisch: Der Server liefert die englische
|
|
312
|
+
Vorlage, `fehlend` nennt `context` -- und der Mensch las "Hier steht kein Firmen-Ordner" samt
|
|
313
|
+
"Bist du der ERSTE in deiner Firma?". Beides falsch. Diese Absage kommt VOR dem Zweig darunter.
|
|
314
|
+
*/
|
|
315
|
+
const ordnerSprache = andereOrdnerSprache(fehlend, istOrdner);
|
|
316
|
+
if (ordnerSprache !== null) {
|
|
317
|
+
console.error(t.folderInOtherLanguage(ordnerSprache, `kimal3 ${befehlIn("arbeitsplatz neu", s)}`)); // kein-anzeigetext: Befehlsschlüssel
|
|
318
|
+
return 1;
|
|
319
|
+
}
|
|
325
320
|
if (fehlend.length > 0) {
|
|
326
|
-
console.error(
|
|
327
|
-
console.error(
|
|
328
|
-
console.error(
|
|
321
|
+
console.error(t.noCompanyFolder1(fehlend.join(", ")));
|
|
322
|
+
console.error(t.noCompanyFolder2);
|
|
323
|
+
console.error(t.noCompanyFolder3);
|
|
329
324
|
console.error("");
|
|
330
|
-
console.error(
|
|
325
|
+
console.error(t.noCompanyFolder4);
|
|
331
326
|
console.error("");
|
|
332
327
|
/*
|
|
333
328
|
🔴 **Hier stand „Du hast noch keinen? kimal3 arbeitsplatz neu"**
|
|
@@ -350,12 +345,12 @@ export async function werkbankNeu(argv) {
|
|
|
350
345
|
das so ist, ist die ehrliche Auskunft „frag, wo er liegt" -- und nicht
|
|
351
346
|
ein Befehl, der etwas Falsches anlegt.
|
|
352
347
|
*/
|
|
353
|
-
console.error(
|
|
354
|
-
console.error("
|
|
348
|
+
console.error(t.noCompanyFolder5);
|
|
349
|
+
console.error(t.noCompanyFolder6(befehlIn("arbeitsplatz neu", s))); // kein-anzeigetext: Befehlsschlüssel
|
|
355
350
|
console.error("");
|
|
356
|
-
console.error(
|
|
357
|
-
console.error(
|
|
358
|
-
console.error(
|
|
351
|
+
console.error(t.noCompanyFolder7);
|
|
352
|
+
console.error(t.noCompanyFolder8);
|
|
353
|
+
console.error(t.noCompanyFolder9);
|
|
359
354
|
return 1;
|
|
360
355
|
}
|
|
361
356
|
/*
|
|
@@ -390,10 +385,10 @@ export async function werkbankNeu(argv) {
|
|
|
390
385
|
sieht, und laesst den Menschen entscheiden.
|
|
391
386
|
*/
|
|
392
387
|
if (abgleich.art === "zweifel") {
|
|
393
|
-
console.error(
|
|
394
|
-
console.error(
|
|
395
|
-
console.error(
|
|
396
|
-
console.error(
|
|
388
|
+
console.error(t.doubt1(abgleich.hier));
|
|
389
|
+
console.error(t.doubt2(abgleich.gewaehlt));
|
|
390
|
+
console.error(t.doubt3);
|
|
391
|
+
console.error(t.doubt4);
|
|
397
392
|
console.error("");
|
|
398
393
|
}
|
|
399
394
|
if (abgleich.art === "andere-firma") {
|
|
@@ -409,20 +404,20 @@ export async function werkbankNeu(argv) {
|
|
|
409
404
|
*/
|
|
410
405
|
const genannt = wunsch.firma ?? wunsch.firmaId;
|
|
411
406
|
if (genannt === undefined) {
|
|
412
|
-
console.error(
|
|
413
|
-
console.error(
|
|
414
|
-
console.error(
|
|
407
|
+
console.error(t.otherCompany1);
|
|
408
|
+
console.error(t.otherCompany2);
|
|
409
|
+
console.error(t.otherCompany3);
|
|
415
410
|
console.error("");
|
|
416
|
-
console.error(
|
|
417
|
-
console.error(
|
|
411
|
+
console.error(t.otherCompany4);
|
|
412
|
+
console.error(t.otherCompany5);
|
|
418
413
|
return 1;
|
|
419
414
|
}
|
|
420
|
-
console.error(
|
|
421
|
-
console.error(
|
|
422
|
-
console.error(
|
|
415
|
+
console.error(t.otherNamedCompany1(genannt));
|
|
416
|
+
console.error(t.otherNamedCompany2);
|
|
417
|
+
console.error(t.otherNamedCompany3);
|
|
423
418
|
console.error("");
|
|
424
|
-
console.error(
|
|
425
|
-
console.error(
|
|
419
|
+
console.error(t.otherNamedCompany4(genannt));
|
|
420
|
+
console.error(t.otherNamedCompany5);
|
|
426
421
|
return 1;
|
|
427
422
|
}
|
|
428
423
|
/*
|
|
@@ -462,13 +457,13 @@ export async function werkbankNeu(argv) {
|
|
|
462
457
|
const meine = umbenannt
|
|
463
458
|
.filter((d) => d.pfad.startsWith(praefix))
|
|
464
459
|
.map((d) => ({ pfad: d.pfad.slice(praefix.length), inhalt: d.inhalt }));
|
|
465
|
-
const wert = dateienSchreiben(meine, ordnerName, hinweisFuer(ordnerName));
|
|
460
|
+
const wert = dateienSchreiben(meine, ordnerName, hinweisFuer(ordnerName, s));
|
|
466
461
|
if (wert !== 0)
|
|
467
462
|
return wert;
|
|
468
|
-
console.log(
|
|
463
|
+
console.log(ARBEITSPLATZ_TEXTE[s].filesCreated(meine.length));
|
|
469
464
|
console.log(` ${resolve(ordnerName)}`);
|
|
470
465
|
console.log("");
|
|
471
|
-
console.log(
|
|
466
|
+
console.log(t.companyUntouched);
|
|
472
467
|
console.log("");
|
|
473
468
|
/*
|
|
474
469
|
Erst NACH dem Anlegen (Lage L2): Vorher koennte noch eine Absage folgen, und
|
|
@@ -476,16 +471,32 @@ export async function werkbankNeu(argv) {
|
|
|
476
471
|
*/
|
|
477
472
|
if (holen.uebernommen) {
|
|
478
473
|
const gewaehlt = firmennameAusClaudeMd(inhaltAus(FIRMEN_CLAUDE_MD));
|
|
479
|
-
console.log(
|
|
480
|
-
console.log("
|
|
474
|
+
console.log(t.companyFromFolder(gewaehlt));
|
|
475
|
+
console.log(t.companyFromFolderHint(schalterIn("firma", s))); // kein-anzeigetext: Schalterschlüssel
|
|
481
476
|
console.log("");
|
|
482
477
|
}
|
|
483
|
-
|
|
484
|
-
console.log(
|
|
485
|
-
console.log(
|
|
486
|
-
console.log(
|
|
478
|
+
// 🔑 Derselbe Rat wie nach `arbeitsplatz neu`: eine Fassung des Ausloesesatzes, nicht zwei.
|
|
479
|
+
console.log(ARBEITSPLATZ_TEXTE[s].nextStepsHeader);
|
|
480
|
+
console.log(` cd ${alsWort(ordnerName)}`); // kein-anzeigetext: Befehlszeile zum Kopieren
|
|
481
|
+
console.log(" claude"); // kein-anzeigetext: Befehlszeile zum Kopieren
|
|
482
|
+
console.log(ARBEITSPLATZ_TEXTE[s].nextStepsSay);
|
|
487
483
|
return 0;
|
|
488
484
|
}
|
|
485
|
+
/**
|
|
486
|
+
* Fehlt NUR der Kontextordner der Lieferung, weil hier der der ANDEREN Sprache steht? (Teil-2-Rest
|
|
487
|
+
* Minor 7: alter deutscher Ordner, Firma inzwischen englisch.) Dann ist das kein "hier steht kein
|
|
488
|
+
* Firmen-Ordner", sondern ein Sprachwechsel der Firma -- die Sprache des VORHANDENEN Ordners, sonst null.
|
|
489
|
+
* Rein (check:cli): `gibtEs` ist im Befehl `istOrdner`.
|
|
490
|
+
*/
|
|
491
|
+
export function andereOrdnerSprache(fehlend, gibtEs) {
|
|
492
|
+
if (fehlend.length !== 1)
|
|
493
|
+
return null;
|
|
494
|
+
if (fehlend[0] === ORDNER_NAMEN.en.kontext && gibtEs(ORDNER_NAMEN.de.kontext))
|
|
495
|
+
return "de";
|
|
496
|
+
if (fehlend[0] === ORDNER_NAMEN.de.kontext && gibtEs(ORDNER_NAMEN.en.kontext))
|
|
497
|
+
return "en";
|
|
498
|
+
return null;
|
|
499
|
+
}
|
|
489
500
|
/**
|
|
490
501
|
* Die Ordner der Firmenebene, aus der Lieferung abgeleitet: jeder erste
|
|
491
502
|
* Pfad-Teil, der einen Unterordner benennt und nicht die Werkbank ist.
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
export const BEFEHLE_EN = {
|
|
2
|
+
"kimal3 login": {
|
|
3
|
+
stempel: "013360ee",
|
|
4
|
+
befehl: "kimal3 login",
|
|
5
|
+
tippen: "! kimal3 login",
|
|
6
|
+
terminal: "kimal3 login",
|
|
7
|
+
beschreibung: "Connect this computer to your account",
|
|
8
|
+
rhythmusOderSatz: "once per computer",
|
|
9
|
+
details: [
|
|
10
|
+
"It shows you an address and a code: open the address in your browser and type in the code. The terminal picks up the confirmation automatically — you have ten minutes.",
|
|
11
|
+
"After that, it stays that way. Your sign-in is saved as a file in your user folder and survives IDE restarts, computer restarts and updates. If the connection does break after a long pause, a command will tell you — then just run kimal3 login once more; that's not an error.",
|
|
12
|
+
],
|
|
13
|
+
},
|
|
14
|
+
"kimal3 skill install": {
|
|
15
|
+
stempel: "8491e5d6",
|
|
16
|
+
befehl: "kimal3 skill install",
|
|
17
|
+
tippen: "! kimal3 skill install",
|
|
18
|
+
terminal: "kimal3 skill install",
|
|
19
|
+
beschreibung: "Teach Claude to use this tool — and give you the /k3 commands",
|
|
20
|
+
rhythmusOderSatz: "once — and again after every update",
|
|
21
|
+
details: [
|
|
22
|
+
"The command that makes the others useful: it sets up 🤖 Claude's instructions (the “skill”) and 🧑 your slash commands.",
|
|
23
|
+
"It does NOT run automatically — run it once after installing and again after every update. Otherwise Claude keeps working with the old instructions.",
|
|
24
|
+
"You'll know it worked when it reports “Skill created.” and lists the slash commands. Claude only picks up both in your NEXT session — restart the current one.",
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
"kimal3 arbeitsplatz neu": {
|
|
28
|
+
stempel: "231b90bf",
|
|
29
|
+
befehl: "kimal3 workplace new",
|
|
30
|
+
tippen: "! kimal3 workplace new",
|
|
31
|
+
terminal: "kimal3 workplace new",
|
|
32
|
+
beschreibung: "Create the whole AI Workplace — company level and workbench",
|
|
33
|
+
rhythmusOderSatz: "once per company",
|
|
34
|
+
details: [
|
|
35
|
+
"Fetches the template from your Pro account and creates it here as a real folder — CLAUDE.md, routine commands, the workbench for your projects. The same package is available to download on /pro.",
|
|
36
|
+
"The folder is called AI-Workplace (KI-Arbeitsplatz for a German-speaking company). To keep several companies apart, use the folder above it, e.g. Clients/ARNO/AI-Workplace. Add your first name and your workbench inside it is called workbench-sabine: kimal3 workplace new sabine.",
|
|
37
|
+
"If the target folder already exists and isn't empty, the command stops instead of overwriting anything — your work is safe. You'll know it worked when it tells you how many files it created.",
|
|
38
|
+
"⚠️ It also creates the company level (context/ with brand, systems, security — kontext/ in a German workplace). If that already exists, you need kimal3 workbench new — otherwise you end up with a second company inside the first.",
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
"kimal3 werkbank neu": {
|
|
42
|
+
stempel: "da69f97f",
|
|
43
|
+
befehl: "kimal3 workbench new",
|
|
44
|
+
tippen: "! kimal3 workbench new",
|
|
45
|
+
terminal: "kimal3 workbench new",
|
|
46
|
+
beschreibung: "Only create your own workbench in an existing company",
|
|
47
|
+
rhythmusOderSatz: "once per person",
|
|
48
|
+
details: [
|
|
49
|
+
"For everyone except the first person: the company folder is already there (context/ with brand, systems, security — kontext/ in a German workplace) — you only need your own workbench inside it.",
|
|
50
|
+
"🔴 It doesn't touch the company level. Not a single byte in context/, CLAUDE.md or README.md — not even by writing an ‘identical’ copy over it.",
|
|
51
|
+
"It only runs if you really are in a company folder. If the company level next to it is missing, it stops and tells you — a workbench without it leads nowhere, because its settings refer to ../context (../kontext in a German workplace).",
|
|
52
|
+
"Add your first name — the folder is named after it: sabine becomes workbench-sabine. Without it, the server builds the name from your sign-in address. That way you can see later whose workbench is whose.",
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
"kimal3 kontext runter": {
|
|
56
|
+
stempel: "9ccf1083",
|
|
57
|
+
befehl: "kimal3 context download",
|
|
58
|
+
tippen: "! kimal3 context download",
|
|
59
|
+
terminal: "kimal3 context download",
|
|
60
|
+
beschreibung: "Fetch the company context — CLAUDE.md and the five files in context/",
|
|
61
|
+
rhythmusOderSatz: "whenever the company might have changed something",
|
|
62
|
+
details: [
|
|
63
|
+
"Fetches CLAUDE.md and the five files in context/ (kontext/ in a German workplace) from your company and puts them in your AI Workplace. Anything you've changed locally is left alone — it tells you how to send it up.",
|
|
64
|
+
"If you changed a file locally AND the company has changed it too in the meantime, it saves your version in context/before-<date>/ (kontext/vorher-<datum>/ in a German workplace) first, then replaces it — nothing gets lost.",
|
|
65
|
+
"You'll know it worked when it names the updated files or says “Your company context is up to date.”",
|
|
66
|
+
"⚠️ Like kimal3 workbench new, it needs your own Pro account. Without one you get exit code 4 — then don't retry.",
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
"kimal3 kontext fragen": {
|
|
70
|
+
stempel: "34decb4c",
|
|
71
|
+
befehl: "kimal3 context questions",
|
|
72
|
+
tippen: "/k3context",
|
|
73
|
+
terminal: "kimal3 context questions",
|
|
74
|
+
beschreibung: "Answer the questions about your company — Claude takes you through them",
|
|
75
|
+
rhythmusOderSatz: "let's answer the questions about my company",
|
|
76
|
+
details: [
|
|
77
|
+
"Reads the five files in context/ (kontext/ in a German workplace) and prints every question that has nothing written under it yet — with file, question and hint. If all are answered, it says so in one sentence.",
|
|
78
|
+
"It only reads: no network, no sign-in, no writing. That's why it comes first — Claude then asks you the questions one by one and writes your answers into the files.",
|
|
79
|
+
"After that, kimal3 context upload sends them to the company. Only the company admin may do that; everyone else passes their answers on.",
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
"kimal3 kontext hoch": {
|
|
83
|
+
stempel: "fbf3f20b",
|
|
84
|
+
befehl: "kimal3 context upload",
|
|
85
|
+
tippen: "! kimal3 context upload",
|
|
86
|
+
terminal: "kimal3 context upload",
|
|
87
|
+
beschreibung: "Upload your local changes to the five company texts",
|
|
88
|
+
rhythmusOderSatz: "after you've edited context/*.md — company admin only",
|
|
89
|
+
details: [
|
|
90
|
+
"Sends all five company texts to your company — the files in context/ (profile.md, company.md, brand.md, systems.md, security.md; in a German workplace kontext/ with kurzprofil.md, firma.md, marke.md, systeme.md, sicherheit.md). That way they also reach your colleagues with their next kimal3 context download.",
|
|
91
|
+
"🔴 Only the company admin may do this. If you're not one, it tells you — then pass your addition on to the company admin; trying again won't change that.",
|
|
92
|
+
"⚠️ If something goes wrong, what counts is the MESSAGE, not the number after it. Exit code 1 stands for ‘you're not an admin’, ‘there's no workplace here’, ‘someone else has changed it in the meantime’ (way out: --overwrite) and several more. The same code also appears under “The company has saved your changes — only the local tracking file couldn't be written”, which only says that a file on your disk couldn't be written. That is a success: everything reached the company. Read the sentence, not the number.",
|
|
93
|
+
"If one of the five files no longer has its original questions — for example because something else was copied over it — it stops and sends nothing, not even the other four. kimal3 context download brings the file back.",
|
|
94
|
+
"You'll know it worked when it reports “✓ changed at the company:” with the file names.",
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
"kimal3 projekt neu …": {
|
|
98
|
+
stempel: "34505297",
|
|
99
|
+
befehl: "kimal3 project new …",
|
|
100
|
+
tippen: "/k3project <what you built>",
|
|
101
|
+
terminal: 'kimal3 project new --title "Quote generator" --hours 4 --result 1200',
|
|
102
|
+
beschreibung: "Add a project to your success profile",
|
|
103
|
+
rhythmusOderSatz: "add this as a project",
|
|
104
|
+
details: [
|
|
105
|
+
"Just say so when you've finished something. Claude puts together the title, time saved and net result itself — it knows the numbers from your conversation. The slash command is the same route, just one step quicker.",
|
|
106
|
+
"It runs kimal3 project new. Only the title is required; kimal3 project new --help shows all the options.",
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
"kimal3 projekt liste": {
|
|
110
|
+
stempel: "87d02e68",
|
|
111
|
+
befehl: "kimal3 project list",
|
|
112
|
+
tippen: "/k3list",
|
|
113
|
+
terminal: "kimal3 project list",
|
|
114
|
+
beschreibung: "Show the projects you've added",
|
|
115
|
+
rhythmusOderSatz: "show my projects",
|
|
116
|
+
details: [
|
|
117
|
+
"Shows what's already in your success profile — with dates and numbers.",
|
|
118
|
+
"What it's really for: Claude looks here BEFORE adding a project. Without that check, the same project would sooner or later appear twice on a public page that carries your name.",
|
|
119
|
+
],
|
|
120
|
+
},
|
|
121
|
+
"kimal3 firma daten": {
|
|
122
|
+
stempel: "3195364c",
|
|
123
|
+
befehl: "kimal3 company data",
|
|
124
|
+
tippen: "/k3analyse <your question>",
|
|
125
|
+
terminal: 'kimal3 company data --company "Nordwind Handel GmbH"',
|
|
126
|
+
beschreibung: "Fetch your company's data so Claude can analyse it",
|
|
127
|
+
rhythmusOderSatz: "analyse my company",
|
|
128
|
+
details: [
|
|
129
|
+
"Fetches the key figures, people and projects of your company — Claude does the analysis. Just ask: “Which three projects bring in the most measurable return?”",
|
|
130
|
+
"If you belong to several companies, it never quietly picks one; it lays them out for you as ready-made commands. If two have the SAME name, --company-id helps — also ready to copy, you don't have to rename anything.",
|
|
131
|
+
"⚠️ This is personal data about your colleagues. For use in a real company you need a commercial Claude account with a data processing agreement. If employees' performance is analysed, in Germany this requires the works council's agreement (co-determination).",
|
|
132
|
+
],
|
|
133
|
+
},
|
|
134
|
+
"kimal3 wache": {
|
|
135
|
+
stempel: "2daae4e2",
|
|
136
|
+
befehl: "kimal3 watch",
|
|
137
|
+
tippen: "! kimal3 watch",
|
|
138
|
+
terminal: "kimal3 watch",
|
|
139
|
+
beschreibung: "Check whether your access is valid and whether anything is pending",
|
|
140
|
+
rhythmusOderSatz: "automatically when Claude starts",
|
|
141
|
+
details: [
|
|
142
|
+
"The daily check runs by itself when Claude Code starts — you don't have to call it. Silent when there's nothing to do; an open task (access, version, skill) is reported in every session until it's done.",
|
|
143
|
+
"If it stays silent, everything is fine: no line means no problem. It only speaks up when your access has expired, a message is waiting, a new version is available or your skill files are out of date.",
|
|
144
|
+
"If it can't reach our server, it says nothing about access and messages — but still reports a new version if npm knows one. The two questions don't depend on each other.",
|
|
145
|
+
],
|
|
146
|
+
},
|
|
147
|
+
"kimal3 logout": {
|
|
148
|
+
stempel: "9dfc20d7",
|
|
149
|
+
befehl: "kimal3 logout",
|
|
150
|
+
tippen: "! kimal3 logout",
|
|
151
|
+
terminal: "kimal3 logout",
|
|
152
|
+
beschreibung: "Disconnect this computer",
|
|
153
|
+
rhythmusOderSatz: "only when needed",
|
|
154
|
+
details: [
|
|
155
|
+
"Disconnects this one computer — useful on someone else's or a shared device, or if a computer goes missing. Your other computers stay signed in.",
|
|
156
|
+
],
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Der Fingerabdruck der deutschen Felder eines Katalog-Eintrags: FNV-1a ueber 32 Bit, 8 Hex-Zeichen.
|
|
161
|
+
* Ein eigener kleiner Hash statt `node:crypto`, damit die Datei importfrei bleibt; er muss keinem
|
|
162
|
+
* Angreifer standhalten, nur eine Textaenderung bemerken.
|
|
163
|
+
*/
|
|
164
|
+
export function fingerabdruck(b) {
|
|
165
|
+
const text = JSON.stringify([b.beschreibung, b.wer === "du" ? b.rhythmus : b.ausloeser, b.tippen, b.terminal, b.details]);
|
|
166
|
+
let h = 0x811c9dc5;
|
|
167
|
+
for (let i = 0; i < text.length; i++) {
|
|
168
|
+
h ^= text.charCodeAt(i);
|
|
169
|
+
h = Math.imul(h, 0x01000193);
|
|
170
|
+
}
|
|
171
|
+
return (h >>> 0).toString(16).padStart(8, "0");
|
|
172
|
+
}
|
|
173
|
+
/** Was ein Katalog-Eintrag in einer Sprache anzeigt -- deutsch unveraendert aus dem Katalog. */
|
|
174
|
+
export function anzeigeIn(eintrag, sprache) {
|
|
175
|
+
if (sprache === "en")
|
|
176
|
+
return BEFEHLE_EN[eintrag.befehl];
|
|
177
|
+
return {
|
|
178
|
+
befehl: eintrag.befehl,
|
|
179
|
+
tippen: eintrag.tippen,
|
|
180
|
+
terminal: eintrag.terminal,
|
|
181
|
+
beschreibung: eintrag.beschreibung,
|
|
182
|
+
rhythmusOderSatz: eintrag.wer === "du" ? eintrag.rhythmus : eintrag.ausloeser,
|
|
183
|
+
details: eintrag.details,
|
|
184
|
+
};
|
|
185
|
+
}
|