Adds real-time subprocess monitoring to the IDE via the callback-chain and subscribe/broadcast socket patterns: Shared types (packages/api): - New subprocess.ts message types: SubProcessStat, RequestProcessStatsMessage, SubscribeDroneMessage, UnsubscribeDroneMessage - New socket events in socket.ts: requestProcessStats, subscribeDrone, unsubscribeDrone (ClientToServer); drone:log, drone:status (ServerToClient) Drone (gadget-drone): - onRequestProcessStats handler calls SubProcessService.ps() + summarize(), returns typed SubProcessStat[] with status detection (exitCode/killed) Backend routing (gadget-code): - SocketService: getDroneSessionByRegistrationId(), droneMonitorIndex map, addDroneMonitor()/removeDroneMonitor()/broadcastToMonitors() - CodeSession: requestProcessStats proxy, subscribeDrone/unsubscribeDrone - DroneSession: broadcast drone:log + drone:status to monitor subscribers in addition to existing chat-session routing Frontend socket layer: - SocketClient: requestProcessStats(), subscribeDrone(), unsubscribeDrone() - drone:log + drone:status events forwarded to event bus Frontend components: - LogRenderer — reusable log rendering core extracted from LogPanel - SubProcessTable — btop-style process table with status dots - DroneMonitorGauge — canvas oscilloscope waveform (studio-equipment aesthetic) - DroneMonitor — 3-gauge container (CPU/red, NETWORK/cyan, FILE I/O/green) Frontend pages: - DroneManager: live log streaming, SubProcessTable, DroneMonitor gauges, 1-second polling, auto-scroll log with pause-on-scroll-up - Home/DroneInspector: process count summary, mini LogRenderer, navigate-to-manager link Documentation: - Updated gadget-drone/docs/subprocess.md Phase 2 section - Updated gadget-code/docs/ui-design-guide.md Phase 2 section - Updated docs/socket-protocol.md with new events, sequences, and patterns
457 lines
19 KiB
Markdown
457 lines
19 KiB
Markdown
# Gadget Code IDE Style Guide
|
|
|
|
Gadget Code is an Agentic Integrated Development Environment (AIDE). It is a tool for professional software developers and project managers to use in the creation of software applications and solutions, to include: code, documentation, configuration, etc.
|
|
|
|
The brand color is #c20600, a rich red. It is to be used when printing Gadget Code.
|
|
|
|
The Gadget Code IDE (hereafter: IDE) is an HTML5 web app building using the latest stable ReactJS 19 and Tailwind CSS 4. The IDE delivers only industrial and purposeful dark theme that uses mostly blacks, near-black, and dark gray with light gray and brand color highlights.
|
|
|
|
Information-dense status and property panels. Tight margins and padding.
|
|
|
|
This is NOT a consumer news blog with giant bloated hero sections, etc. We prefer flat material design with thoughtful borders that help the eye find the information and focus on it - not distract from it.
|
|
|
|
## Theme Colors
|
|
|
|
The IDE uses the following color palette (CSS custom properties):
|
|
|
|
```
|
|
--color-brand: #c20600
|
|
--color-bg-primary: #0a0a0a (main background - pure black)
|
|
--color-bg-secondary: #121212 (panels, sidebars)
|
|
--color-bg-tertiary: #1a1a1a (cards, dropdowns)
|
|
--color-bg-elevated: #202020 (hover states)
|
|
--color-text-primary: #d4d4d4 (main text)
|
|
--color-text-secondary: #a3a3a3 (muted text)
|
|
--color-text-muted: #737373 (disabled, hints)
|
|
--color-border-subtle: #1a1a1a (subtle dividers)
|
|
--color-border-default: #2a2a2a (default borders)
|
|
--color-border-highlight: #3a3a3a (emphasis borders)
|
|
```
|
|
|
|
Font stack:
|
|
|
|
- Primary: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif
|
|
- Code/Retro: Courier New, Courier, monospace
|
|
|
|
## View Layout (Whole Application)
|
|
|
|
The root element is given fixed positioning to fill the browser view entirely, and presents a full-width/full-height Flex column that spans the entire view.
|
|
|
|
```
|
|
#root {
|
|
height: 100vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
}
|
|
```
|
|
|
|
The top row is the header bar (48px). The 2nd row is the content area (flex-1). The 3rd/bottom row is the status bar (32px).
|
|
|
|
### Header Bar
|
|
|
|
The header bar is basically our "window title bar" like for a desktop application:
|
|
|
|
```
|
|
GADGET CODE v1.0.0 [Username ▼]
|
|
```
|
|
|
|
- Left: Application title + version using Courier New font
|
|
- Right: User dropdown menu (display name, click to open)
|
|
- Settings (placeholder)
|
|
- Logout
|
|
|
|
Implementation: `frontend/src/components/Header.tsx`
|
|
|
|
### Status Bar
|
|
|
|
The status bar displays:
|
|
|
|
```
|
|
Ready. my-project | BUILD | ●
|
|
```
|
|
|
|
- Left: Status message ("Ready." default)
|
|
- Center-right: Active project slug (when selected), Session mode (PLAN/BUILD/TEST/SHIP/DEV)
|
|
- Right: Connection indicator (● = connected, animates when healthy)
|
|
|
|
Implementation: `frontend/src/components/StatusBar.tsx`
|
|
|
|
### Content Area
|
|
|
|
Between the header and status bars is the Content Area. It uses React Router for URL-based navigation:
|
|
|
|
| Route | View |
|
|
| ----------------- | ------------------------------------------------- |
|
|
| `/` | Home (authenticated dashboard or unauthenticated) |
|
|
| `/projects` | Project Manager (list view) |
|
|
| `/projects/:slug` | Project Manager (project selected) |
|
|
| `/projects/new` | New project form |
|
|
| `/sign-in` | Sign in page |
|
|
| `/sign-out` | Signs out and redirects to `/` |
|
|
|
|
## Unauthenticated Home View
|
|
|
|
The logged-out home view displays a "System Ready" prompt dialog.
|
|
|
|
- Font: Courier New (monospace)
|
|
- Background: #0a0a0a (pure black)
|
|
- Boxed with 2px border using border-default color
|
|
- Sign In button
|
|
|
|
Users do not "sign up" for Gadget Code - accounts are administered via CLI (`pnpm cli`).
|
|
|
|
Implementation: `frontend/src/pages/Home.tsx` - SystemReady component
|
|
|
|
## Authenticated Home View (Dashboard)
|
|
|
|
The authenticated home view presents:
|
|
|
|
```
|
|
[Welcome, Username!]
|
|
Your dashboard is under construction.
|
|
Select a project or chat session from the sidebar to get started.
|
|
|
|
[Open Project Manager]
|
|
|
|
+---------------------------+-----------------------+
|
|
| | Clock (AM/PM) |
|
|
| Reserved for future | Date |
|
|
| dashboard content +-----------------------+
|
|
| | Projects [+] |
|
|
| | - project-1 |
|
|
| | - project-2 |
|
|
| +-----------------------+
|
|
| | Drones |
|
|
| | - drone-alpha ● |
|
|
| | - drone-beta ○ |
|
|
| +-----------------------+
|
|
| | Recent Chats |
|
|
| | (loading...) |
|
|
+---------------------------+-----------------------+
|
|
```
|
|
|
|
Components:
|
|
|
|
1. Clock - local time in AM/PM format, current date
|
|
2. Projects list - links to `/projects/:slug`, [+]/link navigates to `/projects`
|
|
3. Drones list - status indicator (green=available, yellow=busy, gray=offline)
|
|
4. Recent Chats - loading placeholder (stubbed, requires ChatSession API)
|
|
|
|
Implementation: `frontend/src/pages/Home.tsx` - DashboardSidebar component
|
|
|
|
### Drone Inspector (Dashboard Inline)
|
|
|
|
When a user clicks a drone in the sidebar's Drones list, the main content area switches to the **Drone Inspector**:
|
|
|
|
```
|
|
+-----------------------------------------------------+
|
|
| Drone Inspector ← Back to |
|
|
| Dashboard |
|
|
+-----------------------------------------------------+
|
|
| +-------------------------------------------------+ |
|
|
| | Hostname | |
|
|
| | drone-alpha (mono) | |
|
|
| +-------------------------------------------------+ |
|
|
| | Workspace | |
|
|
| | /path/to/workspace (mono) | |
|
|
| +-------------------------------------------------+ |
|
|
| | Status | |
|
|
| | ● available (or ● busy, ● offline) | |
|
|
| +-------------------------------------------------+ |
|
|
| | Registered | |
|
|
| | 5/14/2026, 10:00:00 AM | |
|
|
| +-------------------------------------------------+ |
|
|
+-----------------------------------------------------+
|
|
```
|
|
|
|
Implementation: `frontend/src/pages/Home.tsx` - DroneInspector component (lines 36-93)
|
|
|
|
The Drone Inspector is a simple read-only card view. For full drone operations (terminate, logs, monitoring), users navigate to the Drone Manager at `/drones` via the gear icon in the Drones sidebar header.
|
|
|
|
## Drone Manager View
|
|
|
|
Route: `/drones`
|
|
|
|
The Drone Manager is a full-page view for detailed drone inspection and operations. It replaces the main content area entirely.
|
|
|
|
Layout:
|
|
|
|
```
|
|
+----------------------------------+----------------------------------------+
|
|
| Drone Manager | Drone Details [Terminate] |
|
|
+----------------------------------+----------------------------------------+
|
|
| Online Drones (N) | +-----------+ +-----------+ |
|
|
| | | Hostname | | Status | |
|
|
| +----------------------------+ | | drone-1 | | ● busy | |
|
|
| | ● drone-1 available | | +-----------+ +-----------+ |
|
|
| | /path/to/workspace | | +-----------+ +-----------+ |
|
|
| +----------------------------+ | | Workspace | | Registered| |
|
|
| +----------------------------+ | | /path/... | | 5/14/2026 | |
|
|
| | ● drone-2 busy | | +-----------+ +-----------+ |
|
|
| | /path/to/workspace | | |
|
|
| +----------------------------+ | Drone Monitor |
|
|
| | +--------------------------------------+ |
|
|
| Offline Drones (N) | | Monitor charts coming soon. | |
|
|
| | | Memory usage, AI operations, and log | |
|
|
| +----------------------------+ | | production metrics will be displayed | |
|
|
| | ○ drone-3 offline | | | here. | |
|
|
| | /path/to/workspace | | +--------------------------------------+ |
|
|
| +----------------------------+ | |
|
|
| | Drone Log (Live) |
|
|
| | +--------------------------------------+ |
|
|
| | | [10:00:01] [PLACEHOLDER] Log entry 1 | |
|
|
| | | [10:00:02] [PLACEHOLDER] Log entry 2 | |
|
|
| | | [10:00:03] [PLACEHOLDER] Log entry 3 | |
|
|
| | | ... | |
|
|
| | +--------------------------------------+ |
|
|
+----------------------------------+----------------------------------------+
|
|
```
|
|
|
|
Current features (Phase 1):
|
|
|
|
- **Drone list** (left sidebar): Split into Online and Offline sections. Each list item shows status dot, hostname, and workspace path. Click to inspect.
|
|
- **Drone details** (right panel, top): 2x2 grid showing hostname, status with dot, workspace, registration date. Terminate button (red) for non-offline drones.
|
|
- **Drone Monitor** (right panel, middle): Placeholder for future monitoring charts.
|
|
- **Drone Log** (right panel, bottom): Collapsible panel with auto-scrolling log viewer. Log entries show timestamp and message. Auto-scroll pauses when user scrolls up, resumes when scrolled to bottom. Max 200 entries shown. Placeholder entries currently used, awaiting live log streaming.
|
|
|
|
Implementation: `frontend/src/pages/DroneManager.tsx`
|
|
|
|
### Phase 2: SubProcess Monitor (Complete)
|
|
|
|
Phase 2 was implemented on the `feature/process-management` branch. The Drone Manager and Drone Inspector now show live SubProcess data and drone logs via Socket.IO.
|
|
|
|
#### Socket Protocol
|
|
|
|
Three new socket events added (defined in `packages/api/src/messages/subprocess.ts`):
|
|
|
|
| Event | Direction | Purpose | Mechanism |
|
|
|-------|-----------|---------|-----------|
|
|
| `requestProcessStats` | IDE → Backend → Drone | Request typed subprocess list | Callback-chain (like `fileTreeRequest`) |
|
|
| `subscribeDrone` | IDE → Backend | Subscribe to live drone events (log, status) | Registers socket in monitor index |
|
|
| `unsubscribeDrone` | IDE → Backend | Unsubscribe from live drone events | Removes socket from monitor index |
|
|
|
|
Broadcast events (backend → IDE, no request needed):
|
|
|
|
| Event | Payload | When |
|
|
|-------|---------|------|
|
|
| `drone:log` | `{ timestamp, level, component, message, metadata? }` | On every drone `log` emission |
|
|
| `drone:status` | `{ timestamp, message }` | On every drone `status` emission |
|
|
|
|
#### SubProcess Table
|
|
|
|
Rendered by `frontend/src/components/SubProcessTable.tsx`. Features:
|
|
- Monospace table: PID, CMD, PROJECT, STATUS, UPDATED
|
|
- Status dots: green for running, yellow for halted, red for error
|
|
- Clickable rows with selection highlight
|
|
- Header shows running count: "SubProcess Monitor (3 running)"
|
|
- Empty state: "No managed subprocesses. The agent has not spawned any processes for this session."
|
|
|
|
#### Resource Gauges (Canvas)
|
|
|
|
Rendered by `frontend/src/components/DroneMonitor.tsx` + `DroneMonitorGauge.tsx`:
|
|
|
|
```
|
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
│ CPU │ │ NETWORK │ │ FILE I/O │
|
|
│ ▁▂▃▄▅▆▇█▇▆ │ │ ▁▂▃▄▅▆▇█▇▆ │ │ ▁▂▃▄▅▆▇█▇▆ │
|
|
│ 42% │ │ 27% │ │ 15% │
|
|
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
```
|
|
|
|
- Canvas-based waveform with glow effect (studio/scientific equipment aesthetic)
|
|
- Brand red for CPU, cyan for NETWORK, green for FILE I/O
|
|
- Grid lines, numeric readout, gradient fill under trace
|
|
- Data is currently simulated (random walk) — placeholder for real metrics
|
|
|
|
#### Live Log Streaming
|
|
|
|
The Drone Log viewer now receives real log events via socket instead of placeholders:
|
|
- Log events flow: `drone` → `DroneSession.onLog()` → broadcast to monitor sessions via `drone:log` event
|
|
- Uses the same `LogRenderer` component as the ChatSession `LogPanel` (refactored in Phase 2)
|
|
- Auto-scroll with pause-on-scroll-up behavior preserved
|
|
- Max 200 entries maintained
|
|
|
|
#### DroneInspector (Dashboard)
|
|
|
|
The inline Drone Inspector in the Home page (`frontend/src/pages/Home.tsx`):
|
|
- Shows SubProcess count summary ("3 running" or "No managed processes")
|
|
- Contains a compact `LogRenderer` (last 50 entries, max-h-48)
|
|
- "Open in Drone Manager →" link navigates to `/drones` with route state for auto-selection
|
|
|
|
#### Polling Behavior
|
|
|
|
- `requestProcessStats` polled every **1 second** while a drone is selected (both DroneManager and DroneInspector)
|
|
- Subscribe/unsubscribe lifecycle tied to component mount/unmount
|
|
- All timers and socket listeners cleaned up on unmount or drone deselection
|
|
|
|
#### Supporting Components
|
|
|
|
| Component | File | Purpose |
|
|
|-----------|------|---------|
|
|
| `SubProcessTable` | `frontend/src/components/SubProcessTable.tsx` | Process list table |
|
|
| `DroneMonitor` | `frontend/src/components/DroneMonitor.tsx` | 3-gauge resource monitor container |
|
|
| `DroneMonitorGauge` | `frontend/src/components/DroneMonitorGauge.tsx` | Canvas waveform gauge |
|
|
| `LogRenderer` | `frontend/src/components/LogRenderer.tsx` | Reusable log rendering core |
|
|
|
|
#### Backend Routing
|
|
|
|
- `SocketService.addDroneMonitor()` / `removeDroneMonitor()` — manages monitor index (`Map<registrationId, Set<socketId>>`)
|
|
- `SocketService.broadcastToMonitors()` — broadcasts events to all monitoring sockets
|
|
- `SocketService.getDroneSessionByRegistrationId()` — lookup for non-chat-session drone routing
|
|
- `DroneSession.onLog()` / `onStatus()` — extended to broadcast to monitors after chat-session routing
|
|
- `CodeSession.onRequestProcessStats()` — proxies to drone with callback
|
|
- `CodeSession.onSubscribeDrone()` / `onUnsubscribeDrone()` — registers/unregisters monitor
|
|
|
|
## Project Manager View
|
|
|
|
The Project Manager presents:
|
|
|
|
```
|
|
+---------------------------+----------------------------------+
|
|
| [New Project] | Project Inspector |
|
|
|---------------------------| |
|
|
| Projects (2) | Select a project to view details |
|
|
| [project-one ] | or create a new project |
|
|
| [project-two ] | |
|
|
| | |
|
|
+---------------------------+----------------------------------+
|
|
```
|
|
|
|
When a project is selected:
|
|
|
|
```
|
|
+---------------------------+---------------------------------+
|
|
| [New Project] | Project Inspector |
|
|
|---------------------------| |
|
|
| Projects (2) | Name: project-one |
|
|
| [project-one ●] | Slug: project-one |
|
|
| [project-two ] | Git URL: https://github.com/... |
|
|
| | Status: active |
|
|
| | Created: 2026-04-28 |
|
|
| | |
|
|
| | [Delete Project] |
|
|
| +---------------------------------+
|
|
| | Chat Sessions |
|
|
| | (loading...) |
|
|
+---------------------------+---------------------------------+
|
|
```
|
|
|
|
Features:
|
|
|
|
- Left sidebar: Project list with [+ New Project] button
|
|
- Project Inspector: Shows name, slug, gitUrl, status, createdAt
|
|
- Delete: Confirmation before deletion
|
|
- Chat Sessions placeholder (requires ChatSession API)
|
|
|
|
URL-based: `/projects` (list), `/projects/:slug` (selected)
|
|
|
|
Implementation: `frontend/src/pages/ProjectManager.tsx`
|
|
|
|
### New Project Form
|
|
|
|
Triggered by [New Project] button or `/projects/new` route:
|
|
|
|
- Fields: Project Name*, Project Slug*, Git Repository URL
|
|
- Slug tip: "Unique identifier for the project directory"
|
|
- Submit: "Create Project" button (brand color)
|
|
- Cancel: Returns to project list
|
|
|
|
## Authentication
|
|
|
|
### Frontend Token Management
|
|
|
|
- Token stored in localStorage: `dtp_auth_token`
|
|
- User stored in localStorage: `dtp_user`
|
|
- Project stored in localStorage: `dtp_current_project`
|
|
|
|
### API Requests
|
|
|
|
All API requests include the JWT in the Authorization header:
|
|
|
|
```typescript
|
|
headers["Authorization"] = `Bearer ${token}`;
|
|
```
|
|
|
|
### Backend Session Restoration
|
|
|
|
The backend restores user sessions from:
|
|
|
|
1. `Authorization: Bearer <token>` header (JWT)
|
|
2. Express session (fallback)
|
|
|
|
The `requireUser()` middleware ensures endpoints are authenticated.
|
|
|
|
## Security
|
|
|
|
### Password Field Handling
|
|
|
|
Password credentials are NEVER exposed:
|
|
|
|
- Mongoose `select: false` on password fields in models
|
|
- Population uses `select: "-passwordSalt -password"` to exclude from queries
|
|
- Frontend User interface only includes: `_id`, `email`, `displayName`, `flags`
|
|
|
|
## Chat Session View (Planned)
|
|
|
|
The Chat Session View presents:
|
|
|
|
```
|
|
Work Area | Session Status
|
|
----------------------------------------------|---------------
|
|
Chat Messages | Chat: name
|
|
| ID: ...
|
|
| Model: ...
|
|
----------------------------------------------|---------------
|
|
[Prompt input ][Expand][Send]| TC | FO | SA
|
|
----------------------------------------------|---------------
|
|
Log | Files
|
|
|
|
|
```
|
|
|
|
Implemented components:
|
|
|
|
- Chat Messages (stubbed)
|
|
- Prompt Input (stubbed)
|
|
- Session Status sidebar (stubbed)
|
|
- File Browser (stubbed)
|
|
|
|
## Mobile Devices and Responsive Design
|
|
|
|
Nope. Gadget Code is a desktop workstation experience with one or more high-resolution displays, keyboard, mouse, webcam, microphone, and ample networking. There is no planned support for mobile devices.
|
|
|
|
Buttons are normal-sized, not bloated for finger use.
|
|
|
|
## Accessibility
|
|
|
|
The IDE wants to be as accessible as possible, providing aria tags as much as possible. Build first with an eye toward accessibility, then take a 2nd pass after the build is accepted to add accessibility enhancements.
|
|
|
|
## Tests
|
|
|
|
### Unit Tests
|
|
|
|
Location: `tests/**/*.test.ts` (excluding `tests/e2e/`)
|
|
|
|
Run: `pnpm test`
|
|
|
|
### E2E Tests
|
|
|
|
Location: `tests/e2e/**/*.test.ts`
|
|
|
|
Run: `npx playwright test`
|
|
|
|
Prerequisites: Running `pnpm dev:backend` and `pnpm dev:frontend`
|
|
|
|
Target: `https://code-dev.g4dge7.com:5174`
|
|
|
|
## Build Commands
|
|
|
|
```bash
|
|
cd gadget-code
|
|
pnpm dev:backend # Backend on https://localhost:3443
|
|
pnpm dev:frontend # Frontend on https://localhost:5174
|
|
pnpm build # Build all (backend -> dist/, frontend -> frontend/dist/)
|
|
pnpm test # Unit tests
|
|
npx playwright test # E2E tests
|
|
```
|