Files
Claude Agent d466f358ce feat(discord-bridge): punte Discord -> Claude Code pe LXC 171
Implementeaza planul claude-master-plan-discord-bridge-20260830 (15 taskuri,
3 lane-uri paralele) — un bot subtire discord.py peste CLI-ul `claude`, cu
proces persistent per fir alimentat pe stdin cu --input-format stream-json.

Nucleu: runner (proces persistent + reaper 20min + respawn --resume), stream
(parser tolerant), session_store (scriere atomica, lock per fir, detectare PID
reuse, recovery), limits (max 4 procese, timeout tur, rate per user, plafon cost
pe zi), render (un loop de editare per canal, interval adaptiv).

Adaptor: allowlist guild/canal/user fail-closed cu respingerea webhook-urilor,
comenzi !new/!cd/!model/!status/!stop/!cleanup, cost si model in subsolul
fiecarui raspuns. Mesajul sosit in timpul unui tur devine steering, nu tur nou.

Securitate: hook PreToolUse fail-closed care cere confirmare in Discord pentru
operatiuni ireversibile, wrapper `infra` cu lista explicita de hosturi. Deny
rules raman strat cosmetic, nu bariera (verificat: /usr/bin/ssh trece pe langa).

Ops: alerte email pe conventia repo-ului, !cleanup pentru orfani, unit systemd
user cu KillMode=control-group si limite de memorie, install.sh idempotent.

Verificat: 275 teste fara retea/Discord/API (10.8s), identic cu si fara
discord.py instalat; e2e pe CLI real confirma steering-ul mid-tur (mesaj la 6s
intr-un tool call de 25s schimba raspunsul final).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
2026-08-30 10:44:39 +00:00

65 lines
1.6 KiB
Python

"""Fixturi comune: totul in tmp, zero retea, zero Discord, zero API."""
from __future__ import annotations
import os
import pathlib
import sys
import pytest
ROOT = pathlib.Path(__file__).resolve().parent.parent
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
import config # noqa: E402
FAKE_CLAUDE = str(pathlib.Path(__file__).resolve().parent / "fake_claude.py")
@pytest.fixture(autouse=True)
def state_dir(tmp_path, monkeypatch):
"""Muta ~/.claude-discord in tmp pentru fiecare test."""
d = tmp_path / "claude-discord"
d.mkdir()
monkeypatch.setenv("CLAUDE_DISCORD_DIR", str(d))
config.reload(d)
config.ensure_dirs()
yield d
config.reload()
@pytest.fixture
def store(state_dir):
import session_store
s = session_store.SessionStore(state_dir / "state.json", alerter=lambda *a, **k: None)
s.load()
return s
@pytest.fixture
def fake_bin():
"""Comanda care inlocuieste `claude` in teste."""
return [sys.executable, FAKE_CLAUDE]
@pytest.fixture
def scenario(monkeypatch):
def _set(name: str, **env):
monkeypatch.setenv("FAKE_CLAUDE_SCENARIO", name)
for k, v in env.items():
monkeypatch.setenv(k, str(v))
return _set
@pytest.fixture(autouse=True)
def _no_real_claude(monkeypatch, request):
"""Nicio suita implicita nu are voie sa cheme `claude --version`."""
if "e2e" in request.keywords:
return
import stream
monkeypatch.setattr(stream, "_cli_version_cache", "test-cli", raising=False)
monkeypatch.setattr(stream, "cli_version", lambda: "test-cli")