[2026-06-25] taiga-vault: personal/projects/personal-os/eagle-dashboard.md

This commit is contained in:
Taiga
2026-06-25 05:55:21 +00:00
parent be328935c7
commit 0da0c9e80d
@@ -270,6 +270,23 @@ When a launchd cron is created and `launchctl print gui/<uid>/<label>` shows `la
1. **`~` not expanded in ProgramArguments.** launchd does not expand `~`. Use full path: `/Users/admin/scripts/foo.sh`
2. **Script itself exits 78.** Check script logic: `exit 78` is `EX_CONFIG` (configuration error). Fix the script.
## Launchd status display — PID & exit code parsing
`_list_launchd_crons()` parses `launchctl list <label>` output to determine process state:
- **next-format plist** — macOS Sequoia returns `{ "PID" = 1234; "LastExitStatus" = 0; ... }` (not JSON, not tab-separated)
- **PID** — parsed via regex `r'"PID"\s*=\s*(\d+)'`
- **LastExitStatus** — parsed via regex `r'"LastExitStatus"\s*=\s*(-?\d+)'`
- `state` logic:
- `running` — if PID > 0 (process alive right now)
- `scheduled` — if no PID but has StartInterval/StartCalendarInterval
- `idle` — if no PID, no schedule, but enabled (KeepAlive daemon between ticks)
- `stopped` — if disabled (unloaded)
- `last_status`: `None` when process is `running` (exit code is meaningless); integer (exit code) when process is not running; `None` when no LastExitStatus field (never run)
- **Frontend** displays: `· exit <code>` in green for 0, red for non-zero; `· never run` when `last_status` is None (grey text)
**Files changed:** `main.py``_list_launchd_crons()`, `templates/index.html` — cron card status line
## Troubleshooting — sync-vault appeared as "none (manual)"
**Root cause:** Launchd create accepted cron expression `*/5 * * * *` (pre-fix), couldn't parse it into StartInterval, wrote plist without schedule → `_list_launchd_crons()` (pre-fix) filtered it out. Fixed in two ways:
@@ -282,6 +299,7 @@ When a launchd cron is created and `launchctl print gui/<uid>/<label>` shows `la
## History
|- 2026-06-25 (round 10): **Launchd status — PID/exit code from launchctl list.** Added PID parsing (next-format "PID" = N) and LastExitStatus parsing in `_list_launchd_crons()`. `last_status` is None for running processes, integer exit code otherwise. Frontend shows `· exit <code>` or `· never run`. Legacy tab-separated format no longer supported. macOS launchctl returns next-format plist (not JSON) — regex parsing, not json.loads.
|- 2026-06-25 (round 9): **RunAtLoad checkbox for launchd crons.** Added `RunAtLoad` field to launchd plist creation. Backend: `main.py` line 636 changed from `pd["RunAtLoad"] = False` to `pd["RunAtLoad"] = body.get("run_at_load", False)`. Frontend: checkbox "Run on load" in cron modal, shown only for source=launchd via `x-show`; `openAddCron()`, `openCronEdit()`, `saveCronModal()` all wired. Backend `_list_launchd_crons()` returns `run_at_load` for edit modal. **Also fixed:** `_msg` auto-dismiss bug — stale object reference after `fetchCrons()` replaced with `find` in fresh array (both crons and services).
- 2026-06-25 (round 7): **Launchd schedule — source-dependent validation.** `validateSchedule()` now takes `source` param. For `launchd`: only `every Ns/m/h/d` accepted; cron and ISO rejected with explicit message. For Eagle/Whale: all three formats. Hints, placeholders, and `prettySchedule()` also differ by source. `Query` import added to FastAPI.
- 2026-06-25 (round 6): **Tab URL routing.** Each tab now persists in URL via `?tab=` query-param + `history.replaceState()`. Frontend initializes `activeTab` from URL. Backend accepts `?tab=` on `GET /`. Added `setUrlTab()` to Alpine.js data.