Skip to content

Commit 1398c9c

Browse files
committed
feat: v0.2.0 stabilization - security, perf, UX, tests, GitPanel decomp
Security: - sandbox: true in production, bypassCSP removed from protocols - will-navigate blocked, terminal cwd validated, PID kill allowlisted - All 74 IPC handlers migrated to ipcHandler factory Performance: - All filesystem I/O async (fs.promises), execSync replaced - Individual Zustand selectors in TerminalPanel - visibleTerminals memoized, editor sync filtered to non-dirty files UX: - GitPanel decomposed into 5 sub-components (StagingArea, CommitBar, BranchSelector, CommitLog) with lightweight refreshStatus - Confirmation dialogs on destructive actions - Separate Commit vs Push buttons, emoji replaced with SVG - Tool Run stays on panel, double-click guard, agent launcher active state - File click auto-switches to editor from any panel Tests: - 72 new tests (pathValidation, WalletService, EnvService, McpConfig, ToolService) - 92/92 total passing Infrastructure: - Plugin context system (PluginContextRegistry, PluginPrompt, IPC bridge) - Browser and Gmail plugin scaffolding - Planning docs for v0.2.0 milestone
1 parent 11292ee commit 1398c9c

29 files changed

Lines changed: 3856 additions & 11 deletions

.planning/MILESTONES.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Milestones
2+
3+
## v0.1.0 -- Initial Build (Completed 2026-03-31)
4+
5+
**Phases 1-8:** Shell, Agent Launcher, Claude Panel, Process Manager, Env Manager, Ports, Git, Wallet
6+
**Refactoring Phases 1-10:** IPC Factory, Types, Zustand helpers, ErrorRecovery, ResourceManager, Saga, Logging, Code Splitting, Validation, DB Migrations
7+
8+
**Shipped:**
9+
- Full IDE with Monaco + terminal + file explorer + project tabs
10+
- Agent system with Claude Code CLI spawning
11+
- 10 production infrastructure services
12+
- Settings, Tools, Onboarding panels
13+
- GitHub Actions CI/CD + release workflow
14+
- 20/20 tests passing, 0 TypeScript errors
15+
16+
**Last phase number:** 10 (refactoring)

.planning/PROJECT.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# DAEMON
2+
3+
**Type:** Electron IDE for AI-native development
4+
**Owner:** nullxnothing
5+
**Repo:** github.com/nullxnothing/daemon
6+
7+
## Core Value
8+
9+
A single-window IDE where solo developers ship with AI agents. Monaco editor, PTY terminals, Claude Code agent spawning, MCP management, Solana wallet, plugin system.
10+
11+
## Current Milestone: v0.2.0 Stabilization & Production Hardening
12+
13+
**Goal:** Address all findings from 7-agent audit (debugger, UX, code reviewer, performance, security, React, test coverage) to make DAEMON release-ready.
14+
15+
**Target outcomes:**
16+
- Zero critical/high audit findings remaining
17+
- Test coverage for all security-critical paths
18+
- Lazy-loaded panels with code splitting
19+
- Async I/O throughout main process
20+
- GitPanel decomposed into maintainable sub-components
21+
- File content decoupled from openFiles store array
22+
23+
## Validated Requirements (Already Built)
24+
25+
- Shell: Monaco editor, node-pty terminals, SQLite, file explorer, project tabs
26+
- Agent Launcher: CRUD, spawn Claude Code CLI, terminal tabs with agent names
27+
- Claude Panel: MCP management per project + global, usage stats, CLAUDE.md tools
28+
- Process Manager, Env Manager, Ports Panel, Git Panel, Wallet Panel
29+
- Settings Panel (API Keys, Integrations, Agents, Display)
30+
- Tools Panel (browser, create, run, import)
31+
- Production infrastructure (ErrorRecovery, ResourceManager, SagaOrchestrator, LogService, ValidationService)
32+
- CI/CD: GitHub Actions for typecheck + test + build, release workflow
33+
- Security: CSP headers, path validation, terminal cwd validation, PID allowlist
34+
35+
## Tech Stack
36+
37+
Electron 33, React 18, TypeScript, Vite, Monaco Editor, node-pty + xterm.js, Zustand, better-sqlite3, simple-git, electron-builder
38+
39+
## Last updated: 2026-03-31

