Skip to content

Add SPS Content Studio loop#694

Open
saxster wants to merge 399 commits into
fathah:mainfrom
saxster:codex/content-studio
Open

Add SPS Content Studio loop#694
saxster wants to merge 399 commits into
fathah:mainfrom
saxster:codex/content-studio

Conversation

@saxster

@saxster saxster commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add markdown row-backed Content Studio objects, host pages, persistence helpers, and claim-level quality gates.
  • Wire assistant draft variants, publish packets, analytics rows, weekly learning proposals, and capture actions from SPS research/source surfaces.
  • Extend SPS smoke coverage through the Content Studio low-score, run creation, and analytics flow.

Test Plan

  • npm test -- src/shared/content-studio.test.ts src/renderer/src/screens/SpsAgent/content/ContentStudioSurface.test.tsx src/renderer/src/screens/SpsAgent/research/SourceIntakePanel.test.tsx tests/assistant-recipes.test.ts
  • npx eslint src/shared/content-studio.ts src/shared/content-studio.test.ts src/renderer/src/screens/SpsAgent/content/ContentStudioSurface.tsx src/renderer/src/screens/SpsAgent/content/ContentStudioSurface.test.tsx src/renderer/src/screens/SpsAgent/content/contentStudioStorage.ts src/renderer/src/screens/SpsAgent/research/SourceIntakePanel.tsx src/renderer/src/screens/SpsAgent/research/SourceIntakePanel.test.tsx src/renderer/src/screens/SpsAgent/research/RssReaderDashboard.tsx src/renderer/src/screens/SpsAgent/research/SubstackRadarPanel.tsx src/renderer/src/screens/SpsAgent/components/CommandPalette.tsx src/renderer/src/screens/SpsAgent/modals/ResearchModal.tsx
  • npm run typecheck
  • npm run build
  • npm run verify:note-index
  • node scripts/sps-smoke.mjs

saxster and others added 30 commits June 6, 2026 17:09
The assistant panel now holds multiple conversations as tabs, so several agent
runs proceed at once — one planning, one working, one researching. Builds directly
on the clientRunId correlation: each streaming run already isolates on the wire,
and this isolates them in the UI.

- store: assistant slice goes from a single messages[]/thinking to
  conversations[] + activeConvId. Async flows (runAgent/runWork) CAPTURE their
  conversation id at start and write only to it, so switching tabs mid-run never
  lands tokens in the wrong tab. Proposal/db decisions search across all
  conversations (message ids are globally unique). Conversations auto-title from
  the first prompt. Always keeps ≥1 tab.
- AgentBody: renders the active conversation + a tab strip (switch, close, +new,
  per-tab running indicator).
- verify-agentic-ui.mjs: +2 assertions (tab strip present, +adds a tab) → 11/11.

Gates: typecheck (both), eslint, full vitest (1303), verify:note-index, build,
live UI smoke 11/11 — all green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…meout headroom

Root cause: Skills.tsx renders only a spinner while `loading` is true and mounts
the header buttons (New skill / Generate from repo) and tabs only after the
initial list IPC calls *resolve* (loadAll → setLoading(false)). Four tests waited
for the IPC call to have been *made* (waitFor(expect(api.X).toHaveBeenCalled()))
and then did a one-shot getByText/querySelector on those post-load elements,
racing the loading→loaded flip. Failed ~1/5 even idle, more under load.

Fix: wait for the rendered DOM instead of the IPC call —
- header buttons: `await view.findByText(...)` (retries until present), called
  OUTSIDE act() (nesting findBy's internal act inside an outer act stalls the
  effect flush — that mistake made loading appear stuck);
- Browse tab: a `findBrowseTab` helper that waitFor's the rendered `.skills-tab`.

Also bumped vitest testTimeout/hookTimeout to 15s so timing-sensitive RTL tests
don't fail purely from CPU starvation when the suite runs alongside other
worktrees/builds on the same machine. No production code changed.

