[2026-06-25] eagle: personal/tech/eagle-dashboard-launchd.md
This commit is contained in:
@@ -46,7 +46,7 @@ Eagle Dashboard ([eagle-dash](https://github.com/mallexxx/eagle-dash)) имее
|
||||
|
||||
### Чтение статуса launchd
|
||||
|
||||
`launchctl list {label}` на macOS (Sequoia 15.x, next-формат) возвращает openstep-style plist:
|
||||
`launchctl list {label}` на macOS (Sequoia 15.x, next-формат) возвращает openstep-style plist (не JSON, не tab-separated):
|
||||
|
||||
```
|
||||
{
|
||||
@@ -64,30 +64,32 @@ Eagle Dashboard ([eagle-dash](https://github.com/mallexxx/eagle-dash)) имее
|
||||
- `state = "scheduled"` — если есть расписание, процесс не запущен
|
||||
- `state = "stopped"` — если disabled (launchctl вернул non-zero)
|
||||
- `state = "idle"` — enabled, без расписания, без PID
|
||||
- `last_status` = None если процесс запущен (PID есть), иначе числовой exit code
|
||||
- `last_status = None` если процесс запущен (PID есть), иначе числовой exit code
|
||||
- `last_status = null` — ни разу не запускался
|
||||
|
||||
### Фронтенд (`templates/index.html`)
|
||||
|
||||
- **Services вкладка** — показывает Docker контейнеры, сервисы из registry, **и** секцию "Launchd (Always-On)" с always-on демонами
|
||||
- **Crons вкладка** — показывает Hermes Eagle/Whale кроны + launchd-кроны (только с расписанием)
|
||||
- **Модалка создания** — при выборе `source = launchd` скрываются поля: Deliver, Prompt, Model+Provider, Skills+Toolsets; показывается чекбокс "Run on load" (`runAtLoad`)
|
||||
- **Services вкладка** — показывает Docker контейнеры, сервисы из registry, **и** секцию "Launchd (Always-On)" с always-on демонами. Карточки launchd-сервисов имеют кнопки Pause/Resume и Delete.
|
||||
- **Crons вкладка** — показывает Hermes Eagle/Whale кроны + launchd-кроны (только с расписанием). Для launchd-кронов показывается schedule, exit code, runs count (runs не реализован из-за отсутствия данных в launchd).
|
||||
- **Модалка создания** — при выборе `source = launchd` скрываются поля: Deliver, Prompt, Model+Provider, Skills+Toolsets; показывается чекбокс "Run on load" (`runAtLoad`, отправляется как `run_at_load: boolean`)
|
||||
- **Schedule hint** — для launchd показывается упрощённый хинт: только `every Ns/m/h/d`
|
||||
- **Tab URL persistence** — через `history.replaceState` + URLSearchParams (`?tab=crons`)
|
||||
- **Контролы на launchd-сервисах (Services вкладка)**: кнопка ⏸ pause / ▶ resume (вызывает `/api/crons/launchd/{label}/toggle`), кнопка 🗑 delete (вызывает `DELETE /api/crons/launchd/{label}`)
|
||||
|
||||
## Ключевые решения
|
||||
|
||||
1. **Зачем отдельный launchd CRUD, а не plist вручную** — чтобы пользователь мог управлять своими кронами из единого интерфейса, не открывая терминал.
|
||||
1. **Зачем отдельный launchd CRUD** — чтобы пользователь мог управлять своими кронами из единого интерфейса, не открывая терминал.
|
||||
2. **Разделение crons/services** — launchd-агенты без `StartInterval`/`StartCalendarInterval` не показываются в Crons. Вместо этого они отображаются на Services вкладке как "Launchd (Always-On)".
|
||||
3. **PID vs LastExitStatus** — для запущенного процесса exit code неактуален, поэтому `last_status = None` при PID > 0.
|
||||
4. **Next-формат** — macOS Sequoia возвращает openstep plist (не tab-separated, не JSON). Парсинг через regex.
|
||||
4. **Next-формат** — macOS Sequoia возвращает openstep plist (не tab-separated, не JSON): `"Key" = value;`. Парсинг через regex.
|
||||
5. **Атомарная запись plist** — через `.tmp` + `.replace()` чтобы не повредить plist при ошибке записи.
|
||||
6. **`_list_launchd_crons()` vs `_list_launchd_services()`** — обе читают все plist из `_list_all_launchd()`, но фильтруют по `has_schedule`. Используют общий `_load_launchd_plist()`.
|
||||
|
||||
## Файлы
|
||||
|
||||
- `/Users/admin/Developer/eagle-dash/main.py` — backend
|
||||
- `/Users/admin/Developer/eagle-dash/templates/index.html` — frontend
|
||||
- `/Users/admin/Developer/eagle-dash/venv/` — virtualenv (FastAPI + uvicorn)
|
||||
- `/Users/admin/Developer/eagle-dash/.venv/` — virtualenv (FastAPI + uvicorn)
|
||||
- Запуск через launchd: `~/Library/LaunchAgents/com.eagle.dashboard.plist`
|
||||
|
||||
## Статус (2026-06-25)
|
||||
@@ -100,3 +102,6 @@ Eagle Dashboard ([eagle-dash](https://github.com/mallexxx/eagle-dash)) имее
|
||||
- [x] PID и LastExitStatus читаются из launchctl list (next-format)
|
||||
- [x] Спрятаны поля для launchd (prompt, deliver, skills и т.д.)
|
||||
- [x] Tab URL persistence
|
||||
- [x] Кнопки Pause/Resume/Delete на карточках launchd (и в Crons, и в Services)
|
||||
- [x] Разделение crons/services: с расписанием → Crons, без расписания → Services
|
||||
- [x] `_list_launchd_services()` — новый endpoint `/api/services/launchd`
|
||||
|
||||
Reference in New Issue
Block a user