Логика статуса в строке меню

Что отображается

  • Мы отображаем текущее состояние работы агента в иконке строки меню и в первой строке статуса меню.
  • Статус здоровья скрыт, пока активна работа; он возвращается, когда все сессии простаивают.
  • Блок "Узлы" в меню перечисляет только устройства (спаренные узлы через node.list), а не записи клиента/присутствия.
  • Раздел "Использование" появляется под Контекстом, когда доступны снимки использования провайдера.

Модель состояния

  • Сессии: события приходят с runId (для каждого запуска) плюс sessionKey в payload. "Основная" сессия - это ключ main; если отсутствует, мы возвращаемся к последней обновленной сессии.
  • Приоритет: main всегда выигрывает. Если main активна, её состояние отображается немедленно. Если main простаивает, отображается последняя активная не-main сессия. Мы не переключаемся туда-сюда во время активности; мы переключаемся только когда текущая сессия переходит в простой или main становится активной.
  • Виды активности:
    • job: высокоуровневое выполнение команды (state: started|streaming|done|error).
    • tool: phase: start|result с toolName и meta/args.

Enum IconState (Swift)

  • idle
  • workingMain(ActivityKind)
  • workingOther(ActivityKind)
  • overridden(ActivityKind) (переопределение отладки)

ActivityKind → глиф

  • exec → 💻
  • read → 📄
  • write → ✍️
  • edit → 📝
  • attach → 📎
  • default → 🛠️

Визуальное отображение

  • idle: обычный critter.
  • workingMain: значок с глифом, полный оттенок, анимация "работы" лап.
  • workingOther: значок с глифом, приглушенный оттенок, без суеты.
  • overridden: использует выбранный глиф/оттенок независимо от активности.

Текст строки статуса (меню)

  • Пока активна работа: <Роль сессии> · <метка активности>
    • Примеры: Main · exec: pnpm test, Other · read: apps/macos/Sources/OpenClaw/AppState.swift.
  • В простое: возвращается к сводке здоровья.

Прием событий

  • Источник: события agent канала управления (ControlChannel.handleAgentEvent).
  • Парсенные поля:
    • stream: "job" с data.state для запуска/остановки.
    • stream: "tool" с data.phase, name, опциональные meta/args.
  • Метки:
    • exec: первая строка args.command.
    • read/write: сокращенный путь.
    • edit: путь плюс выведенный вид изменения из meta/счетчиков diff.
    • fallback: имя инструмента.

Переопределение отладки

  • Настройки ▸ Отладка ▸ Выбор "Переопределение иконки":
    • System (auto) (по умолчанию)
    • Working: main (для каждого вида инструмента)
    • Working: other (для каждого вида инструмента)
    • Idle
  • Хранится через @AppStorage("iconOverride"); отображается в IconState.overridden.

Контрольный список тестирования

  • Запустить задание основной сессии: проверить, что иконка переключается немедленно и строка статуса показывает основную метку.
  • Запустить задание не-основной сессии при простое основной: иконка/статус показывает не-основную; остается стабильной, пока не закончится.
  • Запустить основную, пока другая активна: иконка переключается на основную мгновенно.
  • Быстрые серии инструментов: убедитесь, что значок не мерцает (TTL grace на результатах инструментов).
  • Строка здоровья появляется снова, когда все сессии простаивают.