Commit Graph

2 Commits

Author SHA1 Message Date
Alan Wizemann 4757b5ae49 feat(curator): archive + prune + list-archived (WS-4)
Catches the Curator surface up to Hermes v0.13's new write-side verbs
(`archive <skill>`, `prune`, `list-archived`, synchronous `run`). Adds
a new `CuratorService` actor in ScarfCore mirroring `KanbanService`'s
pattern (Sendable, pure I/O, `Task.detached(priority: .utility)` per
verb), tolerantly-decoded `HermesCuratorArchivedSkill` /
`CuratorPruneSummary` models, and `CuratorError` for inline-banner
surfacing.

Mac UX gains an "Archived" section between the leaderboards and the
last-report block (per-row Restore button), an "archivebox" button on
every active-skill leaderboard row to manually archive, a destructive
"Prune Archived…" confirm sheet enumerating each skill (template-
uninstall pattern — Cancel owns `.defaultAction`, Prune is on the red
`ScarfDestructiveButton`), and a synchronous-with-progress "Run Now"
on v0.13+ hosts (600s timeout, `ProgressView` while in-flight).
Failure path routes through a yellow inline error banner instead of a
modal alert. The legacy `CuratorRestoreSheet` stays accessible from
the overflow menu but only on pre-v0.13 hosts; on v0.13+ the per-row
Restore in the new Archived section replaces it.

All new surfaces gate on `HermesCapabilities.hasCuratorArchive` —
pre-v0.13 hosts see the v2.7.x layout unchanged. iOS picks up the new
`runNow(synchronous:)` signature with the v0.13 capability flag; the
read-only Archived section + WS-9 marker is left for the next stream.
14 new parser tests in `HermesCuratorParserTests` cover the JSON
happy path, the `{"archived": [...]}` envelope, the text fallback
(`--json` not supported), `"no archived skills"` sentinel folding,
prune-dry-run with both wrapper + bare-array shapes, and zero-skill
prune. All 369 ScarfCore tests pass; `xcodebuild` for the `scarf`
scheme succeeds.

Wire-shape unknowns (CLI flag presence on real v0.13) carry
`// TODO(WS-4-Q<N>)` markers in `CuratorService` and fall back
defensively when a flag isn't recognized. Implements WS-4 of Scarf
v2.8.0 (Hermes v0.13.0 catch-up). Plan:
scarf/docs/v2.8/WS-4-curator-archive-plan.md (on
coordination/v2.8.0-plans).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 19:03:13 +02:00
Alan Wizemann 686fb37630 feat(hermes-v12): Curator feature module on Mac + iOS (Phase D)
Hermes v0.12 ships an autonomous Curator that prunes / consolidates
agent-created skills on a 7-day cycle. This phase brings that surface
into Scarf so users can see status, trigger runs, pin protected skills,
and restore archived ones.

Pipeline:

- HermesCuratorStatus + HermesCuratorSkillRow: Sendable value types for
  parsed status + per-skill leaderboard rows.
- HermesCuratorStatusParser: pure text parser for `hermes curator status`
  stdout (no `--json` flag exists upstream). Tolerates Hermes's
  whitespace-padded leaderboard layout (`activity=  0` with N spaces
  between `=` and the value) by slicing between known key positions
  rather than splitting on whitespace. State-file JSON overrides
  text-parsed values for last_run_at / last_run_summary /
  last_report_path because the file carries full ISO timestamps the
  text output may have rounded.
- CuratorViewModel: @Observable @MainActor, drives the CLI verbs
  (status / run / pause / resume / pin / unpin / restore) via
  transport.runProcess so it works equally over local and Citadel SSH.
- HermesPathSet: adds curatorLogsDir + curatorStateFile (the latter
  is `.curator_state` with no extension despite holding JSON).

Mac:

- Features/Curator/Views/CuratorView.swift — page-header + status card
  + skill counts + pinned chips + 3 leaderboard tables (least recent,
  most active, least active) with inline pin toggles and a
  per-skill counter chip row. "Run Now" button + a kebab menu for
  Pause/Resume + Restore Archived.
- Features/Curator/Views/CuratorRestoreSheet.swift — name-entry sheet
  for `hermes curator restore <skill>`. Free-form text field; Hermes
  doesn't ship a `curator list-archived` yet so we don't synthesize a
  picker.
- Sidebar: AppCoordinator + SidebarView gain a `.curator` case under
  Interact (between Memory and Skills); the row is filtered out by
  SidebarView's capability-aware `sections` computed property when
  `HermesCapabilities.hasCurator` is false. ContentView routes
  `.curator` to CuratorView. Pre-v0.12 hosts see the v0.11 sidebar
  unchanged.

iOS:

- Scarf iOS/Curator/CuratorView.swift — read-mostly List with the same
  status / skill counts / pinned / leaderboards + inline pin toggles.
  Run Now / Pause / Resume actions in the section footer.
- ScarfGoTabRoot's System tab gains a Curator NavigationLink under
  Features, gated on `hasCurator`. Uses a stable
  `systemTabContextID` so the SSH transport pool reuses the cached
  Citadel connection keyed by that id.

Tests: 6 new parser tests (215 total, all green). Locks the empty-state
output captured from a real v0.12.0 install + paused-state + state-file
override + multi-word-name-row parsing. Both Mac and iOS schemes build
clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 12:37:48 +02:00