Commit Graph
4 Commits
Author SHA1 Message Date
amosblomqvist bd66b31853 Keys section (auth/provider-keys wave): BYOK keys in the settings dialog
Owner-approved design (2026-09-20): a Keys section right after General,
two groups over the merged auth API (GET /api/keys masked statuses,
PUT/DELETE /api/keys/:id, immediate effect, shape-gated 400s):

- Model providers: OpenRouter pinned as an always-visible row (the
  app's lifeline — synthesized when absent so first boot shows it),
  stored provider keys render as they appear, and an Add-provider
  dropdown lists every pi-ai provider that takes an API key. The
  dropdown reads GET /api/keys' optional providers array — the
  Platform interlude (master-routed) derives it from pi-ai's own
  env-key table; until it lands the group shows a pending note
  (rolePins pattern — absent field, no drift, no guessed routes).
- Tools & services: the curated rows — Deepgram (dictation) and the
  Google pair (search key + CSE ID) — with description hints and docs
  links (external links route through the Electron shell to the real
  browser).
- Rows: always-visible paste inputs (owner choice; no reveal —
  plaintext never returns from the store), masked status line
  (…tail · chars · environment|saved), the shadowedByEnv explanation
  when a real env var owns the name, per-row inline 400 messages, Save
  on Enter/button, Delete when present (env-owned keys honestly keep
  their env status after a file delete).
- Unknown auth.json vars surface as read-only dimmed rows — preserved
  by the store, not editable through the curated surface.

classifyKeys/keyStatusLine pure exports drive the two-group
projection; tests: SSR loading state, first-boot synthesis, provider
row classification, addable filtering, unknown-var read-only status
line formatting. Nav grows to six sections (Keys second).

Live-verified: nav order, structure, bad-paste 400s inline, save
round-trip with env-shadow explanation, delete round-trip, env-owned
OpenRouter status stability. Gates: typecheck, lint, 748/748, build.
2026-09-19 22:53:15 +03:00
amosblomqvist fddbacd330 Settings-app refinement round 3 (owner review): toggle polish, nav spacing, portal dropdowns, Default-named hints
- Toggle (owner bug report): the ON disc sat flush against the pill's
  right edge — translate-x-4.5 left only a 1px sliver; now translate-x-4
  for a 2px inner inset both states (off: 3px left inset; on: 3px right
  inset — measured live, symmetric).
- Toggle colors (owner ask): ON is a gray track (muted-foreground) with
  a WHITE disc (foreground) — the full-white track was too loud; OFF
  stays the muted track with the gray disc.
- Nav spacing (owner ask): gap-1 between the section nav buttons so the
  hover highlights no longer touch.
- Role dropdowns (owner ask): the menus were clipped by the dialog's
  overflow frame — they now portal to document.body with fixed
  positioning against their trigger (AnchoredMenu), right-aligned,
  repositioned on scroll/resize, so they flow over the whole screen
  outside the settings dialog. Verified: a bottom-row menu extends
  137px past the dialog's bottom edge; search + pick + Default-clear
  work through the portal; Esc and inside-dialog clicks close the menu
  but not the dialog.
- Thinking trigger (owner ask): fixed w-20 — the width the Default
  state needs — so picking levels no longer shifts the row; the model
  trigger takes the same width as a minimum (its values vary in length).
- Role hints (owner ask): ALWAYS visible and naming the actual default —
  'Default: <model>'. The resolved per-role pins are not client-side
  yet: master routed rolePins to the Platform stream (GET /api/models
  extension, standalone commit); until that merge the rows read the
  'config pin' fallback and light up on rebase. rolePins also lets the
  thinking list use the pinned model's real supportedLevels when it's
  in the catalog.

Also: staging repair commit 270db53 — the round-1 dialog rewiring
(sidebar row, chord, redirect, keyframes) was listed in 27d4f33's
message but never staged; committed as catch-up.

Live-verified on the worktree dev server. Gates: typecheck, lint,
701/701.
2026-09-19 22:29:17 +03:00
amosblomqvist fd63e4a575 Settings-app refinement round 2 (owner review): toggle fix, shared model dropdown, groups, graph-view graying, pruned hints
- Toggle knob (bug report): the knob span had no left anchor, so it sat
  at its inline static position — right-edge in off, overflowing in on.
  Now left-0 + the intended 2px/18px translate; verified live: 3px from
  left when off, 1px right inset both states.
- Role model/thinking dropdowns (owner ask): the EXACT chat model
  selector dropdown, not a lookalike — the fuzzy-search + arrow-walk +
  Enter machine moved from model-picker.tsx into the shared
  components/settings/model-menu.tsx (ModelMenuList/ThinkingMenuList),
  ModelControl now renders the same bodies, and the agent roles open
  them downward with a pinned Default row (clears the override). The
  collapsed trigger keeps the thin select look (owner: 'the collapsed
  look is good'). Esc claims and closes only the menu (the dialog
  stays); a backdrop click is left to the dialog's own close.
- Sub-groups (owner ask): SettingsGroup — Models / Tools / System
  prompts inside Agent, each with a separator + quiet label; section
  headings more pronounced (text-sm, full-foreground).
- Graying (owner ask): graph-view render-panel convention — the WHOLE
  row dims (opacity-40) and the control locks; the row owns the dim so
  no double-opacity. Applied to the graph ladder, the mode row, and
  prompt rows without an override file. The 'needs X on' prose is gone.
- Hints pruned (owner ask): mechanics-explaining lines removed — the
  ladder mention, 'App-level behavior', 'Applied live as CSS
  variables', per-row explanations. Only the keyboard storage note
  stays, reworded 'Stored on this device' (desktop app — localStorage
  is the Chromium profile in Application Support, not 'this browser').

Live-verified: knob geometry both states + PUT round-trip, menu
search/pick/clear through the record, thinking set/clear, Esc layering,
ladder dim 0.4 with siblings full, pruned phrases absent. Gates:
typecheck, lint, 701/701.
2026-09-19 22:29:17 +03:00
amosblomqvist 5e21561997 Settings-dialog round 1b: un-double the section inset
The dialog's content wrapper added px-6 py-5 ON TOP of SettingsSection's
own padding (48px horizontal, 81px top — measured live). The wrapper is
now bare; the section component owns its rhythm, and the loading/error
states carry their own padding. Section box now spans the scroll column
(61px from the dialog top = the 60px header band), text inset 24px.

Gates: typecheck, lint, 701/701.
2026-09-19 22:29:17 +03:00