mirror of
https://github.com/humanlayer/humanlayer.git
synced 2025-08-20 19:01:22 +03:00
* refactor: reorganize daemon client to mirror Rust architecture - Split monolithic daemon-client.ts into organized modules: - lib/daemon/types.ts: All TypeScript type definitions - lib/daemon/client.ts: DaemonClient implementation - lib/daemon/errors.ts: Error types - lib/daemon/validation.ts: Type guards and validation helpers - lib/daemon/index.ts: Controlled public exports - Matches Rust daemon_client module structure for consistency - Improves maintainability and separation of concerns * feat: add React hooks layer for daemon interactions - useApprovals: Manage approval requests with data enrichment - useSessions: List and launch Claude Code sessions - useConversation: View conversation history - useDaemonConnection: Monitor daemon health - Includes real-time updates via polling - Provides loading states, error handling, and refresh functions - Hooks handle all complexity, components just render * feat: add UI utilities and type definitions - UI types: UnifiedApprovalRequest for display-friendly data - Data enrichment: Join approvals with session context - Formatting utilities: truncate, formatTimestamp, formatParameters - Error formatting: Convert technical errors to user-friendly messages - Separation of UI concerns from protocol implementation * docs: improve documentation structure and developer guides - Update README to be concise with development section first - Add comprehensive documentation: - ARCHITECTURE.md: System design with mermaid diagrams - DEVELOPER_GUIDE.md: Best practices and do's/don'ts - API.md: React hooks reference - Clear guidance on which layer to use (hooks vs daemon client) - Examples showing correct usage patterns for frontend developers * formatting * feat: add real-time subscription support and example components - Update daemon client to support event callbacks for subscriptions - Implement proper real-time updates in useApprovalsWithSubscription hook - Add ApprovalsPanel component using shadcn/ui components - Fix linting errors with proper eslint comments - Update App.tsx imports to use new daemon module path - Fix TypeScript return types in hooks * feat(wui): add missing shadcn/ui components Add card, badge, alert, and collapsible components from shadcn/ui to resolve TypeScript import errors in ApprovalsPanel * add react
4.0 KiB
4.0 KiB
Developer Guide
For Frontend Developers
This guide helps you build UI components that interact with the HumanLayer daemon.
✅ DO
Use Hooks for Everything
import { useApprovals, useSessions } from '@/hooks'
function MyComponent() {
const { approvals, loading, error, approve, deny } = useApprovals()
const { sessions, launchSession } = useSessions()
// Hooks handle all the complexity
}
Use UI Types for Props
import { UnifiedApprovalRequest } from '@/types/ui'
interface Props {
approval: UnifiedApprovalRequest // ✅ UI type
}
Import Enums When Needed
import { ApprovalType, SessionStatus } from '@/lib/daemon/types'
if (approval.type === ApprovalType.FunctionCall) {
// This is fine - enums are meant to be used
}
❌ DON'T
Don't Use the Daemon Client Directly
// ❌ WRONG - Never do this in components
import { daemonClient } from '@/lib/daemon'
const approvals = await daemonClient.fetchApprovals()
// ✅ CORRECT - Use hooks instead
const { approvals } = useApprovals()
Don't Use Raw Protocol Types in Components
// ❌ WRONG - FunctionCall is a protocol type
import { FunctionCall } from '@/lib/daemon/types'
interface Props {
approval: FunctionCall
}
// ✅ CORRECT - Use UI types
import { UnifiedApprovalRequest } from '@/types/ui'
interface Props {
approval: UnifiedApprovalRequest
}
Common Patterns
Handling Approvals
function ApprovalCard({ approval }: { approval: UnifiedApprovalRequest }) {
const { approve, deny, respond } = useApprovals()
const [isProcessing, setIsProcessing] = useState(false)
const handleApprove = async () => {
setIsProcessing(true)
try {
await approve(approval.callId)
toast.success('Approved!')
} catch (error) {
toast.error(error.message)
} finally {
setIsProcessing(false)
}
}
return (
<Card>
<h3>{approval.title}</h3>
<p>{approval.sessionQuery}</p>
<Button onClick={handleApprove} disabled={isProcessing}>
Approve
</Button>
</Card>
)
}
Launching Sessions
function LaunchButton() {
const { launchSession } = useSessions()
const [query, setQuery] = useState('')
const handleLaunch = async () => {
try {
const { sessionId } = await launchSession({
query,
model: 'sonnet',
working_dir: '/path/to/project',
})
navigate(`/sessions/${sessionId}`)
} catch (error) {
alert(error.message)
}
}
return (
<>
<input value={query} onChange={e => setQuery(e.target.value)} />
<button onClick={handleLaunch}>Launch</button>
</>
)
}
Real-time Updates
function LiveApprovals() {
// This hook automatically polls for updates
const { approvals } = useApprovalsWithSubscription()
return (
<div>
{approvals.map(approval => (
<ApprovalCard key={approval.id} approval={approval} />
))}
</div>
)
}
Understanding the Layers
1. Components (Your Code)
- Import hooks and UI types
- Handle user interactions
- Render UI
2. Hooks (React Layer)
- Manage state with useState
- Handle loading/error states
- Enrich data (join approvals + sessions)
- Format errors for display
3. Daemon Client (Protocol Layer)
- Type-safe Tauri invocations
- 1:1 mapping to Rust API
- No business logic
4. Rust/Daemon
- Handles actual daemon communication
- Manages Unix socket connection
- Protocol implementation
Tips
- Loading States: All hooks provide
loading- use it! - Error Handling: Hooks format errors, just display
errorstring - Refreshing: Actions like
approve()auto-refresh the list - Polling:
useApprovalsWithSubscriptionpolls every 5 seconds - Types: When in doubt, check what the hook returns
Need Help?
- Check the API Reference for all available hooks
- Look at existing components for examples
- The TypeScript compiler will guide you - trust the types!