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

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,143 +0,0 @@
1
- /* ========================================
2
- Juejin Style - Markdown Code Highlighting
3
- 掘金风格代码高亮样式
4
- ======================================== */
5
-
6
- /* Base code styles */
7
- .hljs {
8
- display: block;
9
- overflow-x: auto;
10
- padding: 16px;
11
- color: #383a42;
12
- background: #fafafa;
13
- font-family: 'JetBrains Mono', 'Operator Mono', Consolas, Monaco, Menlo, monospace;
14
- font-size: 12px;
15
- line-height: 26px;
16
- -webkit-overflow-scrolling: touch;
17
- }
18
-
19
- /* Keywords */
20
- .hljs-keyword,
21
- .hljs-selector-tag,
22
- .hljs-literal,
23
- .hljs-section,
24
- .hljs-link {
25
- color: #a626a4;
26
- }
27
-
28
- /* Strings */
29
- .hljs-string,
30
- .hljs-title,
31
- .hljs-name,
32
- .hljs-type,
33
- .hljs-attribute,
34
- .hljs-symbol,
35
- .hljs-bullet,
36
- .hljs-addition,
37
- .hljs-variable,
38
- .hljs-template-tag,
39
- .hljs-template-variable {
40
- color: #50a14f;
41
- }
42
-
43
- /* Numbers */
44
- .hljs-number,
45
- .hljs-regexp,
46
- .hljs-built_in,
47
- .hljs-builtin-name {
48
- color: #986801;
49
- }
50
-
51
- /* Comments */
52
- .hljs-comment,
53
- .hljs-quote,
54
- .hljs-deletion,
55
- .hljs-meta {
56
- color: #a0a1a7;
57
- font-style: italic;
58
- }
59
-
60
- /* Functions */
61
- .hljs-function,
62
- .hljs-params {
63
- color: #4078f2;
64
- }
65
-
66
- /* Variables */
67
- .hljs-subst {
68
- color: #e45649;
69
- }
70
-
71
- /* Emphasis */
72
- .hljs-emphasis {
73
- font-style: italic;
74
- }
75
-
76
- .hljs-strong {
77
- font-weight: bold;
78
- }
79
-
80
- /* Code block container */
81
- pre.custom {
82
- margin: 10px 0;
83
- border-radius: 4px;
84
- overflow: hidden;
85
- }
86
-
87
- pre.custom code {
88
- display: block;
89
- overflow-x: auto;
90
- }
91
-
92
- /* Inline code */
93
- code {
94
- font-family: 'JetBrains Mono', 'Operator Mono', Consolas, Monaco, Menlo, monospace;
95
- font-size: 0.9em;
96
- padding: 2px 6px;
97
- border-radius: 4px;
98
- background: rgba(27, 31, 35, 0.05);
99
- color: #d97757;
100
- word-break: break-all;
101
- }
102
-
103
- /* Light theme specific */
104
- body.light code {
105
- background: #f0f0f0;
106
- color: #d97757;
107
- }
108
-
109
- /* Dark theme specific */
110
- body.dark code {
111
- background: #2a2a28;
112
- color: #e8a888;
113
- }
114
-
115
- /* Headers */
116
- .hljs h1,
117
- .hljs h2,
118
- .hljs h3,
119
- .hljs h4,
120
- .hljs h5,
121
- .hljs h6 {
122
- color: #4078f2;
123
- margin: 1em 0 0.5em;
124
- }
125
-
126
- /* Links */
127
- .hljs a {
128
- color: #50a14f;
129
- text-decoration: none;
130
- }
131
-
132
- .hljs a:hover {
133
- text-decoration: underline;
134
- }
135
-
136
- /* Selection */
137
- ::selection {
138
- background: rgba(217, 119, 87, 0.3);
139
- }
140
-
141
- body.light ::selection {
142
- background: rgba(217, 119, 87, 0.2);
143
- }
@@ -1,239 +0,0 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
- import * as os from 'os';
4
- import { execSync } from 'child_process';
5
- import { Config, AgentConfig, ServerConfig, LoggingConfig } from './types';
6
- import { logger } from './utils/logger';
7
-
8
- /**
9
- * 自动检测 aicode 命令路径
10
- */
11
- export function findAicodeCommand(): string {
12
- // 1. 检查环境变量
13
- if (process.env.AICODE_UI_COMMAND) {
14
- return process.env.AICODE_UI_COMMAND;
15
- }
16
-
17
- // 2. 尝试使用 whereis 命令检测
18
- try {
19
- const result = execSync('whereis aicode', { encoding: 'utf-8' });
20
- const match = result.match(/aicode:\s*(.+)$/);
21
- if (match && match[1] && !match[1].includes('not found')) {
22
- const paths = match[1].trim().split(/\s+/);
23
- // 返回第一个有效的路径
24
- for (const cmdPath of paths) {
25
- if (cmdPath && fs.existsSync(cmdPath)) {
26
- logger.info(`[Config] Found aicode at: ${cmdPath}`);
27
- return cmdPath;
28
- }
29
- }
30
- }
31
- } catch (e) {
32
- // whereis 失败,尝试 which
33
- }
34
-
35
- // 3. 尝试 which 命令
36
- try {
37
- const result = execSync('which aicode', { encoding: 'utf-8' }).trim();
38
- if (result && fs.existsSync(result)) {
39
- logger.info(`[Config] Found aicode at: ${result}`);
40
- return result;
41
- }
42
- } catch (e) {
43
- // which 也失败
44
- }
45
-
46
- // 4. 尝试常见安装路径
47
- const commonPaths = [
48
- '/usr/local/bin/aicode',
49
- '/usr/bin/aicode',
50
- path.join(os.homedir(), '.local/bin/aicode'),
51
- path.join(os.homedir(), 'bin/aicode'),
52
- ];
53
-
54
- for (const cmdPath of commonPaths) {
55
- if (fs.existsSync(cmdPath)) {
56
- logger.info(`[Config] Found aicode at: ${cmdPath}`);
57
- return cmdPath;
58
- }
59
- }
60
-
61
- // 5. 默认返回 'aicode'
62
- logger.warn('[Config] aicode not found, using default: aicode');
63
- return 'aicode';
64
- }
65
-
66
- /**
67
- * 默认配置
68
- */
69
- const DEFAULT_CONFIG: Config = {
70
- server: {
71
- port: 8081,
72
- host: '0.0.0.0'
73
- },
74
- agent: {
75
- enabled: false,
76
- command: 'aicode',
77
- provider: 'minimax-custom',
78
- model: 'MiniMax-M2.5',
79
- noSession: true,
80
- sessionDir: '~/.aicode-cli/agent/sessions',
81
- workingDir: '~/.aicode-cli'
82
- },
83
- logging: {
84
- level: 'info'
85
- }
86
- };
87
-
88
- /**
89
- * 展开路径中的 ~ 为用户主目录
90
- */
91
- function expandPath(filePath: string): string {
92
- if (filePath.startsWith('~')) {
93
- return path.join(os.homedir(), filePath.slice(1).replace(/^\//, ''));
94
- }
95
- return filePath;
96
- }
97
-
98
- /**
99
- * 加载配置
100
- */
101
- export function loadConfig(): Config {
102
- // 1. 加载默认配置
103
- let config: Config = JSON.parse(JSON.stringify(DEFAULT_CONFIG));
104
-
105
- // 2. 加载默认配置文件 (项目内)
106
- const defaultConfigPath = path.join(__dirname, '..', 'config', 'default.json');
107
- if (fs.existsSync(defaultConfigPath)) {
108
- try {
109
- const fileConfig = JSON.parse(fs.readFileSync(defaultConfigPath, 'utf-8'));
110
- config = deepMerge(config, fileConfig);
111
- logger.debug(`Loaded default config from ${defaultConfigPath}`);
112
- } catch (e) {
113
- logger.warn(`Failed to load default config: ${e}`);
114
- }
115
- }
116
-
117
- // 3. 加载用户配置文件
118
- const userConfigDir = path.join(os.homedir(), '.aicode-ui');
119
- const userConfigPath = path.join(userConfigDir, 'config.json');
120
-
121
- if (fs.existsSync(userConfigPath)) {
122
- try {
123
- const userConfig = JSON.parse(fs.readFileSync(userConfigPath, 'utf-8'));
124
- config = deepMerge(config, userConfig);
125
- logger.info(`Loaded user config from ${userConfigPath}`);
126
- } catch (e) {
127
- logger.warn(`Failed to load user config: ${e}`);
128
- }
129
- }
130
-
131
- // 4. 环境变量覆盖
132
- if (process.env.AICODE_UI_PORT) {
133
- config.server.port = parseInt(process.env.AICODE_UI_PORT, 10);
134
- }
135
- if (process.env.AICODE_UI_COMMAND) {
136
- config.agent.command = process.env.AICODE_UI_COMMAND;
137
- }
138
- if (process.env.AICODE_UI_PROVIDER) {
139
- config.agent.provider = process.env.AICODE_UI_PROVIDER;
140
- }
141
- if (process.env.AICODE_UI_MODEL) {
142
- config.agent.model = process.env.AICODE_UI_MODEL;
143
- }
144
- if (process.env.AICODE_UI_LOG_LEVEL) {
145
- config.logging.level = process.env.AICODE_UI_LOG_LEVEL;
146
- }
147
-
148
- // 5. 自动检测 aicode 命令路径(如果未配置)
149
- if (!config.agent.command || config.agent.command === 'aicode') {
150
- const detectedCommand = findAicodeCommand();
151
- config.agent.command = detectedCommand;
152
- }
153
-
154
- // 6. 展开路径中的 ~
155
- config.agent.sessionDir = expandPath(config.agent.sessionDir);
156
- config.agent.workingDir = expandPath(config.agent.workingDir);
157
-
158
- return config;
159
- }
160
-
161
- /**
162
- * 保存配置到用户目录
163
- */
164
- export function saveUserConfig(agentConfig: AgentConfig): void {
165
- const userConfigDir = path.join(os.homedir(), '.aicode-ui');
166
- const userConfigPath = path.join(userConfigDir, 'config.json');
167
-
168
- // 确保目录存在
169
- if (!fs.existsSync(userConfigDir)) {
170
- fs.mkdirSync(userConfigDir, { recursive: true });
171
- }
172
-
173
- // 展开路径后保存
174
- const configToSave = {
175
- server: {
176
- port: 8080,
177
- host: '0.0.0.0'
178
- },
179
- agent: {
180
- enabled: true,
181
- command: agentConfig.command,
182
- provider: agentConfig.provider,
183
- model: agentConfig.model,
184
- noSession: agentConfig.noSession,
185
- sessionDir: expandPath(agentConfig.sessionDir),
186
- workingDir: expandPath(agentConfig.workingDir)
187
- },
188
- logging: {
189
- level: 'info'
190
- }
191
- };
192
-
193
- fs.writeFileSync(userConfigPath, JSON.stringify(configToSave, null, 2), 'utf-8');
194
- logger.info(`Config saved to ${userConfigPath}`);
195
- }
196
-
197
- /**
198
- * 获取用户配置路径
199
- */
200
- export function getUserConfigPath(): string {
201
- return path.join(os.homedir(), '.aicode-ui', 'config.json');
202
- }
203
-
204
- /**
205
- * 深度合并对象
206
- */
207
- function deepMerge(target: any, source: any): any {
208
- const result = { ...target };
209
-
210
- for (const key in source) {
211
- if (source.hasOwnProperty(key)) {
212
- const sourceValue = source[key];
213
- const targetValue = result[key];
214
-
215
- if (isObject(sourceValue) && isObject(targetValue)) {
216
- result[key] = deepMerge(targetValue, sourceValue);
217
- } else if (sourceValue !== undefined) {
218
- result[key] = sourceValue;
219
- }
220
- }
221
- }
222
-
223
- return result;
224
- }
225
-
226
- /**
227
- * 判断是否为对象
228
- */
229
- function isObject(value: any): value is Record<string, any> {
230
- return value !== null && typeof value === 'object' && !Array.isArray(value);
231
- }
232
-
233
- /**
234
- * 获取当前配置(仅返回 agent 部分)
235
- */
236
- export function getAgentConfig(): AgentConfig {
237
- const config = loadConfig();
238
- return config.agent;
239
- }
@@ -1,40 +0,0 @@
1
- import { startServer } from './server';
2
- import { logger } from './utils/logger';
3
- import { getAgentRpcService } from './services/agent-rpc';
4
-
5
- /**
6
- * 主入口
7
- */
8
- async function main() {
9
- try {
10
- // 捕获未处理的异常
11
- process.on('uncaughtException', (err) => {
12
- console.error('Uncaught exception:', err);
13
- process.exit(1);
14
- });
15
-
16
- process.on('unhandledRejection', (reason, promise) => {
17
- console.error('Unhandled rejection at:', promise, 'reason:', reason);
18
- });
19
-
20
- // 启动服务器
21
- await startServer();
22
-
23
- // 优雅退出
24
- const shutdown = () => {
25
- logger.info('Shutting down...');
26
- const agentService = getAgentRpcService();
27
- agentService.stop();
28
- process.exit(0);
29
- };
30
-
31
- process.on('SIGINT', shutdown);
32
- process.on('SIGTERM', shutdown);
33
-
34
- } catch (error) {
35
- console.error('Failed to start server:', error);
36
- process.exit(1);
37
- }
38
- }
39
-
40
- main();
@@ -1,103 +0,0 @@
1
- import express, { Express, Request, Response, NextFunction } from 'express';
2
- import http, { Server } from 'http';
3
- import * as path from 'path';
4
- import { WebSocketServer } from 'ws';
5
- import { AgentRpcService, getAgentRpcService } from '../services/agent-rpc';
6
- import { registerRoutes } from './routes';
7
- import { setupWebSocket } from './websocket';
8
- import { loadConfig } from '../config';
9
- import { logger } from '../utils/logger';
10
-
11
- /**
12
- * 创建并启动服务器
13
- */
14
- export async function startServer(): Promise<Server> {
15
- const config = loadConfig();
16
-
17
- // 创建 Express 应用
18
- const app: Express = express();
19
-
20
- // 中间件
21
- app.use(express.json());
22
- app.use(express.urlencoded({ extended: true }));
23
-
24
- // CORS 支持(允许前端跨域访问)
25
- app.use((req: Request, res: Response, next: NextFunction) => {
26
- res.header('Access-Control-Allow-Origin', '*');
27
- res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
28
- res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
29
- if (req.method === 'OPTIONS') {
30
- return res.sendStatus(200);
31
- }
32
- next();
33
- });
34
-
35
- // 健康检查端点(无需跨域)
36
- app.get('/health', (req: Request, res: Response) => {
37
- res.json({ status: 'ok', timestamp: Date.now() });
38
- });
39
-
40
- // 静态文件服务
41
- const publicDir = path.join(__dirname, '..', 'public');
42
- app.use(express.static(publicDir));
43
-
44
- // 默认页面
45
- app.get('/', (req: Request, res: Response) => {
46
- res.sendFile(path.join(publicDir, 'index.html'));
47
- });
48
-
49
- // 获取 AgentRpcService 实例
50
- const agentService = getAgentRpcService();
51
-
52
- // 注册 REST API
53
- registerRoutes(app, agentService);
54
-
55
- // 创建 HTTP 服务器
56
- const server = http.createServer(app);
57
-
58
- // 创建 WebSocket 服务器
59
- const wss = new WebSocketServer({
60
- server,
61
- path: '/ws/agent'
62
- });
63
-
64
- setupWebSocket(wss, agentService);
65
-
66
- // 启动服务器
67
- return new Promise((resolve) => {
68
- server.listen(config.server.port, config.server.host, () => {
69
- logger.info(`========================================`);
70
- logger.info(`Server started: http://localhost:${config.server.port}`);
71
- logger.info(`WebUI: http://localhost:${config.server.port}/index.html`);
72
- logger.info(`API: http://localhost:${config.server.port}/api/aicode/*`);
73
- logger.info(`WebSocket: ws://localhost:${config.server.port}/ws/agent`);
74
- logger.info(`========================================`);
75
-
76
- // 检查是否有已有配置,如果有则提示用户
77
- const agentConfig = agentService.currentConfig;
78
- if (agentConfig) {
79
- logger.info(`Found existing config, agent status: ${agentService.status}`);
80
- } else {
81
- logger.info(`No config found. Please configure via WebUI or API.`);
82
- }
83
-
84
- resolve(server);
85
- });
86
- });
87
- }
88
-
89
- /**
90
- * 获取 Express 应用实例(用于测试)
91
- */
92
- export function createApp(): Express {
93
- const config = loadConfig();
94
- const app: Express = express();
95
-
96
- app.use(express.json());
97
- app.use(express.urlencoded({ extended: true }));
98
-
99
- const agentService = getAgentRpcService();
100
- registerRoutes(app, agentService);
101
-
102
- return app;
103
- }