fix: remove .gsd/ from tracking, ignore entire directory
.gsd/ contains per-worktree project state (milestones, db, decisions) that should never be committed. Auto-commits were leaking these files into the repo, causing the no-gsd-dir CI check to fail. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
2d974dfb59
commit
f28feaed36
13 changed files with 2 additions and 1027 deletions
18
.gitignore
vendored
18
.gitignore
vendored
|
|
@ -52,22 +52,8 @@ TODOS.md
|
|||
.audits/
|
||||
docs/coherence-audit/
|
||||
|
||||
# ── GSD baseline (auto-generated) ──
|
||||
.gsd/activity/
|
||||
.gsd/runtime/
|
||||
.gsd/worktrees/
|
||||
.gsd/auto.lock
|
||||
.gsd/metrics.json
|
||||
.gsd/completed-units.json
|
||||
.gsd/STATE.md
|
||||
.gsd/gsd.db
|
||||
.gsd/DISCUSSION-MANIFEST.json
|
||||
.gsd/milestones/**/*-CONTINUE.md
|
||||
.gsd/milestones/**/continue.md
|
||||
|
||||
# ── GSD baseline (auto-generated) ──
|
||||
.gsd/forensics/
|
||||
.gsd/parallel/
|
||||
# ── GSD project state (per-worktree, never committed) ──
|
||||
.gsd/
|
||||
|
||||
# ── Stale lock files (npm is canonical) ──
|
||||
pnpm-lock.yaml
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
# Decisions Register
|
||||
|
||||
<!-- Append-only. Never edit or remove existing rows.
|
||||
To reverse a decision, add a new row that supersedes it.
|
||||
Read this file at the start of any planning or research phase. -->
|
||||
|
||||
| # | When | Scope | Decision | Choice | Rationale | Revisable? |
|
||||
|---|------|-------|----------|--------|-----------|------------|
|
||||
| D001 | M001-1ya5a3 | arch | Desktop shell framework | Electron + Vite | Chromium-based (required for Monaco, Shiki, potential future WebContainers), mature ecosystem, battle-tested for code editors (VS Code, Cursor). Electrobun considered but too young and needs CEF for Chromium. Tauri has system webview limitations. | Yes — if Electrobun matures |
|
||||
| D002 | M001-1ya5a3 | arch | Web preview approach | Localhost iframe | gsd-2 already spawns local dev servers. iframe is simpler, zero overhead, real environment. WebContainers add complexity for a local app with full filesystem access. | Yes — if sandboxing needed |
|
||||
| D003 | M001-1ya5a3 | library | Code editor | Monaco Editor (@monaco-editor/react) | Powers VS Code. Full language support, IntelliSense, diff views. Custom theming via defineTheme(). CodeMirror lighter but less out-of-box for a coding app. | No |
|
||||
| D004 | M001-1ya5a3 | library | UI primitives | Radix + Tailwind (custom components) | Headless, accessible primitives with zero visual opinions. Total design control. shadcn/ui has recognizable aesthetic that conflicts with "no AI slop" requirement. | No |
|
||||
| D005 | M001-1ya5a3 | convention | Icon set | Phosphor Icons | Minimal, geometric, consistent stroke weight. Used by Linear, Vercel. Anti-Lucide — explicitly chosen to avoid the generic AI app aesthetic. | No |
|
||||
| D006 | M001-1ya5a3 | convention | Typography | Inter (UI) + JetBrains Mono (code) | Inter has great optical sizing and tabular figures. JetBrains Mono has ligatures and clear character distinction. Both high-quality and widely respected. | No |
|
||||
| D007 | M001-1ya5a3 | convention | Color palette | Dark monochrome + warm amber/gold accent | Dark-first, terminal-inspired but refined. Single warm accent color. No purple. Monochrome grays for hierarchy. | Yes — accent color may evolve |
|
||||
| D008 | M001-1ya5a3 | convention | Message layout | Continuous document flow, left-aligned | Not chat bubbles. Not turn-based blocks. A living document that grows — more like reading a premium terminal transcript than texting. | No |
|
||||
| D009 | M001-1ya5a3 | library | Syntax highlighting (messages) | Shiki | TextMate grammar-based, accurate highlighting, theme customization. Used for code blocks in the markdown message stream. Monaco handles the editor separately. | No |
|
||||
| D010 | M001-1ya5a3 | library | State management | Zustand | Lightweight, minimal boilerplate, works well with React. No Redux overhead for a desktop app. | Yes — if state complexity grows |
|
||||
| D011 | M001-1ya5a3 | arch | Layout model | Three-column resizable | File tree (left), conversation (center), editor+preview (right). Draggable dividers. Center is primary focus. Panels collapsible. | No |
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
# GSD Studio
|
||||
|
||||
## What This Is
|
||||
|
||||
A local desktop coding agent app — a premium GUI for gsd-2. Built with Electron + Vite + React, it replaces the terminal experience with a beautifully designed three-column interface where you can see the conversation stream, the code being written, the file tree, and a live preview of what's being built — all at once.
|
||||
|
||||
The AI backend is gsd-2 communicating over its existing JSON-RPC protocol (stdin/stdout JSONL). The app spawns gsd-2 as a subprocess and renders its event stream as a continuous document flow with premium markdown rendering, bespoke tool cards with syntax highlighting and diffs, and wizard-style interactive prompts.
|
||||
|
||||
## Core Value
|
||||
|
||||
<!-- This is the primary value anchor for prioritization and tradeoffs.
|
||||
If scope must shrink, this should survive. -->
|
||||
|
||||
Tool cards that are art — beautiful, informative, syntax-highlighted cards for every tool call the agent makes. This is what you stare at 90% of the time while the agent works. If nothing else ships perfectly, the tool cards must be stunning.
|
||||
|
||||
## Current State
|
||||
|
||||
Greenfield project. No code exists yet. gsd-2 has a mature JSON-RPC protocol (`@gsd/pi-coding-agent` package) with TypeScript SDK, event streaming, and extension UI request/response handling.
|
||||
|
||||
## Architecture / Key Patterns
|
||||
|
||||
- **Desktop shell:** Electron + Vite + React (TypeScript)
|
||||
- **UI primitives:** Radix (headless) + Tailwind CSS — custom component library, not shadcn
|
||||
- **Design system:** Dark monochrome + warm amber accent, Inter + JetBrains Mono, Phosphor Icons
|
||||
- **Code editor:** Monaco Editor with custom dark theme
|
||||
- **Syntax highlighting (messages):** Shiki for code blocks in markdown
|
||||
- **Diff rendering:** react-diff-viewer or custom diff component with Shiki highlighting
|
||||
- **State management:** Zustand
|
||||
- **AI backend:** gsd-2 spawned as subprocess via `RpcClient` from `@gsd/pi-coding-agent`
|
||||
- **Preview pane:** Localhost iframe pointing at dev server the agent spawns
|
||||
- **Electron IPC:** Main process manages gsd-2 subprocess, renderer communicates via contextBridge/preload
|
||||
|
||||
## Capability Contract
|
||||
|
||||
See `.gsd/REQUIREMENTS.md` for the explicit capability contract, requirement status, and coverage mapping.
|
||||
|
||||
## Milestone Sequence
|
||||
|
||||
- [ ] M001-1ya5a3: GSD Studio MVP — Full coding agent GUI with message stream, tool cards, editor, preview, and interactive prompts
|
||||
|
|
@ -1,237 +0,0 @@
|
|||
# Requirements
|
||||
|
||||
This file is the explicit capability and coverage contract for the project.
|
||||
|
||||
## Active
|
||||
|
||||
### R001 — Desktop app shell with native window management
|
||||
- Class: core-capability
|
||||
- Status: active
|
||||
- Description: Electron desktop app launches with native window, title bar, and proper macOS integration
|
||||
- Why it matters: Foundation for everything else — no shell, no app
|
||||
- Source: user
|
||||
- Primary owning slice: M001-1ya5a3/S01
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: Electron + Vite + React. Must support HMR in dev.
|
||||
|
||||
### R002 — gsd-2 RPC connection with full event streaming
|
||||
- Class: core-capability
|
||||
- Status: active
|
||||
- Description: App spawns gsd-2 as a subprocess via JSON-RPC, streams all events (message_update, tool_execution_start/success/error, extension_ui_request), and handles the full bidirectional protocol
|
||||
- Why it matters: This is the brain — without the RPC pipe, the app is an empty shell
|
||||
- Source: user
|
||||
- Primary owning slice: M001-1ya5a3/S02
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: Uses `RpcClient` from `@gsd/pi-coding-agent`. Must handle process lifecycle, crash recovery, and all event types.
|
||||
|
||||
### R003 — Continuous document-flow message rendering with premium markdown
|
||||
- Class: primary-user-loop
|
||||
- Status: active
|
||||
- Description: Agent text streams in real-time as a continuous left-aligned document flow — headings, code blocks with syntax highlighting (Shiki), tables, inline code, lists, blockquotes. Not chat bubbles. Premium typography with Inter, proper spacing, hierarchy, and weights.
|
||||
- Why it matters: This is the primary reading experience. If the markdown rendering is mediocre, the whole app feels mediocre.
|
||||
- Source: user
|
||||
- Primary owning slice: M001-1ya5a3/S03
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: Must handle streaming deltas smoothly without jank. Tables must render properly. Code blocks need language-specific syntax highlighting.
|
||||
|
||||
### R004 — Tool card system — bespoke cards per tool type
|
||||
- Class: differentiator
|
||||
- Status: active
|
||||
- Description: Tool calls render as bespoke collapsed/expandable cards. Edit cards show syntax-highlighted inline diffs. Read cards show formatted code previews with line numbers. Bash cards show styled terminal output. Write cards show the created file with highlighting. Collapsed view shows just enough to be interesting — a code snippet, a diff summary, a command. Expanded view shows full detail. Each card type is a design piece with considered borders, spacing, hierarchy, and subtle expand animation.
|
||||
- Why it matters: Tool cards are what you stare at 90% of the time. They are the product. They must be art.
|
||||
- Source: user
|
||||
- Primary owning slice: M001-1ya5a3/S04
|
||||
- Supporting slices: M001-1ya5a3/S03
|
||||
- Validation: unmapped
|
||||
- Notes: Tool types to cover at minimum: Read, Write, Edit, Bash, lsp, search, browser tools. Each gets bespoke treatment. No generic "tool output" fallback that looks lazy.
|
||||
|
||||
### R005 — Integrated Monaco code editor with custom dark theme
|
||||
- Class: core-capability
|
||||
- Status: active
|
||||
- Description: Monaco Editor panel in the right column with JetBrains Mono font, custom dark theme matching the app's monochrome + amber aesthetic, minimap disabled, proper syntax highlighting for all major languages
|
||||
- Why it matters: Users need to see and read the code the agent is writing
|
||||
- Source: user
|
||||
- Primary owning slice: M001-1ya5a3/S06
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: Theme must match the app aesthetic exactly — not stock VS Code dark. Use `monaco.editor.defineTheme()` with custom token colors.
|
||||
|
||||
### R006 — File tree sidebar with project navigation
|
||||
- Class: core-capability
|
||||
- Status: active
|
||||
- Description: Left sidebar shows the project's file tree with expandable directories, file type icons, and click-to-open behavior that loads files in the Monaco editor
|
||||
- Why it matters: Spatial awareness of what the agent is building
|
||||
- Source: user
|
||||
- Primary owning slice: M001-1ya5a3/S06
|
||||
- Supporting slices: M001-1ya5a3/S02
|
||||
- Validation: unmapped
|
||||
- Notes: Should auto-refresh when the agent creates/modifies files. File watching via Electron's Node.js fs.watch or chokidar.
|
||||
|
||||
### R007 — Localhost iframe preview pane for live web app preview
|
||||
- Class: core-capability
|
||||
- Status: active
|
||||
- Description: Right panel has a tab/toggle to switch between the Monaco editor and a localhost iframe preview. When the agent spins up a dev server, the preview pane loads it.
|
||||
- Why it matters: See what the agent builds in real-time without leaving the app
|
||||
- Source: user
|
||||
- Primary owning slice: M001-1ya5a3/S07
|
||||
- Supporting slices: M001-1ya5a3/S02
|
||||
- Validation: unmapped
|
||||
- Notes: Detect dev server URL from agent's tool output or Bash stdout. iframe should auto-reload on changes.
|
||||
|
||||
### R008 — Dark monochrome + warm amber design system
|
||||
- Class: quality-attribute
|
||||
- Status: active
|
||||
- Description: Comprehensive design system — dark backgrounds, light text, monochrome grays, warm amber/gold as the single accent color. Inter for UI text, JetBrains Mono for code. Phosphor Icons. Radix primitives + Tailwind for styling. No Lucide icons, no purple, no shadcn recognizable aesthetic. Custom component library that feels like Linear or Vercel.
|
||||
- Why it matters: The "no AI slop" requirement. Every pixel must feel intentional, premium, and hand-crafted.
|
||||
- Source: user
|
||||
- Primary owning slice: M001-1ya5a3/S01
|
||||
- Supporting slices: all slices
|
||||
- Validation: unmapped
|
||||
- Notes: Design system is established in S01 and consumed by every subsequent slice. Tailwind config defines the full color palette, typography scale, and spacing system.
|
||||
|
||||
### R009 — Beautiful interactive prompt UI — wizard-style extension UI
|
||||
- Class: differentiator
|
||||
- Status: active
|
||||
- Description: Extension UI requests (select, confirm, input, editor) render as premium inline wizard components in the conversation flow. Single-select shows option cards with radio selection and a "None of the above" with free-form notes field. Multi-select shows checkboxes. Tab headers show question navigation. Recommended options are visually highlighted. The full ask_user_questions interaction surface — tab-to-add-notes, multi-page navigation, review screen — must be beautifully rendered.
|
||||
- Why it matters: Interactive prompts are how the agent asks you questions during discussion, planning, and execution. If they feel like browser confirm() dialogs, the premium experience collapses.
|
||||
- Source: user
|
||||
- Primary owning slice: M001-1ya5a3/S05
|
||||
- Supporting slices: M001-1ya5a3/S02
|
||||
- Validation: unmapped
|
||||
- Notes: Must handle all extension_ui_request methods: select (single + multi), confirm, input, editor. Also handle fire-and-forget: notify, setStatus, setWidget, setTitle. The secure_env_collect tool uses paged masked input — handle via the input method with masking.
|
||||
|
||||
### R010 — Three-column resizable layout
|
||||
- Class: core-capability
|
||||
- Status: active
|
||||
- Description: Three resizable columns — file tree (left), conversation stream (center), editor+preview (right). Draggable dividers. Center column is the primary focus. Panels can be collapsed.
|
||||
- Why it matters: The spatial layout is the cockpit — seeing everything at once is the whole point
|
||||
- Source: user
|
||||
- Primary owning slice: M001-1ya5a3/S01
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: Use a panel library like react-resizable-panels or custom dividers. Remember panel sizes across sessions via localStorage.
|
||||
|
||||
### R011 — No AI slop aesthetic
|
||||
- Class: constraint
|
||||
- Status: active
|
||||
- Description: No Lucide icons, no purple accent, no generic component-kit look, no recognizable shadcn aesthetic, no default Monaco themes. Every visual element must feel intentionally designed, not assembled from a kit.
|
||||
- Why it matters: This is a negative constraint that's sharper than any positive specification — it defines the taste bar
|
||||
- Source: user
|
||||
- Primary owning slice: M001-1ya5a3/S01
|
||||
- Supporting slices: all slices
|
||||
- Validation: unmapped
|
||||
- Notes: Enforce during every slice. UAT should include visual review.
|
||||
|
||||
### R012 — Streaming performance — smooth high-frequency delta rendering
|
||||
- Class: quality-attribute
|
||||
- Status: active
|
||||
- Description: The RPC protocol emits high-frequency message_update deltas. The renderer must accumulate and display them smoothly without jank, dropped frames, or visible flicker. Markdown parsing and syntax highlighting must not block the render loop.
|
||||
- Why it matters: Stuttery streaming kills the premium feel instantly
|
||||
- Source: inferred
|
||||
- Primary owning slice: M001-1ya5a3/S03
|
||||
- Supporting slices: M001-1ya5a3/S04
|
||||
- Validation: unmapped
|
||||
- Notes: Consider requestAnimationFrame batching, virtual scrolling for long conversations, and deferred/async Shiki highlighting.
|
||||
|
||||
## Deferred
|
||||
|
||||
### R013 — Multi-project/session management
|
||||
- Class: continuity
|
||||
- Status: deferred
|
||||
- Description: Manage multiple projects, switch between sessions, session history
|
||||
- Why it matters: Power user need once the core experience is solid
|
||||
- Source: inferred
|
||||
- Primary owning slice: none
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: Deferred to a later milestone. M001 works with one project at a time.
|
||||
|
||||
### R014 — Settings/preferences UI
|
||||
- Class: admin/support
|
||||
- Status: deferred
|
||||
- Description: Settings panel for model selection, theme customization, keybindings, etc.
|
||||
- Why it matters: Useful but not essential for the MVP experience
|
||||
- Source: inferred
|
||||
- Primary owning slice: none
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: Deferred. Model and provider can be configured via gsd-2's existing mechanisms initially.
|
||||
|
||||
### R015 — Onboarding flow for new users
|
||||
- Class: launchability
|
||||
- Status: deferred
|
||||
- Description: First-run experience, project setup wizard, API key configuration
|
||||
- Why it matters: Required for general audience but not for the current primary user
|
||||
- Source: inferred
|
||||
- Primary owning slice: none
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: Building for Lex first. Onboarding comes when generalizing.
|
||||
|
||||
### R016 — App packaging and distribution
|
||||
- Class: operability
|
||||
- Status: deferred
|
||||
- Description: DMG/installer generation, code signing, auto-update mechanism
|
||||
- Why it matters: Required for distribution but not for local development use
|
||||
- Source: inferred
|
||||
- Primary owning slice: none
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: electron-builder handles this. Defer until the app is worth distributing.
|
||||
|
||||
## Out of Scope
|
||||
|
||||
### R017 — Cloud/remote agent execution
|
||||
- Class: anti-feature
|
||||
- Status: out-of-scope
|
||||
- Description: Running gsd-2 on a remote server rather than locally
|
||||
- Why it matters: Prevents scope creep — this is a local desktop app
|
||||
- Source: user
|
||||
- Primary owning slice: none
|
||||
- Supporting slices: none
|
||||
- Validation: n/a
|
||||
- Notes: The agent runs locally as a subprocess. Period.
|
||||
|
||||
### R018 — WebContainers in-browser runtime
|
||||
- Class: anti-feature
|
||||
- Status: out-of-scope
|
||||
- Description: Running Node.js inside the browser via WebContainers instead of using local dev servers
|
||||
- Why it matters: Adds complexity for zero benefit — the agent already has local filesystem access
|
||||
- Source: user
|
||||
- Primary owning slice: none
|
||||
- Supporting slices: none
|
||||
- Validation: n/a
|
||||
- Notes: Preview pane uses localhost iframe instead.
|
||||
|
||||
## Traceability
|
||||
|
||||
| ID | Class | Status | Primary owner | Supporting | Proof |
|
||||
|---|---|---|---|---|---|
|
||||
| R001 | core-capability | active | M001-1ya5a3/S01 | none | unmapped |
|
||||
| R002 | core-capability | active | M001-1ya5a3/S02 | none | unmapped |
|
||||
| R003 | primary-user-loop | active | M001-1ya5a3/S03 | none | unmapped |
|
||||
| R004 | differentiator | active | M001-1ya5a3/S04 | M001-1ya5a3/S03 | unmapped |
|
||||
| R005 | core-capability | active | M001-1ya5a3/S06 | none | unmapped |
|
||||
| R006 | core-capability | active | M001-1ya5a3/S06 | M001-1ya5a3/S02 | unmapped |
|
||||
| R007 | core-capability | active | M001-1ya5a3/S07 | M001-1ya5a3/S02 | unmapped |
|
||||
| R008 | quality-attribute | active | M001-1ya5a3/S01 | all | unmapped |
|
||||
| R009 | differentiator | active | M001-1ya5a3/S05 | M001-1ya5a3/S02 | unmapped |
|
||||
| R010 | core-capability | active | M001-1ya5a3/S01 | none | unmapped |
|
||||
| R011 | constraint | active | M001-1ya5a3/S01 | all | unmapped |
|
||||
| R012 | quality-attribute | active | M001-1ya5a3/S03 | M001-1ya5a3/S04 | unmapped |
|
||||
| R013 | continuity | deferred | none | none | unmapped |
|
||||
| R014 | admin/support | deferred | none | none | unmapped |
|
||||
| R015 | launchability | deferred | none | none | unmapped |
|
||||
| R016 | operability | deferred | none | none | unmapped |
|
||||
| R017 | anti-feature | out-of-scope | none | none | n/a |
|
||||
| R018 | anti-feature | out-of-scope | none | none | n/a |
|
||||
|
||||
## Coverage Summary
|
||||
|
||||
- Active requirements: 12
|
||||
- Mapped to slices: 12
|
||||
- Validated: 0
|
||||
- Unmapped active requirements: 0
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
# GSD State
|
||||
|
||||
**Active Milestone:** M001-1ya5a3: GSD Studio MVP
|
||||
**Active Slice:** S01: Electron Shell + Design System Foundation
|
||||
**Phase:** executing
|
||||
**Requirements Status:** 12 active · 0 validated · 4 deferred · 2 out of scope
|
||||
|
||||
## Milestone Registry
|
||||
- 🔄 **M001-1ya5a3:** GSD Studio MVP
|
||||
|
||||
## Recent Decisions
|
||||
- None recorded
|
||||
|
||||
## Blockers
|
||||
- None
|
||||
|
||||
## Next Action
|
||||
Execute T01: Scaffold Electron project with electron-vite, React, Tailwind v4, and design system tokens.
|
||||
BIN
.gsd/gsd.db-shm
BIN
.gsd/gsd.db-shm
Binary file not shown.
BIN
.gsd/gsd.db-wal
BIN
.gsd/gsd.db-wal
Binary file not shown.
|
|
@ -1,117 +0,0 @@
|
|||
# M001-1ya5a3: GSD Studio MVP
|
||||
|
||||
**Gathered:** 2026-03-18
|
||||
**Status:** Ready for planning
|
||||
|
||||
## Project Description
|
||||
|
||||
A premium local desktop coding agent GUI for gsd-2. Replaces the terminal experience with a beautifully designed Electron app featuring a continuous document-flow conversation stream, bespoke tool cards with syntax-highlighted diffs and code previews, wizard-style interactive prompts, a Monaco code editor, file tree navigation, and a live localhost preview pane. The design language is dark monochrome with warm amber accent, Inter + JetBrains Mono typography, Phosphor icons — inspired by Linear and Vercel's design sensibility. No AI slop. No generic component-kit aesthetic. Tool cards are art.
|
||||
|
||||
## Why This Milestone
|
||||
|
||||
gsd-2 is a powerful coding agent but lives in a terminal. This milestone delivers a visual, spatial interface where you see the conversation, the code, the files, and the preview all at once. It transforms the agent from text-scrolling-by into a cockpit.
|
||||
|
||||
## User-Visible Outcome
|
||||
|
||||
### When this milestone is complete, the user can:
|
||||
|
||||
- Launch the desktop app, point it at a project directory, and start a conversation with gsd-2 through a premium GUI
|
||||
- Watch tool calls stream as beautiful, bespoke cards — diffs for edits, syntax-highlighted code for reads, styled terminal output for bash commands
|
||||
- Interact with agent prompts (select, confirm, input) through wizard-style inline components with tab-to-add-notes, option cards, and recommended option highlighting
|
||||
- Browse the project file tree and open files in a custom-themed Monaco editor
|
||||
- See a live preview of web apps the agent builds via a localhost iframe
|
||||
- Experience the whole thing as a cohesive, premium, Linear/Vercel-quality design
|
||||
|
||||
### Entry point / environment
|
||||
|
||||
- Entry point: Electron app launch (dev: `npm run dev`, prod: app binary)
|
||||
- Environment: local macOS desktop (primary), future: cross-platform
|
||||
- Live dependencies involved: gsd-2 CLI (spawned as subprocess), local filesystem, local dev servers
|
||||
|
||||
## Completion Class
|
||||
|
||||
- Contract complete means: All UI components render correctly, RPC protocol handles all event types, tool cards display accurate data for each tool type
|
||||
- Integration complete means: Full round-trip — user sends prompt, gsd-2 processes it, events stream back, tool cards render, files appear in tree, editor opens them, preview shows running app
|
||||
- Operational complete means: App handles gsd-2 process crashes gracefully, reconnects, and maintains conversation state
|
||||
|
||||
## Final Integrated Acceptance
|
||||
|
||||
To call this milestone complete, we must prove:
|
||||
|
||||
- Send a real prompt to gsd-2 via the GUI and watch the full execution — message streaming, tool cards, file changes — render beautifully in real-time
|
||||
- Interact with an ask_user_questions prompt through the GUI's wizard-style UI, including adding notes and selecting from options
|
||||
- Open a file the agent just created/modified in the Monaco editor and see it syntax-highlighted with the custom theme
|
||||
- See a live web app preview in the iframe after the agent builds something with a dev server
|
||||
|
||||
## Risks and Unknowns
|
||||
|
||||
- **Monaco theming depth** — Custom dark theme needs to match the app aesthetic exactly. Monaco's theming API is powerful but the token color customization can be tedious.
|
||||
- **Streaming performance** — High-frequency message_update deltas need smooth rendering. Markdown parsing + Shiki highlighting in the render loop could cause jank.
|
||||
- **Tool card diversity** — Many tool types with different data shapes. Each needs bespoke rendering. The design surface is large.
|
||||
- **Electron IPC architecture** — Main process manages gsd-2 subprocess, renderer needs the event stream. Need clean IPC bridge via preload/contextBridge.
|
||||
- **Extension UI complexity** — The ask_user_questions interaction model is rich (tab headers, multi-select, notes, review screen). Recreating this in React with premium UX is substantial work.
|
||||
|
||||
## Existing Codebase / Prior Art
|
||||
|
||||
- `packages/pi-coding-agent/src/modes/rpc/rpc-client.ts` — TypeScript RPC client SDK. Use this to spawn and communicate with gsd-2.
|
||||
- `packages/pi-coding-agent/src/modes/rpc/rpc-types.ts` — Full type definitions for all RPC commands, responses, and events.
|
||||
- `packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts` — Server-side RPC mode implementation. Reference for understanding event shapes.
|
||||
- `src/headless.ts` — Headless orchestrator. Reference for how to manage gsd-2 subprocess lifecycle.
|
||||
- `src/headless-events.ts` — Event classification (terminal, blocked, milestone-ready). Reuse patterns.
|
||||
- `src/resources/extensions/ask-user-questions.ts` — Ask user questions tool. Reference for the full interaction model: single/multi-select, "None of the above", notes field, recommended option highlighting.
|
||||
- `src/resources/extensions/get-secrets-from-user.ts` — Secrets collection tool. Reference for paged masked input UI.
|
||||
- `src/resources/extensions/shared/interview-ui.ts` — Interview round widget. Reference for the full multi-page wizard interaction: tab navigation, notes, review screen, exit confirmation.
|
||||
- `~/.claude/skills/gsd-headless-rpc/` — Comprehensive RPC protocol documentation skill.
|
||||
|
||||
> See `.gsd/DECISIONS.md` for all architectural and pattern decisions — it is an append-only register; read it during planning, append to it during execution.
|
||||
|
||||
## Relevant Requirements
|
||||
|
||||
- R001-R012 — All active requirements are owned by this milestone's slices
|
||||
- R008 (design system) and R011 (no AI slop) apply to every slice
|
||||
- R004 (tool cards) and R009 (interactive prompts) are the differentiators
|
||||
|
||||
## Scope
|
||||
|
||||
### In Scope
|
||||
|
||||
- Electron + Vite + React desktop app shell
|
||||
- gsd-2 JSON-RPC integration via TypeScript SDK
|
||||
- Continuous document-flow message rendering with Shiki-highlighted code blocks
|
||||
- Bespoke tool cards for Read, Write, Edit, Bash, lsp, search, and browser tools
|
||||
- Wizard-style interactive prompt UI (select, confirm, input, editor)
|
||||
- Monaco editor with custom dark theme
|
||||
- File tree sidebar with auto-refresh
|
||||
- Localhost iframe preview pane
|
||||
- Dark monochrome + warm amber design system
|
||||
- Zustand state management
|
||||
|
||||
### Out of Scope / Non-Goals
|
||||
|
||||
- Multi-project/session management (R013 — deferred)
|
||||
- Settings/preferences UI (R014 — deferred)
|
||||
- Onboarding flow (R015 — deferred)
|
||||
- App packaging/distribution (R016 — deferred)
|
||||
- Cloud/remote execution (R017 — out of scope)
|
||||
- WebContainers (R018 — out of scope)
|
||||
- Mobile or tablet support
|
||||
- Collaborative/multi-user features
|
||||
|
||||
## Technical Constraints
|
||||
|
||||
- Must use Electron (Chromium-based) for the desktop shell — required for reliable rendering of Monaco, Shiki, and potential future WebContainers
|
||||
- gsd-2 communication MUST use the existing JSON-RPC protocol — no custom protocols
|
||||
- JSONL framing: LF-only splitting, NOT readline (breaks on Unicode separators)
|
||||
- Extension UI requests MUST be responded to — agent blocks until response is sent
|
||||
- Must work on macOS with Apple Silicon (primary dev environment)
|
||||
|
||||
## Integration Points
|
||||
|
||||
- **gsd-2 subprocess** — Spawned via `RpcClient`, communicates via stdin/stdout JSONL
|
||||
- **Local filesystem** — File tree reads, file watching for auto-refresh
|
||||
- **Local dev servers** — Preview iframe loads localhost URLs from agent-spawned servers
|
||||
|
||||
## Open Questions
|
||||
|
||||
- **Conversation persistence** — Should the GUI persist conversation history to disk, or rely on gsd-2's session files? Current thinking: lean on gsd-2's session management initially.
|
||||
- **Multiple gsd-2 instances** — Deferred, but the IPC architecture should not preclude it.
|
||||
|
|
@ -1,171 +0,0 @@
|
|||
# M001-1ya5a3: GSD Studio MVP
|
||||
|
||||
**Vision:** A premium local desktop coding agent GUI for gsd-2 — dark monochrome + warm amber, Linear/Vercel design quality, continuous document-flow messages, bespoke tool cards that are art, wizard-style interactive prompts, Monaco editor, file tree, and localhost preview pane.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- User can launch the app, point it at a project, and converse with gsd-2 through a premium GUI
|
||||
- Agent text streams in real-time with beautiful typography, syntax-highlighted code blocks, and proper markdown tables
|
||||
- Tool calls render as bespoke collapsed/expandable cards with diffs, code previews, and terminal output
|
||||
- Interactive prompts (ask_user_questions) render as inline wizard components with option cards, notes, and recommended highlighting
|
||||
- File tree sidebar shows the project structure and opens files in the Monaco editor
|
||||
- Localhost preview pane displays the running app the agent builds
|
||||
- The entire experience feels like Linear or Vercel — not a hackathon prototype
|
||||
|
||||
## Key Risks / Unknowns
|
||||
|
||||
- **Streaming + highlighting performance** — High-frequency deltas + Shiki syntax highlighting in the render loop could cause jank
|
||||
- **Tool card design surface** — Many tool types, each needs bespoke treatment. Large design effort.
|
||||
- **Extension UI recreation** — The ask_user_questions interaction model is rich and needs faithful, beautiful recreation in React
|
||||
- **Electron IPC bridge** — Clean separation between main process (gsd-2 management) and renderer (React app)
|
||||
|
||||
## Proof Strategy
|
||||
|
||||
- Streaming performance → retire in S03 by proving smooth delta rendering with Shiki highlighting on real agent output
|
||||
- Tool card diversity → retire in S04 by proving bespoke cards for all major tool types on real agent sessions
|
||||
- Extension UI complexity → retire in S05 by proving the full ask_user_questions interaction works through the GUI
|
||||
- Electron IPC → retire in S02 by proving end-to-end event streaming from gsd-2 subprocess to React renderer
|
||||
|
||||
## Verification Classes
|
||||
|
||||
- Contract verification: Component renders match expected designs, RPC protocol handles all event types correctly
|
||||
- Integration verification: Full round-trip — prompt → gsd-2 → events → UI rendering → file tree update → editor open
|
||||
- Operational verification: gsd-2 process crash recovery, reconnection, conversation state preservation
|
||||
- UAT / human verification: Visual design quality assessment — does it feel premium? Tool card review. Typography review.
|
||||
|
||||
## Milestone Definition of Done
|
||||
|
||||
This milestone is complete only when all are true:
|
||||
|
||||
- All seven slice deliverables are complete and styled
|
||||
- The design system is cohesive across all components — no visual inconsistencies
|
||||
- Tool cards are beautiful in both collapsed and expanded states for all major tool types
|
||||
- Interactive prompts work as premium wizard-style components with full interaction model
|
||||
- File tree, editor, and preview pane are wired to real gsd-2 output
|
||||
- A real end-to-end session works: prompt → agent executes → tool cards stream → files appear → editor shows them → preview loads the app
|
||||
- Visual quality passes human UAT — it genuinely feels like Linear/Vercel, not a prototype
|
||||
|
||||
## Requirement Coverage
|
||||
|
||||
- Covers: R001, R002, R003, R004, R005, R006, R007, R008, R009, R010, R011, R012
|
||||
- Partially covers: none
|
||||
- Leaves for later: R013, R014, R015, R016
|
||||
- Orphan risks: none
|
||||
|
||||
## Slices
|
||||
|
||||
- [ ] **S01: Electron Shell + Design System Foundation** `risk:high` `depends:[]`
|
||||
> After this: App launches as a native desktop window with the three-column resizable layout, dark theme, amber accent, Inter + JetBrains Mono loaded, Phosphor icons rendering. Panels show placeholder content.
|
||||
|
||||
- [ ] **S02: gsd-2 RPC Connection + Event Stream** `risk:high` `depends:[S01]`
|
||||
> After this: App spawns gsd-2, connects via JSON-RPC. Raw events stream into the center panel as formatted output — proof the pipe works end-to-end.
|
||||
|
||||
- [ ] **S03: Message Stream + Markdown Rendering** `risk:high` `depends:[S02]`
|
||||
> After this: Agent text streams in real-time with beautiful typography — headings, code blocks with Shiki syntax highlighting, tables, inline code, lists. Continuous document flow.
|
||||
|
||||
- [ ] **S04: Tool Cards — The Art** `risk:high` `depends:[S03]`
|
||||
> After this: Tool calls render as bespoke collapsed/expandable cards. Edit cards show syntax-highlighted diffs. Read cards show formatted code previews. Bash cards show styled terminal output. Write cards show the created file. Each card is a design piece.
|
||||
|
||||
- [ ] **S05: Interactive Prompt UI — Wizards** `risk:high` `depends:[S03]`
|
||||
> After this: Extension UI requests (select, confirm, input, editor) render as premium inline wizard components. Full ask_user_questions interaction with option cards, tab-to-add-notes, recommended highlighting.
|
||||
|
||||
- [ ] **S06: File Tree + Monaco Editor** `risk:medium` `depends:[S01,S02]`
|
||||
> After this: Left sidebar shows the project file tree. Clicking a file opens it in a custom-themed Monaco editor. JetBrains Mono, dark theme matching the app.
|
||||
|
||||
- [ ] **S07: Preview Pane + Final Integration** `risk:medium` `depends:[S06,S04,S05]`
|
||||
> After this: Right panel has editor/preview tab toggle. Full end-to-end: send prompt, watch tool cards, see files in tree, open in editor, preview running app in iframe. Final polish pass.
|
||||
|
||||
## Boundary Map
|
||||
|
||||
### S01 → S02
|
||||
Produces:
|
||||
- `electron/main.ts` — Electron main process with window creation and preload config
|
||||
- `electron/preload.ts` — contextBridge API exposing IPC channels to renderer
|
||||
- `src/App.tsx` — Root React component with three-column layout
|
||||
- `src/components/layout/` — ResizablePanel, Sidebar, CenterPanel, RightPanel components
|
||||
- `src/lib/theme/` — Tailwind config, CSS variables, design tokens (colors, typography scale, spacing)
|
||||
- `src/components/ui/` — Core primitives: Button, Text, Icon wrapper for Phosphor
|
||||
|
||||
Consumes: nothing (first slice)
|
||||
|
||||
### S02 → S03
|
||||
Produces:
|
||||
- `electron/gsd-service.ts` — gsd-2 subprocess manager in main process (spawn, restart, event forwarding)
|
||||
- `src/lib/rpc/` — Renderer-side RPC bridge: event listener hooks, command sender, connection state
|
||||
- `src/stores/session-store.ts` — Zustand store: connection status, raw events, message accumulator
|
||||
- IPC channels: `gsd:event`, `gsd:send-command`, `gsd:spawn`, `gsd:status`
|
||||
|
||||
Consumes from S01:
|
||||
- Electron main/preload/contextBridge architecture
|
||||
- Layout panels (center panel receives event stream)
|
||||
|
||||
### S03 → S04
|
||||
Produces:
|
||||
- `src/components/message-stream/` — MessageStream container, MessageBlock component
|
||||
- `src/components/markdown/` — MarkdownRenderer with Shiki code blocks, tables, inline code
|
||||
- `src/lib/streaming/` — Delta accumulator, RAF-batched render updates, markdown parse pipeline
|
||||
- Shiki highlighter instance (shared, pre-loaded themes + languages)
|
||||
|
||||
Consumes from S02:
|
||||
- `session-store.ts` — message_update events, accumulated text
|
||||
- RPC event stream
|
||||
|
||||
### S04 → S05
|
||||
Produces:
|
||||
- `src/components/tool-cards/` — ToolCard shell, collapsed/expanded states, expand animation
|
||||
- `src/components/tool-cards/EditCard.tsx` — Diff viewer with syntax highlighting
|
||||
- `src/components/tool-cards/ReadCard.tsx` — Code preview with line numbers
|
||||
- `src/components/tool-cards/BashCard.tsx` — Terminal-styled output
|
||||
- `src/components/tool-cards/WriteCard.tsx` — Created file preview
|
||||
- `src/components/tool-cards/SearchCard.tsx` — Search results with match highlighting
|
||||
- `src/components/tool-cards/GenericCard.tsx` — Fallback for uncovered tool types
|
||||
- `src/lib/tool-parser.ts` — Tool event → card data transformer
|
||||
|
||||
Consumes from S03:
|
||||
- MessageStream (tool cards are rendered inline in the message flow)
|
||||
- MarkdownRenderer (reused inside card content)
|
||||
- Shiki highlighter instance
|
||||
|
||||
### S05 → S07
|
||||
Produces:
|
||||
- `src/components/prompts/` — SelectPrompt, ConfirmPrompt, InputPrompt, EditorPrompt
|
||||
- `src/components/prompts/OptionCard.tsx` — Individual option with radio/checkbox, description, recommended badge
|
||||
- `src/components/prompts/NotesField.tsx` — Tab-to-expand notes textarea
|
||||
- `src/components/prompts/PromptWizard.tsx` — Multi-question wrapper with tab navigation
|
||||
- `src/lib/extension-ui-handler.ts` — Routes extension_ui_request events to prompt components, sends responses back
|
||||
|
||||
Consumes from S03:
|
||||
- MessageStream (prompts are rendered inline in the conversation flow)
|
||||
- Design system components
|
||||
|
||||
Consumes from S02:
|
||||
- RPC bridge (sends extension_ui_response back to gsd-2)
|
||||
|
||||
### S06 → S07
|
||||
Produces:
|
||||
- `src/components/file-tree/` — FileTree, FileTreeNode, directory expand/collapse
|
||||
- `src/components/editor/` — MonacoEditor wrapper with custom theme, language detection
|
||||
- `src/stores/file-store.ts` — Zustand store: file tree state, open files, active file
|
||||
- `src/lib/file-watcher.ts` — Electron-side file watching, IPC to renderer for tree refresh
|
||||
|
||||
Consumes from S01:
|
||||
- Layout panels (left sidebar for tree, right panel for editor)
|
||||
|
||||
Consumes from S02:
|
||||
- IPC channels (file watching runs in main process)
|
||||
|
||||
### S07 (final integration)
|
||||
Produces:
|
||||
- `src/components/preview/` — PreviewPane with iframe, URL bar, reload button
|
||||
- `src/components/layout/RightPanel.tsx` — Updated with editor/preview tab toggle
|
||||
- Final integration wiring: tool card file links → editor open, bash server detection → preview URL
|
||||
- Polish pass: transitions, loading states, empty states, error states
|
||||
|
||||
Consumes from S04:
|
||||
- Tool cards (file links in cards trigger editor open)
|
||||
|
||||
Consumes from S05:
|
||||
- Interactive prompts (full wizard flow works end-to-end)
|
||||
|
||||
Consumes from S06:
|
||||
- File tree + Monaco editor (clicking files, opening modified files)
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
# S01: Electron Shell + Design System Foundation
|
||||
|
||||
**Goal:** Deliver a working Electron desktop app with the full design system (dark monochrome + warm amber), three-column resizable layout, custom title bar, and core UI primitives — the foundation every subsequent slice builds on.
|
||||
**Demo:** `npm run dev -w studio` opens a native macOS window with three resizable columns (sidebar, center, right panel), amber-accented drag handles, Inter + JetBrains Mono typography, Phosphor icons, and styled placeholder content in each panel. Dragging handles resizes panels. The app looks premium — not a prototype.
|
||||
|
||||
## Must-Haves
|
||||
|
||||
- Electron window launches via `npm run dev -w studio` with HMR
|
||||
- Tailwind v4 CSS-first `@theme` block defines the full color palette, typography scale, and spacing system
|
||||
- Inter (UI) and JetBrains Mono (code) fonts bundled locally as woff2 assets
|
||||
- Three-column layout via `react-resizable-panels` with draggable dividers
|
||||
- Custom panel handles with amber accent on hover/drag
|
||||
- macOS title bar with `titleBarStyle: 'hiddenInset'` and proper traffic light offset
|
||||
- Core UI primitives: Button, Text, Icon (Phosphor wrapper)
|
||||
- Preload script with `contextBridge` stubs for IPC channels (wired in S02)
|
||||
- TypeScript design tokens file mirroring CSS custom properties
|
||||
- `npm run build -w studio` produces a working production build
|
||||
- No Lucide icons, no purple, no shadcn aesthetic, no generic fonts
|
||||
|
||||
## Proof Level
|
||||
|
||||
- This slice proves: contract (the design system and layout shell that all subsequent slices consume)
|
||||
- Real runtime required: yes (Electron must launch and render)
|
||||
- Human/UAT required: yes (visual quality assessment — does it feel premium?)
|
||||
|
||||
## Verification
|
||||
|
||||
- `cd studio && npm run build` succeeds with exit code 0 (production build works)
|
||||
- `npm run dev -w studio` launches an Electron window (manual verification)
|
||||
- Three columns visible with drag handles; resizing works
|
||||
- Panel handles show amber (`#d4a04e`) on hover
|
||||
- Inter font renders in UI text, JetBrains Mono in code-styled elements
|
||||
- Phosphor icons render at correct size/weight
|
||||
- Title bar has macOS traffic light buttons with no content overlap
|
||||
- All placeholder panels show styled content with correct dark theme colors
|
||||
- HMR works — editing a React component hot-reloads without restart
|
||||
|
||||
## Observability / Diagnostics
|
||||
|
||||
- Runtime signals: Electron main process logs to stdout (app ready, window created, preload loaded)
|
||||
- Inspection surfaces: `npm run dev -w studio` console output, Electron DevTools in renderer
|
||||
- Failure visibility: Build errors surface in terminal; renderer errors in DevTools console
|
||||
- Redaction constraints: none
|
||||
|
||||
## Integration Closure
|
||||
|
||||
- Upstream surfaces consumed: none (first slice)
|
||||
- New wiring introduced: `studio/` workspace added to root `package.json`, electron-vite build pipeline, contextBridge IPC stubs
|
||||
- What remains before milestone is truly usable end-to-end: S02 (RPC connection), S03 (message rendering), S04 (tool cards), S05 (prompts), S06 (file tree + editor), S07 (preview + final integration)
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ] **T01: Scaffold Electron project with electron-vite, React, Tailwind v4, and design system tokens** `est:1h`
|
||||
- Why: Everything else depends on the build pipeline working. This task gets `npm run dev -w studio` opening an Electron window with styled content — proving the full toolchain (electron-vite, React 19, Tailwind v4, font loading) works end-to-end.
|
||||
- Files: `studio/package.json`, `studio/electron.vite.config.ts`, `studio/tsconfig.json`, `studio/tsconfig.node.json`, `studio/tsconfig.web.json`, `studio/src/main/index.ts`, `studio/src/preload/index.ts`, `studio/src/preload/index.d.ts`, `studio/src/renderer/index.html`, `studio/src/renderer/src/main.tsx`, `studio/src/renderer/src/App.tsx`, `studio/src/renderer/src/styles/index.css`, `studio/src/renderer/src/lib/theme/tokens.ts`, `studio/src/renderer/src/assets/fonts/` (Inter + JetBrains Mono woff2), `package.json` (root — add studio to workspaces)
|
||||
- Do: Create `studio/` directory structure following electron-vite conventions (`src/main/`, `src/preload/`, `src/renderer/`). Set up `electron.vite.config.ts` with three build sections — renderer section gets `@tailwindcss/vite` and `@vitejs/plugin-react`. Define the full design system in `index.css` `@theme` block (all colors, typography, spacing from the research spec). Bundle Inter and JetBrains Mono as local woff2 with `@font-face` declarations (`font-display: block`). Create `contextBridge` preload with typed IPC channel stubs. Create minimal `App.tsx` that renders styled test content proving the theme works. Create `tokens.ts` mirroring CSS custom properties for programmatic access. Add `"studio"` to root `package.json` workspaces. Run `npm install` from root. **Skills to load:** `frontend-design` for design system quality.
|
||||
- Verify: `npm run dev -w studio` opens an Electron window showing styled content with correct fonts and dark theme. `npm run build -w studio` exits 0.
|
||||
- Done when: Electron window opens with Inter font in UI text, JetBrains Mono in a code element, dark background (`#0a0a0a`), amber accent color visible, and production build succeeds.
|
||||
|
||||
- [ ] **T02: Three-column resizable layout, custom title bar, and UI primitives with placeholder content** `est:45m`
|
||||
- Why: Delivers the spatial layout, interaction design (resizable panels with amber handles), title bar, and the reusable UI primitives (Button, Text, Icon) that every subsequent slice imports. Placeholder content in each panel proves the design system is cohesive.
|
||||
- Files: `studio/src/renderer/src/App.tsx` (update), `studio/src/renderer/src/components/layout/AppLayout.tsx`, `studio/src/renderer/src/components/layout/Sidebar.tsx`, `studio/src/renderer/src/components/layout/CenterPanel.tsx`, `studio/src/renderer/src/components/layout/RightPanel.tsx`, `studio/src/renderer/src/components/layout/PanelHandle.tsx`, `studio/src/renderer/src/components/layout/TitleBar.tsx`, `studio/src/renderer/src/components/ui/Button.tsx`, `studio/src/renderer/src/components/ui/Text.tsx`, `studio/src/renderer/src/components/ui/Icon.tsx`, `studio/src/renderer/src/styles/index.css` (update if needed)
|
||||
- Do: Install `react-resizable-panels`. Build `AppLayout.tsx` with `PanelGroup`/`Panel`/`PanelResizeHandle` in a three-column layout (sidebar ~20%, center ~50%, right ~30%). Create `PanelHandle.tsx` — a thin vertical bar that shows amber accent on hover/active with a subtle grip indicator. Create `TitleBar.tsx` with `titleBarStyle: 'hiddenInset'` offset (68px padding-left for traffic lights), `-webkit-app-region: drag` for the title area, app name "GSD Studio" in amber. Build `Sidebar.tsx`, `CenterPanel.tsx`, `RightPanel.tsx` with placeholder content that demonstrates the design system — use typography hierarchy, icon samples, color palette preview. Create `Button.tsx` (primary/secondary/ghost variants using Tailwind, Radix Slot pattern for polymorphism), `Text.tsx` (heading/body/label/code presets mapping to the type scale), `Icon.tsx` (thin Phosphor wrapper with `IconContext` provider setting default size/weight/color). Wire everything into `App.tsx`. Ensure panels have min-width constraints and the center panel cannot be collapsed. **Skills to load:** `frontend-design` for component quality, `make-interfaces-feel-better` for polish details. **Note on react-resizable-panels v4+ API:** The library exports `PanelGroup`, `Panel`, `PanelResizeHandle` — the research mentions `Group`/`Panel`/`Separator` names but verify against actual imports.
|
||||
- Verify: `npm run dev -w studio` shows three-column layout. Dragging handles resizes panels. Handles show amber on hover. Title bar has traffic light offset. Button, Text, Icon components render correctly in placeholder content. `npm run build -w studio` still exits 0.
|
||||
- Done when: App shows three resizable columns with amber-accented drag handles, macOS title bar with traffic lights, placeholder content using all three UI primitives (Button, Text, Icon), Inter and JetBrains Mono visible in appropriate contexts, and the overall aesthetic reads as premium dark-theme design — not a prototype.
|
||||
|
||||
## Files Likely Touched
|
||||
|
||||
- `package.json` (root — workspaces update)
|
||||
- `studio/package.json`
|
||||
- `studio/electron.vite.config.ts`
|
||||
- `studio/tsconfig.json`
|
||||
- `studio/tsconfig.node.json`
|
||||
- `studio/tsconfig.web.json`
|
||||
- `studio/src/main/index.ts`
|
||||
- `studio/src/preload/index.ts`
|
||||
- `studio/src/preload/index.d.ts`
|
||||
- `studio/src/renderer/index.html`
|
||||
- `studio/src/renderer/src/main.tsx`
|
||||
- `studio/src/renderer/src/App.tsx`
|
||||
- `studio/src/renderer/src/styles/index.css`
|
||||
- `studio/src/renderer/src/lib/theme/tokens.ts`
|
||||
- `studio/src/renderer/src/assets/fonts/*.woff2`
|
||||
- `studio/src/renderer/src/components/layout/AppLayout.tsx`
|
||||
- `studio/src/renderer/src/components/layout/Sidebar.tsx`
|
||||
- `studio/src/renderer/src/components/layout/CenterPanel.tsx`
|
||||
- `studio/src/renderer/src/components/layout/RightPanel.tsx`
|
||||
- `studio/src/renderer/src/components/layout/PanelHandle.tsx`
|
||||
- `studio/src/renderer/src/components/layout/TitleBar.tsx`
|
||||
- `studio/src/renderer/src/components/ui/Button.tsx`
|
||||
- `studio/src/renderer/src/components/ui/Text.tsx`
|
||||
- `studio/src/renderer/src/components/ui/Icon.tsx`
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
# S01: Electron Shell + Design System Foundation — Research
|
||||
|
||||
**Date:** 2026-03-18
|
||||
|
||||
## Summary
|
||||
|
||||
S01 delivers the Electron desktop shell, three-column resizable layout, and the full design system that every subsequent slice builds on. The technology stack is well-understood: electron-vite (v5) for the build pipeline, React 19 + TypeScript in the renderer, Tailwind v4 CSS-first configuration for the design tokens, Radix primitives for accessible UI, react-resizable-panels for the three-column layout, and Phosphor Icons.
|
||||
|
||||
The main risk is getting the project scaffolding right — electron-vite imposes a specific directory structure (`src/main/`, `src/preload/`, `src/renderer/`) and the design system must be defined in Tailwind v4's CSS-first `@theme` block rather than a traditional `tailwind.config.js`. The font loading story (Inter + JetBrains Mono) needs to work in Electron's renderer without external network requests — fonts should be bundled as local assets. There are no novel unknowns; this is a scaffolding + design foundation slice.
|
||||
|
||||
## Recommendation
|
||||
|
||||
Use **electron-vite** as the build tool (not raw Vite + vite-plugin-electron). electron-vite provides a single `electron.vite.config.ts` that configures main, preload, and renderer builds with HMR out of the box. The studio app should live at `studio/` in the repo root and be added to the root `package.json` workspaces array. This gives it access to `@gsd/pi-coding-agent` for RPC types (consumed in S02) while keeping it isolated from the CLI build.
|
||||
|
||||
Use **Tailwind v4** with `@tailwindcss/vite` plugin in the renderer Vite config. Define the full color palette, typography scale, and spacing system in a `@theme` block in the main CSS file — no `tailwind.config.js` needed. This is cleaner and gives us CSS custom properties that Radix components and Monaco can reference.
|
||||
|
||||
Use **react-resizable-panels** (v4.7+) for the three-column layout. It handles the Group/Panel/Separator pattern, supports pixel min/max constraints, collapsible panels, and localStorage persistence via the `useDefaultLayout` hook.
|
||||
|
||||
## Implementation Landscape
|
||||
|
||||
### Key Files to Create
|
||||
|
||||
- `studio/package.json` — `@gsd/studio`, private, depends on electron, electron-vite, react, tailwindcss, @tailwindcss/vite, @radix-ui/*, react-resizable-panels, @phosphor-icons/react, zustand
|
||||
- `studio/electron.vite.config.ts` — electron-vite config with three builds (main/preload/renderer). Renderer config includes `@tailwindcss/vite` and `@vitejs/plugin-react`
|
||||
- `studio/src/main/index.ts` — Electron main process: `app.whenReady()`, `BrowserWindow` creation with preload, IPC handler stubs for S02. Window config: frameless/custom title bar or native with `titleBarStyle: 'hiddenInset'` for macOS
|
||||
- `studio/src/preload/index.ts` — `contextBridge.exposeInMainWorld('studio', { ... })` exposing typed IPC channels. Stubs for `gsd:event`, `gsd:send-command`, `gsd:spawn`, `gsd:status` (wired in S02)
|
||||
- `studio/src/renderer/index.html` — Minimal HTML entry: `<div id="root">`, loads `src/main.tsx`
|
||||
- `studio/src/renderer/src/main.tsx` — React root render, imports global CSS
|
||||
- `studio/src/renderer/src/App.tsx` — Root component: `<PanelGroup>` with three panels (sidebar, center, right)
|
||||
- `studio/src/renderer/src/styles/index.css` — `@import "tailwindcss"` + `@theme { }` block defining the full design system
|
||||
- `studio/src/renderer/src/components/layout/AppLayout.tsx` — Three-column layout using `react-resizable-panels` Group/Panel/Separator
|
||||
- `studio/src/renderer/src/components/layout/Sidebar.tsx` — Left panel placeholder (file tree goes here in S06)
|
||||
- `studio/src/renderer/src/components/layout/CenterPanel.tsx` — Center conversation panel placeholder
|
||||
- `studio/src/renderer/src/components/layout/RightPanel.tsx` — Right editor/preview panel placeholder
|
||||
- `studio/src/renderer/src/components/layout/PanelHandle.tsx` — Custom-styled drag handle for Separator (amber accent on hover)
|
||||
- `studio/src/renderer/src/components/layout/TitleBar.tsx` — Custom title bar with app name, traffic light offset, session controls placeholder
|
||||
- `studio/src/renderer/src/components/ui/Button.tsx` — Core button primitive (Radix Slot pattern for polymorphism, Tailwind variants)
|
||||
- `studio/src/renderer/src/components/ui/Text.tsx` — Typography component with preset variants (heading, body, label, code)
|
||||
- `studio/src/renderer/src/components/ui/Icon.tsx` — Thin wrapper around Phosphor icons with default context (size, weight, color)
|
||||
- `studio/src/renderer/src/lib/theme/tokens.ts` — TypeScript constants mirroring CSS custom properties for programmatic access (used by Monaco theme in S06, Shiki theme in S03)
|
||||
- `studio/src/renderer/src/assets/fonts/` — Inter and JetBrains Mono font files (woff2), loaded via `@font-face` in the CSS
|
||||
|
||||
### Design System Specification
|
||||
|
||||
The `@theme` block in `index.css` should define:
|
||||
|
||||
**Colors (CSS custom properties):**
|
||||
- `--color-bg-primary`: `#0a0a0a` (near-black base)
|
||||
- `--color-bg-secondary`: `#111111` (panels, cards)
|
||||
- `--color-bg-tertiary`: `#1a1a1a` (elevated surfaces)
|
||||
- `--color-bg-hover`: `#222222` (hover states)
|
||||
- `--color-border`: `#262626` (subtle borders)
|
||||
- `--color-border-active`: `#333333` (focused borders)
|
||||
- `--color-text-primary`: `#e5e5e5` (primary text)
|
||||
- `--color-text-secondary`: `#a3a3a3` (secondary text)
|
||||
- `--color-text-tertiary`: `#737373` (muted text)
|
||||
- `--color-accent`: `#d4a04e` (warm amber/gold — the signature color)
|
||||
- `--color-accent-hover`: `#e0b366` (lighter amber on hover)
|
||||
- `--color-accent-muted`: `rgba(212, 160, 78, 0.15)` (amber wash for backgrounds)
|
||||
|
||||
**Typography:**
|
||||
- `--font-sans`: `'Inter', system-ui, sans-serif`
|
||||
- `--font-mono`: `'JetBrains Mono', ui-monospace, monospace`
|
||||
- Type scale: 11px, 12px, 13px, 14px, 16px, 20px, 24px, 32px
|
||||
|
||||
**Spacing:** 4px base unit grid
|
||||
|
||||
### Build Order
|
||||
|
||||
1. **Scaffold the project** — `studio/package.json`, `electron.vite.config.ts`, directory structure, add `"studio"` to root workspaces. Run `npm install` from root.
|
||||
2. **Electron main + preload** — BrowserWindow creation, preload with contextBridge stubs. Verify: `npm run dev -w studio` opens a window.
|
||||
3. **React renderer + Tailwind** — `index.html`, `main.tsx`, `App.tsx`, CSS with `@import "tailwindcss"` and `@theme` block. Verify: window shows styled content.
|
||||
4. **Font loading** — Bundle Inter and JetBrains Mono woff2 files, `@font-face` declarations. Verify: fonts render in the window.
|
||||
5. **Three-column layout** — `AppLayout.tsx` with react-resizable-panels, custom separator handles, panel placeholders. Verify: panels resize, drag handles show amber on hover.
|
||||
6. **Title bar** — Custom title bar component with macOS traffic light offset. Verify: app looks native.
|
||||
7. **UI primitives** — Button, Text, Icon components. Verify: rendered in placeholder panels with correct styles.
|
||||
8. **Phosphor Icons** — IconContext provider with default theme values. Verify: icons render at correct size/weight.
|
||||
|
||||
### Verification Approach
|
||||
|
||||
1. `cd studio && npm run dev` launches the Electron window with no errors
|
||||
2. The window shows three resizable columns with drag handles
|
||||
3. Dragging handles resizes panels; handles show amber accent on hover
|
||||
4. Inter font renders in UI text, JetBrains Mono renders in code-styled elements
|
||||
5. Phosphor icons render at correct size and weight
|
||||
6. All placeholder panels show styled placeholder content with correct colors
|
||||
7. HMR works — editing a React component hot-reloads without restarting
|
||||
8. `npm run build -w studio` produces a working production build in `studio/out/`
|
||||
|
||||
## Don't Hand-Roll
|
||||
|
||||
| Problem | Existing Solution | Why Use It |
|
||||
|---------|------------------|------------|
|
||||
| Electron + Vite build pipeline | `electron-vite` (v5) | Handles main/preload/renderer builds, HMR, and dev server in one config. No need to wire Vite plugins manually. |
|
||||
| Resizable panel layout | `react-resizable-panels` (v4.7) | Handles drag, keyboard, min/max constraints, localStorage persistence, collapse. Well-tested. |
|
||||
| Accessible UI primitives | `@radix-ui/*` | Headless, zero-style primitives. Dialog, Tooltip, DropdownMenu, etc. for future slices. S01 only needs the dependency installed. |
|
||||
| Icon library | `@phosphor-icons/react` (v2.1) | Tree-shakeable, typed, consistent geometric style. `IconContext` for global defaults. |
|
||||
| CSS framework | `tailwindcss` v4 + `@tailwindcss/vite` | CSS-first config, no JS config file, generates CSS custom properties from `@theme` block. |
|
||||
|
||||
## Constraints
|
||||
|
||||
- **electron-vite directory convention**: Must use `src/main/`, `src/preload/`, `src/renderer/` structure for zero-config. Custom paths require explicit `rollupOptions.input` in each build section.
|
||||
- **Tailwind v4 has no `tailwind.config.js`**: All theme customization goes in the CSS `@theme` block. This is a new pattern — no JS-side theme object. TypeScript token constants must be manually synced with CSS variables.
|
||||
- **Fonts must be local**: Electron apps should not depend on Google Fonts CDN. Bundle woff2 files and use `@font-face` with relative paths.
|
||||
- **Preload script runs in isolated context**: Cannot import renderer modules. Must use `contextBridge.exposeInMainWorld()` to expose IPC channels. TypeScript types can be shared via a `studio/src/shared/` directory.
|
||||
- **electron-vite v5 requires `@swc/core`**: peer dependency — must be installed.
|
||||
- **Root workspace**: `studio/` must be added to root `package.json` `"workspaces"` array to access `@gsd/pi-coding-agent` types in S02.
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
- **Tailwind classes not working in Electron renderer** — The `@tailwindcss/vite` plugin must be added to the `renderer` section of `electron.vite.config.ts`, not the top level. electron-vite has separate Vite configs per process.
|
||||
- **Context isolation breaks direct IPC** — Cannot use `ipcRenderer` directly in renderer. Must go through `contextBridge` in preload. This is secure but means all IPC channels need explicit exposure.
|
||||
- **react-resizable-panels API changed in v4** — The library now uses `Group`, `Panel`, `Separator` (not `PanelGroup`, `Panel`, `PanelResizeHandle`). Import names matter. Docs show the v4 API.
|
||||
- **Font loading flash** — If fonts are loaded asynchronously, there's a brief flash of fallback font. Use `font-display: block` in `@font-face` declarations and preload the font files via `<link rel="preload">` in `index.html`.
|
||||
- **macOS title bar** — `titleBarStyle: 'hiddenInset'` gives native traffic lights but overlaps content. Need `CSS: padding-top` or `-webkit-app-region: drag` to create a drag region that doesn't overlap the layout.
|
||||
|
||||
## Skills Discovered
|
||||
|
||||
| Technology | Skill | Status |
|
||||
|------------|-------|--------|
|
||||
| Electron | `jezweb/claude-skills@electron-base` (267 installs) | available |
|
||||
| Electron | `jwynia/agent-skills@electron-best-practices` (112 installs) | available |
|
||||
| Tailwind v4 | `jezweb/claude-skills@tailwind-v4-shadcn` (2.7K installs) | available (shadcn-oriented, partial relevance) |
|
||||
| Radix | `yonatangross/orchestkit@radix-primitives` (42 installs) | available |
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
---
|
||||
estimated_steps: 8
|
||||
estimated_files: 15
|
||||
---
|
||||
|
||||
# T01: Scaffold Electron project with electron-vite, React, Tailwind v4, and design system tokens
|
||||
|
||||
**Slice:** S01 — Electron Shell + Design System Foundation
|
||||
**Milestone:** M001-1ya5a3
|
||||
|
||||
## Description
|
||||
|
||||
Bootstrap the `studio/` Electron app from scratch using electron-vite v5, React 19, TypeScript, and Tailwind v4. This task establishes the entire build pipeline and design system — colors, typography, spacing — as CSS custom properties in a Tailwind v4 `@theme` block. Fonts (Inter + JetBrains Mono) are bundled locally. The preload script exposes typed IPC channel stubs via `contextBridge` for S02 to wire up. By the end, `npm run dev -w studio` opens a dark-themed Electron window with correct fonts and styled content.
|
||||
|
||||
**Skill to load:** `~/.gsd/agent/skills/frontend-design/SKILL.md` — for design system quality and avoiding generic aesthetics.
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Add `"studio"` to root workspace config.** Edit the root `package.json` — change `"workspaces": ["packages/*"]` to `"workspaces": ["packages/*", "studio"]`.
|
||||
|
||||
2. **Create `studio/package.json`.** Name: `@gsd/studio`, private: true. Dependencies: `react` (^19), `react-dom` (^19), `@phosphor-icons/react` (^2.1), `react-resizable-panels` (^2.1), `zustand` (^5). DevDependencies: `electron` (^35), `electron-vite` (^3), `@vitejs/plugin-react` (^4), `@tailwindcss/vite` (^4), `tailwindcss` (^4), `typescript` (^5.4), `@types/react` (^19), `@types/react-dom` (^19), `@types/node` (^22). Scripts: `dev: "electron-vite dev"`, `build: "electron-vite build"`, `preview: "electron-vite preview"`. **Important:** Check the actual latest versions of `electron-vite` on npm — it may be v2 or v3, not v5 as research suggested. The research version numbers need verification at install time. Same for `react-resizable-panels` — the research says v4.7 but the actual latest may differ. Use `^` ranges and let npm resolve.
|
||||
|
||||
3. **Create TypeScript configs.** Three files following electron-vite convention:
|
||||
- `studio/tsconfig.json` — references `tsconfig.node.json` and `tsconfig.web.json`
|
||||
- `studio/tsconfig.node.json` — for main + preload (Node target, ESM)
|
||||
- `studio/tsconfig.web.json` — for renderer (DOM lib, JSX react-jsx, path aliases)
|
||||
|
||||
4. **Create `studio/electron.vite.config.ts`.** Three build sections:
|
||||
- `main`: entry `src/main/index.ts`
|
||||
- `preload`: entry `src/preload/index.ts`
|
||||
- `renderer`: entry `src/renderer/index.html`, plugins: `@tailwindcss/vite`, `@vitejs/plugin-react`. **Critical:** The Tailwind plugin must be in the renderer section only, not top-level.
|
||||
|
||||
5. **Create Electron main process (`studio/src/main/index.ts`).** `app.whenReady()` → create `BrowserWindow` with: `width: 1400, height: 900`, `titleBarStyle: 'hiddenInset'` (macOS), `trafficLightPosition: { x: 16, y: 16 }`, `backgroundColor: '#0a0a0a'`, `webPreferences: { preload, contextIsolation: true, nodeIntegration: false }`. Load the renderer URL (electron-vite provides the env variable for dev vs production). Log `"GSD Studio ready"` to stdout on window creation. Handle `window-all-closed` to quit on non-macOS, `activate` to recreate window on macOS.
|
||||
|
||||
6. **Create preload script (`studio/src/preload/index.ts`) and type declaration (`studio/src/preload/index.d.ts`).** Use `contextBridge.exposeInMainWorld('studio', { ... })` with stubs: `onEvent(callback)` → no-op, `sendCommand(command, args)` → no-op, `spawn()` → no-op, `getStatus()` → `Promise.resolve({ connected: false })`. The type declaration file (`index.d.ts`) should declare the `window.studio` interface so the renderer can use it with type safety. These stubs get real implementations in S02.
|
||||
|
||||
7. **Create renderer entry files.** `studio/src/renderer/index.html` — minimal HTML with `<div id="root">`, charset meta, viewport meta, and `<link rel="preload">` for font woff2 files. `studio/src/renderer/src/main.tsx` — `createRoot(document.getElementById('root')).render(<App />)`, imports `./styles/index.css`.
|
||||
|
||||
8. **Build the design system CSS (`studio/src/renderer/src/styles/index.css`).** Structure:
|
||||
- `@import "tailwindcss";`
|
||||
- `@font-face` declarations for Inter (regular 400, medium 500, semibold 600) and JetBrains Mono (regular 400, medium 500) — relative paths to `../assets/fonts/`, `font-display: block`.
|
||||
- `@theme { }` block defining all CSS custom properties:
|
||||
- Colors: `--color-bg-primary: #0a0a0a`, `--color-bg-secondary: #111111`, `--color-bg-tertiary: #1a1a1a`, `--color-bg-hover: #222222`, `--color-border: #262626`, `--color-border-active: #333333`, `--color-text-primary: #e5e5e5`, `--color-text-secondary: #a3a3a3`, `--color-text-tertiary: #737373`, `--color-accent: #d4a04e`, `--color-accent-hover: #e0b366`, `--color-accent-muted: rgba(212, 160, 78, 0.15)`
|
||||
- Fonts: `--font-sans: 'Inter', system-ui, sans-serif`, `--font-mono: 'JetBrains Mono', ui-monospace, monospace`
|
||||
- Base styles on `body`: `bg-primary` background, `text-primary` color, `font-sans`, antialiased rendering (`-webkit-font-smoothing: antialiased`).
|
||||
- Scrollbar styles: thin, dark track, subtle thumb.
|
||||
|
||||
9. **Bundle font files.** Download Inter (woff2: regular, medium, semibold) and JetBrains Mono (woff2: regular, medium) into `studio/src/renderer/src/assets/fonts/`. Use specific weights, not variable fonts, for consistent rendering. Source from Google Fonts CDN or the project's GitHub releases — download at scaffold time, commit the files.
|
||||
|
||||
10. **Create `studio/src/renderer/src/lib/theme/tokens.ts`.** TypeScript constants mirroring the CSS custom properties — `colors`, `fonts`, `fontSizes` objects. These are used programmatically by Monaco theme (S06) and Shiki theme (S03). Export as named exports.
|
||||
|
||||
11. **Create `studio/src/renderer/src/App.tsx`.** A simple component that renders test content proving the theme works: a heading in Inter, a code block in JetBrains Mono, the amber accent color, and some text at different hierarchy levels. This gets replaced with the full layout in T02.
|
||||
|
||||
12. **Run `npm install` from the repo root.** Verify the workspace resolves. Then `npm run dev -w studio` to confirm the Electron window opens. Then `npm run build -w studio` to confirm production build succeeds.
|
||||
|
||||
## Must-Haves
|
||||
|
||||
- [ ] `studio/` added to root workspaces, `npm install` succeeds
|
||||
- [ ] `electron.vite.config.ts` has three build sections with Tailwind in renderer only
|
||||
- [ ] `@theme` block defines all 12+ color tokens, font families, and type scale
|
||||
- [ ] Inter and JetBrains Mono woff2 files bundled locally (not CDN)
|
||||
- [ ] `@font-face` declarations use `font-display: block` to prevent FOUT
|
||||
- [ ] Preload exposes `window.studio` with typed IPC stubs via contextBridge
|
||||
- [ ] `npm run dev -w studio` opens an Electron window with styled dark-theme content
|
||||
- [ ] `npm run build -w studio` exits 0
|
||||
- [ ] Main process logs "GSD Studio ready" to stdout
|
||||
|
||||
## Verification
|
||||
|
||||
- `cd studio && npm run build` exits with code 0
|
||||
- `npm run dev -w studio` opens a window — visually confirm dark background, Inter font, JetBrains Mono in code, amber accent visible
|
||||
- No console errors in Electron DevTools
|
||||
- Font files exist in `studio/src/renderer/src/assets/fonts/` (at least 5 woff2 files)
|
||||
|
||||
## Inputs
|
||||
|
||||
- Root `package.json` — need to add `"studio"` to workspaces array
|
||||
- Research spec in `S01-RESEARCH.md` — color palette, typography, directory structure, electron-vite config shape (already inlined in this plan)
|
||||
- Decisions D001 (Electron), D004 (Radix + Tailwind), D005 (Phosphor), D006 (Inter + JetBrains Mono), D007 (dark monochrome + amber)
|
||||
|
||||
## Expected Output
|
||||
|
||||
- `studio/package.json` — workspace package with all dependencies
|
||||
- `studio/electron.vite.config.ts` — three-section build config
|
||||
- `studio/tsconfig.json`, `studio/tsconfig.node.json`, `studio/tsconfig.web.json` — TypeScript configs
|
||||
- `studio/src/main/index.ts` — Electron main process with BrowserWindow
|
||||
- `studio/src/preload/index.ts` — contextBridge with typed IPC stubs
|
||||
- `studio/src/preload/index.d.ts` — TypeScript declarations for window.studio
|
||||
- `studio/src/renderer/index.html` — HTML entry with font preload links
|
||||
- `studio/src/renderer/src/main.tsx` — React root render
|
||||
- `studio/src/renderer/src/App.tsx` — Test component proving theme works
|
||||
- `studio/src/renderer/src/styles/index.css` — Full design system CSS with @theme block
|
||||
- `studio/src/renderer/src/lib/theme/tokens.ts` — TypeScript design tokens
|
||||
- `studio/src/renderer/src/assets/fonts/*.woff2` — Bundled font files
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
---
|
||||
estimated_steps: 7
|
||||
estimated_files: 11
|
||||
---
|
||||
|
||||
# T02: Three-column resizable layout, custom title bar, and UI primitives with placeholder content
|
||||
|
||||
**Slice:** S01 — Electron Shell + Design System Foundation
|
||||
**Milestone:** M001-1ya5a3
|
||||
|
||||
## Description
|
||||
|
||||
Build the three-column resizable layout using `react-resizable-panels`, a custom macOS title bar, and the core UI primitives (Button, Text, Icon) that every subsequent slice imports. Each panel gets styled placeholder content that demonstrates the design system is cohesive — typography hierarchy, icon rendering, button variants, and the amber accent throughout. By the end, the app looks like a premium desktop tool, not a scaffolding demo.
|
||||
|
||||
**Skills to load:**
|
||||
- `~/.gsd/agent/skills/frontend-design/SKILL.md` — for component design quality
|
||||
- `~/.gsd/agent/skills/make-interfaces-feel-better/SKILL.md` — for polish: transitions, hover states, spacing, shadows
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Verify T01 output.** Run `npm run dev -w studio` to confirm the Electron window opens with the design system working. Check that fonts load, colors render, and there are no console errors. If anything is broken from T01, fix it before proceeding.
|
||||
|
||||
2. **Check `react-resizable-panels` API.** The research mentions both `Group/Panel/Separator` and `PanelGroup/Panel/PanelResizeHandle` as possible export names. Before building, verify the actual exports: `import { PanelGroup, Panel, PanelResizeHandle } from 'react-resizable-panels'` — check the installed version's types. Use whatever the library actually exports. Key API features needed: `direction="horizontal"`, `defaultSize` (percentage), `minSize`, `collapsible`, `onLayout` for potential persistence.
|
||||
|
||||
3. **Create `TitleBar.tsx` (`studio/src/renderer/src/components/layout/TitleBar.tsx`).** A horizontal bar at the top of the app window. Must account for macOS traffic lights — `paddingLeft: 78px` (traffic light area + breathing room). The title area uses `-webkit-app-region: drag` so the window is draggable by the title bar. Display "GSD Studio" in the accent color (`--color-accent`), small text, semibold. The bar itself: `--color-bg-secondary` background, `--color-border` bottom border, ~38px height. Include a subtle right-side area for future session controls (just a placeholder div for now).
|
||||
|
||||
4. **Create `PanelHandle.tsx` (`studio/src/renderer/src/components/layout/PanelHandle.tsx`).** A custom drag handle for the panel resize separator. Default state: a thin (1px) vertical line in `--color-border`. Hover state: the line becomes 2px, color transitions to `--color-accent` with a short `transition-colors` (150ms). Active/dragging state: stays amber. Include a small grip indicator (3 dots vertically centered) that appears on hover. The handle should be a reasonable hit target (8-12px wide padding) even though the visual line is thin.
|
||||
|
||||
5. **Create `AppLayout.tsx` (`studio/src/renderer/src/components/layout/AppLayout.tsx`).** The root layout component combining `TitleBar` + `PanelGroup`. Structure:
|
||||
- `TitleBar` at top (fixed height)
|
||||
- Below: horizontal `PanelGroup` with three panels:
|
||||
- Left sidebar: `defaultSize={20}`, `minSize={15}`, `collapsible={true}`
|
||||
- Center panel: `defaultSize={50}`, `minSize={30}` (NOT collapsible — it's always visible)
|
||||
- Right panel: `defaultSize={30}`, `minSize={20}`, `collapsible={true}`
|
||||
- Two `PanelHandle` separators between panels
|
||||
- `autoSaveId="gsd-studio-layout"` on the PanelGroup for localStorage persistence of panel sizes.
|
||||
The outer container fills the full viewport height (`h-screen`), uses `flex flex-col`.
|
||||
|
||||
6. **Create panel placeholder components.** Three files:
|
||||
- `Sidebar.tsx`: Header "Files" with a folder Phosphor icon, a mock file tree (just styled list items with file/folder icons, indentation, hover states). Shows the design system's secondary text, hover backgrounds, icon usage.
|
||||
- `CenterPanel.tsx`: Header "Conversation", a mock message area with sample text showing the typography hierarchy — an h2 heading, body text, inline code in JetBrains Mono, a code block with dark background, and a sample "tool card" placeholder (just a bordered card with an icon, title, and muted description). Include an input bar at the bottom — a text input with amber-accented focus ring and a send button.
|
||||
- `RightPanel.tsx`: Header "Editor", a mock editor area with line numbers (in `--color-text-tertiary`) and code text in JetBrains Mono. Just hardcoded sample code — this gets replaced with Monaco in S06.
|
||||
Each placeholder should look like a real UI, not a "Coming Soon" stub. Use the design system colors, fonts, and spacing throughout.
|
||||
|
||||
7. **Create UI primitives.** Three reusable components:
|
||||
- `Button.tsx` (`studio/src/renderer/src/components/ui/Button.tsx`): Variants — `primary` (amber bg, dark text), `secondary` (border-only, text-secondary), `ghost` (no border, text-secondary, hover bg). Sizes — `sm`, `md`, `lg`. Use `React.forwardRef` and accept all native button props via `React.ComponentPropsWithRef<'button'>`. Implement a Radix-style `asChild` prop using `Slot` from `@radix-ui/react-slot` for polymorphism (render as link, etc). Transitions on hover/active. Disabled state with reduced opacity.
|
||||
- `Text.tsx` (`studio/src/renderer/src/components/ui/Text.tsx`): Presets — `heading` (20px, semibold, text-primary), `subheading` (14px, medium, text-primary), `body` (14px, regular, text-secondary), `label` (12px, medium, text-tertiary), `code` (13px, JetBrains Mono, text-primary). Renders as `<p>` by default, accepts `as` prop for semantic element override. Uses the type scale from the design system.
|
||||
- `Icon.tsx` (`studio/src/renderer/src/components/ui/Icon.tsx`): Wraps `@phosphor-icons/react`'s `IconContext.Provider` at the app level (or exports a configured provider). Default context: `size={18}`, `weight="regular"`, `color="currentColor"`. The component itself is just a convenience re-export pattern — individual icons are imported directly from `@phosphor-icons/react` by consumers, but the context sets defaults.
|
||||
|
||||
8. **Wire everything into `App.tsx`.** Replace the T01 test content with: `<IconContext.Provider>` wrapping `<AppLayout>` which contains `<TitleBar>` + panels with `<Sidebar>`, `<CenterPanel>`, `<RightPanel>`. Import the layout and all primitives.
|
||||
|
||||
9. **Final polish pass.** Check spacing, alignment, color consistency. Ensure no Tailwind class conflicts. Verify the amber accent is used sparingly — only for interactive elements (handles, focus rings, primary buttons, app title). The rest should be monochrome grays. Add `@radix-ui/react-slot` to studio dependencies if not already present.
|
||||
|
||||
## Must-Haves
|
||||
|
||||
- [ ] Three-column layout with resizable panels via react-resizable-panels
|
||||
- [ ] Panel sizes persist to localStorage via `autoSaveId`
|
||||
- [ ] Custom drag handles transition to amber on hover (150ms transition)
|
||||
- [ ] Title bar with macOS traffic light offset and draggable region
|
||||
- [ ] Sidebar panel is collapsible; center panel is not
|
||||
- [ ] Button component with primary/secondary/ghost variants and asChild support
|
||||
- [ ] Text component with heading/subheading/body/label/code presets
|
||||
- [ ] Icon context provider with default size/weight for Phosphor icons
|
||||
- [ ] Placeholder content in all three panels demonstrates the design system
|
||||
- [ ] No Lucide icons, no purple accents, no generic component-kit aesthetics
|
||||
- [ ] `npm run build -w studio` still exits 0 after all changes
|
||||
|
||||
## Verification
|
||||
|
||||
- `npm run build -w studio` exits 0
|
||||
- `npm run dev -w studio` opens app with three visible columns
|
||||
- Drag handles resize panels; amber highlight appears on hover
|
||||
- Title bar shows "GSD Studio" in amber with traffic lights to the left
|
||||
- Sidebar shows mock file tree with Phosphor icons
|
||||
- Center panel shows typography hierarchy (heading, body, code) and input bar with amber focus
|
||||
- Right panel shows mock editor with line numbers in JetBrains Mono
|
||||
- Resizing the window does not break layout — panels flex proportionally
|
||||
- Collapsing the sidebar (double-click handle or drag to minimum) hides it; center expands
|
||||
|
||||
## Inputs
|
||||
|
||||
- T01 output: working Electron app with design system CSS, fonts, tokens.ts
|
||||
- `studio/src/renderer/src/App.tsx` — replace test content with layout
|
||||
- `studio/src/renderer/src/styles/index.css` — may need minor additions for scrollbar styles, selection colors
|
||||
- `react-resizable-panels` — already in T01 dependencies
|
||||
- `@radix-ui/react-slot` — may need to be added to dependencies
|
||||
- `@phosphor-icons/react` — already in T01 dependencies
|
||||
|
||||
## Expected Output
|
||||
|
||||
- `studio/src/renderer/src/components/layout/AppLayout.tsx` — three-column resizable layout
|
||||
- `studio/src/renderer/src/components/layout/TitleBar.tsx` — macOS-aware title bar
|
||||
- `studio/src/renderer/src/components/layout/PanelHandle.tsx` — amber-accented drag handle
|
||||
- `studio/src/renderer/src/components/layout/Sidebar.tsx` — file tree placeholder
|
||||
- `studio/src/renderer/src/components/layout/CenterPanel.tsx` — conversation placeholder
|
||||
- `studio/src/renderer/src/components/layout/RightPanel.tsx` — editor placeholder
|
||||
- `studio/src/renderer/src/components/ui/Button.tsx` — variant button primitive
|
||||
- `studio/src/renderer/src/components/ui/Text.tsx` — typography primitive
|
||||
- `studio/src/renderer/src/components/ui/Icon.tsx` — Phosphor icon context provider
|
||||
- `studio/src/renderer/src/App.tsx` — updated with full layout composition
|
||||
Loading…
Add table
Reference in a new issue