feat(LUKE-55): observe Conductor cloud sessions via a settings-managed API key

Merged
DA
2mo ago
+2636-37

Summary

  • Add ConductorSessionAdapter, Luke's first cloud provider: it walks the public Conductor API (/me → projects → workspaces → sessions → session status) with GET requests only and feeds each session into the existing observation pipeline. Sessions are labeled by repository (Conductor: luke), following the Codex adapter's precedent that prompt-derived text never reaches an observation. Observation is scoped to workspaces whose creatorId matches the authenticated user.
  • Add a Settings view in the expanded panel and a SettingsStore: the Conductor API key is user-specific, so it belongs in the app rather than the environment. It is encrypted at rest via Electron safeStorage (Keychain-derived) into a mode-0600 settings.json, with CONDUCTOR_API_KEY as an env fallback. The renderer can set or clear the key but never reads it back — it only learns where a key came from.
  • Session recency is judged from each session's own status updatedAt, not the workspace's lastActivityAt (which masks per-session recency behind a running sibling), and a working status is trusted as live server state instead of aging out to unknown mid-turn. Both were caught against live data.
  • Provider refreshes now run concurrently with per-adapter error isolation, so a stalled network provider can't hold the refresh lock and stop Claude Code/Codex from being observed.
  • Under --fixture, the Conductor adapter is excluded from the adapter list entirely, keeping fixture runs deterministic and credential-free.

Evidence

  • Platform-independent checks: ./scripts/check.sh green — 59 desktop, 31 core, 5 harness tests. Adapter tests cover status mapping, both timestamp bugs above, credential rejection clearing state, transient failures preserving the last snapshot, GET-only enforcement, and that prompt text never reaches an observation. Settings-store tests cover encryption at rest, file mode, decrypt caching, and that no accessor leaks the key.
  • macOS Electron verification (./scripts/verify.sh): not run in this (Linux) workspace — covered by CI's macOS job.
  • Live-data probe: 25 requests (all GET), 12 observations — 1 working, 3 waiting, 8 observed.

Automated visual evidence

Download the deterministic macOS evidence · workflow run

  • Commit: 53af8a4f00f52d8b3b52afddfa816f6b0104de12
  • Scenario: smoke
  • Physical-notch check: not performed by CI

Physical-device evidence

  • Screenshot or screen recording: not attached (the capture pipeline has no way to open the Settings view; a --profile settings capture flag is a possible follow-up)
  • Physical-notch check: manually verified by @dastratakos on device — Settings reachable via notch hover → footer, key entry works (panel focus steal), rows appear on save, notch capsule stays put
  • Device/display configuration: not recorded
  • On-disk check: settings.json confirmed mode 600, key present only as base64 ciphertext, no plaintext match

Notes

  • Dev runs (@luke/desktop) and the packaged app (Luke) derive different userData directories, so a key saved via run.sh won't be visible to a packaged build. Pre-existing Electron behavior; app.setName("Luke") would unify them but relocates existing state, so it's left for a separate decision (and run.sh's lock-holder lookup would need updating in the same commit).
  • Follow-up worth a ticket: cache the projects/workspaces layers with a minutes-long TTL — a full re-crawl every 15s is ~25 requests to keep 12 rows current, and only the per-session status changes on that timescale.
  • Follow-up worth a ticket: positiveInteger/nonNegativeNumber and the filesystem-error helpers now exist in several copies across adapters; hoisting them into sidecar-core touches files outside this PR's scope.

🤖 Generated with Claude Code


Open workspace in Conductor