feat(diagnostic): Datenschutz-Schalter von Claude Code pruefen und setzen
Drei Kanaele, ueber die Claude Code zusaetzlich zur eigentlichen Anfrage Daten
verschickt — bisher nur per Hand in der docker-compose.yml abschaltbar, und
niemand konnte sehen, ob sie an sind:
DISABLE_ERROR_REPORTING Stacktraces an einen Fehler-Dienst. Bei Pro/Max ab
CLI 2.1.198 standardmaessig AN.
DISABLE_TELEMETRY Nutzungs-Metriken.
DISABLE_FEEDBACK_COMMAND /feedback sendet sonst die ganze Unterhaltung
inkl. Code — 5 Jahre Aufbewahrung.
Gesetzt wird in ~/.claude/settings.json unter "env". Die Datei ist in den
Proxy-Container gemountet, die Diagnostic erreicht sie ueber den vorhandenen
dockerExec — also kein Anfassen der docker-compose.yml und KEIN Neustart: die
CLI liest die Datei pro Aufruf.
Geprueft wird beides: was in settings.json steht UND was im Prozess wirklich
ankommt. Eine echte Container-Umgebungsvariable gewinnt gegen settings.json —
so ein Eintrag wird darum als "per docker-compose gesetzt" angezeigt und der
Haken gesperrt, statt eine Einstellung anzubieten, die nichts tut.
Geschrieben wird atomar (temp + mv) und nur der env-Block angefasst; bestehende
Einstellungen (tui, theme) bleiben. Sind alle drei abgewaehlt, verschwindet der
env-Block wieder ganz.
Der Hinweis im Panel sagt ausdruecklich, dass das NICHT die Trainings-
Einstellung ist — die steht im Anthropic-Konto und laesst sich hier nicht
umstellen. Link dorthin ist daneben.
12 Pruefungen gegen den echten Proxy-Container: lesen, setzen, Teilmengen,
JSON-Integritaet, Erhalt bestehender Werte, CLI laeuft damit, Abwaehlen raeumt
auf, Ausgangszustand wiederhergestellt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -654,6 +654,31 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<h2>Datenschutz — was Claude Code von sich aus sendet</h2>
|
||||
<div class="card" style="max-width:620px;">
|
||||
<div style="font-size:11px;color:#8888AA;margin-bottom:12px;line-height:1.55;">
|
||||
Drei Kanäle, über die Claude Code <strong>zusätzlich</strong> zur eigentlichen
|
||||
Anfrage Daten verschickt. Gesetzt wird in <code>~/.claude/settings.json</code> —
|
||||
greift bei jeder neuen Anfrage, <strong>kein Neustart nötig</strong>.
|
||||
<br><br>
|
||||
Davon unabhängig ist, ob Anthropic mit deinen Unterhaltungen Modelle
|
||||
trainiert — das steht in deinem Konto unter
|
||||
<a href="https://claude.ai/settings/data-privacy-controls" target="_blank"
|
||||
style="color:#0096FF;">Datenschutz → „Help improve our AI models"</a>
|
||||
und lässt sich hier nicht umstellen.
|
||||
</div>
|
||||
<div id="privacy-flags-list" style="display:flex;flex-direction:column;gap:10px;">
|
||||
<span style="color:#555570;font-size:11px;">(noch nicht geprüft)</span>
|
||||
</div>
|
||||
<div style="display:flex;gap:8px;margin-top:14px;flex-wrap:wrap;">
|
||||
<button class="btn secondary" onclick="loadPrivacyFlags()" style="padding:5px 12px;font-size:11px;">🔍 Prüfen</button>
|
||||
<button class="btn" onclick="savePrivacyFlags()" style="padding:5px 12px;font-size:11px;">Speichern</button>
|
||||
</div>
|
||||
<div id="privacy-flags-status" style="margin-top:10px;font-size:11px;color:#8888AA;white-space:pre-wrap;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-section">
|
||||
<h2>Lokales LLM (schnelle Antworten) <button class="info-btn" onclick="showInfo('local-llm')" title="Wie funktioniert das?">ℹ</button></h2>
|
||||
<div class="card" style="max-width:540px;">
|
||||
@@ -2723,6 +2748,14 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.type === 'privacy_flags') { renderPrivacyFlags(msg); return; }
|
||||
if (msg.type === 'privacy_flags_saved') {
|
||||
const st = document.getElementById('privacy-flags-status');
|
||||
if (st && msg.error) { st.textContent = 'Speichern fehlgeschlagen: ' + msg.error; st.style.color = '#FF6B6B'; }
|
||||
// Erfolg: der direkt folgende privacy_flags-Broadcast malt den Stand neu.
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.type === 'model_test_result') {
|
||||
const box = document.getElementById('model-test-result');
|
||||
const btn = document.getElementById('btn-test-model');
|
||||
@@ -4720,6 +4753,7 @@
|
||||
loadJellyfinConfig();
|
||||
refreshVoiceIdStatus();
|
||||
send({ action: 'get_attachment_limit' });
|
||||
send({ action: 'get_privacy_flags' });
|
||||
} else if (tab === 'brain') {
|
||||
loadBrainStatus();
|
||||
loadBrainMemoryList();
|
||||
@@ -8019,6 +8053,68 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ── Datenschutz-Schalter ──────────────────────────────────────────
|
||||
function loadPrivacyFlags() {
|
||||
const st = document.getElementById('privacy-flags-status');
|
||||
if (st) { st.textContent = 'Lese den Proxy-Container …'; st.style.color = '#8888AA'; }
|
||||
send({ action: 'get_privacy_flags' });
|
||||
}
|
||||
|
||||
function savePrivacyFlags() {
|
||||
const flags = {};
|
||||
document.querySelectorAll('#privacy-flags-list input[type=checkbox][data-key]')
|
||||
.forEach(cb => { flags[cb.dataset.key] = cb.checked; });
|
||||
if (!Object.keys(flags).length) {
|
||||
const st = document.getElementById('privacy-flags-status');
|
||||
if (st) { st.textContent = 'Erst „Prüfen" drücken.'; st.style.color = '#FFD60A'; }
|
||||
return;
|
||||
}
|
||||
send({ action: 'set_privacy_flags', flags });
|
||||
}
|
||||
|
||||
function renderPrivacyFlags(msg) {
|
||||
const box = document.getElementById('privacy-flags-list');
|
||||
const st = document.getElementById('privacy-flags-status');
|
||||
if (!box) return;
|
||||
if (msg.error) {
|
||||
box.innerHTML = '';
|
||||
if (st) { st.textContent = 'Fehler: ' + msg.error; st.style.color = '#FF6B6B'; }
|
||||
return;
|
||||
}
|
||||
box.innerHTML = (msg.flags || []).map(f => {
|
||||
// "container" = per docker-compose gesetzt. Das gewinnt gegen
|
||||
// settings.json, also waere ein Haken hier wirkungslos — darum sperren
|
||||
// und ehrlich sagen warum.
|
||||
const locked = f.source === 'container';
|
||||
return '<label style="display:flex;gap:10px;align-items:flex-start;cursor:' + (locked ? 'default' : 'pointer') + ';">'
|
||||
+ '<input type="checkbox" data-key="' + f.key + '"' + (f.disabled ? ' checked' : '')
|
||||
+ (locked ? ' disabled' : '') + ' style="margin-top:3px;">'
|
||||
+ '<span style="flex:1;">'
|
||||
+ '<span style="color:' + (f.disabled ? '#3FFF9F' : '#FFD60A') + ';font-size:12px;">'
|
||||
+ (f.disabled ? '✓ ' : '⚠ ') + escapeHtml(f.label) + '</span>'
|
||||
+ '<span style="color:#555570;font-size:10px;"> — ' + escapeHtml(f.key) + '</span>'
|
||||
+ '<br><span style="color:#8888AA;font-size:10px;">' + escapeHtml(f.info) + '</span>'
|
||||
+ (locked ? '<br><span style="color:#FF9F0A;font-size:10px;">Per docker-compose gesetzt — '
|
||||
+ 'das gewinnt gegen diese Einstellung und lässt sich hier nicht ändern.</span>' : '')
|
||||
+ '</span></label>';
|
||||
}).join('') || '<span style="color:#555570;font-size:11px;">(keine Angaben)</span>';
|
||||
|
||||
const offen = (msg.flags || []).filter(f => !f.disabled).length;
|
||||
if (st) {
|
||||
if (msg.bulkDisabled) {
|
||||
st.textContent = 'CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC ist gesetzt — das schaltet ohnehin alles ab.';
|
||||
st.style.color = '#3FFF9F';
|
||||
} else if (offen === 0) {
|
||||
st.textContent = '✅ Alle drei Kanäle sind zu.';
|
||||
st.style.color = '#3FFF9F';
|
||||
} else {
|
||||
st.textContent = '⚠ ' + offen + ' von ' + (msg.flags || []).length + ' Kanälen senden noch. '
|
||||
+ 'Haken setzen und speichern.';
|
||||
st.style.color = '#FFD60A';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Testet ein Modell mit einer echten Mini-Anfrage.
|
||||
* fromFreeText=true nimmt die handgetippte ID, sonst das Dropdown.
|
||||
|
||||
Reference in New Issue
Block a user