Files

12 KiB
Raw Permalink Blame History

PROGRESS - t3code-mcp

Что сделано, что нет, что проверить руками. Свежие записи сверху. Архитектурная правда - архитектура.md §5 (vault, симлинк в ../../архитектура.md), журнал всей второй итерации - ../../PROGRESS.md.

2026-09-01 - подписка на события треда управляется из диспетчера

Сделано: у Tracked появился флаг watch (по умолчанию true, лежит в том же T3CODE_MCP_STATE); Tracker.apply() при watch=false состояние треда обновляет как раньше, но события гасит - значит после обратной подписки не прилетит задним числом переход, случившийся в тишине. Тулза t3_watch(thread_id?, enabled?): без аргументов - списки watched / unwatched (тред, машина, проект, заголовок, состояние), с обоими - снять или вернуть подписку; неизвестный тред - ToolError. У t3_dispatch параметр watch (по умолчанию true) - чтобы не ловить гонку на быстрых тредах; каждый диспатч в тред флаг перезаписывает, продолжение треда через thread_id= тоже. Загрузка стейта теперь игнорирует незнакомые поля - откат образа на версию без watch не уронит Tracker. 15 тестов.

Не сделано: подписаться на тред, который не запускали через t3_dispatch (в трекере его нет - t3_watch ответит ошибкой); гранулярности по типу события (question отдельно от completed) нет - флаг один на тред. Проверить руками после рестарта beaver-t3code-mcp: t3_watch() из диспетчера отдаёт список, t3_watch("ba48cd69-7c55-461f-9a15-8058425032a0", enabled=false) - тред фейбла на маке, по которому инжекты больше не нужны (на старом образе снять было нечем: трекер держит состояние в памяти и переписывает json, правка файла не живёт до рестарта).

2026-08-29 - S10b: события тредов и ответы на вопросы

