refactor: 统一项目名称从OpenFang到ZCLAW
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

重构所有代码和文档中的项目名称,将OpenFang统一更新为ZCLAW。包括:
- 配置文件中的项目名称
- 代码注释和文档引用
- 环境变量和路径
- 类型定义和接口名称
- 测试用例和模拟数据

同时优化部分代码结构,移除未使用的模块,并更新相关依赖项。
This commit is contained in:
iven
2026-03-27 07:36:03 +08:00
parent 4b08804aa9
commit 0d4fa96b82
226 changed files with 7288 additions and 5788 deletions

View File

@@ -21,13 +21,15 @@ import { Loader2 } from 'lucide-react';
import { isTauriRuntime, getLocalGatewayStatus, startLocalGateway } from './lib/tauri-gateway';
import { useOnboarding } from './lib/use-onboarding';
import { intelligenceClient } from './lib/intelligence-client';
import { loadEmbeddingConfig } from './lib/embedding-client';
import { invoke } from '@tauri-apps/api/core';
import { useProposalNotifications, ProposalNotificationHandler } from './lib/useProposalNotifications';
import { useToast } from './components/ui/Toast';
import type { Clone } from './store/agentStore';
type View = 'main' | 'settings';
// Bootstrap component that ensures OpenFang is running before rendering main UI
// Bootstrap component that ensures ZCLAW is running before rendering main UI
function BootstrapScreen({ status }: { status: string }) {
return (
<div className="h-screen flex items-center justify-center bg-gray-50">
@@ -125,7 +127,7 @@ function App() {
// Don't clear pendingApprovalRun - keep it for reference
}, []);
// Bootstrap: Start OpenFang Gateway before rendering main UI
// Bootstrap: Start ZCLAW Gateway before rendering main UI
useEffect(() => {
let mounted = true;
@@ -140,7 +142,7 @@ function App() {
const isRunning = status.portStatus === 'busy' || status.listenerPids.length > 0;
if (!isRunning && status.cliAvailable) {
setBootstrapStatus('Starting OpenFang Gateway...');
setBootstrapStatus('Starting ZCLAW Gateway...');
console.log('[App] Local gateway not running, auto-starting...');
await startLocalGateway();
@@ -230,7 +232,43 @@ function App() {
// Non-critical, continue without heartbeat
}
// Step 5: Bootstrap complete
// Step 5: Restore embedding config to Rust backend
try {
const embConfig = loadEmbeddingConfig();
if (embConfig.enabled && embConfig.provider !== 'local' && embConfig.apiKey) {
setBootstrapStatus('Restoring embedding configuration...');
await invoke('viking_configure_embedding', {
provider: embConfig.provider,
apiKey: embConfig.apiKey,
model: embConfig.model || undefined,
endpoint: embConfig.endpoint || undefined,
});
console.log('[App] Embedding configuration restored to backend');
}
} catch (embErr) {
console.warn('[App] Failed to restore embedding config:', embErr);
// Non-critical, semantic search will fall back to TF-IDF
}
// Step 5b: Configure summary driver using active LLM (for L0/L1 generation)
try {
const { getDefaultModelConfig } = await import('./store/connectionStore');
const modelConfig = getDefaultModelConfig();
if (modelConfig && modelConfig.apiKey && modelConfig.baseUrl) {
setBootstrapStatus('Configuring summary driver...');
await invoke('viking_configure_summary_driver', {
endpoint: modelConfig.baseUrl,
apiKey: modelConfig.apiKey,
model: modelConfig.model || undefined,
});
console.log('[App] Summary driver configured with active LLM');
}
} catch (sumErr) {
console.warn('[App] Failed to configure summary driver:', sumErr);
// Non-critical, summaries won't be auto-generated
}
// Step 6: Bootstrap complete
setBootstrapping(false);
} catch (err) {
console.error('[App] Bootstrap failed:', err);

View File

@@ -1,10 +1,10 @@
/**
* ApprovalsPanel - OpenFang Execution Approvals UI
* ApprovalsPanel - ZCLAW Execution Approvals UI
*
* Displays pending, approved, and rejected approval requests
* for Hand executions that require human approval.
*
* Design based on OpenFang Dashboard v0.4.0
* Design based on ZCLAW Dashboard v0.4.0
*/
import { useState, useEffect, useCallback } from 'react';

View File

@@ -1,5 +1,5 @@
/**
* AuditLogsPanel - OpenFang Audit Logs UI with Merkle Hash Chain Verification
* AuditLogsPanel - ZCLAW Audit Logs UI with Merkle Hash Chain Verification
*
* Phase 3.4 Enhancement: Full-featured audit log viewer with:
* - Complete log entry display
@@ -51,7 +51,7 @@ export interface AuditLogFilter {
}
interface EnhancedAuditLogEntry extends AuditLogEntry {
// Extended fields from OpenFang
// Extended fields from ZCLAW
targetResource?: string;
operationDetails?: Record<string, unknown>;
ipAddress?: string;
@@ -633,7 +633,7 @@ export function AuditLogsPanel() {
setVerificationResult(null);
try {
// Call OpenFang API to verify the chain
// Call ZCLAW API to verify the chain
const result = await client.verifyAuditLogChain(log.id);
const verification: MerkleVerificationResult = {

View File

@@ -42,7 +42,7 @@ export function CloneManager() {
role: '默认助手',
nickname: a.name,
scenarios: [] as string[],
workspaceDir: '~/.openfang/zclaw-workspace',
workspaceDir: '~/.zclaw/zclaw-workspace',
userName: quickConfig.userName || '未设置',
userRole: '',
restrictFiles: true,

View File

@@ -3,7 +3,7 @@
*
* Displays the current Gateway connection status with visual indicators.
* Supports automatic reconnect and manual reconnect button.
* Includes health status indicator for OpenFang backend.
* Includes health status indicator for ZCLAW backend.
*/
import { useState, useEffect } from 'react';
@@ -230,7 +230,7 @@ export function ConnectionIndicator({ className = '' }: { className?: string })
}
/**
* HealthStatusIndicator - Displays OpenFang backend health status
* HealthStatusIndicator - Displays ZCLAW backend health status
*/
export function HealthStatusIndicator({
className = '',

View File

@@ -3,7 +3,7 @@
*
* Supports trigger types:
* - webhook: External HTTP request trigger
* - event: OpenFang internal event trigger
* - event: ZCLAW internal event trigger
* - message: Chat message pattern trigger
*/
@@ -119,7 +119,7 @@ const triggerTypeOptions: Array<{
{
value: 'event',
label: 'Event',
description: 'OpenFang internal event trigger',
description: 'ZCLAW internal event trigger',
icon: Bell,
},
{

View File

@@ -64,7 +64,7 @@ export function HandList({ selectedHandId, onSelectHand }: HandListProps) {
<div className="p-4 text-center">
<Zap className="w-8 h-8 mx-auto text-gray-300 mb-2" />
<p className="text-xs text-gray-400 mb-1"> Hands</p>
<p className="text-xs text-gray-300"> OpenFang </p>
<p className="text-xs text-gray-300"> ZCLAW </p>
</div>
);
}

View File

@@ -1,10 +1,10 @@
/**
* HandsPanel - OpenFang Hands Management UI
* HandsPanel - ZCLAW Hands Management UI
*
* Displays available OpenFang Hands (autonomous capability packages)
* Displays available ZCLAW Hands (autonomous capability packages)
* with detailed status, requirements, and activation controls.
*
* Design based on OpenFang Dashboard v0.4.0
* Design based on ZCLAW Dashboard v0.4.0
*/
import { useState, useEffect, useCallback } from 'react';
@@ -528,7 +528,7 @@ export function HandsPanel() {
</div>
<p className="text-sm text-gray-500 dark:text-gray-400 mb-3"> Hands</p>
<p className="text-xs text-gray-400 dark:text-gray-500">
OpenFang
ZCLAW
</p>
</div>
);

View File

@@ -441,7 +441,7 @@ export function RightPanel() {
))}
</div>
</div>
<AgentRow label="Workspace" value={selectedClone?.workspaceDir || workspaceInfo?.path || '~/.openfang/zclaw-workspace'} />
<AgentRow label="Workspace" value={selectedClone?.workspaceDir || workspaceInfo?.path || '~/.zclaw/zclaw-workspace'} />
<AgentRow label="Resolved" value={selectedClone?.workspaceResolvedPath || workspaceInfo?.resolvedPath || '-'} />
<AgentRow label="File Restriction" value={selectedClone?.restrictFiles ? 'Enabled' : 'Disabled'} />
<AgentRow label="Opt-in" value={selectedClone?.privacyOptIn ? 'Joined' : 'Not joined'} />
@@ -739,7 +739,7 @@ function createAgentDraft(
nickname: clone.nickname || '',
model: clone.model || currentModel,
scenarios: clone.scenarios?.join(', ') || '',
workspaceDir: clone.workspaceDir || '~/.openfang/zclaw-workspace',
workspaceDir: clone.workspaceDir || '~/.zclaw/zclaw-workspace',
userName: clone.userName || '',
userRole: clone.userRole || '',
restrictFiles: clone.restrictFiles ?? true,

View File

@@ -1,9 +1,9 @@
/**
* SchedulerPanel - OpenFang Scheduler UI
* SchedulerPanel - ZCLAW Scheduler UI
*
* Displays scheduled jobs, event triggers, workflows, and run history.
*
* Design based on OpenFang Dashboard v0.4.0
* Design based on ZCLAW Dashboard v0.4.0
*/
import { useState, useEffect, useCallback } from 'react';

View File

@@ -30,7 +30,7 @@ import type { SecurityLayer, SecurityStatus } from '../store/securityStore';
import { useSecurityStore } from '../store/securityStore';
import { useConnectionStore } from '../store/connectionStore';
// OpenFang 16-layer security architecture definitions
// ZCLAW 16-layer security architecture definitions
export const SECURITY_LAYERS: Array<{
id: string;
name: string;
@@ -482,7 +482,7 @@ export function calculateSecurityScore(layers: SecurityLayer[]): number {
return Math.round((activeCount / SECURITY_LAYERS.length) * 100);
}
// ZCLAW 默认安全状态(独立于 OpenFang
// ZCLAW 默认安全状态(本地检测
export function getDefaultSecurityStatus(): SecurityStatus {
// ZCLAW 默认启用的安全层
const defaultEnabledLayers = [
@@ -687,7 +687,7 @@ export function SecurityStatusPanel({ className = '' }: SecurityStatusPanelProps
</span>
</div>
<p className="text-xs text-gray-500 mt-1">
{!connected && 'ZCLAW 默认安全配置。连接 OpenFang 后可获取完整安全状态。'}
{!connected && 'ZCLAW 默认安全配置。连接后可获取实时安全状态。'}
</p>
</div>

View File

@@ -1,9 +1,8 @@
import { useEffect } from 'react';
import { Shield, ShieldCheck, ShieldAlert, ShieldX, RefreshCw, Loader2, AlertCircle } from 'lucide-react';
import { useConnectionStore } from '../store/connectionStore';
import { useSecurityStore } from '../store/securityStore';
// OpenFang 16-layer security architecture names (Chinese)
// ZCLAW 16-layer security architecture names (Chinese)
const SECURITY_LAYER_NAMES: Record<string, string> = {
// Layer 1: Network
'network.firewall': '网络防火墙',
@@ -76,30 +75,14 @@ function getSecurityLabel(level: 'critical' | 'high' | 'medium' | 'low') {
}
export function SecurityStatus() {
const connectionState = useConnectionStore((s) => s.connectionState);
const securityStatus = useSecurityStore((s) => s.securityStatus);
const securityStatusLoading = useSecurityStore((s) => s.securityStatusLoading);
const securityStatusError = useSecurityStore((s) => s.securityStatusError);
const loadSecurityStatus = useSecurityStore((s) => s.loadSecurityStatus);
const connected = connectionState === 'connected';
useEffect(() => {
if (connected) {
loadSecurityStatus();
}
}, [connected]);
if (!connected) {
return (
<div className="rounded-xl border border-gray-200 bg-white p-4 shadow-sm">
<div className="flex items-center gap-2 mb-3">
<Shield className="w-4 h-4 text-gray-400" />
<span className="text-sm font-semibold text-gray-900"></span>
</div>
<p className="text-xs text-gray-400"></p>
</div>
);
}
loadSecurityStatus();
}, [loadSecurityStatus]);
// Loading state
if (securityStatusLoading && !securityStatus) {
@@ -131,9 +114,9 @@ export function SecurityStatus() {
<RefreshCw className="w-3.5 h-3.5" />
</button>
</div>
<p className="text-xs text-gray-500 mb-2">API </p>
<p className="text-xs text-gray-500 mb-2"></p>
<p className="text-xs text-gray-400">
OpenFang API ({'/api/security/status'})
</p>
</div>
);

View File

@@ -34,10 +34,10 @@ export function About() {
</div>
<div className="mt-12 text-center text-xs text-gray-400">
2026 ZCLAW | Powered by OpenFang
2026 ZCLAW
</div>
<div className="text-center text-xs text-gray-400 space-y-1">
<p> OpenFang Rust Agent OS </p>
<p> Rust Agent OS </p>
<div className="flex justify-center gap-4 mt-3">
<a href="#" className="text-orange-500 hover:text-orange-600"></a>
<a href="#" className="text-orange-500 hover:text-orange-600"></a>

View File

@@ -382,7 +382,7 @@ export function IMChannels() {
<div className="text-xs text-blue-700 dark:text-blue-300">
<p className="font-medium mb-1"></p>
<p> Gateway </p>
<p className="mt-1">: <code className="bg-blue-100 dark:bg-blue-800 px-1 rounded">~/.openfang/openfang.toml</code></p>
<p className="mt-1">: <code className="bg-blue-100 dark:bg-blue-800 px-1 rounded">~/.zclaw/zclaw.toml</code></p>
</div>
</div>
</div>

View File

@@ -266,13 +266,30 @@ export function ModelsAPI() {
};
// 保存 Embedding 配置
const handleSaveEmbeddingConfig = () => {
const handleSaveEmbeddingConfig = async () => {
const configToSave = {
...embeddingConfig,
enabled: embeddingConfig.provider !== 'local' && embeddingConfig.apiKey.trim() !== '',
};
setEmbeddingConfig(configToSave);
saveEmbeddingConfig(configToSave);
// Push config to Rust backend for semantic memory search
if (configToSave.enabled) {
try {
await invoke('viking_configure_embedding', {
provider: configToSave.provider,
apiKey: configToSave.apiKey,
model: configToSave.model || undefined,
endpoint: configToSave.endpoint || undefined,
});
setEmbeddingTestResult({ success: true, message: 'Embedding 配置已应用到语义记忆搜索' });
} catch (error) {
setEmbeddingTestResult({ success: false, message: `配置保存成功但应用失败: ${error}` });
}
} else {
setEmbeddingTestResult(null);
}
};
// 测试 Embedding API

View File

@@ -24,7 +24,7 @@ export function Privacy() {
<h3 className="font-medium mb-2 text-gray-900"></h3>
<div className="text-xs text-gray-500 mb-3"> Agent </div>
<div className="p-3 bg-gray-50 border border-gray-200 rounded-lg text-xs text-gray-600 font-mono">
{workspaceInfo?.resolvedPath || workspaceInfo?.path || quickConfig.workspaceDir || '~/.openfang/zclaw-workspace'}
{workspaceInfo?.resolvedPath || workspaceInfo?.path || quickConfig.workspaceDir || '~/.zclaw/zclaw-workspace'}
</div>
</div>

View File

@@ -1,19 +1,15 @@
import { useEffect, useState } from 'react';
import { useAgentStore } from '../../store/agentStore';
import { useConnectionStore } from '../../store/connectionStore';
import { BarChart3, TrendingUp, Clock, Zap } from 'lucide-react';
export function UsageStats() {
const usageStats = useAgentStore((s) => s.usageStats);
const loadUsageStats = useAgentStore((s) => s.loadUsageStats);
const connectionState = useConnectionStore((s) => s.connectionState);
const [timeRange, setTimeRange] = useState<'7d' | '30d' | 'all'>('7d');
useEffect(() => {
if (connectionState === 'connected') {
loadUsageStats();
}
}, [connectionState]);
loadUsageStats();
}, [loadUsageStats]);
const stats = usageStats || { totalSessions: 0, totalMessages: 0, totalTokens: 0, byModel: {} };
const models = Object.entries(stats.byModel || {});
@@ -56,7 +52,7 @@ export function UsageStats() {
</button>
</div>
</div>
<div className="text-xs text-gray-500 mb-4"> Token </div>
<div className="text-xs text-gray-500 mb-4">使</div>
{/* 主要统计卡片 */}
<div className="grid grid-cols-4 gap-4 mb-8">
@@ -89,6 +85,9 @@ export function UsageStats() {
{/* 总 Token 使用量概览 */}
<div className="bg-white rounded-xl border border-gray-200 p-5 shadow-sm mb-6">
<h3 className="text-sm font-semibold mb-4 text-gray-900">Token 使</h3>
{stats.totalTokens === 0 ? (
<p className="text-xs text-gray-400">Token </p>
) : (
<div className="flex items-center gap-4">
<div className="flex-1">
<div className="flex justify-between text-xs text-gray-500 mb-1">
@@ -111,6 +110,7 @@ export function UsageStats() {
<div className="text-xs text-gray-500"></div>
</div>
</div>
)}
</div>
{/* 按模型分组 */}

View File

@@ -7,18 +7,18 @@ export function Workspace() {
const workspaceInfo = useConfigStore((s) => s.workspaceInfo);
const loadWorkspaceInfo = useConfigStore((s) => s.loadWorkspaceInfo);
const saveQuickConfig = useConfigStore((s) => s.saveQuickConfig);
const [projectDir, setProjectDir] = useState('~/.openfang/zclaw-workspace');
const [projectDir, setProjectDir] = useState('~/.zclaw/zclaw-workspace');
useEffect(() => {
loadWorkspaceInfo().catch(silentErrorHandler('Workspace'));
}, []);
useEffect(() => {
setProjectDir(quickConfig.workspaceDir || workspaceInfo?.path || '~/.openfang/zclaw-workspace');
setProjectDir(quickConfig.workspaceDir || workspaceInfo?.path || '~/.zclaw/zclaw-workspace');
}, [quickConfig.workspaceDir, workspaceInfo?.path]);
const handleWorkspaceBlur = async () => {
const nextValue = projectDir.trim() || '~/.openfang/zclaw-workspace';
const nextValue = projectDir.trim() || '~/.zclaw/zclaw-workspace';
setProjectDir(nextValue);
await saveQuickConfig({ workspaceDir: nextValue });
await loadWorkspaceInfo();

View File

@@ -375,8 +375,10 @@ export function SkillMarket({
/>
</div>
{/* Suggestions - placeholder for future AI-powered recommendations */}
{/* AI 智能推荐功能开发中 */}
<div className="text-xs text-gray-400 dark:text-gray-500 text-center py-1">
AI
</div>
</div>
{/* Category Filter */}

View File

@@ -1,7 +1,7 @@
/**
* TriggersPanel - OpenFang Triggers Management UI
* TriggersPanel - ZCLAW Triggers Management UI
*
* Displays available OpenFang Triggers and allows creating and toggling them.
* Displays available ZCLAW Triggers and allows creating and toggling them.
*/
import { useState, useEffect, useCallback } from 'react';

View File

@@ -1,8 +1,8 @@
/**
* VikingPanel - OpenViking Semantic Memory UI
* VikingPanel - ZCLAW Semantic Memory UI
*
* Provides interface for semantic search and knowledge base management.
* OpenViking is an optional sidecar for semantic memory operations.
* Uses native Rust SqliteStorage with TF-IDF semantic search.
*/
import { useState, useEffect } from 'react';
import {
@@ -11,16 +11,13 @@ import {
AlertCircle,
CheckCircle,
FileText,
Server,
Play,
Square,
Database,
} from 'lucide-react';
import {
getVikingStatus,
findVikingResources,
getVikingServerStatus,
startVikingServer,
stopVikingServer,
listVikingResources,
readVikingResource,
} from '../lib/viking-client';
import type { VikingStatus, VikingFindResult } from '../lib/viking-client';
@@ -30,17 +27,28 @@ export function VikingPanel() {
const [searchQuery, setSearchQuery] = useState('');
const [searchResults, setSearchResults] = useState<VikingFindResult[]>([]);
const [isSearching, setIsSearching] = useState(false);
const [serverRunning, setServerRunning] = useState(false);
const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
const [memoryCount, setMemoryCount] = useState<number | null>(null);
const [expandedUri, setExpandedUri] = useState<string | null>(null);
const [expandedContent, setExpandedContent] = useState<string | null>(null);
const [isLoadingL2, setIsLoadingL2] = useState(false);
const loadStatus = async () => {
setIsLoading(true);
setMessage(null);
try {
const vikingStatus = await getVikingStatus();
setStatus(vikingStatus);
const serverStatus = await getVikingServerStatus();
setServerRunning(serverStatus.running);
if (vikingStatus.available) {
// Load memory count
try {
const resources = await listVikingResources('/');
setMemoryCount(resources.length);
} catch {
setMemoryCount(null);
}
}
} catch (error) {
console.error('Failed to load Viking status:', error);
setStatus({ available: false, error: String(error) });
@@ -74,22 +82,22 @@ export function VikingPanel() {
}
};
const handleServerToggle = async () => {
const handleExpandL2 = async (uri: string) => {
if (expandedUri === uri) {
setExpandedUri(null);
setExpandedContent(null);
return;
}
setExpandedUri(uri);
setIsLoadingL2(true);
try {
if (serverRunning) {
await stopVikingServer();
setServerRunning(false);
setMessage({ type: 'success', text: '服务器已停止' });
} else {
await startVikingServer();
setServerRunning(true);
setMessage({ type: 'success', text: '服务器已启动' });
}
} catch (error) {
setMessage({
type: 'error',
text: `操作失败: ${error instanceof Error ? error.message : '未知错误'}`,
});
const fullContent = await readVikingResource(uri, 'L2');
setExpandedContent(fullContent);
} catch {
setExpandedContent(null);
} finally {
setIsLoadingL2(false);
}
};
@@ -100,7 +108,7 @@ export function VikingPanel() {
<div>
<h1 className="text-xl font-bold text-gray-900 dark:text-white"></h1>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
OpenViking
ZCLAW
</p>
</div>
<div className="flex gap-2 items-center">
@@ -125,10 +133,9 @@ export function VikingPanel() {
<div className="flex items-start gap-2">
<AlertCircle className="w-4 h-4 text-amber-500 mt-0.5" />
<div className="text-xs text-amber-700 dark:text-amber-300">
<p className="font-medium">OpenViking CLI </p>
<p className="font-medium"></p>
<p className="mt-1">
OpenViking CLI {' '}
<code className="bg-amber-100 dark:bg-amber-800 px-1 rounded">ZCLAW_VIKING_BIN</code>
SQLite
</p>
{status?.error && (
<p className="mt-1 text-amber-600 dark:text-amber-400 font-mono text-xs">
@@ -158,47 +165,37 @@ export function VikingPanel() {
</div>
)}
{/* Server Control */}
{/* Storage Info */}
{status?.available && (
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-4 mb-6 shadow-sm">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div
className={`w-10 h-10 rounded-xl flex items-center justify-center ${
serverRunning
? 'bg-gradient-to-br from-green-500 to-emerald-500 text-white'
: 'bg-gray-200 dark:bg-gray-700 text-gray-400'
}`}
>
<Server className="w-4 h-4" />
<div className="flex items-center gap-3 mb-3">
<div className="w-10 h-10 rounded-xl bg-gradient-to-br from-blue-500 to-indigo-500 flex items-center justify-center">
<Database className="w-4 h-4 text-white" />
</div>
<div>
<div className="text-sm font-medium text-gray-900 dark:text-white">
</div>
<div>
<div className="text-sm font-medium text-gray-900 dark:text-white">
Viking Server
</div>
<div className="text-xs text-gray-500 dark:text-gray-400">
{serverRunning ? '运行中' : '已停止'}
</div>
<div className="text-xs text-gray-500 dark:text-gray-400">
{status.version || 'Native'} · {status.dataDir || '默认路径'}
</div>
</div>
<button
onClick={handleServerToggle}
className={`px-4 py-2 rounded-lg flex items-center gap-2 text-sm transition-colors ${
serverRunning
? 'bg-red-100 text-red-600 hover:bg-red-200 dark:bg-red-900/30 dark:text-red-400'
: 'bg-green-100 text-green-600 hover:bg-green-200 dark:bg-green-900/30 dark:text-green-400'
}`}
>
{serverRunning ? (
<>
<Square className="w-4 h-4" />
</>
) : (
<>
<Play className="w-4 h-4" />
</>
)}
</button>
</div>
<div className="flex gap-4 text-xs">
<div className="flex items-center gap-1.5 text-gray-600 dark:text-gray-300">
<CheckCircle className="w-3.5 h-3.5 text-green-500" />
<span>SQLite + FTS5</span>
</div>
<div className="flex items-center gap-1.5 text-gray-600 dark:text-gray-300">
<CheckCircle className="w-3.5 h-3.5 text-green-500" />
<span>TF-IDF </span>
</div>
{memoryCount !== null && (
<div className="flex items-center gap-1.5 text-gray-600 dark:text-gray-300">
<CheckCircle className="w-3.5 h-3.5 text-green-500" />
<span>{memoryCount} </span>
</div>
)}
</div>
</div>
)}
@@ -251,21 +248,43 @@ export function VikingPanel() {
<span className="text-sm font-medium text-gray-900 dark:text-white truncate">
{result.uri}
</span>
<span className="text-xs text-gray-400 bg-gray-100 dark:bg-gray-700 px-2 py-0.5 rounded">
<span className={`text-xs px-2 py-0.5 rounded ${
result.level === 'L1'
? 'text-green-600 bg-green-100 dark:bg-green-900/30 dark:text-green-400'
: 'text-gray-400 bg-gray-100 dark:bg-gray-700'
}`}>
{result.level}
</span>
<span className="text-xs text-blue-600 dark:text-blue-400">
{Math.round(result.score * 100)}%
</span>
</div>
{result.overview && (
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1 line-clamp-2">
{result.overview}
</p>
)}
<p className="text-xs text-gray-600 dark:text-gray-300 mt-2 line-clamp-3 font-mono">
<p className="text-xs text-gray-600 dark:text-gray-300 mt-2 line-clamp-3">
{result.content}
</p>
{result.level === 'L1' && (
<button
onClick={() => handleExpandL2(result.uri)}
className="mt-1.5 text-xs text-blue-500 hover:text-blue-600 dark:text-blue-400 dark:hover:text-blue-300 transition-colors"
>
{expandedUri === result.uri ? '收起全文' : '展开全文'}
</button>
)}
{expandedUri === result.uri && (
<div className="mt-2 p-3 bg-gray-50 dark:bg-gray-900/50 rounded-lg border border-gray-200 dark:border-gray-700">
{isLoadingL2 ? (
<div className="flex items-center gap-2 text-xs text-gray-400">
<RefreshCw className="w-3 h-3 animate-spin" /> ...
</div>
) : expandedContent ? (
<p className="text-xs text-gray-600 dark:text-gray-300 whitespace-pre-wrap font-mono">
{expandedContent}
</p>
) : (
<p className="text-xs text-gray-400"></p>
)}
</div>
)}
</div>
</div>
</div>
@@ -275,11 +294,11 @@ export function VikingPanel() {
{/* Info Section */}
<div className="mt-6 p-4 bg-gray-50 dark:bg-gray-800/50 rounded-lg border border-gray-200 dark:border-gray-700">
<h3 className="text-sm font-medium text-gray-900 dark:text-white mb-2"> OpenViking</h3>
<h3 className="text-sm font-medium text-gray-900 dark:text-white mb-2"></h3>
<ul className="text-xs text-gray-500 dark:text-gray-400 space-y-1">
<li> </li>
<li> </li>
<li> </li>
<li> SQLite + TF-IDF </li>
<li> </li>
<li> </li>
<li> AI </li>
</ul>
</div>

View File

@@ -1,10 +1,10 @@
/**
* WorkflowEditor - OpenFang Workflow Editor Component
* WorkflowEditor - ZCLAW Workflow Editor Component
*
* Allows creating and editing multi-step workflows that chain
* multiple Hands together for complex task automation.
*
* Design based on OpenFang Dashboard v0.4.0
* Design based on ZCLAW Dashboard v0.4.0
*/
import { useState, useEffect, useCallback } from 'react';

View File

@@ -1,10 +1,10 @@
/**
* WorkflowHistory - OpenFang Workflow Execution History Component
* WorkflowHistory - ZCLAW Workflow Execution History Component
*
* Displays the execution history of a specific workflow,
* showing run details, status, and results.
*
* Design based on OpenFang Dashboard v0.4.0
* Design based on ZCLAW Dashboard v0.4.0
*/
import { useState, useEffect, useCallback } from 'react';

View File

@@ -1,15 +1,16 @@
/**
* WorkflowList - OpenFang Workflow Management UI
* WorkflowList - ZCLAW Workflow Management UI
*
* Displays available OpenFang Workflows and allows executing them.
* Displays available ZCLAW Workflows and allows executing them.
*
* Design based on OpenFang Dashboard v0.4.0
* Design based on ZCLAW Dashboard v0.4.0
*/
import { useState, useEffect, useCallback } from 'react';
import { useWorkflowStore, type Workflow } from '../store/workflowStore';
import { WorkflowEditor } from './WorkflowEditor';
import { WorkflowHistory } from './WorkflowHistory';
import { WorkflowBuilder } from './WorkflowBuilder';
import {
Play,
Edit,
@@ -467,18 +468,8 @@ export function WorkflowList() {
</div>
)
) : (
// Visual Builder View (placeholder)
<div className="p-8 text-center bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700">
<div className="w-12 h-12 bg-gray-100 dark:bg-gray-700 rounded-full flex items-center justify-center mx-auto mb-3">
<GitBranch className="w-6 h-6 text-gray-400" />
</div>
<p className="text-sm text-gray-500 dark:text-gray-400 mb-2">
</p>
<p className="text-xs text-gray-400 dark:text-gray-500">
</p>
</div>
// Visual Builder View
<WorkflowBuilder />
)}
{/* Execute Modal */}

View File

@@ -1,7 +1,7 @@
/**
* useAutomationEvents - WebSocket Event Hook for Automation System
*
* Subscribes to hand and workflow events from OpenFang WebSocket
* Subscribes to hand and workflow events from ZCLAW WebSocket
* and updates the corresponding stores.
*
* @module hooks/useAutomationEvents

View File

@@ -1,7 +1,7 @@
/**
* API Fallbacks for ZCLAW Gateway
*
* Provides sensible default data when OpenFang API endpoints return 404.
* Provides sensible default data when ZCLAW API endpoints return 404.
* This allows the UI to function gracefully even when backend features
* are not yet implemented.
*/
@@ -178,7 +178,7 @@ export function getUsageStatsFallback(sessions: SessionForStats[] = []): UsageSt
/**
* Convert skills to plugin status when /api/plugins/status returns 404.
* OpenFang uses Skills instead of traditional plugins.
* ZCLAW uses Skills instead of traditional plugins.
*/
export function getPluginStatusFallback(skills: SkillForPlugins[] = []): PluginStatusFallback[] {
if (skills.length === 0) {
@@ -215,7 +215,7 @@ export function getScheduledTasksFallback(triggers: TriggerForTasks[] = []): Sch
/**
* Default security status when /api/security/status returns 404.
* OpenFang has 16 security layers - show them with conservative defaults.
* ZCLAW has 16 security layers - show them with conservative defaults.
*/
export function getSecurityStatusFallback(): SecurityStatusFallback {
const layers: SecurityLayerFallback[] = [

View File

@@ -1,7 +1,7 @@
/**
* OpenFang Configuration Parser
* ZCLAW Configuration Parser
*
* Provides configuration parsing, validation, and serialization for OpenFang TOML files.
* Provides configuration parsing, validation, and serialization for ZCLAW TOML files.
*
* @module lib/config-parser
*/
@@ -9,7 +9,7 @@
import { tomlUtils, TomlParseError } from './toml-utils';
import { DEFAULT_MODEL_ID, DEFAULT_PROVIDER } from '../constants/models';
import type {
OpenFangConfig,
ZclawConfig,
ConfigValidationResult,
ConfigValidationError,
ConfigValidationWarning,
@@ -64,7 +64,7 @@ const REQUIRED_FIELDS: Array<{ path: string; description: string }> = [
/**
* Default configuration values
*/
const DEFAULT_CONFIG: Partial<OpenFangConfig> = {
const DEFAULT_CONFIG: Partial<ZclawConfig> = {
server: {
host: '127.0.0.1',
port: 4200,
@@ -74,7 +74,7 @@ const DEFAULT_CONFIG: Partial<OpenFangConfig> = {
},
agent: {
defaults: {
workspace: '~/.openfang/workspace',
workspace: '~/.zclaw/workspace',
default_model: DEFAULT_MODEL_ID,
},
},
@@ -89,7 +89,7 @@ const DEFAULT_CONFIG: Partial<OpenFangConfig> = {
*/
export const configParser = {
/**
* Parse TOML content into an OpenFang configuration object
* Parse TOML content into a ZCLAW configuration object
*
* @param content - The TOML content to parse
* @param envVars - Optional environment variables for resolution
@@ -101,13 +101,13 @@ export const configParser = {
* const config = configParser.parseConfig(tomlContent, { OPENAI_API_KEY: 'sk-...' });
* ```
*/
parseConfig: (content: string, envVars?: Record<string, string | undefined>): OpenFangConfig => {
parseConfig: (content: string, envVars?: Record<string, string | undefined>): ZclawConfig => {
try {
// First resolve environment variables
const resolved = tomlUtils.resolveEnvVars(content, envVars);
// Parse TOML
const parsed = tomlUtils.parse<OpenFangConfig>(resolved);
const parsed = tomlUtils.parse<ZclawConfig>(resolved);
return parsed;
} catch (error) {
if (error instanceof TomlParseError) {
@@ -121,7 +121,7 @@ export const configParser = {
},
/**
* Validate an OpenFang configuration object
* Validate a ZCLAW configuration object
*
* @param config - The configuration object to validate
* @returns Validation result with errors and warnings
@@ -238,7 +238,7 @@ export const configParser = {
parseAndValidate: (
content: string,
envVars?: Record<string, string | undefined>
): OpenFangConfig => {
): ZclawConfig => {
const config = configParser.parseConfig(content, envVars);
const result = configParser.validateConfig(config);
if (!result.valid) {
@@ -261,7 +261,7 @@ export const configParser = {
* const toml = configParser.stringifyConfig(config);
* ```
*/
stringifyConfig: (config: OpenFangConfig): string => {
stringifyConfig: (config: ZclawConfig): string => {
return tomlUtils.stringify(config as unknown as Record<string, unknown>);
},
@@ -276,8 +276,8 @@ export const configParser = {
* const fullConfig = configParser.mergeWithDefaults(partialConfig);
* ```
*/
mergeWithDefaults: (config: Partial<OpenFangConfig>): OpenFangConfig => {
return deepMerge(DEFAULT_CONFIG, config) as unknown as OpenFangConfig;
mergeWithDefaults: (config: Partial<ZclawConfig>): ZclawConfig => {
return deepMerge(DEFAULT_CONFIG, config) as unknown as ZclawConfig;
},
/**
@@ -307,19 +307,19 @@ export const configParser = {
/**
* Get default configuration
*
* @returns Default OpenFang configuration
* @returns Default ZCLAW configuration
*/
getDefaults: (): OpenFangConfig => {
return JSON.parse(JSON.stringify(DEFAULT_CONFIG)) as OpenFangConfig;
getDefaults: (): ZclawConfig => {
return JSON.parse(JSON.stringify(DEFAULT_CONFIG)) as ZclawConfig;
},
/**
* Check if a configuration object is valid
*
* @param config - The configuration to check
* @returns Type guard for OpenFangConfig
* @returns Type guard for ZclawConfig
*/
isOpenFangConfig: (config: unknown): config is OpenFangConfig => {
isZclawConfig: (config: unknown): config is ZclawConfig => {
const result = configParser.validateConfig(config);
return result.valid;
},

View File

@@ -7,13 +7,13 @@
* - Agents (Clones)
* - Stats & Workspace
* - Config (Quick Config, Channels, Skills, Scheduler, Models)
* - Hands (OpenFang)
* - Workflows (OpenFang)
* - Sessions (OpenFang)
* - Triggers (OpenFang)
* - Audit (OpenFang)
* - Security (OpenFang)
* - Approvals (OpenFang)
* - Hands (ZCLAW)
* - Workflows (ZCLAW)
* - Sessions (ZCLAW)
* - Triggers (ZCLAW)
* - Audit (ZCLAW)
* - Security (ZCLAW)
* - Approvals (ZCLAW)
*
* These methods are installed onto GatewayClient.prototype via installApiMethods().
* The GatewayClient core class exposes restGet/restPost/restPut/restDelete/restPatch
@@ -179,7 +179,7 @@ export function installApiMethods(ClientClass: { prototype: GatewayClient }): vo
const storedAutoStart = localStorage.getItem('zclaw-autoStart');
const storedShowToolCalls = localStorage.getItem('zclaw-showToolCalls');
// Map OpenFang config to frontend expected format
// Map ZCLAW config to frontend expected format
return {
quickConfig: {
agentName: 'ZCLAW',
@@ -220,15 +220,15 @@ export function installApiMethods(ClientClass: { prototype: GatewayClient }): vo
localStorage.setItem('zclaw-showToolCalls', String(config.showToolCalls));
}
// Map frontend config back to OpenFang format
const openfangConfig = {
// Map frontend config back to ZCLAW format
const zclawConfig = {
data_dir: config.workspaceDir,
default_model: config.defaultModel ? {
model: config.defaultModel,
provider: config.defaultProvider || 'bailian',
} : undefined,
};
return this.restPut('/api/config', openfangConfig);
return this.restPut('/api/config', zclawConfig);
};
// ─── Skills ───
@@ -333,7 +333,7 @@ export function installApiMethods(ClientClass: { prototype: GatewayClient }): vo
return this.restPatch(`/api/scheduler/tasks/${id}`, { enabled });
};
// ─── OpenFang Hands API ───
// ─── ZCLAW Hands API ───
proto.listHands = async function (this: GatewayClient): Promise<{
hands: {
@@ -407,7 +407,7 @@ export function installApiMethods(ClientClass: { prototype: GatewayClient }): vo
return this.restGet(`/api/hands/${name}/runs?${params}`);
};
// ─── OpenFang Workflows API ───
// ─── ZCLAW Workflows API ───
proto.listWorkflows = async function (this: GatewayClient): Promise<{ workflows: { id: string; name: string; steps: number }[] }> {
return this.restGet('/api/workflows');
@@ -476,7 +476,7 @@ export function installApiMethods(ClientClass: { prototype: GatewayClient }): vo
return this.restDelete(`/api/workflows/${id}`);
};
// ─── OpenFang Session API ───
// ─── ZCLAW Session API ───
proto.listSessions = async function (this: GatewayClient, opts?: { limit?: number; offset?: number }): Promise<{
sessions: Array<{
@@ -539,7 +539,7 @@ export function installApiMethods(ClientClass: { prototype: GatewayClient }): vo
return this.restGet(`/api/sessions/${sessionId}/messages?${params}`);
};
// ─── OpenFang Triggers API ───
// ─── ZCLAW Triggers API ───
proto.listTriggers = async function (this: GatewayClient): Promise<{ triggers: { id: string; type: string; enabled: boolean }[] }> {
return this.restGet('/api/triggers');
@@ -580,7 +580,7 @@ export function installApiMethods(ClientClass: { prototype: GatewayClient }): vo
return this.restDelete(`/api/triggers/${id}`);
};
// ─── OpenFang Audit API ───
// ─── ZCLAW Audit API ───
proto.getAuditLogs = async function (this: GatewayClient, opts?: { limit?: number; offset?: number }): Promise<{ logs: unknown[] }> {
const params = new URLSearchParams();
@@ -598,7 +598,7 @@ export function installApiMethods(ClientClass: { prototype: GatewayClient }): vo
return this.restGet(`/api/audit/verify/${logId}`);
};
// ─── OpenFang Security API ───
// ─── ZCLAW Security API ───
proto.getSecurityStatus = async function (this: GatewayClient): Promise<{ layers: { name: string; enabled: boolean }[] }> {
try {
@@ -626,7 +626,7 @@ export function installApiMethods(ClientClass: { prototype: GatewayClient }): vo
}
};
// ─── OpenFang Approvals API ───
// ─── ZCLAW Approvals API ───
proto.listApprovals = async function (this: GatewayClient, status?: string): Promise<{
approvals: {

View File

@@ -1,7 +1,7 @@
/**
/**
* ZCLAW Gateway Client (Browser/Tauri side)
*
* Core WebSocket client for OpenFang Kernel protocol.
* Core WebSocket client for ZCLAW Kernel protocol.
* Handles connection management, WebSocket framing, heartbeat,
* event dispatch, and chat/stream operations.
*
@@ -22,7 +22,7 @@ export type {
GatewayPong,
GatewayFrame,
AgentStreamDelta,
OpenFangStreamEvent,
ZclawStreamEvent,
ConnectionState,
EventCallback,
} from './gateway-types';
@@ -51,7 +51,7 @@ import type {
GatewayFrame,
GatewayResponse,
GatewayEvent,
OpenFangStreamEvent,
ZclawStreamEvent,
ConnectionState,
EventCallback,
AgentStreamDelta,
@@ -158,7 +158,7 @@ function createIdempotencyKey(): string {
export class GatewayClient {
private ws: WebSocket | null = null;
private openfangWs: WebSocket | null = null; // OpenFang stream WebSocket
private zclawWs: WebSocket | null = null; // ZCLAW stream WebSocket
private state: ConnectionState = 'disconnected';
private requestId = 0;
private pendingRequests = new Map<string, {
@@ -243,20 +243,20 @@ export class GatewayClient {
// === Connection ===
/** Connect using REST API only (for OpenFang mode) */
/** Connect using REST API only (for ZCLAW mode) */
async connectRest(): Promise<void> {
if (this.state === 'connected') {
return;
}
this.setState('connecting');
try {
// Check if OpenFang API is healthy
// Check if ZCLAW API is healthy
const health = await this.restGet<{ status: string; version?: string }>('/api/health');
if (health.status === 'ok') {
this.reconnectAttempts = 0;
this.setState('connected');
this.startHeartbeat(); // Start heartbeat after successful connection
this.log('info', `Connected to OpenFang via REST API${health.version ? ` (v${health.version})` : ''}`);
this.log('info', `Connected to ZCLAW via REST API${health.version ? ` (v${health.version})` : ''}`);
this.emitEvent('connected', { version: health.version });
} else {
throw new Error('Health check failed');
@@ -264,7 +264,7 @@ export class GatewayClient {
} catch (err: unknown) {
this.setState('disconnected');
const errorMessage = err instanceof Error ? err.message : String(err);
throw new Error(`Failed to connect to OpenFang: ${errorMessage}`);
throw new Error(`Failed to connect to ZCLAW: ${errorMessage}`);
}
}
@@ -273,7 +273,7 @@ export class GatewayClient {
return Promise.resolve();
}
// Check if URL is for OpenFang (port 4200 or 50051) - use REST mode
// Check if URL is for ZCLAW (port 4200 or 50051) - use REST mode
if (this.url.includes(':4200') || this.url.includes(':50051')) {
return this.connectRest();
}
@@ -389,10 +389,10 @@ export class GatewayClient {
// === High-level API ===
// Default agent ID for OpenFang (will be set dynamically from /api/agents)
// Default agent ID for ZCLAW (will be set dynamically from /api/agents)
private defaultAgentId: string = '';
/** Try to fetch default agent ID from OpenFang /api/agents endpoint */
/** Try to fetch default agent ID from ZCLAW /api/agents endpoint */
async fetchDefaultAgentId(): Promise<string | null> {
try {
// Use /api/agents endpoint which returns array of agents
@@ -422,7 +422,7 @@ export class GatewayClient {
return this.defaultAgentId;
}
/** Send message to agent (OpenFang chat API) */
/** Send message to agent (ZCLAW chat API) */
async chat(message: string, opts?: {
sessionKey?: string;
agentId?: string;
@@ -432,24 +432,24 @@ export class GatewayClient {
temperature?: number;
maxTokens?: number;
}): Promise<{ runId: string; sessionId?: string; response?: string }> {
// OpenFang uses /api/agents/{agentId}/message endpoint
// ZCLAW uses /api/agents/{agentId}/message endpoint
let agentId = opts?.agentId || this.defaultAgentId;
// If no agent ID, try to fetch from OpenFang status
// If no agent ID, try to fetch from ZCLAW status
if (!agentId) {
await this.fetchDefaultAgentId();
agentId = this.defaultAgentId;
}
if (!agentId) {
throw new Error('No agent available. Please ensure OpenFang has at least one agent.');
throw new Error('No agent available. Please ensure ZCLAW has at least one agent.');
}
const result = await this.restPost<{ response?: string; input_tokens?: number; output_tokens?: number }>(`/api/agents/${agentId}/message`, {
message,
session_id: opts?.sessionKey,
});
// OpenFang returns { response, input_tokens, output_tokens }
// ZCLAW returns { response, input_tokens, output_tokens }
return {
runId: createIdempotencyKey(),
sessionId: opts?.sessionKey,
@@ -457,7 +457,7 @@ export class GatewayClient {
};
}
/** Send message with streaming response (OpenFang WebSocket) */
/** Send message with streaming response (ZCLAW WebSocket) */
async chatStream(
message: string,
callbacks: {
@@ -472,20 +472,20 @@ export class GatewayClient {
agentId?: string;
}
): Promise<{ runId: string }> {
let agentId = opts?.agentId || this.defaultAgentId;
const agentId = opts?.agentId || this.defaultAgentId;
const runId = createIdempotencyKey();
const sessionId = opts?.sessionKey || `session_${Date.now()}`;
// If no agent ID, try to fetch from OpenFang status (async, but we'll handle it in connectOpenFangStream)
// If no agent ID, try to fetch from ZCLAW status (async, but we'll handle it in connectZclawStream)
if (!agentId) {
// Try to get default agent asynchronously
this.fetchDefaultAgentId().then(() => {
const resolvedAgentId = this.defaultAgentId;
if (resolvedAgentId) {
this.streamCallbacks.set(runId, callbacks);
this.connectOpenFangStream(resolvedAgentId, runId, sessionId, message);
this.connectZclawStream(resolvedAgentId, runId, sessionId, message);
} else {
callbacks.onError('No agent available. Please ensure OpenFang has at least one agent.');
callbacks.onError('No agent available. Please ensure ZCLAW has at least one agent.');
callbacks.onComplete();
}
}).catch((err) => {
@@ -498,22 +498,22 @@ export class GatewayClient {
// Store callbacks for this run
this.streamCallbacks.set(runId, callbacks);
// Connect to OpenFang WebSocket if not connected
this.connectOpenFangStream(agentId, runId, sessionId, message);
// Connect to ZCLAW WebSocket if not connected
this.connectZclawStream(agentId, runId, sessionId, message);
return { runId };
}
/** Connect to OpenFang streaming WebSocket */
private connectOpenFangStream(
/** Connect to ZCLAW streaming WebSocket */
private connectZclawStream(
agentId: string,
runId: string,
sessionId: string,
message: string
): void {
// Close existing connection if any
if (this.openfangWs && this.openfangWs.readyState !== WebSocket.CLOSED) {
this.openfangWs.close();
if (this.zclawWs && this.zclawWs.readyState !== WebSocket.CLOSED) {
this.zclawWs.close();
}
// Build WebSocket URL
@@ -528,34 +528,34 @@ export class GatewayClient {
wsUrl = httpUrl.replace(/^http/, 'ws') + `/api/agents/${agentId}/ws`;
}
this.log('info', `Connecting to OpenFang stream: ${wsUrl}`);
this.log('info', `Connecting to ZCLAW stream: ${wsUrl}`);
try {
this.openfangWs = new WebSocket(wsUrl);
this.zclawWs = new WebSocket(wsUrl);
this.openfangWs.onopen = () => {
this.log('info', 'OpenFang WebSocket connected');
// Send chat message using OpenFang actual protocol
this.zclawWs.onopen = () => {
this.log('info', 'ZCLAW WebSocket connected');
// Send chat message using ZCLAW actual protocol
const chatRequest = {
type: 'message',
content: message,
session_id: sessionId,
};
this.openfangWs?.send(JSON.stringify(chatRequest));
this.zclawWs?.send(JSON.stringify(chatRequest));
};
this.openfangWs.onmessage = (event) => {
this.zclawWs.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
this.handleOpenFangStreamEvent(runId, data, sessionId);
this.handleZclawStreamEvent(runId, data, sessionId);
} catch (err: unknown) {
const errorMessage = err instanceof Error ? err.message : String(err);
this.log('error', `Failed to parse stream event: ${errorMessage}`);
}
};
this.openfangWs.onerror = (_event) => {
this.log('error', 'OpenFang WebSocket error');
this.zclawWs.onerror = (_event) => {
this.log('error', 'ZCLAW WebSocket error');
const callbacks = this.streamCallbacks.get(runId);
if (callbacks) {
callbacks.onError('WebSocket connection failed');
@@ -563,14 +563,14 @@ export class GatewayClient {
}
};
this.openfangWs.onclose = (event) => {
this.log('info', `OpenFang WebSocket closed: ${event.code} ${event.reason}`);
this.zclawWs.onclose = (event) => {
this.log('info', `ZCLAW WebSocket closed: ${event.code} ${event.reason}`);
const callbacks = this.streamCallbacks.get(runId);
if (callbacks && event.code !== 1000) {
callbacks.onError(`Connection closed: ${event.reason || 'unknown'}`);
}
this.streamCallbacks.delete(runId);
this.openfangWs = null;
this.zclawWs = null;
};
} catch (err: unknown) {
const errorMessage = err instanceof Error ? err.message : String(err);
@@ -583,13 +583,13 @@ export class GatewayClient {
}
}
/** Handle OpenFang stream events */
private handleOpenFangStreamEvent(runId: string, data: OpenFangStreamEvent, sessionId: string): void {
/** Handle ZCLAW stream events */
private handleZclawStreamEvent(runId: string, data: ZclawStreamEvent, sessionId: string): void {
const callbacks = this.streamCallbacks.get(runId);
if (!callbacks) return;
switch (data.type) {
// OpenFang actual event types
// ZCLAW actual event types
case 'text_delta':
// Stream delta content
if (data.content) {
@@ -602,8 +602,8 @@ export class GatewayClient {
if (data.phase === 'done') {
callbacks.onComplete();
this.streamCallbacks.delete(runId);
if (this.openfangWs) {
this.openfangWs.close(1000, 'Stream complete');
if (this.zclawWs) {
this.zclawWs.close(1000, 'Stream complete');
}
}
break;
@@ -617,8 +617,8 @@ export class GatewayClient {
// Mark complete if phase done wasn't sent
callbacks.onComplete();
this.streamCallbacks.delete(runId);
if (this.openfangWs) {
this.openfangWs.close(1000, 'Stream complete');
if (this.zclawWs) {
this.zclawWs.close(1000, 'Stream complete');
}
break;
@@ -649,14 +649,14 @@ export class GatewayClient {
case 'error':
callbacks.onError(data.message || data.code || data.content || 'Unknown error');
this.streamCallbacks.delete(runId);
if (this.openfangWs) {
this.openfangWs.close(1011, 'Error');
if (this.zclawWs) {
this.zclawWs.close(1011, 'Error');
}
break;
case 'connected':
// Connection established
this.log('info', `OpenFang agent connected: ${data.agent_id}`);
this.log('info', `ZCLAW agent connected: ${data.agent_id}`);
break;
case 'agents_updated':
@@ -687,12 +687,12 @@ export class GatewayClient {
callbacks.onError('Stream cancelled');
this.streamCallbacks.delete(runId);
}
if (this.openfangWs && this.openfangWs.readyState === WebSocket.OPEN) {
this.openfangWs.close(1000, 'User cancelled');
if (this.zclawWs && this.zclawWs.readyState === WebSocket.OPEN) {
this.zclawWs.close(1000, 'User cancelled');
}
}
// === REST API Helpers (OpenFang) ===
// === REST API Helpers (ZCLAW) ===
public getRestBaseUrl(): string {
// In browser dev mode, use Vite proxy (empty string = relative path)

View File

@@ -1,5 +1,5 @@
/**
* OpenFang Gateway Configuration Types
* ZCLAW Gateway Configuration Types
*
* Types for gateway configuration and model choices.
*/

View File

@@ -42,7 +42,7 @@ export function isLocalhost(url: string): boolean {
// === URL Constants ===
// OpenFang endpoints (port 50051 - actual running port)
// ZCLAW endpoints (port 50051 - actual running port)
// Note: REST API uses relative path to leverage Vite proxy for CORS bypass
export const DEFAULT_GATEWAY_URL = `${DEFAULT_WS_PROTOCOL}127.0.0.1:50051/ws`;
export const REST_API_URL = ''; // Empty = use relative path (Vite proxy)

View File

@@ -66,8 +66,8 @@ export interface AgentStreamDelta {
workflowResult?: unknown;
}
/** OpenFang WebSocket stream event types */
export interface OpenFangStreamEvent {
/** ZCLAW WebSocket stream event types */
export interface ZclawStreamEvent {
type: 'text_delta' | 'phase' | 'response' | 'typing' | 'tool_call' | 'tool_result' | 'hand' | 'workflow' | 'error' | 'connected' | 'agents_updated';
content?: string;
phase?: 'streaming' | 'done';

View File

@@ -2,7 +2,7 @@
* Health Check Library
*
* Provides Tauri health check command wrappers and utilities
* for monitoring the health status of the OpenFang backend.
* for monitoring the health status of the ZCLAW backend.
*/
import { invoke } from '@tauri-apps/api/core';
@@ -19,7 +19,7 @@ export interface HealthCheckResult {
details?: Record<string, unknown>;
}
export interface OpenFangHealthResponse {
export interface ZclawHealthResponse {
healthy: boolean;
message?: string;
details?: Record<string, unknown>;
@@ -43,7 +43,7 @@ export async function performHealthCheck(): Promise<HealthCheckResult> {
}
try {
const response = await invoke<OpenFangHealthResponse>('openfang_health_check');
const response = await invoke<ZclawHealthResponse>('zclaw_health_check');
return {
status: response.healthy ? 'healthy' : 'unhealthy',

View File

@@ -239,6 +239,14 @@ export const memory = {
async dbPath(): Promise<string> {
return invoke('memory_db_path');
},
async buildContext(
agentId: string,
query: string,
maxTokens: number | null,
): Promise<{ systemPromptAddition: string; totalTokens: number; memoriesUsed: number }> {
return invoke('memory_build_context', { agentId, query, maxTokens });
},
};
// === Heartbeat API ===

View File

@@ -771,7 +771,7 @@ function saveSnapshotsToStorage(snapshots: IdentitySnapshot[]): void {
}
const fallbackIdentities = loadIdentitiesFromStorage();
let fallbackProposals = loadProposalsFromStorage();
const fallbackProposals = loadProposalsFromStorage();
let fallbackSnapshots = loadSnapshotsFromStorage();
const fallbackIdentity = {
@@ -1073,6 +1073,27 @@ export const intelligenceClient = {
}
return fallbackMemory.dbPath();
},
buildContext: async (
agentId: string,
query: string,
maxTokens?: number,
): Promise<{ systemPromptAddition: string; totalTokens: number; memoriesUsed: number }> => {
if (isTauriEnv()) {
return intelligence.memory.buildContext(agentId, query, maxTokens ?? null);
}
// Fallback: use basic search
const memories = await fallbackMemory.search({
agentId,
query,
limit: 8,
minImportance: 3,
});
const addition = memories.length > 0
? `## 相关记忆\n${memories.map(m => `- [${m.type}] ${m.content}`).join('\n')}`
: '';
return { systemPromptAddition: addition, totalTokens: 0, memoriesUsed: memories.length };
},
},
heartbeat: {

View File

@@ -2,7 +2,7 @@
* ZCLAW Kernel Client (Tauri Internal)
*
* Client for communicating with the internal ZCLAW Kernel via Tauri commands.
* This replaces the external OpenFang Gateway WebSocket connection.
* This replaces the external ZCLAW Gateway WebSocket connection.
*
* Phase 5 of Intelligence Layer Migration.
*/
@@ -648,24 +648,14 @@ export class KernelClient {
* Approve a hand execution
*/
async approveHand(name: string, runId: string, approved: boolean, reason?: string): Promise<{ status: string }> {
try {
return await invoke('hand_approve', { handName: name, runId, approved, reason });
} catch {
this.log('warn', `hand_approve not yet implemented, returning fallback`);
return { status: approved ? 'approved' : 'rejected' };
}
return await invoke('hand_approve', { handName: name, runId, approved, reason });
}
/**
* Cancel a hand execution
*/
async cancelHand(name: string, runId: string): Promise<{ status: string }> {
try {
return await invoke('hand_cancel', { handName: name, runId });
} catch {
this.log('warn', `hand_cancel not yet implemented, returning fallback`);
return { status: 'cancelled' };
}
return await invoke('hand_cancel', { handName: name, runId });
}
/**

View File

@@ -9,7 +9,7 @@
* Supports multiple backends:
* - OpenAI (GPT-4, GPT-3.5)
* - Volcengine (Doubao)
* - OpenFang Gateway (passthrough)
* - ZCLAW Gateway (passthrough)
*
* Part of ZCLAW L4 Self-Evolution capability.
*/
@@ -284,7 +284,7 @@ class VolcengineLLMAdapter implements LLMServiceAdapter {
}
}
// === Gateway Adapter (pass through to OpenFang or internal Kernel) ===
// === Gateway Adapter (pass through to ZCLAW or internal Kernel) ===
class GatewayLLMAdapter implements LLMServiceAdapter {
private config: LLMConfig;
@@ -346,7 +346,7 @@ class GatewayLLMAdapter implements LLMServiceAdapter {
}
}
// External Gateway mode: Use OpenFang's chat endpoint
// External Gateway mode: Use ZCLAW's chat endpoint
const agentId = localStorage.getItem('zclaw-default-agent-id') || 'default';
const response = await fetch(`/api/agents/${agentId}/message`, {
@@ -403,7 +403,7 @@ class GatewayLLMAdapter implements LLMServiceAdapter {
}
isAvailable(): boolean {
// Gateway is available if we're in browser (can connect to OpenFang)
// Gateway is available if we're in browser (can connect to ZCLAW)
return typeof window !== 'undefined';
}
@@ -460,7 +460,7 @@ export function loadConfig(): LLMConfig {
// Ignore parse errors
}
// Default to gateway (OpenFang passthrough) for L4 self-evolution
// Default to gateway (ZCLAW passthrough) for L4 self-evolution
return DEFAULT_CONFIGS.gateway;
}

View File

@@ -239,12 +239,7 @@ export function generateWelcomeMessage(config: {
const { userName, agentName, emoji, personality, scenarios } = config;
// Build greeting
let greeting = '';
if (userName) {
greeting = `你好,${userName}`;
} else {
greeting = '你好!';
}
const greeting = userName ? `你好,${userName}` : '你好!';
// Build introduction
let intro = `我是${emoji ? ' ' + emoji : ''} ${agentName}`;

View File

@@ -41,7 +41,7 @@ export function escapeHtml(input: string): string {
if (typeof input !== 'string') {
return '';
}
return input.replace(/[&<>"'`=\/]/g, char => HTML_ENTITIES[char] || char);
return input.replace(/[&<>"'`=/]/g, (char) => HTML_ENTITIES[char] || char);
}
/**
@@ -502,12 +502,13 @@ export function sanitizeFilename(filename: string): string {
}
// Remove path separators
let sanitized = filename.replace(/[\/\\]/g, '_');
let sanitized = filename.replace(/[/\\]/g, '_');
// Remove null bytes
sanitized = sanitized.replace(/\0/g, '');
// Remove control characters
// eslint-disable-next-line no-control-regex
sanitized = sanitized.replace(/[\x00-\x1f\x7f]/g, '');
// Remove dangerous characters

View File

@@ -1,7 +1,7 @@
/**
* TOML Utility Functions
*
* Provides TOML parsing and serialization capabilities for OpenFang configuration files.
* Provides TOML parsing and serialization capabilities for ZCLAW configuration files.
* Supports environment variable interpolation in the format ${VAR_NAME}.
*
* @module toml-utils

View File

@@ -369,7 +369,7 @@ export function yamlToCanvas(yamlString: string): WorkflowCanvas {
// Convert steps to nodes
if (pipeline.spec.steps) {
let x = 300;
const x = 300;
let y = 50;
for (const step of pipeline.spec.steps) {

View File

@@ -6,6 +6,7 @@
*/
import { create } from 'zustand';
import type { GatewayClient } from '../lib/gateway-client';
import { useChatStore } from './chatStore';
// === Types ===
@@ -209,14 +210,25 @@ export const useAgentStore = create<AgentStore>((set, get) => ({
},
loadUsageStats: async () => {
const client = getClient();
if (!client) {
console.warn('[AgentStore] Client not initialized, skipping loadUsageStats');
return;
}
try {
const stats = await client.getUsageStats();
const { conversations } = useChatStore.getState();
let totalMessages = 0;
for (const conversation of conversations) {
for (const message of conversation.messages) {
if (message.role === 'user' || message.role === 'assistant') {
totalMessages += 1;
}
}
}
const stats: UsageStats = {
totalSessions: conversations.length,
totalMessages,
totalTokens: 0,
byModel: {},
};
set({ usageStats: stats });
} catch {
// Usage stats are non-critical, ignore errors silently

View File

@@ -330,53 +330,28 @@ export const useChatStore = create<ChatState>()(
return;
}
// Check context compaction threshold before adding new message
try {
const messages = get().messages.map(m => ({ role: m.role, content: m.content }));
const check = await intelligenceClient.compactor.checkThreshold(messages);
if (check.should_compact) {
log.debug(`Context compaction triggered (${check.urgency}): ${check.current_tokens} tokens`);
const result = await intelligenceClient.compactor.compact(
get().messages.map(m => ({
role: m.role,
content: m.content,
id: m.id,
timestamp: m.timestamp instanceof Date ? m.timestamp.toISOString() : m.timestamp
})),
agentId,
get().currentConversationId ?? undefined
);
// Replace messages with compacted version
const compactedMsgs: Message[] = result.compacted_messages.map((m, i) => ({
id: m.id || `compacted_${i}_${Date.now()}`,
role: m.role as Message['role'],
content: m.content,
timestamp: m.timestamp ? new Date(m.timestamp) : new Date(),
}));
set({ messages: compactedMsgs });
}
} catch (err) {
log.warn('Context compaction check failed:', err);
}
// Context compaction is handled by the kernel (AgentLoop with_compaction_threshold).
// Frontend no longer performs duplicate compaction — see crates/zclaw-runtime/src/compaction.rs.
// Build memory-enhanced content
// Build memory-enhanced content using layered context (L0/L1/L2)
let enhancedContent = content;
try {
const relevantMemories = await intelligenceClient.memory.search({
const contextResult = await intelligenceClient.memory.buildContext(
agentId,
query: content,
limit: 8,
minImportance: 3,
});
const memoryContext = relevantMemories.length > 0
? `\n\n## 相关记忆\n${relevantMemories.map(m => `- [${m.type}] ${m.content}`).join('\n')}`
: '';
const systemPrompt = await intelligenceClient.identity.buildPrompt(agentId, memoryContext);
if (systemPrompt) {
enhancedContent = `<context>\n${systemPrompt}\n</context>\n\n${content}`;
content,
500, // token budget for memory context
);
if (contextResult.systemPromptAddition) {
const systemPrompt = await intelligenceClient.identity.buildPrompt(
agentId,
contextResult.systemPromptAddition,
);
if (systemPrompt) {
enhancedContent = `<context>\n${systemPrompt}\n</context>\n\n${content}`;
}
}
} catch (err) {
log.warn('Memory enhancement failed, proceeding without:', err);
log.warn('Memory context build failed, proceeding without:', err);
}
// Add user message (original content for display)
@@ -415,7 +390,7 @@ export const useChatStore = create<ChatState>()(
// Declare runId before chatStream so callbacks can access it
let runId = `run_${Date.now()}`;
// Try streaming first (OpenFang WebSocket)
// Try streaming first (ZCLAW WebSocket)
const result = await client.chatStream(
enhancedContent,
{
@@ -571,7 +546,7 @@ export const useChatStore = create<ChatState>()(
&& m.streaming
&& (
(delta.runId && m.runId === delta.runId)
|| (!delta.runId && m.runId == null)
|| (!delta.runId && m.runId === null)
)
))
|| [...state.messages]
@@ -616,7 +591,7 @@ export const useChatStore = create<ChatState>()(
}));
}
} else if (delta.stream === 'hand') {
// Handle Hand trigger events from OpenFang
// Handle Hand trigger events from ZCLAW
const handMsg: Message = {
id: `hand_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`,
role: 'hand',
@@ -631,7 +606,7 @@ export const useChatStore = create<ChatState>()(
};
set((s) => ({ messages: [...s.messages, handMsg] }));
} else if (delta.stream === 'workflow') {
// Handle Workflow execution events from OpenFang
// Handle Workflow execution events from ZCLAW
const workflowMsg: Message = {
id: `workflow_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`,
role: 'workflow',

View File

@@ -8,6 +8,7 @@ import { create } from 'zustand';
import type { GatewayModelChoice } from '../lib/gateway-config';
import { setStoredGatewayUrl, setStoredGatewayToken } from '../lib/gateway-client';
import type { GatewayClient } from '../lib/gateway-client';
import { invoke } from '@tauri-apps/api/core';
// === Types ===
@@ -654,9 +655,20 @@ function createConfigClientFromKernel(client: KernelClient): ConfigStoreClient {
createChannel: async () => null,
updateChannel: async () => null,
deleteChannel: async () => {},
listScheduledTasks: async () => ({ tasks: [] }),
createScheduledTask: async () => {
throw new Error('Scheduled tasks not supported in KernelClient');
listScheduledTasks: async () => {
try {
const tasks = await invoke<ScheduledTask[]>('scheduled_task_list');
return { tasks };
} catch {
return { tasks: [] };
}
},
createScheduledTask: async (task) => {
const result = await invoke<{ id: string; name: string; schedule: string; status: string }>(
'scheduled_task_create',
{ request: task },
);
return { ...result, status: result.status as 'active' | 'paused' | 'completed' | 'error' };
},
listModels: async () => {
try {

View File

@@ -249,7 +249,7 @@ interface GatewayFacade {
modelsLoading: boolean;
modelsError: string | null;
// OpenFang Data
// ZCLAW Data
hands: Hand[];
handRuns: Record<string, HandRun[]>;
workflows: Workflow[];

View File

@@ -2,7 +2,7 @@
* handStore.ts - Hand, Trigger, and Approval management store
*
* Extracted from gatewayStore.ts for Phase 11 Store Refactoring.
* Manages OpenFang Hands, Triggers, and Approval workflows.
* Manages ZCLAW Hands, Triggers, and Approval workflows.
*/
import { create } from 'zustand';
import type { GatewayClient } from '../lib/gateway-client';

View File

@@ -1,10 +1,11 @@
/**
* securityStore.ts - Security Status and Audit Log Management
*
* Extracted from gatewayStore.ts for Store Refactoring.
* Manages OpenFang security layers, security status, and audit logs.
* Manages ZCLAW security layers, security status, and audit logs.
* Uses local security checks (security-index.ts + Tauri commands) instead of REST API.
*/
import { create } from 'zustand';
import { invoke } from '@tauri-apps/api/core';
import type { GatewayClient } from '../lib/gateway-client';
// === Types ===
@@ -29,7 +30,7 @@ export interface AuditLogEntry {
actor?: string;
result?: 'success' | 'failure';
details?: Record<string, unknown>;
// Merkle hash chain fields (OpenFang)
// Merkle hash chain fields
hash?: string;
previousHash?: string;
}
@@ -45,6 +46,160 @@ function calculateSecurityLevel(enabledCount: number, totalCount: number): 'crit
return 'low'; // 0-5 layers
}
/**
* Check if OS Keyring (secure store) is available via Tauri command.
* Returns false if not in Tauri environment or if keyring is unavailable.
*/
async function checkKeyringAvailable(): Promise<boolean> {
try {
return await invoke<boolean>('secure_store_is_available');
} catch {
// Not in Tauri environment or command failed
return false;
}
}
/**
* Check if the ZCLAW Kernel is initialized via Tauri command.
*/
async function checkKernelInitialized(): Promise<boolean> {
try {
const status = await invoke<{ initialized: boolean }>('kernel_status');
return status.initialized;
} catch {
return false;
}
}
/**
* Build the 16-layer security model from local security checks.
*/
async function buildLocalSecurityLayers(): Promise<SecurityLayer[]> {
// Gather local security status
let auditEnabled = false;
let keychainAvailable = false;
let chatStorageInitialized = false;
try {
const { getSecurityStatus } = await import('../lib/security-index');
const status = await getSecurityStatus();
auditEnabled = status.auditEnabled;
keychainAvailable = status.keychainAvailable;
chatStorageInitialized = status.chatStorageInitialized;
} catch {
// Security module not available - use defaults
}
// Check OS Keyring availability directly via Tauri
const keyringAvailable = await checkKeyringAvailable();
const kernelInitialized = await checkKernelInitialized();
// Use keychainAvailable from security-index as primary, keyringAvailable as fallback
const hasSecureStorage = keychainAvailable || keyringAvailable;
// Map local security capabilities to the 16-layer security model
const layers: SecurityLayer[] = [
{
name: 'input.validation',
enabled: true,
description: 'security-utils.ts provides input validation and sanitization',
},
{
name: 'output.filter',
enabled: true,
description: 'security-utils.ts provides output sanitization and content filtering',
},
{
name: 'rate.limit',
enabled: true,
description: 'security-utils.ts provides rate limiting',
},
{
name: 'auth.identity',
enabled: hasSecureStorage,
description: hasSecureStorage
? 'OS Keyring available for secure identity storage'
: 'OS Keyring not available',
},
{
name: 'incident.response',
enabled: auditEnabled,
description: auditEnabled
? 'Automated incident detection and alerting via audit events'
: 'Requires audit logging for incident response',
},
{
name: 'session.management',
enabled: true,
description: 'Session management is always active',
},
{
name: 'auth.rbac',
enabled: hasSecureStorage,
description: hasSecureStorage
? 'Device authentication and role-based access available'
: 'Requires OS Keyring for device authentication',
},
{
name: 'encryption',
enabled: chatStorageInitialized,
description: chatStorageInitialized
? 'Encrypted chat storage is initialized (AES-256-GCM)'
: 'Encrypted storage not yet initialized',
},
{
name: 'audit.logging',
enabled: auditEnabled,
description: auditEnabled
? 'Security audit logging is active'
: 'Audit logging is disabled',
},
{
name: 'integrity',
enabled: auditEnabled,
description: auditEnabled
? 'Integrity verification enabled via audit log'
: 'Requires audit logging for integrity verification',
},
{
name: 'sandbox',
enabled: true,
description: 'Tauri sandbox provides process isolation',
},
{
name: 'network.security',
enabled: true,
description: 'WSS enforced, CSP headers active',
},
{
name: 'resource.limits',
enabled: true,
description: 'Path validation and timeout limits active',
},
{
name: 'capability.gates',
enabled: kernelInitialized,
description: kernelInitialized
? 'Kernel capability gates active'
: 'Kernel not yet initialized',
},
{
name: 'prompt.defense',
enabled: true,
description: 'Input sanitization includes prompt injection defense',
},
{
name: 'anomaly.detection',
enabled: auditEnabled,
description: auditEnabled
? 'Anomaly detection via security audit events'
: 'Requires audit logging for anomaly detection',
},
];
return layers;
}
// === Client Interface ===
interface SecurityClient {
@@ -81,32 +236,22 @@ export const useSecurityStore = create<SecurityStore>((set, get) => ({
client: null,
loadSecurityStatus: async () => {
const client = get().client;
if (!client) return;
set({ securityStatusLoading: true, securityStatusError: null });
try {
const result = await client.getSecurityStatus();
if (result?.layers) {
const layers = result.layers as SecurityLayer[];
const enabledCount = layers.filter(l => l.enabled).length;
const totalCount = layers.length;
const securityLevel = calculateSecurityLevel(enabledCount, totalCount);
set({
securityStatus: { layers, enabledCount, totalCount, securityLevel },
securityStatusLoading: false,
securityStatusError: null,
});
} else {
set({
securityStatusLoading: false,
securityStatusError: 'API returned no data',
});
}
const layers = await buildLocalSecurityLayers();
const enabledCount = layers.filter(l => l.enabled).length;
const totalCount = layers.length;
const securityLevel = calculateSecurityLevel(enabledCount, totalCount);
set({
securityStatus: { layers, enabledCount, totalCount, securityLevel },
securityStatusLoading: false,
securityStatusError: null,
});
} catch (err: unknown) {
const message = err instanceof Error ? err.message : String(err);
set({
securityStatusLoading: false,
securityStatusError: (err instanceof Error ? err.message : String(err)) || 'Security API not available',
securityStatusError: message || 'Failed to detect security status',
});
}
},

View File

@@ -1,12 +1,12 @@
/**
* Agent Type Definitions for OpenFang
* Agent Type Definitions for ZCLAW
*
* These types define the Agent entity structure and related configurations
* for the OpenFang desktop client.
* for the ZCLAW desktop client.
*/
/**
* Represents an Agent instance in OpenFang runtime
* Represents an Agent instance in ZCLAW runtime
*/
export interface Agent {
/** Unique identifier for the agent */

View File

@@ -1,8 +1,8 @@
/**
* API Response Types for OpenFang/ZCLAW
* API Response Types for ZCLAW
*
* Standard response envelope types for all API interactions with the
* OpenFang Kernel. These types provide a consistent interface for
* ZCLAW Kernel. These types provide a consistent interface for
* handling API responses, errors, and pagination across the application.
*
* @module types/api-responses

View File

@@ -1,7 +1,7 @@
/**
* OpenFang Configuration Type Definitions
* ZCLAW Configuration Type Definitions
*
* TypeScript types for OpenFang TOML configuration files.
* TypeScript types for ZCLAW TOML configuration files.
* These types correspond to the configuration schema in config/config.toml.
*
* @module types/config
@@ -491,9 +491,9 @@ export interface DevelopmentConfig {
// ============================================================
/**
* Complete OpenFang configuration
* Complete ZCLAW configuration
*/
export interface OpenFangConfig {
export interface ZclawConfig {
/** Server settings */
server: ServerConfig;
/** Agent settings */

View File

@@ -1,8 +1,8 @@
/**
* Error Type Hierarchy for OpenFang/ZCLAW
* Error Type Hierarchy for ZCLAW
*
* Comprehensive error types for type-safe error handling across
* the OpenFang desktop client application.
* the ZCLAW desktop client application.
*
* @module types/errors
*/
@@ -193,7 +193,7 @@ export class ForbiddenError extends AppError {
/**
* RBAC Permission denied error
*
* Specific to OpenFang's role-based access control system.
* Specific to ZCLAW's role-based access control system.
*/
export class RBACPermissionDeniedError extends AppError {
constructor(
@@ -285,7 +285,7 @@ export class JsonParseError extends AppError {
/**
* TOML parsing errors
*
* Specific to OpenFang's TOML configuration format.
* Specific to ZCLAW's TOML configuration format.
*/
export class TomlParseError extends AppError {
constructor(
@@ -518,7 +518,7 @@ export class KeyringUnavailableError extends StorageError {
/**
* Hand execution errors
*
* Specific to OpenFang's Hands system for autonomous capabilities.
* Specific to ZCLAW's Hands system for autonomous capabilities.
*/
export class HandExecutionError extends AppError {
public readonly handId: string;

View File

@@ -1,5 +1,5 @@
/**
* OpenFang Hands and Workflow Types
* ZCLAW Hands and Workflow Types
*
* ZCLAW 提供 8 个自主能力包 (Hands)
* - Clip: 视频处理

View File

@@ -1,8 +1,8 @@
/**
* OpenFang Type Definitions
* ZCLAW Type Definitions
*
* This module exports all TypeScript type definitions for the
* OpenFang desktop client application.
* ZCLAW desktop client application.
*
* @module types
*/

View File

@@ -1,8 +1,8 @@
/**
* Session Type Definitions for OpenFang
* Session Type Definitions for ZCLAW
*
* These types define the Session and message structures
* for conversation management in the OpenFang desktop client.
* for conversation management in the ZCLAW desktop client.
*/
/**

View File

@@ -1,8 +1,8 @@
/**
* Settings Type Definitions for OpenFang
* Settings Type Definitions for ZCLAW
*
* These types define the configuration and settings structures
* for the OpenFang desktop client.
* for the ZCLAW desktop client.
*/
/**
@@ -33,7 +33,7 @@ export interface QuickConfig {
workspaceDir?: string;
// Gateway Configuration
/** URL for the OpenFang gateway server */
/** URL for the ZCLAW gateway server */
gatewayUrl?: string;
/** Authentication token for gateway */
gatewayToken?: string;

View File

@@ -1,14 +1,14 @@
/**
* Workflow Type Definitions for OpenFang
* Workflow Type Definitions for ZCLAW
*
* This module defines all TypeScript types related to workflow
* management, execution, and monitoring in the OpenFang system.
* management, execution, and monitoring in the ZCLAW system.
*
* @module types/workflow
*/
/**
* Types of workflow steps available in OpenFang
* Types of workflow steps available in ZCLAW
*/
export type WorkflowStepType =
| 'hand' // Execute a Hand (autonomous capability)