kimal3 0.4.0-durchstich.3 → 0.4.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 +2 -0
- package/claude-plugins/.claude-plugin/marketplace.json +8 -8
- package/claude-plugins/README.md +7 -7
- package/claude-plugins/kimal3-logo/.claude-plugin/plugin.json +6 -6
- package/claude-plugins/kimal3-logo/hooks/hooks.json +1 -1
- package/claude-plugins/kimal3-logo/hooks/register.tsx +80 -80
- package/coach/de/kimal3-coach.md +167 -0
- package/coach/en/kimal3-coach.md +167 -0
- package/dist/arbeitsplatz-dateien.js +1 -1
- package/dist/arbeitsplatz-finden.js +115 -0
- package/dist/arbeitsplatz-suche.js +176 -0
- package/dist/befehle/einrichten.js +249 -31
- package/dist/befehle/kurs.js +77 -0
- package/dist/befehle/login.js +8 -1
- package/dist/befehle/skill-install.js +12 -0
- package/dist/befehle-katalog-en.js +12 -0
- package/dist/befehle-katalog.js +12 -0
- package/dist/befehlswoerter.js +4 -0
- package/dist/coach-ablegen.js +130 -0
- package/dist/coach-rechnung.js +40 -0
- package/dist/kimal3.js +4 -2
- package/dist/texte/coach.js +27 -0
- package/dist/texte/einrichten-marken.js +2 -2
- package/dist/texte/einrichten.js +48 -2
- package/dist/texte/kurs.js +21 -0
- package/package.json +2 -1
- package/skill/SKILL.md +7 -3
- package/skill/commands/k3feierabend.md +2 -3
- package/skill/commands/k3kurs.md +41 -53
- package/skill/commands/k3start.md +4 -3
- package/skill/en/SKILL.md +7 -3
- package/skill/en/commands/k3course.md +41 -54
- package/skill/en/commands/k3start.md +4 -3
- package/skill/en/commands/k3wrapup.md +3 -4
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { feld, ruf } from "../api.js";
|
|
2
|
+
import { sprache } from "../sprache.js";
|
|
3
|
+
import { ALLGEMEIN_TEXTE } from "../texte/allgemein.js";
|
|
4
|
+
import { KURS_TEXTE } from "../texte/kurs.js";
|
|
5
|
+
import { schlussFehler } from "../fehler.js";
|
|
6
|
+
import { BASIS_URL } from "../anmeldung.js";
|
|
7
|
+
const istZahl = (w) => typeof w === "number" && Number.isFinite(w);
|
|
8
|
+
function schrittAus(w) {
|
|
9
|
+
if (!w || typeof w !== "object")
|
|
10
|
+
return null;
|
|
11
|
+
const s = w;
|
|
12
|
+
if (typeof s.id !== "string" || !istZahl(s.beat) || typeof s.text !== "string" || (s.wer !== "claude" && s.wer !== "mensch"))
|
|
13
|
+
return null;
|
|
14
|
+
return { id: s.id, beat: s.beat, text: s.text, wer: s.wer };
|
|
15
|
+
}
|
|
16
|
+
/** Die Antwort von `GET /api/cli/kurs` -- `null`, wenn sie nicht die erwartete Form hat (z. B. ein WLAN-Anmeldeportal mit `200`). */
|
|
17
|
+
function standAus(koerper) {
|
|
18
|
+
if (!koerper || typeof koerper !== "object")
|
|
19
|
+
return null;
|
|
20
|
+
const k = koerper;
|
|
21
|
+
if (!Array.isArray(k.beats) || !Array.isArray(k.offen) || typeof k.abgeschlossen !== "boolean")
|
|
22
|
+
return null;
|
|
23
|
+
const beats = k.beats.map((b) => {
|
|
24
|
+
const r = b && typeof b === "object" ? b : {};
|
|
25
|
+
return istZahl(r.nummer) && istZahl(r.erledigt) && istZahl(r.gesamt) && typeof r.fertig === "boolean"
|
|
26
|
+
? { nummer: r.nummer, erledigt: r.erledigt, gesamt: r.gesamt, fertig: r.fertig }
|
|
27
|
+
: null;
|
|
28
|
+
});
|
|
29
|
+
const offen = k.offen.map(schrittAus);
|
|
30
|
+
const naechster = k.naechster === null ? null : schrittAus(k.naechster);
|
|
31
|
+
if (beats.includes(null) || offen.includes(null) || (k.naechster !== null && !naechster))
|
|
32
|
+
return null;
|
|
33
|
+
return { beats: beats, offen: offen, naechster, abgeschlossen: k.abgeschlossen };
|
|
34
|
+
}
|
|
35
|
+
/** Reine Rechnung: die Zeilen, die der Mensch (und Claude) zu sehen bekommen. */
|
|
36
|
+
export function kursZeilen(stand, s, basisUrl) {
|
|
37
|
+
const t = KURS_TEXTE[s];
|
|
38
|
+
const browser = t.imBrowser(basisUrl);
|
|
39
|
+
if (stand.abgeschlossen)
|
|
40
|
+
return [t.alleErledigt(stand.beats.reduce((n, b) => n + b.gesamt, 0)), browser];
|
|
41
|
+
const beats = stand.beats.map((b) => (b.fertig ? t.beatFertig(b.nummer) : t.beatTeil(b.nummer, b.erledigt, b.gesamt)));
|
|
42
|
+
const zeilen = [t.uebersicht(beats.join(" · "))];
|
|
43
|
+
if (stand.naechster)
|
|
44
|
+
zeilen.push(t.naechster(stand.naechster.text, stand.naechster.wer === "claude"));
|
|
45
|
+
// Alles Offene ausser dem, was schon als „Als Nächstes“ dasteht -- über die Kennung: Zwei offene Schritte
|
|
46
|
+
// eines Beats können denselben Text tragen, und nur der eine ist der nächste.
|
|
47
|
+
const rest = stand.offen.filter((o) => o.id !== stand.naechster?.id);
|
|
48
|
+
if (rest.length > 0) {
|
|
49
|
+
zeilen.push(t.nochOffen);
|
|
50
|
+
rest.forEach((o) => zeilen.push(t.offenZeile(o.beat, o.text, o.wer === "claude")));
|
|
51
|
+
}
|
|
52
|
+
zeilen.push(browser);
|
|
53
|
+
return zeilen;
|
|
54
|
+
}
|
|
55
|
+
/** Wo der Mensch im Mini-Kurs steht -- die Grundlage von `/k3kurs`. */
|
|
56
|
+
export async function kurs() {
|
|
57
|
+
const antwort = await ruf("/api/cli/kurs", { methode: "GET", mitAusweis: true }); // kein-anzeigetext: HTTP-Methode
|
|
58
|
+
// 🌐 Die Antwort kann die Kontosprache umgestellt haben: Was ab hier gedruckt wird, in der neuen.
|
|
59
|
+
const s = sprache();
|
|
60
|
+
if (antwort.status === 200) {
|
|
61
|
+
const stand = standAus(antwort.koerper);
|
|
62
|
+
if (!stand) {
|
|
63
|
+
console.error(ALLGEMEIN_TEXTE[s].unreadableAnswer);
|
|
64
|
+
return 3;
|
|
65
|
+
}
|
|
66
|
+
kursZeilen(stand, s, BASIS_URL).forEach((z) => console.log(z));
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
const meldung = feld(antwort.koerper, "meldung") ?? ALLGEMEIN_TEXTE[s].genericFailure;
|
|
70
|
+
if (antwort.status === 401) {
|
|
71
|
+
console.error(`${meldung}${ALLGEMEIN_TEXTE[s].pleaseSignIn}`);
|
|
72
|
+
return 2;
|
|
73
|
+
}
|
|
74
|
+
const schluss = schlussFehler(antwort.status, meldung, s);
|
|
75
|
+
console.error(schluss.text);
|
|
76
|
+
return schluss.wert;
|
|
77
|
+
}
|
package/dist/befehle/login.js
CHANGED
|
@@ -5,6 +5,7 @@ import { sprache } from "../sprache.js";
|
|
|
5
5
|
import { anmeldeAdresse, oeffneImBrowser } from "../browser.js";
|
|
6
6
|
import { ALLGEMEIN_TEXTE } from "../texte/allgemein.js";
|
|
7
7
|
import { EINRICHTEN_TEXTE } from "../texte/einrichten.js";
|
|
8
|
+
import { frischeCoachAuf } from "../coach-ablegen.js";
|
|
8
9
|
import { stelleSkillUm } from "./skill-tausch.js";
|
|
9
10
|
const warte = (ms) => new Promise((f) => setTimeout(f, ms));
|
|
10
11
|
// 🌐 Die Sprache wird bei JEDER Ausgabe neu gelesen: Die Abhol-Antwort nennt die Kontosprache
|
|
@@ -27,7 +28,13 @@ export async function login() {
|
|
|
27
28
|
console.log(t().loginOpen(BASIS_URL));
|
|
28
29
|
console.log(t().loginEnterCode(start.nutzerCode));
|
|
29
30
|
console.log(t().loginWaiting);
|
|
30
|
-
|
|
31
|
+
const code = await warteAufBestaetigung(start.geraeteCode);
|
|
32
|
+
// Der Coach zieht mit der Kontosprache mit -- nur beim BEFEHL `kimal3 login`, nicht in der geteilten Warteschleife:
|
|
33
|
+
// `einrichten` meldet anschließend seinen eigenen Coach, eine zweite Zeile wäre doppelt (Gesamt-Durchsicht, Fund 4;
|
|
34
|
+
// dasselbe Muster wie `skillInstallBefehl`). Frischt nur auf, legt nie an (Spec C-13b).
|
|
35
|
+
if (code === 0)
|
|
36
|
+
frischeCoachAuf(sprache());
|
|
37
|
+
return code;
|
|
31
38
|
}
|
|
32
39
|
/**
|
|
33
40
|
* Die Anmeldung für `kimal3 einrichten` (Spec 2026-10-11, S-2): Code und Adresse auf eigenen
|
|
@@ -9,6 +9,7 @@ import { eigeneVersion } from "../version.js";
|
|
|
9
9
|
import { sprache } from "../sprache.js";
|
|
10
10
|
import { andereSpracheZuRaeumen, skillQuelle } from "../slash-befehle.js";
|
|
11
11
|
import { SKILL_TEXTE } from "../texte/skill.js";
|
|
12
|
+
import { frischeCoachAuf } from "../coach-ablegen.js";
|
|
12
13
|
export const VERALTETE_BEFEHLE = [
|
|
13
14
|
/*
|
|
14
15
|
🔴 **Der ERSTE Eintrag ueberhaupt** (2026-08-28). `/k3firma` heisst jetzt
|
|
@@ -320,6 +321,17 @@ export async function skillInstall() {
|
|
|
320
321
|
}
|
|
321
322
|
return 0;
|
|
322
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* Der Befehl `kimal3 skill install`: die Anleitung ablegen und einen VORHANDENEN Coach mitziehen (Update, Sprachwechsel;
|
|
326
|
+
* angelegt wird keiner). Bewusst hier und nicht in `skillInstall()`: `einrichten` ruft das auch, hat seinen Coach aber
|
|
327
|
+
* schon selbst abgelegt und gemeldet -- ein zweites Auffrischen druckte dessen Zeile noch einmal (bei fehlender
|
|
328
|
+
* Trenn-Marke auch die Ersatzdatei ein zweites Mal).
|
|
329
|
+
*/
|
|
330
|
+
export async function skillInstallBefehl() {
|
|
331
|
+
const code = await skillInstall();
|
|
332
|
+
frischeCoachAuf(sprache());
|
|
333
|
+
return code;
|
|
334
|
+
}
|
|
323
335
|
/**
|
|
324
336
|
* Kopiert die Slash-Befehle nach `~/.claude/commands/`.
|
|
325
337
|
*
|
|
@@ -118,6 +118,18 @@ export const BEFEHLE_EN = {
|
|
|
118
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
119
|
],
|
|
120
120
|
},
|
|
121
|
+
"kimal3 kurs": {
|
|
122
|
+
stempel: "3a5c7600",
|
|
123
|
+
befehl: "kimal3 course",
|
|
124
|
+
tippen: "/k3course",
|
|
125
|
+
terminal: "kimal3 course",
|
|
126
|
+
beschreibung: "Show where you are in the mini-course",
|
|
127
|
+
rhythmusOderSatz: "where am I in the course",
|
|
128
|
+
details: [
|
|
129
|
+
"Shows which parts you have finished, what is next and what is still open — and for each step whether you tick it off or Claude sets it.",
|
|
130
|
+
"Claude reads this when you come back to the course and picks up exactly where you left off.",
|
|
131
|
+
],
|
|
132
|
+
},
|
|
121
133
|
"kimal3 firma daten": {
|
|
122
134
|
stempel: "3195364c",
|
|
123
135
|
befehl: "kimal3 company data",
|
package/dist/befehle-katalog.js
CHANGED
|
@@ -167,6 +167,18 @@ export const BEFEHLE = [
|
|
|
167
167
|
"Wofür es wirklich da ist: Claude schaut hier VOR dem Eintragen nach. Ohne diesen Blick stünde dasselbe Projekt irgendwann zweimal auf einer öffentlichen Seite, die deinen Namen trägt.",
|
|
168
168
|
],
|
|
169
169
|
},
|
|
170
|
+
{
|
|
171
|
+
befehl: "kimal3 kurs",
|
|
172
|
+
beschreibung: "Zeigen, wo du im Mini-Kurs stehst",
|
|
173
|
+
wer: "claude",
|
|
174
|
+
ausloeser: "wo stehe ich im Kurs",
|
|
175
|
+
tippen: "/k3kurs",
|
|
176
|
+
terminal: "kimal3 kurs",
|
|
177
|
+
details: [
|
|
178
|
+
"Zeigt, welche Beats du fertig hast, was als Nächstes dran ist und was noch offen ist — und bei jedem Schritt, ob du ihn abhakst oder Claude ihn setzt.",
|
|
179
|
+
"Claude liest das, wenn du in den Kurs zurückkehrst, und macht genau dort weiter, wo du aufgehört hast.",
|
|
180
|
+
],
|
|
181
|
+
},
|
|
170
182
|
{
|
|
171
183
|
befehl: "kimal3 firma daten",
|
|
172
184
|
beschreibung: "Die Daten deiner Firma holen, damit Claude sie auswerten kann",
|
package/dist/befehlswoerter.js
CHANGED
|
@@ -11,6 +11,7 @@ export const BEFEHLSWOERTER = {
|
|
|
11
11
|
"projekt neu": { de: "projekt neu", en: "project new" }, // kein-anzeigetext: Befehlswörter (Spec Abschnitt 6)
|
|
12
12
|
"projekt liste": { de: "projekt liste", en: "project list" }, // kein-anzeigetext: Befehlswörter (Spec Abschnitt 6)
|
|
13
13
|
"firma daten": { de: "firma daten", en: "company data" }, // kein-anzeigetext: Befehlswörter (Spec Abschnitt 6)
|
|
14
|
+
kurs: { de: "kurs", en: "course" }, // kein-anzeigetext: Befehlswörter (Spec Abschnitt 6)
|
|
14
15
|
wache: { de: "wache", en: "watch" },
|
|
15
16
|
"wache an": { de: "wache an", en: "watch on" }, // kein-anzeigetext: Befehlswörter (Spec Abschnitt 6)
|
|
16
17
|
"wache aus": { de: "wache aus", en: "watch off" }, // kein-anzeigetext: Befehlswörter (Spec Abschnitt 6)
|
|
@@ -56,6 +57,9 @@ export const SCHALTER_EN = {
|
|
|
56
57
|
impact: "wirkung",
|
|
57
58
|
"impact-label": "wirkung-label",
|
|
58
59
|
"live-since": "live-seit",
|
|
60
|
+
// `kimal3 einrichten` / `setup` (Spec 2026-10-16, Bauform 6)
|
|
61
|
+
workplace: "arbeitsplatz",
|
|
62
|
+
workbench: "werkbank",
|
|
59
63
|
};
|
|
60
64
|
/** `company` -> `firma`; ein deutscher (oder unbekannter) Name bleibt, wie er ist. */
|
|
61
65
|
export function deutscherSchalter(getippt) {
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { coachNachher } from "./coach-rechnung.js";
|
|
6
|
+
import { COACH_TEXTE } from "./texte/coach.js";
|
|
7
|
+
/**
|
|
8
|
+
* Der Coach im Regel-Ordner (Spec 2026-10-16): Claude Code lädt jede Datei in `~/.claude/rules/` bei jedem Start mit,
|
|
9
|
+
* in jedem Ordner -- dort wirkt er, ohne dass `~/.claude/CLAUDE.md` angefasst wird (die gehört dem Menschen).
|
|
10
|
+
* Was in der Datei steht, rechnet `coach-rechnung.ts` (rein, bewacht von `check:wache`); hier wird nur gelesen und
|
|
11
|
+
* geschrieben. Gemessen am gebauten Programm von `check:cli-live`.
|
|
12
|
+
*/
|
|
13
|
+
export const coachPfad = () => join(homedir(), ".claude", "rules", "kimal3-coach.md"); // kein-anzeigetext: Dateiname
|
|
14
|
+
/** Fehlt die Trenn-Marke, landet die neue Fassung HIER -- außerhalb des Regel-Ordners, sonst lüden zwei Coaches (UX-10). */
|
|
15
|
+
export const coachErsatzPfad = () => join(homedir(), ".kimal3", "kimal3-coach-neu.md"); // kein-anzeigetext: Dateiname
|
|
16
|
+
/** Der Coach aus dem alten Mini-Kurs, und wohin Claude ihn nach einem Ja verschiebt (S-14) -- `kimal3` schreibt ihn nie. */
|
|
17
|
+
export const alterKursCoachPfad = () => join(homedir(), ".claude", "CLAUDE.md"); // kein-anzeigetext: Dateiname
|
|
18
|
+
export const alterKursCoachAblage = () => join(homedir(), ".kimal3", "alter-kurs-coach.md"); // kein-anzeigetext: Dateiname
|
|
19
|
+
/**
|
|
20
|
+
* Legt den Coach ab oder frischt ihn auf. `null` = es liegt keiner da, und dieser Aufruf darf keinen anlegen
|
|
21
|
+
* (nur `einrichten` darf das; `skill install` und `login` frischen nur auf).
|
|
22
|
+
* 🔑 Wirft nie: Jeder Lese- oder Schreibfehler wird `gescheitert` mit der Meldung des Systems -- die Einrichtung läuft
|
|
23
|
+
* weiter (C-10), und der Mensch erfährt den Grund statt einer Stapelspur.
|
|
24
|
+
*/
|
|
25
|
+
export function legeCoachAb(s, darfAnlegen) {
|
|
26
|
+
const pfad = coachPfad();
|
|
27
|
+
try {
|
|
28
|
+
const da = statSync(pfad, { throwIfNoEntry: false });
|
|
29
|
+
// Ein Ordner unter dem Namen gehört nicht uns -- nichts anfassen, wie bei einer fremden Datei (C-11).
|
|
30
|
+
if (da !== undefined && !da.isFile())
|
|
31
|
+
return { art: "fremd", pfad, spracheGewechselt: false };
|
|
32
|
+
if (da === undefined && !darfAnlegen)
|
|
33
|
+
return null;
|
|
34
|
+
// Die Vorlage erst NACH dem `null`: Wer keinen Coach hat, soll von `login` und `skill install` auch dann nichts hören,
|
|
35
|
+
// wenn die Vorlage im Paket fehlt (Gesamt-Durchsicht, Fund 6).
|
|
36
|
+
// `dist/coach-ablegen.js` -> `../coach/<sprache>/…` im installierten Paket (`files` in package.json).
|
|
37
|
+
const vorlage = readFileSync(fileURLToPath(new URL(`../coach/${s}/kimal3-coach.md`, import.meta.url)), "utf8"); // kein-anzeigetext: Paketpfad
|
|
38
|
+
const ergebnis = coachNachher(da === undefined ? null : readFileSync(pfad, "utf8"), vorlage);
|
|
39
|
+
switch (ergebnis.art) {
|
|
40
|
+
case "neu":
|
|
41
|
+
mkdirSync(dirname(pfad), { recursive: true });
|
|
42
|
+
tauscheEin(pfad, ergebnis.inhalt);
|
|
43
|
+
return { art: "angelegt", pfad, spracheGewechselt: false };
|
|
44
|
+
case "aktualisiert":
|
|
45
|
+
tauscheEin(pfad, ergebnis.inhalt);
|
|
46
|
+
return { art: "aktualisiert", pfad, spracheGewechselt: ergebnis.spracheVorher !== null && ergebnis.spracheVorher !== s };
|
|
47
|
+
case "ohne-trenner": {
|
|
48
|
+
// Das Original bleibt Byte für Byte (C-8): Ohne Trenn-Marke wüssten wir nicht, wo seine Regeln anfangen.
|
|
49
|
+
const ersatz = coachErsatzPfad();
|
|
50
|
+
mkdirSync(dirname(ersatz), { recursive: true });
|
|
51
|
+
writeFileSync(ersatz, ergebnis.inhalt, "utf8");
|
|
52
|
+
return { art: "ohne-trenner", pfad, ersatz };
|
|
53
|
+
}
|
|
54
|
+
case "vorlage-ohne-trenner":
|
|
55
|
+
return { art: "gescheitert", pfad, grund: COACH_TEXTE[s].templateWithoutSeparator };
|
|
56
|
+
default:
|
|
57
|
+
return { art: ergebnis.art, pfad, spracheGewechselt: false };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
return { art: "gescheitert", pfad, grund: e.message };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Erst in eine Nebendatei, dann tauschen (Durchsicht Aufgabe 5, Fund 1): `writeFileSync` leert die Datei, BEVOR es
|
|
66
|
+
* schreibt -- bei voller Platte wären die gelernten Regeln weg, und der nächste Lauf hielte den leeren Rest für fremd.
|
|
67
|
+
* 🔑 `kimal3-coach.md.neu` endet nicht auf `.md`: Claude lädt sie nie als zweiten Coach, auch wenn sie liegen bliebe.
|
|
68
|
+
* Scheitert ein Schritt, kommt die Nebendatei weg (ein Ordner unter dem Namen ist nicht unserer und bleibt), und der
|
|
69
|
+
* Fehler geht an `legeCoachAb`, das ihn zu `gescheitert` macht.
|
|
70
|
+
*/
|
|
71
|
+
function tauscheEin(pfad, inhalt) {
|
|
72
|
+
const neben = `${pfad}.neu`; // kein-anzeigetext: Dateiname
|
|
73
|
+
try {
|
|
74
|
+
writeFileSync(neben, inhalt, "utf8");
|
|
75
|
+
renameSync(neben, pfad);
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
try {
|
|
79
|
+
rmSync(neben);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// Lag nie da, oder es ist ein Ordner -- dann nichts anfassen.
|
|
83
|
+
}
|
|
84
|
+
throw e;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/** Liegt unter dem Coach-Pfad eine DATEI (unsere oder eine fremde)? Daran hängt `beat2-coach` (E-5, E-9). Wirft nie. */
|
|
88
|
+
export function coachDateiLiegt() {
|
|
89
|
+
try {
|
|
90
|
+
return statSync(coachPfad(), { throwIfNoEntry: false })?.isFile() === true;
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Die eine Zeile zu einer Ablage, in der Sprache des Laufs -- für `einrichten` (Task 5), `skill install` und `login`.
|
|
98
|
+
* `sprachwechselSagen`: Nur `login` und `skill install` sagen einen Sprachwechsel mit eigenem Satz (Spec 2.6) -- er
|
|
99
|
+
* sagt, was der Mensch dort sonst nicht merkt: dass seine Regeln den Wechsel überlebt haben. `einrichten` bleibt bei der
|
|
100
|
+
* Zeile mit `Coach:`, an der die Anleitung liest. Welche Fälle ein Aufruf verschweigt (`gleich`, `fremd` beim
|
|
101
|
+
* Auffrischen), entscheidet der Aufrufer.
|
|
102
|
+
*/
|
|
103
|
+
export function meldeCoach(ablage, s, sprachwechselSagen = false) {
|
|
104
|
+
if (ablage === null)
|
|
105
|
+
return;
|
|
106
|
+
const t = COACH_TEXTE[s];
|
|
107
|
+
if (ablage.art === "angelegt")
|
|
108
|
+
console.log(t.setUp(ablage.pfad));
|
|
109
|
+
else if (ablage.art === "gleich")
|
|
110
|
+
console.log(t.upToDate);
|
|
111
|
+
else if (ablage.art === "aktualisiert")
|
|
112
|
+
console.log(sprachwechselSagen && ablage.spracheGewechselt ? t.languageSwitched : t.updated);
|
|
113
|
+
else if (ablage.art === "fremd")
|
|
114
|
+
console.log(t.foreign(ablage.pfad));
|
|
115
|
+
else if (ablage.art === "ohne-trenner")
|
|
116
|
+
console.log(t.noSeparator(ablage.pfad, ablage.ersatz));
|
|
117
|
+
else if (ablage.art === "gescheitert")
|
|
118
|
+
console.log(t.failed(ablage.grund));
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Für `skill install` und `login`: einen VORHANDENEN Coach auffrischen (Update, Sprachwechsel), nie einen anlegen --
|
|
122
|
+
* das darf nur `einrichten` (Spec C-13b: Auffrischen ist kein Anlegen). Schweigt, wenn nichts zu sagen ist: kein Coach,
|
|
123
|
+
* ein fremder, ein schon aktueller. Ein Sprachwechsel bekommt seinen eigenen Satz (Spec 2.6).
|
|
124
|
+
*/
|
|
125
|
+
export function frischeCoachAuf(s) {
|
|
126
|
+
const ablage = legeCoachAb(s, false);
|
|
127
|
+
if (ablage === null || ablage.art === "gleich" || ablage.art === "fremd")
|
|
128
|
+
return;
|
|
129
|
+
meldeCoach(ablage, s, true);
|
|
130
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Ein BOM (U+FEFF) vor der ersten Zeile setzen manche Windows-Editoren; er gehört nicht zur Marke.
|
|
2
|
+
const KOPF = /^\uFEFF?<!-- kimal3:coach/;
|
|
3
|
+
const KOPF_SPRACHE = /^\uFEFF?<!-- kimal3:coach sprache=(de|en)(?![A-Za-z])/;
|
|
4
|
+
// Nur am ZEILENANFANG, ohne Einrückung: Die Kopfzeile nennt die Trenn-Marke im Fließtext, und eine gelernte Regel darf
|
|
5
|
+
// es auch. 🔑 Exportiert, weil `check:cli` die Vorlagen mit GENAU diesem Ausdruck prüft -- eine eigene, nachsichtigere
|
|
6
|
+
// Erkennung dort ließe eine eingerückte Marke grün durch, die diese Rechnung nicht findet (Gesamt-Durchsicht, Fund 3).
|
|
7
|
+
export const TRENNER = /^<!-- kimal3:gelernte-regeln/m;
|
|
8
|
+
const ALTER_KURS_COACH = /^\uFEFF?# CLAUDE\.md — (Dein Claude-Coach|Your Claude coach)/;
|
|
9
|
+
export const istUnserCoach = (inhalt) => KOPF.test(inhalt);
|
|
10
|
+
export function coachSprache(inhalt) {
|
|
11
|
+
const treffer = KOPF_SPRACHE.exec(inhalt);
|
|
12
|
+
return treffer ? treffer[1] : null;
|
|
13
|
+
}
|
|
14
|
+
// Der Kurs-Coach von früher (Beat 2 des Mini-Kurses) beginnt mit dieser Überschrift, deutsch wie englisch.
|
|
15
|
+
export const istAlterKursCoach = (inhalt) => ALTER_KURS_COACH.test(inhalt);
|
|
16
|
+
// Alles bis einschließlich des Zeilenendes der ersten Trenn-Zeile (\n oder \r\n -- das \r steht vor dem \n und
|
|
17
|
+
// gehört damit zur Zeile). Ohne Zeilenende danach reicht die Zeile bis zum Dateiende. -1 = keine Trenn-Zeile.
|
|
18
|
+
function obenBis(text) {
|
|
19
|
+
const treffer = TRENNER.exec(text);
|
|
20
|
+
if (!treffer)
|
|
21
|
+
return -1;
|
|
22
|
+
const umbruch = text.indexOf("\n", treffer.index);
|
|
23
|
+
return umbruch === -1 ? text.length : umbruch + 1;
|
|
24
|
+
}
|
|
25
|
+
export function coachNachher(vorher, vorlage) {
|
|
26
|
+
const vorlageEnde = obenBis(vorlage);
|
|
27
|
+
if (vorlageEnde === -1)
|
|
28
|
+
return { art: "vorlage-ohne-trenner" };
|
|
29
|
+
if (vorher === null)
|
|
30
|
+
return { art: "neu", inhalt: vorlage };
|
|
31
|
+
if (!istUnserCoach(vorher))
|
|
32
|
+
return { art: "fremd" };
|
|
33
|
+
const altEnde = obenBis(vorher);
|
|
34
|
+
if (altEnde === -1)
|
|
35
|
+
return { art: "ohne-trenner", inhalt: vorlage };
|
|
36
|
+
const neu = vorlage.slice(0, vorlageEnde) + vorher.slice(altEnde);
|
|
37
|
+
if (neu === vorher)
|
|
38
|
+
return { art: "gleich" };
|
|
39
|
+
return { art: "aktualisiert", inhalt: neu, spracheVorher: coachSprache(vorher) };
|
|
40
|
+
}
|
package/dist/kimal3.js
CHANGED
|
@@ -33,9 +33,10 @@ import { kontextRunter } from "./befehle/kontext-runter.js";
|
|
|
33
33
|
import { kontextHoch } from "./befehle/kontext-hoch.js";
|
|
34
34
|
import { login } from "./befehle/login.js";
|
|
35
35
|
import { logout } from "./befehle/logout.js";
|
|
36
|
+
import { kurs } from "./befehle/kurs.js";
|
|
36
37
|
import { projektListe } from "./befehle/projekt-liste.js";
|
|
37
38
|
import { projektNeu } from "./befehle/projekt-neu.js";
|
|
38
|
-
import { skillDatei,
|
|
39
|
+
import { skillDatei, skillInstallBefehl } from "./befehle/skill-install.js";
|
|
39
40
|
import { wache, wacheSchalten } from "./befehle/wache.js";
|
|
40
41
|
/** Eine Meldung pro Programmlauf -- s. "Einmal-Riegel" im Block darunter. */
|
|
41
42
|
let schonGemeldet = false;
|
|
@@ -480,9 +481,10 @@ async function fuehreAus(name, rest) {
|
|
|
480
481
|
switch (name) {
|
|
481
482
|
case "login": return allein ? login() : null;
|
|
482
483
|
case "logout": return allein ? logout() : null;
|
|
483
|
-
case "skill install": return allein ?
|
|
484
|
+
case "skill install": return allein ? skillInstallBefehl() : null;
|
|
484
485
|
case "projekt neu": return projektNeu(rest);
|
|
485
486
|
case "projekt liste": return allein ? projektListe() : null;
|
|
487
|
+
case "kurs": return allein ? kurs() : null;
|
|
486
488
|
// ⚠️ Rest wird durchgereicht, nicht auf Gleichheit geprueft: `firma daten --firma X` gehoert dazu.
|
|
487
489
|
case "firma daten": return firmaDaten(rest);
|
|
488
490
|
case "einrichten": return einrichten(rest);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { EINRICHTEN_MARKEN } from "./einrichten-marken.js";
|
|
2
|
+
const M = EINRICHTEN_MARKEN;
|
|
3
|
+
const de = {
|
|
4
|
+
setUp: (pfad) => ` ${M.de.coach} eingerichtet (${pfad}).`,
|
|
5
|
+
upToDate: ` ${M.de.coach} ist aktuell.`,
|
|
6
|
+
updated: ` ${M.de.coach} aktualisiert — deine gelernten Regeln sind geblieben.`,
|
|
7
|
+
foreign: (pfad) => ` ${M.de.coach} Unter ${pfad} liegt schon eine Datei, die nicht von KImal3 stammt — ich lasse sie, wie sie ist.`,
|
|
8
|
+
noSeparator: (pfad, neu) => ` ${M.de.coach} nicht aktualisiert — in ${pfad} fehlt die Zeile, ab der deine gelernten Regeln stehen. Die neue Fassung liegt unter ${neu}.`,
|
|
9
|
+
failed: (grund) => ` ${M.de.coach} konnte nicht abgelegt werden — ${grund}`,
|
|
10
|
+
// Der Grund zu `failed`, wenn der Vorlage im Programm selbst die Trenn-Marke fehlt (ein Paketfehler, `coach-rechnung.ts`).
|
|
11
|
+
templateWithoutSeparator: "der Vorlage im Programm fehlt die Zeile, ab der die gelernten Regeln stehen. Das ist ein Fehler in kimal3 — bitte melde ihn uns.",
|
|
12
|
+
// Die Zeile spricht immer die Sprache, in die umgestellt wurde -- deshalb steht der Sprachname fest im Satz.
|
|
13
|
+
languageSwitched: "✓ Dein Coach ist jetzt auf Deutsch — deine gelernten Regeln sind geblieben.",
|
|
14
|
+
oldCourseCoach: (pfad, ablage) => ` ${M.de.alterKursCoach} Du hast im alten Mini-Kurs schon einmal einen Coach eingerichtet (${pfad}). Jetzt gibt es einen neuen, und zwei gleichzeitig würden sich widersprechen. Soll ich den alten beiseitelegen? Du findest ihn danach unter ${ablage}.`,
|
|
15
|
+
};
|
|
16
|
+
const en = {
|
|
17
|
+
setUp: (pfad) => ` ${M.en.coach} set up (${pfad}).`,
|
|
18
|
+
upToDate: ` ${M.en.coach} up to date.`,
|
|
19
|
+
updated: ` ${M.en.coach} updated — your learned rules are still there.`,
|
|
20
|
+
foreign: (pfad) => ` ${M.en.coach} There's already a file at ${pfad} that doesn't come from KImal3 — I'll leave it as it is.`,
|
|
21
|
+
noSeparator: (pfad, neu) => ` ${M.en.coach} not updated — ${pfad} is missing the line your learned rules start below. The new version is at ${neu}.`,
|
|
22
|
+
failed: (grund) => ` ${M.en.coach} couldn't be put in place — ${grund}`,
|
|
23
|
+
templateWithoutSeparator: "the program's template is missing the line your learned rules start below. That's a bug in kimal3 — please tell us.",
|
|
24
|
+
languageSwitched: "✓ Your coach is now in English — your learned rules are still there.",
|
|
25
|
+
oldCourseCoach: (pfad, ablage) => ` ${M.en.alterKursCoach} You set up a coach in the old mini course (${pfad}). There's a new one now, and two at once would contradict each other. Shall I put the old one aside? You'll find it at ${ablage} afterwards.`,
|
|
26
|
+
};
|
|
27
|
+
export const COACH_TEXTE = { de, en };
|
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
* Programm druckt sie, die Anleitung nennt sie, `check:kurs` haelt beide gleich.
|
|
5
5
|
*/
|
|
6
6
|
export const EINRICHTEN_MARKEN = {
|
|
7
|
-
de: { code: "Anmelde-Code:", adresse: "Adresse:", arbeitsplatz: "Arbeitsplatz:", werkbank: "Werkbank:", angemeldet: "Angemeldet als", plugins: "Plugins:" },
|
|
8
|
-
en: { code: "Sign-in code:", adresse: "Address:", arbeitsplatz: "Workplace:", werkbank: "Workbench:", angemeldet: "Signed in as", plugins: "Plugins:" },
|
|
7
|
+
de: { code: "Anmelde-Code:", adresse: "Adresse:", arbeitsplatz: "Arbeitsplatz:", werkbank: "Werkbank:", angemeldet: "Angemeldet als", plugins: "Plugins:", naechster: "Als Nächstes:", coach: "Coach:", alterKursCoach: "Alter Kurs-Coach:" },
|
|
8
|
+
en: { code: "Sign-in code:", adresse: "Address:", arbeitsplatz: "Workplace:", werkbank: "Workbench:", angemeldet: "Signed in as", plugins: "Plugins:", naechster: "Next:", coach: "Coach:", alterKursCoach: "Old course coach:" },
|
|
9
9
|
};
|
package/dist/texte/einrichten.js
CHANGED
|
@@ -5,11 +5,36 @@ const de = {
|
|
|
5
5
|
addressLine: (url) => ` ${M.de.adresse} ${url}`,
|
|
6
6
|
browserOpened: " Ich öffne die Seite gerade in deinem Browser. Bestätige dort nur, wenn derselbe Code dasteht.",
|
|
7
7
|
browserNotOpened: " Öffne die Adresse oben in deinem Browser. Bestätige dort nur, wenn derselbe Code dasteht.",
|
|
8
|
-
help: "\n kimal3 einrichten [--firma \"Name\" | --firma-id \"…\"]\n\n Meldet dich an (der Browser öffnet sich mit deinem Code),
|
|
8
|
+
help: "\n kimal3 einrichten [--firma \"Name\" | --firma-id \"…\"] [--arbeitsplatz \"<pfad>\"] [--werkbank <name>]\n\n Meldet dich an (der Browser öffnet sich mit deinem Code), sucht deinen\n KI-Arbeitsplatz oder legt ihn in deinem Benutzerordner an, richtet die\n /k3-Befehle und die Wache ein und hakt die Schritte im Kurs ab. Ein\n vorhandener Arbeitsplatz wird benutzt, nicht verändert.\n\n --arbeitsplatz wo dein Arbeitsplatz liegt oder neu entstehen soll\n --werkbank welche Werkbank darin deine ist\n",
|
|
9
9
|
start: "\nIch richte deinen KI-Arbeitsplatz ein.",
|
|
10
10
|
filesWritten: (neu, schonDa) => `\n✓ ${neu} Dateien angelegt, ${schonDa} lagen schon da.`,
|
|
11
11
|
workplaceLine: (pfad) => ` ${M.de.arbeitsplatz} ${pfad}`,
|
|
12
12
|
workbenchLine: (name) => ` ${M.de.werkbank} ${name}`,
|
|
13
|
+
// Was Sabine in der nächsten Sitzung schreibt (Spec 2026-10-16, Z-15): Steht die Anleitung für die erste
|
|
14
|
+
// Sitzung noch in ihrer Werkbank, der Startsatz der Vorlage; sonst der Befehl für jeden weiteren Tag.
|
|
15
|
+
nextLine: (offen) => ` ${M.de.naechster} ${offen ? "„Lass uns einrichten“" : "/k3start"}`,
|
|
16
|
+
// Vorhandener Arbeitsplatz (Spec 2026-10-16, „Neue Sätze“). Jede Rückfrage endet mit fertigen Befehlen.
|
|
17
|
+
foundWorkplace: (pfad) => `\nDein Arbeitsplatz liegt schon unter ${pfad} — ich benutze diesen.`,
|
|
18
|
+
severalFound: "\nIch habe mehrere Arbeitsplätze gefunden. Welchen soll ich benutzen?",
|
|
19
|
+
foreignFolder: (pfad) => `\nUnter ${pfad} liegt schon ein Ordner, der nicht von KImal3 stammt. Ich lege dort nichts ab.`,
|
|
20
|
+
searchIncomplete: "\nIch konnte nicht überall nachsehen. Hast du schon einen Arbeitsplatz?",
|
|
21
|
+
rememberedGone: (pfad) => `\nDein Arbeitsplatz lag unter ${pfad}, dort ist er nicht mehr. Wo liegt er jetzt?`,
|
|
22
|
+
noMatchingWorkbench: (pfad) => `\nIn ${pfad} finde ich keine Werkbank für dich.`,
|
|
23
|
+
confirmWorkbench: (name) => `\nIst ${name} deine Werkbank?`,
|
|
24
|
+
noWorkbenchInWorkplace: (pfad) => `\nIn ${pfad} gibt es noch keine Werkbank. Leg deine an und starte die Einrichtung danach noch einmal:`,
|
|
25
|
+
// Die Überschriften über den Befehlen der Rückfragen.
|
|
26
|
+
existingWorkplace: " Er liegt hier (Pfad einsetzen):",
|
|
27
|
+
newWorkplace: " Leg einen neuen an:",
|
|
28
|
+
otherPlace: " Nimm einen anderen Ort, leer oder mit deinem Arbeitsplatz:",
|
|
29
|
+
yes: " Ja:",
|
|
30
|
+
noOther: " Nein, es ist eine andere:",
|
|
31
|
+
oneOfThese: " Ist eine davon deine:",
|
|
32
|
+
ownWorkbench: " Noch keine eigene? Leg sie an und starte die Einrichtung danach noch einmal:",
|
|
33
|
+
pathPlaceholder: "<pfad>",
|
|
34
|
+
// Ein mitkopierter Platzhalter in `--arbeitsplatz` -- Claude fragt dann nach dem echten Ort.
|
|
35
|
+
placeholderPath: (wert) => `\n${wert} ist ein Platzhalter, kein Ordner. Setz dort den echten Pfad deines Arbeitsplatzes ein; ich habe nichts angelegt.`,
|
|
36
|
+
commandLine: (rest) => ` kimal3 ${rest}`,
|
|
37
|
+
cdLine: (pfad) => ` cd ${pfad}`,
|
|
13
38
|
courseMarked: "✓ Im Kurs abgehakt.",
|
|
14
39
|
courseNotMarked: " Die Haken im Kurs konnte ich gerade nicht setzen — der nächste Lauf holt das nach.",
|
|
15
40
|
done: "\n✓ Fertig eingerichtet.",
|
|
@@ -36,11 +61,32 @@ const en = {
|
|
|
36
61
|
addressLine: (url) => ` ${M.en.adresse} ${url}`,
|
|
37
62
|
browserOpened: " Opening the page in your browser now. Only confirm there if it shows the same code.",
|
|
38
63
|
browserNotOpened: " Open the address above in your browser. Only confirm there if it shows the same code.",
|
|
39
|
-
help: "\n kimal3 setup [--company \"Name\" | --company-id \"…\"]\n\n Signs you in (your browser opens with your code),
|
|
64
|
+
help: "\n kimal3 setup [--company \"Name\" | --company-id \"…\"] [--workplace \"<path>\"] [--workbench <name>]\n\n Signs you in (your browser opens with your code), finds your AI Workplace\n or creates it in your user folder, sets up the /k3 commands and the watch,\n and ticks off the course steps. An existing workplace is used, not changed.\n\n --workplace where your workplace is, or where a new one should go\n --workbench which workbench in it is yours\n",
|
|
40
65
|
start: "\nSetting up your AI Workplace.",
|
|
41
66
|
filesWritten: (neu, schonDa) => `\n✓ ${neu} files created, ${schonDa} were already there.`,
|
|
42
67
|
workplaceLine: (pfad) => ` ${M.en.arbeitsplatz} ${pfad}`,
|
|
43
68
|
workbenchLine: (name) => ` ${M.en.werkbank} ${name}`,
|
|
69
|
+
// The start sentence of the English template (workbench-your-name/CLAUDE.md, anleitung-en.ts) -- exactly that one.
|
|
70
|
+
nextLine: (offen) => ` ${M.en.naechster} ${offen ? "“Let's get set up”" : "/k3start"}`,
|
|
71
|
+
foundWorkplace: (pfad) => `\nYour workplace already exists at ${pfad} — I'll use that one.`,
|
|
72
|
+
severalFound: "\nI found more than one workplace. Which one should I use?",
|
|
73
|
+
foreignFolder: (pfad) => `\nThere's already a folder at ${pfad} that doesn't come from KImal3. I won't put anything there.`,
|
|
74
|
+
searchIncomplete: "\nI couldn't look everywhere. Do you already have a workplace?",
|
|
75
|
+
rememberedGone: (pfad) => `\nYour workplace was at ${pfad} and isn't there anymore. Where is it now?`,
|
|
76
|
+
noMatchingWorkbench: (pfad) => `\nI can't find a workbench for you in ${pfad}.`,
|
|
77
|
+
confirmWorkbench: (name) => `\nIs ${name} your workbench?`,
|
|
78
|
+
noWorkbenchInWorkplace: (pfad) => `\nThere's no workbench in ${pfad} yet. Create yours, then run the setup again:`,
|
|
79
|
+
existingWorkplace: " It's here (fill in the path):",
|
|
80
|
+
newWorkplace: " Create a new one:",
|
|
81
|
+
otherPlace: " Choose another place, empty or with your workplace in it:",
|
|
82
|
+
yes: " Yes:",
|
|
83
|
+
noOther: " No, it's another one:",
|
|
84
|
+
oneOfThese: " If one of these is yours:",
|
|
85
|
+
ownWorkbench: " None of your own yet? Create it, then run the setup again:",
|
|
86
|
+
pathPlaceholder: "<path>",
|
|
87
|
+
placeholderPath: (wert) => `\n${wert} is a placeholder, not a folder. Put the real path of your workplace there; I haven't created anything.`,
|
|
88
|
+
commandLine: (rest) => ` kimal3 ${rest}`,
|
|
89
|
+
cdLine: (pfad) => ` cd ${pfad}`,
|
|
44
90
|
courseMarked: "✓ Ticked off in the course.",
|
|
45
91
|
courseNotMarked: " I couldn't tick off the course steps just now — the next run will catch up.",
|
|
46
92
|
done: "\n✓ All set up.",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const de = {
|
|
2
|
+
beatFertig: (nummer) => `Beat ${nummer} ✓`,
|
|
3
|
+
beatTeil: (nummer, erledigt, gesamt) => `Beat ${nummer} — ${erledigt} von ${gesamt}`,
|
|
4
|
+
uebersicht: (beats) => `Kurs: ${beats}`,
|
|
5
|
+
alleErledigt: (anzahl) => `Kurs: abgeschlossen ✓ — alle ${anzahl} Schritte erledigt.`,
|
|
6
|
+
naechster: (text, claude) => `Als Nächstes: ${text} (${claude ? "setzt Claude" : "du hakst ab"})`,
|
|
7
|
+
nochOffen: "Noch offen:",
|
|
8
|
+
offenZeile: (beat, text, claude) => ` ○ Beat ${beat}: ${text} (${claude ? "setzt Claude" : "du hakst ab"})`,
|
|
9
|
+
imBrowser: (url) => `Im Browser: ${url}/kurs`,
|
|
10
|
+
};
|
|
11
|
+
const en = {
|
|
12
|
+
beatFertig: (nummer) => `Part ${nummer} ✓`,
|
|
13
|
+
beatTeil: (nummer, erledigt, gesamt) => `Part ${nummer} — ${erledigt} of ${gesamt}`,
|
|
14
|
+
uebersicht: (beats) => `Course: ${beats}`,
|
|
15
|
+
alleErledigt: (anzahl) => `Course: complete ✓ — all ${anzahl} steps done.`,
|
|
16
|
+
naechster: (text, claude) => `Next: ${text} (${claude ? "Claude sets it" : "you tick it off"})`,
|
|
17
|
+
nochOffen: "Still open:",
|
|
18
|
+
offenZeile: (beat, text, claude) => ` ○ Part ${beat}: ${text} (${claude ? "Claude sets it" : "you tick it off"})`,
|
|
19
|
+
imBrowser: (url) => `In the browser: ${url}/kurs`,
|
|
20
|
+
};
|
|
21
|
+
export const KURS_TEXTE = { de, en };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kimal3",
|
|
3
|
-
"version": "0.4.0
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Trag deine KI-Projekte dort ein, wo sie entstehen: im Terminal. · Log your AI projects where they happen: in the terminal.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"dist",
|
|
11
11
|
"skill",
|
|
12
12
|
"claude-plugins",
|
|
13
|
+
"coach",
|
|
13
14
|
"README.md"
|
|
14
15
|
],
|
|
15
16
|
"engines": {
|
package/skill/SKILL.md
CHANGED
|
@@ -24,7 +24,7 @@ den du erkennst.
|
|
|
24
24
|
| `/k3` | Wo er steht — und alle kimal3-Befehle auf einen Blick |
|
|
25
25
|
| `/k3start` | Sitzung starten: wo das Projekt steht und was als Nächstes dran ist |
|
|
26
26
|
| `/k3feierabend` | Sitzung sauber beenden: Stand sichern, aufräumen, zusammenfassen |
|
|
27
|
-
| `/k3kurs` | Zurück in den Mini-Kurs — da weiter, wo er aufgehört hat |
|
|
27
|
+
| `/k3kurs` | Zurück in den Mini-Kurs — holt den Stand mit `kimal3 kurs` und macht da weiter, wo er aufgehört hat |
|
|
28
28
|
| `/k3projekt` | Ein fertiges Projekt ins Erfolgsprofil eintragen |
|
|
29
29
|
| `/k3liste` | Seine eingetragenen Projekte zeigen |
|
|
30
30
|
| `/k3analyse` | Firmendaten holen und seine Frage dazu beantworten |
|
|
@@ -158,8 +158,7 @@ gemeinsam ausfüllen — es sind vier verschiedene. Such nach eckigen Klammern,
|
|
|
158
158
|
zu folgen: Eine abgetippte Liste veraltet in dem Moment, in dem die Vorlage wächst. Frag nach,
|
|
159
159
|
statt zu raten.
|
|
160
160
|
|
|
161
|
-
⚠️ `[FIRMA]` findest du meist schon ausgefüllt — den Namen setzt der Server beim Ausliefern ein.
|
|
162
|
-
`[DATUM]` ebenso. Was übrig bleibt, sind die Angaben über den **Menschen** vor dir.
|
|
161
|
+
⚠️ `[FIRMA]` findest du meist schon ausgefüllt — den Namen setzt der Server beim Ausliefern ein. Was übrig bleibt, sind die Angaben über den **Menschen** vor dir.
|
|
163
162
|
|
|
164
163
|
🔴 **Nur in der Werkbank — nirgends sonst.** Die oberste `CLAUDE.md` und alles in `kontext/` (in einer englischen Firma `context/`)
|
|
165
164
|
gehören der **Firma**, nicht dem Menschen vor dir. Den Firmennamen setzt der Server beim
|
|
@@ -360,6 +359,11 @@ mitbestimmungspflichtig. Das entscheidet die Firma, nicht dieses Werkzeug.
|
|
|
360
359
|
- „Was würdest du als Geschäftsführung als Nächstes automatisieren, gemessen an dem, was bisher
|
|
361
360
|
funktioniert hat — und was davon lässt sich auf andere Abteilungen übertragen?"
|
|
362
361
|
|
|
362
|
+
## Kursstand lesen (`kimal3 kurs`)
|
|
363
|
+
Zeigt, wo der Mensch im Mini-Kurs steht: eine Zeile je Beat, `Als Nächstes:` mit dem nächsten Schritt und dahinter, wer
|
|
364
|
+
ihn abhakt — „(du hakst ab)" oder „(setzt Claude)". Rückgabewert `2` heißt nicht angemeldet, `3` nicht erreichbar —
|
|
365
|
+
dann **keinen Kurs aus dem Gedächtnis erzählen**. Der Slash-Befehl `/k3kurs` führt dadurch.
|
|
366
|
+
|
|
363
367
|
## Rückgabewerte
|
|
364
368
|
`0` erledigt · `1` **Wiederholen hilft nicht — LIES DIE MELDUNG** · `2` Anmeldung fehlt ·
|
|
365
369
|
`3` vorübergehende Störung, einmal wiederholen · `4` angemeldet, aber kein Pro-Zugang —
|
|
@@ -24,10 +24,9 @@ Die Status-Datei (`WEITER-HIER.md` oder `ROADMAP.md`) ist der Zettel für den n
|
|
|
24
24
|
taugt nur, solange man sie in einem Atemzug lesen kann. **Jeder Feierabend schreibt etwas dazu —
|
|
25
25
|
also muss auch jeder Feierabend etwas wegräumen**, sonst wächst sie, bis niemand sie mehr liest.
|
|
26
26
|
|
|
27
|
-
**
|
|
27
|
+
**Wo der Statuszettel liegt und wie er heißt.** Die Projektregel gilt **nur innerhalb eines Arbeitsplatzes**: Liegt ein Ordner `projekte/` oder `projects/` direkt in einem Ordner `werkbank-…` oder `workbench-…` (beide Schreibweisen kommen vor, auch gemischt) und steht die Sitzung in oder unter einem Ordner darin, ist dieser **Projektordner** der Ort. Name dort: unter `projekte/` `WEITER-HIER.md`, unter `projects/` `NEXT-STEPS.md`. **Überall sonst** (Starter-Paket, eigene Repos, auch ein Ordner `~/projects/mein-repo`) bleibt es wie bisher: Der Zettel liegt im Startordner, liegt einer da, nimm ihn; muss einer neu entstehen, heißt er `WEITER-HIER.md` — oder `NEXT-STEPS.md`, wenn der Ordner englisch angelegt wurde. Liegen beide da, frag, welcher gilt, und schreib in keinen, bevor die Antwort da ist. **Welcher gilt (im Arbeitsplatz):** Hat das Projekt einen, gilt der des Projekts. Sonst gilt ein vorhandener Werkbank-Zettel (`werkbank-…/WEITER-HIER.md` oder `workbench-…/NEXT-STEPS.md` aus der alten Vorlage) — den liest und pflegst du weiter. Gibt es keinen von beiden, entsteht er **im Projekt**. **Leg nie einen neuen Zettel in der Werkbank an.**
|
|
28
28
|
|
|
29
|
-
Gibt es keine Status-Datei und die Arbeit wächst über eine Sitzung hinaus
|
|
30
|
-
dann weiter mit Schritt 3.
|
|
29
|
+
**Im Arbeitsplatz** schreibst du in den Zettel des Projekts, an dem heute gearbeitet wurde — fehlt er und liegt auch kein Werkbank-Zettel, leg ihn im Projekt an. **Nach einer reinen Profil-Sitzung** („Wer hier arbeitet“ ausgefüllt, noch kein Projekt) schreibst du **keinen** Zettel, sondern sagst, dass es beim nächsten Mal mit „Erste Sitzung“ in der Werkbank-`CLAUDE.md` weitergeht — dann weiter mit Schritt 3. **Außerhalb eines Arbeitsplatzes** gilt wie bisher: Gibt es keine Status-Datei und die Arbeit wächst über eine Sitzung hinaus, schlag eine vor, dann weiter mit Schritt 3.
|
|
31
30
|
|
|
32
31
|
1. **Nachziehen:** „Wo wir stehen" und „nächster Schritt" auf das setzen, was heute passiert ist.
|
|
33
32
|
2. **Wegräumen, was nicht mehr gilt.** Ins Archiv wandert:
|