Compare commits

...

3 Commits

Author SHA1 Message Date
devops 86ceb2bcce style: unify all views on Mission Control V2 design tokens
CI - Build & Test / Backend (.NET) (push) Successful in 31s
CI - Build & Test / Frontend (Vue/TS) (push) Successful in 16s
CI - Build & Test / Security Check (push) Successful in 3s
CI - Build & Test / Deploy Nexus (push) Has been skipped
- Map legacy v1 CSS variables (--nx-*, --panel, --text-*, --surface*) to V2 tokens in nexus-tokens.css
- Restyle global shell (main.css), AppSidebar, AppHeader to match V2 Sidebar/Topbar (glass, gradients, Space Grotesk)
- Add GalaxyBackground to the v1 shell in App.vue
- Replace hardcoded v1 hex colors with V2 tokens in all deviating views (Agents, Calendar, Docs, Incidents, Memory, Notifications, ProjectDetail, Security, Team, TaskDetail, Settings)
- Keep JS status colors as hex where alpha suffixes are concatenated (AgentsIndex, Team, Notifications)
- Add Settings nav item (System group) + gear icon to V2 sidebar so it shows on the dashboard
- No component or layout structure changes; LoginView and TaskBoardView untouched

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 08:05:52 +02:00
devops 706ff82ccd fix: harden Nexus runtime health and rollback 2026-07-10 00:37:24 +02:00
devops dbda764190 fix: execute Nexus deploy inside host-mounted workspace
CI - Build & Test / Backend (.NET) (push) Successful in 33s
CI - Build & Test / Frontend (Vue/TS) (push) Successful in 16s
CI - Build & Test / Security Check (push) Successful in 3s
CI - Build & Test / Deploy Nexus (push) Failing after 21s
2026-07-10 00:16:47 +02:00
25 changed files with 638 additions and 518 deletions
+2 -2
View File
@@ -19,7 +19,7 @@ JWT_AUDIENCE=nexus-web
BOOTSTRAP_OWNER_EMAIL=***
# ── OpenClaw Integration ────────────────────────────────
# Base URL of the OpenClaw gateway (host.docker.internal from inside container)
OPENCLAW_BASE_URL=http://host.docker.internal:18789
# Internal Docker-DNS URL of the OpenClaw gateway
OPENCLAW_BASE_URL=http://openclaw-gateway-bao:18789
OPENCLAW_GATEWAY_TOKEN=***
OPENCLAW_GATEWAY_PASSWORD=***
+19 -23
View File
@@ -3,18 +3,13 @@ set -eu
DEPLOY_PATH="${DEPLOY_PATH:-/home/projekte_bao/nexus}"
ENV_TMPFILE_TEMPLATE="${ENV_TMPFILE:-/tmp/nexus-deploy-env}"
COMPOSE_SCRIPT_TEMPLATE="${COMPOSE_SCRIPT:-/tmp/nexus-compose-deploy.sh}"
ENV_TMPFILE=""
COMPOSE_SCRIPT=""
BASE_URL="${BASE_URL:-https://nexus.noveria.net}"
cleanup() {
if [ -n "$ENV_TMPFILE" ] && [ -f "$ENV_TMPFILE" ]; then
shred -u "$ENV_TMPFILE" 2>/dev/null || rm -f "$ENV_TMPFILE"
fi
if [ -n "$COMPOSE_SCRIPT" ]; then
rm -f "$COMPOSE_SCRIPT"
fi
}
trap cleanup EXIT INT TERM
@@ -39,8 +34,7 @@ secure_tmpfile() {
}
ENV_TMPFILE="$(secure_tmpfile "$ENV_TMPFILE_TEMPLATE")"
COMPOSE_SCRIPT="$(secure_tmpfile "$COMPOSE_SCRIPT_TEMPLATE")"
chmod 600 "$ENV_TMPFILE" "$COMPOSE_SCRIPT"
chmod 600 "$ENV_TMPFILE"
if [ ! -f VERSION ]; then
echo "VERSION file not found" >&2
@@ -66,7 +60,7 @@ JWT_KEY=${ENV_JWT_KEY}
JWT_ISSUER=nexus
JWT_AUDIENCE=nexus-web
BOOTSTRAP_OWNER_EMAIL=vmbao62@hotmail.de
OPENCLAW_BASE_URL=http://host.docker.internal:18789
OPENCLAW_BASE_URL=http://openclaw-gateway-bao:18789
OPENCLAW_GATEWAY_TOKEN=${ENV_OPENCLAW_TOKEN:-}
OPENCLAW_GATEWAY_PASSWORD=
NEXUS_VERSION=${VERSION}
@@ -112,24 +106,20 @@ git archive --format=tar HEAD | docker run --rm -i \
'
echo "Building and starting Docker compose stack"
cat > "$COMPOSE_SCRIPT" <<'EOF_DEPLOY'
#!/bin/sh
set -eu
cat > /tmp/nexus-deploy-env
docker compose --env-file /tmp/nexus-deploy-env build
docker compose --env-file /tmp/nexus-deploy-env up -d --force-recreate --remove-orphans --wait
docker compose --env-file /tmp/nexus-deploy-env ps
rm -f /tmp/nexus-deploy-env
EOF_DEPLOY
docker run --rm \
-v "$DEPLOY_PATH:/workspace/nexus" \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$COMPOSE_SCRIPT:/deploy.sh:ro" \
-w /workspace/nexus \
-i \
docker:cli \
sh /deploy.sh < "$ENV_TMPFILE"
sh -c 'set -eu
umask 077
cat > /tmp/nexus-deploy-env
trap '\''rm -f /tmp/nexus-deploy-env'\'' EXIT INT TERM
docker compose --env-file /tmp/nexus-deploy-env build
docker compose --env-file /tmp/nexus-deploy-env up -d --force-recreate --remove-orphans --wait
docker compose --env-file /tmp/nexus-deploy-env ps
' < "$ENV_TMPFILE"
echo "Verifying image provenance"
for container in nexus-api-1 nexus-web-1; do
@@ -150,9 +140,15 @@ echo "Checking live health"
retry=0
while [ "$retry" -lt 6 ]; do
retry=$((retry + 1))
if curl -fsS --max-time 10 "$BASE_URL/health" >/dev/null; then
echo "Health check passed"
break
health_body="$(curl -fsS --max-time 10 "$BASE_URL/health" 2>/dev/null || true)"
case "$health_body" in
'{"status":"Healthy"'*)
echo "Health check passed"
break
;;
esac
if [ -n "$health_body" ]; then
echo "Health endpoint is reachable but not healthy: $health_body" >&2
fi
if [ "$retry" -eq 6 ]; then
echo "Health check failed" >&2
+50 -23
View File
@@ -112,9 +112,11 @@ jobs:
JWT_ISSUER=nexus
JWT_AUDIENCE=nexus-web
BOOTSTRAP_OWNER_EMAIL=vmbao62@hotmail.de
OPENCLAW_BASE_URL=http://host.docker.internal:18789
OPENCLAW_BASE_URL=http://openclaw-gateway-bao:18789
OPENCLAW_GATEWAY_TOKEN=${ENV_OPENCLAW_TOKEN}
OPENCLAW_GATEWAY_PASSWORD=
NEXUS_VERSION=$(tr -d '[:space:]' < VERSION)
NEXUS_GIT_SHA=$(git rev-parse HEAD)
EOF
chmod 600 "${ENV_TMPFILE}"
@@ -127,18 +129,38 @@ jobs:
run: |
set -euo pipefail
docker run --rm \
-v "${{ gitea.workspace }}:/src:ro" \
git archive --format=tar HEAD | docker run --rm -i \
-v "${DEPLOY_PATH}:/dest" \
alpine:latest \
sh -c "
cd /src && \
find . -mindepth 1 -maxdepth 1 \
! -name .git \
-exec cp -r {} /dest/ \; && \
DEST_OWNER=\$(stat -c '%u:%g' /dest) && \
chown -R \"\$DEST_OWNER\" /dest
"
sh -c '
set -eu
dest_owner="$(stat -c "%u:%g" /dest)"
mkdir -p /src-snapshot
tar -xf - -C /src-snapshot
is_protected_path() {
case "$1" in
./.git|./.env|./.env.*|./data|./logs|./backups|./tmp|./uploads|./storage)
return 0
;;
*)
return 1
;;
esac
}
cd /dest
find . -mindepth 1 -maxdepth 1 | while IFS= read -r path; do
if ! is_protected_path "$path"; then rm -rf "$path"; fi
done
cd /src-snapshot
find . -mindepth 1 -maxdepth 1 | while IFS= read -r path; do
if ! is_protected_path "$path"; then cp -a "$path" /dest/; fi
done
chown -R "$dest_owner" /dest
'
echo "✅ Rollback code (${{ inputs.target_tag }}) synced to ${DEPLOY_PATH}"
@@ -151,16 +173,18 @@ jobs:
docker run --rm \
-v "${DEPLOY_PATH}:/workspace/nexus" \
-v "/tmp:/tmp-host:ro" \
-v /var/run/docker.sock:/var/run/docker.sock \
-w /workspace/nexus \
-i \
docker:cli \
sh -c "
set -e
echo '🔙 Rolling back to ${{ inputs.target_tag }}'
docker compose --env-file /tmp-host/$(basename "${ENV_TMPFILE}") build --no-cache
docker compose --env-file /tmp-host/$(basename "${ENV_TMPFILE}") up -d --wait --force-recreate
"
sh -c '
set -eu
umask 077
cat > /tmp/nexus-rollback-env
trap '\''rm -f /tmp/nexus-rollback-env'\'' EXIT INT TERM
docker compose --env-file /tmp/nexus-rollback-env build --no-cache
docker compose --env-file /tmp/nexus-rollback-env up -d --wait --force-recreate
' < "${ENV_TMPFILE}"
echo "✅ Rollback redeploy completed"
@@ -186,11 +210,14 @@ jobs:
WAIT=1
while [ $RETRY -lt $MAX ]; do
RETRY=$((RETRY + 1))
if curl -sf --max-time 10 https://nexus.noveria.net/health; then
echo ""
echo "✅ Health check passed (attempt $RETRY/$MAX)"
exit 0
fi
HEALTH_BODY=$(curl -sf --max-time 10 https://nexus.noveria.net/health || true)
case "$HEALTH_BODY" in
'{"status":"Healthy"'*)
echo "✅ Health check passed (attempt $RETRY/$MAX)"
exit 0
;;
esac
[ -n "$HEALTH_BODY" ] && echo "⚠️ Health endpoint is degraded: $HEALTH_BODY"
echo "⏳ Attempt $RETRY/$MAX failed, waiting ${WAIT}s..."
sleep $WAIT
NEXT=$((WAIT + RETRY))
+12 -3
View File
@@ -2,6 +2,15 @@ name: nexus
services:
postgres:
image: postgres:17-alpine
# WAL-Archivierung bleibt deaktiviert, bis ein verwaltetes Off-Server-Ziel
# mit Retention und Restore-Test existiert. Ein lokales Endlosarchiv ist
# kein Backup und kann bei Fehlern pg_wal ungebremst wachsen lassen.
command:
- postgres
- -c
- archive_mode=off
- -c
- archive_command=
restart: always
deploy:
resources:
@@ -50,7 +59,7 @@ services:
Jwt__Audience: ${JWT_AUDIENCE:-nexus-web}
Bootstrap__OwnerEmail: ${BOOTSTRAP_OWNER_EMAIL:?Set BOOTSTRAP_OWNER_EMAIL in .env}
# Initial owner password is generated once at first seed and then lives only in the DB.
Integrations__OpenClaw__BaseUrl: ${OPENCLAW_BASE_URL:-http://host.docker.internal:18789}
Integrations__OpenClaw__BaseUrl: ${OPENCLAW_BASE_URL:-http://openclaw-gateway-bao:18789}
Integrations__OpenClaw__Token: ${OPENCLAW_GATEWAY_TOKEN:-}
Integrations__OpenClaw__Password: ${OPENCLAW_GATEWAY_PASSWORD:-}
Admin__ResetToken: ${Admin__ResetToken:-}
@@ -59,7 +68,7 @@ services:
- host.docker.internal:host-gateway
depends_on:
postgres:
condition: service_started
condition: service_healthy
restart: true
healthcheck:
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:8080/health/live || exit 1"]
@@ -106,7 +115,7 @@ services:
- "127.0.0.1:18880:80"
depends_on:
api:
condition: service_started
condition: service_healthy
restart: true
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:80/ || exit 1"]
+16 -21
View File
@@ -68,8 +68,8 @@ Ansatz. Das Backend fungiert bereits als sichere Schicht zwischen allen Akteuren
│ │
│ ALLE Gateway-Calls → Authorization: Bearer <Gateway-Password> │
└──────────────┬──────────────────────────────┬────────────────────┘
host.docker.internal:18789 │
│ (Gateway loopback/lan)
openclaw-gateway-bao:18789 │
│ (internes Docker-DNS)
▼ │
┌──────────────────────────────┐ │
│ OpenClaw Gateway Container │ │
@@ -199,7 +199,7 @@ Ebene 4: X-Agent-Id Header (Agent-Identität für Task-State-Enforcement)
```
POST /api/v1/operations/snapshot
→ DashboardService → OpenClawGatewayClient.InvokeToolAsync()
→ POST http://host.docker.internal:18789/tools/invoke
→ POST http://openclaw-gateway-bao:18789/tools/invoke
Authorization: Bearer <Gateway-Password>
```
@@ -220,7 +220,7 @@ POST /api/v1/operations/snapshot
### 5.2 Docker-Netzwerk & Gateway-Bind
**Aktuelles Problem:**
**Aktueller Stand (2026-07-09):**
```
compose.yaml:
api:
@@ -228,32 +228,27 @@ compose.yaml:
- host.docker.internal:host-gateway
networks:
- nexus
- openclaw_default ← API-Container ist im Gateway-Netzwerk
- openclaw_default
Gateway-Konfiguration:
gateway.bind: "loopback" ← Bindet nur 127.0.0.1 IM GATEWAY-CONTAINER
gateway.bind: "lan"
Nexus-Konfiguration:
OPENCLAW_BASE_URL=http://openclaw-gateway-bao:18789
```
**Ergebnis:**
- `host.docker.internal:18789` funktioniert, weil `extra_hosts` auf den Docker-Host zeigt
- ABER: Docker-Port-Forward (wenn vorhanden) sendet an Container-IP, nicht loopback
- Die `openclaw_default` Netzwerk-Mitgliedschaft des API-Containers wird NICHT genutzt
- Nexus erreicht das Gateway direkt über Docker-DNS im gemeinsamen `openclaw_default`-Netz.
- Der Umweg über einen nicht veröffentlichten Host-Port entfällt.
- Der produktive Aggregat-Healthcheck prüft neben PostgreSQL auch die Runtime-Verbindung.
**Empfehlung (siehe gateway-api-research.md, Abschnitt 6):**
```json5
// openclaw.json
{
gateway: {
bind: "lan" // war "loopback"
}
}
```
Der frühere Pfad `host.docker.internal:18789` war auf dem VPS nicht erreichbar und ist obsolet.
Alternativ: API-Container über Gateway-Container-Namen ansprechen:
Produktive Einstellung:
```yaml
Integrations__OpenClaw__BaseUrl: http://openclaw_gateway:18789
Integrations__OpenClaw__BaseUrl: http://openclaw-gateway-bao:18789
```
(Vorausgesetzt der Gateway-Container heißt `openclaw_gateway` und ist im `openclaw_default` Netzwerk)
Beide Container müssen Mitglied im `openclaw_default`-Netzwerk sein.
### 5.3 MCP-artige Integration: Bewertung
+13 -13
View File
@@ -290,30 +290,30 @@ The Nexus compose.yaml already includes the full integration infrastructure:
```yaml
api:
extra_hosts:
- host.docker.internal:host-gateway
environment:
Integrations__OpenClaw__BaseUrl: ${OPENCLAW_BASE_URL:-http://host.docker.internal:18789}
Integrations__OpenClaw__BaseUrl: ${OPENCLAW_BASE_URL:-http://openclaw-gateway-bao:18789}
Integrations__OpenClaw__Token: ${OPENCLAW_GATEWAY_TOKEN:-}
Integrations__OpenClaw__Password: ${OPENCLAW_GATEWAY_PASSWORD:-}
networks:
- nexus
- openclaw_default
```
The API container:
- Uses `host.docker.internal:18789` to reach the Gateway via the Docker host
- Has `extra_hosts` configured for `host.docker.internal`
- Uses Docker DNS (`openclaw-gateway-bao:18789`) in the shared `openclaw_default` network
- Does not depend on a published host port for the Gateway
- Reads token/password from `.env` via `OPENCLAW_GATEWAY_PASSWORD`
### Known Issue: Gateway Bind = loopback
### Resolved Routing Issue (2026-07-09)
The Gateway binds to `127.0.0.1` (`gateway.bind: "loopback"`). This means it only listens inside the gateway container's loopback interface.
The old `host.docker.internal:18789` route was unreachable because no usable host port was published. The Gateway is now reached directly by its container DNS name.
| Scenario | Works? | Why |
|----------|--------|-----|
| Gateway with `--network host` | ✅ Yes | Process sees host's 127.0.0.1 directly |
| Gateway with `-p 18789:18789` + loopback bind | ❌ No | Port forward sends to container IP, not loopback |
| Gateway with `-p 18789:18789` + lan bind | ✅ Yes | Listens on all interfaces including container IP |
| `host.docker.internal:18789` | ❌ No | No reachable host listener on the VPS |
| `openclaw-gateway-bao:18789` in `openclaw_default` | ✅ Yes | Direct container-to-container routing via Docker DNS |
**Fix**: Change `gateway.bind` from `"loopback"` to `"lan"` (binds `0.0.0.0`):
The Gateway must listen on its container interface (`gateway.bind: "lan"`):
```json5
{
@@ -325,8 +325,8 @@ The Gateway binds to `127.0.0.1` (`gateway.bind: "loopback"`). This means it onl
**Test command (from Nexus API container):**
```bash
curl -s http://host.docker.internal:18789/health
# Expected: 200 if gateway bind is lan/container IP is reachable
curl -s http://openclaw-gateway-bao:18789/
# Expected: HTTP 200 from inside nexus-api-1
```
### Required .env Vars for Nexus
+4
View File
@@ -6,6 +6,7 @@ import { useOperationsStore } from './stores/operations'
import { useAuthStore } from './stores/auth'
import AppSidebar from './components/layout/AppSidebar.vue'
import AppHeader from './components/layout/AppHeader.vue'
import GalaxyBackground from './components/background/GalaxyBackground.vue'
import ModuleView from './components/ModuleView.vue'
import ToastContainer from './components/ui/ToastContainer.vue'
@@ -46,6 +47,7 @@ onMounted(() => {
<template>
<RouterView v-if="route.name === 'Login' || route.name === 'Dashboard'" />
<div v-else class="shell">
<GalaxyBackground />
<AppSidebar
:active-view="activeView"
:mobile-nav-open="mobileNavOpen"
@@ -103,6 +105,8 @@ main {
display: flex;
flex-direction: column;
min-width: 0;
position: relative;
z-index: 1;
}
.content {
+108 -80
View File
@@ -83,8 +83,11 @@
}
body {
background: hsl(var(--background));
color: hsl(var(--foreground));
background:
radial-gradient(1100px 700px at 12% -10%, rgba(79, 124, 255, 0.10), transparent 60%),
radial-gradient(1000px 700px at 95% 8%, rgba(181, 87, 246, 0.09), transparent 60%),
var(--space-0, #050410);
color: var(--tx, #ece9ff);
font-family: 'Manrope', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
'Segoe UI', sans-serif;
margin: 0;
@@ -92,6 +95,10 @@ body {
min-height: 100vh;
}
h1, h2, h3, .font-display {
font-family: 'Space Grotesk', 'Manrope', sans-serif;
}
/* Nexus overrides for existing CSS variables used in dashboard */
:root {
--nx-bg: #080a0f;
@@ -126,9 +133,9 @@ body {
display: flex;
flex-direction: column;
padding: 22px 14px 14px;
border-right: 1px solid #1a1e27;
background: rgba(9, 11, 16, 0.94);
backdrop-filter: blur(18px);
border-right: 1px solid var(--line);
background: linear-gradient(180deg, rgba(14, 12, 32, 0.92), rgba(8, 6, 20, 0.92));
backdrop-filter: blur(14px);
}
.brand {
@@ -143,15 +150,16 @@ body {
height: 35px;
display: grid;
place-items: center;
border: 1px solid #443d7c;
border-radius: 10px;
background: linear-gradient(145deg, #241f44, #12121f);
color: #b8adff;
box-shadow: 0 0 24px rgba(139, 124, 246, 0.13);
border: none;
border-radius: 11px;
background: var(--grad);
color: #fff;
box-shadow: var(--glow-purple);
}
.brand strong {
display: block;
font-family: 'Space Grotesk', sans-serif;
font-size: 13px;
letter-spacing: 0.14em;
}
@@ -178,36 +186,38 @@ body {
gap: 10px;
border: 0;
padding: 9px 10px;
border-radius: 7px;
border-radius: 10px;
background: transparent;
color: #8991a1;
color: var(--tx-2);
font-size: 12px;
text-align: left;
cursor: pointer;
}
.nav button:hover,
.nav button.active {
color: #ececf5;
background: var(--nx-accent-soft);
.nav button:hover {
color: var(--tx);
background: rgba(124, 108, 255, 0.08);
}
.nav button.active {
box-shadow: inset 2px 0 var(--nx-accent);
color: #fff;
background: linear-gradient(90deg, rgba(124, 108, 255, 0.22), rgba(124, 108, 255, 0.04));
box-shadow: inset 0 0 0 1px rgba(124, 108, 255, 0.25);
}
.nav button i {
margin-left: auto;
padding: 1px 6px;
border: 1px solid #343947;
border: 1px solid var(--line-2);
border-radius: 8px;
background: rgba(124, 108, 255, 0.10);
font-size: 9px;
font-style: normal;
}
.sidebar-bottom {
margin-top: auto;
border-top: 1px solid #1b1f28;
border-top: 1px solid var(--line);
padding-top: 10px;
}
@@ -240,10 +250,12 @@ body {
height: 31px;
display: grid;
place-items: center;
border-radius: 50%;
background: #28243f;
color: #bcb3ff;
border-radius: 10px;
background: var(--grad-soft);
border: 1px solid var(--line-2);
color: var(--tx);
font-size: 10px;
font-weight: 700;
}
main {
@@ -256,9 +268,9 @@ main {
align-items: center;
justify-content: space-between;
padding: 0 30px;
border-bottom: 1px solid #191d25;
background: rgba(8, 10, 15, 0.68);
backdrop-filter: blur(16px);
border-bottom: 1px solid var(--line);
background: rgba(8, 6, 20, 0.5);
backdrop-filter: blur(14px);
}
.search {
@@ -266,19 +278,20 @@ main {
display: flex;
align-items: center;
gap: 9px;
padding: 8px 10px;
border: 1px solid #202530;
border-radius: 7px;
color: #6f7889;
padding: 8px 12px;
border: 1px solid var(--line);
border-radius: 11px;
background: rgba(124, 108, 255, 0.06);
color: var(--tx-3);
font-size: 11px;
}
.search kbd {
margin-left: auto;
padding: 2px 5px;
border: 1px solid #2c313d;
border: 1px solid var(--line-2);
border-radius: 4px;
color: #606979;
color: var(--tx-3);
font-size: 9px;
}
@@ -293,15 +306,20 @@ main {
gap: 6px;
align-items: center;
font-size: 10px;
color: #8c95a5;
font-weight: 600;
color: var(--tx-2);
border: 1px solid var(--line-2);
background: rgba(124, 108, 255, 0.07);
border-radius: 20px;
padding: 4px 11px;
}
.connection.live {
color: var(--nx-green);
color: var(--st-work);
}
.connection.preview {
color: #e6b75d;
color: var(--st-queue);
}
.ask,
@@ -309,13 +327,20 @@ main {
display: flex;
align-items: center;
gap: 7px;
padding: 8px 11px;
border: 1px solid #37315e;
border-radius: 7px;
background: #18152a;
color: #c4bbff;
padding: 8px 13px;
border: none;
border-radius: 10px;
background: var(--grad);
color: #fff;
font-weight: 600;
box-shadow: var(--glow-purple);
font-size: 10px;
cursor: pointer;
transition: filter .16s;
}
.ask:hover {
filter: brightness(1.08);
}
.content {
@@ -331,7 +356,7 @@ main {
.eyebrow,
.kicker {
color: #7065c8;
color: var(--a-mid);
font-size: 9px;
font-weight: 700;
letter-spacing: 0.18em;
@@ -351,9 +376,10 @@ h1 {
}
.refresh-btn {
border-color: var(--nx-line);
background: var(--nx-panel);
color: #a5adba;
background: rgba(124, 108, 255, 0.07);
border: 1px solid var(--line-2);
box-shadow: none;
color: var(--tx-2);
}
.spin {
@@ -370,7 +396,7 @@ h1 {
display: none;
border: 0;
background: transparent;
color: #aaa4e7;
color: var(--tx-2);
}
/* ── Keep existing module/layout styles for non-dashboard pages ── */
@@ -383,9 +409,10 @@ h1 {
.metrics article,
.panel {
border: 1px solid var(--nx-line);
background: linear-gradient(145deg, rgba(18, 21, 29, 0.96), rgba(12, 15, 21, 0.96));
border-radius: 9px;
border: 1px solid var(--line);
background: var(--glass);
border-radius: var(--r);
backdrop-filter: blur(12px);
}
.metrics article {
@@ -393,7 +420,7 @@ h1 {
}
.metrics span {
color: #717a8a;
color: var(--tx-3);
font-size: 8px;
font-weight: 700;
letter-spacing: 0.14em;
@@ -407,12 +434,12 @@ h1 {
}
.metrics small {
color: #687181;
color: var(--tx-3);
font-size: 9px;
}
.metrics small.up {
color: #55c995;
color: var(--st-work);
}
.dashboard-grid {
@@ -435,7 +462,7 @@ h1 {
align-items: center;
justify-content: space-between;
padding-bottom: 15px;
border-bottom: 1px solid #1d222c;
border-bottom: 1px solid var(--line);
}
.panel-head h2 {
@@ -446,7 +473,7 @@ h1 {
.panel-head button {
border: 0;
background: transparent;
color: #8e96a5;
color: var(--tx-2);
font-size: 9px;
}
@@ -457,18 +484,18 @@ h1 {
}
.badge.positive {
color: var(--nx-green);
background: rgba(81, 212, 154, 0.1);
color: var(--st-work);
background: rgba(61, 220, 151, 0.12);
}
.badge.warning {
color: #e7b660;
background: rgba(231, 182, 96, 0.1);
color: var(--st-queue);
background: rgba(251, 191, 36, 0.12);
}
.badge.negative {
color: #e16e75;
background: rgba(225, 110, 117, 0.1);
color: var(--st-block);
background: rgba(251, 113, 133, 0.12);
}
.runtime-row {
@@ -483,9 +510,10 @@ h1 {
height: 45px;
display: grid;
place-items: center;
border-radius: 9px;
color: #ad9fff;
background: var(--nx-accent-soft);
border-radius: var(--r-sm);
color: var(--a-mid);
background: var(--grad-soft);
border: 1px solid var(--line-2);
}
.runtime-main strong,
@@ -517,7 +545,7 @@ h1 {
width: 3px;
min-height: 5px;
border-radius: 3px;
background: linear-gradient(#927fff, #443b7c);
background: linear-gradient(var(--a-mid), rgba(124, 108, 255, 0.35));
}
.model {
@@ -526,11 +554,11 @@ h1 {
align-items: center;
gap: 9px;
padding: 12px 2px;
border-bottom: 1px solid #1b2029;
border-bottom: 1px solid var(--line);
}
.model > span:last-child {
color: #687181;
color: var(--tx-3);
font-size: 8px;
}
@@ -538,16 +566,16 @@ h1 {
width: 6px;
height: 6px;
border-radius: 50%;
background: #657083;
background: var(--st-idle);
}
.status-dot.online {
background: var(--nx-green);
box-shadow: 0 0 7px rgba(81, 212, 154, 0.4);
background: var(--st-work);
box-shadow: 0 0 7px rgba(61, 220, 151, 0.4);
}
.status-dot.offline {
background: #e16e75;
background: var(--st-block);
}
.project {
@@ -556,7 +584,7 @@ h1 {
align-items: center;
gap: 11px;
padding: 12px 0;
border-bottom: 1px solid #1b2029;
border-bottom: 1px solid var(--line);
}
.project-letter {
@@ -564,9 +592,9 @@ h1 {
height: 31px;
display: grid;
place-items: center;
border: 1px solid #353047;
border: 1px solid var(--line-2);
border-radius: 7px;
color: #a99cf5;
color: var(--a-mid);
font-size: 10px;
}
@@ -581,7 +609,7 @@ h1 {
}
.project b {
color: #838c9c;
color: var(--tx-2);
font-size: 9px;
}
@@ -590,14 +618,14 @@ h1 {
margin-top: 8px;
overflow: hidden;
border-radius: 4px;
background: #242936;
background: var(--space-3);
}
.progress i {
display: block;
height: 100%;
border-radius: inherit;
background: linear-gradient(90deg, #685ac8, #a091ff);
background: var(--grad);
}
.event {
@@ -605,7 +633,7 @@ h1 {
grid-template-columns: auto 1fr;
gap: 10px;
padding: 12px 0;
border-bottom: 1px solid #1b2029;
border-bottom: 1px solid var(--line);
}
.event > span {
@@ -613,19 +641,19 @@ h1 {
height: 6px;
margin-top: 4px;
border-radius: 50%;
background: #657083;
background: var(--st-idle);
}
.event > span.runtime {
background: var(--nx-green);
background: var(--st-work);
}
.event > span.deploy {
background: #8b7cf6;
background: var(--a-mid);
}
.event > span.security {
background: #e5ad52;
background: var(--st-queue);
}
.placeholder {
@@ -639,7 +667,7 @@ h1 {
.placeholder svg {
margin-bottom: 18px;
color: #8074d8;
color: var(--a-mid);
}
.placeholder h2 {
+25
View File
@@ -53,6 +53,31 @@
--sidebar-w: 248px;
--topbar-h: 62px;
--rail-w: 360px;
/* ── Legacy-Aliasse (v1-Views) → V2-Tokens ────────────
Ältere Views konsumieren noch die v1-Variablennamen.
Nicht anfassen: --border/--accent (shadcn-HSL-Tripel,
werden als hsl(var(--…)) konsumiert). */
--nx-bg: var(--space-1);
--nx-panel: var(--glass);
--nx-panel-soft: var(--glass-2);
--nx-line: var(--line);
--nx-muted: var(--tx-3);
--nx-accent: var(--a-mid);
--nx-accent-soft: rgba(124, 108, 255, 0.10);
--nx-green: var(--st-work);
--nx-text: var(--tx);
--nx-text-dim: var(--tx-2);
--panel: var(--glass);
--card-color: var(--glass);
--surface: var(--space-2);
--surface-raised: var(--space-3);
--accent-soft: rgba(124, 108, 255, 0.10);
--accent-secondary: var(--a-purple);
--text-primary: var(--tx);
--text-secondary: var(--tx-2);
--text-muted: var(--tx-3);
--text-dim: var(--tx-3);
}
/* ── Glass card utility ────────────────────────────── */
+28 -17
View File
@@ -35,9 +35,10 @@ defineEmits<{
display: flex;
align-items: center;
gap: 12px;
padding: 10px 20px;
border-bottom: 1px solid var(--nx-line, #1f2330);
background: var(--nx-panel, #11141b);
padding: 12px 22px;
border-bottom: 1px solid var(--line);
background: rgba(8, 6, 20, 0.5);
backdrop-filter: blur(14px);
}
.mobile-menu { display: none; }
.search {
@@ -45,24 +46,27 @@ defineEmits<{
align-items: center;
gap: 8px;
flex: 1;
padding: 6px 12px;
border: 1px solid var(--nx-line, #1f2330);
border-radius: 7px;
color: var(--nx-text-dim, #6f7889);
max-width: 560px;
padding: 8px 14px;
border: 1px solid var(--line);
border-radius: 11px;
background: rgba(124, 108, 255, 0.06);
color: var(--tx-3);
font-size: 11px;
}
.search kbd {
margin-left: auto;
padding: 1px 4px;
border: 1px solid #2a2f3d;
border: 1px solid var(--line-2);
border-radius: 4px;
font-size: 8px;
color: #4a5266;
color: var(--tx-3);
}
.top-actions {
display: flex;
align-items: center;
gap: 10px;
margin-left: auto;
}
.connection {
display: flex;
@@ -70,25 +74,32 @@ defineEmits<{
gap: 5px;
font-size: 9px;
font-weight: 600;
padding: 4px 9px;
border-radius: 6px;
padding: 4px 11px;
border-radius: 20px;
border: 1px solid var(--line-2);
background: rgba(124, 108, 255, 0.07);
color: var(--tx-2);
}
.connection.live { color: #27ae60; background: rgba(39,174,96,.1); }
.connection.preview { color: #e67e22; background: rgba(230,126,34,.1); }
.connection.live { color: var(--st-work); }
.connection.preview { color: var(--st-queue); }
.ask {
display: flex;
align-items: center;
gap: 5px;
padding: 5px 10px;
padding: 6px 12px;
border: none;
border-radius: 6px;
background: var(--nx-accent, #7b6ef2);
border-radius: 10px;
background: var(--grad);
box-shadow: var(--glow-purple);
color: #fff;
font-size: 10px;
font-weight: 600;
cursor: pointer;
transition: filter .16s;
}
.ask:hover { filter: brightness(1.08); }
@media (max-width: 860px) {
.mobile-menu { display: flex; align-items: center; justify-content: center; padding: 6px; border: 1px solid var(--nx-line, #1f2330); border-radius: 6px; background: transparent; color: var(--nx-accent, #7b6ef2); cursor: pointer; }
.mobile-menu { display: flex; align-items: center; justify-content: center; padding: 6px; border: 1px solid var(--line-2); border-radius: 9px; background: transparent; color: var(--tx-2); cursor: pointer; }
}
</style>
+43 -26
View File
@@ -104,8 +104,9 @@ async function logout() {
width: 210px;
display: flex;
flex-direction: column;
background: var(--panel, #11141b);
border-right: 1px solid var(--line, #1f2330);
background: linear-gradient(180deg, rgba(14, 12, 32, 0.92), rgba(8, 6, 20, 0.92));
border-right: 1px solid var(--line);
backdrop-filter: blur(14px);
flex-shrink: 0;
padding: 0 8px;
}
@@ -120,12 +121,13 @@ async function logout() {
height: 30px;
display: grid;
place-items: center;
border-radius: 7px;
background: var(--accent, #7b6ef2);
border-radius: 9px;
background: var(--grad);
box-shadow: var(--glow-purple);
color: #fff;
}
.brand div strong { display: block; font-size: 10px; letter-spacing: .08em; }
.brand div span { font-size: 8px; color: var(--text-dim, #6f7889); }
.brand div strong { display: block; font-family: 'Space Grotesk', sans-serif; font-size: 10px; letter-spacing: .12em; }
.brand div span { font-size: 8px; color: var(--tx-3); }
.nav {
flex: 1;
display: flex;
@@ -141,36 +143,45 @@ async function logout() {
width: 100%;
padding: 8px 10px;
border: none;
border-radius: 6px;
border-radius: 10px;
background: transparent;
color: #9ea5b3;
color: var(--tx-2);
font-size: 10.5px;
text-align: left;
cursor: pointer;
transition: background .15s, color .15s;
}
.nav button:hover { background: var(--accent-soft, rgba(123,110,242,.08)); color: #d8dbe3; }
.nav button.active { background: var(--accent-soft, rgba(123,110,242,.08)); color: var(--accent, #7b6ef2); font-weight: 600; }
.nav button:hover { background: rgba(124,108,255,.08); color: var(--tx); }
.nav button.active {
background: linear-gradient(90deg, rgba(124,108,255,.22), rgba(124,108,255,.04));
box-shadow: inset 0 0 0 1px rgba(124,108,255,.25);
color: #fff;
font-weight: 600;
}
.nav button i {
margin-left: auto;
background: var(--accent, #7b6ef2);
color: #fff;
background: rgba(124,108,255,.14);
border: 1px solid var(--line-2);
color: var(--tx);
font-family: 'JetBrains Mono', monospace;
font-style: normal;
font-size: 8px;
font-weight: 700;
padding: 1px 5px;
border-radius: 5px;
padding: 1px 6px;
border-radius: 20px;
line-height: 1.4;
}
.nav button i.badge-red {
background: #e16e75;
background: rgba(251,113,133,.18);
border-color: rgba(251,113,133,.4);
color: var(--st-block);
}
.nav-separator {
height: 1px;
margin: 6px 10px;
background: var(--nx-line, #1f2330);
background: var(--line);
}
.sidebar-bottom { padding: 8px 0; border-top: 1px solid var(--nx-line, #1f2330); }
.sidebar-bottom { padding: 8px 0; border-top: 1px solid var(--line); }
.sidebar-bottom > button {
display: flex;
align-items: center;
@@ -178,33 +189,39 @@ async function logout() {
width: 100%;
padding: 8px 10px;
border: none;
border-radius: 6px;
border-radius: 10px;
background: transparent;
color: #9ea5b3;
color: var(--tx-2);
font-size: 10.5px;
cursor: pointer;
transition: background .15s, color .15s;
}
.sidebar-bottom > button:hover { background: var(--nx-accent-soft, rgba(123,110,242,.08)); color: #d8dbe3; }
.sidebar-bottom > button.active { background: var(--nx-accent-soft, rgba(123,110,242,.08)); color: var(--nx-accent, #7b6ef2); font-weight: 600; }
.sidebar-bottom > button:hover { background: rgba(124,108,255,.08); color: var(--tx); }
.sidebar-bottom > button.active {
background: linear-gradient(90deg, rgba(124,108,255,.22), rgba(124,108,255,.04));
box-shadow: inset 0 0 0 1px rgba(124,108,255,.25);
color: #fff;
font-weight: 600;
}
.owner {
display: flex;
align-items: center;
gap: 8px;
margin-top: 6px;
}
.owner div strong { display: block; font-size: 9px; }
.owner div span { font-size: 7.5px; color: var(--text-dim, #6f7889); text-transform: capitalize; }
.owner div strong { display: block; font-size: 9px; color: var(--tx); }
.owner div span { font-size: 7.5px; color: var(--tx-3); text-transform: capitalize; }
.owner > svg:last-child { margin-left: auto; opacity: .4; transition: opacity .15s; }
.owner:hover > svg:last-child { opacity: 1; }
.avatar {
width: 26px;
height: 26px;
border-radius: 6px;
border-radius: 8px;
display: grid;
place-items: center;
background: var(--accent, #7b6ef2);
color: #fff;
background: var(--grad-soft);
border: 1px solid var(--line-2);
color: var(--tx);
font-size: 9px;
font-weight: 700;
}
+7
View File
@@ -25,6 +25,7 @@ export const icons: Record<string, string> = {
arrow: `<path d="M5 12h14M13 6l6 6-6 6"/>`,
plus: `<path d="M12 5v14M5 12h14"/>`,
command: `<path d="M7 4a3 3 0 0 0-3 3v10a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3V7a3 3 0 0 0-3-3H7z"/><path d="M12 8v8M8 12h8"/>`,
gear: `<circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .34 1.87l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.7 1.7 0 0 0-1.87-.34 1.7 1.7 0 0 0-1.03 1.56V21a2 2 0 1 1-4 0v-.09a1.7 1.7 0 0 0-1.11-1.56 1.7 1.7 0 0 0-1.87.34l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.7 1.7 0 0 0 .34-1.87 1.7 1.7 0 0 0-1.56-1.03H3a2 2 0 1 1 0-4h.09a1.7 1.7 0 0 0 1.56-1.11 1.7 1.7 0 0 0-.34-1.87l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.7 1.7 0 0 0 1.87.34h.09a1.7 1.7 0 0 0 1.03-1.56V3a2 2 0 1 1 4 0v.09a1.7 1.7 0 0 0 1.03 1.56 1.7 1.7 0 0 0 1.87-.34l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.7 1.7 0 0 0-.34 1.87v.09a1.7 1.7 0 0 0 1.56 1.03H21a2 2 0 1 1 0 4h-.09a1.7 1.7 0 0 0-1.51 1.87Z"/>`,
chevron_left: `<path d="m15 18-6-6 6-6"/>`,
chevron_right: `<path d="m9 18 6-6-6-6"/>`,
dots: `<circle cx="12" cy="12" r="1.5"/><circle cx="19" cy="12" r="1.5"/><circle cx="5" cy="12" r="1.5"/>`,
@@ -86,4 +87,10 @@ export const navigation: NavGroupDef[] = [
{ icon: 'alert', label: 'Incidents', route: '/incidents' },
],
},
{
group: 'System',
items: [
{ icon: 'gear', label: 'Settings', route: '/settings' },
],
},
]
+34 -34
View File
@@ -143,10 +143,10 @@ function formatModifiedAt(dateStr: string): string {
const statusColor = (status: string): string => {
switch (status) {
case 'Online': return '#51d49a'
case 'Degraded': return '#e5b05e'
case 'Offline': return '#e16e75'
default: return '#7e8799'
case 'Online': return 'var(--st-work)'
case 'Degraded': return 'var(--st-queue)'
case 'Offline': return 'var(--st-block)'
default: return 'var(--tx-3)'
}
}
@@ -612,15 +612,15 @@ onUnmounted(() => {
border: 1px solid var(--line);
border-radius: 7px;
background: var(--panel);
color: #7e8799;
color: var(--tx-3);
font-size: 10.5px;
cursor: pointer;
margin-bottom: 20px;
transition: border-color 0.15s, color 0.15s;
}
.back-link:hover {
border-color: #443d7c;
color: #d8dbe3;
border-color: var(--line-3);
color: var(--tx);
}
.status-message {
@@ -629,11 +629,11 @@ onUnmounted(() => {
justify-content: center;
gap: 8px;
padding: 48px;
color: #7e8799;
color: var(--tx-3);
font-size: 12px;
}
.status-message.error {
color: #e16e75;
color: var(--st-block);
}
.status-message.compact {
padding: 20px;
@@ -660,15 +660,15 @@ onUnmounted(() => {
place-items: center;
border-radius: 12px;
background: rgba(139,124,246,.1);
color: #8b7cf6;
color: var(--a-mid);
flex-shrink: 0;
}
.agent-avatar.iris { background: rgba(139,124,246,.15); color: #8b7cf6; }
.agent-avatar.programmer { background: rgba(77,140,246,.15); color: #4d8cf6; }
.agent-avatar.architekt { background: rgba(77,168,246,.15); color: #4da8f6; }
.agent-avatar.reviewer { background: rgba(246,168,77,.15); color: #f6a84d; }
.agent-avatar.researcher { background: rgba(139,77,246,.15); color: #8b4df6; }
.agent-avatar.executor { background: rgba(77,246,212,.15); color: #4df6d4; }
.agent-avatar.iris { background: rgba(139,124,246,.15); color: var(--a-mid); }
.agent-avatar.programmer { background: rgba(77,140,246,.15); color: var(--a-blue); }
.agent-avatar.architekt { background: rgba(77,168,246,.15); color: var(--a-blue); }
.agent-avatar.reviewer { background: rgba(246,168,77,.15); color: var(--st-queue); }
.agent-avatar.researcher { background: rgba(139,77,246,.15); color: var(--a-purple); }
.agent-avatar.executor { background: rgba(77,246,212,.15); color: var(--st-think); }
.agent-header-info {
flex: 1;
@@ -678,7 +678,7 @@ onUnmounted(() => {
font-size: 8.5px;
font-weight: 700;
letter-spacing: .12em;
color: var(--accent, #7b6ef2);
color: var(--a-mid);
text-transform: uppercase;
margin-bottom: 2px;
}
@@ -686,7 +686,7 @@ onUnmounted(() => {
margin: 0 0 4px;
font-size: 20px;
font-weight: 600;
color: #e8eaf0;
color: var(--tx);
}
.agent-status-row {
display: flex;
@@ -702,18 +702,18 @@ onUnmounted(() => {
}
.status-label {
font-size: 11px;
color: #7e8799;
color: var(--tx-3);
display: inline-flex;
align-items: center;
gap: 4px;
}
.status-label.muted { color: #6b7385; }
.status-label.muted { color: var(--tx-3); }
.status-label.mono { font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace; }
.status-sep { color: #3d4152; font-size: 11px; }
.status-sep { color: var(--line-2); font-size: 11px; }
.thinking-section {
border: 1px solid var(--line);
border-radius: 9px;
border-radius: var(--r);
background: var(--panel);
margin-bottom: 16px;
overflow: hidden;
@@ -731,11 +731,11 @@ onUnmounted(() => {
font-size: 8.5px;
font-weight: 700;
letter-spacing: .12em;
color: var(--accent, #7b6ef2);
color: var(--a-mid);
}
.section-head h2 {
margin: 2px 0 0;
color: #e8eaf0;
color: var(--tx);
font-size: 13px;
font-weight: 600;
display: inline-flex;
@@ -744,7 +744,7 @@ onUnmounted(() => {
}
.section-note {
margin: 6px 0 0;
color: #6f788b;
color: var(--tx-3);
font-size: 10px;
line-height: 1.45;
max-width: 560px;
@@ -753,10 +753,10 @@ onUnmounted(() => {
width: 6px;
height: 6px;
border-radius: 999px;
background: #6b7385;
background: var(--tx-3);
}
.live-dot.on {
background: #51d49a;
background: var(--st-work);
}
.icon-button {
width: 30px;
@@ -764,7 +764,7 @@ onUnmounted(() => {
border: 1px solid var(--line);
border-radius: 7px;
background: rgba(255,255,255,.03);
color: #9ba3b5;
color: var(--tx-2);
display: grid;
place-items: center;
cursor: pointer;
@@ -790,13 +790,13 @@ onUnmounted(() => {
.summary-card small {
display: block;
margin-top: 7px;
color: #6f788b;
color: var(--tx-3);
font-size: 9.5px;
line-height: 1.4;
}
.summary-row span {
display: block;
color: #6f788b;
color: var(--tx-3);
font-size: 9px;
font-weight: 700;
text-transform: uppercase;
@@ -804,7 +804,7 @@ onUnmounted(() => {
}
.summary-row p {
margin: 0;
color: #cbd0dc;
color: var(--tx-2);
font-size: 11px;
line-height: 1.5;
overflow-wrap: anywhere;
@@ -821,20 +821,20 @@ onUnmounted(() => {
align-items: center;
gap: 8px;
margin-bottom: 6px;
color: #6f788b;
color: var(--tx-3);
font-size: 10px;
}
.type-pill {
padding: 2px 6px;
border-radius: 999px;
border: 1px solid rgba(123,110,242,.24);
color: #aaa1ff;
color: var(--a-mid);
background: rgba(123,110,242,.08);
font-size: 9px;
}
.thinking-item p {
margin: 0;
color: #cbd0dc;
color: var(--tx-2);
font-size: 11px;
line-height: 1.55;
overflow-wrap: anywhere;
+35 -35
View File
@@ -41,7 +41,7 @@ const fallbackAgents: AgentCard[] = [
role: 'Chief of Staff',
description: 'Koordiniert, delegiert, hält das Team tight. Die erste Anlaufstelle zwischen Boss und Maschine.',
tags: ['Orchestration', 'Delegation', 'Approval'],
color: '#8b7cf6',
color: '#7c6cff',
icon: 'bot',
},
{
@@ -50,7 +50,7 @@ const fallbackAgents: AgentCard[] = [
role: 'Lead Developer',
description: 'Implementiert Features, schreibt Code, führt Builds und Tests aus. Arbeitet autonom im Scope.',
tags: ['Coding', 'Development', 'Builds'],
color: '#4d8cf6',
color: '#4f7cff',
icon: 'code',
},
{
@@ -59,7 +59,7 @@ const fallbackAgents: AgentCard[] = [
role: 'Infrastructure Engineer',
description: 'Verantwortlich für Docker, Nginx, Deployment und VPS-Infrastruktur.',
tags: ['Infrastructure', 'Deployment', 'Docker'],
color: '#4da8f6',
color: '#4f7cff',
icon: 'server',
},
{
@@ -68,7 +68,7 @@ const fallbackAgents: AgentCard[] = [
role: 'Code QA',
description: 'Prüft Code auf Bugs, Sicherheit und Wartbarkeit. Fixt Probleme eigenständig.',
tags: ['QA', 'Security', 'Code Review'],
color: '#f6a84d',
color: '#fbbf24',
icon: 'shield',
},
{
@@ -77,7 +77,7 @@ const fallbackAgents: AgentCard[] = [
role: 'Research Analyst',
description: 'Recherchiert, analysiert Quellen, prüft Fakten. Nur Lese-Rechte, keine Aktionen.',
tags: ['Research', 'Analysis', 'Fact-Checking'],
color: '#8b4df6',
color: '#b557f6',
icon: 'search',
},
{
@@ -86,7 +86,7 @@ const fallbackAgents: AgentCard[] = [
role: 'Host Executor',
description: 'Führt Host-Kommandos auf dem VPS aus. Nur auf Iris-Befehl, niemals eigeninitiativ.',
tags: ['Execution', 'Docker', 'VPS'],
color: '#4df6d4',
color: '#34d6f5',
icon: 'terminal',
},
]
@@ -161,7 +161,7 @@ function enrichAgent(item: any): AgentCard {
role: item.role || fallback?.role || 'Agent',
description: item.description || fallback?.description || 'OpenClaw agent',
tags: item.tags?.length ? item.tags : fallback?.tags ?? [],
color: fallback?.color ?? '#7e8799',
color: fallback?.color ?? '#6f6aa0',
icon: fallback?.icon ?? 'bot',
model: item.model,
statusLabel: item.statusLabel,
@@ -327,19 +327,19 @@ onMounted(loadMissionControl)
place-items: center;
border-radius: 11px;
background: rgba(139, 124, 246, 0.1);
color: #8b7cf6;
color: var(--a-mid);
flex-shrink: 0;
}
.header-text h1 {
margin: 0 0 2px;
font-size: 22px;
font-weight: 600;
color: #e8eaf0;
color: var(--tx);
}
.header-subtitle {
margin: 0;
font-size: 11px;
color: #7e8799;
color: var(--tx-3);
}
.gateway-chip {
margin-left: auto;
@@ -349,24 +349,24 @@ onMounted(loadMissionControl)
padding: 6px 9px;
border: 1px solid var(--line);
border-radius: 7px;
color: #9ba3b5;
color: var(--tx-2);
font-size: 10px;
}
.gateway-chip.ok {
color: #51d49a;
color: var(--st-work);
border-color: rgba(81, 212, 154, .25);
}
.gateway-chip.warn {
color: #e5b05e;
color: var(--st-queue);
border-color: rgba(229, 176, 94, .28);
}
.gateway-chip.error {
color: #f29b9b;
color: var(--st-block);
border-color: rgba(242, 155, 155, .3);
}
.load-error {
margin-bottom: 14px;
color: #e5b05e;
color: var(--st-queue);
font-size: 11px;
}
.gateway-warning,
@@ -376,19 +376,19 @@ onMounted(loadMissionControl)
border-radius: 11px;
border: 1px solid rgba(229, 176, 94, .24);
background: rgba(229, 176, 94, .08);
color: #f1d7aa;
color: var(--st-queue);
font-size: 11px;
line-height: 1.5;
}
.empty-state {
border-color: var(--line);
background: rgba(255,255,255,.03);
color: #aab2c3;
color: var(--tx-2);
}
.empty-state h3 {
margin: 0 0 6px;
font-size: 14px;
color: #e8eaf0;
color: var(--tx);
}
.empty-state p {
margin: 0;
@@ -451,7 +451,7 @@ onMounted(loadMissionControl)
height: 36px;
display: grid;
place-items: center;
border-radius: 9px;
border-radius: var(--r);
flex-shrink: 0;
}
@@ -464,19 +464,19 @@ onMounted(loadMissionControl)
margin: 0 0 1px;
font-size: 13px;
font-weight: 600;
color: #e8eaf0;
color: var(--tx);
}
.card-role {
display: block;
font-size: 9px;
color: #7e8799;
color: var(--tx-3);
letter-spacing: 0.02em;
}
.card-desc {
font-size: 10.5px;
color: #7e8799;
color: var(--tx-3);
line-height: 1.5;
margin: 0 0 10px;
flex: 1;
@@ -486,7 +486,7 @@ onMounted(loadMissionControl)
align-items: center;
gap: 6px;
margin-bottom: 8px;
color: #8a92a5;
color: var(--tx-2);
font-size: 9.5px;
min-width: 0;
}
@@ -494,19 +494,19 @@ onMounted(loadMissionControl)
width: 7px;
height: 7px;
border-radius: 999px;
background: #6b7385;
background: var(--tx-3);
flex-shrink: 0;
}
.runtime-dot.on {
background: #51d49a;
background: var(--st-work);
}
.runtime-dot.connected { background: #51d49a; }
.runtime-dot.thinking { background: #79aaff; }
.runtime-dot.blocked { background: #f87171; }
.runtime-dot.stale { background: #f59e0b; }
.runtime-dot.error { background: #f29b9b; }
.runtime-dot.unsupported { background: #e5b05e; }
.runtime-dot.ready { background: #6b7385; }
.runtime-dot.connected { background: var(--st-work); }
.runtime-dot.thinking { background: var(--a-blue); }
.runtime-dot.blocked { background: var(--st-block); }
.runtime-dot.stale { background: var(--st-queue); }
.runtime-dot.error { background: var(--st-block); }
.runtime-dot.unsupported { background: var(--st-queue); }
.runtime-dot.ready { background: var(--tx-3); }
.runtime-model {
margin-left: auto;
max-width: 46%;
@@ -514,12 +514,12 @@ onMounted(loadMissionControl)
text-overflow: ellipsis;
white-space: nowrap;
font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
color: #6f788b;
color: var(--tx-3);
}
.runtime-detail {
margin: 0 0 10px;
min-height: 28px;
color: #7e8799;
color: var(--tx-3);
font-size: 10px;
line-height: 1.4;
}
@@ -561,7 +561,7 @@ onMounted(loadMissionControl)
border-top: 1px solid var(--line);
font-size: 9px;
font-weight: 600;
color: #6b7385;
color: var(--tx-3);
text-transform: uppercase;
letter-spacing: 0.06em;
transition: color 0.15s;
+20 -20
View File
@@ -219,7 +219,7 @@ onMounted(() => {
}
.calendar-panel {
border: 1px solid var(--line);
border-radius: 9px;
border-radius: var(--r);
background: var(--panel);
padding: 16px;
}
@@ -235,7 +235,7 @@ onMounted(() => {
margin: 0;
font-size: 13px;
font-weight: 600;
color: #e8eaf0;
color: var(--tx);
}
.calendar-status {
display: flex;
@@ -243,11 +243,11 @@ onMounted(() => {
justify-content: center;
gap: 8px;
padding: 32px;
color: #7e8799;
color: var(--tx-3);
font-size: 11px;
}
.calendar-status.error {
color: #e16e75;
color: var(--st-block);
}
/* Upcoming jobs */
@@ -268,25 +268,25 @@ onMounted(() => {
display: grid;
place-items: center;
border-radius: 6px;
color: #a99cf5;
color: var(--a-mid);
background: rgba(139,124,246,.1);
}
.upcoming-item-info strong {
display: block;
font-size: 11px;
margin-bottom: 2px;
color: #e8eaf0;
color: var(--tx);
}
.upcoming-item-schedule {
display: block;
font-size: 9px;
color: #7e8799;
color: var(--tx-3);
margin-bottom: 2px;
}
.upcoming-item-next {
display: block;
font-size: 9px;
color: #a99cf5;
color: var(--a-mid);
font-weight: 600;
}
@@ -310,19 +310,19 @@ onMounted(() => {
border-radius: 6px;
}
.job-item-icon.status-completed {
color: #27ae60;
color: var(--st-work);
background: rgba(39, 174, 96, 0.12);
}
.job-item-icon.status-running {
color: #3498db;
color: var(--a-blue);
background: rgba(52, 152, 219, 0.12);
}
.job-item-icon.status-failed {
color: #e74c3c;
color: var(--st-block);
background: rgba(231, 76, 60, 0.12);
}
.job-item-icon.status-idle {
color: #7e8799;
color: var(--tx-3);
background: rgba(126, 135, 153, 0.12);
}
.job-item-info {
@@ -332,19 +332,19 @@ onMounted(() => {
display: block;
font-size: 11px;
margin-bottom: 2px;
color: #e8eaf0;
color: var(--tx);
}
.job-item-id {
display: block;
font-size: 9px;
color: #6b7385;
color: var(--tx-3);
margin-bottom: 2px;
font-family: monospace;
}
.job-item-schedule {
display: block;
font-size: 9px;
color: #7e8799;
color: var(--tx-3);
}
.job-item-meta {
display: flex;
@@ -355,7 +355,7 @@ onMounted(() => {
}
.job-item-meta small {
font-size: 8px;
color: #6b7385;
color: var(--tx-3);
text-align: right;
}
.job-status-badge {
@@ -368,19 +368,19 @@ onMounted(() => {
}
.job-status-badge.status-completed {
background: rgba(39, 174, 96, 0.15);
color: #27ae60;
color: var(--st-work);
}
.job-status-badge.status-running {
background: rgba(52, 152, 219, 0.15);
color: #3498db;
color: var(--a-blue);
}
.job-status-badge.status-failed {
background: rgba(231, 76, 60, 0.15);
color: #e74c3c;
color: var(--st-block);
}
.job-status-badge.status-idle {
background: rgba(126, 135, 153, 0.15);
color: #7e8799;
color: var(--tx-3);
}
.spin {
animation: spin 1s linear infinite;
+32 -32
View File
@@ -203,14 +203,14 @@ onMounted(loadDocs)
border: 1px solid var(--line);
border-radius: 8px;
background: var(--panel);
color: #6f7889;
color: var(--tx-3);
}
.docs-search-bar input {
flex: 1;
border: none;
outline: none;
background: transparent;
color: #e8eaf0;
color: var(--tx);
font: inherit;
font-size: 13px;
}
@@ -222,13 +222,13 @@ onMounted(loadDocs)
border: 1px solid var(--line);
border-radius: 8px;
background: var(--panel);
color: #8991a1;
color: var(--tx-2);
}
.docs-filter-group select {
border: none;
outline: none;
background: transparent;
color: #e8eaf0;
color: var(--tx);
font: inherit;
font-size: 12px;
cursor: pointer;
@@ -241,7 +241,7 @@ onMounted(loadDocs)
}
.memory-sidebar {
border: 1px solid var(--line);
border-radius: 9px;
border-radius: var(--r);
background: var(--panel);
padding: 8px;
max-height: 640px;
@@ -250,7 +250,7 @@ onMounted(loadDocs)
.memory-list-header {
font-size: 9px;
font-weight: 700;
color: #7065c8;
color: var(--a-mid);
text-transform: uppercase;
letter-spacing: 0.14em;
padding: 10px 8px 6px;
@@ -264,7 +264,7 @@ onMounted(loadDocs)
border: none;
border-radius: 7px;
background: transparent;
color: #e8eaf0;
color: var(--tx);
text-align: left;
cursor: pointer;
font: inherit;
@@ -280,7 +280,7 @@ onMounted(loadDocs)
display: grid;
place-items: center;
border-radius: 6px;
color: #a99cf5;
color: var(--a-mid);
background: rgba(139,124,246,.1);
}
.memory-file-info strong {
@@ -305,41 +305,41 @@ onMounted(loadDocs)
}
.doc-category-badge.cat-phases {
background: rgba(139,124,246,.12);
color: #a99cf5;
color: var(--a-mid);
}
.doc-category-badge.cat-skills {
background: rgba(81,212,154,.1);
color: #51d49a;
color: var(--st-work);
}
.doc-category-badge.cat-workspace {
background: rgba(229,176,94,.1);
color: #e5b05e;
color: var(--st-queue);
}
.doc-category-badge.cat-nexus {
background: rgba(109,159,230,.1);
color: #6d9fe6;
color: var(--a-blue);
}
.doc-category-badge.cat-nexus-phases {
background: rgba(225,110,117,.1);
color: #e16e75;
color: var(--st-block);
}
.doc-type-tag {
font-size: 8px;
padding: 1px 5px;
border: 1px solid #343947;
border: 1px solid var(--line-2);
border-radius: 4px;
color: #8991a1;
color: var(--tx-2);
}
.memory-file-meta {
display: flex;
align-items: center;
gap: 4px;
font-size: 9px;
color: #7e8799;
color: var(--tx-3);
}
.memory-content {
border: 1px solid var(--line);
border-radius: 9px;
border-radius: var(--r);
background: var(--panel);
padding: 24px;
min-height: 480px;
@@ -363,7 +363,7 @@ onMounted(loadDocs)
align-items: center;
gap: 4px;
font-size: 9px;
color: #7e8799;
color: var(--tx-3);
margin-top: 4px;
}
.memory-back-btn {
@@ -374,13 +374,13 @@ onMounted(loadDocs)
border: 1px solid var(--line);
border-radius: 6px;
background: transparent;
color: #8991a1;
color: var(--tx-2);
font-size: 10px;
cursor: pointer;
flex-shrink: 0;
}
.memory-back-btn:hover {
color: #e8eaf0;
color: var(--tx);
background: var(--accent-soft);
}
.memory-status {
@@ -389,11 +389,11 @@ onMounted(loadDocs)
justify-content: center;
gap: 8px;
padding: 32px;
color: #7e8799;
color: var(--tx-3);
font-size: 11px;
}
.memory-status.error {
color: #e16e75;
color: var(--st-block);
}
.memory-empty-state {
display: flex;
@@ -402,27 +402,27 @@ onMounted(loadDocs)
justify-content: center;
text-align: center;
min-height: 360px;
color: #6b7385;
color: var(--tx-3);
}
.memory-empty-state h3 {
margin: 12px 0 6px;
font-size: 14px;
color: #a5adba;
color: var(--tx-2);
}
.memory-empty-state p {
margin: 0;
font-size: 10px;
color: #7e8799;
color: var(--tx-3);
}
.memory-rendered {
font-size: 12px;
line-height: 1.7;
color: #d0d4dd;
color: var(--tx-2);
}
.memory-rendered :deep(h1),
.memory-rendered :deep(h2),
.memory-rendered :deep(h3) {
color: #e8eaf0;
color: var(--tx);
margin: 1.2em 0 0.5em;
}
.memory-rendered :deep(h1) { font-size: 1.3rem; }
@@ -438,8 +438,8 @@ onMounted(loadDocs)
.memory-rendered :deep(pre) {
padding: 12px;
border-radius: 8px;
background: #0d1016;
border: 1px solid var(--nx-line);
background: var(--space-2);
border: 1px solid var(--line);
overflow-x: auto;
}
.memory-rendered :deep(pre code) {
@@ -447,7 +447,7 @@ onMounted(loadDocs)
padding: 0;
}
.memory-rendered :deep(a) {
color: #a99cf5;
color: var(--a-mid);
text-decoration: none;
}
.memory-rendered :deep(a:hover) {
@@ -461,11 +461,11 @@ onMounted(loadDocs)
}
.memory-rendered :deep(hr) {
border: none;
border-top: 1px solid var(--nx-line);
border-top: 1px solid var(--line);
margin: 1.2em 0;
}
.memory-rendered :deep(strong) {
color: #e8eaf0;
color: var(--tx);
}
.spin {
animation: spin 1s linear infinite;
+29 -29
View File
@@ -202,7 +202,7 @@ onMounted(loadIncidents)
}
.incident-sidebar {
border: 1px solid var(--line);
border-radius: 9px;
border-radius: var(--r);
background: var(--panel);
padding: 8px;
max-height: 640px;
@@ -211,7 +211,7 @@ onMounted(loadIncidents)
.incident-list-header {
font-size: 9px;
font-weight: 700;
color: #7065c8;
color: var(--a-mid);
text-transform: uppercase;
letter-spacing: 0.14em;
padding: 10px 8px 6px;
@@ -225,7 +225,7 @@ onMounted(loadIncidents)
border: none;
border-radius: 7px;
background: transparent;
color: #e8eaf0;
color: var(--tx);
text-align: left;
cursor: pointer;
font: inherit;
@@ -243,19 +243,19 @@ onMounted(loadIncidents)
border-radius: 6px;
}
.incident-file-icon.sev-critical {
color: #e74c3c;
color: var(--st-block);
background: rgba(231, 76, 60, 0.12);
}
.incident-file-icon.sev-major {
color: #e67e22;
color: var(--st-queue);
background: rgba(230, 126, 34, 0.12);
}
.incident-file-icon.sev-minor {
color: #f1c40f;
color: var(--st-queue);
background: rgba(241, 196, 15, 0.12);
}
.incident-file-icon.sev-unknown {
color: #7e8799;
color: var(--tx-3);
background: rgba(126, 135, 153, 0.12);
}
.incident-file-info strong {
@@ -269,7 +269,7 @@ onMounted(loadIncidents)
align-items: center;
gap: 4px;
font-size: 9px;
color: #7e8799;
color: var(--tx-3);
margin-bottom: 4px;
}
.incident-file-excerpt {
@@ -278,7 +278,7 @@ onMounted(loadIncidents)
-webkit-box-orient: vertical;
overflow: hidden;
font-size: 9px;
color: #6b7385;
color: var(--tx-3);
line-height: 1.5;
}
.severity-badge {
@@ -291,23 +291,23 @@ onMounted(loadIncidents)
}
.severity-badge.sev-critical {
background: rgba(231, 76, 60, 0.15);
color: #e74c3c;
color: var(--st-block);
}
.severity-badge.sev-major {
background: rgba(230, 126, 34, 0.15);
color: #e67e22;
color: var(--st-queue);
}
.severity-badge.sev-minor {
background: rgba(241, 196, 15, 0.15);
color: #f1c40f;
color: var(--st-queue);
}
.severity-badge.sev-unknown {
background: rgba(126, 135, 153, 0.15);
color: #7e8799;
color: var(--tx-3);
}
.incident-content {
border: 1px solid var(--line);
border-radius: 9px;
border-radius: var(--r);
background: var(--panel);
padding: 24px;
min-height: 480px;
@@ -335,7 +335,7 @@ onMounted(loadIncidents)
align-items: center;
gap: 4px;
font-size: 9px;
color: #7e8799;
color: var(--tx-3);
}
.incident-back-btn {
display: flex;
@@ -345,13 +345,13 @@ onMounted(loadIncidents)
border: 1px solid var(--line);
border-radius: 6px;
background: transparent;
color: #8991a1;
color: var(--tx-2);
font-size: 10px;
cursor: pointer;
flex-shrink: 0;
}
.incident-back-btn:hover {
color: #e8eaf0;
color: var(--tx);
background: var(--accent-soft);
}
.incident-status {
@@ -360,11 +360,11 @@ onMounted(loadIncidents)
justify-content: center;
gap: 8px;
padding: 32px;
color: #7e8799;
color: var(--tx-3);
font-size: 11px;
}
.incident-status.error {
color: #e16e75;
color: var(--st-block);
}
.incident-empty-state {
display: flex;
@@ -373,27 +373,27 @@ onMounted(loadIncidents)
justify-content: center;
text-align: center;
min-height: 360px;
color: #6b7385;
color: var(--tx-3);
}
.incident-empty-state h3 {
margin: 12px 0 6px;
font-size: 14px;
color: #a5adba;
color: var(--tx-2);
}
.incident-empty-state p {
margin: 0;
font-size: 10px;
color: #7e8799;
color: var(--tx-3);
}
.incident-rendered {
font-size: 12px;
line-height: 1.7;
color: #d0d4dd;
color: var(--tx-2);
}
.incident-rendered :deep(h1),
.incident-rendered :deep(h2),
.incident-rendered :deep(h3) {
color: #e8eaf0;
color: var(--tx);
margin: 1.2em 0 0.5em;
}
.incident-rendered :deep(h1) { font-size: 1.3rem; }
@@ -409,8 +409,8 @@ onMounted(loadIncidents)
.incident-rendered :deep(pre) {
padding: 12px;
border-radius: 8px;
background: #0d1016;
border: 1px solid var(--nx-line);
background: var(--space-2);
border: 1px solid var(--line);
overflow-x: auto;
}
.incident-rendered :deep(pre code) {
@@ -418,7 +418,7 @@ onMounted(loadIncidents)
padding: 0;
}
.incident-rendered :deep(a) {
color: #a99cf5;
color: var(--a-mid);
text-decoration: none;
}
.incident-rendered :deep(a:hover) {
@@ -432,11 +432,11 @@ onMounted(loadIncidents)
}
.incident-rendered :deep(hr) {
border: none;
border-top: 1px solid var(--nx-line);
border-top: 1px solid var(--line);
margin: 1.2em 0;
}
.incident-rendered :deep(strong) {
color: #e8eaf0;
color: var(--tx);
}
.spin {
animation: spin 1s linear infinite;
+25 -25
View File
@@ -227,22 +227,22 @@ onMounted(loadMemories)
border-radius: 8px;
background: var(--panel);
margin-bottom: 16px;
color: #6f7889;
color: var(--tx-3);
}
.memory-search-bar input {
flex: 1;
border: none;
outline: none;
background: transparent;
color: #e8eaf0;
color: var(--tx);
font: inherit;
font-size: 13px;
}
.memory-search-bar kbd {
padding: 2px 5px;
border: 1px solid #2c313d;
border: 1px solid var(--line-2);
border-radius: 4px;
color: #606979;
color: var(--tx-3);
font-size: 9px;
}
.memory-layout {
@@ -253,7 +253,7 @@ onMounted(loadMemories)
}
.memory-sidebar {
border: 1px solid var(--line);
border-radius: 9px;
border-radius: var(--r);
background: var(--panel);
padding: 8px;
max-height: 640px;
@@ -262,7 +262,7 @@ onMounted(loadMemories)
.memory-list-header {
font-size: 9px;
font-weight: 700;
color: #7065c8;
color: var(--a-mid);
text-transform: uppercase;
letter-spacing: 0.14em;
padding: 10px 8px 6px;
@@ -276,7 +276,7 @@ onMounted(loadMemories)
border: none;
border-radius: 7px;
background: transparent;
color: #e8eaf0;
color: var(--tx);
text-align: left;
cursor: pointer;
font: inherit;
@@ -292,7 +292,7 @@ onMounted(loadMemories)
display: grid;
place-items: center;
border-radius: 6px;
color: #a99cf5;
color: var(--a-mid);
background: rgba(139,124,246,.1);
}
.memory-file-info strong {
@@ -307,7 +307,7 @@ onMounted(loadMemories)
align-items: center;
gap: 4px;
font-size: 9px;
color: #7e8799;
color: var(--tx-3);
line-height: 1.5;
}
.memory-file-excerpt {
@@ -318,7 +318,7 @@ onMounted(loadMemories)
}
.memory-content {
border: 1px solid var(--line);
border-radius: 9px;
border-radius: var(--r);
background: var(--panel);
padding: 24px;
min-height: 480px;
@@ -342,7 +342,7 @@ onMounted(loadMemories)
align-items: center;
gap: 4px;
font-size: 9px;
color: #7e8799;
color: var(--tx-3);
}
.memory-back-btn {
display: flex;
@@ -352,13 +352,13 @@ onMounted(loadMemories)
border: 1px solid var(--line);
border-radius: 6px;
background: transparent;
color: #8991a1;
color: var(--tx-2);
font-size: 10px;
cursor: pointer;
flex-shrink: 0;
}
.memory-back-btn:hover {
color: #e8eaf0;
color: var(--tx);
background: var(--accent-soft);
}
.memory-status {
@@ -367,11 +367,11 @@ onMounted(loadMemories)
justify-content: center;
gap: 8px;
padding: 32px;
color: #7e8799;
color: var(--tx-3);
font-size: 11px;
}
.memory-status.error {
color: #e16e75;
color: var(--st-block);
}
.memory-empty-state {
display: flex;
@@ -380,27 +380,27 @@ onMounted(loadMemories)
justify-content: center;
text-align: center;
min-height: 360px;
color: #6b7385;
color: var(--tx-3);
}
.memory-empty-state h3 {
margin: 12px 0 6px;
font-size: 14px;
color: #a5adba;
color: var(--tx-2);
}
.memory-empty-state p {
margin: 0;
font-size: 10px;
color: #7e8799;
color: var(--tx-3);
}
.memory-rendered {
font-size: 12px;
line-height: 1.7;
color: #d0d4dd;
color: var(--tx-2);
}
.memory-rendered :deep(h1),
.memory-rendered :deep(h2),
.memory-rendered :deep(h3) {
color: #e8eaf0;
color: var(--tx);
margin: 1.2em 0 0.5em;
}
.memory-rendered :deep(h1) { font-size: 1.3rem; }
@@ -416,8 +416,8 @@ onMounted(loadMemories)
.memory-rendered :deep(pre) {
padding: 12px;
border-radius: 8px;
background: #0d1016;
border: 1px solid var(--nx-line);
background: var(--space-2);
border: 1px solid var(--line);
overflow-x: auto;
}
.memory-rendered :deep(pre code) {
@@ -425,7 +425,7 @@ onMounted(loadMemories)
padding: 0;
}
.memory-rendered :deep(a) {
color: #a99cf5;
color: var(--a-mid);
text-decoration: none;
}
.memory-rendered :deep(a:hover) {
@@ -439,11 +439,11 @@ onMounted(loadMemories)
}
.memory-rendered :deep(hr) {
border: none;
border-top: 1px solid var(--nx-line);
border-top: 1px solid var(--line);
margin: 1.2em 0;
}
.memory-rendered :deep(strong) {
color: #e8eaf0;
color: var(--tx);
}
.spin {
animation: spin 1s linear infinite;
+14 -14
View File
@@ -26,10 +26,10 @@ function typeIcon(type: string): string {
function typeColor(type: string): string {
switch (type) {
case 'task_assigned': return '#4d8cf6'
case 'task_review': return '#f6a84d'
case 'task_blocked': return '#e16e75'
default: return '#7b6ef2'
case 'task_assigned': return '#4f7cff'
case 'task_review': return '#fbbf24'
case 'task_blocked': return '#fb7185'
default: return '#7c6cff'
}
}
@@ -137,18 +137,18 @@ onUnmounted(() => {
align-items: center;
gap: 6px;
padding: 6px 12px;
border: 1px solid var(--nx-line, #1f2330);
border: 1px solid var(--line);
border-radius: 6px;
background: transparent;
color: var(--nx-text-dim, #6f7889);
color: var(--tx-3);
font-size: 10.5px;
cursor: pointer;
transition: background .15s, color .15s;
}
.mark-all-btn:hover {
background: var(--nx-accent-soft, rgba(123, 110, 242, .08));
color: #d8dbe3;
background: rgba(124, 108, 255, 0.08);
color: var(--tx);
}
/* ── Empty State ── */
@@ -158,7 +158,7 @@ onUnmounted(() => {
align-items: center;
justify-content: center;
padding: 80px 0;
color: var(--nx-text-dim, #6f7889);
color: var(--tx-3);
gap: 16px;
}
@@ -186,7 +186,7 @@ onUnmounted(() => {
}
.notification-card:hover {
background: var(--nx-accent-soft, rgba(123, 110, 242, .06));
background: rgba(124, 108, 255, 0.06);
}
.notification-card.unread {
@@ -215,7 +215,7 @@ onUnmounted(() => {
.card-title {
font-size: 12.5px;
color: #d8dbe3;
color: var(--tx);
line-height: 1.4;
}
@@ -226,7 +226,7 @@ onUnmounted(() => {
.card-message {
font-size: 10.5px;
color: var(--nx-text-dim, #6f7889);
color: var(--tx-3);
margin-top: 3px;
line-height: 1.3;
}
@@ -242,12 +242,12 @@ onUnmounted(() => {
.timestamp {
font-size: 9px;
color: var(--nx-text-dim, #6f7889);
color: var(--tx-3);
white-space: nowrap;
}
.arrow {
color: var(--nx-text-dim, #6f7889);
color: var(--tx-3);
opacity: .5;
}
</style>
+15 -15
View File
@@ -221,7 +221,7 @@ onMounted(loadProject)
}
.project-detail-card {
background: var(--surface);
border: 1px solid var(--border);
border: 1px solid var(--line-2);
border-radius: 12px;
padding: 1.5rem;
}
@@ -234,7 +234,7 @@ onMounted(loadProject)
width: 48px;
height: 48px;
border-radius: 10px;
background: linear-gradient(135deg, var(--accent), var(--accent-secondary));
background: linear-gradient(135deg, var(--a-mid), var(--accent-secondary));
color: #fff;
font-size: 1.25rem;
font-weight: 600;
@@ -273,7 +273,7 @@ onMounted(loadProject)
}
.btn-icon {
background: var(--surface-raised);
border: 1px solid var(--border);
border: 1px solid var(--line-2);
border-radius: 8px;
padding: 0.5rem;
cursor: pointer;
@@ -282,8 +282,8 @@ onMounted(loadProject)
transition: all 0.15s;
}
.btn-icon:hover {
background: var(--nx-accent-soft);
color: var(--nx-accent);
background: rgba(124, 108, 255, 0.10);
color: var(--a-mid);
}
.btn-icon.btn-danger:hover {
background: rgba(239, 68, 68, 0.1);
@@ -294,7 +294,7 @@ onMounted(loadProject)
width: 100%;
padding: 0.5rem 0.75rem;
background: var(--surface-raised);
border: 1px solid var(--border);
border: 1px solid var(--line-2);
border-radius: 8px;
font-size: 1.1rem;
color: var(--text-primary);
@@ -304,7 +304,7 @@ onMounted(loadProject)
width: 100%;
padding: 0.5rem 0.75rem;
background: var(--surface-raised);
border: 1px solid var(--border);
border: 1px solid var(--line-2);
border-radius: 8px;
font-size: 0.9rem;
color: var(--text-primary);
@@ -321,7 +321,7 @@ onMounted(loadProject)
align-items: center;
gap: 0.35rem;
padding: 0.4rem 0.8rem;
background: var(--nx-accent);
background: var(--a-mid);
color: #fff;
border: none;
border-radius: 6px;
@@ -335,7 +335,7 @@ onMounted(loadProject)
padding: 0.4rem 0.8rem;
background: var(--surface-raised);
color: var(--text-secondary);
border: 1px solid var(--border);
border: 1px solid var(--line-2);
border-radius: 6px;
font-size: 0.85rem;
cursor: pointer;
@@ -343,7 +343,7 @@ onMounted(loadProject)
.progress-section {
margin-top: 1.25rem;
padding-top: 1rem;
border-top: 1px solid var(--border);
border-top: 1px solid var(--line-2);
}
.progress-header {
display: flex;
@@ -361,7 +361,7 @@ onMounted(loadProject)
.progress-bar i {
display: block;
height: 100%;
background: linear-gradient(90deg, var(--nx-accent), var(--accent-secondary));
background: linear-gradient(90deg, var(--a-mid), var(--accent-secondary));
border-radius: 4px;
transition: width 0.3s;
}
@@ -380,7 +380,7 @@ onMounted(loadProject)
padding: 1.5rem;
text-align: center;
background: var(--surface);
border: 1px dashed var(--border);
border: 1px dashed var(--line-2);
border-radius: 8px;
}
.task-list {
@@ -394,7 +394,7 @@ onMounted(loadProject)
gap: 0.75rem;
padding: 0.75rem 1rem;
background: var(--surface);
border: 1px solid var(--border);
border: 1px solid var(--line-2);
border-radius: 8px;
}
.task-icon {
@@ -403,7 +403,7 @@ onMounted(loadProject)
.task-icon.done { color: rgb(34, 197, 94); }
.task-icon.blocked { color: rgb(239, 68, 68); }
.task-icon.backlog { color: var(--text-muted); }
.task-icon.in-progress { color: var(--nx-accent); }
.task-icon.in-progress { color: var(--a-mid); }
.task-info {
flex: 1;
}
@@ -441,7 +441,7 @@ onMounted(loadProject)
}
.modal {
background: var(--surface);
border: 1px solid var(--border);
border: 1px solid var(--line-2);
border-radius: 12px;
padding: 1.5rem;
max-width: 420px;
+18 -18
View File
@@ -192,7 +192,7 @@ onMounted(loadStatus)
}
.security-card {
border: 1px solid var(--line);
border-radius: 9px;
border-radius: var(--r);
background: var(--panel);
padding: 20px;
display: flex;
@@ -204,27 +204,27 @@ onMounted(loadStatus)
height: 40px;
display: grid;
place-items: center;
border-radius: 9px;
color: #a99cff;
border-radius: var(--r);
color: var(--a-mid);
background: var(--accent-soft);
}
.security-card-icon.twofa-icon {
color: #e5b05e;
color: var(--st-queue);
background: rgba(229,176,94,.1);
}
.security-card-icon.passkey-icon {
color: #6d9fe6;
color: var(--a-blue);
background: rgba(109,159,230,.1);
}
.security-card h3 {
margin: 0;
font-size: 13px;
color: #e8eaf0;
color: var(--tx);
}
.security-value {
font-size: 13px;
font-weight: 600;
color: #e8eaf0;
color: var(--tx);
}
.policy-text {
font-size: 11px;
@@ -234,7 +234,7 @@ onMounted(loadStatus)
.security-desc {
margin: 0;
font-size: 10px;
color: #7e8799;
color: var(--tx-3);
line-height: 1.5;
}
.security-detail-list {
@@ -250,14 +250,14 @@ onMounted(loadStatus)
}
.security-detail-label {
font-size: 10px;
color: #8991a1;
color: var(--tx-2);
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.03em;
}
.security-detail-value {
font-size: 10px;
color: #e8eaf0;
color: var(--tx);
font-weight: 500;
text-align: right;
word-break: break-word;
@@ -281,11 +281,11 @@ code.security-detail-value {
}
.status-bool.enabled {
background: rgba(81,212,154,.1);
color: #51d49a;
color: var(--st-work);
}
.status-bool.disabled {
background: rgba(225,110,117,.08);
color: #e16e75;
color: var(--st-block);
}
.security-status-row {
display: flex;
@@ -293,16 +293,16 @@ code.security-detail-value {
gap: 6px;
}
.check-icon {
color: #51d49a;
color: var(--st-work);
}
.x-icon {
color: #e16e75;
color: var(--st-block);
}
.enabled-text {
color: #51d49a;
color: var(--st-work);
}
.disabled-text {
color: #e16e75;
color: var(--st-block);
}
.memory-status {
@@ -311,11 +311,11 @@ code.security-detail-value {
justify-content: center;
gap: 8px;
padding: 48px;
color: #7e8799;
color: var(--tx-3);
font-size: 12px;
}
.memory-status.error {
color: #e16e75;
color: var(--st-block);
}
.spin {
animation: spin 1s linear infinite;
+29 -29
View File
@@ -409,7 +409,7 @@ onMounted(() => {
}
.grad-text {
background: linear-gradient(135deg, #4f7cff, #b557f6);
background: linear-gradient(135deg, var(--a-blue), var(--a-purple));
-webkit-background-clip: text;
background-clip: text;
color: transparent;
@@ -418,7 +418,7 @@ onMounted(() => {
.settings-subtitle {
margin: 4px 0 0;
font-size: 11px;
color: #6f6aa0;
color: var(--tx-3);
font-family: 'Manrope', sans-serif;
}
@@ -444,7 +444,7 @@ onMounted(() => {
display: flex;
align-items: center;
gap: 10px;
color: #ece9ff;
color: var(--tx);
padding-bottom: 14px;
border-bottom: 1px solid rgba(150, 140, 255, 0.08);
}
@@ -470,7 +470,7 @@ onMounted(() => {
.field label {
font-size: 10px;
font-weight: 600;
color: #a8a3d6;
color: var(--tx-2);
text-transform: uppercase;
letter-spacing: 0.05em;
}
@@ -490,7 +490,7 @@ onMounted(() => {
border: 1px solid rgba(150, 140, 255, 0.12);
border-radius: 11px;
background: rgba(10, 9, 24, 0.55);
color: #ece9ff;
color: var(--tx);
font-size: 13.5px;
font-family: 'Manrope', sans-serif;
outline: none;
@@ -513,13 +513,13 @@ onMounted(() => {
}
.galaxy-select option {
background: #141130;
color: #ece9ff;
background: var(--space-3);
color: var(--tx);
}
.value-tag {
font-size: 14px;
color: #ece9ff;
color: var(--tx);
font-weight: 500;
}
@@ -538,7 +538,7 @@ onMounted(() => {
text-transform: uppercase;
letter-spacing: 0.05em;
background: linear-gradient(135deg, rgba(79, 124, 255, 0.15), rgba(181, 87, 246, 0.15));
color: #b8adff;
color: var(--a-mid);
border: 1px solid rgba(124, 108, 255, 0.15);
width: fit-content;
}
@@ -589,14 +589,14 @@ onMounted(() => {
border: none;
border-radius: 8px;
background: transparent;
color: #6f6aa0;
color: var(--tx-3);
cursor: pointer;
transition: background 0.15s, color 0.15s;
}
.pw-toggle:hover {
background: rgba(124, 108, 255, 0.08);
color: #a8a3d6;
color: var(--tx-2);
}
/* ── Messages ──────────────────────────────────── */
@@ -613,13 +613,13 @@ onMounted(() => {
.msg.error {
background: rgba(244, 63, 94, 0.1);
border: 1px solid rgba(244, 63, 94, 0.2);
color: #fda4af;
color: var(--st-block);
}
.msg.success {
background: rgba(34, 197, 94, 0.1);
border: 1px solid rgba(34, 197, 94, 0.2);
color: #86efac;
color: var(--st-work);
}
/* ── Buttons ──────────────────────────────────── */
@@ -630,7 +630,7 @@ onMounted(() => {
padding: 9px 16px;
border: none;
border-radius: 10px;
background: linear-gradient(135deg, #4f7cff, #7c6cff, #b557f6);
background: linear-gradient(135deg, var(--a-blue), var(--a-mid), var(--a-purple));
color: #fff;
font-size: 12.5px;
font-weight: 600;
@@ -665,7 +665,7 @@ onMounted(() => {
font-family: 'Manrope', sans-serif;
background: transparent;
border: 1px solid rgba(150, 140, 255, 0.12);
color: #a8a3d6;
color: var(--tx-2);
border-radius: 8px;
cursor: pointer;
transition: background 0.15s, color 0.15s;
@@ -673,7 +673,7 @@ onMounted(() => {
.btn-ghost:hover {
background: rgba(124, 108, 255, 0.08);
color: #ece9ff;
color: var(--tx);
}
/* ── Admin User Management ───────────────────── */
@@ -711,7 +711,7 @@ onMounted(() => {
place-items: center;
background: linear-gradient(135deg, rgba(79, 124, 255, 0.2), rgba(181, 87, 246, 0.2));
border: 1px solid rgba(124, 108, 255, 0.15);
color: #b8adff;
color: var(--a-mid);
font-weight: 700;
font-size: 14px;
flex-shrink: 0;
@@ -725,12 +725,12 @@ onMounted(() => {
.user-name {
font-size: 13px;
font-weight: 600;
color: #ece9ff;
color: var(--tx);
}
.user-email {
font-size: 11px;
color: #6f6aa0;
color: var(--tx-3);
display: flex;
align-items: center;
gap: 4px;
@@ -754,31 +754,31 @@ onMounted(() => {
text-transform: uppercase;
letter-spacing: 0.04em;
background: rgba(124, 108, 255, 0.1);
color: #b8adff;
color: var(--a-mid);
border: 1px solid rgba(124, 108, 255, 0.1);
}
.role-tag.owner {
background: linear-gradient(135deg, rgba(244, 63, 94, 0.15), rgba(251, 191, 36, 0.15));
color: #fde68a;
color: var(--st-queue);
border-color: rgba(251, 191, 36, 0.2);
}
.role-tag.admin {
background: rgba(79, 124, 255, 0.12);
color: #93c5fd;
color: var(--a-blue);
border-color: rgba(79, 124, 255, 0.2);
}
.role-tag.viewer {
background: rgba(107, 103, 150, 0.15);
color: #a8a3d6;
color: var(--tx-2);
border-color: rgba(107, 103, 150, 0.2);
}
.user-date {
font-size: 10px;
color: #6f6aa0;
color: var(--tx-3);
}
.loading-pulse {
@@ -806,7 +806,7 @@ onMounted(() => {
align-items: center;
gap: 12px;
padding: 32px;
color: #6f6aa0;
color: var(--tx-3);
}
.empty-state p {
@@ -849,7 +849,7 @@ onMounted(() => {
margin: 0;
font-size: 16px;
font-weight: 700;
color: #ece9ff;
color: var(--tx);
font-family: 'Space Grotesk', sans-serif;
}
@@ -861,7 +861,7 @@ onMounted(() => {
justify-content: center;
border: none;
background: transparent;
color: #6f6aa0;
color: var(--tx-3);
cursor: pointer;
border-radius: 6px;
font-size: 20px;
@@ -870,11 +870,11 @@ onMounted(() => {
.modal-close:hover {
background: rgba(124, 108, 255, 0.08);
color: #ece9ff;
color: var(--tx);
}
.req {
color: #fb7185;
color: var(--st-block);
}
.modal-form {
+45 -45
View File
@@ -111,9 +111,9 @@ function statusClass(state: string): string {
function priorityColor(p: string): string {
const lower = p.toLowerCase()
if (lower === 'high') return '#f87171'
if (lower === 'low') return '#60a5fa'
return '#facc15'
if (lower === 'high') return 'var(--st-block)'
if (lower === 'low') return 'var(--a-blue)'
return 'var(--st-queue)'
}
function priorityLabel(p: string): string {
@@ -638,7 +638,7 @@ function handleKeydown(e: KeyboardEvent) {
border: 1px solid rgba(150, 140, 255, 0.12);
border-radius: 10px;
background: transparent;
color: #a8a3d6;
color: var(--tx-2);
font-size: 12px;
font-family: 'Manrope', sans-serif;
cursor: pointer;
@@ -648,7 +648,7 @@ function handleKeydown(e: KeyboardEvent) {
.back-btn:hover {
background: rgba(124, 108, 255, 0.08);
color: #ece9ff;
color: var(--tx);
}
/* ── Loading / Error ────────────────────────── */
@@ -659,14 +659,14 @@ function handleKeydown(e: KeyboardEvent) {
justify-content: center;
gap: 16px;
padding: 80px 20px;
color: #6f6aa0;
color: var(--tx-3);
}
.spinner {
width: 24px;
height: 24px;
border: 2.5px solid rgba(150, 140, 255, 0.15);
border-top-color: #7c6cff;
border-top-color: var(--a-mid);
border-radius: 50%;
animation: spin 0.6s linear infinite;
}
@@ -675,7 +675,7 @@ function handleKeydown(e: KeyboardEvent) {
width: 16px;
height: 16px;
border: 2px solid rgba(150, 140, 255, 0.15);
border-top-color: #7c6cff;
border-top-color: var(--a-mid);
border-radius: 50%;
animation: spin 0.6s linear infinite;
flex-shrink: 0;
@@ -686,7 +686,7 @@ function handleKeydown(e: KeyboardEvent) {
.error-state p {
font-size: 14px;
margin: 0;
color: #fda4af;
color: var(--st-block);
}
/* ── Detail Header ──────────────────────────── */
@@ -711,15 +711,15 @@ function handleKeydown(e: KeyboardEvent) {
border: 1px solid transparent;
}
.state-badge.is-backlog { color: #fde68a; background: rgba(251,191,36,.12); border-color: rgba(251,191,36,.25); }
.state-badge.is-progress { color: #86efac; background: rgba(34,197,94,.12); border-color: rgba(34,197,94,.25); }
.state-badge.is-review { color: #fdba74; background: rgba(249,115,22,.12); border-color: rgba(249,115,22,.25); }
.state-badge.is-blocked { color: #fda4af; background: rgba(244,63,94,.12); border-color: rgba(244,63,94,.25); }
.state-badge.is-done { color: #86efac; background: rgba(34,197,94,.12); border-color: rgba(34,197,94,.25); }
.state-badge.is-backlog { color: var(--st-queue); background: rgba(251,191,36,.12); border-color: rgba(251,191,36,.25); }
.state-badge.is-progress { color: var(--st-work); background: rgba(34,197,94,.12); border-color: rgba(34,197,94,.25); }
.state-badge.is-review { color: var(--st-queue); background: rgba(249,115,22,.12); border-color: rgba(249,115,22,.25); }
.state-badge.is-blocked { color: var(--st-block); background: rgba(244,63,94,.12); border-color: rgba(244,63,94,.25); }
.state-badge.is-done { color: var(--st-work); background: rgba(34,197,94,.12); border-color: rgba(34,197,94,.25); }
.meta-chip {
font-size: 10px;
color: #6f6aa0;
color: var(--tx-3);
background: rgba(10, 9, 24, 0.35);
padding: 3px 10px;
border-radius: 6px;
@@ -735,7 +735,7 @@ function handleKeydown(e: KeyboardEvent) {
border-radius: 10px;
background: rgba(147,51,234,.08);
border: 1px solid rgba(147,51,234,.18);
color: #c084fc;
color: var(--a-purple);
font-size: 12px;
}
@@ -759,7 +759,7 @@ function handleKeydown(e: KeyboardEvent) {
border: none;
border-bottom: 2px solid transparent;
padding: 4px 0;
color: #ece9ff;
color: var(--tx);
font-family: 'Space Grotesk', sans-serif;
font-size: 28px;
font-weight: 700;
@@ -777,7 +777,7 @@ function handleKeydown(e: KeyboardEvent) {
flex-wrap: wrap;
gap: 16px;
font-size: 12px;
color: #6f6aa0;
color: var(--tx-3);
}
.meta-row span {
@@ -791,7 +791,7 @@ function handleKeydown(e: KeyboardEvent) {
border-radius: 12px;
background: rgba(124, 108, 255, 0.08);
border: 1px solid rgba(124, 108, 255, 0.14);
color: #a8a3d6;
color: var(--tx-2);
font-size: 12px;
}
@@ -808,7 +808,7 @@ function handleKeydown(e: KeyboardEvent) {
align-items: center;
gap: 8px;
margin-bottom: 14px;
color: #a8a3d6;
color: var(--tx-2);
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
@@ -826,7 +826,7 @@ function handleKeydown(e: KeyboardEvent) {
border: 1px solid rgba(150, 140, 255, 0.10);
border-radius: 12px;
background: rgba(10, 9, 24, 0.45);
color: #ece9ff;
color: var(--tx);
font-size: 14px;
line-height: 1.6;
font-family: 'Manrope', sans-serif;
@@ -897,13 +897,13 @@ function handleKeydown(e: KeyboardEvent) {
.subtask-title {
font-size: 13px;
font-weight: 600;
color: #ece9ff;
color: var(--tx);
}
.subtask-detail {
margin: 4px 0 0;
font-size: 11.5px;
color: #6f6aa0;
color: var(--tx-3);
line-height: 1.4;
}
@@ -919,7 +919,7 @@ function handleKeydown(e: KeyboardEvent) {
border: 1px solid rgba(150, 140, 255, 0.12);
border-radius: 6px;
background: rgba(10, 9, 24, 0.5);
color: #a8a3d6;
color: var(--tx-2);
font-size: 10px;
font-family: 'Manrope', sans-serif;
cursor: pointer;
@@ -927,8 +927,8 @@ function handleKeydown(e: KeyboardEvent) {
}
.state-select-mini option {
background: #141130;
color: #ece9ff;
background: var(--space-3);
color: var(--tx);
}
.state-select-mini:disabled {
@@ -941,14 +941,14 @@ function handleKeydown(e: KeyboardEvent) {
align-items: center;
gap: 8px;
padding: 16px;
color: #6f6aa0;
color: var(--tx-3);
font-size: 12px;
}
.empty-section {
padding: 20px;
text-align: center;
color: #6f6aa0;
color: var(--tx-3);
font-size: 12px;
}
@@ -996,7 +996,7 @@ function handleKeydown(e: KeyboardEvent) {
display: grid;
place-items: center;
background: rgba(124, 108, 255, 0.08);
color: #7c6cff;
color: var(--a-mid);
flex-shrink: 0;
}
@@ -1007,13 +1007,13 @@ function handleKeydown(e: KeyboardEvent) {
.activity-msg {
font-size: 12.5px;
color: #a8a3d6;
color: var(--tx-2);
line-height: 1.4;
}
.activity-time {
font-size: 10px;
color: #6f6aa0;
color: var(--tx-3);
margin-top: 3px;
}
@@ -1042,7 +1042,7 @@ function handleKeydown(e: KeyboardEvent) {
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.06em;
color: #a8a3d6;
color: var(--tx-2);
margin-bottom: 14px;
}
@@ -1060,7 +1060,7 @@ function handleKeydown(e: KeyboardEvent) {
.sidebar-field span {
font-size: 10px;
font-weight: 600;
color: #6f6aa0;
color: var(--tx-3);
text-transform: uppercase;
letter-spacing: 0.04em;
}
@@ -1079,13 +1079,13 @@ function handleKeydown(e: KeyboardEvent) {
}
.info-list dt {
color: #6f6aa0;
color: var(--tx-3);
font-size: 11px;
}
.info-list dd {
margin: 0;
color: #a8a3d6;
color: var(--tx-2);
font-size: 11.5px;
text-align: right;
}
@@ -1104,7 +1104,7 @@ function handleKeydown(e: KeyboardEvent) {
border: 1px solid rgba(150, 140, 255, 0.12);
border-radius: 10px;
background: rgba(10, 9, 24, 0.55);
color: #ece9ff;
color: var(--tx);
font-size: 13.5px;
font-family: 'Manrope', sans-serif;
outline: none;
@@ -1127,8 +1127,8 @@ function handleKeydown(e: KeyboardEvent) {
}
.galaxy-select option {
background: #141130;
color: #ece9ff;
background: var(--space-3);
color: var(--tx);
}
.galaxy-select:disabled {
@@ -1143,7 +1143,7 @@ function handleKeydown(e: KeyboardEvent) {
padding: 9px 16px;
border: none;
border-radius: 10px;
background: linear-gradient(135deg, #4f7cff, #7c6cff, #b557f6);
background: linear-gradient(135deg, var(--a-blue), var(--a-mid), var(--a-purple));
color: #fff;
font-size: 12.5px;
font-weight: 600;
@@ -1169,7 +1169,7 @@ function handleKeydown(e: KeyboardEvent) {
border: 1px solid rgba(150, 140, 255, 0.12);
border-radius: 8px;
background: transparent;
color: #a8a3d6;
color: var(--tx-2);
font-size: 11px;
font-family: 'Manrope', sans-serif;
cursor: pointer;
@@ -1186,13 +1186,13 @@ function handleKeydown(e: KeyboardEvent) {
border: none;
border-radius: 7px;
background: rgba(124, 108, 255, 0.06);
color: #a8a3d6;
color: var(--tx-2);
cursor: pointer;
transition: background 0.15s, color 0.15s;
}
.btn-icon-sm:hover { background: rgba(124, 108, 255, 0.12); color: #ece9ff; }
.btn-icon-sm.danger:hover { background: rgba(244, 63, 94, 0.12); color: #fda4af; }
.btn-icon-sm:hover { background: rgba(124, 108, 255, 0.12); color: var(--tx); }
.btn-icon-sm.danger:hover { background: rgba(244, 63, 94, 0.12); color: var(--st-block); }
.btn-icon-sm:disabled { opacity: 0.4; cursor: not-allowed; }
.msg {
@@ -1202,8 +1202,8 @@ function handleKeydown(e: KeyboardEvent) {
border-radius: 8px;
}
.msg.error { background: rgba(244, 63, 94, 0.08); border: 1px solid rgba(244, 63, 94, 0.15); color: #fda4af; }
.msg.success { background: rgba(34, 197, 94, 0.08); border: 1px solid rgba(34, 197, 94, 0.15); color: #86efac; display: flex; align-items: center; gap: 6px; }
.msg.error { background: rgba(244, 63, 94, 0.08); border: 1px solid rgba(244, 63, 94, 0.15); color: var(--st-block); }
.msg.success { background: rgba(34, 197, 94, 0.08); border: 1px solid rgba(34, 197, 94, 0.15); color: var(--st-work); display: flex; align-items: center; gap: 6px; }
/* ── Responsive ──────────────────────────────── */
@media (max-width: 860px) {
+12 -12
View File
@@ -23,7 +23,7 @@ const agents: AgentCardData[] = [
role: 'Chief of Staff',
description: 'Koordiniert, delegiert, hält das Team tight. Die erste Anlaufstelle zwischen Boss und Maschine.',
tags: ['Orchestration', 'Delegation', 'Approval'],
color: '#8b7cf6',
color: '#7c6cff',
icon: 'bot',
hero: true,
},
@@ -33,7 +33,7 @@ const agents: AgentCardData[] = [
role: 'Lead Developer',
description: 'Implementiert Features, schreibt Code, führt Builds und Tests aus. Arbeitet autonom im Scope.',
tags: ['coding', 'development', 'builds'],
color: '#3b82f6',
color: '#4f7cff',
icon: 'code',
},
{
@@ -42,7 +42,7 @@ const agents: AgentCardData[] = [
role: 'Code QA',
description: 'Prüft Code auf Bugs, Sicherheit und Wartbarkeit. Fixt Probleme eigenständig.',
tags: ['Quality Assurance', 'Security', 'Code Review'],
color: '#a855f7',
color: '#b557f6',
icon: 'shield',
},
{
@@ -51,7 +51,7 @@ const agents: AgentCardData[] = [
role: 'Research Analyst',
description: 'Recherchiert, analysiert Quellen, prüft Fakten. Nur Lese-Rechte, keine Aktionen.',
tags: ['Research', 'Analysis', 'Fact-Checking'],
color: '#22c55e',
color: '#3ddc97',
icon: 'search',
},
{
@@ -60,7 +60,7 @@ const agents: AgentCardData[] = [
role: 'Host Executor',
description: 'Führt Host-Kommandos auf dem VPS aus. Nur auf Iris-Befehl, niemals eigeninitiativ.',
tags: ['Execution', 'Deployment', 'VPS'],
color: '#eab308',
color: '#fbbf24',
icon: 'terminal',
},
]
@@ -133,7 +133,7 @@ function goToAgent(id: string) {
.quote-text {
font-style: italic;
font-size: 12px;
color: #9ea5b3;
color: var(--tx-2);
line-height: 1.5;
}
@@ -144,17 +144,17 @@ function goToAgent(id: string) {
.team-title {
font-size: 26px;
font-weight: 600;
color: #e8eaf0;
color: var(--tx);
margin: 0 0 6px;
}
.team-subtitle {
font-size: 12px;
color: #7e8799;
color: var(--tx-3);
margin: 0 0 4px;
}
.team-description {
font-size: 10.5px;
color: #6b7385;
color: var(--tx-3);
margin: 0;
max-width: 560px;
margin-left: auto;
@@ -182,7 +182,7 @@ function goToAgent(id: string) {
align-items: center;
gap: 8px;
font-size: 10px;
color: #7e8799;
color: var(--tx-3);
}
.legend-dot {
width: 8px;
@@ -191,11 +191,11 @@ function goToAgent(id: string) {
flex-shrink: 0;
}
.active-pulse {
background: #51d49a;
background: var(--st-work);
box-shadow: 0 0 6px rgba(81, 212, 154, 0.6);
}
.idle-pulse {
background: #3a3f4b;
background: var(--line-2);
}
.pulse-dot {
background: white;
+3 -2
View File
@@ -1,6 +1,6 @@
# Runtime und Routing
> Letzte Aktualisierung: 2026-06-16
> Letzte Aktualisierung: 2026-07-09
## Aktive Modelle (7 von 8 konfiguriert)
@@ -23,6 +23,7 @@
- Einzige aktive Integration: `OpenClawRuntime` über `IAgentRuntime`
- Model-Routing läuft zentral über OpenClaw Gateway (kein direct provider routing)
- API kommuniziert via `host.docker.internal:18789` (Gateway loopback — wird über `openclaw_default` Netzwerk gefixt)
- API kommuniziert über Docker-DNS via `http://openclaw-gateway-bao:18789` im gemeinsamen `openclaw_default`-Netzwerk.
- Der frühere Pfad `host.docker.internal:18789` ist auf dem VPS nicht erreichbar und wurde entfernt.
- **Achtung:** `[AllowAnonymous]` auf `/tasks/board` und `/tasks/reset-stale` muss durch ApiKey-Auth ersetzt werden (siehe [Architektur-Review](../docs/architecture-board-first-orchestration.md#61-kritisch--allowanonymous-auf-board-endpunkten))
- Vollständige Architektur- und Sicherheitsanalyse: [architecture-board-first-orchestration.md](../docs/architecture-board-first-orchestration.md)