Skip to content

Commit 9949f23

Browse files
author
OpenSIN-AI
committed
chore: mark gitlab-storage plugin as DEPRECATED and add Box Storage migration notes
- Added deprecation header and replaced old purpose with Box Storage replacement - Updated 'Bekannte Projekte' table to show all projects migrated to Box.com - Updated Machine-Links section to indicate it's no longer used - Added deprecation to Auto-Rotation, Migration, and Rules sections - Updated Quick Reference to point to box_storage.py
1 parent 708c3cf commit 9949f23

7 files changed

Lines changed: 679 additions & 0 deletions
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#!/usr/bin/env bash
2+
# DEBUG: PCPM beforeRun hook with verbose logging
3+
set -euo pipefail
4+
5+
echo "🔍 [DEBUG] PCPM Hook starting..." >&2
6+
7+
BRAIN_CLI="/Users/jeremy/dev/global-brain/src/cli.js"
8+
BRAIN_ROOT="/Users/jeremy/dev/global-brain"
9+
PROJECT_ID="OpenSIN-documentation"
10+
GOAL_ID="default-goal"
11+
GOAL_DESC="Continue development"
12+
13+
CONTEXT_FILE="/tmp/pcpm-context-${PROJECT_ID}-${$}.json"
14+
15+
echo "🔍 [DEBUG] Calling brain CLI..." >&2
16+
echo " BRAIN_CLI: $BRAIN_CLI" >&2
17+
echo " CONTEXT_FILE: $CONTEXT_FILE" >&2
18+
19+
# Timeout protection: kill after 2s
20+
(timeout 2s node "$BRAIN_CLI" context \
21+
--root "$BRAIN_ROOT" \
22+
--project "$PROJECT_ID" \
23+
--goal-id "$GOAL_ID" \
24+
--description "$GOAL_DESC" \
25+
> "$CONTEXT_FILE" 2>&1) || {
26+
echo "❌ [DEBUG] Brain CLI failed or timed out (exit: $?)" >&2
27+
echo "PCPM_CONTEXT_LOADED=false"
28+
exit 0
29+
}
30+
31+
if [ -f "$CONTEXT_FILE" ] && [ -s "$CONTEXT_FILE" ]; then
32+
SIZE=$(wc -c < "$CONTEXT_FILE")
33+
echo "✅ [DEBUG] Context generated (${SIZE} bytes)" >&2
34+
echo "PCPM_CONTEXT_LOADED=true"
35+
cat "$CONTEXT_FILE"
36+
rm -f "$CONTEXT_FILE"
37+
else
38+
echo "⚠️ [DEBUG] Context file empty or missing" >&2
39+
echo "PCPM_CONTEXT_LOADED=false"
40+
fi
88.1 KB
Loading
42.2 KB
Loading

