@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,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway Skills 路由
|
|
3
|
+
* 用户已安装技能管理
|
|
4
|
+
*/
|
|
5
|
+
import express from 'express';
|
|
6
|
+
import { skillsService } from '../services/index.js';
|
|
7
|
+
import { persistStore } from '../stores/persistStore.js';
|
|
8
|
+
import { getLogger } from '@pocketclaw/shared';
|
|
9
|
+
import { requireAuth } from '../middleware/auth.js';
|
|
10
|
+
const logger = getLogger('skills');
|
|
11
|
+
const router = express.Router();
|
|
12
|
+
router.use(requireAuth);
|
|
13
|
+
/**
|
|
14
|
+
* 获取用户已安装的技能列表
|
|
15
|
+
* GET /api/v1/skills
|
|
16
|
+
*/
|
|
17
|
+
router.get('/', async (req, res) => {
|
|
18
|
+
try {
|
|
19
|
+
const result = await skillsService.list();
|
|
20
|
+
res.json(result);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
logger.error('获取技能列表失败:', error?.message);
|
|
24
|
+
res.status(500).json({ success: false, error: '获取技能列表失败' });
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* 解析技能内容(从脚本中提取技能元数据)
|
|
29
|
+
* POST /api/v1/skills/parse
|
|
30
|
+
*/
|
|
31
|
+
router.post('/parse', async (req, res) => {
|
|
32
|
+
try {
|
|
33
|
+
const { content } = req.body;
|
|
34
|
+
if (!content) {
|
|
35
|
+
return res.status(400).json({ success: false, error: '缺少 content 参数' });
|
|
36
|
+
}
|
|
37
|
+
const result = await skillsService.parse(content);
|
|
38
|
+
res.json(result);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
logger.error('解析技能内容失败:', error?.message);
|
|
42
|
+
res.status(500).json({ success: false, error: '解析技能内容失败' });
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
/**
|
|
46
|
+
* 获取单个技能详情
|
|
47
|
+
* GET /api/v1/skills/:id
|
|
48
|
+
*/
|
|
49
|
+
router.get('/:id', async (req, res) => {
|
|
50
|
+
try {
|
|
51
|
+
const skillId = req.params.id;
|
|
52
|
+
const result = await skillsService.get(skillId);
|
|
53
|
+
res.json(result);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
logger.error('获取技能详情失败:', error?.message);
|
|
57
|
+
res.status(500).json({ success: false, error: '获取技能详情失败' });
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
/**
|
|
61
|
+
* 安装技能(从技能库安装)或创建自定义技能
|
|
62
|
+
* POST /api/v1/skills
|
|
63
|
+
* - 有 skillHubId → 从技能库安装
|
|
64
|
+
* - 无 skillHubId → 创建自定义技能(需提供 name, content 等)
|
|
65
|
+
*/
|
|
66
|
+
router.post('/', async (req, res) => {
|
|
67
|
+
try {
|
|
68
|
+
const { skillHubId } = req.body;
|
|
69
|
+
if (skillHubId) {
|
|
70
|
+
// 从技能库安装
|
|
71
|
+
const hubId = String(skillHubId);
|
|
72
|
+
const result = await skillsService.install(hubId);
|
|
73
|
+
res.json(result);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
// 创建自定义技能
|
|
77
|
+
if (!req.body.name) {
|
|
78
|
+
return res.status(400).json({ success: false, error: '自定义技能必须提供 name' });
|
|
79
|
+
}
|
|
80
|
+
const result = await skillsService.create(req.body);
|
|
81
|
+
res.json(result);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
logger.error('安装/创建技能失败:', error?.message);
|
|
86
|
+
res.status(500).json({ success: false, error: error?.message || '操作失败' });
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
/**
|
|
90
|
+
* 更新技能
|
|
91
|
+
* PUT /api/v1/skills/:id
|
|
92
|
+
*/
|
|
93
|
+
router.put('/:id', async (req, res) => {
|
|
94
|
+
try {
|
|
95
|
+
const skillId = req.params.id;
|
|
96
|
+
const result = await skillsService.update(skillId, req.body);
|
|
97
|
+
res.json(result);
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
logger.error('更新技能失败:', error?.message);
|
|
101
|
+
res.status(500).json({ success: false, error: '更新技能失败' });
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
/**
|
|
105
|
+
* 卸载技能
|
|
106
|
+
* DELETE /api/v1/skills/:id
|
|
107
|
+
*/
|
|
108
|
+
router.delete('/:id', async (req, res) => {
|
|
109
|
+
try {
|
|
110
|
+
const skillId = req.params.id;
|
|
111
|
+
const result = await skillsService.uninstall(skillId);
|
|
112
|
+
res.json(result);
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
logger.error('卸载技能失败:', error?.message);
|
|
116
|
+
res.status(500).json({ success: false, error: '卸载技能失败' });
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
/**
|
|
120
|
+
* 设置技能 API Key(本地存储,不上传服务端)
|
|
121
|
+
* POST /api/v1/skills/:id/api-key
|
|
122
|
+
*/
|
|
123
|
+
router.post('/:id/api-key', async (req, res) => {
|
|
124
|
+
try {
|
|
125
|
+
const skillId = req.params.id;
|
|
126
|
+
const { apiKey, apiBaseUrl } = req.body;
|
|
127
|
+
if (!apiKey) {
|
|
128
|
+
return res.status(400).json({ success: false, error: '缺少 apiKey 参数' });
|
|
129
|
+
}
|
|
130
|
+
// 只存储到本地,不发送到服务端
|
|
131
|
+
persistStore.setSkillApiKey(skillId, apiKey);
|
|
132
|
+
logger.info(`Skill API Key stored locally for skill: ${skillId}`);
|
|
133
|
+
res.json({ success: true, message: 'API Key 已保存到本地' });
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
logger.error('设置 API Key 失败:', error?.message);
|
|
137
|
+
res.status(500).json({ success: false, error: '设置 API Key 失败' });
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
/**
|
|
141
|
+
* 技能评分
|
|
142
|
+
* POST /api/v1/skills/:id/rating
|
|
143
|
+
*/
|
|
144
|
+
router.post('/:id/rating', async (req, res) => {
|
|
145
|
+
try {
|
|
146
|
+
const skillId = req.params.id;
|
|
147
|
+
const { score } = req.body;
|
|
148
|
+
if (!score || score < 1 || score > 5) {
|
|
149
|
+
return res.status(400).json({ success: false, error: '评分必须在 1-5 之间' });
|
|
150
|
+
}
|
|
151
|
+
const result = await skillsService.rate(skillId, score);
|
|
152
|
+
res.json(result);
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
logger.error('评分失败:', error?.message);
|
|
156
|
+
res.status(500).json({ success: false, error: '评分失败' });
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
export default router;
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway Tasks 路由
|
|
3
|
+
* 任务管理
|
|
4
|
+
*/
|
|
5
|
+
import express from 'express';
|
|
6
|
+
import { tasksService } from '../services/index.js';
|
|
7
|
+
import { getLogger } from '@pocketclaw/shared';
|
|
8
|
+
import { requireAuth } from '../middleware/auth.js';
|
|
9
|
+
const logger = getLogger('tasks');
|
|
10
|
+
const router = express.Router();
|
|
11
|
+
router.use(requireAuth);
|
|
12
|
+
/**
|
|
13
|
+
* 获取任务列表
|
|
14
|
+
* GET /api/v1/tasks
|
|
15
|
+
*/
|
|
16
|
+
router.get('/', async (req, res) => {
|
|
17
|
+
try {
|
|
18
|
+
const { status, page, pageSize } = req.query;
|
|
19
|
+
const userId = req.userId;
|
|
20
|
+
const result = await tasksService.list({ status, page, pageSize }, userId);
|
|
21
|
+
res.json(result);
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
logger.error('获取任务列表失败:', error?.message);
|
|
25
|
+
res.status(500).json({ success: false, error: '获取任务列表失败' });
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
/**
|
|
29
|
+
* 获取单个任务详情
|
|
30
|
+
* GET /api/v1/tasks/:id
|
|
31
|
+
*/
|
|
32
|
+
router.get('/:id', async (req, res) => {
|
|
33
|
+
try {
|
|
34
|
+
const taskId = req.params.id;
|
|
35
|
+
const result = await tasksService.get(taskId);
|
|
36
|
+
res.json(result);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
logger.error('获取任务详情失败:', error?.message);
|
|
40
|
+
res.status(500).json({ success: false, error: '获取任务详情失败' });
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
/**
|
|
44
|
+
* 创建任务
|
|
45
|
+
* POST /api/v1/tasks
|
|
46
|
+
*/
|
|
47
|
+
router.post('/', async (req, res) => {
|
|
48
|
+
try {
|
|
49
|
+
const userId = req.userId;
|
|
50
|
+
const result = await tasksService.create(req.body, String(userId));
|
|
51
|
+
res.json(result);
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
logger.error('创建任务失败:', error?.message);
|
|
55
|
+
res.status(500).json({ success: false, error: '创建任务失败' });
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
/**
|
|
59
|
+
* 更新任务
|
|
60
|
+
* PUT /api/v1/tasks/:id
|
|
61
|
+
*/
|
|
62
|
+
router.put('/:id', async (req, res) => {
|
|
63
|
+
try {
|
|
64
|
+
const taskId = req.params.id;
|
|
65
|
+
const result = await tasksService.update(taskId, req.body);
|
|
66
|
+
res.json(result);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
logger.error('更新任务失败:', error?.message);
|
|
70
|
+
res.status(500).json({ success: false, error: '更新任务失败' });
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
/**
|
|
74
|
+
* 删除任务
|
|
75
|
+
* DELETE /api/v1/tasks/:id
|
|
76
|
+
*/
|
|
77
|
+
router.delete('/:id', async (req, res) => {
|
|
78
|
+
try {
|
|
79
|
+
const taskId = req.params.id;
|
|
80
|
+
const result = await tasksService.delete(taskId);
|
|
81
|
+
res.json(result);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
logger.error('删除任务失败:', error?.message);
|
|
85
|
+
res.status(500).json({ success: false, error: '删除任务失败' });
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
/**
|
|
89
|
+
* 开始任务
|
|
90
|
+
* POST /api/v1/tasks/:id/start
|
|
91
|
+
*/
|
|
92
|
+
router.post('/:id/start', async (req, res) => {
|
|
93
|
+
try {
|
|
94
|
+
const taskId = req.params.id;
|
|
95
|
+
const result = await tasksService.updateStatus(taskId, 'running');
|
|
96
|
+
res.json(result);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
logger.error('开始任务失败:', error?.message);
|
|
100
|
+
res.status(500).json({ success: false, error: '开始任务失败' });
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
/**
|
|
104
|
+
* 完成任务
|
|
105
|
+
* POST /api/v1/tasks/:id/complete
|
|
106
|
+
*/
|
|
107
|
+
router.post('/:id/complete', async (req, res) => {
|
|
108
|
+
try {
|
|
109
|
+
const taskId = req.params.id;
|
|
110
|
+
const result = await tasksService.updateStatus(taskId, 'completed');
|
|
111
|
+
res.json(result);
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
logger.error('完成任务失败:', error?.message);
|
|
115
|
+
res.status(500).json({ success: false, error: '完成任务失败' });
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
/**
|
|
119
|
+
* 取消任务
|
|
120
|
+
* POST /api/v1/tasks/:id/cancel
|
|
121
|
+
*/
|
|
122
|
+
router.post('/:id/cancel', async (req, res) => {
|
|
123
|
+
try {
|
|
124
|
+
const taskId = req.params.id;
|
|
125
|
+
const result = await tasksService.cancel(taskId);
|
|
126
|
+
res.json(result);
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
logger.error('取消任务失败:', error?.message);
|
|
130
|
+
res.status(500).json({ success: false, error: '取消任务失败' });
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
/**
|
|
134
|
+
* 更新任务状态
|
|
135
|
+
* POST /api/v1/tasks/:id/status
|
|
136
|
+
*/
|
|
137
|
+
router.post('/:id/status', async (req, res) => {
|
|
138
|
+
try {
|
|
139
|
+
const taskId = req.params.id;
|
|
140
|
+
const { status } = req.body;
|
|
141
|
+
const result = await tasksService.updateStatus(taskId, status);
|
|
142
|
+
res.json(result);
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
logger.error('更新任务状态失败:', error?.message);
|
|
146
|
+
res.status(500).json({ success: false, error: '更新任务状态失败' });
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
export default router;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import multer from 'multer';
|
|
3
|
+
import { appConfig } from '@/config/index.js';
|
|
4
|
+
import { requireAuth } from '@/middleware/auth.js';
|
|
5
|
+
import { getLogger } from '@pocketclaw/shared';
|
|
6
|
+
const logger = getLogger('UploadRoutes');
|
|
7
|
+
const router = Router();
|
|
8
|
+
router.use(requireAuth);
|
|
9
|
+
// 配置 multer 用于解析 multipart/form-data
|
|
10
|
+
const upload = multer({
|
|
11
|
+
storage: multer.memoryStorage(),
|
|
12
|
+
limits: {
|
|
13
|
+
fileSize: 50 * 1024 * 1024, // 50MB
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
/**
|
|
17
|
+
* Allowed file extensions for upload
|
|
18
|
+
*/
|
|
19
|
+
const ALLOWED_UPLOAD_EXTS = new Set([
|
|
20
|
+
// Images
|
|
21
|
+
'.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg', '.bmp', '.ico',
|
|
22
|
+
// Documents
|
|
23
|
+
'.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.txt', '.csv', '.md',
|
|
24
|
+
// Audio
|
|
25
|
+
'.mp3', '.wav', '.ogg', '.flac', '.aac', '.m4a',
|
|
26
|
+
// Video
|
|
27
|
+
'.mp4', '.webm', '.avi', '.mov', '.mkv',
|
|
28
|
+
// Archives
|
|
29
|
+
'.zip', '.rar', '.7z', '.tar', '.gz',
|
|
30
|
+
// Code
|
|
31
|
+
'.js', '.ts', '.jsx', '.tsx', '.py', '.go', '.rs', '.java', '.json', '.yaml', '.yml', '.toml', '.xml', '.html', '.css', '.sh', '.bat', '.ps1',
|
|
32
|
+
]);
|
|
33
|
+
function getFileExt(filename) {
|
|
34
|
+
const idx = filename.lastIndexOf('.');
|
|
35
|
+
return idx >= 0 ? filename.substring(idx).toLowerCase() : '';
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* POST /api/v1/upload
|
|
39
|
+
* 上传文件到 OSS(代理到 Server)
|
|
40
|
+
*/
|
|
41
|
+
router.post('/', upload.single('file'), async (req, res) => {
|
|
42
|
+
try {
|
|
43
|
+
if (!req.file) {
|
|
44
|
+
res.status(400).json({ success: false, error: '没有上传文件' });
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// File type validation
|
|
48
|
+
const ext = getFileExt(req.file.originalname);
|
|
49
|
+
if (!ALLOWED_UPLOAD_EXTS.has(ext)) {
|
|
50
|
+
res.status(400).json({ success: false, error: `不支持的文件类型: ${ext}` });
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
// 创建 FormData 并转发到 Server
|
|
54
|
+
const formData = new FormData();
|
|
55
|
+
formData.append('file', new Blob([req.file.buffer], { type: req.file.mimetype }), req.file.originalname);
|
|
56
|
+
const response = await fetch(`${appConfig.serverBaseUrl}/api/v1/upload`, {
|
|
57
|
+
method: 'POST',
|
|
58
|
+
headers: {
|
|
59
|
+
'Authorization': `Bearer ${req.token}`,
|
|
60
|
+
},
|
|
61
|
+
body: formData,
|
|
62
|
+
});
|
|
63
|
+
const text = await response.text();
|
|
64
|
+
let result;
|
|
65
|
+
try {
|
|
66
|
+
result = JSON.parse(text);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
logger.error('Invalid JSON from server:', text.substring(0, 200));
|
|
70
|
+
res.status(500).json({ success: false, error: 'Upload server error' });
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
res.status(response.status).json(result);
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
logger.error('Proxy upload error:', error);
|
|
77
|
+
res.status(500).json({ success: false, error: 'Upload failed' });
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
/**
|
|
81
|
+
* DELETE /api/v1/upload
|
|
82
|
+
* 从 OSS 删除文件(代理到 Server)
|
|
83
|
+
*/
|
|
84
|
+
router.delete('/', async (req, res) => {
|
|
85
|
+
try {
|
|
86
|
+
// 从 query 参数获取文件 keys(逗号分隔)
|
|
87
|
+
const keysParam = req.query.keys;
|
|
88
|
+
if (!keysParam) {
|
|
89
|
+
res.status(400).json({ success: false, error: '缺少文件 keys 参数' });
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
// 转发到 Server
|
|
93
|
+
const response = await fetch(`${appConfig.serverBaseUrl}/api/v1/upload?keys=${encodeURIComponent(keysParam)}`, {
|
|
94
|
+
method: 'DELETE',
|
|
95
|
+
headers: {
|
|
96
|
+
'Authorization': `Bearer ${req.token}`,
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
const text = await response.text();
|
|
100
|
+
let result;
|
|
101
|
+
try {
|
|
102
|
+
result = JSON.parse(text);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
logger.error('Invalid JSON from server:', text.substring(0, 200));
|
|
106
|
+
res.status(500).json({ success: false, error: 'Delete server error' });
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
res.status(response.status).json(result);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
logger.error('Proxy delete error:', error);
|
|
113
|
+
res.status(500).json({ success: false, error: 'Delete failed' });
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
export async function deleteFile(url, token) {
|
|
117
|
+
const response = await fetch(`${appConfig.serverBaseUrl}/api/v1/upload`, {
|
|
118
|
+
method: 'DELETE',
|
|
119
|
+
headers: {
|
|
120
|
+
'Content-Type': 'application/json',
|
|
121
|
+
'Authorization': token ? `Bearer ${token}` : '',
|
|
122
|
+
},
|
|
123
|
+
body: JSON.stringify({ url }),
|
|
124
|
+
});
|
|
125
|
+
if (!response.ok) {
|
|
126
|
+
throw new Error(`Delete failed: ${response.status}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
export default router;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
import { appConfig } from '../config/index.js';
|
|
4
|
+
import { optionalAuth } from '../middleware/auth.js';
|
|
5
|
+
import { readFileSync } from 'fs';
|
|
6
|
+
import { resolve, dirname } from 'path';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
import { getLogger } from '@pocketclaw/shared';
|
|
9
|
+
const logger = getLogger('VersionRoutes');
|
|
10
|
+
const router = express.Router();
|
|
11
|
+
// ESM 兼容的 __dirname
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = dirname(__filename);
|
|
14
|
+
/**
|
|
15
|
+
* 获取 Gateway 本地版本及运行方式
|
|
16
|
+
* GET /api/v1/version/local
|
|
17
|
+
*/
|
|
18
|
+
router.get('/local', async (req, res) => {
|
|
19
|
+
try {
|
|
20
|
+
// 读取 package.json 获取版本
|
|
21
|
+
const packageJsonPath = resolve(__dirname, '../../package.json');
|
|
22
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
23
|
+
// 判断运行方式:pkg 打包的 exe 会有 (process as any).pkg
|
|
24
|
+
const runMode = process.pkg ? 'exe' : 'node';
|
|
25
|
+
res.json({
|
|
26
|
+
success: true,
|
|
27
|
+
data: {
|
|
28
|
+
version: packageJson.version,
|
|
29
|
+
runMode,
|
|
30
|
+
execPath: process.execPath,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
logger.error('获取本地版本失败:', error);
|
|
36
|
+
res.status(500).json({
|
|
37
|
+
success: false,
|
|
38
|
+
error: error instanceof Error ? error.message : '获取本地版本失败',
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* 转发到服务端接口
|
|
44
|
+
*/
|
|
45
|
+
router.get('/latest', optionalAuth, async (req, res) => {
|
|
46
|
+
try {
|
|
47
|
+
const serverBaseUrl = appConfig.serverBaseUrl || 'https://api.pocketclaw.ai';
|
|
48
|
+
const response = await axios.get(`${serverBaseUrl}/api/v1/version/latest`, {
|
|
49
|
+
timeout: 10000,
|
|
50
|
+
headers: {
|
|
51
|
+
'Content-Type': 'application/json',
|
|
52
|
+
Authorization: req.token ? `Bearer ${req.token}` : '',
|
|
53
|
+
},
|
|
54
|
+
params: req.query, // 转发所有查询参数,包括lang
|
|
55
|
+
});
|
|
56
|
+
res.json(response.data);
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
logger.error('获取版本信息失败:', error);
|
|
60
|
+
res.status(500).json({
|
|
61
|
+
success: false,
|
|
62
|
+
error: error instanceof Error ? error.message : '获取版本信息失败',
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
export default router;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HMS Push 服务(华为设备专用)
|
|
3
|
+
*/
|
|
4
|
+
class HMSPushService {
|
|
5
|
+
/**
|
|
6
|
+
* 检查服务是否可用
|
|
7
|
+
*/
|
|
8
|
+
isAvailable() {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 发送推送消息
|
|
13
|
+
*/
|
|
14
|
+
async send(token, payload, options) {
|
|
15
|
+
return { success: false };
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 批量发送
|
|
19
|
+
*/
|
|
20
|
+
async sendToMany(tokens, payload, options) {
|
|
21
|
+
return { success: false, sent: 0, failed: tokens.length };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export const hmsPushService = new HMSPushService();
|