Fold NOTES.md into README.md
NOTES.md was written before the code, to hold the intent and the checked
facts about the environment. Everything in it that still applies now
lives in README.md, and the parts that do not -- the order of work, the
fields to verify against real hook input -- were answered by building it.
Two notes were kept rather than dropped: the rejection of desktop
notifications, which is a decision that would otherwise be re-litigated,
and the reasoning for hiding sub-agents. The original text stays in
history at 7fc7f63.
This commit is contained in:
@@ -1,123 +0,0 @@
|
|||||||
# Индикатор статуса Claude Code в панели GNOME
|
|
||||||
|
|
||||||
Заметка для быстрого старта. Написана до кода — здесь замысел и проверенные
|
|
||||||
факты об окружении, а не описание существующего.
|
|
||||||
|
|
||||||
## Задача
|
|
||||||
|
|
||||||
Знать, **когда переключиться** на терминал с Claude Code и **на какой именно**,
|
|
||||||
не глядя в сами терминалы. Состояний три: работает / ждёт меня / тихо.
|
|
||||||
|
|
||||||
Сессий одновременно несколько (разные проекты, разные терминалы) — это основной
|
|
||||||
режим, а не краевой случай.
|
|
||||||
|
|
||||||
## Решения, принятые заранее
|
|
||||||
|
|
||||||
- **Уведомлений не будет.** `notify-send` отвергнут сознательно, хотя он и был бы
|
|
||||||
дешевле. Следствие: панель — единственный канал, значит расширение делается
|
|
||||||
сразу, «сначала уведомления, потом может быть индикатор» отпадает.
|
|
||||||
- **Панель называет проект, а не только состояние.** «Кто-то ждёт» оставляет
|
|
||||||
гадать, в каком из четырёх терминалов; знать «когда» без «куда» бесполезно.
|
|
||||||
- **Сабагенты внутри сессии не показываются.** Батч из восьми задач — это одна
|
|
||||||
строка «работает 40 мин», и это правильная строка: пятый воркер из восьми ни о
|
|
||||||
чём не просит. Хук `SubagentStop` для этого существует, но вешать на него
|
|
||||||
статус — шум. Если понадобится прогресс внутри батча (сделано N из 8), брать
|
|
||||||
его надо из учёта задач, а не из хуков.
|
|
||||||
|
|
||||||
## Окружение (проверено 2026-08-07)
|
|
||||||
|
|
||||||
- GNOME Shell **46.0**, сессия **Wayland**, `XDG_CURRENT_DESKTOP=ubuntu:GNOME`.
|
|
||||||
- `~/.claude/settings.json`: ключа `hooks` нет вовсе (`{}`) — место чистое,
|
|
||||||
ничего не сломаем. `statusLine` занят: `bash ~/.claude/statusline-command.sh`.
|
|
||||||
|
|
||||||
## Шаблон — своё же расширение
|
|
||||||
|
|
||||||
`~/projects/private/sing-box-gnome-extension`, оно же
|
|
||||||
`sing-box-status@git.vakhrushev.me`. Установлено **симлинком** из репозитория в
|
|
||||||
`~/.local/share/gnome-shell/extensions/<uuid>` — так же ставим и это.
|
|
||||||
|
|
||||||
Скелет копируется целиком:
|
|
||||||
|
|
||||||
```
|
|
||||||
extension.js 16 строк: enable() → Main.panel.addToStatusArea(uuid, indicator)
|
|
||||||
lib/indicator.js панель и меню
|
|
||||||
lib/format.js форматирование
|
|
||||||
prefs.js настройки
|
|
||||||
schemas/ gschema.xml + gschemas.compiled
|
|
||||||
metadata.json "shell-version": ["45","46","47","48"]
|
|
||||||
stylesheet.css
|
|
||||||
```
|
|
||||||
|
|
||||||
Меняется только источник данных: вместо опроса Clash API по HTTP —
|
|
||||||
**`Gio.FileMonitor`** на каталоге состояния. Это push, поллинг не нужен, выходит
|
|
||||||
проще оригинала.
|
|
||||||
|
|
||||||
Предполагаемый uuid: `claude-code-status@git.vakhrushev.me`.
|
|
||||||
|
|
||||||
## Источник данных — хуки Claude Code
|
|
||||||
|
|
||||||
Пишутся в глобальный `~/.claude/settings.json`, чтобы работало во всех проектах.
|
|
||||||
|
|
||||||
| Хук | Состояние |
|
|
||||||
|---|---|
|
|
||||||
| `SessionStart` | сессия появилась |
|
|
||||||
| `UserPromptSubmit` | работает |
|
|
||||||
| `Notification` | ждёт меня — разрешение или простой на вводе |
|
|
||||||
| `Stop` | ход закончен, ждёт ввода |
|
|
||||||
| `SessionEnd` | сессия исчезла |
|
|
||||||
|
|
||||||
`Notification` и `Stop` **разделять в панели**: первое горит (заблокирована на
|
|
||||||
разрешении), второе просто ждёт (задача сделана). Слитые в одно, законченная
|
|
||||||
задача выглядит так же срочно, как заблокированная.
|
|
||||||
|
|
||||||
### Файл состояния
|
|
||||||
|
|
||||||
Один файл на сессию, иначе параллельные сессии затирают друг друга:
|
|
||||||
|
|
||||||
```
|
|
||||||
~/.local/state/claude-code-status/<session_id>.json
|
|
||||||
```
|
|
||||||
|
|
||||||
Поля: состояние, `cwd`, метка времени последней смены, `$PPID` для проверки
|
|
||||||
живости. `SessionEnd` файл удаляет.
|
|
||||||
|
|
||||||
**Проверить на первом же прогоне** (по памяти, не подтверждено): хук получает на
|
|
||||||
stdin JSON с `session_id`, `cwd`, `transcript_path`, `hook_event_name`. Имена
|
|
||||||
полей сверить с реальным вводом, а не доверять этой строке.
|
|
||||||
|
|
||||||
Названия событий `SubagentStop`, `SessionEnd`, `UserPromptSubmit` подтверждены —
|
|
||||||
встречаются в конфиге плагина wakatime (`~/.claude/plugins/cache/wakatime/`),
|
|
||||||
там же можно подсмотреть рабочий пример hooks.json.
|
|
||||||
|
|
||||||
## Правила отображения
|
|
||||||
|
|
||||||
Приоритет агрегации: **хоть одна ждёт → «ждёт»**, иначе **хоть одна работает →
|
|
||||||
«работает»**, иначе тихо.
|
|
||||||
|
|
||||||
- Показывается **дольше всех ждущая** сессия, не последняя: последняя и так
|
|
||||||
свежа в голове, забывается именно давняя.
|
|
||||||
- Несколько ждущих — счётчиком: `✋ dev-skills +2`.
|
|
||||||
- Для работающей полезно «работает 6 мин» — по этому решаешь, ждать или уходить.
|
|
||||||
- В меню — список сессий с **полным путём**: два worktree одного репозитория по
|
|
||||||
basename не различаются.
|
|
||||||
|
|
||||||
## Известные шероховатости
|
|
||||||
|
|
||||||
- **Протухание.** Убитый терминал не пришлёт `SessionEnd`, файл останется.
|
|
||||||
Лечится меткой времени плюс проверкой живости `$PPID` — не идеально, но
|
|
||||||
практично; индикатор гасит протухшие.
|
|
||||||
- **Клик в меню не переключит фокус** на нужный терминал: на Wayland расширению
|
|
||||||
это просто так не даётся. Меню информационное.
|
|
||||||
- **`Stop` не отличает «закончил» от «упал»** — оба выглядят как «ждёт ввода».
|
|
||||||
Для задачи «пора переключиться» разницы нет, но знать стоит.
|
|
||||||
|
|
||||||
## Порядок работ
|
|
||||||
|
|
||||||
1. Хуки и формат файла состояния — в `~/.claude/settings.json`.
|
|
||||||
2. **Проверить на живых сессиях** через `watch cat`, что состояния переключаются
|
|
||||||
правильно и поля stdin те, что ожидались. Здесь же выяснится, когда реально
|
|
||||||
срабатывает `Notification`.
|
|
||||||
3. Индикатор поверх заведомо верных данных.
|
|
||||||
|
|
||||||
Порядок именно такой: отлаживать GJS и раскладку состояний одновременно — это
|
|
||||||
две неизвестные в одном уравнении.
|
|
||||||
@@ -24,6 +24,11 @@ The panel shows the **highest-priority** session and, when others share that
|
|||||||
state, a `+N` count. Within a state the **oldest** one wins: the session you
|
state, a `+N` count. Within a state the **oldest** one wins: the session you
|
||||||
have forgotten about is the one that has been waiting longest, never the latest.
|
have forgotten about is the one that has been waiting longest, never the latest.
|
||||||
|
|
||||||
|
There are deliberately **no desktop notifications**. `notify-send` from a hook
|
||||||
|
would have been far cheaper to build, and it is the wrong shape: a session that
|
||||||
|
has been waiting twenty minutes needs to stay visible, and a notification is
|
||||||
|
gone the moment it is dismissed. The panel is the whole channel.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|||||||
Reference in New Issue
Block a user