.planning/REQUIREMENTS.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Requirements -- Milestone v0.2.0 Stabilization
2+
3+
## Performance
4+
5+
- [ ] **PERF-01**: Lazy-load all non-default panels with React.lazy + Suspense (EditorPanel and TerminalPanel stay eager)
6+
- [ ] **PERF-02**: Split Monaco and xterm into separate vendor chunks via Vite manualChunks
7+
- [ ] **PERF-03**: Replace all sync filesystem I/O in main process with async equivalents (fs.promises)
8+
- [ ] **PERF-04**: GitPanel uses lightweight refreshStatus() (status only) after stage/unstage instead of full 4-IPC reload
9+
- [ ] **PERF-05**: Decouple file content from openFiles Zustand array into a separate Map to eliminate expensive clones per keystroke
10+
11+
## Memory
12+
13+
- [ ] **MEM-01**: Dispose all Monaco models for a project when that project is removed or switched away
14+
- [ ] **MEM-02**: Cap viewStateCache at 50 entries with LRU eviction
15+
16+
## Security
17+
18+
- [ ] **SEC-01**: Add sandbox: true to BrowserWindow webPreferences and verify preload still works
19+
- [ ] **SEC-02**: Remove bypassCSP: true from monaco-editor and daemon-icon protocol registrations
20+
- [ ] **SEC-03**: Add will-navigate handler on webContents to block all navigation away from app origin
21+
22+
## React Stability
23+
24+
- [ ] **REACT-01**: Add cancellation guards to all async IPC calls in useEffect (agents list, skills section, usage section)
25+
- [ ] **REACT-02**: Wrap TerminalView in React.memo to prevent unnecessary re-renders in split pane layout
26+
- [ ] **REACT-03**: Replace ternary chain in App.tsx center-area routing with a lookup map
27+
28+
## UX Polish
29+
30+
- [ ] **UX-01**: Add confirmation dialogs before destructive actions (API key delete, tool delete, branch checkout with uncommitted changes)
31+
- [ ] **UX-02**: Add standalone "Commit" button separate from "Commit & Push" in GitPanel
32+
- [ ] **UX-03**: Replace emoji wand button in GitPanel with SVG icon
33+
- [ ] **UX-04**: Show placeholder in branch selector during initial load
34+
- [ ] **UX-05**: Display "No tidy changes" as neutral info message, not error
35+
- [ ] **UX-06**: Tool "Run" action stays on Tools panel instead of navigating to Claude
36+
- [ ] **UX-07**: Add startingToolIds guard to prevent double-click spawning two terminals
37+
- [ ] **UX-08**: Agent Launcher sidebar button shows active state when launcher is open
38+
39+
## Code Quality
40+
41+
- [ ] **CODE-01**: Decompose GitPanel into sub-components (StagingArea, CommitBar, BranchSelector, StashControls, CommitLog)
42+
- [ ] **CODE-02**: Migrate remaining IPC handlers (filesystem, wallet, recovery, claude, env, ports, processes, settings, tweets, plugins) to ipcHandler factory
43+
44+
## Test Coverage
45+
46+
- [ ] **TEST-01**: pathValidation.test.ts -- path traversal, prefix attacks, empty projects, Windows normalization
47+
- [ ] **TEST-02**: WalletService.test.ts -- address validation, default promotion on delete, project assignment
48+
- [ ] **TEST-03**: EnvService.test.ts -- parse/write roundtrip, quote handling, export prefix, secret detection
49+
- [ ] **TEST-04**: McpConfig.test.ts -- toggle/restore, corrupted JSON resilience, project vs global isolation
50+
- [ ] **TEST-05**: ToolService.test.ts -- scaffold, import validation, deleteTool rmSync safety, buildRunCommand per language
51+
52+
## Traceability
53+
54+
| Requirement | Phase |
55+
|-------------|-------|
56+
| PERF-01..05 | TBD |
57+
| MEM-01..02 | TBD |
58+
| SEC-01..03 | TBD |
59+
| REACT-01..03 | TBD |
60+
| UX-01..08 | TBD |
61+
| CODE-01..02 | TBD |
62+
| TEST-01..05 | TBD |
63+
64+
## Future (Out of Scope for v0.2.0)
65+
66+
- Lazy-load the MonacoEditor component itself (complex due to worker setup)
67+
- Batch IPC calls into single project:switch handler
68+
- Move file content to IndexedDB for truly large files
69+
- Redis-backed rate limiting for IPC
70+
- Full e2e test suite with Playwright against packaged app

