release(v0.2.0): streaming, MCP protocol, Browser Hand, security enhancements

## Major Features

### Streaming Response System
- Implement LlmDriver trait with `stream()` method returning async Stream
- Add SSE parsing for Anthropic and OpenAI API streaming
- Integrate Tauri event system for frontend streaming (`stream:chunk` events)
- Add StreamChunk types: Delta, ToolStart, ToolEnd, Complete, Error

### MCP Protocol Implementation
- Add MCP JSON-RPC 2.0 types (mcp_types.rs)
- Implement stdio-based MCP transport (mcp_transport.rs)
- Support tool discovery, execution, and resource operations

### Browser Hand Implementation
- Complete browser automation with Playwright-style actions
- Support Navigate, Click, Type, Scrape, Screenshot, Wait actions
- Add educational Hands: Whiteboard, Slideshow, Speech, Quiz

### Security Enhancements
- Implement command whitelist/blacklist for shell_exec tool
- Add SSRF protection with private IP blocking
- Create security.toml configuration file

## Test Improvements
- Fix test import paths (security-utils, setup)
- Fix vi.mock hoisting issues with vi.hoisted()
- Update test expectations for validateUrl and sanitizeFilename
- Add getUnsupportedLocalGatewayStatus mock

## Documentation Updates
- Update architecture documentation
- Improve configuration reference
- Add quick-start guide updates

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
iven
2026-03-24 03:24:24 +08:00
parent e49ba4460b
commit 3ff08faa56
78 changed files with 29575 additions and 1682 deletions

View File

@@ -25,6 +25,9 @@ import { Users, Loader2, Settings } from 'lucide-react';
import { EmptyState } from './components/ui';
import { isTauriRuntime, getLocalGatewayStatus, startLocalGateway } from './lib/tauri-gateway';
import { useOnboarding } from './lib/use-onboarding';
import { intelligenceClient } from './lib/intelligence-client';
import { useProposalNotifications, ProposalNotificationHandler } from './lib/useProposalNotifications';
import { useToast } from './components/ui/Toast';
import type { Clone } from './store/agentStore';
type View = 'main' | 'settings';
@@ -63,6 +66,24 @@ function App() {
const { setCurrentAgent, newConversation } = useChatStore();
const { isNeeded: onboardingNeeded, isLoading: onboardingLoading, markCompleted } = useOnboarding();
// Proposal notifications
const { toast } = useToast();
useProposalNotifications(); // Sets up polling for pending proposals
// Show toast when new proposals are available
useEffect(() => {
const handleProposalAvailable = (event: Event) => {
const customEvent = event as CustomEvent<{ count: number }>;
const { count } = customEvent.detail;
toast(`${count} 个新的人格变更提案待审批`, 'info');
};
window.addEventListener('zclaw:proposal-available', handleProposalAvailable);
return () => {
window.removeEventListener('zclaw:proposal-available', handleProposalAvailable);
};
}, [toast]);
useEffect(() => {
document.title = 'ZCLAW';
}, []);
@@ -160,6 +181,41 @@ function App() {
// Step 4: Initialize stores with gateway client
initializeStores();
// Step 4.5: Auto-start heartbeat engine for self-evolution
try {
const defaultAgentId = 'zclaw-main';
await intelligenceClient.heartbeat.init(defaultAgentId, {
enabled: true,
interval_minutes: 30,
quiet_hours_start: '22:00',
quiet_hours_end: '08:00',
notify_channel: 'ui',
proactivity_level: 'standard',
max_alerts_per_tick: 5,
});
// Sync memory stats to heartbeat engine
try {
const stats = await intelligenceClient.memory.stats();
const taskCount = stats.byType?.['task'] || 0;
await intelligenceClient.heartbeat.updateMemoryStats(
defaultAgentId,
taskCount,
stats.totalEntries,
stats.storageSizeBytes
);
console.log('[App] Memory stats synced to heartbeat engine');
} catch (statsErr) {
console.warn('[App] Failed to sync memory stats:', statsErr);
}
await intelligenceClient.heartbeat.start(defaultAgentId);
console.log('[App] Heartbeat engine started for self-evolution');
} catch (err) {
console.warn('[App] Failed to start heartbeat engine:', err);
// Non-critical, continue without heartbeat
}
// Step 5: Bootstrap complete
setBootstrapping(false);
} catch (err) {
@@ -364,6 +420,9 @@ function App() {
onReject={handleRejectHand}
onClose={handleCloseApprovalModal}
/>
{/* Proposal Notifications Handler */}
<ProposalNotificationHandler />
</div>
);
}