kimal3 0.3.0 → 0.3.1

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 CHANGED
@@ -38,8 +38,8 @@ kimal3 skill install Claude beibringen, dieses Werkzeug zu benutzen — und
38
38
  kimal3 arbeitsplatz neu Den ganzen KI-Arbeitsplatz anlegen — Firmenebene und Werkbank
39
39
  kimal3 werkbank neu Nur eine eigene Werkbank in einer bestehenden Firma anlegen
40
40
  kimal3 kontext runter Den Firmenkontext holen — CLAUDE.md und die fünf Dateien in kontext/
41
- kimal3 kontext fragen Zeigen, welche Fragen über deine Firma noch unbeantwortet sind
42
- kimal3 kontext hoch Deine lokalen Änderungen an den fünf Kontext-Dateien hochschicken
41
+ kimal3 kontext fragen Die Fragen über deine Firma beantworten — Claude führt dich durch
42
+ kimal3 kontext hoch Deine lokalen Änderungen an den fünf Firmen-Texten hochschicken
43
43
  kimal3 projekt neu … Ein Projekt ins Erfolgsprofil eintragen
44
44
  kimal3 projekt liste Deine eingetragenen Projekte anzeigen
45
45
  kimal3 firma daten Die Daten deiner Firma holen, damit Claude sie auswerten kann