.planning/STATE.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# State
2+
3+
## Current Position
4+
5+
Phase: Not started (defining requirements)
6+
Plan: --
7+
Status: Defining requirements from 7-agent audit
8+
Last activity: 2026-03-31 -- Milestone v0.2.0 started
9+
10+
## Accumulated Context
11+
12+
### Decisions
13+
- All internal planning docs removed from public repo (gitignored)
14+
- CI/CD set up with GitHub Actions (typecheck + test + build + release)
15+
- Git author set to nullxnothing for all commits
16+
- Conventional commits enforced
17+
18+
### Audit Findings (Source)
19+
- Round 1: Debugger (7 bugs), UX Optimizer (28 issues), Code Reviewer (19 findings)
20+
- Round 2: Performance (13 findings), Security (17 findings), React (11 findings), Test Coverage (10 priority test files)
21+
- Critical/High items from rounds 1+2 already fixed in commits 3b6119f and 11292ee
22+
- Remaining items are medium/low priority - this milestone addresses them systematically

.planning/config.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"commit_docs": true,
3+
"model_profile": "balanced"
4+
}

PLUGIN_TODOS.md

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Plugin Implementation TODOs
2+
3+
Each plugin has a **context** (AI persona, templates, skills) and a **service** (IPC, business logic, UI).
4+
Context system is complete for all 9 plugins. Service/UI work remains per plugin.
5+
6+
---
7+
8+
## Phase 9: Image Generator (imagegen)
9+
- [x] Plugin context registered (system prompt, templates: generate/refine, skills: photo-real/ui-mockup/logo-icon)
10+
- [x] Plugin registered in PLUGIN_REGISTRY
11+
- [ ] ImageGenService — call Gemini imagen-4 API for generation
12+
- [ ] Wire pluginPrompt('imagegen', 'generate') for prompt refinement before sending to imagen
13+
- [ ] IPC handlers: imagegen:generate, imagegen:list, imagegen:delete
14+
- [ ] Preload bridge: window.daemon.imagegen.*
15+
- [ ] UI: prompt input, style/ratio selectors, gallery grid, image preview
16+
- [ ] Save generated images to images table + ~/.daemon/images/
17+
- [ ] Saga orchestration: generate prompt → call imagen → save file → insert DB
18+
19+
## Phase 10: Gmail Code Catcher (gmail)
20+
- [x] Plugin context registered (system prompt, templates: extract/summarize, skills: code-detect/action-items)
21+
- [x] Plugin registered in PLUGIN_REGISTRY
22+
- [x] GmailService — OAuth2 flow via Google API (tokens in oauth_tokens table via safeStorage)
23+
- [x] Wire pluginPrompt('gmail', 'extract') to parse email bodies
24+
- [x] IPC handlers: gmail:auth-status, gmail:auth, gmail:exchange-code, gmail:logout, gmail:list, gmail:read, gmail:extract, gmail:summarize
25+
- [x] Preload bridge: window.daemon.gmail.*
26+
- [x] UI: auth flow (credentials + code exchange), inbox list, email viewer, extract + summarize buttons, extraction cards with copy
27+
- [x] Saga orchestration: extract code via orchestratedPrompt
28+
- [ ] Auto-detect code in new emails, surface in morning briefing
29+
- [ ] Onboarding: Gmail OAuth setup during first-run
30+
31+
## Phase 11: Tweet Generator (tweet-generator)
32+
- [x] Plugin context registered (system prompt, templates: original/reply/quote/thread, skills: ct-voice/solana-context/engagement-hooks/thread-craft)
33+
- [x] TweetService refactored to use pluginPrompt + SagaOrchestrator
34+
- [x] Voice profile reads from plugin context (falls back to legacy DB)
35+
- [x] IPC handlers complete
36+
- [x] Preload bridge complete
37+
- [x] UI: TweetGenerator, VoiceProfileEditor, TweetVariations, DraftList
38+
- [ ] Thread generation UI (uses 'thread' template, not yet wired)
39+
- [ ] Plugin context editor UI (toggle skills, edit system prompt from Settings)
40+
- [ ] Scheduled tweet drafts (morning batch generation)
41+
42+
## Phase 12: Subscription Manager (subscriptions)
43+
- [x] Plugin context registered (system prompt, templates: analyze-usage/cost-alert/compare-plans, skills: usage-tracking/cost-optimization/overage-prediction)
44+
- [x] Plugin registered in PLUGIN_REGISTRY
45+
- [x] DB table: subscriptions (id, name, monthly_cost, renewal_day, usage_limit, usage_current, alert_at, url, api_key_hint)
46+
- [ ] SubscriptionService — CRUD + usage tracking + alert logic
47+
- [ ] Wire pluginPrompt('subscriptions', 'analyze-usage') for monthly reports
48+
- [ ] Wire pluginPrompt('subscriptions', 'cost-alert') for overage warnings
49+
- [ ] IPC handlers: subscriptions:list, subscriptions:add, subscriptions:update, subscriptions:delete, subscriptions:analyze
50+
- [ ] Preload bridge: window.daemon.subscriptions.*
51+
- [ ] UI: subscription list, add/edit modal, usage bars, cost breakdown chart
52+
- [ ] Alert integration with morning briefing (flag services approaching limits)
53+
54+
## Phase 13: Remotion Panel (remotion)
55+
- [x] Plugin context registered (full production formula hardwired, templates: scene/composition/animate/terminal-demo/encode, 10 skills)
56+
- [x] Plugin registered in PLUGIN_REGISTRY
57+
- [ ] RemotionService — manage localhost Remotion studio, render pipeline
58+
- [ ] Wire pluginPrompt('remotion', 'scene') for AI scene generation
59+
- [ ] Wire pluginPrompt('remotion', 'composition') for full video scaffolding
60+
- [ ] Wire pluginPrompt('remotion', 'encode') for ffmpeg command generation
61+
- [ ] IPC handlers: remotion:render, remotion:preview, remotion:generate-scene, remotion:list-compositions
62+
- [ ] Preload bridge: window.daemon.remotion.*
63+
- [ ] UI: composition browser, scene editor, render queue, preview iframe
64+
- [ ] CompanionPanel (already in registry) — timeline, props editor
65+
- [ ] Saga orchestration: generate scene → write file → preview → render → encode
66+
67+
## Phase 14: Browser + Playwright CDP (browser)
68+
- [x] Plugin context registered (system prompt, templates: summarize-page/extract-data/compare-pages/audit-page, skills: content-extract/page-diff/security-recon/screenshot-analysis)
69+
- [x] Plugin registered in PLUGIN_REGISTRY
70+
- [x] BrowserService — fetch-based navigation, page caching, AI analysis via pluginPrompt
71+
- [x] Wire pluginPrompt('browser', 'summarize-page') for page analysis
72+
- [x] Wire pluginPrompt('browser', 'audit-page') for security recon
73+
- [x] IPC handlers: browser:navigate, browser:content, browser:analyze, browser:audit, browser:history, browser:clear
74+
- [x] Preload bridge: window.daemon.browser.*
75+
- [x] UI: URL bar, page info, summarize/extract/audit buttons, content/analysis/history tabs, history list
76+
- [x] Saga orchestration: analysis via orchestratedPrompt
77+
- [ ] Playwright CDP integration (port 9222) for interactive automation
78+
- [ ] Embedded webview for visual browsing (currently fetch-only)
79+
- [ ] Screenshot capture + visual analysis
80+
- [ ] Page diff tracking (compare states before/after actions)
81+
- [ ] Onboarding: optional Playwright setup during first-run
82+
83+
## Phase 15: Context Bridge Extension
84+
- [ ] VS Code extension that syncs DAEMON context to editor
85+
- [ ] Bi-directional: editor selections → DAEMON plugins, DAEMON outputs → editor
86+
- [ ] No plugin context needed (bridge, not AI consumer)
87+
88+
---
89+
90+
## Future Plugins
91+
92+
### Telegram (telegram)
93+
- [x] Plugin context registered (system prompt, templates: compose/summarize-chat/reply/announcement, skills: ct-tone/dev-tone/chat-summary/formatting)
94+
- [x] Plugin registered in PLUGIN_REGISTRY
95+
- [ ] TelegramService — connect via telegram-user MCP or TDLib
96+
- [ ] Wire pluginPrompt('telegram', 'compose') for message drafting
97+
- [ ] Wire pluginPrompt('telegram', 'summarize-chat') for conversation digests
98+
- [ ] IPC handlers: telegram:dialogs, telegram:read, telegram:send, telegram:summarize
99+
- [ ] Preload bridge: window.daemon.telegram.*
100+
- [ ] UI: dialog list, chat view, compose panel, channel management
101+
- [ ] Integration with morning briefing (overnight message summaries)
102+
103+
### Morning Briefing (morning-briefing)
104+
- [x] Plugin context registered (system prompt, templates: digest/prioritize, skills: error-triage/git-summary)
105+
- [x] Plugin registered in PLUGIN_REGISTRY
106+
- [ ] BriefingService — aggregate overnight data from all sources
107+
- [ ] Wire pluginPrompt('morning-briefing', 'digest') for overnight compilation
108+
- [ ] Wire pluginPrompt('morning-briefing', 'prioritize') for task ranking
109+
- [ ] IPC handlers: briefing:generate, briefing:history, briefing:dismiss
110+
- [ ] Preload bridge: window.daemon.briefing.*
111+
- [ ] UI: overlay panel (already mounted as 'overlay' position), dismiss/snooze
112+
- [ ] Data sources: error_logs, git activity, crash_history, overnight_runs, telegram, gmail
113+
- [ ] DB table: overnight_runs (exists) — link briefings to run data
114+
115+
### Services Panel (services)
116+
- [x] Plugin context registered (system prompt, templates: diagnose-crash/health-report/suggest-config/log-analysis, skills: crash-analysis/auto-fix/resource-monitor/log-parsing)
117+
- [x] Plugin registered in PLUGIN_REGISTRY
118+
- [x] DB tables: services, crash_history (exist)
119+
- [ ] ServicesService — start/stop/restart, health checks, log capture
120+
- [ ] Wire pluginPrompt('services', 'diagnose-crash') for crash analysis
121+
- [ ] Wire pluginPrompt('services', 'log-analysis') for pattern detection
122+
- [ ] IPC handlers: services:list, services:start, services:stop, services:logs, services:diagnose
123+
- [ ] Preload bridge: window.daemon.services.*
124+
- [ ] UI: service list with status dots, log viewer, crash history, config editor
125+
- [ ] Auto-restart with crash analysis before retry
126+
- [ ] Saga orchestration: detect crash → analyze logs → suggest fix → optionally auto-apply → restart
127+
128+
---
129+
130+
## Cross-Plugin Infrastructure (Complete)
131+
- [x] PluginContextRegistry — register/get/update/toggle/reset per plugin
132+
- [x] PluginPrompt — template interpolation, skill injection, ClaudeRouter routing
133+
- [x] SagaOrchestrator — multi-step operations with compensation/rollback
134+
- [x] orchestratedPrompt() — wraps pluginPrompt in saga steps
135+
- [x] plugin_contexts DB table (V9 migration)
136+
- [x] IPC: plugin-context:get/update/toggle-skill/reset/list
137+
- [x] Preload: window.daemon.plugins.contextGet/Update/ToggleSkill/Reset/List
138+
- [x] Type declarations: PluginContextConfig, PluginSkill, PromptTemplate
139+
- [ ] Plugin Context Editor UI — settings panel to edit system prompts, toggle skills, switch models per plugin

