Files
scarf/scarf/scarf/Navigation/AppCoordinator.swift
T
Alan Wizemann b6d9113579 feat: Settings tabs, Platforms, Credential Pools, Model Picker, and Configure sidebar
Major expansion of Scarf's Hermes platform coverage. Settings is now a 10-tab
layout exposing ~60 previously hidden config fields. A new "Configure" sidebar
section groups per-platform setup, personality management, quick commands,
credential pools, plugins, webhooks, and profile switching.

## Highlights

- **Platforms feature** — Native GUI setup for all 13 messaging platforms
  (Telegram, Discord, Slack, WhatsApp, Signal, Email, Matrix, Mattermost,
  Feishu, iMessage, Home Assistant, Webhook, CLI). Per-platform forms write
  credentials to ~/.hermes/.env and behavior toggles to ~/.hermes/config.yaml.
  WhatsApp and Signal use an inline SwiftTerm terminal for QR/link pairing.

- **Credential Pools** — Provider-aware add/remove with proper type handling.
  OAuth flow uses Process + pipes to extract the authorization URL, open the
  browser explicitly, and accept the code via a form field. Fixes the Anthropic
  OAuth failure where the code had nowhere to be entered.

- **Model Picker** — Hierarchical provider -> model picker backed by
  ~/.hermes/models_dev_cache.json (111 providers, every major model). Used in
  Settings -> General and Delegation. "Custom..." escape hatch for unlisted IDs.

- **Settings as tabs** — 10 tabs (General, Display, Agent, Terminal, Browser,
  Voice, Memory, Aux Models, Security, Advanced). HermesConfig grew from 32 to
  ~90 fields via grouped sub-structs. All new fields round-trip through
  `hermes config set`.

- **Extended existing features** — Cron (create/edit/pause/resume/run-now/
  delete), Skills (Browse Hub + Updates tabs), Health (run `hermes dump` and
  `hermes debug share` with confirmation dialog), Sessions (rename/delete/
  export/export-all).

## Bug fixes

- Tools platform picker showed only CLI (was reading a nonexistent
  `platform_toolsets:` YAML section). Now enumerates KnownPlatforms.all with
  live connectivity dots from gateway_state.json.
- Credentials add with --api-key was triggering OAuth for providers like
  Anthropic because --type was missing. Now always passes --type api-key.
- Remove-by-index used 0-based indexing; hermes CLI expects 1-based. Fixed.
- Various CLI parser fragility issues (plugins, profiles, skills hub, webhooks)
  replaced with structured file reads or proper box-drawn table parsers.

## New core services

- HermesEnvService — reads/writes ~/.hermes/.env atomically, preserves
  comments, commented-out keys get enabled in-place on save, values with
  spaces/specials get quoted, unset commented out (non-destructive).
- ModelCatalogService — decodes the models.dev cache into typed providers and
  models with context/cost/release-date metadata.
- OAuthFlowController — manages the OAuth Process subprocess: extracts the
  auth URL via regex, opens the browser, pipes the code back via stdin,
  detects success/failure markers in output.

## New sidebar structure

Monitor / Projects / Interact / **Configure (new)** / Manage

The Configure section gathers the setup-style features that used to require
the CLI: Platforms, Personalities, Quick Commands, Credential Pools, Plugins,
Webhooks, Profiles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-16 15:39:07 -07:00

68 lines
2.2 KiB
Swift

import Foundation
enum SidebarSection: String, CaseIterable, Identifiable {
// Monitor
case dashboard = "Dashboard"
case insights = "Insights"
case sessions = "Sessions"
case activity = "Activity"
// Projects
case projects = "Projects"
// Interact
case chat = "Chat"
case memory = "Memory"
case skills = "Skills"
// Configure (Phase 2/3 additions)
case platforms = "Platforms"
case personalities = "Personalities"
case quickCommands = "Quick Commands"
case credentialPools = "Credential Pools"
case plugins = "Plugins"
case webhooks = "Webhooks"
case profiles = "Profiles"
// Manage
case tools = "Tools"
case mcpServers = "MCP Servers"
case gateway = "Gateway"
case cron = "Cron"
case health = "Health"
case logs = "Logs"
case settings = "Settings"
var id: String { rawValue }
var icon: String {
switch self {
case .dashboard: return "gauge.with.dots.needle.33percent"
case .insights: return "chart.bar"
case .sessions: return "bubble.left.and.bubble.right"
case .activity: return "bolt.horizontal"
case .projects: return "square.grid.2x2"
case .chat: return "text.bubble"
case .memory: return "brain"
case .skills: return "lightbulb"
case .platforms: return "dot.radiowaves.left.and.right"
case .personalities: return "theatermasks"
case .quickCommands: return "command.square"
case .credentialPools: return "key.horizontal"
case .plugins: return "app.badge.checkmark"
case .webhooks: return "arrow.up.right.square"
case .profiles: return "person.2.crop.square.stack"
case .tools: return "wrench.and.screwdriver"
case .mcpServers: return "puzzlepiece.extension"
case .gateway: return "antenna.radiowaves.left.and.right"
case .cron: return "clock.arrow.2.circlepath"
case .health: return "stethoscope"
case .logs: return "doc.text"
case .settings: return "gearshape"
}
}
}
@Observable
final class AppCoordinator {
var selectedSection: SidebarSection = .dashboard
var selectedSessionId: String?
var selectedProjectName: String?
}