Verified: typecheck ✓, lint 0/0, 10/10 consecutive full parallel runs green
(1343 passed, 3 skipped).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
# Conflicts:
#	src/main/index.ts
#	src/main/skills.ts
#	src/main/sps-agent.ts
#	src/preload/index.d.ts
#	src/preload/index.ts
#	src/renderer/src/screens/Skills/Skills.tsx
#	src/renderer/src/screens/SpsAgent/assistant/AgentBody.tsx
#	src/renderer/src/screens/SpsAgent/components/iconPaths.ts
#	src/renderer/src/screens/SpsAgent/types.ts
Bring personalization out of the admin overlay and into the SPS workspace,
and add a structured "How I like things" rules list on top of existing storage.

Why: the highest-value personalization capabilities (focus.md daily-context
hook, USER.md persona/guardrails, MEMORY.md durable facts) already shipped, but
lived only in the admin overlay (gear/⌘,) where normal users never find them,
and USER.md guardrails were one free-form blob with no per-item control.

- New SPS "You" surface (rail nav + Surface union) mounts focus/persona/durable
  facts/daily-context-hook where users actually work.
- Structured rules: each rule is a plain-English line with an on/off toggle +
  delete + one-click starter templates. Persisted as a managed `## Rules`
  section inside USER.md (disabled rules wrapped in HTML comments so the agent
  never sees them) — NO new IPC/backend; reuses writeUserProfile.
- YouSurface is the single owner of USER.md while open, so persona prose and the
  rules list share one in-memory state + serializer and can't clobber each other.
  Over-budget saves are refused so the 2200-char window is never truncated.
- Extract EditorSection/hookStatusText into Personalization/parts.tsx (shared by
  the admin screen and the new surface; no behavior change for the overlay).
- Pure userMd parse/serialize helper with unit tests; probe-you-surface.mjs
  proves the surface renders and a rule round-trips to USER.md on disk.

Verified: typecheck (both), eslint (touched), vitest (1379 pass incl preload
parity + new userMd tests), npm run build, sps-smoke (13 shots), probe.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… Recents menu, remove dead affordances

Brings every interactive control on the SPS workspace surface to "functional
or removed". Reported issues plus a full dead-control sweep.

- Assistant/Comments top-bar buttons are now tab-aware toggles (close only when
  their tab is active), fixing the intermittent "click does nothing" caused by a
  blind panelOpen toggle.
- Recents chats get right-click + hover-⋯ Rename/Delete, wired to the existing
  hermesAPI updateSessionTitle/deleteSession; deleting the active chat redirects.
- Composer: remove dead file/mention placeholder icons; grounding toggle now
  flashes a confirmation toast; taller input box (min-height 60px, grows to 200).
- Remove the no-op top-bar Share button and the hardcoded TK/PS/SD presence
  avatars (no sharing/presence backend); delete Presence.tsx + its dead CSS.
- Remove orphaned TaskDrawer Share/⋯ buttons.
- "Copy link" (page) and "Copy link to block" now copy a resolvable [[wikilink]]
  to the clipboard with a toast, instead of being no-ops.
- Wire onOpenDiagnose: SPS chat surfaces dispatch a hermes:open-settings event;
  Layout listens and opens Settings.

Mic dictation intentionally left unchanged.

Verified: typecheck (both projects), lint (clean on touched files), vitest
(1370 passed), build, and the sps-smoke harness (13/13).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…it used

Two coupled changes: (1) make the in-workspace SPS co-author actually apply the
enabled USER.md `## Rules` the user builds in the "You" surface, and (2) surface
a dismissable chip on assistant replies showing what the reply was grounded in.

Why: the co-author (assembleVaultContext → spsAssistant) injected vault notes +
MEMORY.md but NOT the USER.md rules, so rules built in "You" had no effect on the
in-workspace assistant. A trust chip claiming "used your rules" would have lied;
fixing the injection makes it honest AND closes the real gap.

- src/shared/userMd.ts: relocated the pure rules parser from the renderer so the
  main process can reuse it (parseUserMd now drives both the UI and grounding).
