@myassis/gateway 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +194 -0
- package/dist/.env +6 -0
- package/dist/api/index.js +182 -0
- package/dist/config/index.js +41 -0
- package/dist/index.js +183 -0
- package/dist/middleware/auth.js +53 -0
- package/dist/middleware/errorHandler.js +20 -0
- package/dist/routes/agent.js +513 -0
- package/dist/routes/auth.js +172 -0
- package/dist/routes/chat.js +45 -0
- package/dist/routes/config.js +21 -0
- package/dist/routes/models.js +123 -0
- package/dist/routes/service.js +240 -0
- package/dist/routes/settings.js +101 -0
- package/dist/routes/skillHub.js +126 -0
- package/dist/routes/skills.js +159 -0
- package/dist/routes/tasks.js +149 -0
- package/dist/routes/upload.js +129 -0
- package/dist/routes/version.js +66 -0
- package/dist/services/HMSPushService.js +24 -0
- package/dist/services/LocalTaskService.js +223 -0
- package/dist/services/NotificationService.js +242 -0
- package/dist/services/ServiceManager.js +348 -0
- package/dist/services/TaskSchedulerService.js +195 -0
- package/dist/services/TaskService.js +240 -0
- package/dist/services/WebSocketService.js +236 -0
- package/dist/services/agent/Agent.js +120 -0
- package/dist/services/agent/AgentManager.js +265 -0
- package/dist/services/agent/AgentStore.js +73 -0
- package/dist/services/dataService.js +293 -0
- package/dist/services/index.js +15 -0
- package/dist/services/llm/LLMClient.js +724 -0
- package/dist/services/memory/MemoryManager.js +117 -0
- package/dist/services/model/ModelCapabilities.js +141 -0
- package/dist/services/model/index.js +4 -0
- package/dist/services/models.js +16 -0
- package/dist/services/session/MigrationManager.js +176 -0
- package/dist/services/session/Session.js +733 -0
- package/dist/services/session/SessionManager.js +255 -0
- package/dist/services/session/SessionStore.js +186 -0
- package/dist/services/session/index.js +3 -0
- package/dist/services/skills.js +34 -0
- package/dist/services/systemPrompt.js +150 -0
- package/dist/services/task/PushTokenStore.js +124 -0
- package/dist/services/task/TaskStore.js +143 -0
- package/dist/services/tools/calculator.js +27 -0
- package/dist/services/tools/edit.js +318 -0
- package/dist/services/tools/exec.js +119 -0
- package/dist/services/tools/fetch.js +155 -0
- package/dist/services/tools/file.js +315 -0
- package/dist/services/tools/index.js +48 -0
- package/dist/services/tools/keyboard.js +145 -0
- package/dist/services/tools/model.js +86 -0
- package/dist/services/tools/mouse.js +55 -0
- package/dist/services/tools/screenshot.js +19 -0
- package/dist/services/tools/search.js +53 -0
- package/dist/services/tools/skill.js +108 -0
- package/dist/services/tools/task.js +110 -0
- package/dist/services/tools/types.js +1 -0
- package/dist/services/tools/webFetch.js +34 -0
- package/dist/stores/authStore.js +178 -0
- package/dist/stores/index.js +6 -0
- package/dist/stores/memoryStore.js +191 -0
- package/dist/stores/persistStore.js +317 -0
- package/package.json +94 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
2
|
+
import { Agent } from './Agent';
|
|
3
|
+
import { sessionManager } from '../session/SessionManager';
|
|
4
|
+
import { authStore } from '@/stores/authStore';
|
|
5
|
+
import { getLogger } from '@pocketclaw/shared';
|
|
6
|
+
import appConfig from '@/config';
|
|
7
|
+
const logger = getLogger('AgentManager');
|
|
8
|
+
/**
|
|
9
|
+
* AgentManager - Business logic layer
|
|
10
|
+
* Manages multiple agents in memory
|
|
11
|
+
*/
|
|
12
|
+
export class AgentManager {
|
|
13
|
+
store;
|
|
14
|
+
agents = null;
|
|
15
|
+
initialized = false;
|
|
16
|
+
constructor(store) {
|
|
17
|
+
this.store = store;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Initialize - Load all agents from database on startup
|
|
21
|
+
*/
|
|
22
|
+
initialize() {
|
|
23
|
+
if (this.initialized) {
|
|
24
|
+
logger.warn('Already initialized');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const userId = this.getCurrentUserId();
|
|
28
|
+
if (!userId) {
|
|
29
|
+
logger.info('No user logged in, skipping initialization');
|
|
30
|
+
this.initialized = true;
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
this.agents = new Map();
|
|
34
|
+
// Load all agents from database
|
|
35
|
+
const agentDataList = this.store.findByUserId(userId);
|
|
36
|
+
for (const agentData of agentDataList) {
|
|
37
|
+
const agent = new Agent(agentData, this.store, this);
|
|
38
|
+
this.agents.set(agent.id, agent);
|
|
39
|
+
}
|
|
40
|
+
// If no agents exist, create default "MyClaw" agent
|
|
41
|
+
if (this.agents.size === 0) {
|
|
42
|
+
logger.info('No agents found, creating default "MyClaw" agent');
|
|
43
|
+
this.createDefaultAgent(userId);
|
|
44
|
+
}
|
|
45
|
+
// Ensure exactly one agent has isCurrent=true
|
|
46
|
+
const hasCurrent = Array.from(this.agents.values()).some(a => a.isCurrent);
|
|
47
|
+
if (!hasCurrent) {
|
|
48
|
+
const first = Array.from(this.agents.values())[0];
|
|
49
|
+
if (first) {
|
|
50
|
+
first.isCurrent = true;
|
|
51
|
+
first.save();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
this.initialized = true;
|
|
55
|
+
logger.info(`Initialized with ${this.agents.size} agents for user ${userId}`);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get current user ID
|
|
59
|
+
*/
|
|
60
|
+
getCurrentUserId() {
|
|
61
|
+
const user = authStore.getUser();
|
|
62
|
+
return user ? String(user.id) : null;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Create default "MyClaw" agent
|
|
66
|
+
*/
|
|
67
|
+
createDefaultAgent(userId) {
|
|
68
|
+
const agentData = {
|
|
69
|
+
id: uuidv4(),
|
|
70
|
+
userId,
|
|
71
|
+
name: appConfig.appName,
|
|
72
|
+
description: '默认 AI 助手',
|
|
73
|
+
systemPrompt: undefined,
|
|
74
|
+
avatar: undefined,
|
|
75
|
+
config: undefined,
|
|
76
|
+
createdAt: Date.now(),
|
|
77
|
+
updatedAt: Date.now(),
|
|
78
|
+
isCurrent: true,
|
|
79
|
+
};
|
|
80
|
+
this.store.insert(agentData);
|
|
81
|
+
const agent = new Agent(agentData, this.store, this);
|
|
82
|
+
this.agents.set(agent.id, agent);
|
|
83
|
+
// Create default session
|
|
84
|
+
agent.createSession({ title: '新会话' });
|
|
85
|
+
logger.info(`Created default agent: ${agent.id}`);
|
|
86
|
+
return agent;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get agent list summary
|
|
90
|
+
*/
|
|
91
|
+
getAgentList() {
|
|
92
|
+
this.ensureInitialized();
|
|
93
|
+
const userId = this.getCurrentUserId();
|
|
94
|
+
if (!userId)
|
|
95
|
+
return [];
|
|
96
|
+
const agentDataList = this.store.findByUserId(userId);
|
|
97
|
+
return agentDataList.map(data => {
|
|
98
|
+
const sessions = sessionManager.getUserSessions();
|
|
99
|
+
const agentSessions = sessions
|
|
100
|
+
.filter(s => s.agentId === data.id)
|
|
101
|
+
.map(s => ({
|
|
102
|
+
id: s.id,
|
|
103
|
+
title: s.title,
|
|
104
|
+
createdAt: s.createdAt,
|
|
105
|
+
updatedAt: s.updatedAt,
|
|
106
|
+
isCurrent: s.isCurrent,
|
|
107
|
+
unreadCount: s.unreadCount
|
|
108
|
+
}));
|
|
109
|
+
return {
|
|
110
|
+
...data,
|
|
111
|
+
sessionCount: agentSessions.length,
|
|
112
|
+
sessions: agentSessions,
|
|
113
|
+
unreadCount: agentSessions.reduce((sum, item) => sum + item.unreadCount, 0)
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get agent by ID
|
|
119
|
+
*/
|
|
120
|
+
getAgent(agentId) {
|
|
121
|
+
this.ensureInitialized();
|
|
122
|
+
return this.agents.get(agentId) || null;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Create new agent
|
|
126
|
+
*/
|
|
127
|
+
createAgent(config) {
|
|
128
|
+
const userId = this.getCurrentUserId();
|
|
129
|
+
if (!userId) {
|
|
130
|
+
throw new Error('No user logged in, cannot create agent');
|
|
131
|
+
}
|
|
132
|
+
// Check if name already exists
|
|
133
|
+
const existing = this.store.findByName(userId, config.name);
|
|
134
|
+
if (existing) {
|
|
135
|
+
throw new Error(`Agent with name "${config.name}" already exists`);
|
|
136
|
+
}
|
|
137
|
+
const agentData = {
|
|
138
|
+
id: uuidv4(),
|
|
139
|
+
userId,
|
|
140
|
+
name: config.name,
|
|
141
|
+
description: config.description,
|
|
142
|
+
systemPrompt: config.systemPrompt,
|
|
143
|
+
avatar: config.avatar,
|
|
144
|
+
config: config.config,
|
|
145
|
+
createdAt: Date.now(),
|
|
146
|
+
updatedAt: Date.now(),
|
|
147
|
+
};
|
|
148
|
+
this.store.insert(agentData);
|
|
149
|
+
const agent = new Agent(agentData, this.store, this);
|
|
150
|
+
this.agents.set(agent.id, agent);
|
|
151
|
+
// Create default session
|
|
152
|
+
agent.createSession({ title: '新会话' });
|
|
153
|
+
logger.info(`Created agent: ${agent.name} (${agent.id})`);
|
|
154
|
+
return agent;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Update agent
|
|
158
|
+
*/
|
|
159
|
+
updateAgent(agentId, updates) {
|
|
160
|
+
const agent = this.agents.get(agentId);
|
|
161
|
+
if (!agent)
|
|
162
|
+
return null;
|
|
163
|
+
// Check name conflict
|
|
164
|
+
if (updates.name && updates.name !== agent.name) {
|
|
165
|
+
const userId = this.getCurrentUserId();
|
|
166
|
+
const existing = this.store.findByName(userId, updates.name);
|
|
167
|
+
if (existing && existing.id !== agentId) {
|
|
168
|
+
throw new Error(`Agent with name "${updates.name}" already exists`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
agent.update(updates);
|
|
172
|
+
return agent;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Delete agent
|
|
176
|
+
*/
|
|
177
|
+
deleteAgent(agentId) {
|
|
178
|
+
const agent = this.agents.get(agentId);
|
|
179
|
+
if (!agent)
|
|
180
|
+
return false;
|
|
181
|
+
// Cannot delete the last agent
|
|
182
|
+
if (this.agents.size <= 1) {
|
|
183
|
+
throw new Error('Cannot delete the last agent');
|
|
184
|
+
}
|
|
185
|
+
const wasCurrent = agent.isCurrent;
|
|
186
|
+
// Delete all sessions under this agent
|
|
187
|
+
const sessions = agent.getSessions();
|
|
188
|
+
for (const session of sessions) {
|
|
189
|
+
sessionManager.deleteSession(session.id);
|
|
190
|
+
}
|
|
191
|
+
// Delete agent
|
|
192
|
+
this.store.delete(agentId);
|
|
193
|
+
this.agents.delete(agentId);
|
|
194
|
+
// If deleted agent was current, set first remaining as current
|
|
195
|
+
if (wasCurrent && this.agents.size > 0) {
|
|
196
|
+
const first = Array.from(this.agents.values())[0];
|
|
197
|
+
if (first) {
|
|
198
|
+
first.isCurrent = true;
|
|
199
|
+
first.save();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
logger.info(`Deleted agent: ${agentId}`);
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Set current agent (when user views it)
|
|
207
|
+
*/
|
|
208
|
+
setCurrentAgent(agentId) {
|
|
209
|
+
this.ensureInitialized();
|
|
210
|
+
// 清除旧当前 Agent 的 isCurrent 标记
|
|
211
|
+
const old = Array.from(this.agents.values()).find(a => a.isCurrent);
|
|
212
|
+
if (old) {
|
|
213
|
+
old.isCurrent = false;
|
|
214
|
+
old.save();
|
|
215
|
+
}
|
|
216
|
+
// 设置新当前 Agent
|
|
217
|
+
if (agentId) {
|
|
218
|
+
const next = this.agents.get(agentId);
|
|
219
|
+
if (next) {
|
|
220
|
+
next.isCurrent = true;
|
|
221
|
+
next.save();
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Get current agent
|
|
227
|
+
*/
|
|
228
|
+
getCurrentAgent() {
|
|
229
|
+
this.ensureInitialized();
|
|
230
|
+
return Array.from(this.agents.values()).find(a => a.isCurrent) || null;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Get sessions under an agent
|
|
234
|
+
*/
|
|
235
|
+
getAgentSessions(agentId) {
|
|
236
|
+
const sessions = sessionManager.getUserSessions();
|
|
237
|
+
return sessions
|
|
238
|
+
.filter(s => s.agentId === agentId)
|
|
239
|
+
.map(s => ({
|
|
240
|
+
id: s.id,
|
|
241
|
+
title: s.title,
|
|
242
|
+
createdAt: s.createdAt,
|
|
243
|
+
updatedAt: s.updatedAt,
|
|
244
|
+
}));
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Reload (for login switch)
|
|
248
|
+
*/
|
|
249
|
+
reload() {
|
|
250
|
+
this.initialized = false;
|
|
251
|
+
this.agents = null;
|
|
252
|
+
this.initialize();
|
|
253
|
+
}
|
|
254
|
+
ensureInitialized() {
|
|
255
|
+
if (!this.initialized) {
|
|
256
|
+
this.initialize();
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// Export singleton
|
|
261
|
+
export let agentManager;
|
|
262
|
+
export function initAgentManager(store) {
|
|
263
|
+
agentManager = new AgentManager(store);
|
|
264
|
+
return agentManager;
|
|
265
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { getLogger } from '@pocketclaw/shared';
|
|
2
|
+
const logger = getLogger('AgentStore');
|
|
3
|
+
/**
|
|
4
|
+
* AgentStore - Data access layer
|
|
5
|
+
* Operates on SQLite database
|
|
6
|
+
*/
|
|
7
|
+
export class AgentStore {
|
|
8
|
+
db;
|
|
9
|
+
constructor(db) {
|
|
10
|
+
this.db = db;
|
|
11
|
+
this.initTable();
|
|
12
|
+
}
|
|
13
|
+
initTable() {
|
|
14
|
+
// Ensure agents table exists
|
|
15
|
+
this.db.exec(`
|
|
16
|
+
CREATE TABLE IF NOT EXISTS agents (
|
|
17
|
+
id TEXT PRIMARY KEY,
|
|
18
|
+
user_id TEXT NOT NULL,
|
|
19
|
+
name TEXT NOT NULL,
|
|
20
|
+
description TEXT,
|
|
21
|
+
system_prompt TEXT,
|
|
22
|
+
avatar TEXT,
|
|
23
|
+
config TEXT,
|
|
24
|
+
created_at INTEGER NOT NULL,
|
|
25
|
+
updated_at INTEGER NOT NULL
|
|
26
|
+
)
|
|
27
|
+
`);
|
|
28
|
+
logger.info('Tables initialized');
|
|
29
|
+
}
|
|
30
|
+
// ========== Agent Operations ==========
|
|
31
|
+
insert(agent) {
|
|
32
|
+
this.db.prepare(`
|
|
33
|
+
INSERT INTO agents (id, user_id, name, description, system_prompt, avatar, config, created_at, updated_at, is_current)
|
|
34
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
35
|
+
`).run(agent.id, agent.userId, agent.name, agent.description || null, agent.systemPrompt || null, agent.avatar || null, agent.config || null, agent.createdAt, agent.updatedAt, agent.isCurrent ? 1 : 0);
|
|
36
|
+
}
|
|
37
|
+
update(agent) {
|
|
38
|
+
this.db.prepare(`
|
|
39
|
+
UPDATE agents
|
|
40
|
+
SET name = ?, description = ?, system_prompt = ?, avatar = ?, config = ?, updated_at = ?, is_current = ?
|
|
41
|
+
WHERE id = ?
|
|
42
|
+
`).run(agent.name, agent.description || null, agent.systemPrompt || null, agent.avatar || null, agent.config || null, agent.updatedAt, agent.isCurrent ? 1 : 0, agent.id);
|
|
43
|
+
}
|
|
44
|
+
delete(id) {
|
|
45
|
+
this.db.prepare('DELETE FROM agents WHERE id = ?').run(id);
|
|
46
|
+
}
|
|
47
|
+
findById(id) {
|
|
48
|
+
const row = this.db.prepare('SELECT * FROM agents WHERE id = ?').get(id);
|
|
49
|
+
return row ? this.rowToData(row) : null;
|
|
50
|
+
}
|
|
51
|
+
findByUserId(userId) {
|
|
52
|
+
const rows = this.db.prepare('SELECT * FROM agents WHERE user_id = ? ORDER BY updated_at DESC').all(userId);
|
|
53
|
+
return rows.map(row => this.rowToData(row));
|
|
54
|
+
}
|
|
55
|
+
findByName(userId, name) {
|
|
56
|
+
const row = this.db.prepare('SELECT * FROM agents WHERE user_id = ? AND name = ?').get(userId, name);
|
|
57
|
+
return row ? this.rowToData(row) : null;
|
|
58
|
+
}
|
|
59
|
+
rowToData(row) {
|
|
60
|
+
return {
|
|
61
|
+
id: row.id,
|
|
62
|
+
userId: row.user_id,
|
|
63
|
+
name: row.name,
|
|
64
|
+
description: row.description || undefined,
|
|
65
|
+
systemPrompt: row.system_prompt || undefined,
|
|
66
|
+
avatar: row.avatar || undefined,
|
|
67
|
+
config: row.config || undefined,
|
|
68
|
+
createdAt: row.created_at,
|
|
69
|
+
updatedAt: row.updated_at,
|
|
70
|
+
isCurrent: !!row.is_current,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway 数据服务层
|
|
3
|
+
* 直接转发服务端数据,不做二次包装
|
|
4
|
+
*
|
|
5
|
+
* 服务端路由结构:
|
|
6
|
+
* - /api/v1/auth/* - 认证路由 (login, register, logout, me, profile, password, account)
|
|
7
|
+
* - /api/v1/data/* - 用户数据路由 (models, skills, tasks, settings)
|
|
8
|
+
* - /api/v1/skill-hubs/* - 技能库路由
|
|
9
|
+
*/
|
|
10
|
+
import { authApi, skillsApi, skillHubApi, modelsApi, settingsApi } from '../api';
|
|
11
|
+
import { authStore, memoryStore, persistStore } from '../stores';
|
|
12
|
+
import { taskService } from './TaskService';
|
|
13
|
+
import { getLogger } from '@pocketclaw/shared';
|
|
14
|
+
const logger = getLogger('DataService');
|
|
15
|
+
// ============ 认证服务 ============
|
|
16
|
+
export const authService = {
|
|
17
|
+
// 登录
|
|
18
|
+
login: async (account, password, platform) => {
|
|
19
|
+
const response = await authApi.login({ account, password, platform });
|
|
20
|
+
if (response.success && response.data) {
|
|
21
|
+
const expiresIn = response.data.expiresIn || 86400;
|
|
22
|
+
authStore.save({
|
|
23
|
+
token: response.data.accessToken,
|
|
24
|
+
refreshToken: response.data.refreshToken,
|
|
25
|
+
expiresIn,
|
|
26
|
+
expiresAt: Date.now() + expiresIn * 1000,
|
|
27
|
+
user: response.data.user
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return response;
|
|
31
|
+
},
|
|
32
|
+
// 注册
|
|
33
|
+
register: async (account, password, platform) => {
|
|
34
|
+
const response = await authApi.register({
|
|
35
|
+
account,
|
|
36
|
+
password,
|
|
37
|
+
nickname: account,
|
|
38
|
+
platform
|
|
39
|
+
});
|
|
40
|
+
if (response.success && response.data) {
|
|
41
|
+
const expiresIn = response.data.expiresIn || 86400;
|
|
42
|
+
authStore.save({
|
|
43
|
+
token: response.data.accessToken,
|
|
44
|
+
refreshToken: response.data.refreshToken,
|
|
45
|
+
expiresIn,
|
|
46
|
+
expiresAt: Date.now() + expiresIn * 1000,
|
|
47
|
+
user: response.data.user
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return response;
|
|
51
|
+
},
|
|
52
|
+
// 登出
|
|
53
|
+
logout: async () => {
|
|
54
|
+
try {
|
|
55
|
+
await authApi.logout();
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
// 忽略错误
|
|
59
|
+
}
|
|
60
|
+
authStore.clear();
|
|
61
|
+
return { success: true };
|
|
62
|
+
},
|
|
63
|
+
// 获取当前用户
|
|
64
|
+
me: () => authApi.me(),
|
|
65
|
+
// 更新资料
|
|
66
|
+
updateProfile: (data) => authApi.updateProfile(data),
|
|
67
|
+
// 修改密码
|
|
68
|
+
changePassword: (oldPassword, newPassword) => authApi.changePassword({ oldPassword, newPassword }),
|
|
69
|
+
// 删除账号
|
|
70
|
+
deleteAccount: (password) => authApi.deleteAccount({ password }),
|
|
71
|
+
// 获取认证状态
|
|
72
|
+
isAuthenticated: () => authStore.isAuthenticated(),
|
|
73
|
+
// 获取当前用户(从内存)
|
|
74
|
+
getUser: () => authStore.get()?.user || null,
|
|
75
|
+
// 获取 Token
|
|
76
|
+
getToken: () => authStore.getToken(),
|
|
77
|
+
// 刷新 Token
|
|
78
|
+
refresh: async (refreshToken) => {
|
|
79
|
+
const response = await authApi.refresh(refreshToken);
|
|
80
|
+
if (response.success && response.accessToken) {
|
|
81
|
+
authStore.updateToken(response.accessToken, response.refreshToken);
|
|
82
|
+
}
|
|
83
|
+
return response;
|
|
84
|
+
},
|
|
85
|
+
// 检查认证(供 Desktop 使用)
|
|
86
|
+
checkAuth: async () => {
|
|
87
|
+
const isAuth = authStore.isAuthenticated();
|
|
88
|
+
const user = authStore.get()?.user || null;
|
|
89
|
+
return { success: true, authenticated: isAuth, user };
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
// ============ 技能服务 (用户已安装的技能) ============
|
|
93
|
+
export const skillsService = {
|
|
94
|
+
list: async () => await skillsApi.list(),
|
|
95
|
+
get: (skillId) => skillsApi.get(skillId),
|
|
96
|
+
install: async (skillHubId) => {
|
|
97
|
+
// 1. 从技能库获取技能详情
|
|
98
|
+
const hubResult = await skillHubApi.get(skillHubId);
|
|
99
|
+
if (!hubResult.success || !hubResult.data) {
|
|
100
|
+
return { success: false, error: '获取技能详情失败' };
|
|
101
|
+
}
|
|
102
|
+
const hub = hubResult.data;
|
|
103
|
+
// 2. 创建用户技能记录
|
|
104
|
+
const skillData = {
|
|
105
|
+
name: hub.name,
|
|
106
|
+
description: hub.description || '',
|
|
107
|
+
content: hub.content || '',
|
|
108
|
+
icon: hub.icon,
|
|
109
|
+
templateId: skillHubId,
|
|
110
|
+
isActive: true,
|
|
111
|
+
apiKeyRequired: hub.apiKeyRequired || false,
|
|
112
|
+
};
|
|
113
|
+
const response = await skillsApi.create(skillData);
|
|
114
|
+
if (response.success) {
|
|
115
|
+
// 3. 增加安装计数
|
|
116
|
+
await skillHubApi.install(skillHubId);
|
|
117
|
+
}
|
|
118
|
+
return response;
|
|
119
|
+
},
|
|
120
|
+
update: (skillId, data) => skillsApi.update(skillId, data),
|
|
121
|
+
uninstall: async (skillId) => await skillsApi.uninstall(skillId),
|
|
122
|
+
setApiKey: (skillId, apiKey) => {
|
|
123
|
+
persistStore.setSkillApiKey(skillId, apiKey);
|
|
124
|
+
return { success: true };
|
|
125
|
+
},
|
|
126
|
+
getApiKey: async (skillId) => {
|
|
127
|
+
const apikey = persistStore.getSkillApiKey(skillId);
|
|
128
|
+
if (!apikey) {
|
|
129
|
+
// 判断是否有内置 apikey
|
|
130
|
+
const skill = (await skillsService.get(skillId)).data;
|
|
131
|
+
if (skill.templateId) {
|
|
132
|
+
const skillHub = (await skillHubService.get(skill.templateId)).data;
|
|
133
|
+
if (skillHub?.builtinApikey) {
|
|
134
|
+
persistStore.setSkillApiKey(skillId, skillHub.builtinApikey);
|
|
135
|
+
return { success: true, apiKey: skillHub.builtinApikey };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return { success: true, apiKey: apikey?.apiKey };
|
|
140
|
+
},
|
|
141
|
+
rate: (skillId, score) => skillsApi.rate(skillId, { score }),
|
|
142
|
+
parse: (content) => skillsApi.parse({ content }),
|
|
143
|
+
create: async (data) => {
|
|
144
|
+
const response = await skillsApi.create(data);
|
|
145
|
+
if (response.success) {
|
|
146
|
+
// 创建成功后更新技能列表缓存
|
|
147
|
+
const listResponse = await skillsApi.list();
|
|
148
|
+
if (listResponse.success) {
|
|
149
|
+
memoryStore.set('skills', listResponse.data);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return response;
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
// ============ 技能库服务 (可安装的技能) ============
|
|
156
|
+
export const skillHubService = {
|
|
157
|
+
list: (params) => skillHubApi.list(params),
|
|
158
|
+
get: (hubId) => skillHubApi.get(hubId),
|
|
159
|
+
categories: () => skillHubApi.categories(),
|
|
160
|
+
preinstalled: () => skillHubApi.preinstalled(),
|
|
161
|
+
user: () => skillHubApi.user(),
|
|
162
|
+
checkUsed: (hubId) => skillHubApi.checkUsed(hubId),
|
|
163
|
+
rate: (hubId, rating) => skillHubApi.rate(hubId, rating),
|
|
164
|
+
userRating: (hubId) => skillHubApi.userRating(hubId),
|
|
165
|
+
install: (hubId) => skillHubApi.install(hubId),
|
|
166
|
+
use: (hubId) => skillHubApi.use(hubId),
|
|
167
|
+
};
|
|
168
|
+
// ============ 模型服务 ============
|
|
169
|
+
export const modelsService = {
|
|
170
|
+
list: () => modelsApi.list(),
|
|
171
|
+
get: (modelId) => modelsApi.get(modelId),
|
|
172
|
+
create: (data) => modelsApi.create(data),
|
|
173
|
+
update: (modelId, data) => modelsApi.update(modelId, data),
|
|
174
|
+
delete: (modelId) => modelsApi.delete(modelId),
|
|
175
|
+
setPrimary: (modelId) => modelsApi.setPrimary(modelId),
|
|
176
|
+
};
|
|
177
|
+
export const tasksService = {
|
|
178
|
+
list: async (params, userId) => {
|
|
179
|
+
const result = await taskService.listTasks({
|
|
180
|
+
status: params?.status,
|
|
181
|
+
userId,
|
|
182
|
+
page: params?.page ? parseInt(params.page) : undefined,
|
|
183
|
+
pageSize: params?.pageSize ? parseInt(params.pageSize) : undefined,
|
|
184
|
+
});
|
|
185
|
+
return { success: true, data: result.tasks, total: result.total };
|
|
186
|
+
},
|
|
187
|
+
get: async (taskId) => {
|
|
188
|
+
const task = await taskService.getTask(taskId);
|
|
189
|
+
if (!task)
|
|
190
|
+
return { success: false, error: 'Task not found' };
|
|
191
|
+
return { success: true, data: task };
|
|
192
|
+
},
|
|
193
|
+
create: async (data, userId) => {
|
|
194
|
+
const uid = userId || data?.userId || 'local';
|
|
195
|
+
try {
|
|
196
|
+
const result = await taskService.createTask({
|
|
197
|
+
userId: uid,
|
|
198
|
+
title: data.title,
|
|
199
|
+
description: data.description,
|
|
200
|
+
taskType: data.taskType,
|
|
201
|
+
recurrenceRule: data.recurrenceRule,
|
|
202
|
+
intervalValue: data.intervalValue,
|
|
203
|
+
intervalUnit: data.intervalUnit,
|
|
204
|
+
scheduledAt: data.scheduledAt,
|
|
205
|
+
startTime: data.startTime,
|
|
206
|
+
endTime: data.endTime,
|
|
207
|
+
platformApply: data.platformApply,
|
|
208
|
+
pushToken: data.pushToken,
|
|
209
|
+
});
|
|
210
|
+
return { success: true, data: { id: result.id, isLocal: result.isLocal } };
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
logger.error('[tasksService] Create failed', { error });
|
|
214
|
+
return { success: false, error: error.message };
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
update: async (taskId, data) => {
|
|
218
|
+
try {
|
|
219
|
+
const result = await taskService.updateTask(taskId, {
|
|
220
|
+
title: data.title,
|
|
221
|
+
description: data.description,
|
|
222
|
+
taskType: data.taskType,
|
|
223
|
+
recurrenceRule: data.recurrenceRule,
|
|
224
|
+
intervalValue: data.intervalValue,
|
|
225
|
+
intervalUnit: data.intervalUnit,
|
|
226
|
+
scheduledAt: data.scheduledAt,
|
|
227
|
+
startTime: data.startTime,
|
|
228
|
+
endTime: data.endTime,
|
|
229
|
+
status: data.status,
|
|
230
|
+
platformApply: data.platformApply,
|
|
231
|
+
pushToken: data.pushToken,
|
|
232
|
+
});
|
|
233
|
+
return { success: result };
|
|
234
|
+
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
logger.error('[tasksService] Update failed', { taskId, error });
|
|
237
|
+
return { success: false, error: error.message };
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
delete: async (taskId) => {
|
|
241
|
+
try {
|
|
242
|
+
const result = await taskService.deleteTask(taskId);
|
|
243
|
+
return { success: result };
|
|
244
|
+
}
|
|
245
|
+
catch (error) {
|
|
246
|
+
logger.error('[tasksService] Delete failed', { taskId, error });
|
|
247
|
+
return { success: false, error: error.message };
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
cancel: async (taskId) => {
|
|
251
|
+
try {
|
|
252
|
+
const result = await taskService.cancelTask(taskId);
|
|
253
|
+
return { success: result };
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
logger.error('[tasksService] Cancel failed', { taskId, error });
|
|
257
|
+
return { success: false, error: error.message };
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
updateStatus: async (taskId, status) => {
|
|
261
|
+
try {
|
|
262
|
+
const result = await taskService.updateTaskStatus(taskId, status);
|
|
263
|
+
return { success: result };
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
logger.error('[tasksService] UpdateStatus failed', { taskId, status, error });
|
|
267
|
+
return { success: false, error: error.message };
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
// ============ 设置服务 ============
|
|
272
|
+
export const settingsService = {
|
|
273
|
+
get: async () => {
|
|
274
|
+
const settings = memoryStore.get('settings'); // 预热缓存
|
|
275
|
+
if (settings) {
|
|
276
|
+
return { success: true, data: settings };
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
const response = await settingsApi.get();
|
|
280
|
+
if (response.success) {
|
|
281
|
+
memoryStore.set('settings', response.data); // 更新缓存
|
|
282
|
+
}
|
|
283
|
+
return response;
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
update: async (data) => {
|
|
287
|
+
const response = await settingsApi.update(data);
|
|
288
|
+
if (response.success) {
|
|
289
|
+
memoryStore.set('settings', response.data); // 更新缓存
|
|
290
|
+
}
|
|
291
|
+
return response;
|
|
292
|
+
},
|
|
293
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Re-export all services from dataService
|
|
2
|
+
export { authService, skillsService, skillHubService, modelsService, settingsService, } from './dataService';
|
|
3
|
+
// Re-export tasksService from dataService (server-only tasks)
|
|
4
|
+
export { tasksService } from './dataService';
|
|
5
|
+
// Re-export session manager
|
|
6
|
+
export { sessionManager } from './session';
|
|
7
|
+
// Re-export task services
|
|
8
|
+
export { taskSchedulerService } from './TaskSchedulerService';
|
|
9
|
+
export { taskService } from './TaskService';
|
|
10
|
+
export { localTaskService } from './LocalTaskService';
|
|
11
|
+
// Re-export notification and holiday services
|
|
12
|
+
export { notificationService } from './NotificationService';
|
|
13
|
+
// Re-export task stores
|
|
14
|
+
export { TaskStore } from './task/TaskStore';
|
|
15
|
+
export { PushTokenStore } from './task/PushTokenStore';
|