- .claude/agents/planer.md - .claude/settings.json - .claude/workflows/executer-welle.js - .claude/workflows/plankritik.js - .claude/workflows/planung.js - .claude/workflows/quorum.js - .claude/workflows/verbrauch.js - .claude/workflows/welle-mit-pruefung.js - .vault-tools/shell-wache/ENTWURF.md - .vault-tools/shell-wache/docs/code/shell_wache.md - .vault-tools/shell-wache/docs/plans/2026-10-30-shell-wache/00-uebersicht.md - .vault-tools/shell-wache/docs/plans/2026-10-30-shell-wache/task-01-shell-wache.md - … und 34 weitere Erzeugt vom PostToolUse-Hook .vault-tools/auto-push/auto_push.py. Co-Authored-By: Claude Opus 5 <[email protected]>
100 lines
4.1 KiB
Python
100 lines
4.1 KiB
Python
"""Ordnet die Einträge direkt unter dem Datenordner von Claude Code ein: bekannte Ordner gegen zufällig benannte Temp-Ordner.
|
|
|
|
Ersteller: Pascal Michel
|
|
Erstellt: 2026-10-30
|
|
Doku: LIESMICH.md in diesem Ordner
|
|
|
|
Nur lesend. Gibt Anzahl, Größe, Alter und Endungsmuster aus, keine Dateiinhalte; die Strukturbeispiele
|
|
am Schluss nennen bis zu fünf Dateinamen je Ordner.
|
|
Was es nicht sieht: Ob ein Zufallsordner noch von einer laufenden Sitzung benutzt wird. Das Alter kommt
|
|
aus mtime, und die App fasst beim Neustart viele Dateien an (Harness-Erinnerung
|
|
transkript-usage-groesster-wert-je-nachricht). Vor jedem Löschen also laufende Sitzungen über die App
|
|
prüfen, nicht über dieses Skript.
|
|
Zufällig benannt heißt: 21 Zeichen aus [A-Za-z0-9_-] (nanoid-artig) und nicht in BEKANNT.
|
|
Aufruf: python -I -X utf8 claudedata_wurzel.py [Wurzel, Vorgabe D:\\ClaudeData]
|
|
"""
|
|
import collections
|
|
import datetime
|
|
import os
|
|
import re
|
|
import sys
|
|
import time
|
|
|
|
BEKANNT = {"claude", "config", "tmp", "umzug", "codex-review"}
|
|
MUSTER = re.compile(r"^[A-Za-z0-9_-]{21}$")
|
|
|
|
|
|
def groesse(p):
|
|
total = 0; anzahl = 0; namen = collections.Counter(); neueste = 0
|
|
for root, dirs, files in os.walk(p):
|
|
for f in files:
|
|
fp = os.path.join(root, f)
|
|
try:
|
|
st = os.stat(fp)
|
|
except OSError:
|
|
continue
|
|
total += st.st_size; anzahl += 1; neueste = max(neueste, st.st_mtime)
|
|
ext = os.path.splitext(f)[1].lower() or f[:20]
|
|
namen[ext] += 1
|
|
return total, anzahl, namen, neueste
|
|
|
|
|
|
def main(argv):
|
|
wurzel = argv[1] if len(argv) > 1 else r"D:\ClaudeData"
|
|
if not os.path.isdir(wurzel):
|
|
print(f"Wurzel fehlt: {wurzel}")
|
|
return 2
|
|
jetzt = time.time()
|
|
with os.scandir(wurzel) as it:
|
|
eintraege = list(it)
|
|
zufall = [e for e in eintraege if e.is_dir() and MUSTER.match(e.name) and e.name not in BEKANNT]
|
|
andere = [e for e in eintraege if e not in zufall]
|
|
print(f"Einträge gesamt: {len(eintraege)}; zufällig benannte Ordner: {len(zufall)}; andere: {len(andere)}")
|
|
print("\nAndere Einträge:")
|
|
for e in sorted(andere, key=lambda x: x.name):
|
|
try:
|
|
st = e.stat()
|
|
print(f" {'D' if e.is_dir() else 'F'} {e.name} mtime {datetime.datetime.fromtimestamp(st.st_mtime):%Y-%m-%d}")
|
|
except OSError:
|
|
print(" ?", e.name)
|
|
|
|
gesamt = 0; dateien = 0; alter = collections.Counter(); muster = collections.Counter(); tage_liste = []
|
|
topnamen = collections.Counter(); beispiele = {}
|
|
for e in zufall:
|
|
t, n, namen, neueste = groesse(e.path)
|
|
gesamt += t; dateien += n
|
|
try:
|
|
mt = e.stat().st_mtime
|
|
except OSError:
|
|
mt = neueste
|
|
tage = (jetzt - max(mt, neueste)) / 86400
|
|
tage_liste.append(tage)
|
|
stufe = "<1 Tag" if tage < 1 else "1-7 Tage" if tage < 7 else "7-30 Tage" if tage < 30 else ">30 Tage"
|
|
alter[stufe] += 1
|
|
sig = ",".join(f"{k}:{v}" for k, v in sorted(namen.items())[:4])
|
|
muster[sig] += 1
|
|
for k in namen:
|
|
topnamen[k] += 1
|
|
beispiele.setdefault(sig, e.name)
|
|
print(f"\nZufallsordner: {len(zufall)}, Dateien {dateien}, Größe {gesamt/1e6:.1f} MB")
|
|
print("Alter (nach jüngster Änderung):", dict(alter))
|
|
if tage_liste:
|
|
print(f"ältester {max(tage_liste):.0f} Tage, jüngster {min(tage_liste):.2f} Tage")
|
|
print("\nHäufigste Inhaltsmuster (Endung:Anzahl je Ordner):")
|
|
for sig, n in muster.most_common(12):
|
|
print(f" {n:5d} x {sig or '(leer)'} Beispiel: {beispiele[sig]}")
|
|
print("\nHäufigste Dateiendungen über alle Zufallsordner:", dict(topnamen.most_common(12)))
|
|
for sig, n in muster.most_common(3):
|
|
p = os.path.join(wurzel, beispiele[sig])
|
|
print(f"\nStruktur von {beispiele[sig]}:")
|
|
for root, dirs, files in os.walk(p):
|
|
tiefe = root[len(p):].count(os.sep)
|
|
if tiefe > 2:
|
|
continue
|
|
print(" " * tiefe + os.path.basename(root) + "/", f"({len(dirs)} Ordner, {len(files)} Dateien)", sorted(files)[:5])
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main(sys.argv))
|