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
19 KiB
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:
- Clock - local time in AM/PM format, current date
- Projects list - links to
/projects/:slug, [+]/link navigates to/projects - Drones list - status indicator (green=available, yellow=busy, gray=offline)
- 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 viadrone:logevent - Uses the same
LogRenderercomponent as the ChatSessionLogPanel(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
/droneswith route state for auto-selection
Polling Behavior
requestProcessStatspolled 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 socketsSocketService.getDroneSessionByRegistrationId()— lookup for non-chat-session drone routingDroneSession.onLog()/onStatus()— extended to broadcast to monitors after chat-session routingCodeSession.onRequestProcessStats()— proxies to drone with callbackCodeSession.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:
headers["Authorization"] = `Bearer ${token}`;
Backend Session Restoration
The backend restores user sessions from:
Authorization: Bearer <token>header (JWT)- Express session (fallback)
The requireUser() middleware ensures endpoints are authenticated.
Security
Password Field Handling
Password credentials are NEVER exposed:
- Mongoose
select: falseon 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
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