@ia-ccun/code-agent-claw 0.0.3 → 0.0.5

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.
@@ -1,342 +0,0 @@
1
- import { Express, Request, Response, NextFunction } from 'express';
2
- import { AgentRpcService } from '../services/agent-rpc';
3
- import { getAgentConfig, saveUserConfig, loadConfig, findAicodeCommand } from '../config';
4
- import { AgentConfig, ConfigRequest, ApiResponse } from '../types';
5
- import { logger } from '../utils/logger';
6
- import * as fs from 'fs';
7
- import * as path from 'path';
8
- import * as os from 'os';
9
- import { execSync } from 'child_process';
10
-
11
- /**
12
- * 注册 API 路由
13
- */
14
- export function registerRoutes(app: Express, agentService: AgentRpcService): void {
15
-
16
- // ==================== 配置相关 ====================
17
-
18
- /**
19
- * 获取当前配置
20
- */
21
- app.get('/api/aicode/config', (req: Request, res: Response) => {
22
- logger.info('[API] GET /api/aicode/config');
23
- const config = getAgentConfig();
24
- const currentConfig = agentService.currentConfig;
25
-
26
- // 读取 models.json
27
- let models = null;
28
- const modelsPath = path.join(os.homedir(), '.aicode-cli', 'agent', 'models.json');
29
- if (fs.existsSync(modelsPath)) {
30
- try {
31
- models = JSON.parse(fs.readFileSync(modelsPath, 'utf-8'));
32
- } catch (e) {
33
- logger.warn('Failed to parse models.json:', e);
34
- }
35
- }
36
-
37
- const response: ApiResponse<{
38
- config: AgentConfig;
39
- status: string;
40
- models: any;
41
- }> = {
42
- success: true,
43
- data: {
44
- config: {
45
- ...config,
46
- command: config.command
47
- },
48
- status: agentService.status,
49
- models
50
- }
51
- };
52
-
53
- res.json(response);
54
- });
55
-
56
- /**
57
- * 保存配置并初始化 agent
58
- */
59
- app.post('/api/aicode/config', async (req: Request, res: Response) => {
60
- logger.info('[API] POST /api/aicode/config', req.body);
61
-
62
- const body = req.body as ConfigRequest;
63
-
64
- // command 字段可选,如果没有填则自动检测
65
-
66
- // 自动检测 command 路径
67
- let command = body.command;
68
- if (!command || command === 'aicode') {
69
- command = findAicodeCommand();
70
- logger.info('[API] Auto-detected aicode command:', command);
71
- }
72
-
73
- const config: AgentConfig = {
74
- enabled: true,
75
- command: command,
76
- provider: body.provider || 'minimax-custom',
77
- model: body.model || 'MiniMax-M2.5',
78
- noSession: body.noSession !== false,
79
- sessionDir: body.sessionDir || '~/.aicode-cli/agent/sessions',
80
- workingDir: body.workingDir || '~/.aicode-cli'
81
- };
82
-
83
- // 先停止已有 agent
84
- if (agentService.isRunning()) {
85
- logger.info('[API] Stopping existing agent...');
86
- agentService.stop();
87
- }
88
-
89
- // 保存配置
90
- saveUserConfig(config);
91
-
92
- // 初始化并启动
93
- const result = await agentService.initialize(config);
94
-
95
- if (result.success) {
96
- res.json({
97
- success: true,
98
- message: 'Agent initialized successfully'
99
- } as ApiResponse);
100
- } else {
101
- res.status(500).json({
102
- success: false,
103
- message: result.message
104
- } as ApiResponse);
105
- }
106
- });
107
-
108
- // ==================== 状态相关 ====================
109
-
110
- /**
111
- * 获取 agent 状态
112
- */
113
- app.get('/api/aicode/status', (req: Request, res: Response) => {
114
- logger.info('[API] GET /api/aicode/status');
115
-
116
- res.json({
117
- success: true,
118
- data: {
119
- status: agentService.status,
120
- running: agentService.isRunning()
121
- }
122
- } as ApiResponse);
123
- });
124
-
125
- /**
126
- * 健康检查
127
- */
128
- app.get('/api/aicode/health', (req: Request, res: Response) => {
129
- res.json({
130
- success: true,
131
- data: {
132
- status: agentService.status,
133
- running: agentService.isRunning()
134
- }
135
- } as ApiResponse);
136
- });
137
-
138
- /**
139
- * 检测 aicode 命令路径
140
- */
141
- app.get('/api/aicode/detect', (req: Request, res: Response) => {
142
- logger.info('[API] GET /api/aicode/detect');
143
-
144
- // 使用 findAicodeCommand 获取所有可能的路径
145
- const detectedPaths: string[] = [];
146
-
147
- try {
148
- // 1. 尝试 whereis
149
- const whereisResult = execSync('whereis aicode', { encoding: 'utf-8' });
150
- const match = whereisResult.match(/aicode:\s*(.+)$/);
151
- if (match && match[1] && !match[1].includes('not found')) {
152
- const paths = match[1].trim().split(/\s+/);
153
- paths.forEach(p => {
154
- if (p && fs.existsSync(p) && !detectedPaths.includes(p)) {
155
- detectedPaths.push(p);
156
- }
157
- });
158
- }
159
- } catch (e) {
160
- // ignore
161
- }
162
-
163
- // 2. 尝试 which
164
- try {
165
- const whichResult = execSync('which -a aicode', { encoding: 'utf-8' }).trim();
166
- if (whichResult) {
167
- whichResult.split('\n').forEach(p => {
168
- const trimmed = p.trim();
169
- if (trimmed && fs.existsSync(trimmed) && !detectedPaths.includes(trimmed)) {
170
- detectedPaths.push(trimmed);
171
- }
172
- });
173
- }
174
- } catch (e) {
175
- // ignore
176
- }
177
-
178
- // 3. 检查常见路径
179
- const commonPaths = [
180
- '/usr/local/bin/aicode',
181
- '/usr/bin/aicode',
182
- path.join(os.homedir(), '.local/bin/aicode'),
183
- path.join(os.homedir(), 'bin/aicode'),
184
- ];
185
- commonPaths.forEach(p => {
186
- if (fs.existsSync(p) && !detectedPaths.includes(p)) {
187
- detectedPaths.push(p);
188
- }
189
- });
190
-
191
- res.json({
192
- success: true,
193
- data: {
194
- paths: detectedPaths,
195
- recommended: detectedPaths.length > 0 ? detectedPaths[0] : 'aicode'
196
- }
197
- } as ApiResponse);
198
- });
199
-
200
- // ==================== Agent 操作 ====================
201
-
202
- /**
203
- * 发送提示
204
- */
205
- app.post('/api/aicode/prompt', async (req: Request, res: Response) => {
206
- const { message } = req.body;
207
- logger.info(`[API] POST /api/aicode/prompt: ${message?.substring(0, 50)}...`);
208
-
209
- if (!agentService.isRunning()) {
210
- return res.status(503).json({
211
- success: false,
212
- message: 'Agent is not running. Please initialize first.'
213
- } as ApiResponse);
214
- }
215
-
216
- try {
217
- const result = await agentService.sendPrompt(message);
218
- if (result.success) {
219
- res.json({ success: true, data: result } as ApiResponse);
220
- } else {
221
- res.status(500).json({ success: false, message: result.message } as ApiResponse);
222
- }
223
- } catch (e: any) {
224
- logger.error('[API] /prompt error:', e);
225
- res.status(500).json({ success: false, message: e.message } as ApiResponse);
226
- }
227
- });
228
-
229
- /**
230
- * 发送引导消息
231
- */
232
- app.post('/api/aicode/steer', async (req: Request, res: Response) => {
233
- const { message } = req.body;
234
- logger.info(`[API] POST /api/aicode/steer: ${message?.substring(0, 50)}...`);
235
-
236
- if (!agentService.isRunning()) {
237
- return res.status(503).json({
238
- success: false,
239
- message: 'Agent is not running'
240
- } as ApiResponse);
241
- }
242
-
243
- try {
244
- const result = await agentService.sendSteer(message);
245
- if (result.success) {
246
- res.json({ success: true, data: result } as ApiResponse);
247
- } else {
248
- res.status(500).json({ success: false, message: result.message } as ApiResponse);
249
- }
250
- } catch (e: any) {
251
- res.status(500).json({ success: false, message: e.message } as ApiResponse);
252
- }
253
- });
254
-
255
- /**
256
- * 发送后续消息
257
- */
258
- app.post('/api/aicode/follow-up', async (req: Request, res: Response) => {
259
- const { message } = req.body;
260
- logger.info(`[API] POST /api/aicode/follow-up`);
261
-
262
- if (!agentService.isRunning()) {
263
- return res.status(503).json({
264
- success: false,
265
- message: 'Agent is not running'
266
- } as ApiResponse);
267
- }
268
-
269
- try {
270
- const result = await agentService.sendFollowUp(message);
271
- if (result.success) {
272
- res.json({ success: true, data: result } as ApiResponse);
273
- } else {
274
- res.status(500).json({ success: false, message: result.message } as ApiResponse);
275
- }
276
- } catch (e: any) {
277
- res.status(500).json({ success: false, message: e.message } as ApiResponse);
278
- }
279
- });
280
-
281
- /**
282
- * 中止操作
283
- */
284
- app.post('/api/aicode/abort', async (req: Request, res: Response) => {
285
- logger.info('[API] POST /api/aicode/abort');
286
-
287
- if (!agentService.isRunning()) {
288
- return res.status(503).json({
289
- success: false,
290
- message: 'Agent is not running'
291
- } as ApiResponse);
292
- }
293
-
294
- try {
295
- const result = await agentService.sendAbort();
296
- if (result.success) {
297
- res.json({ success: true, data: result } as ApiResponse);
298
- } else {
299
- res.status(500).json({ success: false, message: result.message } as ApiResponse);
300
- }
301
- } catch (e: any) {
302
- res.status(500).json({ success: false, message: e.message } as ApiResponse);
303
- }
304
- });
305
-
306
- /**
307
- * 创建新会话
308
- */
309
- app.post('/api/aicode/new-session', async (req: Request, res: Response) => {
310
- const parentSession = req.query.parentSession as string | undefined;
311
- logger.info(`[API] POST /api/aicode/new-session: parentSession=${parentSession}`);
312
-
313
- if (!agentService.isRunning()) {
314
- return res.status(503).json({
315
- success: false,
316
- message: 'Agent is not running'
317
- } as ApiResponse);
318
- }
319
-
320
- try {
321
- const result = await agentService.newSession(parentSession);
322
- if (result.success) {
323
- res.json({ success: true, data: result } as ApiResponse);
324
- } else {
325
- res.status(500).json({ success: false, message: result.message } as ApiResponse);
326
- }
327
- } catch (e: any) {
328
- res.status(500).json({ success: false, message: e.message } as ApiResponse);
329
- }
330
- });
331
-
332
- // 错误处理中间件
333
- app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
334
- logger.error('[API] Error:', err);
335
- res.status(500).json({
336
- success: false,
337
- message: err.message
338
- } as ApiResponse);
339
- });
340
-
341
- logger.info('[API] Routes registered');
342
- }
@@ -1,82 +0,0 @@
1
- import { WebSocketServer, WebSocket } from 'ws';
2
- import { AgentRpcService } from '../services/agent-rpc';
3
- import { AgentEvent } from '../types';
4
- import { logger } from '../utils/logger';
5
-
6
- /**
7
- * WebSocket 客户端集合
8
- */
9
- const clients: Set<WebSocket> = new Set();
10
-
11
- /**
12
- * 设置 WebSocket 处理
13
- */
14
- export function setupWebSocket(wss: WebSocketServer, agentService: AgentRpcService): void {
15
-
16
- // 注册事件回调
17
- agentService.registerCallback((event: AgentEvent) => {
18
- broadcast(event);
19
- });
20
-
21
- wss.on('connection', (ws: WebSocket) => {
22
- logger.info('[WebSocket] Client connected');
23
- clients.add(ws);
24
-
25
- // 发送客户端数量
26
- broadcastClientCount();
27
-
28
- // 发送欢迎消息
29
- ws.send(JSON.stringify({
30
- type: 'welcome',
31
- message: 'Connected to AICode Agent WebSocket'
32
- }));
33
-
34
- ws.on('close', () => {
35
- logger.info('[WebSocket] Client disconnected');
36
- clients.delete(ws);
37
- broadcastClientCount();
38
- });
39
-
40
- ws.on('error', (error) => {
41
- logger.error('[WebSocket] Error:', error);
42
- clients.delete(ws);
43
- });
44
- });
45
-
46
- logger.info('[WebSocket] Server initialized');
47
- }
48
-
49
- /**
50
- * 广播消息给所有客户端
51
- */
52
- function broadcast(event: AgentEvent): void {
53
- const message = JSON.stringify(event);
54
- clients.forEach((client) => {
55
- if (client.readyState === WebSocket.OPEN) {
56
- try {
57
- client.send(message);
58
- } catch (e) {
59
- logger.error('[WebSocket] Send error:', e);
60
- }
61
- }
62
- });
63
- }
64
-
65
- /**
66
- * 广播客户端数量
67
- */
68
- function broadcastClientCount(): void {
69
- const message = JSON.stringify({
70
- type: 'client_count',
71
- count: clients.size
72
- });
73
- clients.forEach((client) => {
74
- if (client.readyState === WebSocket.OPEN) {
75
- try {
76
- client.send(message);
77
- } catch (e) {
78
- // 忽略
79
- }
80
- }
81
- });
82
- }