- sps-context.ts: VaultContextInput gains `rules`; formatVaultContext emits a
  leading "standing rules — follow these" directive section; assembleVaultContext
  reads enabled rules from USER.md and now returns { text, used } where `used` is
  a {notes,memory,rules} count (new pure `vaultUsage`, unit-tested).
- sps-agent.ts: AssistantResult carries optional `context`; spsAssistant attaches
  the usage summary when anything was injected.
- Renderer: AssistantResult/AgentMessage gain `context`; BridgeAssistant re-attaches
  it after validateResult rebuilds the object; runAgent threads it onto bot msgs;
  AgentBody renders a dismissable "✦ Used your 2 rules · 1 memory item · 3 notes"
  chip (pure contextChipLabel, unit-tested) with sps-scoped CSS.

Verified: typecheck (both), eslint (touched), vitest 1386 pass (incl preload
parity + new userMd/contextChip/sps-context tests), build, verify:note-index,
sps-smoke (13 shots).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Document in runWork that the streaming sendMessage agent path applies grounding
server-side, so the desktop has no honest notes/memory/rules count to show — a
chip there would be fabricated. Prevents a future 'fix' that adds a fake count.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the two renderer brand assets (icon.png, hermes.png) and the
packaged-build icons (resources/icon.png, build/icon.png, build/icon.icns)
with the SUKHI shield badge. Pure asset swap — every logo reference is
already abstracted behind these files, so no JSX/logic changes.

- icon.png upscaled to 1024 from the 256px source badge
- hermes.png wordmark slot now shows the square badge (height 30)
- build/icon.ico left as-is (no ImageMagick to regenerate cleanly)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…panel shut

The Outline/Comments/Assistant controls felt unreliable ('lots of clicking')
because two systems fought each other: the top-bar buttons TOGGLED the panel
closed when clicked on their already-active tab, while the panel tabs only
SELECTED. Same button sometimes opened, sometimes closed.

- Top-bar Comments/Assistant buttons now always open+select their tab; closing
  the panel is the dedicated X button's / ⌘J's job only.
- Right-panel tabs route through openPanelTab so a click always keeps the panel
  open and selects (defensive).
- Persist the active right tab (localStorage) so Outline/Comments/Info survive a
  reload instead of snapping back to Assistant.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add a visible 'Hide sidebar' collapse handle in the rail header. The collapse
  capability already existed (data-rail=hidden) but had no discoverable trigger;
  the only way back was a top-bar button after the fact.
- Remove the Inbox nav item: it showed a hardcoded '3' unread badge but just
  opened the Search palette — a label that lied about both its count and action.
- Remove the three 'Coming soon' disabled filter chips (Created by / In / Filter)
  from the command palette; keep the working 'Title only' chip.
- De-seed single-user identity: demo fallback user 'Maya Rao' -> 'You', and the
  apps section label 'Notion apps' -> 'Apps' (this isn't Notion).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The app shipped as a fake team demo ("Team Home", "4 contributors", Maya/Theo/
Priya/Sam, a seeded Theo K comment, "Hi Maya" greeting), which made a one-person
app feel like someone else's workspace.

- Rewrite the Home doc + page tree as a personal agent cockpit (Home, Projects,
  Reading list) with onboarding-flavored to-dos instead of a product-team sprint.
- PEOPLE table -> single built-in person "You" (PersonKey stays a free string, so
  assignees/@mentions can still grow); reassign all sample tasks to "you".
- Assistant greeting drops "Hi Maya"; mock canned responses no longer reference a
  fictional team/release.
- DocHeader drops the hardcoded "4 contributors"; InfoPane owner -> You, team-only
  Contributors section removed; reply author -> You; ship zero seed comments.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comments was team-collaboration framing (threads you resolve, replies from other
people) in a one-person app. Reframe the surface as private margin notes you pin
to text — same anchored-thread data model, single-user language:

- Right-panel tab + top-bar title: Comments -> Notes
- Empty state: 'pin a private note. Your assistant can read these.'
- Thread input placeholder Reply… -> Add a note…; Resolve/Re-open -> Archive/Restore
- Selection toolbar button title Comment -> Add note

