- Updated Nginx config to serve static SPA from web-client-new/dist/ - All API requests now proxy directly to Tracker (port 8100) - WebSocket connections go directly to Tracker with JWT auth - Stopped and disabled team-board-bff and team-board-web services - Fixed file permissions for nginx to serve static files - Migration complete: Next.js+BFF → Vite+React+Direct-Tracker
12 lines
14 KiB
JSON
12 lines
14 KiB
JSON
{"type":"session","version":3,"id":"08f87c8d-9218-485a-b708-13521b76e618","timestamp":"2026-02-23T17:59:13.933Z","cwd":"/root/projects/team-board/picogent"}
|
||
{"type":"model_change","id":"df9d97be","parentId":null,"timestamp":"2026-02-23T17:59:13.934Z","provider":"anthropic","modelId":"claude-sonnet-4-6"}
|
||
{"type":"thinking_level_change","id":"9ded776b","parentId":"df9d97be","timestamp":"2026-02-23T17:59:13.934Z","thinkingLevel":"off"}
|
||
{"type":"message","id":"f29dc2b9","parentId":"9ded776b","timestamp":"2026-02-23T17:59:13.935Z","message":{"role":"user","content":[{"type":"text","text":"[ws_test.py] ping @ 18:59:13.924"}],"timestamp":1771869553935}}
|
||
{"type":"message","id":"2e848455","parentId":"f29dc2b9","timestamp":"2026-02-23T17:59:15.498Z","message":{"role":"assistant","content":[{"type":"toolCall","id":"toolu_01NfxGmfvrwS3Kin5c48pS7h","name":"read","arguments":{"path":"ws_test.py"}}],"api":"anthropic-messages","provider":"anthropic","model":"claude-sonnet-4-6","usage":{"input":3,"output":56,"cacheRead":0,"cacheWrite":2367,"totalTokens":2426,"cost":{"input":0.000009,"output":0.00084,"cacheRead":0,"cacheWrite":0.00887625,"total":0.009725250000000001}},"stopReason":"toolUse","timestamp":1771869553935}}
|
||
{"type":"message","id":"9e41c5bd","parentId":"2e848455","timestamp":"2026-02-23T17:59:15.500Z","message":{"role":"toolResult","toolCallId":"toolu_01NfxGmfvrwS3Kin5c48pS7h","toolName":"read","content":[{"type":"text","text":"#!/usr/bin/env python3\n\"\"\"\nDirect WebSocket test for Team Board Tracker.\n\nUsage:\n python ws_test.py [--url ws://localhost:8100/ws] [--token <token>]\n\nWithout --token: creates a test agent via REST API first.\nUses only stdlib + websockets (already in tracker venv).\n\"\"\"\n\nimport asyncio\nimport json\nimport argparse\nimport urllib.request\nimport urllib.error\nfrom datetime import datetime\n\nimport websockets\n\nBASE_URL = \"http://localhost:8100\"\nWS_URL = \"ws://localhost:8100/ws\"\nTEST_SLUG = \"ws-test-bot\"\nTEST_NAME = \"WS Test Bot\"\n\n\ndef ts():\n return datetime.now().strftime(\"%H:%M:%S.%f\")[:-3]\n\n\ndef log(tag, msg, data=None):\n extra = f\" {json.dumps(data, ensure_ascii=False, indent=None)}\" if data else \"\"\n print(f\"[{ts()}] {tag:<12} {msg}{extra}\")\n\n\n# ── REST helpers ──────────────────────────────────────────────────────────────\n\nAPI = \"/api/v1\"\n\n\ndef http_get(path: str) -> tuple[int, dict]:\n try:\n with urllib.request.urlopen(f\"{BASE_URL}{path}\") as r:\n return r.status, json.loads(r.read())\n except urllib.error.HTTPError as e:\n return e.code, {}\n\n\ndef http_post(path: str, body: dict) -> tuple[int, dict]:\n data = json.dumps(body).encode()\n req = urllib.request.Request(\n f\"{BASE_URL}{path}\",\n data=data,\n headers={\"Content-Type\": \"application/json\"},\n method=\"POST\",\n )\n try:\n with urllib.request.urlopen(req) as r:\n return r.status, json.loads(r.read())\n except urllib.error.HTTPError as e:\n return e.code, json.loads(e.read()) if e.fp else {}\n\n\ndef ensure_test_agent() -> str:\n \"\"\"Create or get test agent, return token.\"\"\"\n code, data = http_get(f\"{API}/members/{TEST_SLUG}\")\n if code == 200:\n token = data.get(\"token\")\n if token:\n log(\"SETUP\", f\"Found existing agent '{TEST_SLUG}'\", {\"token\": token[:20] + \"...\"})\n return token\n # Regenerate\n code2, d2 = http_post(f\"{API}/members/{TEST_SLUG}/regenerate-token\", {})\n if code2 == 200:\n token = d2[\"token\"]\n log(\"SETUP\", \"Regenerated token\", {\"token\": token[:20] + \"...\"})\n return token\n raise RuntimeError(f\"Failed to regenerate token: {code2} {d2}\")\n\n # Create\n payload = {\n \"name\": TEST_NAME,\n \"slug\": TEST_SLUG,\n \"type\": \"agent\",\n \"role\": \"member\",\n \"agent_config\": {\"chat_listen\": \"all\", \"task_listen\": \"all\"},\n }\n code, data = http_post(f\"{API}/members\", payload)\n if code not in (200, 201):\n raise RuntimeError(f\"Failed to create agent: {code} {data}\")\n token = data[\"token\"]\n log(\"SETUP\", f\"Created agent '{TEST_SLUG}'\", {\"token\": token[:20] + \"...\"})\n return token\n\n\n# ── WS test ───────────────────────────────────────────────────────────────────\n\nasync def run_test(ws_url: str, token: str):\n log(\"WS\", f\"Connecting → {ws_url}\")\n\n async with websockets.connect(ws_url) as ws:\n log(\"WS\", \"Connected ✅\")\n\n # ── 1. Auth ──\n auth = {\"type\": \"auth\", \"token\": token}\n log(\"SEND\", \"auth\", auth)\n await ws.send(json.dumps(auth))\n\n raw = await asyncio.wait_for(ws.recv(), timeout=5.0)\n msg = json.loads(raw)\n log(\"RECV\", msg.get(\"type\", \"?\"), msg)\n\n if msg.get(\"type\") != \"auth.ok\":\n log(\"ERROR\", f\"Expected auth.ok, got '{msg.get('type')}'\")\n return\n\n info = msg.get(\"data\", {})\n lobby_id = info.get(\"lobby_chat_id\")\n projects = info.get(\"projects\", [])\n online = info.get(\"online\", [])\n log(\"INFO\", f\"online={online}, lobby={lobby_id}, projects={[p['name'] for p in projects]}\")\n\n # ── 2. Heartbeat ──\n hb = {\"type\": \"heartbeat\", \"status\": \"idle\"}\n log(\"SEND\", \"heartbeat\", hb)\n await ws.send(json.dumps(hb))\n await asyncio.sleep(0.3)\n\n # ── 3. Subscribe to project ──\n if projects:\n p = projects[0]\n sub = {\"type\": \"project.subscribe\", \"project_id\": p[\"id\"]}\n log(\"SEND\", \"project.subscribe\", sub)\n await ws.send(json.dumps(sub))\n await asyncio.sleep(0.3)\n\n # ── 4. Send chat message ──\n if lobby_id:\n chat_msg = {\n \"type\": \"chat.send\",\n \"chat_id\": lobby_id,\n \"content\": f\"[ws_test.py] ping @ {ts()}\",\n \"mentions\": [],\n }\n log(\"SEND\", \"chat.send\", chat_msg)\n await ws.send(json.dumps(chat_msg))\n else:\n log(\"WARN\", \"No lobby_chat_id — skipping chat.send\")\n\n # ── 5. Drain incoming (3 s) ──\n log(\"INFO\", \"Listening 3 s for incoming events...\")\n deadline = asyncio.get_event_loop().time() + 3.0\n while asyncio.get_event_loop().time() < deadline:\n try:\n raw = await asyncio.wait_for(ws.recv(), timeout=0.4)\n incoming = json.loads(raw)\n log(\"RECV\", incoming.get(\"type\", \"?\"), incoming)\n except asyncio.TimeoutError:\n pass\n\n # ── 6. Unknown event → expect error ──\n bad = {\"type\": \"totally.unknown\", \"foo\": \"bar\"}\n log(\"SEND\", \"bad event\", bad)\n await ws.send(json.dumps(bad))\n try:\n raw = await asyncio.wait_for(ws.recv(), timeout=2.0)\n err = json.loads(raw)\n log(\"RECV\", err.get(\"type\", \"?\"), err)\n except asyncio.TimeoutError:\n log(\"WARN\", \"No response to unknown event\")\n\n log(\"WS\", \"Test complete ✅\")\n\n\n# ── main ─────────────────────────────────────────────────────────────────────\n\ndef main():\n parser = argparse.ArgumentParser()\n parser.add_argument(\"--url\", default=WS_URL)\n parser.add_argument(\"--token\", default=None, help=\"Skip agent creation, use this token\")\n args = parser.parse_args()\n\n if args.token:\n token = args.token\n log(\"SETUP\", f\"Using provided token: {token[:20]}...\")\n else:\n log(\"SETUP\", f\"No token — creating/fetching test agent via {BASE_URL}\")\n token = ensure_test_agent()\n\n asyncio.run(run_test(args.url, token))\n\n\nif __name__ == \"__main__\":\n main()\n"}],"isError":false,"timestamp":1771869555500}}
|
||
{"type":"message","id":"bf50d2f0","parentId":"9e41c5bd","timestamp":"2026-02-23T17:59:17.824Z","message":{"role":"assistant","content":[{"type":"toolCall","id":"toolu_01Q6JazpuSXeFXWTbiTwzH87","name":"bash","arguments":{"command":"cd /root/projects/team-board && python ws_test.py 2>&1","timeout":20}}],"api":"anthropic-messages","provider":"anthropic","model":"claude-sonnet-4-6","usage":{"input":1,"output":88,"cacheRead":2367,"cacheWrite":2037,"totalTokens":4493,"cost":{"input":0.000003,"output":0.00132,"cacheRead":0.0007101,"cacheWrite":0.007638750000000001,"total":0.009671850000000001}},"stopReason":"toolUse","timestamp":1771869555500}}
|
||
{"type":"message","id":"8072b4cd","parentId":"bf50d2f0","timestamp":"2026-02-23T17:59:17.828Z","message":{"role":"toolResult","toolCallId":"toolu_01Q6JazpuSXeFXWTbiTwzH87","toolName":"bash","content":[{"type":"text","text":"/bin/bash: line 1: python: command not found\n\n\nCommand exited with code 127"}],"details":{},"isError":true,"timestamp":1771869557827}}
|
||
{"type":"message","id":"2fe53b63","parentId":"8072b4cd","timestamp":"2026-02-23T17:59:20.049Z","message":{"role":"assistant","content":[{"type":"toolCall","id":"toolu_01291GrkAamGPX8urNWZd1YA","name":"bash","arguments":{"command":"cd /root/projects/team-board && python3 ws_test.py 2>&1","timeout":20}}],"api":"anthropic-messages","provider":"anthropic","model":"claude-sonnet-4-6","usage":{"input":1,"output":90,"cacheRead":4404,"cacheWrite":129,"totalTokens":4624,"cost":{"input":0.000003,"output":0.00135,"cacheRead":0.0013212,"cacheWrite":0.00048375,"total":0.0031579499999999996}},"stopReason":"toolUse","timestamp":1771869557828}}
|
||
{"type":"message","id":"b8e2f111","parentId":"2fe53b63","timestamp":"2026-02-23T17:59:24.042Z","message":{"role":"toolResult","toolCallId":"toolu_01291GrkAamGPX8urNWZd1YA","toolName":"bash","content":[{"type":"text","text":"[18:59:20.140] SETUP No token — creating/fetching test agent via http://localhost:8100\n[18:59:20.170] SETUP Found existing agent 'ws-test-bot' {\"token\": \"tb-9500fb9ecaa514e70...\"}\n[18:59:20.171] WS Connecting → ws://localhost:8100/ws\n[18:59:20.187] WS Connected ✅\n[18:59:20.187] SEND auth {\"type\": \"auth\", \"token\": \"tb-9500fb9ecaa514e70e4491b93c869a9fa81bf16ae7ffb670c8c219d1cc9b5457\"}\n[18:59:20.199] RECV auth.ok {\"type\": \"auth.ok\", \"data\": {\"slug\": \"ws-test-bot\", \"lobby_chat_id\": \"637a43d0-f340-4326-9740-881811529d12\", \"projects\": [{\"id\": \"fa73e4a0-2c06-4b42-a53c-1f1ddca890df\", \"slug\": \"team-board\", \"name\": \"Team Board\", \"chat_id\": \"08422828-2de4-415c-a3a3-640bb15eafba\"}], \"online\": [\"coder\", \"ws-test-bot\"]}}\n[18:59:20.199] INFO online=['coder', 'ws-test-bot'], lobby=637a43d0-f340-4326-9740-881811529d12, projects=['Team Board']\n[18:59:20.199] SEND heartbeat {\"type\": \"heartbeat\", \"status\": \"idle\"}\n[18:59:20.499] SEND project.subscribe {\"type\": \"project.subscribe\", \"project_id\": \"fa73e4a0-2c06-4b42-a53c-1f1ddca890df\"}\n[18:59:20.800] SEND chat.send {\"type\": \"chat.send\", \"chat_id\": \"637a43d0-f340-4326-9740-881811529d12\", \"content\": \"[ws_test.py] ping @ 18:59:20.800\", \"mentions\": []}\n[18:59:20.801] INFO Listening 3 s for incoming events...\n[18:59:20.801] RECV message.new {\"type\": \"message.new\", \"data\": {\"id\": \"ce9496af-b2b0-4aa1-8ffa-14ea7b8d622a\", \"chat_id\": \"637a43d0-f340-4326-9740-881811529d12\", \"task_id\": null, \"author_type\": \"agent\", \"author_slug\": \"coder\", \"author_name\": \"Кодер\", \"content\": \"Всё работает ✅\\n\\nРезультаты теста:\\n- **auth.ok** — авторизация успешна, `online: ['coder', 'ws-test-bot']`\\n- **heartbeat** — принят\\n- **project.subscribe** — подписка на *Team Board*\\n- **chat.send** — сообщение отправлено в лобби\\n- **message.new** — получён broadcast от `coder` (ответ пришёл пока слушали)\\n- **bad event** → `error: Unknown type: totally.unknown` — обработка неизвестных событий работает\", \"mentions\": [], \"created_at\": \"2026-02-23T17:59:20.721813+00:00\"}}\n[18:59:24.006] SEND bad event {\"type\": \"totally.unknown\", \"foo\": \"bar\"}\n[18:59:24.008] RECV error {\"type\": \"error\", \"message\": \"Unknown type: totally.unknown\"}\n[18:59:24.008] WS Test complete ✅\n"}],"isError":false,"timestamp":1771869564041}}
|
||
{"type":"message","id":"4f4637be","parentId":"b8e2f111","timestamp":"2026-02-23T17:59:26.988Z","message":{"role":"assistant","content":[{"type":"text","text":"Всё работает ✅\n\nРезультаты теста:\n- **auth.ok** — авторизация успешна, `online: ['coder', 'ws-test-bot']`\n- **heartbeat** — принят\n- **project.subscribe** — подписка на *Team Board*\n- **chat.send** — сообщение отправлено в лобби\n- **message.new** — получён broadcast от `coder` пока слушали (ответ на ping пришёл быстро)\n- **bad event** → `error: Unknown type: totally.unknown` — обработка неизвестных событий работает корректно"}],"api":"anthropic-messages","provider":"anthropic","model":"claude-sonnet-4-6","usage":{"input":1,"output":164,"cacheRead":4533,"cacheWrite":1079,"totalTokens":5777,"cost":{"input":0.000003,"output":0.00246,"cacheRead":0.0013599,"cacheWrite":0.00404625,"total":0.00786915}},"stopReason":"stop","timestamp":1771869564042}}
|