diff --git a/openspec/changes/headless-panel/.openspec.yaml b/openspec/changes/archive/2026-10-18-headless-panel/.openspec.yaml similarity index 100% rename from openspec/changes/headless-panel/.openspec.yaml rename to openspec/changes/archive/2026-10-18-headless-panel/.openspec.yaml diff --git a/openspec/changes/headless-panel/design.md b/openspec/changes/archive/2026-10-18-headless-panel/design.md similarity index 100% rename from openspec/changes/headless-panel/design.md rename to openspec/changes/archive/2026-10-18-headless-panel/design.md diff --git a/openspec/changes/headless-panel/proposal.md b/openspec/changes/archive/2026-10-18-headless-panel/proposal.md similarity index 100% rename from openspec/changes/headless-panel/proposal.md rename to openspec/changes/archive/2026-10-18-headless-panel/proposal.md diff --git a/openspec/changes/headless-panel/specs/panel-appearance/spec.md b/openspec/changes/archive/2026-10-18-headless-panel/specs/panel-appearance/spec.md similarity index 100% rename from openspec/changes/headless-panel/specs/panel-appearance/spec.md rename to openspec/changes/archive/2026-10-18-headless-panel/specs/panel-appearance/spec.md diff --git a/openspec/changes/headless-panel/specs/panel-service/spec.md b/openspec/changes/archive/2026-10-18-headless-panel/specs/panel-service/spec.md similarity index 100% rename from openspec/changes/headless-panel/specs/panel-service/spec.md rename to openspec/changes/archive/2026-10-18-headless-panel/specs/panel-service/spec.md diff --git a/openspec/specs/panel-appearance/spec.md b/openspec/specs/panel-appearance/spec.md new file mode 100644 index 0000000..83ef285 --- /dev/null +++ b/openspec/specs/panel-appearance/spec.md @@ -0,0 +1,64 @@ +# panel-appearance Specification + +## Purpose +Позволяет пользователю выбрать фон панели прямо на странице, отдельно на каждом устройстве +(Safari на iPad, Toolbelt на Mac), чтобы панель не резала глаза рядом с его терминалом. + +## Requirements + +### Requirement: Шестерёнка настройки фона +Нижняя строка панели (рядом с «обновлено ЧЧ:ММ:СС») SHALL содержать значок ⚙. Тап по нему SHALL +раскрывать строку с образцами фона, кнопкой «свой цвет» и кнопкой «сброс»; повторный тап SHALL её +сворачивать. В свёрнутом виде, кроме значка, ничего нового на странице не видно. + +#### Scenario: Раскрыть и свернуть +- **WHEN** пользователь нажимает ⚙ +- **THEN** появляется строка образцов; при повторном нажатии она скрывается + +#### Scenario: Попадание пальцем +- **WHEN** страница открыта в Safari на iPad +- **THEN** ⚙, образцы и кнопки нажимаются пальцем без промахов (не мельче привычных элементов + управления iPadOS) + +### Requirement: Выбор фона +Выбор образца или своего цвета SHALL сразу менять фон всей панели, включая окно сообщений. Цвет +основного текста, приглушённого текста, линий дерева и разделителей SHALL подстраиваться под +яркость фона, чтобы оставаться читаемым. Цвета статусов и лимитов (зелёный, жёлтый, красный) +SHALL оставаться прежними. + +#### Scenario: Светлый фон +- **WHEN** пользователь выбирает светлый образец +- **THEN** фон становится светлым, а текст — тёмным и читаемым + +#### Scenario: Свой цвет +- **WHEN** пользователь нажимает «свой цвет» и выбирает цвет в системной палитре +- **THEN** фон панели становится этим цветом, текст подстраивается + +### Requirement: Выбор хранится на устройстве +Выбранный фон SHALL сохраняться средствами того браузера или web view, где он выбран, и SHALL +применяться при каждом открытии и автоматической перезагрузке страницы без мелькания темы по +умолчанию. Выбор на одном устройстве SHALL NOT влиять на другие. Если клиент не сохраняет данные +страницы между своими перезапусками (возможно, web view Toolbelt), после перезапуска клиента +показывается тема по умолчанию; на сервере выбор не хранится. + +#### Scenario: Клиент без постоянного хранилища +- **WHEN** выбор фона сделан в Toolbelt, а web view Toolbelt не сохраняет данные между + перезапусками iTerm2, и iTerm2 перезапущен +- **THEN** панель в Toolbelt показывает тему по умолчанию + +#### Scenario: Перезагрузка страницы +- **WHEN** пользователь выбрал фон в Safari на iPad и страница перезагрузилась (сама раз в минуту + или вручную) +- **THEN** сразу отображается выбранный фон + +#### Scenario: Разные устройства +- **WHEN** в Safari на iPad выбран светлый фон +- **THEN** панель в Toolbelt на Mac сохраняет свой фон + +### Requirement: Сброс к теме по умолчанию +«Сброс» SHALL удалять сохранённый выбор и возвращать тему, которую отдаёт сервер. Тема по умолчанию +SHALL выглядеть как нынешний профиль iTerm2 пользователя (`Chat`: фон `#002b36`, текст `#aacace`). + +#### Scenario: Сброс +- **WHEN** пользователь нажимает «сброс» +- **THEN** панель показывает тему по умолчанию, и после перезагрузки она остаётся по умолчанию diff --git a/openspec/specs/panel-service/spec.md b/openspec/specs/panel-service/spec.md new file mode 100644 index 0000000..0bc3f06 --- /dev/null +++ b/openspec/specs/panel-service/spec.md @@ -0,0 +1,96 @@ +# panel-service Specification + +## Purpose +Определяет, где и как работает сервер панели «Claude»: фоновая служба пользователя, не зависящая +от iTerm2, единственный владелец порта панели, тонкая регистрация в Toolbelt и установка/удаление. + +## Requirements + +### Requirement: Сервер панели работает без iTerm2 +Сервер панели SHALL отдавать страницу, дерево сессий, лимиты и баланс на `127.0.0.1:` +(по умолчанию 8766), пока пользователь вошёл в систему, независимо от того, запущен ли iTerm2. + +#### Scenario: iTerm2 не запущен +- **WHEN** пользователь вошёл в систему, iTerm2 не запущен, а сессия Claude Code работает в tmux +- **THEN** `http://127.0.0.1:8766/` отвечает 200 и показывает эту сессию с её субагентами, моделью, + контекстом и worktree, а нижний блок показывает лимиты и баланс + +#### Scenario: Имена сессий в tmux +- **WHEN** сессия Claude Code работает в панели tmux +- **THEN** её имя берётся из заголовка панели tmux или из `сессия:окно имя_окна`, как и раньше + +### Requirement: Служба стартует при входе и перезапускается при падении +Сервер панели SHALL запускаться автоматически при входе пользователя в систему и SHALL +перезапускаться, если его процесс завершился. + +#### Scenario: Вход в систему +- **WHEN** пользователь входит в систему на Mac после перезагрузки +- **THEN** сервер панели запускается без открытия iTerm2 и каких-либо действий пользователя + +#### Scenario: Падение процесса +- **WHEN** процесс сервера панели завершился (ошибка, `kill`) +- **THEN** он снова запущен и отвечает на порту в пределах нескольких десятков секунд + +### Requirement: Порт панели занимает один процесс +На порту панели SHALL работать ровно один сервер; лимиты и баланс SHALL опрашиваться одним +процессом, чтобы не удваивать запросы к API. + +#### Scenario: iTerm2 запускается при работающей службе +- **WHEN** служба уже отвечает на порту и пользователь запускает iTerm2 +- **THEN** второй сервер не запускается, в API лимитов идёт один поток запросов, а в Toolbelt + появляется панель «Claude», показывающая ту же страницу + +### Requirement: Toolbelt показывает панель фоновой службы +Скрипт панели в iTerm2 SHALL регистрировать web view «Claude» в Toolbelt, указывающий на адрес +фоновой службы, и SHALL NOT поднимать собственный сервер. + +#### Scenario: Toolbelt при запущенной службе +- **WHEN** iTerm2 запущен и пользователь выбирает Toolbelt → Claude +- **THEN** панель показывает ту же страницу, что и `http://127.0.0.1:8766/` в браузере + +#### Scenario: Служба не отвечает при старте iTerm2 +- **WHEN** iTerm2 стартует, а служба на порту не отвечает +- **THEN** скрипт просит launchd запустить службу и всё равно регистрирует web view + +### Requirement: Сервер доступен только локально +Сервер панели SHALL слушать только `127.0.0.1`; доступ с других устройств возможен только через +туннель (например, SSH local forward). + +#### Scenario: Запрос из локальной сети +- **WHEN** устройство в той же сети обращается к Mac по его LAN-адресу на порт панели +- **THEN** соединение не устанавливается + +### Requirement: Действия по клику работают через tmux +Переход к сессии и открытие worktree по клику SHALL выполняться средствами tmux для сессий в tmux, +независимо от iTerm2 и от того, на каком устройстве открыта страница. + +#### Scenario: Переход к сессии с iPad +- **WHEN** пользователь с iPad (страница через туннель) нажимает «↗ вкладка» у сессии в tmux +- **THEN** клиент tmux переключается на окно и панель этой сессии + +#### Scenario: Открытие worktree с iPad +- **WHEN** пользователь нажимает `⎇ папка` у сессии в tmux +- **THEN** в том же окне tmux открывается новая панель с файловым менеджером в этой папке + +### Requirement: Установка и удаление службы +`install.sh` SHALL устанавливать, (пере)запускать службу и останавливать прежний сервер, державший +порт; повторный запуск SHALL быть безопасным. `uninstall.sh` SHALL останавливать и удалять службу. + +#### Scenario: Обновление старой установки +- **WHEN** у пользователя стоит прежняя версия (сервер внутри iTerm2) и он запускает `install.sh` +- **THEN** прежний сервер остановлен, служба установлена и отвечает на порту, а iTerm2-скрипт + обновлён до регистратора + +#### Scenario: Повторная установка +- **WHEN** `install.sh` запускается второй раз подряд +- **THEN** служба одна, отвечает на порту, записи хуков в `settings.json` не задублированы + +#### Scenario: Запуск по SSH +- **WHEN** `install.sh` или `uninstall.sh` запущен из SSH-сессии +- **THEN** скрипт сообщает, что его нужно запускать за самим Mac, и завершается с ненулевым кодом, + ничего не изменив: прежний сервер продолжает работать + +#### Scenario: Удаление +- **WHEN** пользователь запускает `uninstall.sh` +- **THEN** служба остановлена, её описание удалено, порт свободен и после повторного входа в систему + служба не запускается