Auftragsbuch: 'wartung/ui-politur' angenommen (Ein-Klick-Gate)
This commit is contained in:
@@ -0,0 +1,92 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(git fetch *)",
|
||||||
|
"Bash(git push:*)",
|
||||||
|
"Bash(git rev-list *)",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151:*)",
|
||||||
|
"Bash(grep -E \"\\\\.py$|^d\")",
|
||||||
|
"Bash(grep -rn \"http://\\\\|https://\\\\|/srv/\\\\|/opt/\\\\|/etc/\" services/*.py routers/*.py)",
|
||||||
|
"Bash(awk '/^\\(async \\)?def /{in_func=1; func=$0; line=NR} in_func {count++} /^\\(async \\)?def / && NR!=line {if\\(count>30\\) print \"Line \" line \": \" func \" \\(\" count \" lines\\)\"; count=0; func=$0; line=NR} END{if\\(count>30\\) print \"Line \" line \": \" func \" \\(\" count \" lines\\)\"}' routers/*.py services/*.py)",
|
||||||
|
"Bash(grep -rhoE 'api\\(<[^>]+>\\)?\\\\\\(\"\\(/api|/v1\\)[^\"`]*' frontend/src/)",
|
||||||
|
"Bash(sed -E 's/api\\(<[^>]+>\\)?\\\\\\(\"//')",
|
||||||
|
"Bash(grep -rhoE 'api\\(<[^>]+>\\)?\\\\\\(`[^`]*`' frontend/src/)",
|
||||||
|
"Bash(python -c ' *)",
|
||||||
|
"Bash(echo \"tsc exit: $?\")",
|
||||||
|
"WebSearch",
|
||||||
|
"WebFetch(domain:lobehub.com)",
|
||||||
|
"WebFetch(domain:docs.litellm.ai)",
|
||||||
|
"WebFetch(domain:github.com)",
|
||||||
|
"WebFetch(domain:runaihome.com)",
|
||||||
|
"WebFetch(domain:docs.getbifrost.ai)",
|
||||||
|
"WebFetch(domain:thefrontierlab.ai)",
|
||||||
|
"WebFetch(domain:www.glukhov.org)",
|
||||||
|
"WebFetch(domain:cognio.so)",
|
||||||
|
"Bash(ssh -o BatchMode=yes -o ConnectTimeout=10 hitonabi@192.168.178.151 'curl -s http://127.0.0.1:8080/running; echo; echo \"--- after a quick hermes ping, whats running ---\"; curl -s http://127.0.0.1:8080/running')",
|
||||||
|
"Bash(git checkout *)",
|
||||||
|
"Bash(ssh -o BatchMode=yes -o ConnectTimeout=10 hitonabi@192.168.178.151 \"sed -n '46,75p' /etc/llama-swap/config.yaml\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"node --version 2>/dev/null || echo 'no-node'; docker --version 2>/dev/null || echo 'no-docker'; python3 --version; systemctl --user list-units --type=service --state=running 2>/dev/null | head -10\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"systemctl --user cat hermes-gateway.service 2>/dev/null; echo '---'; ls ~/hermes-gateway/ 2>/dev/null || ls ~/mission-control-v2/deploy/ | grep gateway\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"ls ~/.hermes/ && echo '---' && ls ~/.hermes/hermes-agent/ 2>/dev/null && echo '---' && cat ~/.hermes/config/config.yaml 2>/dev/null || cat ~/.hermes/config.yaml 2>/dev/null\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"journalctl --user -u hermes-gateway.service --no-pager -n 20\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"cat ~/.hermes/config.yaml | grep -A5 'api_server\\\\|api_key\\\\|gateway_api\\\\|secret' | head -30\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"grep -r 'gateway_api_key\\\\|api_server\\\\|HERMES_API_KEY\\\\|8642' ~/.hermes/config.yaml ~/.config/environment.d/ 2>/dev/null | head -20; echo '---'; cat ~/.config/environment.d/*.conf 2>/dev/null | grep -i hermes | head -20\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"grep -r 'hermes.*gateway\\\\|gateway.*url\\\\|8642\\\\|GATEWAY' ~/mission-control-v2/backend/ 2>/dev/null | grep -v '.pyc' | head -20\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"grep -A20 'def get_agent_status\\\\|def check\\\\|HERMES_API' ~/mission-control-v2/backend/services/agent.py | head -40\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"cat ~/.hermes/gateway_state.json 2>/dev/null | python3 -c 'import json,sys; d=json.load\\(sys.stdin\\); print\\(list\\(d.keys\\(\\)\\)\\); print\\(d.get\\(\\\\\"api_key\\\\\"\\) or d.get\\(\\\\\"key\\\\\"\\) or \\\\\"no key field\\\\\"\\)' 2>/dev/null; echo '---'; ls ~/.hermes/auth* ~/.hermes/pairing/ 2>/dev/null\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"~/.hermes/hermes-agent/venv/bin/python -m hermes_cli.main gateway status 2>&1 | head -20; echo '---'; curl -s http://127.0.0.1:8642/health 2>/dev/null || curl -s http://127.0.0.1:8642/ 2>/dev/null | head -5\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"cat ~/.hermes/gateway_state.json | python3 -c 'import json,sys; d=json.load\\(sys.stdin\\); print\\(json.dumps\\(d.get\\(\\\\\"platforms\\\\\", {}\\), indent=2\\)\\)'\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"bash ~/mission-control-v2/deploy/deploy.sh\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"~/.hermes/hermes-agent/venv/bin/python -m hermes_cli.main gateway connect --help 2>&1 | head -30\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"~/.hermes/hermes-agent/venv/bin/python -m hermes_cli.main gateway enroll --help 2>&1\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"~/.hermes/hermes-agent/venv/bin/python -m hermes_cli.main gateway setup --help 2>&1\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"~/.hermes/hermes-agent/venv/bin/python -m hermes_cli.main --help 2>&1 | head -40\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"cat ~/.hermes/.env 2>/dev/null; echo '---'; ~/ .hermes/hermes-agent/venv/bin/python -m hermes_cli.main config --help 2>&1 | head -20\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"sed -i 's|# TELEGRAM_BOT_TOKEN=|TELEGRAM_BOT_TOKEN=8908266336:AAElPDmdEJXZ5cs0gUzbAnm4a9glRY18Zac|' ~/.hermes/.env && grep TELEGRAM_BOT_TOKEN ~/.hermes/.env\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"systemctl --user restart hermes-gateway && sleep 3 && journalctl --user -u hermes-gateway --no-pager -n 15\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"sleep 4 && journalctl --user -u hermes-gateway --no-pager -n 20 --since '1 minute ago'\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"sleep 3 && journalctl --user -u hermes-gateway --no-pager -n 25 --since '2 minutes ago'\")",
|
||||||
|
"Bash(ssh hitonabi@192.168.178.151 \"sed -i 's|# TELEGRAM_ALLOWED_USERS=.*|TELEGRAM_ALLOWED_USERS=6150562984|' ~/.hermes/.env && grep TELEGRAM_ALLOWED ~/.hermes/.env\")",
|
||||||
|
"Bash(mkdir -p \"F:\\\\Coding Stuff\\\\mission-control-2\\\\docs\\\\memory\")",
|
||||||
|
"Bash(cp \"C:\\\\Users\\\\TobisPC\\\\.claude\\\\projects\\\\F--Coding-Stuff-mission-control-2\\\\memory\\\\project-stack-state.md\" \"F:\\\\Coding Stuff\\\\mission-control-2\\\\docs\\\\memory\\\\\" && cp \"C:\\\\Users\\\\TobisPC\\\\.claude\\\\projects\\\\F--Coding-Stuff-mission-control-2\\\\memory\\\\project-hermes-setup.md\" \"F:\\\\Coding Stuff\\\\mission-control-2\\\\docs\\\\memory\\\\\")",
|
||||||
|
"Bash(cp \"C:\\\\Users\\\\TobisPC\\\\.claude\\\\projects\\\\F--Coding-Stuff-mission-control-2\\\\memory\\\\project-mc2-architecture.md\" \"F:\\\\Coding Stuff\\\\mission-control-2\\\\docs\\\\memory\\\\\" && cp \"C:\\\\Users\\\\TobisPC\\\\.claude\\\\projects\\\\F--Coding-Stuff-mission-control-2\\\\memory\\\\project-pending-tasks.md\" \"F:\\\\Coding Stuff\\\\mission-control-2\\\\docs\\\\memory\\\\\")",
|
||||||
|
"Bash(ssh -o BatchMode=yes -o ConnectTimeout=8 hitonabi@192.168.178.151 'echo \"=== ENGINE VERSION ===\"; /usr/local/bin/llama-server --version 2>&1 | head -3; echo \"=== LLAMA-SWAP VERSION ===\"; \\(llama-swap --version 2>&1 || /usr/local/bin/llama-swap --version 2>&1 || echo \"no --version\"\\) | head -3; echo \"=== RUNNING MODELS ===\"; curl -s http://127.0.0.1:8080/running 2>&1 | head -c 2000; echo; echo \"=== FREE MEM ===\"; free -g | head -3')",
|
||||||
|
"Bash(ssh -o BatchMode=yes -o ConnectTimeout=8 hitonabi@192.168.178.151 'echo \"=== HERMES CONFIG ===\"; cat ~/.hermes/config.yaml 2>&1 | head -120; echo \"=== HERMES DIR ===\"; ls -la ~/.hermes/ 2>&1 | head -40')",
|
||||||
|
"Bash(ssh -o BatchMode=yes -o ConnectTimeout=8 hitonabi@192.168.178.151 'echo \"=== HERMES CONFIG \\(rest\\) ===\"; sed -n \"120,400p\" ~/.hermes/config.yaml 2>&1; echo \"=== TOOLS COUNT \\(api/all\\) ===\"; cd ~/.hermes 2>/dev/null; \\(hermes tools list 2>&1 | tail -40\\) || echo \"hermes CLI not on PATH\"')",
|
||||||
|
"Bash(ssh -o BatchMode=yes -o ConnectTimeout=8 hitonabi@192.168.178.151 ' *)",
|
||||||
|
"Bash(xargs cat)",
|
||||||
|
"Bash(ssh -o ConnectTimeout=8 -o BatchMode=yes hitonabi@192.168.178.151 'echo \"=== llama-server version ===\"; /usr/local/bin/llama-server --version 2>&1 | head -5; echo \"=== running models ===\"; curl -s http://127.0.0.1:8080/running 2>/dev/null | head -c 2000; echo; echo \"=== free ===\"; free -g')",
|
||||||
|
"Bash(ssh -o ConnectTimeout=8 -o BatchMode=yes hitonabi@192.168.178.151 'echo \"=== config.yaml ===\"; cat /etc/llama-swap/config.yaml; echo; echo \"=== models on disk ===\"; du -sh /srv/models/* 2>/dev/null | sort -h')",
|
||||||
|
"Bash(ssh -o ConnectTimeout=8 -o BatchMode=yes hitonabi@192.168.178.151 'echo \"=== Qwen3.6 MTP dir ===\"; ls -la /srv/models/Qwen3.6-35B-A3B-MTP-GGUF/ 2>/dev/null; echo \"=== drafts dir ===\"; ls -la /srv/models/drafts/ 2>/dev/null; echo \"=== disk free ===\"; df -h /srv 2>/dev/null; echo \"=== gemma remnant ===\"; ls -la /srv/models/gemma-4-26B-A4B-it-GGUF/ 2>/dev/null')",
|
||||||
|
"Bash(ssh -o ConnectTimeout=8 -o BatchMode=yes hitonabi@192.168.178.151 ' *)",
|
||||||
|
"Bash(ssh -o ConnectTimeout=12 -o BatchMode=yes hitonabi@192.168.178.151 ' *)",
|
||||||
|
"WebFetch(domain:unsloth.ai)",
|
||||||
|
"WebFetch(domain:huggingface.co)",
|
||||||
|
"Bash(xargs ls -la)",
|
||||||
|
"Bash(xargs wc -l)",
|
||||||
|
"PowerShell(ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=10 -o BatchMode=yes hitonabi@192.168.178.151 \"echo '=== engine ==='; /opt/llamacpp-vulkan/llama-server --version 2>&1 | head -3; echo; echo '=== llama-swap version ==='; /opt/llama-swap/llama-swap --version 2>/dev/null || llama-swap --version 2>/dev/null || ls -la /opt/llama-swap 2>/dev/null | head -5; echo; echo '=== running models ==='; curl -s http://127.0.0.1:8080/running; echo; echo '=== services ==='; for s in llama-swap mc2-backend hermes-api hermes-webui mem0-service voice-service; do printf '%s: ' $s; systemctl is-active $s 2>/dev/null; done; echo '=== uname/mem ==='; uname -r; free -g | head -2\")",
|
||||||
|
"PowerShell(ssh -o ConnectTimeout=10 -o BatchMode=yes hitonabi@192.168.178.151 \"echo '=== ports ==='; ss -tlnp 2>/dev/null | grep -E ':\\(9001|8642|8650|8765|8787|7681|8080|8130\\)'; echo; echo '=== wer serviert 9001? ==='; systemctl list-units --all --type=service --no-pager --no-legend | grep -iE 'gateway|backend|control|api'; echo; echo '=== mem0 venv ==='; systemctl cat mem0-service 2>/dev/null | grep -E 'ExecStart|WorkingDirectory'; echo; echo '=== voice venv ==='; systemctl cat voice-service 2>/dev/null | grep -E 'ExecStart|WorkingDirectory'\")",
|
||||||
|
"PowerShell(ssh -o ConnectTimeout=10 -o BatchMode=yes hitonabi@192.168.178.151 \"echo '=== 9001 Prozess ==='; cat /proc/11257/cmdline 2>/dev/null | tr '\\\\0' ' '; echo; readlink /proc/11257/cwd; ps -o etime= -p 11257; echo; echo '=== mc2 backend unit? ==='; ls /etc/systemd/system/ | grep -iE 'mc2|mission|backend'; echo; echo '=== mem0 pip ==='; MEMPY=/proc/7277/exe; readlink /proc/7277/cwd; readlink /proc/7277/exe; V=\\(dirname \\(readlink /proc/7277/exe\\)\\); echo; /srv/mc2/mem0-venv/bin/pip show mem0ai 2>/dev/null | head -2\")",
|
||||||
|
"PowerShell(ssh -o ConnectTimeout=10 -o BatchMode=yes hitonabi@192.168.178.151 \"echo '=== 9001 Prozess ==='; tr '\\\\0' ' ' < /proc/11257/cmdline; echo; readlink /proc/11257/cwd; ps -o etime= -p 11257; echo '=== mc2 unit? ==='; ls /etc/systemd/system/ | grep -iE 'mc2|mission|backend|llama|hermes|mem0|voice'; echo '=== mem0 exe ==='; readlink /proc/7277/exe; readlink /proc/7277/cwd\")",
|
||||||
|
"PowerShell(ssh -o ConnectTimeout=10 -o BatchMode=yes hitonabi@192.168.178.151 \"echo '=== mission-control.service ==='; systemctl is-enabled mission-control 2>&1; systemctl is-active mission-control 2>&1; grep -E 'ExecStart|WorkingDirectory' /etc/systemd/system/mission-control.service; echo; echo '=== mem0ai version ==='; ls /home/hitonabi/mission-control-v2/mem0_service/ | head; for p in /home/hitonabi/mission-control-v2/mem0_service/.venv/bin/pip /home/hitonabi/mission-control-v2/mem0_service/venv/bin/pip; do [ -x \\\\\"\\\\$p\\\\\" ] && \\\\\"\\\\$p\\\\\" show mem0ai chromadb 2>/dev/null | grep -E 'Name|Version'; done\")",
|
||||||
|
"PowerShell(ssh -o ConnectTimeout=10 -o BatchMode=yes hitonabi@192.168.178.151 \"tr '\\\\0' '\\\\n' < /proc/7277/environ | grep -E 'VIRTUAL_ENV|PATH=' | head -3; tr '\\\\0' ' ' < /proc/7277/cmdline; echo; /home/hitonabi/.local/share/uv/python/cpython-3.12.13-linux-x86_64-gnu/bin/python3.12 -c 'import mem0; print\\(mem0.__version__\\)' 2>&1 | tail -1\")",
|
||||||
|
"PowerShell(ssh -o ConnectTimeout=10 -o BatchMode=yes hitonabi@192.168.178.151 \"/home/hitonabi/.mem0/venv/bin/pip show mem0ai 2>/dev/null | grep -E 'Name|Version'; /home/hitonabi/.mem0/venv/bin/pip show chromadb 2>/dev/null | grep Version\")",
|
||||||
|
"PowerShell(ssh -o ConnectTimeout=10 -o BatchMode=yes hitonabi@192.168.178.151 \"ls /home/hitonabi/.mem0/venv/bin/ | head -8; /home/hitonabi/.mem0/venv/bin/python -m pip show mem0ai chromadb 2>&1 | grep -E 'Name:|Version:'\")",
|
||||||
|
"PowerShell(ssh -o ConnectTimeout=10 -o BatchMode=yes hitonabi@192.168.178.151 \"/home/hitonabi/.mem0/venv/bin/python -c 'import importlib.metadata as m; print\\(\\\\\"mem0ai\\\\\", m.version\\(\\\\\"mem0ai\\\\\"\\)\\); print\\(\\\\\"chromadb\\\\\", m.version\\(\\\\\"chromadb\\\\\"\\)\\)' 2>&1\")",
|
||||||
|
"Bash(ssh -o ConnectTimeout=10 -o BatchMode=yes hitonabi@192.168.178.151 '/home/hitonabi/.mem0/venv/bin/python -c \"import importlib.metadata as m; print\\(\\\\\"mem0ai\\\\\", m.version\\(\\\\\"mem0ai\\\\\"\\)\\); print\\(\\\\\"chromadb\\\\\", m.version\\(\\\\\"chromadb\\\\\"\\)\\)\"')",
|
||||||
|
"WebFetch(domain:docs.mem0.ai)",
|
||||||
|
"PowerShell(Write-Output '=== Lucy-Prozesse lokal ==='; Get-Process | Where-Object {$_.ProcessName -match 'electron|python|node'} | Select-Object ProcessName, Id, WorkingSet64 | Format-Table; Write-Output '=== Port 8130 \\(Pocket-TTS\\) ==='; Get-NetTCPConnection -LocalPort 8130 -State Listen -ErrorAction SilentlyContinue | Select-Object LocalAddress, OwningProcess; Write-Output '=== GPU ==='; Get-CimInstance Win32_VideoController | Select-Object Name, DriverVersion | Format-Table)",
|
||||||
|
"PowerShell($p = 'F:\\\\Coding Stuff\\\\mission-control-2\\\\client\\\\lucy-tts\\\\ptts-venv\\\\Scripts\\\\python.exe'; if \\(Test-Path $p\\) { & $p -c \"import importlib.metadata as m; [print\\(n, m.version\\(n\\)\\) for n in ['pocket-tts','torch','onnxruntime','fastapi','numpy'] if True]\" 2>&1 } else { Write-Output 'ptts-venv nicht gefunden'; Get-ChildItem 'F:\\\\Coding Stuff\\\\mission-control-2\\\\client\\\\lucy-tts' -Directory | Select-Object Name })",
|
||||||
|
"Bash(ssh -o ConnectTimeout=10 -o BatchMode=yes hitonabi@192.168.178.151 'echo \"=== /v1/models ===\"; curl -s http://127.0.0.1:9001/v1/models | head -c 600; echo; echo \"=== voice metrics ===\"; curl -s http://127.0.0.1:9001/api/voice/metrics | head -c 1200')",
|
||||||
|
"Bash(ssh -o ConnectTimeout=15 -o BatchMode=yes hitonabi@192.168.178.151 'curl -s -o /dev/null -w \"TTFB_chat_lane: %{time_starttransfer}s total: %{time_total}s\\\\n\" -N -X POST http://127.0.0.1:9001/v1/chat/completions -H \"Content-Type: application/json\" -d \"{\\\\\"model\\\\\":\\\\\"chat\\\\\",\\\\\"stream\\\\\":true,\\\\\"max_tokens\\\\\":24,\\\\\"messages\\\\\":[{\\\\\"role\\\\\":\\\\\"user\\\\\",\\\\\"content\\\\\":\\\\\"Sag nur: hallo\\\\\"}]}\"')",
|
||||||
|
"Bash(ssh -o ConnectTimeout=30 -o BatchMode=yes hitonabi@192.168.178.151 'curl -s -N -X POST http://127.0.0.1:9001/v1/chat/completions -H \"Content-Type: application/json\" -d \"{\\\\\"model\\\\\":\\\\\"chat\\\\\",\\\\\"stream\\\\\":true,\\\\\"max_tokens\\\\\":24,\\\\\"messages\\\\\":[{\\\\\"role\\\\\":\\\\\"user\\\\\",\\\\\"content\\\\\":\\\\\"Sag nur: hallo\\\\\"}]}\" | head -c 500')",
|
||||||
|
"Bash(ssh -o ConnectTimeout=60 -o BatchMode=yes hitonabi@192.168.178.151 'echo \"=== routing policy ===\"; curl -s http://127.0.0.1:9001/api/routing | head -c 800; echo; echo \"=== aliases in llama-swap config ===\"; grep -B1 -A3 \"aliases:\" /etc/llama-swap/config.yaml | head -40; echo \"=== direkt hermes ===\"; curl -s -o /dev/null -w \"TTFB: %{time_starttransfer}s\\\\n\" -N -X POST http://127.0.0.1:9001/v1/chat/completions -H \"Content-Type: application/json\" -d \"{\\\\\"model\\\\\":\\\\\"hermes\\\\\",\\\\\"stream\\\\\":true,\\\\\"max_tokens\\\\\":24,\\\\\"messages\\\\\":[{\\\\\"role\\\\\":\\\\\"user\\\\\",\\\\\"content\\\\\":\\\\\"Sag nur: hallo\\\\\"}]}\"')",
|
||||||
|
"Bash(ssh -o ConnectTimeout=60 -o BatchMode=yes hitonabi@192.168.178.151 'curl -s -N -X POST http://127.0.0.1:9001/v1/chat/completions -H \"Content-Type: application/json\" -d \"{\\\\\"model\\\\\":\\\\\"hermes\\\\\",\\\\\"stream\\\\\":true,\\\\\"max_tokens\\\\\":24,\\\\\"messages\\\\\":[{\\\\\"role\\\\\":\\\\\"user\\\\\",\\\\\"content\\\\\":\\\\\"Sag nur: hallo\\\\\"}]}\" | head -c 400; echo; echo \"=== direkt an llama-swap :8080 ===\"; curl -s -o /dev/null -w \"TTFB: %{time_starttransfer}s total: %{time_total}s\\\\n\" -N -X POST http://127.0.0.1:8080/v1/chat/completions -H \"Content-Type: application/json\" -d \"{\\\\\"model\\\\\":\\\\\"hermes\\\\\",\\\\\"stream\\\\\":true,\\\\\"max_tokens\\\\\":24,\\\\\"messages\\\\\":[{\\\\\"role\\\\\":\\\\\"user\\\\\",\\\\\"content\\\\\":\\\\\"Sag nur: hallo\\\\\"}]}\"')",
|
||||||
|
"WebFetch(domain:www.hermes-ai.net)",
|
||||||
|
"WebFetch(domain:releases.electronjs.org)",
|
||||||
|
"WebFetch(domain:dev.to)",
|
||||||
|
"WebFetch(domain:kyuz0.github.io)",
|
||||||
|
"WebFetch(domain:kmarble.dev)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+165
-165
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
Vendored
+2
-2
@@ -7,8 +7,8 @@
|
|||||||
<link rel="manifest" href="/manifest.webmanifest" />
|
<link rel="manifest" href="/manifest.webmanifest" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
<title>Mission Control 2.0</title>
|
<title>Mission Control 2.0</title>
|
||||||
<script type="module" crossorigin src="/assets/index-BmqzJdEY.js"></script>
|
<script type="module" crossorigin src="/assets/index-BquQKOWt.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-CAFno6lH.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-BlX5e5eL.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
+36
-19
@@ -123,25 +123,42 @@ export default function App() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav className="flex-1 space-y-1 px-3 py-4 overflow-y-auto">
|
<nav className="flex-1 space-y-1 px-3 py-4 overflow-y-auto">
|
||||||
{NAV.map((item) => (
|
{(() => {
|
||||||
<a
|
let lastGroup: string | null = null
|
||||||
key={item.id}
|
return NAV.map((item) => {
|
||||||
href={`#${item.id}`}
|
const showGroupHeader = item.group !== lastGroup
|
||||||
aria-current={view === item.id ? "page" : undefined}
|
lastGroup = item.group
|
||||||
className={cn(
|
return (
|
||||||
"flex w-full items-center rounded-md text-sm transition-all cursor-pointer",
|
<div key={item.id} className="space-y-1">
|
||||||
sidebarCollapsed ? "justify-center p-2.5" : "gap-3 px-3 py-2",
|
{showGroupHeader && (
|
||||||
view === item.id
|
sidebarCollapsed ? (
|
||||||
? "bg-primary/15 text-primary shadow-sm shadow-primary/5"
|
lastGroup !== NAV[0].group && <div className="my-3 border-t border-border/30" />
|
||||||
: "text-muted-foreground hover:bg-accent hover:text-accent-foreground",
|
) : (
|
||||||
)}
|
<div className="mt-5 mb-1.5 px-3 text-[10px] font-bold uppercase tracking-widest text-muted-foreground/40 first:mt-0 select-none">
|
||||||
title={sidebarCollapsed ? item.label : undefined}
|
{item.group}
|
||||||
aria-label={sidebarCollapsed ? item.label : undefined}
|
</div>
|
||||||
>
|
)
|
||||||
<item.icon className="h-4.5 w-4.5 shrink-0" aria-hidden="true" />
|
)}
|
||||||
{!sidebarCollapsed && <span className="truncate">{item.label}</span>}
|
<a
|
||||||
</a>
|
href={`#${item.id}`}
|
||||||
))}
|
aria-current={view === item.id ? "page" : undefined}
|
||||||
|
className={cn(
|
||||||
|
"flex w-full items-center rounded-md text-sm transition-all cursor-pointer",
|
||||||
|
sidebarCollapsed ? "justify-center p-2.5" : "gap-3 px-3 py-2",
|
||||||
|
view === item.id
|
||||||
|
? "bg-primary/15 text-primary shadow-sm shadow-primary/5"
|
||||||
|
: "text-muted-foreground hover:bg-accent hover:text-accent-foreground",
|
||||||
|
)}
|
||||||
|
title={sidebarCollapsed ? item.label : undefined}
|
||||||
|
aria-label={sidebarCollapsed ? item.label : undefined}
|
||||||
|
>
|
||||||
|
<item.icon className="h-4.5 w-4.5 shrink-0" aria-hidden="true" />
|
||||||
|
{!sidebarCollapsed && <span className="truncate">{item.label}</span>}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})()}
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div className={cn("py-3 text-xs text-muted-foreground border-t border-border/40 shrink-0", sidebarCollapsed ? "px-2 text-center" : "px-5")}>
|
<div className={cn("py-3 text-xs text-muted-foreground border-t border-border/40 shrink-0", sidebarCollapsed ? "px-2 text-center" : "px-5")}>
|
||||||
|
|||||||
+13
-10
@@ -14,25 +14,28 @@ import {
|
|||||||
|
|
||||||
export type ViewId = "dashboard" | "auftraege" | "models" | "memory" | "wissen" | "chronik" | "connect" | "agent" | "konsole" | "guide"
|
export type ViewId = "dashboard" | "auftraege" | "models" | "memory" | "wissen" | "chronik" | "connect" | "agent" | "konsole" | "guide"
|
||||||
|
|
||||||
|
export type NavGroup = "Operativ" | "Wissen" | "Werkzeuge" | "Wartung"
|
||||||
|
|
||||||
export interface NavItem {
|
export interface NavItem {
|
||||||
id: ViewId
|
id: ViewId
|
||||||
label: string
|
label: string
|
||||||
hint: string
|
hint: string
|
||||||
icon: LucideIcon
|
icon: LucideIcon
|
||||||
|
group: NavGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eine Quelle der Wahrheit für Sidebar UND Command-Palette.
|
// Eine Quelle der Wahrheit für Sidebar UND Command-Palette.
|
||||||
export const NAV: NavItem[] = [
|
export const NAV: NavItem[] = [
|
||||||
{ id: "dashboard", label: "Cockpit", hint: "Deine Box auf einen Blick", icon: LayoutDashboard },
|
{ id: "dashboard", label: "Cockpit", hint: "Deine Box auf einen Blick", icon: LayoutDashboard, group: "Operativ" },
|
||||||
{ id: "auftraege", label: "Auftragsbuch", hint: "Vorschläge der Box — annehmen oder ablehnen", icon: Inbox },
|
{ id: "auftraege", label: "Auftragsbuch", hint: "Vorschläge der Box — annehmen oder ablehnen", icon: Inbox, group: "Operativ" },
|
||||||
{ id: "models", label: "Modelle", hint: "Speicher, laden & Rollen", icon: Boxes },
|
{ id: "chronik", label: "Chronik", hint: "Was die Box von allein getan hat + Zeitmaschine", icon: History, group: "Operativ" },
|
||||||
{ id: "memory", label: "Gedächtnis", hint: "Geteiltes Memory verwalten", icon: Brain },
|
{ id: "memory", label: "Gedächtnis", hint: "Geteiltes Memory verwalten", icon: Brain, group: "Wissen" },
|
||||||
{ id: "wissen", label: "Wissen", hint: "Lucys Wissens-Vault (Traum-Notizen)", icon: Library },
|
{ id: "wissen", label: "Wissen", hint: "Lucys Wissens-Vault (Traum-Notizen)", icon: Library, group: "Wissen" },
|
||||||
{ id: "chronik", label: "Chronik", hint: "Was die Box von allein getan hat + Zeitmaschine", icon: History },
|
{ id: "connect", label: "Verbinden", hint: "IDE-/Agent-Configs erzeugen", icon: Plug, group: "Werkzeuge" },
|
||||||
{ id: "connect", label: "Verbinden", hint: "IDE-/Agent-Configs erzeugen", icon: Plug },
|
{ id: "konsole", label: "Konsole", hint: "Direkte Box-Shell (SSH-artig)", icon: SquareTerminal, group: "Werkzeuge" },
|
||||||
{ id: "agent", label: "Hermes", hint: "Agent-Status & Verdrahtung", icon: Bot },
|
{ id: "guide", label: "Anleitung", hint: "Einrichten & Vibe-Coding", icon: HelpCircle, group: "Werkzeuge" },
|
||||||
{ id: "konsole", label: "Konsole", hint: "Direkte Box-Shell (SSH-artig)", icon: SquareTerminal },
|
{ id: "models", label: "Modelle", hint: "Speicher, laden & Rollen", icon: Boxes, group: "Wartung" },
|
||||||
{ id: "guide", label: "Anleitung", hint: "Einrichten & Vibe-Coding", icon: HelpCircle },
|
{ id: "agent", label: "Hermes", hint: "Agent-Status & Verdrahtung", icon: Bot, group: "Wartung" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ export function MemoryView() {
|
|||||||
className="h-9 px-3 rounded-lg bg-primary text-primary-foreground text-xs font-semibold hover:opacity-90 transition-all flex items-center gap-1.5 cursor-pointer shadow-md shadow-primary/10">
|
className="h-9 px-3 rounded-lg bg-primary text-primary-foreground text-xs font-semibold hover:opacity-90 transition-all flex items-center gap-1.5 cursor-pointer shadow-md shadow-primary/10">
|
||||||
<Plus className="h-4 w-4" /> Eintrag
|
<Plus className="h-4 w-4" /> Eintrag
|
||||||
</button>
|
</button>
|
||||||
<div className="flex items-center gap-1 p-1 bg-card/30 border border-border/40 rounded-lg">
|
<div className="flex items-center gap-1 p-1 bg-card/30 border border-border/40 rounded-lg lg:hidden">
|
||||||
{([["liste", List, "Liste"], ["graph", Share2, "Graph"]] as const).map(([v, Icon, lbl]) => (
|
{([["liste", List, "Liste"], ["graph", Share2, "Graph"]] as const).map(([v, Icon, lbl]) => (
|
||||||
<button key={v} onClick={() => setView(v)}
|
<button key={v} onClick={() => setView(v)}
|
||||||
className={cn("flex h-7 px-2.5 items-center gap-1.5 text-[11px] font-semibold rounded-md transition-all cursor-pointer",
|
className={cn("flex h-7 px-2.5 items-center gap-1.5 text-[11px] font-semibold rounded-md transition-all cursor-pointer",
|
||||||
@@ -270,83 +270,89 @@ export function MemoryView() {
|
|||||||
<button onClick={() => setShowAdd(true)} className="underline hover:text-foreground">oder lieber manuell anlegen</button>.
|
<button onClick={() => setShowAdd(true)} className="underline hover:text-foreground">oder lieber manuell anlegen</button>.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
) : view === "graph" ? (
|
|
||||||
<GraphErrorBoundary>
|
|
||||||
<Suspense fallback={<div className="h-[480px] rounded-2xl border border-border/60 bg-card/30 flex items-center justify-center text-xs text-muted-foreground">Graph wird geladen…</div>}>
|
|
||||||
<GraphView data={graphData} onDelete={del} />
|
|
||||||
</Suspense>
|
|
||||||
</GraphErrorBoundary>
|
|
||||||
) : (
|
) : (
|
||||||
<>
|
<div className="flex flex-col lg:flex-row gap-6 items-stretch">
|
||||||
{/* Kategorie-Filter */}
|
{/* Liste-Sicht */}
|
||||||
<div className="flex flex-wrap items-center gap-1.5 p-1 bg-card/30 border border-border/40 rounded-xl w-fit">
|
<div className={cn("flex-1 space-y-5 lg:max-w-md xl:max-w-xl lg:shrink-0", view === "graph" && "hidden lg:block")}>
|
||||||
<button onClick={() => setFilter("")}
|
{/* Kategorie-Filter */}
|
||||||
className={cn("h-7 px-3 rounded-lg text-[10px] font-semibold uppercase tracking-wider transition-all cursor-pointer",
|
<div className="flex flex-wrap items-center gap-1.5 p-1 bg-card/30 border border-border/40 rounded-xl w-fit">
|
||||||
!filter ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground")}>Alle</button>
|
<button onClick={() => setFilter("")}
|
||||||
{CATEGORIES.map((c) => {
|
className={cn("h-7 px-3 rounded-lg text-[10px] font-semibold uppercase tracking-wider transition-all cursor-pointer",
|
||||||
const conf = CAT_CONFIG[c] || DEFAULT_CAT
|
!filter ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground")}>Alle</button>
|
||||||
const Icon = conf.icon
|
{CATEGORIES.map((c) => {
|
||||||
return (
|
|
||||||
<button key={c} onClick={() => setFilter(c)}
|
|
||||||
className={cn("h-7 px-2.5 rounded-lg text-[10px] font-semibold uppercase tracking-wider transition-all cursor-pointer flex items-center gap-1",
|
|
||||||
filter === c ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground")}>
|
|
||||||
<Icon className="h-3 w-3" /> {conf.label}
|
|
||||||
</button>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{items.length === 0 ? (
|
|
||||||
<div className="text-xs text-muted-foreground border border-dashed border-border/60 rounded-2xl p-12 text-center">
|
|
||||||
Keine Einträge für die aktuellen Filterkriterien gefunden.
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="space-y-5">
|
|
||||||
{[...CATEGORIES, "__other"].map((c) => {
|
|
||||||
const list = c === "__other" ? otherItems : (grouped[c] || [])
|
|
||||||
if (!list.length) return null
|
|
||||||
const conf = CAT_CONFIG[c] || DEFAULT_CAT
|
const conf = CAT_CONFIG[c] || DEFAULT_CAT
|
||||||
const Icon = conf.icon
|
const Icon = conf.icon
|
||||||
return (
|
return (
|
||||||
<div key={c}>
|
<button key={c} onClick={() => setFilter(c)}
|
||||||
{/* Sektions-Kopf je Kategorie */}
|
className={cn("h-7 px-2.5 rounded-lg text-[10px] font-semibold uppercase tracking-wider transition-all cursor-pointer flex items-center gap-1",
|
||||||
<div className="flex items-center gap-2 mb-2 px-1">
|
filter === c ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:text-foreground")}>
|
||||||
<Icon className={cn("h-3.5 w-3.5", conf.text)} />
|
<Icon className="h-3 w-3" /> {conf.label}
|
||||||
<span className={cn("text-[11px] font-bold uppercase tracking-wider", conf.text)}>{conf.label}</span>
|
</button>
|
||||||
<span className="text-[10px] font-mono text-muted-foreground/60 bg-card/50 rounded px-1.5 py-0.5">{list.length}</span>
|
|
||||||
<div className="ml-1 h-px flex-1 bg-border/30" />
|
|
||||||
</div>
|
|
||||||
<div className="space-y-2">
|
|
||||||
{list.map((m) => {
|
|
||||||
const isAuto = AUTO_SOURCES.has(m.source)
|
|
||||||
return (
|
|
||||||
<div key={m.id} className={cn("flex items-start justify-between gap-4 p-3.5 rounded-xl border border-l-4 bg-card/45 backdrop-blur-md border-border/60 hover:border-primary/20 transition-all group",
|
|
||||||
BORDER_CLASSES[m.category] || "border-l-muted")}>
|
|
||||||
<span className="text-xs text-foreground leading-relaxed break-words whitespace-pre-wrap flex-1 min-w-0">{m.content}</span>
|
|
||||||
<div className="flex items-center gap-2 shrink-0">
|
|
||||||
{typeof m.score === "number" && (
|
|
||||||
<span className="text-[9px] font-mono text-primary bg-primary/10 px-1.5 py-0.5 rounded" title="Relevanz der semantischen Suche">{Math.round(m.score * 100)}%</span>
|
|
||||||
)}
|
|
||||||
<span className={cn("flex items-center gap-1 text-[9px] font-mono px-1.5 py-0.5 rounded",
|
|
||||||
isAuto ? "text-emerald-400 bg-emerald-500/10" : "text-muted-foreground/60 bg-background/20")}
|
|
||||||
title={isAuto ? "Automatisch gelernt" : "Manuell angelegt"}>
|
|
||||||
{isAuto && <Sparkles className="h-2.5 w-2.5" />}{m.source}
|
|
||||||
</span>
|
|
||||||
<button onClick={() => del(m.id)} aria-label="Eintrag löschen" title="Eintrag löschen"
|
|
||||||
className="h-7 w-7 rounded-lg flex items-center justify-center border border-border/40 text-muted-foreground hover:text-red-400 hover:bg-red-500/5 transition-all opacity-0 group-hover:opacity-100">
|
|
||||||
<Trash2 className="h-3.5 w-3.5" aria-hidden="true" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
</>
|
{items.length === 0 ? (
|
||||||
|
<div className="text-xs text-muted-foreground border border-dashed border-border/60 rounded-2xl p-12 text-center bg-card/10">
|
||||||
|
Keine Einträge für die aktuellen Filterkriterien gefunden.
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="space-y-5 max-h-[calc(100vh-14rem)] overflow-y-auto pr-1 scrollbar-thin">
|
||||||
|
{[...CATEGORIES, "__other"].map((c) => {
|
||||||
|
const list = c === "__other" ? otherItems : (grouped[c] || [])
|
||||||
|
if (!list.length) return null
|
||||||
|
const conf = CAT_CONFIG[c] || DEFAULT_CAT
|
||||||
|
const Icon = conf.icon
|
||||||
|
return (
|
||||||
|
<div key={c} className="space-y-2">
|
||||||
|
{/* Sektions-Kopf je Kategorie */}
|
||||||
|
<div className="flex items-center gap-2 mb-2 px-1">
|
||||||
|
<Icon className={cn("h-3.5 w-3.5", conf.text)} />
|
||||||
|
<span className={cn("text-[11px] font-bold uppercase tracking-wider", conf.text)}>{conf.label}</span>
|
||||||
|
<span className="text-[10px] font-mono text-muted-foreground/60 bg-card/50 rounded px-1.5 py-0.5">{list.length}</span>
|
||||||
|
<div className="ml-1 h-px flex-1 bg-border/30" />
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
{list.map((m) => {
|
||||||
|
const isAuto = AUTO_SOURCES.has(m.source)
|
||||||
|
return (
|
||||||
|
<div key={m.id} className={cn("flex items-start justify-between gap-4 p-3.5 rounded-xl border border-l-4 bg-card/45 backdrop-blur-md border-border/60 hover:border-primary/20 transition-all group",
|
||||||
|
BORDER_CLASSES[m.category] || "border-l-muted")}>
|
||||||
|
<span className="text-xs text-foreground leading-relaxed break-words whitespace-pre-wrap flex-1 min-w-0">{m.content}</span>
|
||||||
|
<div className="flex items-center gap-2 shrink-0">
|
||||||
|
{typeof m.score === "number" && (
|
||||||
|
<span className="text-[9px] font-mono text-primary bg-primary/10 px-1.5 py-0.5 rounded" title="Relevanz der semantischen Suche">{Math.round(m.score * 100)}%</span>
|
||||||
|
)}
|
||||||
|
<span className={cn("flex items-center gap-1 text-[9px] font-mono px-1.5 py-0.5 rounded",
|
||||||
|
isAuto ? "text-emerald-400 bg-emerald-500/10" : "text-muted-foreground/60 bg-background/20")}
|
||||||
|
title={isAuto ? "Automatisch gelernt" : "Manuell angelegt"}>
|
||||||
|
{isAuto && <Sparkles className="h-2.5 w-2.5" />}{m.source}
|
||||||
|
</span>
|
||||||
|
<button onClick={() => del(m.id)} aria-label="Eintrag löschen" title="Eintrag löschen"
|
||||||
|
className="h-7 w-7 rounded-lg flex items-center justify-center border border-border/40 text-muted-foreground hover:text-red-400 hover:bg-red-500/5 transition-all opacity-0 group-hover:opacity-100">
|
||||||
|
<Trash2 className="h-3.5 w-3.5" aria-hidden="true" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Graph-Sicht */}
|
||||||
|
<div className={cn("flex-1", view === "liste" && "hidden lg:block")}>
|
||||||
|
<GraphErrorBoundary>
|
||||||
|
<Suspense fallback={<div className="h-[480px] rounded-2xl border border-border/60 bg-card/30 flex items-center justify-center text-xs text-muted-foreground">Graph wird geladen…</div>}>
|
||||||
|
<GraphView data={graphData} onDelete={del} />
|
||||||
|
</Suspense>
|
||||||
|
</GraphErrorBoundary>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{dialogElement}
|
{dialogElement}
|
||||||
|
|||||||
@@ -75,6 +75,20 @@ export function CockpitView({ onNavigate }: { onNavigate: (v: string) => void })
|
|||||||
const connectOk = connect?.gateway.ok && connect?.memory.ok
|
const connectOk = connect?.gateway.ok && connect?.memory.ok
|
||||||
const openAuftraege = auftraege?.available ? auftraege.open_count : 0
|
const openAuftraege = auftraege?.available ? auftraege.open_count : 0
|
||||||
|
|
||||||
|
// Zusätzliche reaktive Livedaten für die Kacheln
|
||||||
|
const activeBrain = models?.models?.find((m: any) => m.role === "hermes")
|
||||||
|
const brainName = activeBrain?.name ? activeBrain.name.split("/").pop()?.replace(/\.gguf$/i, "") : ""
|
||||||
|
const autoNotes = memory ? memory.filter((m: any) => ["auto", "agent", "hermes"].includes(m.source)).length : 0
|
||||||
|
const failedSvc = svc?.services.filter((s: any) => !s.ok).map((s: any) => s.name).join(", ")
|
||||||
|
|
||||||
|
const upParts = updates ? [
|
||||||
|
updates.os > 0 && "OS",
|
||||||
|
updates.engine > 0 && "Engine",
|
||||||
|
updates.swap > 0 && "Swap",
|
||||||
|
updates.models > 0 && "Modelle"
|
||||||
|
].filter(Boolean) : []
|
||||||
|
const updateSummary = upParts.length > 0 ? upParts.join(" + ") : ""
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-7">
|
<div className="space-y-7">
|
||||||
{/* Kopf */}
|
{/* Kopf */}
|
||||||
@@ -109,38 +123,44 @@ export function CockpitView({ onNavigate }: { onNavigate: (v: string) => void })
|
|||||||
icon={Inbox} title="Auftragsbuch" value={auftraege?.available ? openAuftraege : "—"}
|
icon={Inbox} title="Auftragsbuch" value={auftraege?.available ? openAuftraege : "—"}
|
||||||
unit={openAuftraege === 1 ? "Vorschlag" : "Vorschläge"}
|
unit={openAuftraege === 1 ? "Vorschlag" : "Vorschläge"}
|
||||||
tone={!auftraege ? "loading" : openAuftraege > 0 ? "warn" : "ok"}
|
tone={!auftraege ? "loading" : openAuftraege > 0 ? "warn" : "ok"}
|
||||||
hint="Annehmen oder ablehnen"
|
hint={openAuftraege > 0 ? `${openAuftraege} offene Patches prüfen` : "Keine ausstehenden Vorschläge"}
|
||||||
onClick={() => onNavigate("auftraege")}
|
onClick={() => onNavigate("auftraege")}
|
||||||
/>
|
/>
|
||||||
<CockpitTile
|
<CockpitTile
|
||||||
icon={Boxes} title="Modelle" value={running} unit="warm"
|
icon={Boxes} title="Modelle" value={running} unit="warm"
|
||||||
tone={running > 0 ? "ok" : "muted"} hint="Speicher, laden & Rollen"
|
tone={running > 0 ? "ok" : "muted"}
|
||||||
|
hint={brainName ? `Hirn: ${brainName}` : "Kein Hermes-Modell geladen"}
|
||||||
onClick={() => onNavigate("models")}
|
onClick={() => onNavigate("models")}
|
||||||
/>
|
/>
|
||||||
<CockpitTile
|
<CockpitTile
|
||||||
icon={Brain} title="Gedächtnis" value={memory ? notes : "…"} unit="Notizen"
|
icon={Brain} title="Gedächtnis" value={memory ? notes : "…"} unit="Notizen"
|
||||||
tone={memory ? "ok" : "loading"} hint="Lucys geteiltes Wissen"
|
tone={memory ? "ok" : "loading"}
|
||||||
|
hint={memory ? `${notes} Fakten (${autoNotes} auto gelernt)` : "Gedächtnis-Pool laden..."}
|
||||||
onClick={() => onNavigate("memory")}
|
onClick={() => onNavigate("memory")}
|
||||||
/>
|
/>
|
||||||
<CockpitTile
|
<CockpitTile
|
||||||
icon={Server} title="Dienste" value={svc ? `${svcOk}/${svcTotal}` : "…"} unit="laufen"
|
icon={Server} title="Dienste" value={svc ? `${svcOk}/${svcTotal}` : "…"} unit="laufen"
|
||||||
tone={!svc ? "loading" : svcErrors > 0 ? "warn" : "ok"} hint="Status & Neustart"
|
tone={!svc ? "loading" : svcErrors > 0 ? "warn" : "ok"}
|
||||||
|
hint={failedSvc ? `Ausfall: ${failedSvc}` : "Alle Dienste online"}
|
||||||
onClick={() => openDrawer("maintenance")}
|
onClick={() => openDrawer("maintenance")}
|
||||||
/>
|
/>
|
||||||
<CockpitTile
|
<CockpitTile
|
||||||
icon={ShieldAlert} title="Updates" value={updates ? (pendingCount > 0 ? pendingCount : "0") : "…"}
|
icon={ShieldAlert} title="Updates" value={updates ? (pendingCount > 0 ? pendingCount : "0") : "…"}
|
||||||
unit={pendingCount > 0 ? "bereit" : "aktuell"}
|
unit={pendingCount > 0 ? "bereit" : "aktuell"}
|
||||||
tone={!updates ? "loading" : pendingCount > 0 ? "warn" : "ok"} hint="Prüfen & einspielen"
|
tone={!updates ? "loading" : pendingCount > 0 ? "warn" : "ok"}
|
||||||
|
hint={pendingCount > 0 ? `Verfügbar: ${updateSummary}` : "Alles auf dem neuesten Stand"}
|
||||||
onClick={() => openDrawer("maintenance")}
|
onClick={() => openDrawer("maintenance")}
|
||||||
/>
|
/>
|
||||||
<CockpitTile
|
<CockpitTile
|
||||||
icon={Plug} title="Verbinden" value="Zed" unit={connectOk ? "· bereit" : ""}
|
icon={Plug} title="Verbinden" value="Zed" unit={connectOk ? "· bereit" : ""}
|
||||||
tone={!connect ? "loading" : connectOk ? "ok" : "warn"} hint="IDE- & Agent-Configs"
|
tone={!connect ? "loading" : connectOk ? "ok" : "warn"}
|
||||||
|
hint={agent?.pc_executor_reachable ? "IDE & PC online (:7777)" : "IDE-Kopplung (PC offline)"}
|
||||||
onClick={() => onNavigate("connect")}
|
onClick={() => onNavigate("connect")}
|
||||||
/>
|
/>
|
||||||
<CockpitTile
|
<CockpitTile
|
||||||
icon={ScrollText} title="Logs" value={svc ? svcErrors : "…"} unit={svcErrors === 1 ? "Fehler" : "Fehler"}
|
icon={ScrollText} title="Logs" value={svc ? svcErrors : "…"} unit={svcErrors === 1 ? "Fehler" : "Fehler"}
|
||||||
tone={!svc ? "loading" : svcErrors > 0 ? "alert" : "ok"} hint="Verlauf & Diagnose"
|
tone={!svc ? "loading" : svcErrors > 0 ? "alert" : "ok"}
|
||||||
|
hint={svcErrors > 0 ? `${svcErrors} Dienst-Fehler gefunden` : "Keine Log-Warnungen"}
|
||||||
onClick={() => openDrawer("logs")}
|
onClick={() => openDrawer("logs")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -288,12 +308,12 @@ function NeedsYou({
|
|||||||
) : (
|
) : (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{problems.map((c) => (
|
{problems.map((c) => (
|
||||||
<div key={c.id} className="flex items-center justify-between gap-3 rounded-2xl border border-red-500/25 bg-red-500/5 p-4">
|
<div key={c.id} className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 rounded-2xl border border-red-500/25 bg-red-500/5 p-4">
|
||||||
<div className="flex min-w-0 items-center gap-3">
|
<div className="flex min-w-0 items-center gap-3 w-full">
|
||||||
<span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border border-red-500/30 bg-background/30 text-red-300">
|
<span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg border border-red-500/30 bg-background/30 text-red-300">
|
||||||
<c.icon className="h-4.5 w-4.5" />
|
<c.icon className="h-4.5 w-4.5" />
|
||||||
</span>
|
</span>
|
||||||
<div className="min-w-0">
|
<div className="min-w-0 flex-1">
|
||||||
<p className="text-sm font-bold text-foreground">{c.label}</p>
|
<p className="text-sm font-bold text-foreground">{c.label}</p>
|
||||||
<p className="truncate text-xs text-muted-foreground">{c.detail}</p>
|
<p className="truncate text-xs text-muted-foreground">{c.detail}</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -302,7 +322,7 @@ function NeedsYou({
|
|||||||
<button
|
<button
|
||||||
onClick={() => c.repair && onRepair(c.id, c.repair)}
|
onClick={() => c.repair && onRepair(c.id, c.repair)}
|
||||||
disabled={!!busy[c.id]}
|
disabled={!!busy[c.id]}
|
||||||
className="flex h-9 shrink-0 items-center gap-1.5 rounded-lg border border-red-500/40 bg-red-500/10 px-3 text-[11px] font-bold uppercase tracking-wide text-red-300 transition-all hover:bg-red-500/20 cursor-pointer disabled:opacity-60"
|
className="flex h-9 shrink-0 items-center gap-1.5 rounded-lg border border-red-500/40 bg-red-500/10 px-3 text-[11px] font-bold uppercase tracking-wide text-red-300 transition-all hover:bg-red-500/20 cursor-pointer disabled:opacity-60 w-full sm:w-auto justify-center"
|
||||||
>
|
>
|
||||||
{busy[c.id] ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Wrench className="h-3.5 w-3.5" />}
|
{busy[c.id] ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Wrench className="h-3.5 w-3.5" />}
|
||||||
{c.repair.label}
|
{c.repair.label}
|
||||||
|
|||||||
Reference in New Issue
Block a user