Internal data-model name stays 'comments' (persisted tab value, block wiring,
tests) — only user-facing strings change. Phase 2b wires these notes into the
assistant's context so the agent can actually read/act on them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Completes the Comments->Notes repurpose: private annotations you pin to text are
now fed to the agent as authoritative intent, so it can act on them.

- PageContext gains optional notes[]; runAgent gathers the current page's
  unarchived annotations (quote + body) and passes them through.
- spsAssistant IPC payload carries notes (preload .ts + .d.ts in parity); main's
  buildSpsAssistantMessages injects a 'Your notes on this page' section into the
  user turn (omitted when empty), placed after page content and before the request.
- Pinned-note count folds into the trust chip's existing 'notes' tally, so the
  'what it used' chip reflects them honestly.
- Tests: notes injected when present, section omitted when empty.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 11 built-in templates were hardcoded; you couldn't make your own. Now you can
save any page's structure as a reusable template.

- New templates store slice (localStorage 'sps-agent-templates-v1', mirroring the
  tweaks/sidebar convenience-persistence pattern): saveAsTemplate snapshots a
  page's blocks + icon/title; removeUserTemplate drops one.
- PageMenu ('…') gains 'Save as template'.
- TemplatesModal shows a 'Your templates' section above the built-ins; each card
  instantiates with FRESH block ids (so two pages from one template never share
  block identity) and has a hover-reveal delete button.
- Templates are a UI recipe layer, not workspace data — the PAGES they create are
  still markdown-on-disk. Tests cover round-trip, malformed-entry filtering,
  snapshot, empty-page guard, and removal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Callouts and toggles already existed and are in the slash menu; the missing
layout primitive was columns. Adds a 2–3 column block so you can build your own
side-by-side visual setups (pros/cons, before/after, note + checklist).

- New 'columns' block type with a columns[] field (HTML per column). It is NOT
  in the serializer's cleanTypes, so it round-trips losslessly through the
  existing Tier-2 <!-- sps:… --> meta comment — ZERO serializer changes, proven
  by a new golden round-trip test.
- ColumnsBlock renders independent contentEditable columns using Editable's
  cursor-safe seed-once pattern; sanitises on display, plain-text paste only;
  hover controls to add (max 3) / remove (min 1) a column.
- Slash menu gains 'Columns'; insert seeds two empty columns.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A new 'Cockpit' surface (sidebar, below Home): an at-a-glance dashboard you build
yourself. Delivers the 'build my own visual setup' ask without a heavy dependency
— a CSS grid + HTML5 drag, no react-grid-layout.

- New cockpit store slice (localStorage 'sps-agent-cockpit-v1', matching the
  tweaks/sidebar/templates convenience-persistence pattern rather than the
  workspace.json substrate): ordered widgets, each 1× or 2× wide; reorder, resize,
  add, remove, reset.
- Five widgets, all reading live store state: Quick actions, At a glance (page/
  note/template counts), Pinned notes (jump to the annotated page), Jump to a page,
  and Ask your assistant (starts a grounded chat).
- Drag a card to rearrange, toggle 1×/2× width, remove, or add from the catalog.
- Tests: reorder, span, add/remove, persistence round-trip + malformed-input
  hardening (unknown kind dropped, span clamped).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
At large window sizes the right panel floated with a dead band to its right and
its close button was clipped off-screen (and sat under the floating admin gear),
so the panel couldn't be reliably turned off.

- .main now flex:1 so it grows and the panel sits flush against the window's
  right edge — verified at 1900px: panel.right === window width, zero gap (was a
  wasted band before).
- Replace the clipped in-panel close X with a dedicated panel toggle in the topbar
  (panelRight icon, highlighted when open) — one clear on/off control. Verified it
  hides and reopens the panel.
- Reserve topbar right-padding when the panel is closed so its controls clear the
  floating admin gear (a pre-existing collision).
- Tighten rp-tab padding (11px→8px) so the four tabs never overflow the panel.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e float