Сделано: watch.py - WS-подписка orchestration.subscribeShell на каждую машину (протокол Effect RPC проверен живьём: тикет POST /api/auth/websocket-ticketws://…/ws?wsTicket=, Request{id, tag, payload, headers: []}Chunk{values} + обязательный Ack, Ping keepalive, Exit; реконнект с afterSequence, при снапшоте состояние трекаемых тредов переигрывается - переходы, пропущенные офлайн, не теряются). Tracker держит треды из t3_dispatch в json (T3CODE_MCP_STATE, volume t3code-state), apply() превращает shell-апдейты в события question / approval / completed / interrupted / failed (session.lastError). Hook - persisted outbox с ретраями в T3CODE_MCP_HOOK_URL (bearer T3CODE_MCP_GATEWAY_TOKEN). Тулза t3_answer(thread_id, answers)thread.user-input.respond (requestId из activity user-input.requested, answers - id вопроса → label; у Claude id = текст вопроса). t3_thread/t3_wait отдают question (request_id, вопросы, варианты). Общие read-model хелперы вынесены в views.py. Gateway: Job(dedupe=False) (beaver-gateway 0365ab5), в beaver-agent/config.py job t3code (webhook) → inject_master(urgency="urgent", origin="t3code") с текстом события и подсказкой про t3_answer/say; compose: env T3CODE_MCP_HOOK_URL=http://gateway:62990/hooks/t3code, T3CODE_MCP_STATE, volume; токен gateway t3code-mcp-hooks (scope api) выпущен и лежит в /root/beaver-agent/.env как T3CODE_MCP_GATEWAY_TOKEN. Живой прогон: диспатч на мак с AskUserQuestion → событие question через 10 с в приёмник → t3_answer(…, {id: "beta"}) → тред дописал файл → событие completed с ответом; 13 тестов (трекер, outbox с ретраем, t3_answer, трекинг при диспатче).

Не сделано: аппрувы (thread.approval.respond) - в full-access не возникают, событие approval приходит, ответить нечем; инжект всегда в мастер (ветка, которая диспатчила, не знает своего id в MCP); t3_wait оставлен как есть. Проверить руками после деплоя: docker logs beaver-t3code-mcp - две строки watch <machine>: subscribed; в телеге попросить диспетчера запустить тред с вопросом и посмотреть, что он ответит сам или спросит через say.

2026-08-29 - S10 (M6b): коннектор, две машины, dell как фоновые руки

Сделано: репа beaver/t3code-mcp (Python 3.13, FastMCP 3.4.7, httpx, pydantic-settings; ruff ALL + ty + pytest, make check чистый, 9 тестов на фейковом T3 через httpx transport). Тулзы t3_machines, t3_projects, t3_dispatch (thread.create + thread.turn.start, или только turn.start при thread_id=), t3_thread, t3_wait, t3_interrupt - по packages/contracts/src/environmentHttp.ts + orchestration.ts из ~/projects/playgrounds/t3code (HEAD 2026-08-29, серверы 0.0.36). Конфиг t3code.toml (машины, token_env, allowlist fnmatch по названию и workspace root, модель по умолчанию), токены только из env. Проверено живьём: диспатч в t3-smoke на маке (~/projects/playgrounds/t3-smoke, заведён t3 project add) → turn.completed за 10 с, ответ и smoke.txt на месте; диспатч в projects на dell → Клод прочитал ~/.claude/CLAUDE.md, склонировал beaver/beaver-land по ssh как hh, сделал t3 project add, проверил gh и токен Gitea - 25 с. Dell поднят как вторая машина: node 22 + t3@0.0.36 (npm -g, нужен build-essential для node-pty), claude CLI 2.1.251, uv, gh (залогинен как haikesan), t3 service install (user-unit t3code.service, linger включён) с drop-in EnvironmentFile=/root/.t3/service.env (T3CODE_HOST=100.76.140.93, T3CODE_PORT=3773, CLAUDE_CODE_OAUTH_TOKEN из beaver-agent/.env, PATH с bun/uv, IS_SANDBOX=1 - иначе Claude Code отказывает в bypassPermissions под root), textGenerationModelSelection → claudeAgent/sonnet (иначе заголовки тредов пытаются звать codex, которого нет). На dell: /root/.claude/{CLAUDE.md,commands/commit.md,skills/komodo,settings.json} (те же /commit и komodo, что на маке; CLAUDE.md - раскладка ~/projects/<org>/<repo> как организации Gitea, правила пуша), ~/.gitconfig, ~/.config/komodo/credentials, ~/.config/gitea/token (новый токен dell-claude-2026-08: repository/organization/issue/package), свой ssh-ключ id_ed25519_gitea в аккаунте hh (старый id_ed25519 - read-only deploy key cars-demo), /root/projects заведён проектом projects. Токены t3 auth session issue --ttl 365d --label beaver-t3code-mcp с обеих машин записаны в /root/beaver-agent/.env как T3_MAC_TOKEN/T3_DELL_TOKEN, там же COMPOSE_PROFILES=…,t3 и T3CODE_MCP_REF=main. В beaver-agent: сервис t3code-mcp в compose (профиль t3, образ из git), t3code.toml, McpServer.http("t3code") в config.py, отдаётся только диспетчеру; .env.example без T3_URL/T3_TOKEN. Скилл мета/бобер/скиллы/диспетчер/t3code/SKILL.md написан целиком.

Решения по ходу (легко откатить): (1) t3_wait - обычный долгий вызов, не MCP Task: расширение Tasks в 2026-07-28 вынесено в io.modelcontextprotocol/tasks, python-SDK 1.29 на 2025-11-25, Claude Code Tasks не поддерживает и сам уводит вызов > 2 мин в фон (CLAUDE_CODE_MCP_AUTO_BACKGROUND_MS); потолок ожидания 3600 с, опрос 5 с, флаги pending из shell-снапшота раз в 30 с. (2) Сразу после turn.start у треда ещё нет latestTurn - это состояние starting; t3_wait не выходит из него, пока не появится тёрн, сессия не упадёт (lastError) или тред не простоит stopped три опроса. (3) На маке отдельный t3 serve не поднимал: сервер десктопного T3 Code уже слушает 0.0.0.0:3773, из tailnet и из контейнера на dell доступен по http://100.65.207.48:3773; жив, пока запущено приложение. Tailscale Serve/HTTPS не включал - внутри tailnet хватает http. (4) Треды без worktree (branch/worktreePath = null), в workspace root. (5) t3_dispatch умеет thread_id= для продолжения треда - шестая тулза из §5 не добавлялась, это параметр. (6) Dell работает под root (так устроен весь /root/*), граница - allowlist проектов и IS_SANDBOX; отдельный пользователь для t3 - если понадобится.

После ревью h: allowlist * на обеих машинах (решение h), репо сделано публичным (compose на dell тянет context: https://git.kotikot.com/beaver/t3code-mcp.git#main без кредов, private падал на could not read Username), задеплоено пушем beaver-agent main:stable + DeployStack. Не сделано: ответ на pending.user_input/аппрувы через MCP (thread.user-input.respond не обёрнут - тред прерывается и продолжается новым t3_dispatch(thread_id=)); вложения; worktree-режим; codex на dell; pre-commit на dell не ставил. Расхождения с архитектура.md §5, не правил: «t3 serve --tailscale-serve на маке» - фактически сервер десктопа по http в tailnet; «Tasks вместо t3_wait» - проверено, неприменимо (см. выше); t3_thread(thread_id) без машины - тред ищется по всем машинам.

Проверить руками:

cd t3code-mcp && make check
# живой диспатч с мака (токен - `t3 auth session issue --token-only --ttl 1h`):
T3_MAC_TOKEN=... T3CODE_MCP_CONFIG=t3code.example.toml uv run python -m t3code_mcp   # в другом окне
uv run python scripts/smoke.py http://127.0.0.1:8000/mcp mac t3-smoke
# dell:
ssh root@100.76.140.93 'XDG_RUNTIME_DIR=/run/user/0 systemctl --user status t3code.service | head -5; curl -s http://100.76.140.93:3773/.well-known/t3/environment'
# после `make deploy` в beaver-agent:
ssh root@100.76.140.93 'docker logs beaver-t3code-mcp --tail 5; docker exec beaver-gateway python -c "import urllib.request;print(urllib.request.urlopen(\"http://t3code-mcp:8000/healthz\").read())"'
# в телеге: «запусти на dell в проекте projects: …» → диспетчер зовёт t3_dispatch, t3_wait