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.
- package/coach/de/kimal3-coach.md +1 -1
- package/coach/en/kimal3-coach.md +1 -1
- package/dist/befehle/zeigen-einrichten.js +29 -9
- package/dist/befehle/zeigen-pruefen.js +56 -0
- package/dist/befehle/zeigen-start.js +8 -10
- package/dist/befehle/zeigen.js +20 -8
- package/dist/befehle-katalog-en.js +4 -4
- package/dist/befehle-katalog.js +2 -2
- package/dist/befehlswoerter.js +4 -0
- package/dist/kimal3.js +2 -0
- package/dist/texte/zeigen.js +54 -2
- package/dist/zeigen-freigaben.js +65 -0
- package/dist/zeigen-rechnung.js +72 -19
- package/dist/zeigen-umgebung.js +9 -13
- package/package.json +1 -1
- package/skill/commands/k3zeigen.md +154 -8
- package/skill/en/commands/k3show.md +150 -8
- package/zeigen/gemeinsam.py +86 -4
- package/zeigen/starter.py +24 -8
- package/zeigen/werkzeug.py +17 -9
- package/zeigen/zeitleiste.py +59 -16
package/coach/de/kimal3-coach.md
CHANGED
|
@@ -182,7 +182,7 @@ Das Board in der App zeigt nur, was du meldest: Wer nicht meldet, lässt eine Ka
|
|
|
182
182
|
6. **`/k3plan`:** Specs gegen den Code prüfen und jede Abweichung einzeln melden — dort steht, wie. **Prüfen ist Arbeit:** Eine Story mit offenen Gegenproben (Spalte „Claude-Test offen“), die du gegen den Code prüfst, meldest du vorher als „in Arbeit“, mit `"pruefen":true` — so kommt die Karte dabei nicht ins Gespräch. Stories in „Dein Test“ oder „Fertig“ meldest du beim Abgleich nicht neu.
|
|
183
183
|
7. **Feierabend:** den Tag abgleichen — dort steht, wie.
|
|
184
184
|
|
|
185
|
-
🔑 **Bleibt eine Story unfertig, wenn du aufhörst** (am Ende von `/k3plan` oder im Feierabend), meldest du sie mit `--ohne-sitzung` (`kimal3 plan melde --ohne-sitzung`): Ihr Plan-Stand bleibt `in_arbeit`, aber der Punkt am Projekt leuchtet nicht weiter, obwohl das Fenster offen bleibt — auf dem Board steht sie dann in „
|
|
185
|
+
🔑 **Bleibt eine Story unfertig, wenn du aufhörst** (am Ende von `/k3plan` oder im Feierabend), meldest du sie mit `--ohne-sitzung` (`kimal3 plan melde --ohne-sitzung`): Ihr Plan-Stand bleibt `in_arbeit`, aber der Punkt am Projekt leuchtet nicht weiter, obwohl das Fenster offen bleibt — auf dem Board steht sie dann in „Plan“ als angefangen.
|
|
186
186
|
|
|
187
187
|
„Gebaut“ meldest du erst nach einer Gegenprobe, die in dieser Sitzung gelaufen ist, nie aus dem Gedächtnis.
|
|
188
188
|
- **Subagenten melden nie.** Der Mod erinnert nur dich, nicht sie: Du meldest „in Arbeit“ **vor** dem Auftrag an einen Subagenten, der
|
package/coach/en/kimal3-coach.md
CHANGED
|
@@ -181,7 +181,7 @@ The board in the app shows only what you report: if you don't, a card sits in "P
|
|
|
181
181
|
6. **`/k3plan`:** check the specs against the code and report every deviation individually — it says how. **Checking is work:** a story with pending counter-checks (column "Claude test pending") that you check against the code, you report as "in progress" beforehand, with `"pruefen":true` — so the card doesn't come into discussion meanwhile. Stories under "Your test" or "Done" you do not report again during the reconciliation.
|
|
182
182
|
7. **Wrap-up:** reconcile the day — it says how.
|
|
183
183
|
|
|
184
|
-
🔑 **If a story stays unfinished when you stop** (at the end of `/k3plan` or in the wrap-up), you report it with `--no-session` (`kimal3 plan report --no-session`): its plan state stays `in_arbeit`, but the dot at the project stops glowing although the window stays open — on the board it then sits
|
|
184
|
+
🔑 **If a story stays unfinished when you stop** (at the end of `/k3plan` or in the wrap-up), you report it with `--no-session` (`kimal3 plan report --no-session`): its plan state stays `in_arbeit`, but the dot at the project stops glowing although the window stays open — on the board it then sits in "Plan" as started.
|
|
185
185
|
|
|
186
186
|
You report "built" only after a counter-check that ran in this session, never from memory.
|
|
187
187
|
- **Subagents never report.** The mod reminds only you, not them: you report "in progress" **before** the job to a subagent that
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import {
|
|
2
|
+
import { platform } from "node:os";
|
|
3
|
+
import { dirname, posix, win32 } from "node:path";
|
|
3
4
|
import { zerlege } from "../argumente.js";
|
|
4
|
-
import { AUFNEHMER_FASSUNG, aufnehmerArgumente, einrichtPlan, teileAus, uvEinrichtung, } from "../zeigen-rechnung.js";
|
|
5
|
+
import { AUFNEHMER_FASSUNG, aufnehmerArgumente, aufnehmerOrte, einrichtPlan, teileAus, uvEinrichtung, } from "../zeigen-rechnung.js";
|
|
5
6
|
import { LESEN_MS, aufnehmerPython, findeUv, rufeWerkzeug, stillAusfuehren, uvBinOrdner } from "../zeigen-umgebung.js";
|
|
6
7
|
import { vorab } from "./zeigen.js";
|
|
7
8
|
/**
|
|
@@ -21,19 +22,34 @@ const ZEIT_MODELL = 60 * MINUTE;
|
|
|
21
22
|
/** Was jetzt da ist: uv (Suchpfad + bekannte Orte), und vom Aufnehmer selbst, was er hat. */
|
|
22
23
|
function bestand() {
|
|
23
24
|
const p = aufnehmerPython();
|
|
24
|
-
return { teile: teileAus(findeUv()?.uv ?? null, p === null ? null : rufeWerkzeug(p, ["teile"], null, LESEN_MS)), umgebungDa: p !== null };
|
|
25
|
+
return { teile: teileAus(findeUv()?.uv ?? null, p === null ? null : rufeWerkzeug(p, ["teile"], null, LESEN_MS), platform()), umgebungDa: p !== null };
|
|
26
|
+
}
|
|
27
|
+
/** Der Paketmanager fuer uv: Windows winget; Mac das erste brew, das antwortet (Apple-Silicon-, Intel-Ort, Suchpfad). */
|
|
28
|
+
function paketmanager() {
|
|
29
|
+
if (platform() === "win32")
|
|
30
|
+
return stillAusfuehren("winget", ["--version"], LESEN_MS) ? "winget" : null; // kein-anzeigetext: Befehl
|
|
31
|
+
// kein-anzeigetext: Befehl
|
|
32
|
+
return ["/opt/homebrew/bin/brew", "/usr/local/bin/brew", "brew"].find((brew) => stillAusfuehren(brew, ["--version"], LESEN_MS)) ?? null;
|
|
25
33
|
}
|
|
26
34
|
function richteUvEin() {
|
|
27
|
-
const
|
|
28
|
-
|
|
35
|
+
const pm = paketmanager();
|
|
36
|
+
const { befehl, argumente, umgebung } = uvEinrichtung(platform(), pm);
|
|
37
|
+
stillAusfuehren(befehl, argumente, ZEIT_UV, umgebung);
|
|
29
38
|
// Der Suchpfad dieser Sitzung ist noch der alte: findeUv sieht auch an den bekannten Orten nach.
|
|
39
|
+
if (findeUv() !== null)
|
|
40
|
+
return true;
|
|
41
|
+
// Mac: brew gescheitert (kein Schreibrecht, kein Netz fuer die Formel) -> einmal der offizielle Installer.
|
|
42
|
+
if (pm === null || platform() !== "darwin")
|
|
43
|
+
return false;
|
|
44
|
+
const ersatz = uvEinrichtung("darwin", null);
|
|
45
|
+
stillAusfuehren(ersatz.befehl, ersatz.argumente, ZEIT_UV, ersatz.umgebung);
|
|
30
46
|
return findeUv() !== null;
|
|
31
47
|
}
|
|
32
48
|
function richteAufnehmerEin(umgebungDa) {
|
|
33
49
|
const uv = findeUv();
|
|
34
50
|
if (uv === null)
|
|
35
51
|
return false;
|
|
36
|
-
stillAusfuehren(uv.uv, aufnehmerArgumente(umgebungDa), ZEIT_AUFNEHMER);
|
|
52
|
+
stillAusfuehren(uv.uv, aufnehmerArgumente(umgebungDa, platform()), ZEIT_AUFNEHMER);
|
|
37
53
|
return bestand().teile.aufnehmer === AUFNEHMER_FASSUNG;
|
|
38
54
|
}
|
|
39
55
|
function richteFfmpegEin() {
|
|
@@ -42,9 +58,13 @@ function richteFfmpegEin() {
|
|
|
42
58
|
if (uv === null || p === null)
|
|
43
59
|
return false;
|
|
44
60
|
const bin = uvBinOrdner(uv.uv);
|
|
45
|
-
// `capture
|
|
46
|
-
const
|
|
47
|
-
|
|
61
|
+
// `capture` liegt im Programmordner von uv und neben dem Python des Aufnehmers; der erste, den es gibt.
|
|
62
|
+
const system = platform();
|
|
63
|
+
const pfad = system === "win32" ? win32 : posix;
|
|
64
|
+
const namen = aufnehmerOrte(system, null, process.env, "").at(0)?.captureNamen ?? []; // Namen sind vom Ort unabhaengig
|
|
65
|
+
const capture = [bin, dirname(p.python)]
|
|
66
|
+
.flatMap((ordner) => (ordner === null ? [] : namen.map((n) => pfad.join(ordner, n))))
|
|
67
|
+
.find((d) => existsSync(d));
|
|
48
68
|
if (capture === undefined)
|
|
49
69
|
return false;
|
|
50
70
|
stillAusfuehren(capture, ["install-ffmpeg"], ZEIT_FFMPEG); // kein-anzeigetext: Befehl
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { platform } from "node:os";
|
|
3
|
+
import { zerlege } from "../argumente.js";
|
|
4
|
+
import { EINSTELLUNGS_SEITE, freigabeApp, freigabeAus, freigabenAusgang } from "../zeigen-freigaben.js";
|
|
5
|
+
import { LESEN_MS, aufnehmerPython, rufeWerkzeug } from "../zeigen-umgebung.js";
|
|
6
|
+
import { freigabenZeilen } from "../texte/zeigen.js";
|
|
7
|
+
import { vorab } from "./zeigen.js";
|
|
8
|
+
/**
|
|
9
|
+
* `kimal3 zeigen pruefen` / `kimal3 show check` (Spec 2026-10-24-k3zeigen-mac-design.md, US-M3): welche der vier
|
|
10
|
+
* macOS-Freigaben fehlen. `--anfragen` laesst macOS fragen, `--oeffnen` oeffnet die Seite der Systemeinstellungen.
|
|
11
|
+
* 🔴 Vom Werkzeug werden nur Wahrheitswerte gelesen (`freigabenAusgang`); keine Zeile gibt etwas Fremdes weiter.
|
|
12
|
+
*/
|
|
13
|
+
const ANFRAGE_MS = 90_000; // macOS wartet auf den Klick des Menschen
|
|
14
|
+
export async function zeigenPruefen(rest) {
|
|
15
|
+
const lage = vorab(rest, (t) => t.helpPruefen);
|
|
16
|
+
if (typeof lage === "number")
|
|
17
|
+
return lage;
|
|
18
|
+
const { s, t } = lage;
|
|
19
|
+
if (platform() === "win32") {
|
|
20
|
+
console.log(t.freigabenUnnoetig);
|
|
21
|
+
return 0;
|
|
22
|
+
}
|
|
23
|
+
const z = zerlege(rest, ["oeffnen", "anfragen"], s);
|
|
24
|
+
const oeffnen = z.ok ? z.werte.optionen.oeffnen : undefined;
|
|
25
|
+
const anfragen = z.ok ? z.werte.optionen.anfragen : undefined;
|
|
26
|
+
const oeffnenF = freigabeAus(oeffnen);
|
|
27
|
+
const anfragenF = freigabeAus(anfragen);
|
|
28
|
+
// Unbekannter Wert, beide Schalter zugleich oder ein Zerlegefehler: die Hilfe, nichts wird getan.
|
|
29
|
+
if (!z.ok || (oeffnen !== undefined && oeffnenF === null) || (anfragen !== undefined && anfragenF === null)
|
|
30
|
+
|| (oeffnen !== undefined && anfragen !== undefined)) {
|
|
31
|
+
console.error(`${z.ok ? "" : `${z.meldung}\n`}${t.helpPruefen}`);
|
|
32
|
+
return 1;
|
|
33
|
+
}
|
|
34
|
+
// Oeffnen braucht den Aufnehmer nicht und prueft danach nicht.
|
|
35
|
+
if (oeffnenF !== null) {
|
|
36
|
+
const r = spawnSync("open", [EINSTELLUNGS_SEITE[oeffnenF]], { stdio: "ignore" }); // kein-anzeigetext: macOS-Programm
|
|
37
|
+
if (r.error !== undefined || r.status !== 0) {
|
|
38
|
+
console.error(t.freigabeNichtGeoeffnet);
|
|
39
|
+
return 1;
|
|
40
|
+
}
|
|
41
|
+
console.log(t.freigabeGeoeffnet(t.freigabeName[oeffnenF]));
|
|
42
|
+
return 0;
|
|
43
|
+
}
|
|
44
|
+
const p = aufnehmerPython();
|
|
45
|
+
if (p === null) {
|
|
46
|
+
console.error(t.nichtEingerichtet);
|
|
47
|
+
return 1;
|
|
48
|
+
}
|
|
49
|
+
const antwort = anfragenF === null
|
|
50
|
+
? rufeWerkzeug(p, ["freigaben"], null, LESEN_MS)
|
|
51
|
+
: rufeWerkzeug(p, ["freigaben", "--anfragen", anfragenF], null, ANFRAGE_MS);
|
|
52
|
+
const { stand } = freigabenAusgang(antwort);
|
|
53
|
+
const { zeilen, code } = freigabenZeilen(t, freigabeApp(process.env), stand);
|
|
54
|
+
(code === 0 ? console.log : console.error)(zeilen.join("\n"));
|
|
55
|
+
return code;
|
|
56
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { platform } from "node:os";
|
|
2
3
|
import { join } from "node:path";
|
|
3
4
|
import { trenneNamenUndOptionen, zerlege } from "../argumente.js";
|
|
4
|
-
import {
|
|
5
|
+
import { nenntProtokoll } from "../zeigen-freigaben.js";
|
|
6
|
+
import { einrichtPlan, fehlerGrund, teileAus } from "../zeigen-rechnung.js";
|
|
5
7
|
import { LESEN_MS, aufnehmerPython, leseStarter, rufeWerkzeug, schreibeNotiz, starteStarter, starterFakt, uvFassung } from "../zeigen-umgebung.js";
|
|
6
|
-
import { ermittleZustand, grundSatz,
|
|
8
|
+
import { ermittleZustand, grundSatz, ortHier, uhrzeit, vorab, zeigeOrdner } from "./zeigen.js";
|
|
7
9
|
/**
|
|
8
10
|
* `kimal3 zeigen start "<Satz>" [--hoechstens N]` (Spec US-3, US-4, US-5). Reihenfolge: Ort -> laeuft schon etwas? ->
|
|
9
11
|
* eingerichtet? -> Ordner -> Starter abgehaengt -> warten, bis er "laeuft, Sitzung …" meldet.
|
|
@@ -81,12 +83,8 @@ export async function zeigenStart(rest) {
|
|
|
81
83
|
}
|
|
82
84
|
}
|
|
83
85
|
const teile = p === null ? null : rufeWerkzeug(p, ["teile"], null, LESEN_MS);
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
aufnehmer: gueltigeFassung(teile.daten.aufnehmer),
|
|
87
|
-
ffmpeg: teile.daten.ffmpeg === true,
|
|
88
|
-
modell: teile.daten.modell === true,
|
|
89
|
-
}).length > 0;
|
|
86
|
+
// teileAus: auf dem Mac zaehlt ein Aufnehmer ohne AVFoundation als nicht eingerichtet (Spec US-M2)
|
|
87
|
+
const fehlt = !teile?.ok || einrichtPlan(teileAus(uvFassung(), teile, platform())).length > 0;
|
|
90
88
|
if (p === null || fehlt) {
|
|
91
89
|
console.error(t.nichtEingerichtet);
|
|
92
90
|
return 1;
|
|
@@ -125,8 +123,8 @@ export async function zeigenStart(rest) {
|
|
|
125
123
|
/* ohne Bremse meldet unten "nicht bestaetigt" */
|
|
126
124
|
}
|
|
127
125
|
bericht = await warteAufStarter(ordner, WARTEN_ENDE_MS, (f) => f !== null && !laeuftNoch(f.zustand));
|
|
128
|
-
const grund = bericht?.grund ?? fehlerGrund(liesProtokoll(protokoll));
|
|
129
|
-
console.error(t.nichtGestartet(grundSatz(t, grund), protokoll));
|
|
126
|
+
const grund = bericht?.grund ?? fehlerGrund(liesProtokoll(protokoll), platform());
|
|
127
|
+
console.error(nenntProtokoll(grund) ? t.nichtGestartet(grundSatz(t, grund), protokoll) : t.nichtGestartetOhneProtokoll(grundSatz(t, grund)));
|
|
130
128
|
// Ohne Bericht (Starter nie angelaufen) ist das Ende genauso wenig bestaetigt wie bei "laeuft noch".
|
|
131
129
|
if (bericht === null || laeuftNoch(bericht.zustand) || bericht.grund === "nicht-beendet")
|
|
132
130
|
console.error(t.endeUnbestaetigt);
|
package/dist/befehle/zeigen.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import { platform } from "node:os";
|
|
2
|
+
import { platform, release } from "node:os";
|
|
3
3
|
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
4
4
|
import { schalterOhneWert, trenneNamenUndOptionen, zerlege } from "../argumente.js";
|
|
5
5
|
import { sprache } from "../sprache.js";
|
|
6
|
+
import { freigabeApp } from "../zeigen-freigaben.js";
|
|
6
7
|
import { ZEIGEN_TEXTE } from "../texte/zeigen.js";
|
|
7
|
-
import { AUFNEHMER_FASSUNG, aufnahmeOrt, aufnahmeZustand, bildName, dauerText, gueltigeFassung, starterLebt, stoppAusgang, zeitAusText, zustandOhneAufnehmer, } from "../zeigen-rechnung.js";
|
|
8
|
+
import { AUFNEHMER_FASSUNG, aufnahmeOrt, aufnahmeZustand, bildName, dauerText, gueltigeFassung, macosFassung, starterLebt, stoppAusgang, teileAus, zeitAusText, zustandOhneAufnehmer, } from "../zeigen-rechnung.js";
|
|
8
9
|
import { LESEN_MS, STOPPEN_MS, aufnehmerPython, juengsterOrdner, leseNotiz, leseStarter, loescheNotiz, rufeWerkzeug, starterFakt, uvFassung, } from "../zeigen-umgebung.js";
|
|
9
10
|
/** `--help` (auch auf dem Mac), dann die Plattform. Eine Zahl = fertig, sonst die Lage fuer den Befehl. */
|
|
10
11
|
export function vorab(rest, hilfe) {
|
|
@@ -14,8 +15,17 @@ export function vorab(rest, hilfe) {
|
|
|
14
15
|
console.log(hilfe(t));
|
|
15
16
|
return 0;
|
|
16
17
|
}
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
const system = platform();
|
|
19
|
+
if (system === "win32")
|
|
20
|
+
return { s, t };
|
|
21
|
+
if (system !== "darwin") {
|
|
22
|
+
console.error(t.nurWindowsUndMac);
|
|
23
|
+
return 1;
|
|
24
|
+
}
|
|
25
|
+
// Mindestens macOS 13 (Darwin-Kern 22); ist die Fassung nicht lesbar, sagt der Satz es ohne Zahl und lehnt ab.
|
|
26
|
+
const mac = macosFassung(release());
|
|
27
|
+
if (mac === null || mac < 13) {
|
|
28
|
+
console.error(t.macZuAlt(mac));
|
|
19
29
|
return 1;
|
|
20
30
|
}
|
|
21
31
|
return { s, t };
|
|
@@ -38,8 +48,6 @@ export function uhrzeit(sek) {
|
|
|
38
48
|
export function grundSatz(t, code) {
|
|
39
49
|
return typeof code === "string" && Object.hasOwn(t.gruende, code) ? t.gruende[code] : t.gruende.unbekannt;
|
|
40
50
|
}
|
|
41
|
-
/** Wohnt seit Task 5 in `zeigen-rechnung.ts` (auch `einrichten` braucht sie); hier weitergereicht fuer `start`. */
|
|
42
|
-
export { gueltigeFassung };
|
|
43
51
|
const istZahl = (w) => typeof w === "number" && Number.isFinite(w);
|
|
44
52
|
const istZaehlung = (w) => istZahl(w) && Number.isInteger(w) && w >= 0;
|
|
45
53
|
/**
|
|
@@ -95,8 +103,10 @@ export async function zeigenStatus(rest) {
|
|
|
95
103
|
zeilen.push(t.teilUnbekannt("aufnehmer"), t.teilUnbekannt("ffmpeg"), t.teilUnbekannt("modell"));
|
|
96
104
|
else {
|
|
97
105
|
const roh = teile.daten.aufnehmer;
|
|
98
|
-
|
|
99
|
-
|
|
106
|
+
// Ueber teileAus: Auf dem Mac gilt ein Aufnehmer ohne AVFoundation als nicht eingerichtet (Spec US-M2) -> "fehlt".
|
|
107
|
+
// Unter Windows ist f genau gueltigeFassung(roh), die Ausgabe also wie bisher.
|
|
108
|
+
const f = teileAus(null, teile, platform()).aufnehmer;
|
|
109
|
+
zeilen.push(roh === null || (f === null && gueltigeFassung(roh) !== null) ? t.aufnehmerFehlt
|
|
100
110
|
: f === null ? t.teilUnbekannt("aufnehmer")
|
|
101
111
|
: f === AUFNEHMER_FASSUNG ? t.aufnehmerDa(f) : t.aufnehmerAlt(f, AUFNEHMER_FASSUNG));
|
|
102
112
|
zeilen.push(t.ffmpeg(teile.daten.ffmpeg === true), t.modell(teile.daten.modell === true));
|
|
@@ -127,6 +137,8 @@ export async function zeigenStatus(rest) {
|
|
|
127
137
|
if (ordner !== null && zustand.letzte === "abgebrochen")
|
|
128
138
|
zeilen.push(t.letzteAbgebrochen(zeigeOrdner(ordner, ort)));
|
|
129
139
|
}
|
|
140
|
+
if (platform() === "darwin")
|
|
141
|
+
zeilen.push(t.freigabenGehenAn(freigabeApp(process.env)));
|
|
130
142
|
if (ort.art === "ort")
|
|
131
143
|
zeilen.push(t.ortHier(ort.aufnahmen));
|
|
132
144
|
else
|
|
@@ -158,7 +158,7 @@ export const BEFEHLE_EN = {
|
|
|
158
158
|
],
|
|
159
159
|
},
|
|
160
160
|
"kimal3 zeigen start": {
|
|
161
|
-
stempel: "
|
|
161
|
+
stempel: "39dd03bd",
|
|
162
162
|
befehl: "kimal3 show start",
|
|
163
163
|
tippen: "/k3show",
|
|
164
164
|
terminal: 'kimal3 show start "Send the open quotes to my boss every Monday"',
|
|
@@ -168,11 +168,11 @@ export const BEFEHLE_EN = {
|
|
|
168
168
|
"You do a task once on screen and say out loud what you are doing and why. Claude guides you through it: first the briefing on what gets recorded, then the recording, then the evaluation on your computer.",
|
|
169
169
|
"All screens, sound, clicks and keys are recorded — so don't type a password. The recording lies in the project under material/aufnahmen/ and never ends up in Git; it stops by itself after 15 minutes at the latest.",
|
|
170
170
|
"Claude asks you before reading any of it: only after your yes does the timeline go to Anthropic. At the end the task is written down in the project's plan folder, and Claude suggests deleting the recording.",
|
|
171
|
-
"Windows
|
|
171
|
+
"Windows and Mac (macOS 13 or later). On the Mac, Claude first checks the four macOS permissions.",
|
|
172
172
|
],
|
|
173
173
|
},
|
|
174
174
|
"kimal3 zeigen status": {
|
|
175
|
-
stempel: "
|
|
175
|
+
stempel: "5d79830b",
|
|
176
176
|
befehl: "kimal3 show status",
|
|
177
177
|
tippen: "! kimal3 show status",
|
|
178
178
|
terminal: "kimal3 show status",
|
|
@@ -181,7 +181,7 @@ export const BEFEHLE_EN = {
|
|
|
181
181
|
details: [
|
|
182
182
|
"Shows two blocks: what is set up (uv, recorder, FFmpeg, speech model) and whether a recording of your screen is running — with start time, folder and the time at which it stops by itself at the latest.",
|
|
183
183
|
"If it can't tell whether something is being recorded, it says exactly that, with exit code 1 — it then never claims that nothing is running.",
|
|
184
|
-
"It only reads and changes nothing. Windows
|
|
184
|
+
"It only reads and changes nothing. Windows and Mac (macOS 13 or later).",
|
|
185
185
|
],
|
|
186
186
|
},
|
|
187
187
|
"kimal3 wache": {
|
package/dist/befehle-katalog.js
CHANGED
|
@@ -222,7 +222,7 @@ export const BEFEHLE = [
|
|
|
222
222
|
"Du machst eine Aufgabe einmal am Bildschirm vor und sagst dabei laut, was du tust und warum. Claude führt dich durch: vorher die Ansage, was aufgenommen wird, dann die Aufnahme, danach das Auswerten auf deinem Rechner.",
|
|
223
223
|
"Aufgenommen werden alle Bildschirme, Ton, Klicks und Tasten — tippe deshalb kein Passwort. Die Aufnahme liegt im Projekt unter material/aufnahmen/ und landet nie in Git; spätestens nach 15 Minuten stoppt sie von selbst.",
|
|
224
224
|
"Bevor Claude etwas davon liest, fragt er dich: Erst nach deinem Ja geht die Zeitleiste an Anthropic. Am Ende steht die Aufgabe in plan/aufgabe-vorgefuehrt.md, und Claude schlägt vor, die Aufnahme zu löschen.",
|
|
225
|
-
"
|
|
225
|
+
"Für Windows und den Mac (ab macOS 13). Auf dem Mac prüft Claude vorher die vier Freigaben von macOS.",
|
|
226
226
|
],
|
|
227
227
|
},
|
|
228
228
|
{
|
|
@@ -235,7 +235,7 @@ export const BEFEHLE = [
|
|
|
235
235
|
details: [
|
|
236
236
|
"Zeigt zwei Blöcke: was eingerichtet ist (uv, Aufnehmer, FFmpeg, Sprachmodell) und ob gerade eine Aufnahme von deinem Bildschirm läuft — mit Startzeit, Ordner und der Uhrzeit, zu der sie spätestens von selbst stoppt.",
|
|
237
237
|
"Kann es nicht feststellen, ob aufgenommen wird, sagt es genau das, mit Rückgabewert 1 — es behauptet dann nie, dass nichts läuft.",
|
|
238
|
-
"Es liest nur und ändert nichts.
|
|
238
|
+
"Es liest nur und ändert nichts. Für Windows und den Mac (ab macOS 13).",
|
|
239
239
|
],
|
|
240
240
|
},
|
|
241
241
|
/*
|
package/dist/befehlswoerter.js
CHANGED
|
@@ -29,6 +29,7 @@ export const BEFEHLSWOERTER = {
|
|
|
29
29
|
"zeigen auswerten": { de: "zeigen auswerten", en: "show evaluate" }, // kein-anzeigetext: Befehlswörter (Spec k3zeigen)
|
|
30
30
|
"zeigen bild": { de: "zeigen bild", en: "show picture" }, // kein-anzeigetext: Befehlswörter (Spec k3zeigen)
|
|
31
31
|
"zeigen status": { de: "zeigen status", en: "show status" }, // kein-anzeigetext: Befehlswörter (Spec k3zeigen)
|
|
32
|
+
"zeigen pruefen": { de: "zeigen pruefen", en: "show check" }, // kein-anzeigetext: Befehlswörter (Spec k3zeigen-mac)
|
|
32
33
|
};
|
|
33
34
|
/**
|
|
34
35
|
* Welcher Befehl steht vorne in `argv` -- und was bleibt dahinter?
|
|
@@ -78,6 +79,9 @@ export const SCHALTER_EN = {
|
|
|
78
79
|
"at-most": "hoechstens",
|
|
79
80
|
language: "sprache",
|
|
80
81
|
"without-typed": "ohne-getipptes",
|
|
82
|
+
// `kimal3 show check` (Spec 2026-10-24-k3zeigen-mac-design.md)
|
|
83
|
+
open: "oeffnen",
|
|
84
|
+
ask: "anfragen",
|
|
81
85
|
// `kimal3 plan upload` (Spec 2026-10-21-projektseite-planung, US-11); `--overwrite` steht schon oben.
|
|
82
86
|
"dry-run": "probe",
|
|
83
87
|
// `kimal3 project connect` (Board in Echtzeit, Task 7)
|
package/dist/kimal3.js
CHANGED
|
@@ -45,6 +45,7 @@ import { projektVerbinden } from "./befehle/projekt-verbinden.js";
|
|
|
45
45
|
import { skillDatei, skillInstallBefehl } from "./befehle/skill-install.js";
|
|
46
46
|
import { wache, wacheSchalten } from "./befehle/wache.js";
|
|
47
47
|
import { zeigenAuswerten, zeigenBild, zeigenStatus, zeigenStopp } from "./befehle/zeigen.js";
|
|
48
|
+
import { zeigenPruefen } from "./befehle/zeigen-pruefen.js";
|
|
48
49
|
import { zeigenStart } from "./befehle/zeigen-start.js";
|
|
49
50
|
import { zeigenEinrichten } from "./befehle/zeigen-einrichten.js";
|
|
50
51
|
/** Eine Meldung pro Programmlauf -- s. "Einmal-Riegel" im Block darunter. */
|
|
@@ -527,6 +528,7 @@ async function fuehreAus(name, rest) {
|
|
|
527
528
|
case "zeigen auswerten": return zeigenAuswerten(rest);
|
|
528
529
|
case "zeigen bild": return zeigenBild(rest);
|
|
529
530
|
case "zeigen status": return zeigenStatus(rest);
|
|
531
|
+
case "zeigen pruefen": return zeigenPruefen(rest);
|
|
530
532
|
case "wache an": return allein ? wacheSchalten(true) : null;
|
|
531
533
|
case "wache aus": return allein ? wacheSchalten(false) : null;
|
|
532
534
|
case "wache":
|
package/dist/texte/zeigen.js
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
|
+
import { FREIGABEN } from "../zeigen-freigaben.js";
|
|
1
2
|
const TEIL_DE = { aufnehmer: "Aufnehmer", ffmpeg: "FFmpeg", modell: "Sprachmodell" };
|
|
2
3
|
const TEIL_EN = { aufnehmer: "Recorder", ffmpeg: "FFmpeg", modell: "Speech model" };
|
|
3
4
|
const SCHRITT_DE = { uv: "uv", ...TEIL_DE };
|
|
4
5
|
const SCHRITT_EN = { uv: "uv", aufnehmer: "recorder", ffmpeg: "FFmpeg", modell: "speech model" };
|
|
5
6
|
const mehrzahl = (n, eins, viele) => `${n} ${n === 1 ? eins : viele}`;
|
|
6
7
|
const de = {
|
|
7
|
-
|
|
8
|
+
nurWindowsUndMac: "`kimal3 zeigen` gibt es für Windows und den Mac.",
|
|
9
|
+
macZuAlt: (n) => `Für Aufnahmen braucht es macOS 13 oder neuer${n === null ? "" : ` — dieser Mac hat macOS ${n}`}.`,
|
|
10
|
+
freigabenGehenAn: (app) => `Freigaben gehen an: ${app.art === "claude-app" ? "Claude (Desktop-App)"
|
|
11
|
+
: app.art === "ssh" ? "niemanden — über SSH kann macOS keine Freigaben geben"
|
|
12
|
+
: app.art === "terminal" && app.name !== null ? app.name : "die App, aus der du Claude gestartet hast"}`,
|
|
8
13
|
helpStatus: "\n kimal3 zeigen status\n\n Zeigt, ob der Aufnehmer eingerichtet ist und ob gerade aufgenommen wird.\n Liest nur, ändert nichts.\n",
|
|
9
14
|
helpStart: "\n kimal3 zeigen start \"<deine Aufgabe in einem Satz>\" [--hoechstens <minuten>]\n\n Startet eine Aufnahme von Bildschirm, Ton, Klicks und Tasten im Ordner\n material/aufnahmen/ deines Projekts. Sie stoppt spätestens nach 15 Minuten\n von selbst (--hoechstens: weniger, 1 bis 15).\n",
|
|
10
15
|
helpStopp: "\n kimal3 zeigen stopp\n\n Stoppt die laufende Aufnahme und nennt nur Zahlen: Dauer, Klicks, Tasten, Ton.\n",
|
|
11
16
|
helpAuswerten: "\n kimal3 zeigen auswerten [<ordner>] [--sprache de|en] [--ohne-getipptes]\n\n Macht aus der Aufnahme auf diesem Rechner eine Zeitleiste (zeitleiste.md):\n was gesagt, geklickt und getippt wurde. Ohne Ordner: die jüngste Aufnahme\n des Projekts. --ohne-getipptes lässt alles Getippte aus.\n",
|
|
12
17
|
helpBild: "\n kimal3 zeigen bild <m:ss> [<ordner>]\n\n Legt ein Bildschirmfoto der Aufnahme zu diesem Zeitpunkt in bilder/ ab\n (höchstens 1600 Pixel breit). Ohne Ordner: die jüngste Aufnahme des Projekts.\n",
|
|
18
|
+
helpPruefen: "\n kimal3 zeigen pruefen\n kimal3 zeigen pruefen --anfragen <bildschirm|eingabe|bedienungshilfen|mikrofon>\n kimal3 zeigen pruefen --oeffnen <bildschirm|eingabe|bedienungshilfen|mikrofon>\n\n Nur auf dem Mac: zeigt, welche der vier Freigaben für Aufnahmen da sind.\n --anfragen lässt macOS nach einer Freigabe fragen, --oeffnen öffnet ihre Seite\n in den Systemeinstellungen. Unter Windows braucht es keine.\n",
|
|
13
19
|
helpEinrichten: "\n kimal3 zeigen einrichten\n\n Richtet einmal ein, was für Aufnahmen fehlt: uv, den Aufnehmer, FFmpeg und das\n Sprachmodell (zusammen etwa 2,1 GB). Nur in deinem Benutzerordner, ohne\n Adminrechte. Was schon da ist, wird nicht noch einmal geladen.\n",
|
|
14
20
|
schrittUv: "uv wird eingerichtet …",
|
|
15
21
|
schrittAufnehmer: (fassung) => `Aufnehmer ${fassung} wird eingerichtet …`,
|
|
@@ -48,6 +54,7 @@ const de = {
|
|
|
48
54
|
ordnerNichtAnlegbar: (ordner) => `Den Aufnahmeordner kann ich nicht anlegen: ${ordner}`,
|
|
49
55
|
laeuftJetzt: (ordner, ende) => `Die Aufnahme läuft (Ordner \`${ordner}\`), stoppt spätestens um ${ende}.`,
|
|
50
56
|
nichtGestartet: (grund, protokoll) => `Die Aufnahme ist nicht gestartet: ${grund}. Protokoll: ${protokoll}`,
|
|
57
|
+
nichtGestartetOhneProtokoll: (grund) => `Die Aufnahme ist nicht gestartet: ${grund}.`,
|
|
51
58
|
endeUnbestaetigt: "Ob der Aufnehmer noch läuft, sagt `kimal3 zeigen status`.",
|
|
52
59
|
keineAufnahmeLaeuft: "Es läuft keine Aufnahme.",
|
|
53
60
|
zahlen: (dauer, klicks, tasten, ton) => `${dauer} Minuten, ${mehrzahl(klicks, "Klick", "Klicks")}, ${mehrzahl(tasten, "Taste", "Tasten")}, ${ton ? "Ton ist da" : "kein Ton"}.`,
|
|
@@ -74,6 +81,15 @@ const de = {
|
|
|
74
81
|
zeitFalsch: (wert) => `„${wert}" verstehe ich nicht als Zeitpunkt — bitte so: 0:26 oder 1:02:05.`,
|
|
75
82
|
bildFertig: (datei) => `Bild: ${datei}`,
|
|
76
83
|
bildFehler: (grund) => `Das Bild ist nicht entstanden: ${grund}.`,
|
|
84
|
+
freigabenUnnoetig: "Unter Windows braucht es keine Freigaben.",
|
|
85
|
+
freigabeAppName: (app) => (app.art === "claude-app" || app.art === "terminal") && app.name !== null ? app.name : "diese App",
|
|
86
|
+
freigabenAlleDa: (app) => `Alle vier Freigaben für ${app} sind da.`,
|
|
87
|
+
freigabenKopf: (app) => `Freigaben für ${app}:`,
|
|
88
|
+
freigabeName: { bildschirm: "Bildschirm- & Systemaudioaufnahme", eingabe: "Eingabeüberwachung", bedienungshilfen: "Bedienungshilfen", mikrofon: "Mikrofon" },
|
|
89
|
+
freigabeStand: { da: "da", fehlt: "fehlt", unbekannt: "kann ich nicht feststellen" },
|
|
90
|
+
freigabenUnbekannt: "Ob die Freigaben da sind, kann ich nicht feststellen.",
|
|
91
|
+
freigabeGeoeffnet: (name) => `Ich habe ‚${name}' in den Systemeinstellungen geöffnet.`,
|
|
92
|
+
freigabeNichtGeoeffnet: "Die Systemeinstellungen ließen sich nicht öffnen.",
|
|
77
93
|
gruende: {
|
|
78
94
|
"ffmpeg-fehlt": "FFmpeg fehlt — `kimal3 zeigen einrichten` holt es",
|
|
79
95
|
"kein-mikrofon": "ich finde kein Mikrofon",
|
|
@@ -92,16 +108,25 @@ const de = {
|
|
|
92
108
|
unvollstaendig: "das Sprachmodell ist nicht vollständig angekommen",
|
|
93
109
|
"ordner-fehlt": "der Aufnahmeordner fehlt",
|
|
94
110
|
"schreiben-gescheitert": "die Zeitleiste ließ sich nicht schreiben",
|
|
111
|
+
"freigabe-bildschirm": "es fehlt die Freigabe Bildschirm- & Systemaudioaufnahme — `kimal3 zeigen pruefen` zeigt, was fehlt",
|
|
112
|
+
"freigabe-eingabe": "es fehlt die Freigabe Eingabeüberwachung — `kimal3 zeigen pruefen` zeigt, was fehlt",
|
|
113
|
+
"freigabe-bedienungshilfen": "es fehlt die Freigabe Bedienungshilfen — `kimal3 zeigen pruefen` zeigt, was fehlt",
|
|
114
|
+
"abgriff-abgeschaltet": "macOS hat das Mitlesen von Maus und Tastatur abgeschaltet — eine neue Aufnahme hilft meist",
|
|
95
115
|
unbekannt: "den Grund kenne ich nicht",
|
|
96
116
|
},
|
|
97
117
|
};
|
|
98
118
|
const en = {
|
|
99
|
-
|
|
119
|
+
nurWindowsUndMac: "`kimal3 show` is available on Windows and the Mac.",
|
|
120
|
+
macZuAlt: (n) => `Recording needs macOS 13 or later${n === null ? "" : ` — this Mac has macOS ${n}`}.`,
|
|
121
|
+
freigabenGehenAn: (app) => `Permissions go to: ${app.art === "claude-app" ? "Claude (desktop app)"
|
|
122
|
+
: app.art === "ssh" ? "nobody — macOS can't grant permissions over SSH"
|
|
123
|
+
: app.art === "terminal" && app.name !== null ? app.name : "the app you started Claude from"}`,
|
|
100
124
|
helpStatus: "\n kimal3 show status\n\n Shows whether the recorder is set up and whether a recording is running.\n Only reads, changes nothing.\n",
|
|
101
125
|
helpStart: "\n kimal3 show start \"<your task in one sentence>\" [--at-most <minutes>]\n\n Starts a recording of screen, sound, clicks and keys in your project's\n material/aufnahmen/ folder. It stops by itself after 15 minutes at the latest\n (--at-most: less, 1 to 15).\n",
|
|
102
126
|
helpStopp: "\n kimal3 show stop\n\n Stops the running recording and reports numbers only: length, clicks, keys, sound.\n",
|
|
103
127
|
helpAuswerten: "\n kimal3 show evaluate [<folder>] [--language de|en] [--without-typed]\n\n Turns the recording into a timeline on this computer (zeitleiste.md):\n what was said, clicked and typed. Without a folder: the project's latest\n recording. --without-typed leaves out everything typed.\n",
|
|
104
128
|
helpBild: "\n kimal3 show picture <m:ss> [<folder>]\n\n Saves a screenshot of the recording at that moment in bilder/\n (at most 1600 pixels wide). Without a folder: the project's latest recording.\n",
|
|
129
|
+
helpPruefen: "\n kimal3 show check\n kimal3 show check --ask <screen|input|accessibility|microphone>\n kimal3 show check --open <screen|input|accessibility|microphone>\n\n Mac only: shows which of the four permissions for recordings are in place.\n --ask makes macOS ask for a permission, --open opens its page in System\n Settings. Windows needs none.\n",
|
|
105
130
|
helpEinrichten: "\n kimal3 show setup\n\n Sets up once what recordings still need: uv, the recorder, FFmpeg and the\n speech model (about 2.1 GB together). Only in your user folder, no admin\n rights. Whatever is already there isn't downloaded again.\n",
|
|
106
131
|
schrittUv: "Setting up uv …",
|
|
107
132
|
schrittAufnehmer: (fassung) => `Setting up recorder ${fassung} …`,
|
|
@@ -140,6 +165,7 @@ const en = {
|
|
|
140
165
|
ordnerNichtAnlegbar: (ordner) => `I can't create the recording folder: ${ordner}`,
|
|
141
166
|
laeuftJetzt: (ordner, ende) => `The recording is running (folder \`${ordner}\`), stops at ${ende} at the latest.`,
|
|
142
167
|
nichtGestartet: (grund, protokoll) => `The recording didn't start: ${grund}. Log: ${protokoll}`,
|
|
168
|
+
nichtGestartetOhneProtokoll: (grund) => `The recording didn't start: ${grund}.`,
|
|
143
169
|
endeUnbestaetigt: "Whether the recorder is still running: `kimal3 show status`.",
|
|
144
170
|
keineAufnahmeLaeuft: "No recording is running.",
|
|
145
171
|
zahlen: (dauer, klicks, tasten, ton) => `${dauer} minutes, ${klicks} ${klicks === 1 ? "click" : "clicks"}, ${tasten} ${tasten === 1 ? "key" : "keys"}, ${ton ? "audio present" : "no audio"}.`,
|
|
@@ -165,6 +191,15 @@ const en = {
|
|
|
165
191
|
zeitFalsch: (wert) => `I don't understand “${wert}” as a point in time — please like this: 0:26 or 1:02:05.`,
|
|
166
192
|
bildFertig: (datei) => `Picture: ${datei}`,
|
|
167
193
|
bildFehler: (grund) => `The picture wasn't created: ${grund}.`,
|
|
194
|
+
freigabenUnnoetig: "Windows needs no permissions.",
|
|
195
|
+
freigabeAppName: (app) => (app.art === "claude-app" || app.art === "terminal") && app.name !== null ? app.name : "this app",
|
|
196
|
+
freigabenAlleDa: (app) => `All four permissions for ${app} are in place.`,
|
|
197
|
+
freigabenKopf: (app) => `Permissions for ${app}:`,
|
|
198
|
+
freigabeName: { bildschirm: "Screen & System Audio Recording", eingabe: "Input Monitoring", bedienungshilfen: "Accessibility", mikrofon: "Microphone" },
|
|
199
|
+
freigabeStand: { da: "in place", fehlt: "missing", unbekannt: "can't tell" },
|
|
200
|
+
freigabenUnbekannt: "I can't tell whether the permissions are in place.",
|
|
201
|
+
freigabeGeoeffnet: (name) => `I opened ‘${name}’ in System Settings.`,
|
|
202
|
+
freigabeNichtGeoeffnet: "System Settings couldn't be opened.",
|
|
168
203
|
gruende: {
|
|
169
204
|
"ffmpeg-fehlt": "FFmpeg is missing — `kimal3 show setup` gets it",
|
|
170
205
|
"kein-mikrofon": "I can't find a microphone",
|
|
@@ -183,7 +218,24 @@ const en = {
|
|
|
183
218
|
unvollstaendig: "the speech model didn't arrive completely",
|
|
184
219
|
"ordner-fehlt": "the recording folder is missing",
|
|
185
220
|
"schreiben-gescheitert": "the timeline could not be written",
|
|
221
|
+
"freigabe-bildschirm": "the Screen & System Audio Recording permission is missing — `kimal3 show check` shows what's missing",
|
|
222
|
+
"freigabe-eingabe": "the Input Monitoring permission is missing — `kimal3 show check` shows what's missing",
|
|
223
|
+
"freigabe-bedienungshilfen": "the Accessibility permission is missing — `kimal3 show check` shows what's missing",
|
|
224
|
+
"abgriff-abgeschaltet": "macOS switched off reading the mouse and keyboard — a new recording usually helps",
|
|
186
225
|
unbekannt: "I don't know the reason",
|
|
187
226
|
},
|
|
188
227
|
};
|
|
189
228
|
export const ZEIGEN_TEXTE = { de, en };
|
|
229
|
+
/**
|
|
230
|
+
* Die Ausgabe von `kimal3 zeigen pruefen` ohne Schalter, rein aus Stand und Saetzen. `code` 0 nur, wenn alle vier da sind;
|
|
231
|
+
* "weiss nicht" (auch bei einzelnen) ist nie "da". Alle vier unbekannt -> ein Satz statt vier gleicher Zeilen.
|
|
232
|
+
*/
|
|
233
|
+
export function freigabenZeilen(t, app, stand) {
|
|
234
|
+
const name = t.freigabeAppName(app);
|
|
235
|
+
if (FREIGABEN.every((f) => stand[f] === "da"))
|
|
236
|
+
return { zeilen: [t.freigabenAlleDa(name)], code: 0 };
|
|
237
|
+
if (FREIGABEN.every((f) => stand[f] === "unbekannt"))
|
|
238
|
+
return { zeilen: [t.freigabenUnbekannt], code: 1 };
|
|
239
|
+
const breite = Math.max(...FREIGABEN.map((f) => t.freigabeName[f].length));
|
|
240
|
+
return { zeilen: [t.freigabenKopf(name), ...FREIGABEN.map((f) => ` ${t.freigabeName[f].padEnd(breite)} ${t.freigabeStand[stand[f]]}`)], code: 1 };
|
|
241
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/** In dieser Reihenfolge werden sie geprueft und gezeigt. */
|
|
2
|
+
export const FREIGABEN = ["bildschirm", "eingabe", "bedienungshilfen", "mikrofon"]; // kein-anzeigetext: Schluessel
|
|
3
|
+
// Beide Wortsaetze gelten in beiden Sprachen (wie die Befehlswoerter: der Mensch soll nicht an der Sprache scheitern).
|
|
4
|
+
const WERTE = {
|
|
5
|
+
bildschirm: "bildschirm", eingabe: "eingabe", bedienungshilfen: "bedienungshilfen", mikrofon: "mikrofon", // kein-anzeigetext: Schalterwerte
|
|
6
|
+
screen: "bildschirm", input: "eingabe", accessibility: "bedienungshilfen", microphone: "mikrofon", // kein-anzeigetext: Schalterwerte
|
|
7
|
+
};
|
|
8
|
+
/** Wert von `--oeffnen`/`--anfragen` -> Freigabe; unbekannt (auch "constructor") -> null. */
|
|
9
|
+
export const freigabeAus = (w) => (w !== undefined && Object.hasOwn(WERTE, w) ? WERTE[w] : null);
|
|
10
|
+
/** Nennt die Absage von `start` das Protokoll? Nicht bei einer fehlenden Freigabe: Die prueft der Starter, bevor er es anlegt. */
|
|
11
|
+
export const nenntProtokoll = (grund) => !(typeof grund === "string" && grund.startsWith("freigabe-")); // kein-anzeigetext: Code-Anfang
|
|
12
|
+
/**
|
|
13
|
+
* Die Antwort von `werkzeug.py freigaben` -> Stand je Freigabe. Nur ein echtes `true` heisst "da", nur ein echtes
|
|
14
|
+
* `false` "fehlt"; alles andere (null, Zahl, "ja", fehlender Schluessel, kaputte Antwort) heisst "weiss nicht" --
|
|
15
|
+
* nie "da" (Ein Fehlschlag sieht nie aus wie ein Erfolg).
|
|
16
|
+
*/
|
|
17
|
+
export function freigabenAusgang(antwort) {
|
|
18
|
+
const roh = antwort.ok ? antwort.daten.freigaben : undefined;
|
|
19
|
+
const quelle = roh !== null && typeof roh === "object" && !Array.isArray(roh) ? roh : {};
|
|
20
|
+
const von = (w) => (w === true ? "da" : w === false ? "fehlt" : "unbekannt");
|
|
21
|
+
const stand = {
|
|
22
|
+
bildschirm: von(quelle.bildschirm), eingabe: von(quelle.eingabe),
|
|
23
|
+
bedienungshilfen: von(quelle.bedienungshilfen), mikrofon: von(quelle.mikrofon),
|
|
24
|
+
};
|
|
25
|
+
return { stand, alleDa: FREIGABEN.every((f) => stand[f] === "da") };
|
|
26
|
+
}
|
|
27
|
+
const BUENDEL = {
|
|
28
|
+
"com.apple.Terminal": "Terminal", // kein-anzeigetext: App-Name
|
|
29
|
+
"com.googlecode.iterm2": "iTerm", // kein-anzeigetext: App-Name
|
|
30
|
+
"com.microsoft.VSCode": "Visual Studio Code", // kein-anzeigetext: App-Name
|
|
31
|
+
"com.todesktop.230313mzl4w4u92": "Cursor", // kein-anzeigetext: App-Name
|
|
32
|
+
"dev.warp.Warp-Stable": "Warp", // kein-anzeigetext: App-Name
|
|
33
|
+
"com.mitchellh.ghostty": "Ghostty", // kein-anzeigetext: App-Name
|
|
34
|
+
};
|
|
35
|
+
const TERM_PROGRAMM = {
|
|
36
|
+
Apple_Terminal: "Terminal", // kein-anzeigetext: App-Name
|
|
37
|
+
"iTerm.app": "iTerm", // kein-anzeigetext: App-Name
|
|
38
|
+
vscode: "Visual Studio Code", // kein-anzeigetext: App-Name
|
|
39
|
+
WarpTerminal: "Warp", // kein-anzeigetext: App-Name
|
|
40
|
+
ghostty: "Ghostty", // kein-anzeigetext: App-Name
|
|
41
|
+
};
|
|
42
|
+
const CLAUDE_APP = "com.anthropic.claudefordesktop"; // kein-anzeigetext: Bundle-ID
|
|
43
|
+
/** Erkennt aus den Umgebungsvariablen, welches Programm die Freigabe braucht. Reihenfolge: Bundle-ID, SSH, TERM_PROGRAM, Claude-App. */
|
|
44
|
+
export function freigabeApp(env) {
|
|
45
|
+
const buendel = env.__CFBundleIdentifier;
|
|
46
|
+
if (buendel === CLAUDE_APP)
|
|
47
|
+
return { art: "claude-app", name: "Claude" }; // kein-anzeigetext: App-Name
|
|
48
|
+
if (buendel !== undefined && Object.hasOwn(BUENDEL, buendel))
|
|
49
|
+
return { art: "terminal", name: BUENDEL[buendel] };
|
|
50
|
+
if (env.SSH_CONNECTION)
|
|
51
|
+
return { art: "ssh", name: null };
|
|
52
|
+
const term = env.TERM_PROGRAM;
|
|
53
|
+
if (term !== undefined && Object.hasOwn(TERM_PROGRAMM, term))
|
|
54
|
+
return { art: "terminal", name: TERM_PROGRAMM[term] };
|
|
55
|
+
if (env.CLAUDE_CODE_ENTRYPOINT === "claude-desktop")
|
|
56
|
+
return { art: "claude-app", name: "Claude" }; // kein-anzeigetext: App-Name
|
|
57
|
+
return { art: "unbekannt", name: null };
|
|
58
|
+
}
|
|
59
|
+
/** Die Seite der Systemeinstellungen, auf der man die Freigabe erteilt. */
|
|
60
|
+
export const EINSTELLUNGS_SEITE = {
|
|
61
|
+
bildschirm: "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture", // kein-anzeigetext: Systemadresse
|
|
62
|
+
eingabe: "x-apple.systempreferences:com.apple.preference.security?Privacy_ListenEvent", // kein-anzeigetext: Systemadresse
|
|
63
|
+
bedienungshilfen: "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility", // kein-anzeigetext: Systemadresse
|
|
64
|
+
mikrofon: "x-apple.systempreferences:com.apple.preference.security?Privacy_Microphone", // kein-anzeigetext: Systemadresse
|
|
65
|
+
};
|