kimal3 0.1.0 → 0.1.2
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 +79 -74
- package/dist/anmeldung.js +1 -1
- package/dist/api.js +6 -9
- package/dist/argumente.js +35 -7
- package/dist/befehle/firma-daten.js +113 -0
- package/dist/befehle/projekt-liste.js +90 -9
- package/dist/befehle/projekt-neu.js +8 -2
- package/dist/befehle/skill-install.js +271 -6
- package/dist/befehle-katalog.js +112 -0
- package/dist/fehler.js +66 -0
- package/dist/firmen-liste.js +52 -0
- package/dist/kimal3.js +52 -13
- package/dist/projekt-zeilen.js +253 -0
- package/package.json +27 -13
- package/skill/SKILL.md +125 -39
- package/skill/commands/k3.md +44 -0
- package/skill/commands/k3firma.md +57 -0
- package/skill/commands/k3liste.md +26 -0
- package/skill/commands/k3projekt.md +44 -0
package/README.md
CHANGED
|
@@ -1,74 +1,79 @@
|
|
|
1
|
-
# kimal3
|
|
2
|
-
|
|
3
|
-
**Trag deine KI-Projekte dort ein, wo sie entstehen: im Terminal.**
|
|
4
|
-
|
|
5
|
-
Wer mit Claude Code arbeitet, baut echte Dinge — und dokumentiert sie hinterher nicht,
|
|
6
|
-
weil das ein zweiter Arbeitsschritt in einem anderen Fenster wäre. `kimal3` schließt
|
|
7
|
-
diese Lücke: Am Ende einer Sitzung trägt Claude das fertige Projekt selbst in dein
|
|
8
|
-
KImal3-Erfolgsprofil ein. Du gibst es dort nur noch frei.
|
|
9
|
-
|
|
10
|
-
> **Voraussetzung: ein KImal3-Konto mit Pro.**
|
|
11
|
-
> Ohne Pro meldet sich dieses Werkzeug ab, ohne etwas zu tun.
|
|
12
|
-
> Was Pro enthält und wie du es bekommst: **https://kimal3-app.vercel.app/pro**
|
|
13
|
-
|
|
14
|
-
## Loslegen
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
kimal3
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
##
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
1
|
+
# kimal3
|
|
2
|
+
|
|
3
|
+
**Trag deine KI-Projekte dort ein, wo sie entstehen: im Terminal.**
|
|
4
|
+
|
|
5
|
+
Wer mit Claude Code arbeitet, baut echte Dinge — und dokumentiert sie hinterher nicht,
|
|
6
|
+
weil das ein zweiter Arbeitsschritt in einem anderen Fenster wäre. `kimal3` schließt
|
|
7
|
+
diese Lücke: Am Ende einer Sitzung trägt Claude das fertige Projekt selbst in dein
|
|
8
|
+
KImal3-Erfolgsprofil ein. Du gibst es dort nur noch frei.
|
|
9
|
+
|
|
10
|
+
> **Voraussetzung: ein KImal3-Konto mit Pro.**
|
|
11
|
+
> Ohne Pro meldet sich dieses Werkzeug ab, ohne etwas zu tun.
|
|
12
|
+
> Was Pro enthält und wie du es bekommst: **https://kimal3-app.vercel.app/pro**
|
|
13
|
+
|
|
14
|
+
## Loslegen
|
|
15
|
+
|
|
16
|
+
Einmal pro Rechner:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install -g kimal3 # das Werkzeug installieren (setzt Node.js voraus)
|
|
20
|
+
kimal3 login # diesen Rechner mit deinem Konto verbinden
|
|
21
|
+
kimal3 skill install # Claude beibringen, das Werkzeug zu benutzen
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
> **In Claude Code?** Dann lass es einrichten, statt es zu tippen — der Satz zum Kopieren steht
|
|
25
|
+
> auf **https://kimal3-app.vercel.app/pro**. Nur `kimal3 login` tippst du selbst (dort mit `!`
|
|
26
|
+
> davor), weil die Bestätigung im Browser einen Menschen braucht.
|
|
27
|
+
|
|
28
|
+
`login` zeigt dir eine Adresse und einen achtstelligen Code. Die Adresse rufst du selbst
|
|
29
|
+
auf und bestätigst den Code dort in deinem eingeloggten Konto — so wie bei `gh auth login`.
|
|
30
|
+
**Es wird kein Passwort ins Terminal getippt.**
|
|
31
|
+
|
|
32
|
+
## Befehle
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
kimal3 Zeigt, ob dieser Rechner angemeldet ist
|
|
36
|
+
kimal3 login Diesen Rechner mit deinem Konto verbinden
|
|
37
|
+
kimal3 logout Verbindung wieder aufheben
|
|
38
|
+
kimal3 projekt neu … Ein Projekt ins Erfolgsprofil eintragen
|
|
39
|
+
kimal3 projekt liste Deine eingetragenen Projekte anzeigen
|
|
40
|
+
kimal3 skill install Claude beibringen, dieses Werkzeug zu benutzen
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Mehr zu einem Befehl: `kimal3 projekt neu --help`
|
|
44
|
+
|
|
45
|
+
## Was eingetragen wird
|
|
46
|
+
|
|
47
|
+
Nur, was du eingibst — Titel, Beschreibung, optional ein Link. **Dein Code wird nicht
|
|
48
|
+
gelesen, nicht hochgeladen und nicht analysiert.** Das Werkzeug schreibt ausschließlich
|
|
49
|
+
über die KImal3-App und hat keinen eigenen Datenbankzugang.
|
|
50
|
+
|
|
51
|
+
Eingetragene Projekte sind zunächst **nicht öffentlich**. Sie erscheinen in deinem
|
|
52
|
+
Erfolgsprofil, und du entscheidest dort, was sichtbar wird.
|
|
53
|
+
|
|
54
|
+
## Rückgabewerte
|
|
55
|
+
|
|
56
|
+
Für Skripte und für Claude selbst:
|
|
57
|
+
|
|
58
|
+
| Wert | Bedeutung | Hilft |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| `0` | hat geklappt | — |
|
|
61
|
+
| `1` | Eingabe unvollständig oder nichts gefunden | Eingabe prüfen |
|
|
62
|
+
| `2` | nicht angemeldet | `kimal3 login` |
|
|
63
|
+
| `3` | gerade nicht erreichbar | später noch einmal |
|
|
64
|
+
| `4` | kein Pro-Konto | erneutes Versuchen hilft **nicht** |
|
|
65
|
+
|
|
66
|
+
Der Unterschied zwischen `3` und `4` ist Absicht: Bei `3` lohnt ein zweiter Versuch,
|
|
67
|
+
bei `4` nie.
|
|
68
|
+
|
|
69
|
+
## Voraussetzungen
|
|
70
|
+
|
|
71
|
+
Node.js 20 oder neuer. Sonst nichts — das Werkzeug bringt **keine fremden Bibliotheken**
|
|
72
|
+
mit.
|
|
73
|
+
|
|
74
|
+
## Lizenz
|
|
75
|
+
|
|
76
|
+
Proprietär. Die Nutzung ist Inhabern eines gültigen KImal3-Pro-Kontos gestattet;
|
|
77
|
+
Weitergabe, Veränderung und Weiterverwendung des Codes sind nicht erlaubt.
|
|
78
|
+
|
|
79
|
+
© KImal3 · https://kimal3.de
|
package/dist/anmeldung.js
CHANGED
|
@@ -3,7 +3,7 @@ import { homedir } from "node:os";
|
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
/**
|
|
5
5
|
* Wo die App wohnt. Ueberschreibbar fuers lokale Entwickeln:
|
|
6
|
-
* KIMAL3_URL=http://localhost:3000
|
|
6
|
+
* KIMAL3_URL=http://localhost:3000 kimal3 projekt liste
|
|
7
7
|
*/
|
|
8
8
|
export const BASIS_URL = process.env.KIMAL3_URL ?? "https://kimal3-app.vercel.app";
|
|
9
9
|
const ORDNER = join(homedir(), ".kimal3");
|
package/dist/api.js
CHANGED
|
@@ -40,12 +40,9 @@ export function feld(koerper, name) {
|
|
|
40
40
|
}
|
|
41
41
|
return null;
|
|
42
42
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
43
|
+
// `textListe` stand hier bis zum 2026-08-18 und zog EIN Textfeld je Eintrag --
|
|
44
|
+
// genau das war die Grenze, an der `projekt liste` haengen blieb (Befund L-4).
|
|
45
|
+
// Die Liste zeigt jetzt mehrere Felder je Projekt und liest ihre Antwort in
|
|
46
|
+
// `projekt-zeilen.ts`, wo `check:cli` sie messen kann. Eine Funktion, die
|
|
47
|
+
// niemand mehr ruft, wird nicht aufgehoben: Sie waere beim naechsten Mal die
|
|
48
|
+
// naheliegende, aber zu enge Wahl.
|
package/dist/argumente.js
CHANGED
|
@@ -7,22 +7,50 @@
|
|
|
7
7
|
* Titel anzulegen.
|
|
8
8
|
*/
|
|
9
9
|
export function zerlege(argv, erlaubt) {
|
|
10
|
-
const befehl = [];
|
|
11
10
|
const optionen = {};
|
|
12
11
|
for (let i = 0; i < argv.length; i++) {
|
|
13
12
|
const teil = argv[i];
|
|
13
|
+
// ⚠️ **Jedes Wort ohne `--` ist hier ein Fehler** (B-4). `zerlege` bekommt
|
|
14
|
+
// vom Verteiler nur den Teil NACH dem Befehlsnamen -- dort gehoert nichts
|
|
15
|
+
// hin ausser Optionen. Frueher landeten solche Woerter in `werte.befehl`
|
|
16
|
+
// und wurden nie wieder angesehen.
|
|
14
17
|
if (!teil.startsWith("--")) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
continue;
|
|
18
|
+
return {
|
|
19
|
+
ok: false,
|
|
20
|
+
meldung: `Mit „${teil}" kann ich hier nichts anfangen. Erwartet werden nur Optionen wie „--name wert".`,
|
|
21
|
+
};
|
|
20
22
|
}
|
|
21
23
|
const gleich = teil.indexOf("=");
|
|
22
24
|
const name = gleich === -1 ? teil.slice(2) : teil.slice(2, gleich);
|
|
23
25
|
if (!erlaubt.includes(name)) {
|
|
24
26
|
return { ok: false, meldung: `Die Option „--${name}" kenne ich nicht.` };
|
|
25
27
|
}
|
|
28
|
+
// ⚠️ **Dieselbe Option zweimal ist ein FEHLER** (QA-Befund B-3, 2026-08-18).
|
|
29
|
+
//
|
|
30
|
+
// `optionen` ist ein `Record` -- die zweite Nennung ueberschrieb die erste
|
|
31
|
+
// stillschweigend. `kimal3 firma daten --firma "A" --firma "B"` lieferte
|
|
32
|
+
// die Daten von B, mit Rueckgabewert 0 und ohne jeden Hinweis. Wer die
|
|
33
|
+
// Antwort danach "fuer A" ueberschreibt, hat eine falsche Antwort auf eine
|
|
34
|
+
// richtige Frage.
|
|
35
|
+
//
|
|
36
|
+
// 🔑 Die Route ist gegen den Fall gewappnet (`getAll("firma").length > 1`,
|
|
37
|
+
// gebaut nach dem Absturz aus PR #14) -- nur bekam sie ihn ueber den
|
|
38
|
+
// CLI-Weg nie zu sehen: Hier wurde aus zwei Nennungen laengst eine.
|
|
39
|
+
// *Ein Schutz an der zweiten Tuer nuetzt nichts, wenn die erste das
|
|
40
|
+
// Problem schon weggeraeumt hat -- und man sieht ihm das beim Lesen nicht
|
|
41
|
+
// an.* Deshalb steht die Strenge HIER, wo sie alle Befehle auf einmal
|
|
42
|
+
// erreicht, und nicht in einem einzelnen Befehl.
|
|
43
|
+
//
|
|
44
|
+
// `Object.hasOwn` und nicht `name in optionen`: Letzteres findet auch
|
|
45
|
+
// geerbte Namen wie `constructor` und wuerde `--constructor` faelschlich
|
|
46
|
+
// als doppelt melden. Heute faengt `erlaubt` das ab -- aber diese Zeile
|
|
47
|
+
// soll auch dann noch stimmen, wenn jemand die Reihenfolge aendert.
|
|
48
|
+
if (Object.hasOwn(optionen, name)) {
|
|
49
|
+
return {
|
|
50
|
+
ok: false,
|
|
51
|
+
meldung: `Die Option „--${name}" steht zweimal da. Bitte nenne sie nur einmal.`,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
26
54
|
if (gleich !== -1) {
|
|
27
55
|
optionen[name] = teil.slice(gleich + 1);
|
|
28
56
|
continue;
|
|
@@ -35,5 +63,5 @@ export function zerlege(argv, erlaubt) {
|
|
|
35
63
|
optionen[name] = wert;
|
|
36
64
|
i++;
|
|
37
65
|
}
|
|
38
|
-
return { ok: true, werte: {
|
|
66
|
+
return { ok: true, werte: { optionen } };
|
|
39
67
|
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { zerlege } from "../argumente.js";
|
|
2
|
+
import { feld, ruf } from "../api.js";
|
|
3
|
+
import { schlussFehler } from "../fehler.js";
|
|
4
|
+
import { firmenZeilen } from "../firmen-liste.js";
|
|
5
|
+
import { BASIS_URL } from "../anmeldung.js";
|
|
6
|
+
const ERLAUBT = ["firma"];
|
|
7
|
+
/**
|
|
8
|
+
* Die Firmendaten holen — als JSON, unveraendert.
|
|
9
|
+
*
|
|
10
|
+
* 🔑 **Dieser Befehl INTERPRETIERT NICHTS. Er transportiert.** Die Auswertung
|
|
11
|
+
* macht Claude, gefuehrt vom Skill — das ist die KI-native Bauform und der
|
|
12
|
+
* Grund, warum es keine `--abteilung`- oder `--zeitraum`-Optionen gibt: Filtern
|
|
13
|
+
* kann Claude aus dem JSON selbst, und jede Option waere eine zweite Stelle fuer
|
|
14
|
+
* dieselbe Regel.
|
|
15
|
+
*
|
|
16
|
+
* ⚠️ Auf stdout geht das JSON und SONST NICHTS. Wer hier eine freundliche
|
|
17
|
+
* Ueberschrift dazudruckt, macht die Ausgabe als JSON unlesbar — alles fuer
|
|
18
|
+
* Menschen gehoert nach stderr (`console.error`).
|
|
19
|
+
*/
|
|
20
|
+
const HILFE = `
|
|
21
|
+
kimal3 firma daten [--firma "Name"]
|
|
22
|
+
|
|
23
|
+
Holt die Daten deiner Firma als JSON: Kennzahlen, Menschen, Projekte.
|
|
24
|
+
Die Auswertung macht Claude daraus selbst.
|
|
25
|
+
|
|
26
|
+
--firma "Name" Noetig, wenn du zu mehreren Firmen gehoerst.
|
|
27
|
+
Die Absage nennt dir die Namen als fertige Befehle.
|
|
28
|
+
`;
|
|
29
|
+
export async function firmaDaten(argv) {
|
|
30
|
+
// ⚠️ VOR `zerlege`, genau wie bei `projekt neu`: Ein Schalter ist keine
|
|
31
|
+
// Option-mit-Wert, `--help` scheiterte dort sonst mit "fehlt ihr Wert".
|
|
32
|
+
// Die Terminal-Hilfe wirbt mit "Mehr zu einem Befehl: … --help" -- ein
|
|
33
|
+
// Befehl, der darauf mit einem Fehler antwortet, macht die Werbung zur Luege.
|
|
34
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
35
|
+
console.log(HILFE);
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
const zerlegt = zerlege(argv, ERLAUBT);
|
|
39
|
+
if (!zerlegt.ok) {
|
|
40
|
+
console.error(zerlegt.meldung);
|
|
41
|
+
return 1;
|
|
42
|
+
}
|
|
43
|
+
// ⚠️ `!== undefined` und NICHT auf Wahrheitswert pruefen: `zerlege`
|
|
44
|
+
// unterscheidet ausdruecklich "nicht angegeben" (`undefined`) von
|
|
45
|
+
// "ausdruecklich leer" (`--firma=` -> `""`), und `check:cli` sichert genau
|
|
46
|
+
// das ab. Wer hier auf Wahrheit prueft, wirft beides zusammen: `--firma=`
|
|
47
|
+
// lieferte dann die Daten der einzigen Firma, als haette niemand gefragt.
|
|
48
|
+
const wunsch = zerlegt.werte.optionen.firma;
|
|
49
|
+
const pfad = wunsch !== undefined
|
|
50
|
+
? `/api/cli/firma?firma=${encodeURIComponent(wunsch)}`
|
|
51
|
+
: "/api/cli/firma";
|
|
52
|
+
const antwort = await ruf(pfad, { methode: "GET", mitAusweis: true });
|
|
53
|
+
if (antwort.status === 200) {
|
|
54
|
+
// 🔴 Ein `200` mit unlesbarem Rumpf ist KEIN Erfolg (Review-Befund Runde 1):
|
|
55
|
+
// `ruf` verschluckt Parse-Fehler zu `null`. Ein Zwischending im Netz --
|
|
56
|
+
// etwa ein WLAN-Anmeldeportal -- antwortet mit `200` und HTML. Ohne diese
|
|
57
|
+
// Wache druckte der Befehl das Wort `null` auf stdout und meldete 0.
|
|
58
|
+
// Und die 0 ist die Schnittstelle: Claude liest sie als "erledigt" und
|
|
59
|
+
// haelt `null` fuer die Daten der Firma.
|
|
60
|
+
if (antwort.koerper === null || typeof antwort.koerper !== "object") {
|
|
61
|
+
console.error("Die Antwort war nicht lesbar. Bitte gleich noch einmal.");
|
|
62
|
+
return 3;
|
|
63
|
+
}
|
|
64
|
+
console.log(JSON.stringify(antwort.koerper, null, 2));
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
const meldung = feld(antwort.koerper, "meldung") ?? "Das hat nicht geklappt.";
|
|
68
|
+
// 402 VOR 401: Beide heissen "kommst hier nicht rein", verlangen aber
|
|
69
|
+
// Gegenteiliges. Wer sie zusammenwirft, raet dem Menschen `kimal3 login` --
|
|
70
|
+
// und der meldet sich dann erfolgreich an, ohne dass es etwas aendert.
|
|
71
|
+
if (antwort.status === 402) {
|
|
72
|
+
console.error(meldung);
|
|
73
|
+
return 4;
|
|
74
|
+
}
|
|
75
|
+
if (antwort.status === 401) {
|
|
76
|
+
console.error(`${meldung} Bitte \`kimal3 login\` ausführen.`);
|
|
77
|
+
return 2;
|
|
78
|
+
}
|
|
79
|
+
if (antwort.status === 409) {
|
|
80
|
+
const grund = feld(antwort.koerper, "grund");
|
|
81
|
+
const koerper = antwort.koerper;
|
|
82
|
+
const namen = Array.isArray(koerper?.firmen)
|
|
83
|
+
? koerper.firmen.filter((x) => typeof x === "string")
|
|
84
|
+
: [];
|
|
85
|
+
console.error(meldung);
|
|
86
|
+
// Die Namen als FERTIGE Befehle ausgeben, nicht als blosse Liste: Der
|
|
87
|
+
// naechste Schritt ist dann Kopieren statt Abtippen -- und ein Firmenname
|
|
88
|
+
// mit Leerzeichen braucht Anfuehrungszeichen, an die sonst niemand denkt.
|
|
89
|
+
//
|
|
90
|
+
// ⚠️ Welche Namen einen Befehl bekommen, entscheidet `firmenZeilen` (B-5):
|
|
91
|
+
// Ein doppelt vergebener Name bekommt KEINEN -- er waere ein Vorschlag,
|
|
92
|
+
// der garantiert wieder in derselben Absage endet.
|
|
93
|
+
const zeilen = firmenZeilen(namen);
|
|
94
|
+
if (zeilen.length > 0) {
|
|
95
|
+
console.error("\n Deine Firmen:");
|
|
96
|
+
zeilen.forEach((z) => console.error(z));
|
|
97
|
+
}
|
|
98
|
+
if (grund === "keine-firma") {
|
|
99
|
+
console.error(`\n Eine Firma anlegen: ${BASIS_URL}/firma/neu`);
|
|
100
|
+
}
|
|
101
|
+
return 1;
|
|
102
|
+
}
|
|
103
|
+
// ⚠️ Die 503 landet HIER und nicht oben bei der 402: Rueckgabewert 3 heisst
|
|
104
|
+
// "nochmal versuchen kann helfen", 4 heisst laut SKILL.md ausdruecklich
|
|
105
|
+
// "nicht wiederholen". Ein Aussetzer gehoert in den ersten Topf.
|
|
106
|
+
//
|
|
107
|
+
// 🔑 Den Rest entscheidet `schlussFehler` fuer alle Befehle gemeinsam --
|
|
108
|
+
// insbesondere die `404` (B-7), die hier frueher auf die `1` fiel und damit
|
|
109
|
+
// "Eingabe passt nicht" meldete, obwohl die Eingabe stimmte.
|
|
110
|
+
const schluss = schlussFehler(antwort.status, meldung);
|
|
111
|
+
console.error(schluss.text);
|
|
112
|
+
return schluss.wert;
|
|
113
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { feld, ruf
|
|
1
|
+
import { feld, ruf } from "../api.js";
|
|
2
|
+
import { schlussFehler } from "../fehler.js";
|
|
3
|
+
import { MAX_PROJEKTE_ANZEIGE, antwortHatProjekteFeld, titelFeldLesen, projekteAusAntwort, projektZeilen, titelAusAlterAntwort, } from "../projekt-zeilen.js";
|
|
2
4
|
import { BASIS_URL } from "../anmeldung.js";
|
|
3
5
|
/**
|
|
4
6
|
* Die eigenen Projekte anzeigen.
|
|
@@ -6,24 +8,98 @@ import { BASIS_URL } from "../anmeldung.js";
|
|
|
6
8
|
* 🔑 Wofuer das da ist: Damit Claude VOR dem Eintragen nachsehen kann. Ohne
|
|
7
9
|
* diesen Befehl steht dasselbe Projekt irgendwann zweimal auf einer
|
|
8
10
|
* oeffentlichen Seite mit dem Namen eines Menschen darauf.
|
|
11
|
+
*
|
|
12
|
+
* ⚠️ Seit dem 2026-08-18 (Befund L-4) stehen auch Live-Datum und Zahlen da.
|
|
13
|
+
* Der Slash-Befehl `/k3liste` versprach das schon vorher woertlich -- und die
|
|
14
|
+
* Ausgabe gab nur Titel her. *Eine Anleitung, die mehr verspricht als das
|
|
15
|
+
* Werkzeug hergibt, laesst Claude entweder raten oder sich entschuldigen.*
|
|
9
16
|
*/
|
|
10
17
|
export async function projektListe() {
|
|
11
18
|
const antwort = await ruf("/api/cli/projekt", { methode: "GET", mitAusweis: true });
|
|
12
19
|
if (antwort.status === 200) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
20
|
+
// 🔴 Ein `200` mit unlesbarem Rumpf ist KEIN Erfolg -- dieselbe Wache wie
|
|
21
|
+
// in `firma-daten.ts`: `ruf` verschluckt Parse-Fehler zu `null`, und ein
|
|
22
|
+
// WLAN-Anmeldeportal antwortet mit `200` und HTML.
|
|
23
|
+
const projekte = projekteAusAntwort(antwort.koerper);
|
|
24
|
+
if (!projekte) {
|
|
25
|
+
/*
|
|
26
|
+
🔴 **B-7 in der GEGENRICHTUNG** (Befund L-7, 2026-08-18, im Live-Durchlauf
|
|
27
|
+
selbst hineingelaufen). Bisher wurde jede unlesbare Antwort gleich
|
|
28
|
+
behandelt: „Die Antwort war nicht lesbar. Bitte gleich noch einmal."
|
|
29
|
+
|
|
30
|
+
Es gibt aber einen Fall, in dem Wiederholen NIE hilft: Die CLI ist neuer
|
|
31
|
+
als die App. Dann antwortet der Server ordentlich — nur eben in der
|
|
32
|
+
alten Form, mit `titel` statt `projekte`. Das passiert bei jedem
|
|
33
|
+
Deployment im Fenster zwischen npm und Vercel, und es traf hier den
|
|
34
|
+
eigenen Entwickler.
|
|
35
|
+
|
|
36
|
+
*Ein Rat, der garantiert nicht hilft, ist schlimmer als kein Rat: Er
|
|
37
|
+
sieht aus wie ein Ausweg.* -- dieselbe Lehre wie bei B-5.
|
|
38
|
+
|
|
39
|
+
Die alte Form ist erkennbar, also wird sie auch bedient: Der Mensch
|
|
40
|
+
bekommt seine Liste, nur ohne die neuen Angaben. Nichts kaputt, nichts
|
|
41
|
+
zu wiederholen.
|
|
42
|
+
*/
|
|
43
|
+
const alt = titelAusAlterAntwort(antwort.koerper);
|
|
44
|
+
if (alt) {
|
|
45
|
+
if (alt.length === 0) {
|
|
46
|
+
console.log("Du hast noch keine Projekte eingetragen.");
|
|
47
|
+
console.log(` Eintragen: kimal3 projekt neu --titel "…"`);
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
console.log(`\n Deine Projekte (${alt.length} von ${MAX_PROJEKTE_ANZEIGE}):`);
|
|
51
|
+
alt.forEach((t, i) => console.log(` ${i + 1}. ${t}`));
|
|
52
|
+
console.log("\n (Diese Version der App liefert noch keine Zahlen zu den");
|
|
53
|
+
console.log(" Projekten. Du hast nichts falsch gemacht — sie kommen mit");
|
|
54
|
+
console.log(" dem nächsten Update der App von selbst dazu.)");
|
|
55
|
+
console.log(`\n Ansehen: ${BASIS_URL}/profil\n`);
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
/*
|
|
59
|
+
🔴 **Die dritte Richtung: die App ist NEUER als dieses Werkzeug**
|
|
60
|
+
(Review-Runde 4, 2026-08-18). Steht `projekte` in der Antwort und war
|
|
61
|
+
sie trotzdem nicht lesbar, hat ein Eintrag eine Form, die diese
|
|
62
|
+
Fassung nicht kennt. Das ist **stabil** -- Wiederholen aendert daran
|
|
63
|
+
nichts, bis aktualisiert wird. Vorher fiel es in denselben Topf wie
|
|
64
|
+
eine kaputte Antwort und riet "gleich noch einmal".
|
|
65
|
+
*/
|
|
66
|
+
if (antwortHatProjekteFeld(antwort.koerper)) {
|
|
67
|
+
/*
|
|
68
|
+
🔑 **Erst geben, was da ist** (Review-Runde 6, 2026-08-18). Die neue
|
|
69
|
+
Route liefert `titel` und `projekte` IMMER gemeinsam. Aendert eine
|
|
70
|
+
spaetere App-Fassung die Form eines Eintrags, sind die Titel trotzdem
|
|
71
|
+
lesbar -- sie dann NICHT zu zeigen und stattdessen nur "aktualisiere"
|
|
72
|
+
zu sagen, wirft Daten weg, die man in der Hand haelt.
|
|
73
|
+
*Wer dem Menschen etwas geben kann, gibt es ihm -- und sagt dazu,
|
|
74
|
+
was fehlt.*
|
|
75
|
+
*/
|
|
76
|
+
const titel = titelFeldLesen(antwort.koerper);
|
|
77
|
+
if (titel && titel.length > 0) {
|
|
78
|
+
console.log(`\n Deine Projekte (${titel.length} von ${MAX_PROJEKTE_ANZEIGE}):`);
|
|
79
|
+
titel.forEach((t, i) => console.log(` ${i + 1}. ${t}`));
|
|
80
|
+
console.log("\n (Die Zahlen dazu kann diese Fassung von kimal3 nicht lesen —");
|
|
81
|
+
console.log(" die App ist neuer als das Werkzeug. Du hast nichts falsch");
|
|
82
|
+
console.log(" gemacht; `npm install -g kimal3` holt sie.)");
|
|
83
|
+
console.log(`\n Ansehen: ${BASIS_URL}/profil\n`);
|
|
84
|
+
return 0;
|
|
85
|
+
}
|
|
86
|
+
console.error("Diese Fassung von kimal3 versteht die Antwort der App nicht.");
|
|
87
|
+
console.error("Du hast nichts falsch gemacht — das Werkzeug ist älter als die App.");
|
|
88
|
+
console.error(" npm install -g kimal3");
|
|
89
|
+
return 1;
|
|
90
|
+
}
|
|
91
|
+
console.error("Die Antwort war nicht lesbar. Bitte gleich noch einmal.");
|
|
16
92
|
return 3;
|
|
17
93
|
}
|
|
18
94
|
// Eine leere Liste ist KEIN Fehler — sie ist eine gueltige Antwort auf
|
|
19
95
|
// eine gueltige Frage. Deshalb 0 und ein Satz, kein Fehlertext.
|
|
20
|
-
if (
|
|
96
|
+
if (projekte.length === 0) {
|
|
21
97
|
console.log("Du hast noch keine Projekte eingetragen.");
|
|
22
98
|
console.log(` Eintragen: kimal3 projekt neu --titel "…"`);
|
|
23
99
|
return 0;
|
|
24
100
|
}
|
|
25
|
-
console.log(`\n Deine Projekte (${
|
|
26
|
-
|
|
101
|
+
console.log(`\n Deine Projekte (${projekte.length} von ${MAX_PROJEKTE_ANZEIGE}):\n`);
|
|
102
|
+
projektZeilen(projekte).forEach((z) => console.log(z));
|
|
27
103
|
console.log(`\n Ansehen: ${BASIS_URL}/profil\n`);
|
|
28
104
|
return 0;
|
|
29
105
|
}
|
|
@@ -48,6 +124,11 @@ export async function projektListe() {
|
|
|
48
124
|
// versuchen kann helfen"; 4 heisst laut SKILL.md ausdruecklich "nicht
|
|
49
125
|
// wiederholen". Ein Lesefehler an der Pro-Schranke gehoert in den ersten
|
|
50
126
|
// Topf. (Review-Befund 2026-08-14.)
|
|
51
|
-
|
|
52
|
-
|
|
127
|
+
//
|
|
128
|
+
// 🔑 Den Rest entscheidet `schlussFehler` fuer alle Befehle gemeinsam --
|
|
129
|
+
// insbesondere die `404` (B-7), die hier frueher auf die `1` fiel und damit
|
|
130
|
+
// "Eingabe passt nicht" meldete, obwohl die Eingabe stimmte.
|
|
131
|
+
const schluss = schlussFehler(antwort.status, meldung);
|
|
132
|
+
console.error(schluss.text);
|
|
133
|
+
return schluss.wert;
|
|
53
134
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { feld, ruf } from "../api.js";
|
|
2
|
+
import { schlussFehler } from "../fehler.js";
|
|
2
3
|
import { BASIS_URL } from "../anmeldung.js";
|
|
3
4
|
import { zerlege } from "../argumente.js";
|
|
4
5
|
const OPTIONEN = [
|
|
@@ -77,6 +78,11 @@ export async function projektNeu(argv) {
|
|
|
77
78
|
// versuchen kann helfen"; 4 heisst laut SKILL.md ausdruecklich "nicht
|
|
78
79
|
// wiederholen". Ein Lesefehler an der Pro-Schranke gehoert in den ersten
|
|
79
80
|
// Topf. (Review-Befund 2026-08-14.)
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
//
|
|
82
|
+
// 🔑 Den Rest entscheidet `schlussFehler` fuer alle Befehle gemeinsam --
|
|
83
|
+
// insbesondere die `404` (B-7), die hier frueher auf die `1` fiel und damit
|
|
84
|
+
// "Eingabe passt nicht" meldete, obwohl die Eingabe stimmte.
|
|
85
|
+
const schluss = schlussFehler(antwort.status, meldung);
|
|
86
|
+
console.error(schluss.text);
|
|
87
|
+
return schluss.wert;
|
|
82
88
|
}
|