kimal3 0.9.2 → 0.9.3

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.
@@ -1,7 +1,7 @@
1
1
  // Reine Rechnungen hinter `kimal3 zeigen` (Aufnahme von Bildschirm und Ton fuer Claude).
2
2
  // Kein Dateisystem, kein Prozess, keine Anzeige-Texte: Die Befehle holen die Fakten und fragen hier.
3
3
  // Gedeckt von `npm run check:zeigen` (Spec 2026-10-18-k3zeigen-design.md).
4
- import { win32 } from "node:path";
4
+ import { posix, win32 } from "node:path";
5
5
  const MAX_PFAD_WINDOWS = 170;
6
6
  /** "2026-10-19-0912" in Ortszeit. */
7
7
  export function ordnerName(jetzt) {
@@ -22,8 +22,9 @@ function projektEnde(segmente) {
22
22
  }
23
23
  /** Wohin die Aufnahme faellt: ins Projekt, in dem man steht -- nie in die Werkbank selbst. */
24
24
  export function aufnahmeOrt(start, jetzt, plattform, gibtEs) {
25
- const trenner = start.includes("\\") ? "\\" : "/";
26
- const segmente = start.split(/[\\/]/);
25
+ // Auf dem Mac ist der Backslash ein erlaubtes Zeichen im Ordnernamen, kein Trenner.
26
+ const trenner = plattform === "darwin" || !start.includes("\\") ? "/" : "\\";
27
+ const segmente = start.split(plattform === "darwin" ? "/" : /[\\/]/);
27
28
  while (segmente.length > 1 && segmente[segmente.length - 1] === "")
28
29
  segmente.pop();
29
30
  const ende = projektEnde(segmente);
@@ -63,16 +64,37 @@ export function bildName(sekunden) {
63
64
  return `${dauerText(sekunden).replaceAll(":", "-")}.png`; // kein-anzeigetext: Dateiname
64
65
  }
65
66
  // Reihenfolge zaehlt: das erste Muster, das trifft, gewinnt. Das Protokoll enthaelt Fenstertitel -- es wird nie
66
- // zurueckgegeben oder angezeigt, nur nach diesen festen Mustern durchsucht.
67
- const GRUENDE = [
67
+ // zurueckgegeben oder angezeigt, nur nach diesen festen Mustern durchsucht. Die Mac-Muster sind die festen Saetze des
68
+ // Aufnehmers (nie "Accessibility" allein: ein Fenstertitel "Accessibility Settings" ist kein Grund).
69
+ const GRUENDE_WINDOWS = [
68
70
  [/FFmpegUnavailableError|ffmpeg.*not found/i, "ffmpeg-fehlt"],
69
71
  [/returned success without a non-empty output/, "pfad-zu-lang"],
70
72
  [/PortAudio|No Default Input Device|sounddevice/, "kein-mikrofon"],
71
73
  [/DesktopCaptureError|screen layout/, "bildschirm-gesperrt"],
72
74
  [/did not become ready|did not start/, "startet-nicht"],
73
75
  ];
74
- export function fehlerGrund(protokoll) {
75
- return GRUENDE.find(([muster]) => muster.test(protokoll))?.[1] ?? "unbekannt";
76
+ const GRUENDE_MAC = [
77
+ [/FFmpegUnavailableError|ffmpeg.*not found/i, "ffmpeg-fehlt"],
78
+ [/denied global input observation/, "freigabe-eingabe"],
79
+ [/denied the ordered input barrier/, "freigabe-bedienungshilfen"],
80
+ [/disabled the input event tap/, "abgriff-abgeschaltet"],
81
+ [/PortAudio|No Default Input Device|sounddevice/, "kein-mikrofon"],
82
+ [/DesktopCaptureError|screen layout/, "bildschirm-gesperrt"],
83
+ [/did not become ready|did not start/, "startet-nicht"],
84
+ ];
85
+ export function fehlerGrund(protokoll, plattform) {
86
+ const gruende = plattform === "win32" ? GRUENDE_WINDOWS : GRUENDE_MAC;
87
+ return gruende.find(([muster]) => muster.test(protokoll))?.[1] ?? "unbekannt";
88
+ }
89
+ /** Darwin-Kern -> macOS-Hauptnummer ("22.6.0" -> 13, "25.0.0" -> 26); `null`, wenn es keine Zahl ab macOS 11 ist. */
90
+ export function macosFassung(release) {
91
+ const m = /^(\d+)(?:\.|$)/.exec(release);
92
+ if (m === null)
93
+ return null;
94
+ const kern = Number(m[1]);
95
+ if (kern < 20)
96
+ return null;
97
+ return kern >= 25 ? kern + 1 : kern - 9;
76
98
  }
77
99
  /** Der Aufnehmer antwortet mit einer JSON-Zeile ganz am Ende; alles andere (auch ein Traceback) ist ein Fehlschlag. */
78
100
  export function liesWerkzeugAntwort(rueckgabe, stdout) {
@@ -154,28 +176,40 @@ export const gueltigeFassung = (w) => (typeof w === "string" && /^\d+\.\d+\.\d+\
154
176
  * Die Antwort von `werkzeug.py teile` -> `Teile`. Ohne Antwort (kein Aufnehmer-Python) oder mit einer unlesbaren gilt
155
177
  * alles ausser uv als fehlend: Einrichten holt es dann (wieder), statt einem stummen Aufnehmer zu glauben.
156
178
  */
157
- export function teileAus(uv, antwort) {
179
+ export function teileAus(uv, antwort, plattform) {
158
180
  if (antwort === null || !antwort.ok)
159
181
  return { uv, aufnehmer: null, ffmpeg: false, modell: false };
160
182
  const d = antwort.daten;
161
- return { uv, aufnehmer: gueltigeFassung(d.aufnehmer), ffmpeg: d.ffmpeg === true, modell: d.modell === true };
183
+ // Auf dem Mac gilt der Aufnehmer ohne die Bildschirm-Anbindung (AVFoundation) als nicht eingerichtet.
184
+ const aufnehmer = plattform === "darwin" && d.avfoundation !== true ? null : gueltigeFassung(d.aufnehmer);
185
+ return { uv, aufnehmer, ffmpeg: d.ffmpeg === true, modell: d.modell === true };
162
186
  }
163
187
  export const AUFNEHMER_PAKET = `openadapt-capture[transcribe-fast]==${AUFNEHMER_FASSUNG}`; // kein-anzeigetext: Paketname
164
188
  /** `uv tool install …` -- `ersetzen`, sobald schon eine Umgebung des Aufnehmers liegt (andere Fassung, kaputt). */
165
- export function aufnehmerArgumente(ersetzen) {
189
+ export function aufnehmerArgumente(ersetzen, plattform) {
190
+ // kein-anzeigetext: Befehlszeile
191
+ const mac = plattform === "darwin" ? ["--with", "pyobjc-framework-AVFoundation==12.2.2"] : [];
166
192
  // kein-anzeigetext: Befehlszeile
167
- return ["tool", "install", "--python", "3.12", ...(ersetzen ? ["--force"] : []), AUFNEHMER_PAKET];
193
+ return ["tool", "install", "--python", "3.12", ...(ersetzen ? ["--force"] : []), ...mac, AUFNEHMER_PAKET];
168
194
  }
169
195
  /**
170
- * Wie uv auf den Rechner kommt: winget zuerst (Coach-Regel: Paketmanager), sonst der offizielle Installer pro Benutzer.
171
- * Ohne die beiden Zustimmungsschalter haengt winget auf einem frischen Rechner an einer Frage (Spec US-2).
196
+ * Wie uv auf den Rechner kommt. Windows: winget zuerst (Coach-Regel: Paketmanager; ohne die beiden Zustimmungsschalter
197
+ * haengt es auf einem frischen Rechner an einer Frage, Spec US-2), sonst der offizielle Installer pro Benutzer.
198
+ * Mac: `paketmanager` ist der Pfad zu brew oder `null` -- dann der offizielle Installer, der den PATH nicht anfasst.
172
199
  */
173
- export function uvEinrichtung(winget) {
200
+ export function uvEinrichtung(plattform, paketmanager) {
201
+ if (plattform === "darwin") {
202
+ // kein-anzeigetext: Befehlszeile
203
+ if (paketmanager !== null)
204
+ return { befehl: paketmanager, argumente: ["install", "uv"], umgebung: { HOMEBREW_NO_AUTO_UPDATE: "1" } };
205
+ // kein-anzeigetext: Befehlszeile
206
+ return { befehl: "/bin/sh", argumente: ["-c", "curl -LsSf https://astral.sh/uv/install.sh | sh"], umgebung: { UV_NO_MODIFY_PATH: "1" } };
207
+ }
174
208
  // kein-anzeigetext: Befehlszeile
175
- if (winget)
176
- return { befehl: "winget", argumente: ["install", "--id", "astral-sh.uv", "-e", "--scope", "user", "--accept-source-agreements", "--accept-package-agreements"] };
209
+ if (paketmanager === "winget")
210
+ return { befehl: "winget", argumente: ["install", "--id", "astral-sh.uv", "-e", "--scope", "user", "--accept-source-agreements", "--accept-package-agreements"], umgebung: {} };
177
211
  // kein-anzeigetext: Befehlszeile
178
- return { befehl: "powershell", argumente: ["-ExecutionPolicy", "ByPass", "-c", "irm https://astral.sh/uv/install.ps1 | iex"] };
212
+ return { befehl: "powershell", argumente: ["-ExecutionPolicy", "ByPass", "-c", "irm https://astral.sh/uv/install.ps1 | iex"], umgebung: {} };
179
213
  }
180
214
  /** Was beim Einrichten noch fehlt, in der Reihenfolge, in der es gebraucht wird. */
181
215
  export function einrichtPlan(t) {
@@ -187,8 +221,11 @@ export function einrichtPlan(t) {
187
221
  ];
188
222
  return fehlt.filter(([f]) => f).map(([, schritt]) => schritt);
189
223
  }
190
- /** Wo uv unter Windows liegen kann, wenn es nicht im PATH steht (frisch installiert, Terminal noch alt). */
191
- export function uvKandidaten(env, home) {
224
+ /** Wo uv liegen kann, wenn es nicht im PATH steht (frisch installiert, Terminal noch alt). */
225
+ export function uvKandidaten(env, home, plattform) {
226
+ // kein-anzeigetext: Ordnerpfad
227
+ if (plattform === "darwin")
228
+ return [posix.join(home, ".local", "bin", "uv"), "/opt/homebrew/bin/uv", "/usr/local/bin/uv", posix.join(home, ".cargo", "bin", "uv")];
192
229
  const lokal = env.LOCALAPPDATA ?? win32.join(home, "AppData", "Local"); // kein-anzeigetext: Ordnerpfad
193
230
  return [
194
231
  // kein-anzeigetext: Ordnerpfad
@@ -197,6 +234,22 @@ export function uvKandidaten(env, home) {
197
234
  win32.join(home, ".cargo", "bin", "uv.exe"),
198
235
  ];
199
236
  }
237
+ /**
238
+ * Wo das Python des Aufnehmers liegen kann, in Suchreihenfolge. Antwortet uv mit seinem Ordner (`toolDir`), gilt er
239
+ * allein (so greift `UV_TOOL_DIR`); der Standardort nur ohne Antwort.
240
+ */
241
+ export function aufnehmerOrte(plattform, toolDir, env, home) {
242
+ // kein-anzeigetext: Ordnerpfad
243
+ if (plattform === "darwin") {
244
+ const ort = toolDir ?? posix.join(env.XDG_DATA_HOME ?? posix.join(home, ".local", "share"), "uv", "tools");
245
+ const python = posix.join(ort, "openadapt-capture", "bin", "python");
246
+ return [{ python, pythonw: python, captureNamen: ["capture"] }];
247
+ }
248
+ // Linux kommt hier nie an (`vorab` weist es ab); `fehlerGrund` behandelt es nur der Vollstaendigkeit halber wie den Mac.
249
+ const appdata = env.APPDATA ?? win32.join(home, "AppData", "Roaming"); // kein-anzeigetext: Ordnerpfad
250
+ const scripts = win32.join(toolDir ?? win32.join(appdata, "uv", "tools"), "openadapt-capture", "Scripts"); // kein-anzeigetext: Ordnerpfad
251
+ return [{ python: win32.join(scripts, "python.exe"), pythonw: win32.join(scripts, "pythonw.exe"), captureNamen: ["capture.exe"] }];
252
+ }
200
253
  /**
201
254
  * Welcher Ordner in `material/aufnahmen/` ist die juengste Aufnahme? Nur Namen von `ordnerName` (mit Endung `-2` …)
202
255
  * zaehlen; `-10` kommt nach `-9` (als Text stuende es davor). `istAufnahme` sortiert Ordner aus, in denen keine
@@ -1,9 +1,9 @@
1
1
  import { spawn, spawnSync } from "node:child_process";
2
2
  import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
3
- import { homedir, tmpdir } from "node:os";
4
- import { join, win32 } from "node:path";
3
+ import { homedir, platform, tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
- import { juengsteAufnahme, liesWerkzeugAntwort, starterLebt, uvKandidaten } from "./zeigen-rechnung.js";
6
+ import { aufnehmerOrte, juengsteAufnahme, liesWerkzeugAntwort, starterLebt, uvKandidaten } from "./zeigen-rechnung.js";
7
7
  /**
8
8
  * Die Umgebung hinter `kimal3 zeigen`: wo der Aufnehmer und sein Python liegen, wie das Werkzeug gerufen wird, und
9
9
  * die Notiz `~/.kimal3/zeigen.json` (welcher Ordner zu welcher Sitzung gehoert). Entscheidungen trifft
@@ -24,7 +24,7 @@ function laeuft(befehl, argumente) {
24
24
  }
25
25
  /** Das erste uv, das antwortet: Suchpfad, dann die bekannten Orte (frisch installiert, Terminal noch alt). */
26
26
  export function findeUv() {
27
- for (const uv of ["uv", ...uvKandidaten(process.env, homedir())]) {
27
+ for (const uv of ["uv", ...uvKandidaten(process.env, homedir(), platform())]) {
28
28
  const version = laeuft(uv, ["--version"]);
29
29
  if (version !== null)
30
30
  return { uv, version };
@@ -35,18 +35,13 @@ export function findeUv() {
35
35
  export function uvFassung() {
36
36
  return /^uv (\d+\.\d+\.\d+\S*)/.exec(findeUv()?.version ?? "")?.[1] ?? null;
37
37
  }
38
- /** Python und pythonw des Aufnehmers: `<uv tool dir>/openadapt-capture/Scripts/`, sonst `%APPDATA%\uv\tools\…`. */
38
+ /** Python und pythonw des Aufnehmers: im `uv tool dir`, sonst am Standardort (Orte: `aufnehmerOrte`). */
39
39
  export function aufnehmerPython() {
40
40
  const uv = findeUv();
41
41
  const toolDir = uv === null ? null : laeuft(uv.uv, ["tool", "dir"])?.trim() || null;
42
- const appdata = process.env.APPDATA ?? win32.join(homedir(), "AppData", "Roaming"); // kein-anzeigetext: Ordnerpfad
43
42
  // Antwortet uv, gilt sein Ordner allein (so greift `UV_TOOL_DIR`); der Standardort nur, wenn uv selbst fehlt (Task 5:
44
43
  // sonst faende ein nachgestellter frischer Rechner den echten Aufnehmer unter %APPDATA% doch).
45
- const orte = toolDir !== null ? [toolDir] : [win32.join(appdata, "uv", "tools")]; // kein-anzeigetext: Ordnerpfad
46
- for (const ort of orte) {
47
- const scripts = win32.join(ort, "openadapt-capture", "Scripts"); // kein-anzeigetext: Ordnerpfad
48
- const python = win32.join(scripts, "python.exe");
49
- const pythonw = win32.join(scripts, "pythonw.exe");
44
+ for (const { python, pythonw } of aufnehmerOrte(platform(), toolDir, process.env, homedir())) {
50
45
  if (existsSync(python) && existsSync(pythonw))
51
46
  return { python, pythonw };
52
47
  }
@@ -59,11 +54,12 @@ export function uvBinOrdner(uv) {
59
54
  /**
60
55
  * Ein fremdes Programm (winget, uv, capture) ohne Fenster und ohne dass eine Zeile davon irgendwo erscheint -- nicht
61
56
  * einmal eingesammelt. `true` nur bei Rueckgabewert 0; ob die Sache danach WIRKLICH da ist, prueft der Aufrufer neu.
57
+ * `extraUmgebung`: zusaetzliche Variablen nur fuer diesen Aufruf (brew: kein Auto-Update, uv-Installer: PATH unberuehrt).
62
58
  * Arbeitsordner ist der Temp-Ordner: nie das Projekt (eine `uv.toml`/`.env` dort gehoert nicht zum Einrichten).
63
59
  */
64
- export function stillAusfuehren(befehl, argumente, zeitgrenze) {
60
+ export function stillAusfuehren(befehl, argumente, zeitgrenze, extraUmgebung = {}) {
65
61
  try {
66
- const r = spawnSync(befehl, argumente, { stdio: "ignore", windowsHide: true, cwd: tmpdir(), env: UMGEBUNG(), timeout: zeitgrenze });
62
+ const r = spawnSync(befehl, argumente, { stdio: "ignore", windowsHide: true, cwd: tmpdir(), env: { ...UMGEBUNG(), ...extraUmgebung }, timeout: zeitgrenze });
67
63
  return r.status === 0;
68
64
  }
69
65
  catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kimal3",
3
- "version": "0.9.2",
3
+ "version": "0.9.3",
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": {
@@ -29,7 +29,8 @@ hier stehen nur die Fälle dieses Befehls.
29
29
  diesem Schritt.** Eine Datei aus der Aufnahme öffnest du für den Menschen nur in Notepad, und so,
30
30
  dass dein Aufruf sofort zurückkommt: in Bash `cmd //c start "" notepad "<pfad>"`, in PowerShell
31
31
  `Start-Process notepad -ArgumentList '"<pfad>"'`. Ein nacktes `notepad "<pfad>"` blockiert, bis
32
- das Fenster wieder zu ist. Nie in einer IDE oder einem Editor, an dem Claude Code hängt (dort
32
+ das Fenster wieder zu ist. Auf dem Mac öffnest du sie in TextEdit: `open -e "<pfad>"` — das kommt
33
+ sofort zurück. Nie in einer IDE oder einem Editor, an dem Claude Code hängt (dort
33
34
  landen markierte Zeilen von selbst im Gespräch).
34
35
  3. **Ein Fehlschlag sieht nie aus wie ein Erfolg.** Endet ein `kimal3 zeigen …` nicht mit `0`,
35
36
  sag ehrlich, was seine Meldung sagt, und mach nicht weiter, als hätte es geklappt.
@@ -38,6 +39,10 @@ Alle `kimal3 zeigen …` laufen **im Projektordner** (Schritt 3) — das Program
38
39
  über den Ordner, in dem es gestartet wird. Liegt eine Aufnahme in einem anderen Projekt, wechselst
39
40
  du zuerst dorthin: Der Projektordner ist der Teil des Pfads vor `material/aufnahmen/`.
40
41
 
42
+ Ist die Sandbox von Claude Code eingeschaltet, führst du jedes `kimal3 zeigen …` **außerhalb der
43
+ Sandbox** aus (im Bash-Werkzeug mit `dangerouslyDisableSandbox`): Das Programm schreibt in
44
+ `~/.kimal3` und `~/.local`, und das kann in der Sandbox scheitern.
45
+
41
46
  ## 1. Ankommen und nachsehen
42
47
 
43
48
  Führe zuerst `kimal3 zeigen status` aus. Es liest nur. Den Block „Eingerichtet:" liest du dem
@@ -46,7 +51,8 @@ prüfbar", „kann ich nicht feststellen" oder „(gebraucht wird …)" → Schr
46
51
 
47
52
  | Die Ausgabe sagt | Was du tust |
48
53
  |---|---|
49
- | `kimal3 zeigen` gibt es bisher nur unter Windows; der Mac folgt. | Sag genau das, freundlich: Vormachen geht auf diesem Rechner noch nicht, der Mac kommt. Biete an, dass der Mensch die Aufgabe stattdessen in Worten beschreibt. Hier endet der Befehl. |
54
+ | „`kimal3 zeigen` gibt es für Windows und den Mac." (Rückgabewert 1) | Sag genau das, freundlich: Vormachen geht auf diesem Rechner nicht, nur unter Windows und auf dem Mac. Biete an, dass der Mensch die Aufgabe stattdessen in Worten beschreibt. Hier endet der Befehl. |
55
+ | „Für Aufnahmen braucht es macOS 13 oder neuer — dieser Mac hat macOS 12." oder, wenn sich die Fassung nicht lesen lässt, „Für Aufnahmen braucht es macOS 13 oder neuer." (Rückgabewert 1) | Sag genau das, freundlich: Auf diesem Mac geht Vormachen erst mit macOS 13 oder neuer. Biete an, dass der Mensch die Aufgabe stattdessen in Worten beschreibt. Hier endet der Befehl. |
50
56
  | „Ob gerade aufgenommen wird, kann ich nicht feststellen." (Rückgabewert 1) | Sag ehrlich, dass du es gerade nicht feststellen kannst. **Starte nichts.** Biete an, in einer Minute noch einmal nachzusehen. |
51
57
  | „Läuft seit 09:12 (3 Minuten), Ordner `…`, stoppt spätestens 09:27." | Eine Aufnahme aus einer früheren Sitzung läuft noch. Steht im Ordner ein voller Pfad außerhalb dieses Projekts, wechsle zuerst in dessen Projektordner. Dann frag: „Da läuft noch eine Aufnahme von 09:12 — bist du mit dem Vormachen durch? Dann stoppe ich sie jetzt." Ja → Schritt 8. |
52
58
  | „Läuft (in einer anderen Sitzung gestartet)." | Es läuft eine Aufnahme, die dieses Projekt nicht zuordnen kann. Sag das, **starte keine zweite**, und schlag vor, mit `kimal3 zeigen status` nachzusehen, sobald sie zu Ende ist. |
@@ -54,6 +60,30 @@ prüfbar", „kann ich nicht feststellen" oder „(gebraucht wird …)" → Schr
54
60
  | „Keine Aufnahme läuft." und darunter „Die letzte (`…`) ist abgebrochen." | Freundlich: Die letzte Aufnahme ist mittendrin abgebrochen — der Mensch hat nichts falsch gemacht. Biete an, die Aufgabe neu vorzumachen. |
55
61
  | „Keine Aufnahme läuft." | Weiter. |
56
62
 
63
+ **Nur auf dem Mac** steht vor der letzten Zeile noch „Freigaben gehen an: …". Daran erkennst du im
64
+ ganzen Gespräch, dass du auf einem Mac bist. Merk dir den Namen dahinter (meist „Terminal") — er
65
+ heißt unten **<App>**.
66
+
67
+ - **„Freigaben gehen an: Claude (Desktop-App)"** → sag **zuerst**, vor allem anderen:
68
+
69
+ > „Auf dem Mac geht die Aufnahme verlässlich nur aus dem Terminal: In dieser App fragt macOS teils
70
+ > gar nicht nach den Erlaubnissen, und nach jedem Claude-Update müsstest du sie neu geben. Soll ich
71
+ > dir Terminal gleich im richtigen Ordner öffnen? Dort tippst du `claude` und dann `/k3zeigen` — das
72
+ > ist ein neues Gespräch, die Aufgabe sagst du mir dort einfach noch einmal. Oder sollen wir es hier
73
+ > trotzdem probieren?"
74
+
75
+ **Ja** → `open -a Terminal "<projektordner>"` (gibt es noch kein Projekt, der Ordner, in dem die
76
+ Sitzung gerade steht). Sag, dass Terminal jetzt offen ist; hier endet der Befehl. **„Trotzdem
77
+ hier"** → weiter wie sonst; <App> heißt dann „Claude".
78
+ - **„Freigaben gehen an: niemanden — über SSH kann macOS keine Freigaben geben"** → sag genau das:
79
+ Über eine Fernverbindung kann macOS die Erlaubnisse für Bildschirm, Tasten und Mikrofon nicht
80
+ geben. Schlag vor, am Mac selbst ein Terminal zu öffnen und dort `claude` und `/k3zeigen` zu
81
+ starten. Hier endet der Befehl.
82
+ - **„Freigaben gehen an: die App, aus der du Claude gestartet hast"** → frag **gleich hier** einmal,
83
+ wie die App heißt, aus der Claude läuft (Vorschlag: „Terminal?"), und nimm die Antwort als <App> —
84
+ so steht der richtige Name schon in der Ansage von Schritt 4. Erst danach kommt die Frage nach der
85
+ Aufgabe (eine Frage auf einmal).
86
+
57
87
  Die letzte Zeile sagt, ob der Ordner passt — merk sie dir für Schritt 3:
58
88
  „Aufnahmen landen hier in: …" (passt) · „Wechsle zuerst in ein Projekt …" (die Sitzung steht in
59
89
  der Werkbank) · „Der Projektordner liegt zu tief für den Aufnehmer …" (der Pfad ist zu lang).
@@ -90,28 +120,138 @@ wichtigste Rückfrage (Schritt 11). Ein grober Satz reicht; bohr nicht nach.
90
120
 
91
121
  ## 4. Einrichten — nur wenn etwas fehlt
92
122
 
93
- Fehlt nichts, überspring diesen Schritt ohne ein Wort darüber. Fehlt etwas, sag **vorher genau
94
- das** und warte auf die Antwort:
123
+ Fehlt nichts, überspring diesen Schritt ohne ein Wort darüber (auf dem Mac weiter mit Schritt 4b).
124
+ Fehlt etwas, sag **vorher genau das** und warte auf die Antwort:
95
125
 
96
126
  > „Dafür richte ich einmal den Aufnehmer ein — ein freies Programm, das Bildschirm, Ton, Klicks
97
127
  > und Tasten aufzeichnet. Etwa 2,1 GB, je nach Leitung 10 bis 20 Minuten, nur in deinem
98
128
  > Benutzerordner, ohne Adminrechte. Weil er Tasten mitschreibt, kann der Virenschutz deiner Firma
99
129
  > ihn melden; auf einem Firmenrechner frag im Zweifel vorher die IT. Soll ich?"
100
130
 
131
+ **Auf dem Mac** sagst du stattdessen diesen Satz, mit <App> aus Schritt 1:
132
+
133
+ > „Dafür richte ich einmal den Aufnehmer ein — ein freies Programm, das Bildschirm, Ton, Klicks und
134
+ > Tasten aufzeichnet. Etwa 2 GB, je nach Leitung 10 bis 20 Minuten, nur in deinem Benutzerordner.
135
+ > Danach schaltest du für <App> vier Erlaubnisse in den Systemeinstellungen ein — ich zeige dir jede
136
+ > einzeln. macOS will dabei ein Admin-Passwort (auf deinem eigenen Mac ist das dein
137
+ > Anmeldepasswort), und <App> startet einmal neu. Auf einem Firmen-Mac geht das oft nur mit der IT.
138
+ > Soll ich?"
139
+
101
140
  - **Ja:** Starte `kimal3 zeigen einrichten` **im Hintergrund** — es kann länger dauern als die zehn
102
141
  Minuten, die ein Befehl im Vordergrund laufen darf. Sag, dass es läuft und der Mensch solange
103
142
  etwas anderes tun kann. **Warte auf die Meldung, dass es fertig ist** — frag nicht
104
143
  zwischendurch nach, und schlaf nicht in einer Schleife. Danach:
105
144
  - Rückgabewert `0` → `kimal3 zeigen status`; stehen alle vier Teile da (uv, Aufnehmer, FFmpeg,
106
- Sprachmodell), weiter mit Schritt 5.
145
+ Sprachmodell), weiter mit Schritt 5 (auf dem Mac mit Schritt 4b).
107
146
  - Rückgabewert `1` („Schritt … hat nicht geklappt.") → nenn diesen Schritt und biete eine
108
- fertige Nachricht an die IT an: **was** (uv von Astral · der Aufnehmer openadapt-capture 1.3.0,
147
+ fertige Nachricht an die IT an (auf dem Mac die unten): **was** (uv von Astral · der Aufnehmer openadapt-capture 1.3.0,
109
148
  Lizenz MIT, mit Python 3.12 · FFmpeg · das Sprachmodell large-v3-turbo von Hugging Face),
110
149
  **wozu** (eine Arbeitsaufgabe einmal am Bildschirm vorführen und auf dem Rechner auswerten),
111
150
  **woher** (astral.sh bzw. winget, pypi.org, huggingface.co), **welche Ordner** (nur der
112
151
  Benutzerordner, ohne Adminrechte).
113
152
  - **Nein:** „Kein Problem — mit `/k3zeigen` geht es jederzeit später." Hier endet der Befehl.
114
153
 
154
+ **Die Nachricht an die IT auf dem Mac:** **was** (uv von Astral, bzw. über Homebrew, wenn es da ist ·
155
+ der Aufnehmer openadapt-capture 1.3.0, Lizenz MIT, mit Python 3.12 und dem Zusatz
156
+ pyobjc-framework-AVFoundation 12.2.2 · FFmpeg · das Sprachmodell large-v3-turbo von Hugging Face),
157
+ **wozu** (eine Arbeitsaufgabe einmal am Bildschirm vorführen und auf dem Rechner auswerten),
158
+ **woher** (astral.sh bzw. Homebrew, pypi.org, github.com, huggingface.co), **welche Ordner** (nur der
159
+ Benutzerordner) — und dazu **die vier Freigaben** unter Systemeinstellungen → Datenschutz &
160
+ Sicherheit (Bildschirm- & Systemaudioaufnahme, Eingabeüberwachung, Bedienungshilfen, Mikrofon),
161
+ **für welche App** (<App>), und dass ein Standardkonto zwei davon (Bildschirm- &
162
+ Systemaudioaufnahme, Eingabeüberwachung) nicht selbst einschalten darf.
163
+
164
+ ## 4b. Freigaben — nur auf dem Mac
165
+
166
+ Unter Windows überspringst du diesen Schritt. Auf dem Mac (der Status hat die Zeile „Freigaben
167
+ gehen an …") kommt er **vor jeder** Ansage in Schritt 5: Ohne die vier Freigaben nimmt der Aufnehmer
168
+ nichts Brauchbares auf. Führe `kimal3 zeigen pruefen` aus.
169
+
170
+ | Die Ausgabe sagt | Was du tust |
171
+ |---|---|
172
+ | „Alle vier Freigaben für <App> sind da." (Rückgabewert 0) | Ohne ein Wort darüber weiter mit Schritt 5. |
173
+ | „Freigaben für <App>:" und darunter je Freigabe „da", „fehlt" oder „kann ich nicht feststellen" (Rückgabewert 1) | Kein Fehlschlag, sondern die Liste, was noch fehlt → weiter unten. Eine Zeile mit „kann ich nicht feststellen" behandelst du wie „fehlt", nennst sie dem Menschen aber nie „da" und nie „fehlt". |
174
+ | „Ob die Freigaben da sind, kann ich nicht feststellen." (Rückgabewert 1) | Sag ehrlich, dass du es gerade nicht feststellen kannst. Schlag vor, die vier Schalter trotzdem durchzugehen (weiter unten) — schaden kann es nicht. |
175
+ | „Der Aufnehmer ist noch nicht eingerichtet: `kimal3 zeigen einrichten`." | Zurück zu Schritt 4. |
176
+
177
+ Steht hinter „Freigaben für" nur „diese App", nimm als <App> den Namen, den der Mensch dir in
178
+ Schritt 1 genannt hat; hast du noch keinen, frag jetzt einmal (Vorschlag: „Terminal?").
179
+
180
+ **Fehlt etwas**, sag einmal vorab (fehlen weniger als vier, nenn statt „vier" die Zahl):
181
+
182
+ > „Ich zeige dir jetzt nacheinander vier Schalter. Bietet macOS zwischendurch ‚Beenden & erneut
183
+ > öffnen' an, klick ‚Später', bis alle vier an sind — dann starten wir einmal neu."
184
+
185
+ Dann **je fehlender Freigabe**, in der Reihenfolge der Liste, eine nach der anderen:
186
+
187
+ 1. **Ein Satz, was sie ist:**
188
+ Bildschirm- & Systemaudioaufnahme — damit der Aufnehmer sieht, was auf dem Bildschirm passiert ·
189
+ Eingabeüberwachung — damit er deine Klicks und Tasten mitschreiben kann · Bedienungshilfen — damit
190
+ er die Namen der Knöpfe und Felder lesen kann, auf die du klickst · Mikrofon — damit er hört, was
191
+ du sagst.
192
+ 2. `kimal3 zeigen pruefen --anfragen <freigabe>` (`bildschirm`, `eingabe`, `bedienungshilfen` oder
193
+ `mikrofon`) — damit trägt macOS <App> in die Liste dieser Freigabe ein. Sag vorher: Beim Mikrofon
194
+ fragt macOS selbst, dort „Erlauben" klicken; zeigt macOS bei den anderen ein Fenster, ist jeder
195
+ Knopf darin in Ordnung — die Seite öffnest du gleich selbst. Die Ausgabe ist wieder die Liste;
196
+ lies darin **nur die Zeile dieser Freigabe**. Steht dort „da" (oft beim Mikrofon nach
197
+ „Erlauben"), ist sie erledigt → die nächste.
198
+ 3. `kimal3 zeigen pruefen --oeffnen <freigabe>` öffnet genau diese Seite der Systemeinstellungen
199
+ („Ich habe ‚…' in den Systemeinstellungen geöffnet."). Sagt es „Die Systemeinstellungen ließen
200
+ sich nicht öffnen.", nenn den Weg von Hand: Apple-Menü → Systemeinstellungen → Datenschutz &
201
+ Sicherheit → der Name der Freigabe.
202
+ 4. **Der Klickweg:** „In der Liste ‚<App>' einschalten." Bei der ersten, Bildschirm- &
203
+ Systemaudioaufnahme, genauer: „im **oberen** Bereich ‚Bildschirm- & Systemaudioaufnahme', nicht
204
+ bei ‚Nur Systemaudioaufnahme'". Fehlt <App> in der Liste: „Unten auf das Plus klicken →
205
+ Programme → Dienstprogramme → Terminal" (bei einer anderen App: Programme → <App>).
206
+ Bei **Bildschirm- & Systemaudioaufnahme** und **Eingabeüberwachung** sag dazu: „macOS fragt dabei
207
+ nach einem Admin-Passwort — auf deinem eigenen Mac ist das dein Anmeldepasswort." Hat der Mensch
208
+ keins (Firmen-Mac, Standardkonto): biete die Nachricht an die IT aus Schritt 4 an; hier endet der
209
+ Befehl.
210
+ 5. Warte, bis der Mensch sagt, dass der Schalter an ist. **Prüf jetzt nicht nach** — macOS meldet
211
+ eine neue Freigabe oft erst nach dem Neustart. Weiter mit der nächsten.
212
+
213
+ **Sind alle an:** `kimal3 zeigen pruefen` noch einmal.
214
+
215
+ - „Alle vier Freigaben für <App> sind da." → weiter mit Schritt 5.
216
+ - Weiter „fehlt" (oder „kann ich nicht feststellen") bei einer Freigabe, die der Mensch eingeschaltet
217
+ hat → **erst der Neustart** (unten). Schick ihn **nicht** noch einmal in die Einstellungen.
218
+ - „fehlt" bei einer, die ihr noch nicht durchgegangen seid → zurück zu ihr, Punkt 1.
219
+
220
+ ### Der Neustart
221
+
222
+ Leg **vorher** den Rückweg in die Zwischenablage — **immer** mit dem Ordner, in dem **diese
223
+ Claude-Sitzung gestartet** wurde („Primary working directory" in deiner Umgebung), **nie** mit dem
224
+ Projektordner, auch wenn du gerade dort arbeitest: `claude --continue` setzt nur das Gespräch fort,
225
+ das in genau diesem Ordner begonnen hat.
226
+
227
+ ```bash
228
+ printf '%s' "cd '<ordner, in dem diese Claude-Sitzung gestartet wurde>' && claude --continue" | LC_CTYPE=UTF-8 pbcopy
229
+ ```
230
+
231
+ (Steht im Ordnernamen ein `'`, schreib es als `'\''`. `LC_CTYPE=UTF-8` hält Umlaute im Ordnernamen
232
+ heil.) Zeig dieselbe Zeile `cd '…' && claude --continue` **zusätzlich sichtbar** im Gespräch, als
233
+ eigenen Codeblock — klappt das Einfügen nicht, tippt der Mensch sie dort ab. Dann sag wörtlich:
234
+
235
+ > „Jetzt beendest du Terminal einmal ganz: ⌘ + Q (oder oben im Menü ‚Terminal → Terminal beenden').
236
+ > Fragt Terminal, ob laufende Prozesse beendet werden sollen: ‚Beenden'. Dann öffnest du Terminal
237
+ > wieder (⌘ + Leertaste, ‚Terminal' tippen, Enter), fügst mit ⌘ + V ein und drückst Enter. Den
238
+ > Befehl dafür habe ich dir schon kopiert — unser Gespräch geht dann genau hier weiter."
239
+
240
+ Häng im selben Zug an: „Schreib dann einfach ‚weiter', und ich sehe nach, ob die Freigaben jetzt
241
+ da sind." — in **derselben** Nachricht wie den Satz oben: Nach dem Neustart kommt von dir nichts
242
+ Neues, bis der Mensch etwas schreibt.
243
+ Heißt <App> nicht „Terminal", setz ihren Namen ein. Läuft Claude in der Desktop-App, passt dieser
244
+ Weg nicht: Biete dann das Terminal an (Satz und `open -a Terminal` aus Schritt 1).
245
+
246
+ Ist der Mensch zurück, sieh nach — **aus dem Projektordner**, wie alle `kimal3 zeigen …`:
247
+ `cd "<projektordner>" && kimal3 zeigen pruefen`.
248
+
249
+ - „Alle vier Freigaben für <App> sind da." → weiter mit Schritt 5.
250
+ - Weiter „fehlt": Öffne genau diese Seite noch einmal (`--oeffnen`) und lass nachsehen, ob der
251
+ Schalter bei <App> an ist. War er aus: einschalten lassen, dann noch ein Neustart wie oben. War er
252
+ an: Sag ehrlich, dass macOS die Freigabe nicht annimmt, und biete die Nachricht an die IT aus
253
+ Schritt 4 an. Hier endet der Befehl.
254
+
115
255
  ## 5. Die Ansage vor dem Start
116
256
 
117
257
  Sag diese vier Punkte, bevor irgendetwas aufnimmt:
@@ -124,6 +264,11 @@ Sag diese vier Punkte, bevor irgendetwas aufnimmt:
124
264
  4. Wenn du fertig bist, komm hierher zurück und schreib **„fertig"**; spätestens nach 15 Minuten
125
265
  stoppt die Aufnahme von selbst.
126
266
 
267
+ **Auf dem Mac** heißt es in Punkt 1 statt „schalte ‚Nicht stören' ein": „schalte den Fokus ‚Nicht
268
+ stören' ein (Kontrollzentrum → Fokus)". Und es kommt ein fünfter Punkt dazu:
269
+
270
+ 5. Fragt macOS mittendrin, ob <App> weiter aufnehmen darf: ‚Erlauben' klicken und weitermachen.
271
+
127
272
  Dann: „Schreib ‚los‘, wenn alles bereit ist." — und warte.
128
273
 
129
274
  - **Ein klares Startsignal** — „los", „bereit", „kann losgehen", „start" — → Schritt 6.
@@ -146,6 +291,7 @@ darin als `'\''`), in PowerShell in einfachen Anführungszeichen (ein `'` darin
146
291
  | „Es läuft schon eine Aufnahme (in einer anderen Sitzung gestartet)." | Frag: „Da läuft noch eine Aufnahme aus einer anderen Sitzung — soll ich sie stoppen, damit wir neu anfangen?" Ja → `kimal3 zeigen stopp`; sagt es, dass es sie hier nicht zuordnen kann, sag das ehrlich und schlag vor, zu warten, bis sie von selbst aufhört (`kimal3 zeigen status`). |
147
292
  | „Ob gerade aufgenommen wird, kann ich nicht feststellen — deshalb starte ich keine zweite." | Ehrlich sagen, nichts erzwingen, später noch einmal nachsehen. |
148
293
  | „Der Aufnehmer ist noch nicht eingerichtet: `kimal3 zeigen einrichten`." | Zurück zu Schritt 4. |
294
+ | „Die Aufnahme ist nicht gestartet: es fehlt die Freigabe … — `kimal3 zeigen pruefen` zeigt, was fehlt. Protokoll: …" | Nenn die Freigabe. **Öffne das Protokoll nicht.** Zurück zu Schritt 4b. |
149
295
  | „Die Aufnahme ist nicht gestartet: <Grund>. Protokoll: …" | Nenn den Grund. **Öffne das Protokoll nicht** — darin stehen Fenstertitel. Folgt „Ob der Aufnehmer noch läuft, sagt `kimal3 zeigen status`.", führ `kimal3 zeigen status` aus und sag, was es meldet. Biete einen neuen Versuch an. |
150
296
  | „Wechsle zuerst in ein Projekt …" · „Der Projektordner liegt zu tief …" | Zurück zu Schritt 3. |
151
297
 
@@ -174,7 +320,7 @@ gut 8 Minuten, also bevor die 10 Minuten um sind.
174
320
  | „Es läuft keine Aufnahme." | Sieh mit `kimal3 zeigen status` nach. Steht dort „Die letzte (`…`) hat nach … Minuten von selbst gestoppt.", geht es mit Schritt 9 weiter; sonst sag ehrlich, dass keine Aufnahme da ist. |
175
321
  | „Ob gerade aufgenommen wird, kann ich nicht feststellen." | Ehrlich sagen — **nie** „gestoppt". Biete an, in einer Minute mit `kimal3 zeigen status` noch einmal nachzusehen. |
176
322
  | „Die Aufnahme ist nicht sauber abgeschlossen: <Grund>." (Rückgabewert 1) | Nenn den Grund und biete eine neue Aufnahme an. |
177
- | „Die Aufnahme ist abgebrochen: <Grund>. …" (Rückgabewert 1) | Freundlich: Der Mensch hat nichts falsch gemacht. Nenn den Grund und biete eine neue Aufnahme an. |
323
+ | „Die Aufnahme ist abgebrochen: <Grund>. …" (Rückgabewert 1) | Freundlich: Der Mensch hat nichts falsch gemacht. Nenn den Grund und biete eine neue Aufnahme an (nennt der Grund eine Freigabe: vorher Schritt 4b). |
178
324
  | „Die Aufnahme ließ sich nicht stoppen …" · „Es läuft eine Aufnahme, die ich hier nicht zuordnen kann …" | `kimal3 zeigen status` ausführen und ehrlich sagen, was es meldet — **nie** „gestoppt". Läuft die Sitzung im falschen Ordner, wechsle in das Projekt der Aufnahme. |
179
325
 
180
326
  ## 9. Auswerten — auf dem Rechner des Menschen
@@ -221,7 +367,7 @@ Dann diese Frage, wörtlich:
221
367
  > damit du vorher hineinsehen kannst? Einverstanden — oder lieber ohne die getippten Stellen?"
222
368
 
223
369
  - **„Öffnen":** in Notepad, wie in Regel 2 (`cmd //c start "" notepad "<voller pfad>"` bzw.
224
- `Start-Process`), mit dem vollen Pfad zur `zeitleiste.md` (Projektordner plus der Pfad aus
370
+ `Start-Process`; auf dem Mac in TextEdit mit `open -e "<voller pfad>"`), mit dem vollen Pfad zur `zeitleiste.md` (Projektordner plus der Pfad aus
225
371
  Schritt 9). Der Mensch liest selbst; du liest nicht mit. Danach dieselbe Frage nach dem
226
372
  Einverständnis noch einmal.
227
373
  - **„Ohne die getippten Stellen":** `kimal3 zeigen auswerten --ohne-getipptes` — mit demselben