Topbar had three panel controls (Notes button, Assistant button, toggle) plus the
panel's own tabs, and 'Assistant' was labelled twice (topbar button + panel tab).
The Settings gear floated fixed over the top-right corner, overlapping the panel,
and duplicated the sidebar-foot Tweaks gear.

- Topbar: drop the Notes and Assistant buttons; keep one icon-only panel toggle.
  'Assistant' now appears once (the panel tab). Panel controls: 3 -> 1.
- Relocate settings into the sidebar 'More' section as labelled nav items —
  'Appearance' (was the foot gear → Tweaks) and 'Settings' (Hermes admin). Remove
  the floating .sps-admin-gear button and the redundant foot gear.
- Wire the parent to listen for the 'hermes:open-settings' event (previously
  dispatched by SPS but unhandled — a dead dispatch); ⌘, still toggles admin.

Verified at 1900px: no floating gear, topbar has 2 buttons, single panel toggle,
sidebar More = Trash/Appearance/Settings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Three new cockpit widgets, all reading live data with graceful offline fallbacks:
- Recent chats: hermesAPI.listSessions → click opens the chat surface on that
  session (empty state offers to start one).
- Today: weekday + date, with a button to open today's journal entry.
- Agent status: the active Hermes profile (name · model · running/stopped) with a
  status dot; click → Agent Console. Offline → 'Set one up' opens settings.

Added to the widget catalog and the default cockpit layout; existing layouts get
them via 'Add widget'. cockpit slice ALL_KINDS extended (validates persisted
layouts against the new kinds).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Each column is now its own block list (headings, lists, todos, quotes, code,
dividers) instead of a single rich-text region. block.columns becomes Block[][].

- New ColumnEditor (in ColumnsBlock) reuses BlockInner for rendering and the page
  editor's keyboard grammar (Enter carries list/todo type, Backspace de-indents
  then unwraps then merges, Tab indents) plus markdown shortcuts via detectMarkdown
  ('- ', '# ', '[] ', '> ', '```', '--- '). No slash menu, so a column can't nest
  another columns/database/media block — no recursion.
- Each column always keeps >=1 block; normalizeColumns tolerates the legacy
  string[] shape (migrates a rich-text column to one paragraph).
- Still serializes losslessly via the generic Tier-2 path (NOT in cleanTypes);
  golden test updated to a nested-block columns block and passes.

