Andrey Epifancev c810f5a880 fix: pass shell PATH to panel service so tmux panes find lf (#4, H-1)
The launchd service runs with PATH=/usr/bin:/bin:/usr/sbin:/sbin; tmux
split-window gives the new pane the caller's PATH, so 'exec lf' failed
and the pane closed at once. install.sh now records its own PATH in the
plist EnvironmentVariables.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 22:44:58 +04:00

7.3 KiB
Raw Permalink Blame History

cc-agents-iterm-plugin

Что это

Панель «Claude» — страница на http://127.0.0.1:8766/. Сверху — дерево активных сессий Claude Code и их субагентов (название, модель, размер контекста, worktree, статус), снизу — лимиты подписки (5 ч, неделя, разбивка по продуктам) и баланс extra usage. Её показывает iTerm2 Toolbelt и браузер — в том числе Safari на iPad через SSH-туннель Termius. Для одного пользователя на его Mac: видеть, что делают все запущенные claude (в tmux), сколько осталось лимитов, и в один клик переходить в нужную панель tmux.

Стек и ограничения

  • Python 3.8+, только стандартная библиотека; модуль iterm2 нужен только регистратору Toolbelt (его даёт iTerm2). Без зависимостей из pip — пользователь ставит панель ./install.sh.
  • Хук — POSIX sh + jq. Хук никогда не мешает Claude Code: ничего не выводит, всегда exit 0.
  • macOS, launchd. Токен OAuth берётся из Keychain (Claude Code-credentials) или ~/.claude/.credentials.json, поэтому служба работает в GUI-сессии пользователя.
  • Сервер слушает только 127.0.0.1 — в панели видны тексты сообщений сессий.
  • Установщик не трогает чужие хуки и настройки: правит ~/.claude/settings.json только через settings_hooks.py (маркер agents_panel_hook), перед заменой кладёт копии в ~/.claude-panel-backup/<дата>/. Повторный запуск install.sh идемпотентен. Запуск по SSH install.sh/uninstall.sh отклоняют.

Архитектура

  • files/agents_panel_hook.sh — хук Claude Code на SessionStart/End, UserPromptSubmit, Stop, Notification, SubagentStart/Stop, PostModelSwitch, PreToolUse(Agent|Task). Дописывает событие в ~/.cache/claude-agents/<session_id>.jsonl вместе с PID процесса claude, ITERM_SESSION_ID или сокетом/панелью tmux.
  • files/claude_agents.py — один файл, два режима (run):
    • --headless (serve) — служба launchd com.andrey.claude-agents, единственный владелец порта:
      • refresher раз в poll_sec перечитывает jsonl (load_sessions → replay), сверяет с процессами (ps) и панелями tmux, дочитывает из транскриптов модель и токены, из git — worktree; собирает state["tree"] (build_tree, без данных iTerm2).
      • usage_poller / balance_poller ходят в api.anthropic.com/api/oauth/usage и .../prepaid/credits (запасной путь — claude.ai с sessionKey из Keychain).
      • HTTP-сервер (handle): /, /fragment (дерево), /limits, /message (последние сообщения), /activate и /open-wt (через tmux), /raw (отладка).
    • без флага (register_toolbelt) — скрипт AutoLaunch iTerm2: регистрирует web view «Claude» на адрес службы; если порт молчит — launchctl kickstart. Свой сервер не поднимает.
  • files/launchagent.py — пишет plist службы (write <plist> <python> <script> <log> <PATH>; PATH берётся из оболочки install.sh, его наследуют панели tmux, которые открывает служба).
  • files/settings_hooks.py — добавляет/убирает хуки панели в settings.json (add / remove).
  • files/config.example.json — все ключи настроек; рабочий файл ~/.config/claude-agents/config.json перечитывается на лету, кроме port.
  • install.sh / uninstall.sh [--purge] — раскладывают файлы, ставят/убирают службу (таблица в README.md).

Команды

  • ./install.sh — установить или обновить у себя (за самим Mac); затем Toolbelt → Claude и перезапуск сессий claude.
  • ./uninstall.sh — удалить (--purge — вместе с настройками и логами).
  • python3 -m unittest discover -s tests -v — весь набор тестов (stdlib, без pytest; node нужен для теста клиентского JS). Зелёным считается только весь набор.
  • python3 -m py_compile files/*.py && sh -n files/agents_panel_hook.sh && bash -n install.sh && bash -n uninstall.sh — синтаксическая проверка; сборки нет.
  • curl -s http://127.0.0.1:8766/raw — что видит запущенная панель: логи хука, причины скрытия сессий, ошибки лимитов и баланса. Лог службы — ~/Library/Logs/claude-agents/panel.log, состояние — launchctl print gui/$(id -u)/com.andrey.claude-agents.

Тесты

  • tests/ — unittest. claude_agents.py импортируется без iTerm2 (iterm2 = None). Сеть, Keychain, launchd, ps и tmux в тестах подменяются; реальные ~/.claude и ~/Library не трогаются.
  • install.sh и uninstall.sh в тестах запускаются только с SSH_CONNECTION/SSH_TTY (проверка отказа): без охраны они остановили бы настоящую панель на порту 8766.

Где лежит код

  • Код — в files/; хук require-plan защищает его через .claude/code-paths. install.sh и uninstall.sh в корне хуком не покрыты (он умеет только каталоги).

OpenSpec и superpowers

  • Вход в любую задачу — superpowers:brainstorming. Skills openspec-propose и openspec-explore сами по себе не запускать.
  • Когда brainstorming классифицировал задачу как architectural, структуру change создать через openspec new change <id> (или /opsx:propose <id>), а содержимое proposal.md, specs/ и design.md написать по итогам brainstorming. tasks.md из OpenSpec не заполнять — задачи живут в плане superpowers.
  • /opsx:apply не использовать: исполнение идёт через writing-plans и SDD/executing-plans.
  • openspec archive <id> — после merge PR, как часть чеклиста закрытия.
  • Хук require-plan защищает любой каталог src/ на любой глубине. Если код лежит иначе — перечислить каталоги (префиксы от корня, по одному в строке) в .claude/code-paths.