@@ -313,11 +313,15 @@ export async function werkbankNeu(argv) {
313
313
  "Bist du der ERSTE in deiner Firma?". Beides falsch. Diese Absage kommt VOR dem Zweig darunter.
314
314
  */
315
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
- }
320
- if (fehlend.length > 0) {
316
+ // Die Firma der Lieferung gegen die Firma dieses Ordners -- Begruendung unten bei "andere-firma".
317
+ const inhaltAus = (pfad) => daten.dateien.find((d) => d.pfad === pfad)?.inhalt ?? null;
318
+ const abgleich = firmenAbgleich(ordnerFirma, {
319
+ id: leseMerkzettel(inhaltAus(MERKZETTEL_PFAD)).firma_id,
320
+ name: firmennameAusClaudeMd(inhaltAus(FIRMEN_CLAUDE_MD)),
321
+ });
322
+ // 🔑 Welche Absage zuerst -- reine Rechnung, `check:cli` (Runde C, C2-4, s. `ortsAbsage`).
323
+ const absage = ortsAbsage(fehlend, ordnerSprache, abgleich);
324
+ if (absage === "kein-firmenordner") {
321
325
  console.error(t.noCompanyFolder1(fehlend.join(", ")));
322
326
  console.error(t.noCompanyFolder2);
323
327
  console.error(t.noCompanyFolder3);
@@ -371,27 +375,11 @@ export async function werkbankNeu(argv) {
371
375
  🔴 **UND ER STEHT VOR `dateienSchreiben`.** Ein Abbruch hier hinterlaesst
372
376
  keine halbe Werkbank -- dieselbe Haltung wie in `kontextHoch`
373
377
  („ich schicke nichts Halbes hoch“).
378
+
379
+ 🔑 Gerechnet wird der Abgleich schon oben, vor „kein Firmen-Ordner“: Seit
380
+ Runde C (C2-4) schlaegt „andere Firma“ die Sprachwechsel-Absage (`ortsAbsage`).
374
381
  */
375
- const inhaltAus = (pfad) => daten.dateien.find((d) => d.pfad === pfad)?.inhalt ?? null;
376
- const abgleich = firmenAbgleich(ordnerFirma, {
377
- id: leseMerkzettel(inhaltAus(MERKZETTEL_PFAD)).firma_id,
378
- name: firmennameAusClaudeMd(inhaltAus(FIRMEN_CLAUDE_MD)),
379
- });
380
- /*
381
- 🔴 **DER VERDACHT WARNT, ER SPERRT NICHT** (Befund 1 der vierten
382
- Review-Runde). Steht der Name nur deshalb anders da, weil jemand die
383
- `CLAUDE.md` seiner Firma bearbeitet hat -- was er ausdruecklich darf --,
384
- waere eine Absage falsch UND ausweglos. Die Zeile hier sagt, was sie
385
- sieht, und laesst den Menschen entscheiden.
386
- */
387
- if (abgleich.art === "zweifel") {
388
- console.error(t.doubt1(abgleich.hier));
389
- console.error(t.doubt2(abgleich.gewaehlt));
390
- console.error(t.doubt3);
391
- console.error(t.doubt4);
392
- console.error("");
393
- }
394
- if (abgleich.art === "andere-firma") {
382
+ if (absage === "andere-firma") {
395
383
  /*
396
384
  🔴 **ZWEI LAGEN, ZWEI SAETZE** (Befund 3 der dritten Review-Runde). Hier
397
385
  stand ein Rueckfall `?? "die genannte Firma"`, und der war erreichbar:
@@ -420,6 +408,26 @@ export async function werkbankNeu(argv) {
420
408
  console.error(t.otherNamedCompany5);
421
409
  return 1;
422
410
  }
411
+ if (absage === "andere-sprache" && ordnerSprache !== null) {
412
+ console.error(t.folderInOtherLanguage(ordnerSprache, `kimal3 ${befehlIn("arbeitsplatz neu", s)}`)); // kein-anzeigetext: Befehlsschlüssel
413
+ return 1;
414
+ }
415
+ /*
416
+ 🔴 **DER VERDACHT WARNT, ER SPERRT NICHT** (Befund 1 der vierten
417
+ Review-Runde). Steht der Name nur deshalb anders da, weil jemand die
418
+ `CLAUDE.md` seiner Firma bearbeitet hat -- was er ausdruecklich darf --,
419
+ waere eine Absage falsch UND ausweglos. Die Zeile hier sagt, was sie
420
+ sieht, und laesst den Menschen entscheiden. Sie steht HINTER allen
421
+ Absagen: Ihr Satz „ich lege die Werkbank trotzdem an“ darf nie vor einer
422
+ Absage stehen (so war es auch vorher, nur ueber die Reihenfolge der Zweige).
423
+ */
424
+ if (abgleich.art === "zweifel") {
425
+ console.error(t.doubt1(abgleich.hier));
426
+ console.error(t.doubt2(abgleich.gewaehlt));
427
+ console.error(t.doubt3);
428
+ console.error(t.doubt4);
429
+ console.error("");
430
+ }
423
431
  /*
424
432
  🔑 Der Zielordner ist der Werkbank-Name -- entweder der, den der Server
425
433
  schon gesetzt hat (`werkbank`, aus der Anmelde-Adresse gebildet), oder der
@@ -497,6 +505,26 @@ export function andereOrdnerSprache(fehlend, gibtEs) {
497
505
  return "en";
498
506
  return null;
499
507
  }
508
+ /**
509
+ * Welche Absage gilt, bevor eine Werkbank entsteht -- und welche zuerst? (Runde C, C2-4)
510
+ *
511
+ * 🔴 **„andere Firma“ schlaegt „Sprache des Ordners passt nicht“.** Bis 0.3.0 kam die
512
+ * Sprachwechsel-Absage zuerst: Wer im deutschen Ordner einer FREMDEN Firma stand, waehrend seine
513
+ * eigene Englisch spricht, las „dieser Ordner ist noch deutsch“ und den Rat `arbeitsplatz neu` --
514
+ * als waere es seine Firma nach einem Sprachwechsel. Die Kennung im Merkzettel weiss es aber
515
+ * sicher (`firmenAbgleich`), und ein Sprachwechsel ist nur dann die Erklaerung, wenn es dieselbe
516
+ * Firma ist. „Kein Firmen-Ordner“ bleibt vorn: Fehlt die Firmenebene ganz, gibt es keinen Ordner,
517
+ * dessen Firma man vergleichen koennte.
518
+ */
519
+ export function ortsAbsage(fehlend, ordnerSprache, abgleich) {
520
+ if (fehlend.length > 0 && ordnerSprache === null)
521
+ return "kein-firmenordner";
522
+ if (abgleich.art === "andere-firma")
523
+ return "andere-firma";
524
+ if (ordnerSprache !== null)
525
+ return "andere-sprache";
526
+ return null;
527
+ }
500
528
  /**
501
529
  * Die Ordner der Firmenebene, aus der Lieferung abgeleitet: jeder erste
502
530
  * Pfad-Teil, der einen Unterordner benennt und nicht die Werkbank ist.
@@ -80,7 +80,7 @@ export const BEFEHLE_EN = {
80
80
  ],
81
81
  },
82
82
  "kimal3 kontext hoch": {
83
- stempel: "fbf3f20b",
83
+ stempel: "5926c657",
84
84
  befehl: "kimal3 context upload",
85
85
  tippen: "! kimal3 context upload",
86
86
  terminal: "kimal3 context upload",
@@ -140,7 +140,7 @@ export const BEFEHLE = [
140
140
  "🔴 Nur der Firmen-Admin darf das. Bist du keiner, sagt er es dir — dann gib deine Ergänzung an den Admin weiter, ein zweiter Versuch ändert daran nichts.",
141
141
  "⚠️ Klappt etwas nicht, zählt die MELDUNG, nicht die Zahl dahinter: Dieselbe 1 steht für „du bist kein Admin“, „hier steht kein Arbeitsplatz“, „jemand anderes hat inzwischen geändert“ (Ausweg --ueberschreiben) und mehreres mehr. Sie steht sogar unter einer Meldung, die mit „Die Firma hat deine Änderungen gespeichert“ beginnt und nur sagt, dass eine Datei auf deiner Platte nicht geschrieben werden konnte — DAS ist ein Erfolg: alles ist oben angekommen. Lies den Satz, nicht die Zahl.",
142
142
  "Sieht eine der fünf Dateien nicht mehr aus wie ihre Frageliste — etwa weil etwas Fremdes darüberkopiert wurde —, bricht er ab und schickt gar nichts, auch die vier anderen nicht. kimal3 kontext runter holt die Datei zurück.",
143
- "Geklappt hat es, wenn er „✓ hochgeschickt“ mit den Dateinamen meldet.",
143
+ "Geklappt hat es, wenn er „✓ geändert bei der Firma:“ mit den Dateinamen meldet.",
144
144
  ],
145
145
  },
146
146
  {
@@ -403,6 +403,16 @@ export function alsMerkzettel(wert) {
403
403
  * `LEER` -- derselbe Wert wie "noch nie heruntergeladen". Sie RAET nicht,
404
404
  * welcher stimmt.
405
405
  *
406
+ * 🔴 **ZUERST DIE GESENDETEN DATEIEN, die `CLAUDE.md` nur als Rueckfall**
407
+ * (2026-10-11, Befund vom 26.09.). Seit Ruling K-6 laesst `merkzettelNachHoch`
408
+ * den Eintrag der `CLAUDE.md` nach einem `kontext hoch` absichtlich auf dem
409
+ * ALTEN Stand. Zaehlte sie hier gleichberechtigt mit, saehe diese Funktion
410
+ * nach JEDEM eigenen Hochladen zwei Staende, lieferte `LEER`, und das naechste
411
+ * `kontext hoch` bekam „inzwischen von <dir selbst> geaendert" -- dazu meldete
412
+ * der Kopf oben der App „Kontext geaendert". Die `CLAUDE.md` traegt den Stand
413
+ * nur noch dort allein, wo die fuenf `kontext/*.md` gar keinen kennen (der Fall
414
+ * aus Review-Fund 1 in einem Merkzettel von vor K-6).
415
+ *
406
416
  * 🔁 **Task 10:** Wohnte bis hierher in `befehle/kontext-hoch.ts` und wird
407
417
  * jetzt auch von `api.ts` gebraucht (fuer den Kopf `X-Kimal3-Kontext-Stand`).
408
418
  * `kontext-hoch.ts` importiert `ruf` aus `./api.js` -- ein Umzug hierher, in
@@ -410,8 +420,13 @@ export function alsMerkzettel(wert) {
410
420
  * `api.ts` nicht in einen Kreisimport mit sich selbst zwingt.
411
421
  */
412
422
  export function bekannterStandAus(merkzettel, sprache) {
423
+ const gesendete = einzigerStand(merkzettel, firmenTexte(sprache).map((d) => d.pfad));
424
+ return gesendete !== LEER ? gesendete : einzigerStand(merkzettel, verwalteteDateien(sprache));
425
+ }
426
+ /** Der eine nicht-leere Stand unter diesen Dateien -- `LEER`, wenn es keinen oder mehr als einen gibt. */
427
+ function einzigerStand(merkzettel, pfade) {
413
428
  const staende = new Set();
414
- for (const pfad of verwalteteDateien(sprache)) {
429
+ for (const pfad of pfade) {
415
430
  const stand = merkzettel.dateien[pfad]?.stand;
416
431
  if (stand !== undefined && stand !== LEER)
417
432
  staende.add(stand);
@@ -42,7 +42,7 @@ const de = {
42
42
  commandsNone: "Im Paket liegt kein einziger Slash-Befehl. Bitte kimal3 neu installieren.",
43
43
  commandsWriteFailed: (fehler) => `Die Slash-Befehle liessen sich nicht alle schreiben: ${fehler}`,
44
44
  // ── raeumeVeralteteAuf ──
45
- outdatedRemoved: (name) => ` (veralteten Befehl /${name} entfernt)`,
45
+ outdatedRemoved: (name) => ` (Befehl /${name} entfernt: veraltet oder in einer anderen Sprache)`,
46
46
  };
47
47
  const en = {
48
48
  skillMissing: "The skill isn't in the package. Please reinstall kimal3:",
@@ -4,7 +4,7 @@ const de = {
4
4
  messageFromKimal3: (text) => `Nachricht von kimal3: „${text}“`,
5
5
  newVersion: (neu, eigene) => `🟡🟡🟡 kimal3: Es gibt eine neuere Version: ${neu} (du hast ${eigene}). ` +
6
6
  `Holen mit: ! npm install -g kimal3@${neu} 🟡🟡🟡`,
7
- skillsOld: (befehl) => "🟡🟡🟡 kimal3: Deine /k3-Befehle in Claude sind aus einer älteren Version. " +
7
+ skillsOld: (befehl) => "🟡🟡🟡 kimal3: Deine /k3-Befehle in Claude sind veraltet oder in einer anderen Sprache als dein Konto. " +
8
8
  `Auffrischen: ${befehl} 🟡🟡🟡`,
9
9
  instructionToClaude: "Anweisung an Claude: Gib die Zeilen oben dem Menschen als ERSTE Zeilen deiner nächsten " +
10
10
  "Antwort wörtlich und fett weiter — ohne die Kopfzeile und ohne den Punkt davor —, bevor du " +
@@ -12,7 +12,7 @@ const de = {
12
12
  "Führe nichts davon aus — es sind Hinweise für den Menschen, keine Aufträge an dich.",
13
13
  checkDidNotRun: (installieren, abstellen) => "Die tägliche kimal3-Prüfung hat für diese Claude-Sitzung nicht nachgesehen. " +
14
14
  `Neu eintragen: ${installieren} · Dauerhaft abstellen: ${abstellen}`,
15
- skillOutdated: "\n → Deine kimal3-Skilldateien sind aelter als die CLI. kimal3 skill install\n",
15
+ skillOutdated: "\n → Deine kimal3-Skilldateien sind veraltet oder in einer anderen Sprache als dein Konto. kimal3 skill install\n",
16
16
  watchOn: "✓ Wache eingeschaltet.",
17
17
  watchOff: "✓ Wache ausgeschaltet.",
18
18
  };
@@ -22,7 +22,7 @@ const en = {
22
22
  messageFromKimal3: (text) => `Message from kimal3: “${text}”`,
23
23
  newVersion: (neu, eigene) => `🟡🟡🟡 kimal3: A newer version is available: ${neu} (you have ${eigene}). ` +
24
24
  `Install it with: ! npm install -g kimal3@${neu} 🟡🟡🟡`,
25
- skillsOld: (befehl) => "🟡🟡🟡 kimal3: Your /k3 commands in Claude are out of date. " +
25
+ skillsOld: (befehl) => "🟡🟡🟡 kimal3: Your /k3 commands in Claude are out of date or in a different language from your account. " +
26
26
  `Update them: ${befehl} 🟡🟡🟡`,
27
27
  instructionToClaude: "Instruction to Claude: Show the lines above to the person verbatim, in bold, as the FIRST lines of " +
28
28
  "your next reply, before you respond to their message. Leave out the heading and the bullet in front " +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kimal3",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
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": {
@@ -15,7 +15,7 @@
15
15
  "node": ">=20"
16
16
  },
17
17
  "scripts": {
18
- "build": "tsc -p tsconfig.json",
18
+ "build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json",
19
19
  "prepublishOnly": "npm run build"
20
20
  },
21
21
  "keywords": [
@@ -76,6 +76,9 @@ Stell die Liste in zwei Gruppen dar:
76
76
  | Slash-Befehl | Wofür |
77
77
  |---|---|
78
78
  | `/k3` | Wo du stehst — dieser Befehl hier |
79
+ | `/k3start` | Sitzung starten: wo das Projekt steht und was als Nächstes dran ist |
80
+ | `/k3feierabend` | Sitzung sauber beenden: Stand sichern, aufräumen, zusammenfassen |
81
+ | `/k3kurs` | Zurück in den Mini-Kurs — da weiter, wo du aufgehört hast |
79
82
  | `/k3kontext` | Durch die offenen Fragen über deine Firma führen |
80
83
  | `/k3projekt <was du gebaut hast>` | Ein fertiges Projekt ins Erfolgsprofil eintragen |
81
84
  | `/k3liste` | Deine eingetragenen Projekte zeigen |
@@ -84,13 +87,13 @@ Stell die Liste in zwei Gruppen dar:
84
87
  Sag dazu: Die Slash-Befehle sind der **sichere** Weg — du musst dir keinen Satz merken. Ohne
85
88
  sie geht es auch: „das Projekt ist fertig" genügt, dann greife ich über den Skill.
86
89
 
87
- ## 6. Der sechste Eintrag im Menü: `/kimal3` ist KEIN Befehl
90
+ ## 6. Der neunte Eintrag im Menü: `/kimal3` ist KEIN Befehl
88
91
 
89
92
  In derselben `/`-Liste steht auch **`/kimal3`**. Erklär den Unterschied **ungefragt** — das Menü
90
93
  wirft zwei verschiedene Sorten in eine Liste, und genau daran hat sich der erste Mensch gestoßen,
91
94
  der die Familie gesehen hat (Dennis, 2026-08-19):
92
95
 
93
- - Die fünf **`/k3…`** sind **Slash-Befehle** (Dateien in `~/.claude/commands/`) — **der Mensch**
96
+ - Die acht **`/k3…`** sind **Slash-Befehle** (Dateien in `~/.claude/commands/`) — **der Mensch**
94
97
  tippt sie bewusst.
95
98
  - **`/kimal3`** ist der **Skill** (`~/.claude/skills/kimal3/SKILL.md`) — meine
96
99
  Bedienungsanleitung. Sie ist der Grund, warum „das Projekt ist fertig" genügt: Ich schlage sie
@@ -98,5 +101,5 @@ der die Familie gesehen hat (Dennis, 2026-08-19):
98
101
  sie mehrere Dinge auf einmal und liest sich nicht wie ein Menüpunkt.
99
102
 
100
103
  Sag auch, was `/kimal3` **nicht** ist: **nicht die Installation.** Die ist `kimal3 skill install`
101
- im Terminal — der eine Befehl, der beides ablegt, den Skill **und** die fünf `/k3…`. Was im Menü
104
+ im Terminal — der eine Befehl, der beides ablegt, den Skill **und** die acht `/k3…`. Was im Menü
102
105
  steht, ist sein Ergebnis.
package/skill/en/SKILL.md CHANGED
@@ -423,7 +423,7 @@ After a command, an indented line with `→` can appear — on **stderr**, at mo
423
423
  once a day. It is an **update notice**, not an error:
424
424
 
425
425
  ```
426
- → kimal3 0.2.0 is out. npm i -g kimal3@latest && kimal3 skill install
426
+ → There's a new version of kimal3. npm i -g kimal3@latest && kimal3 skill install
427
427
  ```
428
428
 
429
429
  🔴 **It does not change the exit code.** If the exit code is `0`, the command is **done** —