feat: initialize ZCLAW project with core systems and Tauri desktop
- Created backend core systems: - Remote Execution System (远程执行系统) - Task Orchestration Engine (任务编排引擎) - Persistent Memory System (持续记忆系统) - Proactive Service System (主动服务系统) - Created Tauri desktop app: - Three-column layout based on AutoClaw design - React + TypeScript + Tailwind CSS - Zustand state management - Lucide React icons - Components: - Sidebar (Agent list, IM channels, scheduled tasks) - ChatArea (Chat interface with message bubbles) - RightPanel (Task progress, statistics, next actions) Next: Test Tauri dev server and integrate with OpenClaw backend
This commit is contained in:
1
src/core/memory/index.ts
Normal file
1
src/core/memory/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './memory';
|
||||
54
src/core/memory/memory.ts
Normal file
54
src/core/memory/memory.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
// 持续记忆系统
|
||||
export interface UserProfile {
|
||||
id: string;
|
||||
preferences: {
|
||||
language: 'zh' | 'en';
|
||||
timezone: string;
|
||||
responseStyle: 'concise' | 'detailed';
|
||||
};
|
||||
patterns: {
|
||||
activeHours: number[];
|
||||
frequentCommands: string[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface MemoryEvent {
|
||||
id: string;
|
||||
userId: string;
|
||||
type: string;
|
||||
content: any;
|
||||
timestamp: Date;
|
||||
embedding?: number[];
|
||||
}
|
||||
|
||||
export class PersistentMemorySystem {
|
||||
private profiles: Map<string, UserProfile> = new Map();
|
||||
private events: MemoryEvent[] = [];
|
||||
|
||||
async remember(userId: string, event: MemoryEvent): Promise<void> {
|
||||
event.id = event.id || this.generateId();
|
||||
event.timestamp = new Date();
|
||||
this.events.push(event);
|
||||
console.log([Memory] Event remembered: );
|
||||
}
|
||||
|
||||
async recall(userId: string, query: string, limit: number = 10): Promise<MemoryEvent[]> {
|
||||
// TODO: 实现向量搜索(后续实现)
|
||||
return this.events.filter(e => e.userId === userId).slice(0, limit);
|
||||
}
|
||||
|
||||
async getProfile(userId: string): Promise<UserProfile | undefined> {
|
||||
return this.profiles.get(userId);
|
||||
}
|
||||
|
||||
async updateProfile(userId: string, updates: Partial<UserProfile>): Promise<void> {
|
||||
const profile = this.profiles.get(userId);
|
||||
if (profile) {
|
||||
Object.assign(profile, updates);
|
||||
}
|
||||
}
|
||||
|
||||
private generateId(): string {
|
||||
return mem__;
|
||||
}
|
||||
}
|
||||
1
src/core/proactive/index.ts
Normal file
1
src/core/proactive/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './proactive';
|
||||
49
src/core/proactive/proactive.ts
Normal file
49
src/core/proactive/proactive.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
// 主动服务系统
|
||||
export interface ScheduledTask {
|
||||
id: string;
|
||||
userId: string;
|
||||
channel: string;
|
||||
schedule: {
|
||||
type: 'once' | 'daily' | 'weekly' | 'cron';
|
||||
time: string;
|
||||
timezone: string;
|
||||
};
|
||||
task: {
|
||||
type: string;
|
||||
prompt: string;
|
||||
};
|
||||
status: 'active' | 'paused' | 'completed';
|
||||
lastRun?: Date;
|
||||
nextRun?: Date;
|
||||
}
|
||||
|
||||
export class ProactiveServiceSystem {
|
||||
private tasks: Map<string, ScheduledTask> = new Map();
|
||||
private cronJobs: Map<string, any> = new Map();
|
||||
|
||||
async scheduleTask(task: ScheduledTask): Promise<void> {
|
||||
task.id = task.id || this.generateId();
|
||||
task.status = 'active';
|
||||
|
||||
this.tasks.set(task.id, task);
|
||||
|
||||
// TODO: 使用 node-cron 设置定时任务(后续实现)
|
||||
console.log([Proactive] Task scheduled: );
|
||||
}
|
||||
|
||||
async cancelTask(taskId: string): Promise<void> {
|
||||
const task = this.tasks.get(taskId);
|
||||
if (task) {
|
||||
task.status = 'paused';
|
||||
// TODO: 取消 cron job
|
||||
}
|
||||
}
|
||||
|
||||
async listTasks(userId: string): Promise<ScheduledTask[]> {
|
||||
return Array.from(this.tasks.values()).filter(t => t.userId === userId);
|
||||
}
|
||||
|
||||
private generateId(): string {
|
||||
return cron__;
|
||||
}
|
||||
}
|
||||
125
src/core/remote-execution/engine.ts
Normal file
125
src/core/remote-execution/engine.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
// 远程执行系统 - 实现类
|
||||
import type {
|
||||
RemoteExecutionSystem,
|
||||
Device,
|
||||
Task,
|
||||
TaskStatus,
|
||||
StatusHandler,
|
||||
Result,
|
||||
DeviceStatus
|
||||
} from './types';
|
||||
|
||||
export class RemoteExecutionEngine implements RemoteExecutionSystem {
|
||||
private devices: Map<string, Device> = new Map();
|
||||
private tasks: Map<string, Task> = new Map();
|
||||
private subscriptions: Map<string, StatusHandler[]> = new Map();
|
||||
private taskQueue: Task[] = [];
|
||||
|
||||
async registerDevice(device: Device): Promise<void> {
|
||||
this.devices.set(device.id, device);
|
||||
console.log([RemoteExecution] Device registered: ());
|
||||
}
|
||||
|
||||
async heartbeat(deviceId: string): Promise<DeviceStatus> {
|
||||
const device = this.devices.get(deviceId);
|
||||
if (!device) {
|
||||
throw new Error(Device not found: );
|
||||
}
|
||||
|
||||
device.lastHeartbeat = new Date();
|
||||
return device.status;
|
||||
}
|
||||
|
||||
async submitTask(task: Task): Promise<string> {
|
||||
task.id = task.id || this.generateId();
|
||||
task.status = 'pending';
|
||||
task.createdAt = new Date();
|
||||
|
||||
this.tasks.set(task.id, task);
|
||||
this.taskQueue.push(task);
|
||||
|
||||
console.log([RemoteExecution] Task submitted: );
|
||||
|
||||
// 立即执行(后续会改为队列处理)
|
||||
this.executeTask(task).catch(console.error);
|
||||
|
||||
return task.id;
|
||||
}
|
||||
|
||||
async cancelTask(taskId: string): Promise<void> {
|
||||
const task = this.tasks.get(taskId);
|
||||
if (!task) {
|
||||
throw new Error(Task not found: );
|
||||
}
|
||||
|
||||
task.status = 'cancelled';
|
||||
this.notifySubscribers(taskId, 'cancelled');
|
||||
}
|
||||
|
||||
async getStatus(taskId: string): Promise<TaskStatus> {
|
||||
const task = this.tasks.get(taskId);
|
||||
if (!task) {
|
||||
throw new Error(Task not found: );
|
||||
}
|
||||
|
||||
return task.status;
|
||||
}
|
||||
|
||||
subscribe(taskId: string, handler: StatusHandler): void {
|
||||
if (!this.subscriptions.has(taskId)) {
|
||||
this.subscriptions.set(taskId, []);
|
||||
}
|
||||
this.subscriptions.get(taskId)!.push(handler);
|
||||
}
|
||||
|
||||
async pushResult(taskId: string, result: Result): Promise<void> {
|
||||
const task = this.tasks.get(taskId);
|
||||
if (!task) {
|
||||
throw new Error(Task not found: );
|
||||
}
|
||||
|
||||
task.result = result;
|
||||
task.status = result.success ? 'completed' : 'failed';
|
||||
task.completedAt = new Date();
|
||||
|
||||
this.notifySubscribers(taskId, task.status);
|
||||
}
|
||||
|
||||
private async executeTask(task: Task): Promise<void> {
|
||||
try {
|
||||
task.status = 'running';
|
||||
task.startedAt = new Date();
|
||||
this.notifySubscribers(task.id, 'running');
|
||||
|
||||
// TODO: 实际执行逻辑(调用 OpenClaw SDK)
|
||||
console.log([RemoteExecution] Executing task: );
|
||||
|
||||
// 模拟执行
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
|
||||
await this.pushResult(task.id, {
|
||||
taskId: task.id,
|
||||
success: true,
|
||||
data: { message: 'Task completed successfully' }
|
||||
});
|
||||
|
||||
} catch (error: any) {
|
||||
await this.pushResult(task.id, {
|
||||
taskId: task.id,
|
||||
success: false,
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private notifySubscribers(taskId: string, status: TaskStatus, progress?: number): void {
|
||||
const handlers = this.subscriptions.get(taskId);
|
||||
if (handlers) {
|
||||
handlers.forEach(handler => handler(status, progress));
|
||||
}
|
||||
}
|
||||
|
||||
private generateId(): string {
|
||||
return ask__;
|
||||
}
|
||||
}
|
||||
2
src/core/remote-execution/index.ts
Normal file
2
src/core/remote-execution/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './types';
|
||||
export * from './engine';
|
||||
46
src/core/remote-execution/types.ts
Normal file
46
src/core/remote-execution/types.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
// 远程执行系统 - 核心接口
|
||||
export interface Device {
|
||||
id: string;
|
||||
name: string;
|
||||
userId: string;
|
||||
platform: 'macos' | 'windows' | 'linux';
|
||||
capabilities: string[];
|
||||
status: 'online' | 'offline' | 'busy';
|
||||
lastHeartbeat: Date;
|
||||
}
|
||||
|
||||
export interface Task {
|
||||
id: string;
|
||||
userId: string;
|
||||
deviceId: string;
|
||||
channel: string;
|
||||
type: 'immediate' | 'scheduled';
|
||||
priority: 'high' | 'normal' | 'low';
|
||||
payload: any;
|
||||
status: TaskStatus;
|
||||
result?: any;
|
||||
createdAt: Date;
|
||||
startedAt?: Date;
|
||||
completedAt?: Date;
|
||||
}
|
||||
|
||||
export type TaskStatus = 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
|
||||
|
||||
export interface RemoteExecutionSystem {
|
||||
registerDevice(device: Device): Promise<void>;
|
||||
heartbeat(deviceId: string): Promise<DeviceStatus>;
|
||||
submitTask(task: Task): Promise<string>;
|
||||
cancelTask(taskId: string): Promise<void>;
|
||||
getStatus(taskId: string): Promise<TaskStatus>;
|
||||
subscribe(taskId: string, handler: StatusHandler): void;
|
||||
pushResult(taskId: string, result: Result): Promise<void>;
|
||||
}
|
||||
|
||||
export type StatusHandler = (status: TaskStatus, progress?: number) => void;
|
||||
export type DeviceStatus = 'online' | 'offline' | 'busy';
|
||||
export interface Result {
|
||||
taskId: string;
|
||||
success: boolean;
|
||||
data?: any;
|
||||
error?: string;
|
||||
}
|
||||
2
src/core/task-orchestration/index.ts
Normal file
2
src/core/task-orchestration/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './types';
|
||||
export * from './orchestrator';
|
||||
186
src/core/task-orchestration/orchestrator.ts
Normal file
186
src/core/task-orchestration/orchestrator.ts
Normal file
@@ -0,0 +1,186 @@
|
||||
// 任务编排引擎 - 实现类
|
||||
import type {
|
||||
TaskOrchestrationEngine,
|
||||
TaskPlan,
|
||||
TaskStep,
|
||||
ExecutionResult,
|
||||
Progress,
|
||||
StepStatus
|
||||
} from './types';
|
||||
|
||||
export class TaskOrchestrator implements TaskOrchestrationEngine {
|
||||
private plans: Map<string, TaskPlan> = new Map();
|
||||
|
||||
async plan(goal: string, context: any): Promise<TaskPlan> {
|
||||
// TODO: 使用 AI 规划任务(后续实现)
|
||||
// 这里先返回一个简单的示例计划
|
||||
const steps: TaskStep[] = [
|
||||
{
|
||||
id: 'step_1',
|
||||
description: '分析任务需求',
|
||||
tool: 'ai',
|
||||
params: { goal },
|
||||
dependencies: [],
|
||||
status: 'pending'
|
||||
},
|
||||
{
|
||||
id: 'step_2',
|
||||
description: '执行任务',
|
||||
tool: 'executor',
|
||||
params: { goal },
|
||||
dependencies: ['step_1'],
|
||||
status: 'pending'
|
||||
},
|
||||
{
|
||||
id: 'step_3',
|
||||
description: '整理结果',
|
||||
tool: 'combiner',
|
||||
params: {},
|
||||
dependencies: ['step_2'],
|
||||
status: 'pending'
|
||||
}
|
||||
];
|
||||
|
||||
const plan: TaskPlan = {
|
||||
id: this.generateId(),
|
||||
goal,
|
||||
steps,
|
||||
dependencies: new Map(),
|
||||
context: new Map(Object.entries(context)),
|
||||
status: 'planned',
|
||||
progress: 0
|
||||
};
|
||||
|
||||
this.plans.set(plan.id, plan);
|
||||
console.log([TaskOrchestrator] Plan created: );
|
||||
|
||||
return plan;
|
||||
}
|
||||
|
||||
async execute(plan: TaskPlan): Promise<ExecutionResult> {
|
||||
plan.status = 'executing';
|
||||
|
||||
try {
|
||||
// 拓扑排序
|
||||
const sortedSteps = this.topologicalSort(plan.steps);
|
||||
|
||||
for (const step of sortedSteps) {
|
||||
// 检查依赖
|
||||
await this.waitForDependencies(step, plan);
|
||||
|
||||
// 执行步骤
|
||||
step.status = 'running';
|
||||
plan.progress = this.calculateProgress(plan);
|
||||
|
||||
console.log([TaskOrchestrator] Executing step: );
|
||||
|
||||
// TODO: 实际执行逻辑(后续实现)
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
|
||||
step.status = 'completed';
|
||||
step.result = { message: 'Step completed' };
|
||||
|
||||
plan.progress = this.calculateProgress(plan);
|
||||
}
|
||||
|
||||
plan.status = 'completed';
|
||||
plan.progress = 1;
|
||||
|
||||
return {
|
||||
planId: plan.id,
|
||||
status: 'completed',
|
||||
results: plan.steps.map(s => s.result)
|
||||
};
|
||||
|
||||
} catch (error: any) {
|
||||
plan.status = 'failed';
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async getProgress(planId: string): Promise<Progress> {
|
||||
const plan = this.plans.get(planId);
|
||||
if (!plan) {
|
||||
throw new Error(Plan not found: );
|
||||
}
|
||||
|
||||
const completed = plan.steps.filter(s => s.status === 'completed').length;
|
||||
const percentage = (plan.progress * 100).toFixed(1) + '%';
|
||||
|
||||
return {
|
||||
planId: plan.id,
|
||||
goal: plan.goal,
|
||||
total: plan.steps.length,
|
||||
completed,
|
||||
current: plan.steps.find(s => s.status === 'running')?.description || '',
|
||||
percentage,
|
||||
steps: plan.steps.map(s => ({
|
||||
description: s.description,
|
||||
status: s.status,
|
||||
result: s.result
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
async pause(planId: string): Promise<void> {
|
||||
const plan = this.plans.get(planId);
|
||||
if (plan) {
|
||||
plan.status = 'paused';
|
||||
}
|
||||
}
|
||||
|
||||
async resume(planId: string): Promise<void> {
|
||||
const plan = this.plans.get(planId);
|
||||
if (plan && plan.status === 'paused') {
|
||||
plan.status = 'executing';
|
||||
// 继续执行(后续实现)
|
||||
}
|
||||
}
|
||||
|
||||
async cancel(planId: string): Promise<void> {
|
||||
const plan = this.plans.get(planId);
|
||||
if (plan) {
|
||||
plan.status = 'failed';
|
||||
}
|
||||
}
|
||||
|
||||
private topologicalSort(steps: TaskStep[]): TaskStep[] {
|
||||
// 简单实现:按依赖顺序排序
|
||||
const sorted: TaskStep[] = [];
|
||||
const visited = new Set<string>();
|
||||
|
||||
const visit = (step: TaskStep) => {
|
||||
if (visited.has(step.id)) return;
|
||||
visited.add(step.id);
|
||||
|
||||
for (const depId of step.dependencies) {
|
||||
const dep = steps.find(s => s.id === depId);
|
||||
if (dep) visit(dep);
|
||||
}
|
||||
|
||||
sorted.push(step);
|
||||
};
|
||||
|
||||
steps.forEach(visit);
|
||||
return sorted;
|
||||
}
|
||||
|
||||
private async waitForDependencies(step: TaskStep, plan: TaskPlan): Promise<void> {
|
||||
for (const depId of step.dependencies) {
|
||||
const dep = plan.steps.find(s => s.id === depId);
|
||||
if (dep && dep.status !== 'completed') {
|
||||
// 等待依赖完成(简单实现)
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private calculateProgress(plan: TaskPlan): number {
|
||||
const completed = plan.steps.filter(s => s.status === 'completed').length;
|
||||
return completed / plan.steps.length;
|
||||
}
|
||||
|
||||
private generateId(): string {
|
||||
return plan__;
|
||||
}
|
||||
}
|
||||
53
src/core/task-orchestration/types.ts
Normal file
53
src/core/task-orchestration/types.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
// 任务编排引擎 - 类型定义
|
||||
export interface TaskPlan {
|
||||
id: string;
|
||||
goal: string;
|
||||
steps: TaskStep[];
|
||||
dependencies: Map<string, string[]>;
|
||||
context: Map<string, any>;
|
||||
status: PlanStatus;
|
||||
progress: number;
|
||||
}
|
||||
|
||||
export interface TaskStep {
|
||||
id: string;
|
||||
description: string;
|
||||
tool: string;
|
||||
params: any;
|
||||
dependencies: string[];
|
||||
status: StepStatus;
|
||||
result?: any;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export type PlanStatus = 'planned' | 'executing' | 'completed' | 'failed' | 'paused';
|
||||
export type StepStatus = 'pending' | 'running' | 'completed' | 'failed' | 'skipped';
|
||||
|
||||
export interface ExecutionResult {
|
||||
planId: string;
|
||||
status: PlanStatus;
|
||||
results: any[];
|
||||
}
|
||||
|
||||
export interface Progress {
|
||||
planId: string;
|
||||
goal: string;
|
||||
total: number;
|
||||
completed: number;
|
||||
current: string;
|
||||
percentage: string;
|
||||
steps: Array<{
|
||||
description: string;
|
||||
status: StepStatus;
|
||||
result?: any;
|
||||
}>;
|
||||
}
|
||||
|
||||
export interface TaskOrchestrationEngine {
|
||||
plan(goal: string, context: any): Promise<TaskPlan>;
|
||||
execute(plan: TaskPlan): Promise<ExecutionResult>;
|
||||
getProgress(planId: string): Promise<Progress>;
|
||||
pause(planId: string): Promise<void>;
|
||||
resume(planId: string): Promise<void>;
|
||||
cancel(planId: string): Promise<void>;
|
||||
}
|
||||
5
src/index.ts
Normal file
5
src/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
// ZCLAW 入口文件
|
||||
export * from './core/remote-execution';
|
||||
export * from './core/task-orchestration';
|
||||
export * from './core/memory';
|
||||
export * from './core/proactive';
|
||||
Reference in New Issue
Block a user