electron/ipc/browser.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { ipcMain } from 'electron'
2+
import {
3+
navigate,
4+
getPage,
5+
getLatestPage,
6+
analyzePage,
7+
auditPage,
8+
getHistory,
9+
clearHistory,
10+
} from '../services/BrowserService'
11+
import { ipcHandler } from '../services/IpcHandlerFactory'
12+
13+
export function registerBrowserHandlers() {
14+
ipcMain.handle('browser:navigate', ipcHandler(async (_event, url: string) => {
15+
return await navigate(url)
16+
}))
17+
18+
ipcMain.handle('browser:content', ipcHandler(async (_event, pageId: string) => {
19+
const page = getPage(pageId) ?? getLatestPage()
20+
if (!page) throw new Error('No page loaded')
21+
return page
22+
}))
23+
24+
ipcMain.handle('browser:analyze', ipcHandler(async (
25+
_event,
26+
pageId: string,
27+
type: 'summarize' | 'extract' | 'audit' | 'compare',
28+
target?: string,
29+
) => {
30+
return await analyzePage(pageId, type, target)
31+
}))
32+
33+
ipcMain.handle('browser:audit', ipcHandler(async (_event, pageId: string) => {
34+
return await auditPage(pageId)
35+
}))
36+
37+
ipcMain.handle('browser:history', ipcHandler(async () => {
38+
return getHistory()
39+
}))
40+
41+
ipcMain.handle('browser:clear', ipcHandler(async () => {
42+
clearHistory()
43+
}))
44+
}

electron/ipc/gmail.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { ipcMain } from 'electron'
2+
import {
3+
getAuthStatus,
4+
authenticate,
5+
exchangeAuthCode,
6+
logout,
7+
listMessages,
8+
readMessage,
9+
extractCode,
10+
summarizeMessage,
11+
} from '../services/GmailService'
12+
import { ipcHandler } from '../services/IpcHandlerFactory'
13+
14+
export function registerGmailHandlers() {
15+
ipcMain.handle('gmail:auth-status', ipcHandler(async () => {
16+
return await getAuthStatus()
17+
}))
18+
19+
ipcMain.handle('gmail:auth', ipcHandler(async (_event, clientId: string, clientSecret: string) => {
20+
return await authenticate(clientId, clientSecret)
21+
}))
22+
23+
ipcMain.handle('gmail:exchange-code', ipcHandler(async (_event, code: string) => {
24+
return await exchangeAuthCode(code)
25+
}))
26+
27+
ipcMain.handle('gmail:logout', ipcHandler(async () => {
28+
logout()
29+
}))
30+
31+
ipcMain.handle('gmail:list', ipcHandler(async (_event, query?: string, maxResults?: number) => {
32+
return await listMessages(query, maxResults)
33+
}))
34+
35+
ipcMain.handle('gmail:read', ipcHandler(async (_event, messageId: string) => {
36+
return await readMessage(messageId)
37+
}))
38+
39+
ipcMain.handle('gmail:extract', ipcHandler(async (_event, messageId: string) => {
40+
return await extractCode(messageId)
41+
}))
42+
43+
ipcMain.handle('gmail:summarize', ipcHandler(async (_event, messageId: string) => {
44+
const summary = await summarizeMessage(messageId)
45+
return { summary }
46+
}))
47+
}

0 commit comments

Comments
 (0)