scripts/fix_qwen_accounts.py

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
#!/usr/bin/env python3
2+
"""
3+
QWEN AUTH ACCOUNTS HEALTH REPAIR SCRIPT
4+
Autor: OpenCode Agent
5+
Zweck: Automatische Reparatur der Qwen Multi-Account Konfiguration
6+
"""
7+
8+
import json
9+
import sys
10+
import os
11+
from datetime import datetime
12+
13+
CONFIG_PATH = "/Users/jeremy/.config/opencode/qwen-auth-accounts.json"
14+
15+
16+
def load_config():
17+
with open(CONFIG_PATH, "r") as f:
18+
return json.load(f)
19+
20+
21+
def save_config(data):
22+
# Atomic write
23+
temp_path = CONFIG_PATH + ".tmp"
24+
with open(temp_path, "w") as f:
25+
json.dump(data, f, indent=2)
26+
os.replace(temp_path, CONFIG_PATH)
27+
28+
29+
def select_healthiest_account(accounts):
30+
"""
31+
Wählt den gesündesten Account basierend auf:
32+
1. consecutiveFailures == 0 (bevorzugt)
33+
2. Höchste successCount
34+
3. Gutes success/failure Verhältnis
35+
"""
36+
healthy_candidates = []
37+
38+
for idx, acc in enumerate(accounts):
39+
health = acc.get("health", {})
40+
cons = health.get("consecutiveFailures", 0)
41+
success = health.get("successCount", 0)
42+
failure = health.get("failureCount", 0)
43+
44+
# Kriterien für gesunde Accounts
45+
if cons == 0 and success > 0:
46+
ratio = success / (success + failure) if (success + failure) > 0 else 0
47+
healthy_candidates.append(
48+
{
49+
"index": idx,
50+
"success": success,
51+
"failure": failure,
52+
"ratio": ratio,
53+
"lastUsed": acc.get("lastUsed", 0),
54+
}
55+
)
56+
57+
if not healthy_candidates:
58+
print("❌ KEINE GESUNDEN ACCOUNTS GEFUNDEN!")
59+
return None
60+
61+
# Sortiere nach successCount (meiste successes zuerst)
62+
healthy_candidates.sort(key=lambda x: x["success"], reverse=True)
63+
64+
print(f"✅ {len(healthy_candidates)} gesunde Accounts gefunden:")
65+
for cand in healthy_candidates[:10]:
66+
print(
67+
f" Index {cand['index']}: {cand['success']} successes, ratio {cand['ratio']:.2%}"
68+
)
69+
70+
return healthy_candidates[0]["index"]
71+
72+
73+
def main():
74+
print(f"\n🔧 QWEN AUTH ACCOUNTS REPAIR TOOL")
75+
print(f"Timestamp: {datetime.now().isoformat()}")
76+
print(f"=" * 60)
77+
78+
# Load config
79+
try:
80+
data = load_config()
81+
except Exception as e:
82+
print(f"❌ Fehler beim Laden: {e}")
83+
sys.exit(1)
84+
85+
accounts = data.get("accounts", [])
86+
current_active = data.get("activeIndex")
87+
print(f"Aktueller activeIndex: {current_active}")
88+
print(f"Total Accounts: {len(accounts)}")
89+
90+
# Finde Probleme
91+
problematic = []
92+
for idx, acc in enumerate(accounts):
93+
health = acc.get("health", {})
94+
cons = health.get("consecutiveFailures", 0)
95+
if cons > 20:
96+
problematic.append(
97+
{
98+
"index": idx,
99+
"consecutive": cons,
100+
"success": health.get("successCount", 0),
101+
"failure": health.get("failureCount", 0),
102+
}
103+
)
104+
105+
if problematic:
106+
print(f"\n⚠️ PROBLEMATISCHE ACCOUNTS (consecutiveFailures > 20):")
107+
for p in sorted(problematic, key=lambda x: x["consecutive"], reverse=True)[:10]:
108+
print(
109+
f" Index {p['index']}: {p['consecutive']} cons.fails, {p['success']}/{p['failure']}"
110+
)
111+
else:
112+
print("\n✅ Keine kritischen Accounts gefunden!")
113+
114+
# Wähle gesündesten Account
115+
best_index = select_healthiest_account(accounts)
116+
117+
if best_index is None:
118+
print("❌ ABBRUCH: Kein gesunder Account verfügbar!")
119+
sys.exit(1)
120+
121+
# Prüfe ob wir wechseln müssen
122+
if current_active == best_index:
123+
print(f"\n✅ activeIndex ist bereits optimal: {best_index}")
124+
else:
125+
print(f"\n🔄 Wechsle activeIndex von {current_active}{best_index}")
126+
data["activeIndex"] = best_index
127+
try:
128+
save_config(data)
129+
print("✅ Konfiguration erfolgreich gespeichert!")
130+
except Exception as e:
131+
print(f"❌ Fehler beim Speichern: {e}")
132+
sys.exit(1)
133+
134+
print("\n" + "=" * 60)
135+
print("✅ REPARATURE ABGESCHLOSSEN")
136+
print(f"🎯 Neuer aktiver Account: Index {best_index}")
137+
print(
138+
f"📊 Bitte testen Sie nun einen Qwen API-Call um zu bestätigen, dass der Account funktioniert."
139+
)
140+
141+
142+
if __name__ == "__main__":
143+
main()
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
#!/usr/bin/env python3
2+
"""
3+
QWEN ACCOUNT QUARANTINE SCRIPT
4+
Verschiebt/kennzeichnet Accounts mit hohen consecutiveFailures in Quarantäne
5+
"""
6+
7+
import json
8+
import sys
9+
import os
10+
from datetime import datetime
11+
12+
CONFIG_PATH = "/Users/jeremy/.config/opencode/qwen-auth-accounts.json"
13+
QUARANTINE_PATH = "/Users/jeremy/.config/opencode/qwen-auth-accounts.quarantined.json"
14+
15+
16+
def load_config():
17+
with open(CONFIG_PATH, "r") as f:
18+
return json.load(f)
19+
20+
21+
def save_config(data):
22+
temp_path = CONFIG_PATH + ".tmp"
23+
with open(temp_path, "w") as f:
24+
json.dump(data, f, indent=2)
25+
os.replace(temp_path, CONFIG_PATH)
26+
27+
28+
def main():
29+
print(f"\n🧹 QWEN ACCOUNT QUARANTINE TOOL")
30+
print(f"Timestamp: {datetime.now().isoformat()}")
31+
print(f"=" * 60)
32+
33+
data = load_config()
34+
accounts = data.get("accounts", [])
35+
current_active = data.get("activeIndex")
36+
37+
# Identify quarantine candidates: consecutiveFailures > 20
38+
to_quarantine = []
39+
to_keep = []
40+
41+
for idx, acc in enumerate(accounts):
42+
health = acc.get("health", {})
43+
cons = health.get("consecutiveFailures", 0)
44+
success = health.get("successCount", 0)
45+
failure = health.get("failureCount", 0)
46+
47+
if cons > 20:
48+
to_quarantine.append(
49+
{
50+
"index": idx,
51+
"consecutive": cons,
52+
"success": success,
53+
"failure": failure,
54+
"refreshToken": acc.get("refreshToken", "")[:20] + "...",
55+
}
56+
)
57+
else:
58+
to_keep.append(acc)
59+
60+
print(f"🔍 Gefundene kritische Accounts: {len(to_quarantine)}")
61+
print(f"✅ Verbleibende gesunde Accounts: {len(to_keep)}")
62+
print(f"📊 Aktueller activeIndex: {current_active}")
63+
64+
if to_quarantine:
65+
print(
66+
f"\n⚠️ KONTROLLE: Werden diese Accounts wirklich in Quarantäne verschoben?"
67+
)
68+
print(f" (Sie werden aus der Hauptkonfiguration entfernt)")
69+
for q in sorted(to_quarantine, key=lambda x: x["consecutive"], reverse=True)[
70+
:10
71+
]:
72+
print(
73+
f" Index {q['index']}: {q['consecutive']} cons.fails, {q['success']}/{q['failure']}"
74+
)
75+
76+
# Check if active account is among them
77+
if current_active is not None and any(
78+
q["index"] == current_active for q in to_quarantine
79+
):
80+
print(
81+
f"\n❌ KRITISCH: Der aktive Account (Index {current_active}) ist in Quarantäne!"
82+
)
83+
print(
84+
f" Bitte vor dem Verschieben einen neuen aktiven Account auswählen."
85+
)
86+
87+
confirm = input(
88+
f"\n?? Drücke ENTER um diese {len(to_quarantine)} Accounts zu quarantänen, oder 'n' um abzubrechen: "
89+
)
90+
if confirm.lower() == "n":
91+
print("❌ Abgebrochen.")
92+
sys.exit(0)
93+
94+
# Build new accounts list (only healthy)
95+
new_data = {
96+
"version": data.get("version", 1),
97+
"accounts": to_keep,
98+
"activeIndex": data.get("activeIndex"),
99+
}
100+
101+
# Save new config
102+
save_config(new_data)
103+
print(f"\n✅ Hauptkonfiguration gespeichert: {len(to_keep)} Accounts verbleiben.")
104+
105+
# Save quarantined accounts separately (for recovery)
106+
if to_quarantine:
107+
quarantine_data = {
108+
"version": data.get("version", 1),
109+
"accounts": [accounts[q["index"]] for q in to_quarantine],
110+
"quarantinedAt": datetime.now().isoformat(),
111+
"reason": "consecutiveFailures > 20",
112+
}
113+
with open(QUARANTINE_PATH, "w") as f:
114+
json.dump(quarantine_data, f, indent=2)
115+
print(
116+
f"✅ Quarantäne-Datei gespeichert: {QUARANTINE_PATH} ({len(to_quarantine)} Accounts)"
117+
)
118+
119+
# Recompute best active index if needed
120+
if current_active is None or any(
121+
q["index"] == current_active for q in to_quarantine
122+
):
123+
# Pick healthiest remaining account
124+
best_idx = None
125+
best_score = -1
126+
for idx, acc in enumerate(to_keep):
127+
health = acc.get("health", {})
128+
cons = health.get("consecutiveFailures", 0)
129+
success = health.get("successCount", 0)
130+
if cons == 0 and success > 0:
131+
score = success
132+
if score > best_score:
133+
best_score = score
134+
best_idx = idx
135+
136+
if best_idx is not None:
137+
new_data["activeIndex"] = best_idx
138+
save_config(new_data)
139+
print(f"✅ Neuer aktiver Index gesetzt: {best_idx} (gesündester Account)")
140+
else:
141+
print("⚠️ Kein optimaler aktiver Account gefunden – bitte manuell prüfen.")
142+
143+
print("\n" + "=" * 60)
144+
print("✅ QUARANTÄNE ABGESCHLOSSEN")
145+
print(f"🎯 Aktive Accounts: {len(to_keep)}")
146+
print(f"🗑️ In Quarantäne: {len(to_quarantine)}")
147+
print(f"📍 Quarantäne-Datei: {QUARANTINE_PATH}")
148+
149+
150+
if __name__ == "__main__":
151+
main()

0 commit comments

Comments
 (0)