Verified at 1500px (real Electron): 2 columns render an h3 + bullets beside an h3
+ checked/unchecked todos. Full gate green (typecheck, lint, 1396 tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The floating admin gear button was removed when settings moved into the sidebar
'More' section; its CSS was left behind. Sweep the now-unused rules (the
.sps-admin-overlay it opened stays).
On macOS the renderer paints a .drag-region (position:fixed, top:0, height:28px,
z-index:1000) so the frameless window can be dragged. The SPS topbar sits in that
strip, so its controls (the panel toggle, page menu, breadcrumbs) fell UNDER the
drag layer and clicks hit the drag-region instead of the button — the panel toggle
'did not work'.

Fix: lift .topbar above the drag layer (position:relative; z-index:1001), make the
topbar's own empty space the window-drag handle (-webkit-app-region: drag), and opt
the interactive children (button/.seg/.crumb) back out with no-drag.

Verified in real Electron at 1500px: elementFromPoint over the toggle is now the
button, and a real hit-tested click closes AND reopens the panel (previously the
click timed out — only a synthetic JS click worked, which had masked the bug).
Same drag-region trap as the topbar (fixed in 84ffe3e): the panel tab row (.rp-tabs:
Assistant/Outline/Notes/Info) sits in the top 28px window-drag strip (.drag-region,
fixed, z-index 1000), so clicks on the tabs hit the drag layer instead.

Fix: lift .rp-tabs above the drag layer (position:relative; z-index:1001), keep its
empty space a window-drag handle (-webkit-app-region: drag), and opt the tab buttons
back out (no-drag).

Found via a full-surface click audit (elementFromPoint over every interactive
control on every surface). Verified in real Electron: rp-tab is the top element and a
real click on 'Outline' switches the active tab. (The sidebar Appearance/Settings
items sit below the scroll fold on short windows but ARE reachable by scrolling —
clickable, not covered — so left as-is.)
Settings sat at the bottom of the scrollable nav, below the fold on short windows.
Move it to a gear pinned in the rail foot (next to the profile), always visible
without scrolling. Removed the duplicate Settings item from the 'More' section;
Appearance stays there. Foot is below the macOS drag strip, so no app-region issue.

Verified in real Electron: foot gear is clickable and a real click opens the Hermes
admin overlay; Settings no longer appears in the scrollable nav.
…hidden

When the sidebar is collapsed, the topbar reaches the window's left edge — where the
macOS traffic-light buttons sit (trafficLightPosition x:16). The breadcrumb + show-
sidebar control rendered underneath them. Inset the topbar by 78px on mac when
data-rail=hidden so they clear the lights (mirrors the existing rail-top margin-top
clearance for the visible-sidebar case).

Verified in real Electron (sidebar hidden): topbar padding-left 78px, show-sidebar
button at x:78 and breadcrumb at x:113 — both clear of the x:16-70 light zone.
The Settings overlay mounts the legacy Hermes Layout, whose sidebar still listed
'SPS Agent' and 'Chat' workspace views (WORKSPACE_NAV_ITEMS). Clicking 'SPS Agent'
there rendered a SECOND full copy of the SPS app inside the overlay, beside a nav
that duplicated the SPS sidebar (Insights, Memory, Chat, …). Since SPS replaced the
Layout as the main app, those workspace entries are pure redundancy.

Remove WORKSPACE_NAV_ITEMS (SPS Agent / Chat) and the spsAgent content pane so the
overlay is a focused admin panel (Agent Control Center: Sessions/Profiles/Office/
Kanban/Insights/Models/Providers/Skills/Memory/Personalization/Tools/Schedules/
Gateway/Settings). Drop the now-unused SpsAgent/Sparkles/ChatBubble imports.

Verified in real Electron: opening Settings shows only admin nav (no SPS Agent/Chat
item) and exactly one SPS rail in the DOM (no embedded second app).
- Rename the Hermes admin-overlay 'Insights'/'Memory' to 'Agent Insights'/'Agent
  Memory' so they no longer read as duplicates of the SPS workspace's own Insights/
  Memory surfaces (different layer, same words).
- Pin Appearance to the sidebar foot next to Settings (both always visible, no
  scrolling); remove it from the scrollable 'More' section (now just Trash).

Verified in real Electron: foot has Appearance+Settings gears (Appearance gone from
the nav, clickable), admin overlay shows Agent Insights/Agent Memory (plain labels
gone). Also smoke-audited all 14 admin screens — every one mounts and renders with
no console/page errors.
Dark mode gets a 'Dark palette' picker (Appearance): Black, Warm, Terminal.

- Black (NEW DEFAULT): near-black #0a0a0a bg + off-white #e8e8e8 text, tuned
  off-pure to avoid white-on-black halation while keeping subtle elevation
  (surface #161616) so cards/panels/hover don't flatten.
- Warm: the original gold-tinted dark (unchanged base [data-theme=dark]).
- Terminal: shares the black palette but paints the DOCUMENT text terminal-green
  (#3fb950 body, #4ade80 headings); chrome (sidebar/menus) stays neutral so the
  app stays scannable. Accent stays gold across all three.

Implemented as a data-skin variant layer over [data-theme=dark] — pure attribute
swap, no JS color math; mirrored to documentElement like data-theme. darkSkin added
to Tweaks (default 'black'); existing persisted tweaks merge to the black default.

Verified in real Electron: default loads data-skin=black (rail bg #0a0a0a); terminal
gives green doc text + neutral chrome (#a6a6a6); picker shows only in dark mode.
Copilot AI review requested due to automatic review settings June 16, 2026 17:10

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review this pull request because it exceeds the maximum number of files (300). Try reducing the number of changed files and requesting a review from Copilot again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants