- Introduced new planning files including PROJECT.md, REQUIREMENTS.md, ROADMAP.md, and STATE.md to outline the vision and requirements for SSH multi-context workspaces. - Added ARCHITECTURE.md and CONCERNS.md to detail the codebase structure and address technical debt, known bugs, and security considerations. - Created CONVENTIONS.md to establish coding standards and practices for the project. - Updated .gitignore to exclude demo files and added configuration for planning tools. This commit lays the groundwork for enhancing SSH functionality and user experience in managing multiple workspaces.
17 KiB
Codebase Concerns
Analysis Date: 2026-02-12
Tech Debt
Large, complex files needing refactoring:
- Issue: Several files exceed 700-1100 lines with complex business logic
- Files:
src/renderer/utils/contextTracker.ts(1099 lines)src/main/services/discovery/ProjectScanner.ts(827 lines)src/main/services/infrastructure/FileWatcher.ts(798 lines)src/renderer/components/chat/ChatHistory.tsx(745 lines)src/renderer/store/slices/tabSlice.ts(740 lines)src/main/services/infrastructure/ConfigManager.ts(701 lines)src/renderer/utils/groupTransformer.ts(700 lines)src/main/services/parsing/GitIdentityResolver.ts(674 lines)src/renderer/store/slices/sessionDetailSlice.ts(658 lines)src/main/services/infrastructure/NotificationManager.ts(657 lines)src/renderer/utils/claudeMdTracker.ts(656 lines)src/main/ipc/config.ts(628 lines)
- Impact: Difficult to maintain, test, and debug; high cognitive load for changes
- Fix approach: Extract into smaller modules with single responsibilities; split contextTracker into separate concerns (injection detection, stats computation, phase tracking); break ConfigManager into domain-specific config handlers; split ChatHistory view logic from virtualization/scroll management
Type safety gaps with as any and as unknown casts:
- Issue: Type assertions bypass TypeScript's type checking
- Files:
src/main/services/infrastructure/SshConnectionManager.ts:171-sftp as anyfor SSH providersrc/main/services/infrastructure/SshFileSystemProvider.ts:44-data as unknown as stringsrc/main/services/infrastructure/NotificationManager.ts:170-JSON.parse(data) as unknownsrc/main/services/discovery/ProjectScanner.ts:659-JSON.parse(content) as unknownsrc/main/services/analysis/ToolResultExtractor.ts:140-content as unknown[]src/main/services/analysis/SemanticStepExtractor.ts:169-msg.toolUseResult as unknownsrc/main/utils/jsonl.ts:450-entry as unknown as Record<string, unknown>- Test files: Extensive use in
test/main/services/infrastructure/FileWatcher.test.tsfor mocking
- Impact: Potential runtime type errors; bypasses compiler safety net
- Fix approach: Create proper type guards and validation functions; use Zod schemas for JSON parsing; properly type SSH2/SFTP library interfaces instead of
any
Empty catch blocks silently swallowing errors:
- Issue: 213 try/catch occurrences across 62 files, many with minimal error handling
- Files: All IPC handlers, store slices, service files
- Impact: Silent failures make debugging difficult; errors may go unnoticed
- Fix approach: Add structured logging to all catch blocks; implement error telemetry; ensure all errors bubble up or are explicitly handled with user feedback
SSH connection type safety issues:
- Issue: SSH2 library types not properly integrated, forcing
anycasts - Files:
src/main/services/infrastructure/SshConnectionManager.ts,src/main/services/infrastructure/SshFileSystemProvider.ts - Impact: Runtime errors in SSH operations won't be caught at compile time
- Fix approach: Create proper TypeScript interfaces for SSH2/SFTP types; use branded types or runtime validation
Disabled ESLint rules indicate code smells:
- Issue: 30+ eslint-disable comments suggest underlying design issues
- Files:
src/renderer/components/chat/ChatHistory.tsx:417,425- Direct DOM mutation for search highlightingsrc/renderer/components/chat/AIChatGroup.tsx:195- Manual memoization instead of React Compilersrc/renderer/hooks/useAutoScrollBottom.ts:144,178,204,247- Complex effect dependenciessrc/renderer/components/sidebar/DateGroupedSessions.tsx:157- TanStack Virtual API limitationsrc/renderer/utils/groupTransformer.ts:57- Regex flagged as potentially unsafe
- Impact: Code may be fragile or have performance issues
- Fix approach: Refactor direct DOM mutations into proper React state management; simplify effect dependencies; document why ESLint rules must be disabled
Known Bugs
None explicitly documented in code:
- Symptoms: No TODO/FIXME/HACK/BUG comments found in source
- Trigger: N/A
- Workaround: N/A
Security Considerations
IPC input validation present but could be stricter:
- Risk: Malformed IPC inputs could cause crashes or unexpected behavior
- Files:
src/main/ipc/guards.ts, all IPC handlers insrc/main/ipc/ - Current mitigation: Validation guards with max length checks (128-512 chars), pattern validation, coercion for numeric inputs
- Recommendations:
- Add rate limiting on IPC calls to prevent DOS
- Validate file paths more strictly to prevent directory traversal
- Add schema validation for complex config objects (use Zod)
Content sanitization exists but not comprehensive:
- Risk: User-provided content from JSONL files could contain malicious content
- Files:
src/shared/utils/contentSanitizer.ts- sanitizes display content, removes control characters - Current mitigation: Basic content sanitization with regex pattern removal
- Recommendations:
- Add HTML escaping for any user content rendered in DOM
- Validate markdown content for XSS vectors
- Implement Content Security Policy headers
File system access is broad:
- Risk: App has access to entire user home directory via
~/.claude/ - Files:
src/main/services/infrastructure/LocalFileSystemProvider.ts,src/main/services/infrastructure/SshFileSystemProvider.ts - Current mitigation: Access limited to specific Claude directories; path validation in IPC handlers
- Recommendations:
- Add explicit allow-list of accessible directories
- Log all file system operations for audit trail
- Implement file size limits to prevent memory exhaustion
SSH connection security:
- Risk: SSH credentials and private keys handled in memory
- Files:
src/main/services/infrastructure/SshConnectionManager.ts,src/main/services/infrastructure/SshConfigParser.ts - Current mitigation: Supports SSH agent, private key files; no plain password storage
- Recommendations:
- Ensure private keys are not logged
- Add connection timeout and retry limits
- Validate SSH host keys to prevent MITM attacks
- Document that passwords should use SSH agent, not inline
Regex injection prevention:
- Risk: User-provided regex patterns in notification triggers could cause ReDoS
- Files:
src/main/utils/regexValidation.ts,src/main/services/error/TriggerMatcher.ts - Current mitigation: Regex validation with complexity limits, documented as preventing ReDoS
- Recommendations: Continue validating all user regex; consider timeout mechanism for regex execution
Performance Bottlenecks
Large JSONL file parsing on every load:
- Problem: Session files can be large (10k+ lines), parsed synchronously line-by-line
- Files:
src/main/utils/jsonl.ts:50-80-parseJsonlFile(),src/main/services/parsing/SessionParser.ts - Cause: Streaming reads mitigate memory issues but CPU-bound parsing still blocks
- Improvement path:
- Implement incremental parsing (read only viewport range initially)
- Add progress indicators for large files
- Cache parsed results more aggressively (current: 50 entries, 10min TTL)
- Consider worker threads for parsing if files exceed threshold
DataCache could be more aggressive:
- Problem: Cache size limited to 50 entries with 10min TTL; may evict frequently accessed sessions
- Files:
src/main/services/infrastructure/DataCache.ts:34 - Cause: Conservative cache settings to limit memory usage
- Improvement path:
- Make cache size configurable based on available memory
- Implement smarter eviction (frequency-based, not just LRU)
- Add cache warming for recently accessed projects
- Monitor cache hit rate and adjust limits
Virtual scrolling threshold may be too high:
- Problem: ChatHistory uses virtualization only after 120 items
- Files:
src/renderer/components/chat/ChatHistory.tsx:33-VIRTUALIZATION_THRESHOLD = 120 - Cause: Balance between performance and simplicity
- Improvement path: Lower threshold to 50 or make dynamic based on item complexity
File watcher polling overhead in SSH mode:
- Problem: SSH mode polls every 5 seconds instead of using native file watching
- Files:
src/main/services/infrastructure/FileWatcher.ts:76-SSH_POLL_INTERVAL_MS = 5000 - Cause: SFTP doesn't support native file watching
- Improvement path:
- Increase polling interval for inactive sessions
- Only poll actively viewed sessions
- Implement exponential backoff when no changes detected
React re-renders from array state updates:
- Problem: Components use
useStatewith arrays, triggering re-renders on mutation - Files: Found in
src/renderer/components/search/CommandPalette.tsx,src/renderer/components/settings/NotificationTriggerSettings/hooks/useAddTriggerFormState.ts - Cause: React's immutability model
- Improvement path: Use immer for state updates; move to Zustand for complex state; add React.memo() strategically
Context tracking computation on every turn:
- Problem:
contextTracker.ts(1099 lines) recomputes context stats for entire session - Files:
src/renderer/utils/contextTracker.ts - Cause: Comprehensive tracking across 6 categories for all messages
- Improvement path:
- Memoize computation results
- Compute incrementally as messages arrive
- Move computation to web worker for large sessions
Fragile Areas
Search highlighting with direct DOM manipulation:
- Files:
src/renderer/components/chat/ChatHistory.tsx:417-425 - Why fragile: Directly mutates DOM outside React; tightly coupled to DOM structure
- Safe modification: Changes to chat item rendering may break highlighting; modify
searchHighlightUtils.tsin parallel - Test coverage: No automated tests for search highlighting
File watcher concurrency handling:
- Files:
src/main/services/infrastructure/FileWatcher.ts:79-82- concurrency guards withprocessingInProgress,pendingReprocessSets - Why fragile: Complex state machine with polling, debouncing, catch-up scans, and concurrency guards; edge cases in reconnection
- Safe modification: Test thoroughly with concurrent file changes; validate that reprocessing queue works correctly
- Test coverage: Partial coverage in
test/main/services/infrastructure/FileWatcher.test.ts
Tab state synchronization across panes:
- Files:
src/renderer/store/slices/tabSlice.ts:88-96-syncFromLayout(), pane helpers - Why fragile: Complex facade pattern synchronizing root state with focused pane; multi-level updates
- Safe modification: Changes to pane layout must maintain backward compatibility with openTabs/activeTabId
- Test coverage: Basic tests in
test/renderer/store/tabSlice.test.ts
Subagent resolution with parallel execution detection:
- Files:
src/main/services/discovery/SubagentResolver.ts(547 lines) - Why fragile: Detects parallel execution by analyzing timing; enriches team metadata with color assignments
- Safe modification: Changes to team detection logic could break teammate display; timing heuristics may need tuning
- Test coverage: No automated tests for SubagentResolver
Auto-scroll with search navigation:
- Files:
src/renderer/hooks/useAutoScrollBottom.ts:144,178,204,247- complex effect dependencies - Why fragile: Multiple setTimeout/RAF coordination; interacts with virtualization, search, and user scroll
- Safe modification: Changes to scroll behavior should be tested with all interaction modes (search, navigation, user scroll)
- Test coverage: Basic tests in
test/renderer/hooks/useAutoScrollBottom.test.ts
Scaling Limits
In-memory session storage:
- Current capacity: Limited by DataCache (50 sessions) and Zustand store (unbounded arrays)
- Limit: Projects with 1000+ sessions may cause memory issues
- Scaling path:
- Implement pagination for session lists (already exists via
getSessionsPaginated) - Add session unloading when tabs close
- Consider IndexedDB for session metadata caching in renderer
- Implement pagination for session lists (already exists via
Context injection tracking:
- Current capacity: All injections tracked for entire session in memory
- Limit: Very long sessions (1000+ turns) will accumulate large context stats
- Scaling path:
- Compute stats on-demand instead of upfront
- Store only aggregates, not individual injections
- Implement rolling window (last N turns)
Notification storage:
- Current capacity: Max 100 notifications in
~/.claude/claude-devtools-notifications.json - Limit: Hard cap prevents unbounded growth
- Scaling path: Already well-bounded; consider adding pagination UI if 100 is insufficient
Virtual scrolling limitations:
- Current capacity: Handles 1000+ items but estimated height may cause jumps
- Limit: Dynamic height items (collapsed/expanded) can cause scroll jank
- Scaling path: Use measured heights instead of estimates; implement "scroll anchoring"
Dependencies at Risk
Electron version updates:
- Risk: Currently on Electron 40.3.0; major version updates may break IPC contracts
- Impact: File watching, native notifications, window management
- Migration plan: Test thoroughly on Electron beta releases; monitor breaking changes in Electron docs
SSH2 library type coverage:
- Risk:
ssh2@1.17.0has incomplete TypeScript types, requiringas anycasts - Impact: SSH functionality breaks at runtime, not compile time
- Migration plan: Contribute types to DefinitelyTyped or switch to better-typed SSH library
React 18 concurrent rendering:
- Risk: Some components may not be concurrent-safe (direct DOM mutations)
- Impact: Search highlighting, scroll behavior may have race conditions
- Migration plan: Audit all DOM mutations; move to proper React state; enable strict mode
Zustand store performance:
- Risk: Large state trees with deep subscriptions cause re-render cascades
- Impact: Noticeable lag on large sessions
- Migration plan: Use
useShallowmore broadly; implement selector memoization; consider Jotai for derived state
Missing Critical Features
Offline SSH support:
- Problem: SSH connections disconnect without graceful degradation
- Blocks: Viewing remote sessions when host unreachable
- Priority: Medium - add cached mode for read-only access
Session export/archive:
- Problem: No way to export session data for backup or sharing
- Blocks: Long-term archival, data portability
- Priority: Low - users can manually copy JSONL files
Undo/redo for configuration:
- Problem: No way to revert config changes or notification trigger edits
- Blocks: Safe experimentation with triggers
- Priority: Low - manual backup of
~/.claude/config.jsonworks
Test Coverage Gaps
Service layer severely undertested:
- What's not tested: 38 of 44 service files lack tests (86% untested)
- Files:
- All infrastructure services except FileWatcher:
ConfigManager.ts,NotificationManager.ts,SshConnectionManager.ts,DataCache.ts(DataCache has no tests despite complex LRU logic) - All discovery services except ProjectScanner, SessionSearcher:
SubagentResolver.ts,SubagentLocator.ts,WorktreeGrouper.ts,SessionContentFilter.ts - All analysis services:
ChunkBuilder.ts(tested), butSubagentDetailBuilder.ts,SemanticStepExtractor.ts,ToolExecutionBuilder.tsuntested - All error services:
ErrorDetector.ts,ErrorTriggerChecker.ts,ErrorMessageBuilder.ts - All parsing services except MessageClassifier, SessionParser:
GitIdentityResolver.ts,ClaudeMdReader.ts
- All infrastructure services except FileWatcher:
- Risk: Complex business logic could break unnoticed; refactoring is risky
- Priority: High - focus on: DataCache LRU eviction, NotificationManager throttling, SubagentResolver parallel detection, ErrorDetector token counting
React components completely untested:
- What's not tested: 126 component files, 0 component tests
- Files: All of
src/renderer/components/(chat, sidebar, settings, dashboard, layout) - Risk: UI regressions go unnoticed; interaction bugs not caught
- Priority: Medium - focus on critical paths: ChatHistory rendering, search functionality, tab management
IPC handlers have minimal coverage:
- What's not tested: Most IPC handlers in
src/main/ipc/lack integration tests - Files:
config.ts(628 lines, 0% coverage),sessions.ts,notifications.ts,ssh.ts - Risk: Handler crashes or incorrect responses not caught
- Priority: Medium - guards.ts has 53% coverage; add handler-level tests
Store slices partially tested:
- What's not tested: 6 of 12 slices tested; missing:
projectSlice,repositorySlice,sessionDetailSlice,subagentSlice,conversationSlice,configSlice - Files:
test/renderer/store/has tests fornotificationSlice,paneSlice,sessionSlice,tabSlice,tabUISlice - Risk: State mutations may have side effects; action creators could have bugs
- Priority: Medium - focus on complex slices: sessionDetailSlice, conversationSlice
Context tracking logic untested:
- What's not tested:
contextTracker.ts(1099 lines) has no tests - Files:
src/renderer/utils/contextTracker.ts,src/renderer/utils/claudeMdTracker.ts - Risk: Context stats computation could be wrong; token counting inaccurate
- Priority: High - this is a core feature; add comprehensive tests for all 6 injection categories
Utility functions have good coverage:
- What's tested:
jsonl.ts,pathDecoder.ts,pathValidation.ts,regexValidation.ts,tokenizer.ts, formatters, date grouping - Coverage: Core parsing and utility logic is well-tested
- Priority: Low - maintain current coverage
Concerns audit: 2026-02-12