@lcap/wave-sandbox-sdk 0.0.1
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 +1154 -0
- package/dist/client.d.ts +64 -0
- package/dist/client.js +126 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +7 -0
- package/dist/modules/agent.d.ts +448 -0
- package/dist/modules/agent.js +251 -0
- package/dist/modules/exec.d.ts +27 -0
- package/dist/modules/exec.js +35 -0
- package/dist/modules/file-system.d.ts +64 -0
- package/dist/modules/file-system.js +172 -0
- package/dist/modules/port.d.ts +30 -0
- package/dist/modules/port.js +41 -0
- package/dist/modules/project.d.ts +37 -0
- package/dist/modules/project.js +64 -0
- package/dist/types/agent-types.d.ts +127 -0
- package/dist/types/agent-types.js +5 -0
- package/dist/types/index.d.ts +105 -0
- package/dist/types/index.js +10 -0
- package/dist/utils/socket.d.ts +10 -0
- package/dist/utils/socket.js +27 -0
- package/package.json +34 -0
- package/src/client.ts +152 -0
- package/src/index.ts +60 -0
- package/src/modules/agent.ts +624 -0
- package/src/modules/exec.ts +49 -0
- package/src/modules/file-system.ts +212 -0
- package/src/modules/port.ts +47 -0
- package/src/modules/project.ts +77 -0
- package/src/types/agent-types.ts +140 -0
- package/src/types/index.ts +136 -0
- package/src/utils/socket.ts +34 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import type { Socket } from 'socket.io-client';
|
|
2
|
+
import { createSocketHandler, onSocketEvent } from '../utils/socket.js';
|
|
3
|
+
import type { FileStat, DirectoryItem, FileChangeEvent, HttpResponse } from '../types/index.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 文件系统模块
|
|
7
|
+
*/
|
|
8
|
+
export class FileSystemModule {
|
|
9
|
+
constructor(
|
|
10
|
+
private socket: Socket,
|
|
11
|
+
private baseUrl: string,
|
|
12
|
+
private projectId?: string
|
|
13
|
+
) {}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 获取查询参数
|
|
17
|
+
*/
|
|
18
|
+
private getQueryParams(filePath: string): string {
|
|
19
|
+
const params = new URLSearchParams({ filePath });
|
|
20
|
+
if (this.projectId) {
|
|
21
|
+
params.set('projectId', this.projectId);
|
|
22
|
+
}
|
|
23
|
+
return params.toString();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 获取文件状态
|
|
28
|
+
*/
|
|
29
|
+
async stat(filePath: string): Promise<FileStat> {
|
|
30
|
+
const url = `${this.baseUrl}/api/fs/stat?${this.getQueryParams(filePath)}`;
|
|
31
|
+
const response = await fetch(url);
|
|
32
|
+
const result: HttpResponse<FileStat> = await response.json();
|
|
33
|
+
|
|
34
|
+
if (result.status === 'error') {
|
|
35
|
+
throw new Error(result.message);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return result.data;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 读取文件
|
|
43
|
+
* @param filePath 文件路径
|
|
44
|
+
* @param asText 是否以文本形式读取,默认 false(返回 Blob)
|
|
45
|
+
* @returns Promise<string | Blob> 文件内容
|
|
46
|
+
*/
|
|
47
|
+
async read(filePath: string, asText: false): Promise<Blob>;
|
|
48
|
+
async read(filePath: string, asText: true): Promise<string>;
|
|
49
|
+
async read(filePath: string, asText: boolean = false): Promise<string | Blob> {
|
|
50
|
+
if (asText) {
|
|
51
|
+
// 使用 readFile 端点获取文本内容
|
|
52
|
+
const url = `${this.baseUrl}/api/fs/readFile?${this.getQueryParams(filePath)}`;
|
|
53
|
+
const response = await fetch(url);
|
|
54
|
+
const result: HttpResponse<string> = await response.json();
|
|
55
|
+
|
|
56
|
+
if (result.status === 'error') {
|
|
57
|
+
throw new Error(result.message);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return result.data;
|
|
61
|
+
} else {
|
|
62
|
+
// 使用 read 端点获取原始文件(支持二进制)
|
|
63
|
+
const url = `${this.baseUrl}/api/fs/read?${this.getQueryParams(filePath)}`;
|
|
64
|
+
const response = await fetch(url);
|
|
65
|
+
if (!response.ok) {
|
|
66
|
+
throw new Error(`Failed to read file: ${response.statusText}`);
|
|
67
|
+
}
|
|
68
|
+
return response.blob();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 读取文件内容(文本形式)
|
|
74
|
+
* @param filePath 文件路径
|
|
75
|
+
* @returns Promise<string> 文件文本内容
|
|
76
|
+
*/
|
|
77
|
+
async readFile(filePath: string): Promise<string> {
|
|
78
|
+
return this.read(filePath, true);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* 读取目录
|
|
83
|
+
*/
|
|
84
|
+
async readdir(filePath: string): Promise<DirectoryItem[]> {
|
|
85
|
+
const url = `${this.baseUrl}/api/fs/readdir?${this.getQueryParams(filePath)}`;
|
|
86
|
+
const response = await fetch(url);
|
|
87
|
+
const result: HttpResponse<DirectoryItem[]> = await response.json();
|
|
88
|
+
|
|
89
|
+
if (result.status === 'error') {
|
|
90
|
+
throw new Error(result.message);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return result.data;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 写入文件(流式)
|
|
98
|
+
* @param filePath 文件路径
|
|
99
|
+
* @param data 文件数据(可以是字符串、Blob、ArrayBuffer 或 Buffer)
|
|
100
|
+
* @param chunkSize 分块大小(字节),默认 64KB
|
|
101
|
+
*/
|
|
102
|
+
async writeFile(
|
|
103
|
+
filePath: string,
|
|
104
|
+
data: string | Blob | ArrayBuffer | Uint8Array,
|
|
105
|
+
chunkSize: number = 64 * 1024
|
|
106
|
+
): Promise<void> {
|
|
107
|
+
// 开始写入
|
|
108
|
+
const { taskId } = await createSocketHandler<{ filePath: string }, { taskId: string }>(
|
|
109
|
+
this.socket,
|
|
110
|
+
'fs:writeFileStart',
|
|
111
|
+
() => ({ filePath })
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
// 将数据转换为 Uint8Array
|
|
116
|
+
let buffer: Uint8Array;
|
|
117
|
+
if (typeof data === 'string') {
|
|
118
|
+
buffer = new TextEncoder().encode(data);
|
|
119
|
+
} else if (data instanceof Blob) {
|
|
120
|
+
const arrayBuffer = await data.arrayBuffer();
|
|
121
|
+
buffer = new Uint8Array(arrayBuffer);
|
|
122
|
+
} else if (data instanceof ArrayBuffer) {
|
|
123
|
+
buffer = new Uint8Array(data);
|
|
124
|
+
} else {
|
|
125
|
+
buffer = data;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 分块发送数据
|
|
129
|
+
for (let i = 0; i < buffer.length; i += chunkSize) {
|
|
130
|
+
const chunk = buffer.slice(i, i + chunkSize);
|
|
131
|
+
// 将 Uint8Array 转换为 ArrayBuffer,Socket.IO 会自动处理
|
|
132
|
+
await createSocketHandler<{ taskId: string; chunk: Uint8Array }, void>(
|
|
133
|
+
this.socket,
|
|
134
|
+
'fs:writeFileChunk',
|
|
135
|
+
() => ({ taskId, chunk })
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// 结束写入
|
|
140
|
+
await createSocketHandler<{ taskId: string }, void>(this.socket, 'fs:writeFileEnd', () => ({ taskId }));
|
|
141
|
+
} catch (error) {
|
|
142
|
+
// 如果出错,尝试结束写入以清理资源
|
|
143
|
+
try {
|
|
144
|
+
await createSocketHandler<{ taskId: string }, void>(this.socket, 'fs:writeFileEnd', () => ({ taskId }));
|
|
145
|
+
} catch {
|
|
146
|
+
// 忽略清理错误
|
|
147
|
+
}
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* 创建目录
|
|
154
|
+
*/
|
|
155
|
+
async mkdir(filePath: string): Promise<string | undefined> {
|
|
156
|
+
return createSocketHandler<{ filePath: string }, string | undefined>(this.socket, 'fs:mkdir', () => ({ filePath }));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* 重命名文件或目录
|
|
161
|
+
*/
|
|
162
|
+
async rename(oldPath: string, newPath: string): Promise<void> {
|
|
163
|
+
return createSocketHandler<{ oldPath: string; newPath: string }, void>(this.socket, 'fs:rename', () => ({
|
|
164
|
+
oldPath,
|
|
165
|
+
newPath,
|
|
166
|
+
}));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* 删除文件或目录
|
|
171
|
+
*/
|
|
172
|
+
async rm(filePath: string): Promise<void> {
|
|
173
|
+
return createSocketHandler<{ filePath: string }, void>(this.socket, 'fs:rm', () => ({ filePath }));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* 监听文件变化
|
|
178
|
+
* @param paths 要监听的文件路径数组
|
|
179
|
+
* @param ignored 要忽略的文件路径数组
|
|
180
|
+
* @param callback 文件变化回调函数
|
|
181
|
+
* @returns 取消监听的函数
|
|
182
|
+
*/
|
|
183
|
+
watch(paths: string[], ignored: string[] = [], callback: (event: FileChangeEvent) => void): () => void {
|
|
184
|
+
let taskId: string | null = null;
|
|
185
|
+
|
|
186
|
+
// 启动监听
|
|
187
|
+
createSocketHandler<{ paths: string[]; ignored: string[] }, { taskId: string }>(this.socket, 'fs:watch', () => ({
|
|
188
|
+
paths,
|
|
189
|
+
ignored,
|
|
190
|
+
}))
|
|
191
|
+
.then((result) => {
|
|
192
|
+
taskId = result.taskId;
|
|
193
|
+
// 监听文件变化事件
|
|
194
|
+
const eventName = `fs:file-change:${taskId}`;
|
|
195
|
+
onSocketEvent<FileChangeEvent>(this.socket, eventName, callback);
|
|
196
|
+
})
|
|
197
|
+
.catch((error) => {
|
|
198
|
+
console.error('Failed to start file watch:', error);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// 返回取消监听的函数
|
|
202
|
+
return () => {
|
|
203
|
+
if (taskId) {
|
|
204
|
+
createSocketHandler<{ taskId: string }, void>(this.socket, 'fs:unwatch', () => ({ taskId: taskId! })).catch(
|
|
205
|
+
(error) => {
|
|
206
|
+
console.error('Failed to stop file watch:', error);
|
|
207
|
+
}
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Socket } from 'socket.io-client';
|
|
2
|
+
import { createSocketHandler, onSocketEvent } from '../utils/socket.js';
|
|
3
|
+
import type { PortStatusChangedEvent } from '../types/index.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 端口监听模块
|
|
7
|
+
*/
|
|
8
|
+
export class PortModule {
|
|
9
|
+
constructor(private socket: Socket) {}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 获取可用端口
|
|
13
|
+
* @param count 需要获取的端口数量,默认 2
|
|
14
|
+
* @returns Promise<number[]> 可用端口数组
|
|
15
|
+
*/
|
|
16
|
+
async getPorts(count: number = 2): Promise<number[]> {
|
|
17
|
+
const result = await createSocketHandler<{ count?: number }, { ports: number[] }>(this.socket, 'port:find', () => ({
|
|
18
|
+
count,
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
return result.ports;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 开始监听端口状态
|
|
26
|
+
* @param ports 要监听的端口数组
|
|
27
|
+
*/
|
|
28
|
+
async startWatch(ports: number[]): Promise<void> {
|
|
29
|
+
return createSocketHandler<{ ports: number[] }, void>(this.socket, 'port:watch', () => ({ ports }));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 停止监听端口状态
|
|
34
|
+
*/
|
|
35
|
+
async stopWatch(): Promise<void> {
|
|
36
|
+
return createSocketHandler<void, void>(this.socket, 'port:unwatch', () => undefined);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 监听端口状态变化
|
|
41
|
+
* @param callback 端口状态变化回调函数
|
|
42
|
+
* @returns 取消监听的函数
|
|
43
|
+
*/
|
|
44
|
+
onStatusChanged(callback: (event: PortStatusChangedEvent) => void): () => void {
|
|
45
|
+
return onSocketEvent<PortStatusChangedEvent>(this.socket, 'portStatusChanged', callback);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { Socket } from 'socket.io-client';
|
|
2
|
+
import { createSocketHandler, onSocketEvent } from '../utils/socket.js';
|
|
3
|
+
import type { ProjectInfo, ProjectFile, HttpResponse, FileChangeEvent } from '../types/index.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 项目模块
|
|
7
|
+
*/
|
|
8
|
+
export class ProjectModule {
|
|
9
|
+
constructor(
|
|
10
|
+
private socket: Socket,
|
|
11
|
+
private baseUrl: string,
|
|
12
|
+
private projectId?: string
|
|
13
|
+
) {}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 获取查询参数
|
|
17
|
+
*/
|
|
18
|
+
private getQueryParams(): string {
|
|
19
|
+
if (this.projectId) {
|
|
20
|
+
return `projectId=${encodeURIComponent(this.projectId)}`;
|
|
21
|
+
}
|
|
22
|
+
return '';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 获取项目信息
|
|
27
|
+
*/
|
|
28
|
+
async getInfo(): Promise<ProjectInfo> {
|
|
29
|
+
const url = `${this.baseUrl}/project/info${this.projectId ? `?${this.getQueryParams()}` : ''}`;
|
|
30
|
+
const response = await fetch(url);
|
|
31
|
+
const result: HttpResponse<ProjectInfo> = await response.json();
|
|
32
|
+
|
|
33
|
+
if (result.status === 'error') {
|
|
34
|
+
throw new Error(result.message);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return result.data;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 获取项目文件列表
|
|
42
|
+
*/
|
|
43
|
+
async getFiles(): Promise<ProjectFile[]> {
|
|
44
|
+
const url = `${this.baseUrl}/project/files${this.projectId ? `?${this.getQueryParams()}` : ''}`;
|
|
45
|
+
const response = await fetch(url);
|
|
46
|
+
const result: HttpResponse<{ files: ProjectFile[] }> = await response.json();
|
|
47
|
+
|
|
48
|
+
if (result.status === 'error') {
|
|
49
|
+
throw new Error(result.message);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return result.data.files;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 开始监听项目变化
|
|
57
|
+
*/
|
|
58
|
+
async watch(): Promise<void> {
|
|
59
|
+
return createSocketHandler<void, void>(this.socket, 'project:watch', () => undefined);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 停止监听项目变化
|
|
64
|
+
*/
|
|
65
|
+
async unwatch(): Promise<void> {
|
|
66
|
+
return createSocketHandler<void, void>(this.socket, 'project:unwatch', () => undefined);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 监听项目文件变化
|
|
71
|
+
* @param callback 文件变化回调函数
|
|
72
|
+
* @returns 取消监听的函数
|
|
73
|
+
*/
|
|
74
|
+
onFileChange(callback: (event: FileChangeEvent) => void): () => void {
|
|
75
|
+
return onSocketEvent<FileChangeEvent>(this.socket, 'project:file-change', callback);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent 消息块类型
|
|
3
|
+
* 这些类型原本来自 wave-agent-sdk,现在复制到项目中以避免外部依赖
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 文本块
|
|
8
|
+
*/
|
|
9
|
+
export interface TextBlock {
|
|
10
|
+
type: 'text';
|
|
11
|
+
content: string;
|
|
12
|
+
customCommandContent?: string;
|
|
13
|
+
source?: 'user' | 'hook';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 工具块
|
|
18
|
+
*/
|
|
19
|
+
export interface ToolBlock {
|
|
20
|
+
type: 'tool';
|
|
21
|
+
parameters?: string;
|
|
22
|
+
result?: string;
|
|
23
|
+
shortResult?: string;
|
|
24
|
+
images?: Array<{
|
|
25
|
+
data: string;
|
|
26
|
+
mediaType?: string;
|
|
27
|
+
}>;
|
|
28
|
+
id?: string;
|
|
29
|
+
name?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Tool execution stage:
|
|
32
|
+
* - 'start': Tool call initiated (from AI service streaming)
|
|
33
|
+
* - 'streaming': Tool parameters being streamed (from AI service)
|
|
34
|
+
* - 'running': Tool execution in progress (from AI manager)
|
|
35
|
+
* - 'end': Tool execution completed (from AI manager)
|
|
36
|
+
*/
|
|
37
|
+
stage: 'start' | 'streaming' | 'running' | 'end';
|
|
38
|
+
success?: boolean;
|
|
39
|
+
error?: string | Error;
|
|
40
|
+
compactParams?: string;
|
|
41
|
+
parametersChunk?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 错误块
|
|
46
|
+
*/
|
|
47
|
+
export interface ErrorBlock {
|
|
48
|
+
type: 'error';
|
|
49
|
+
content: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface SubagentConfiguration {
|
|
53
|
+
name: string;
|
|
54
|
+
description: string;
|
|
55
|
+
tools?: string[];
|
|
56
|
+
model?: string;
|
|
57
|
+
systemPrompt: string;
|
|
58
|
+
filePath: string;
|
|
59
|
+
scope: 'project' | 'user';
|
|
60
|
+
priority: number;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 子代理块
|
|
65
|
+
*/
|
|
66
|
+
export interface SubagentBlock {
|
|
67
|
+
type: 'subagent';
|
|
68
|
+
subagentId: string;
|
|
69
|
+
subagentName: string;
|
|
70
|
+
status: 'active' | 'completed' | 'error' | 'aborted';
|
|
71
|
+
configuration: SubagentConfiguration;
|
|
72
|
+
blocks: AssistantBlock[];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* MCP 服务器配置
|
|
77
|
+
*/
|
|
78
|
+
export interface McpServerConfig {
|
|
79
|
+
command: string;
|
|
80
|
+
args?: string[];
|
|
81
|
+
env?: Record<string, string>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* MCP 服务器状态
|
|
86
|
+
*/
|
|
87
|
+
export interface McpServerStatus {
|
|
88
|
+
name: string;
|
|
89
|
+
config: McpServerConfig;
|
|
90
|
+
status: 'disconnected' | 'connected' | 'connecting' | 'error';
|
|
91
|
+
tools?: Array<{
|
|
92
|
+
name: string;
|
|
93
|
+
description?: string;
|
|
94
|
+
inputSchema: Record<string, unknown>;
|
|
95
|
+
}>;
|
|
96
|
+
toolCount?: number;
|
|
97
|
+
capabilities?: string[];
|
|
98
|
+
lastConnected?: number;
|
|
99
|
+
error?: string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 附件接口
|
|
104
|
+
*/
|
|
105
|
+
export interface Attachment {
|
|
106
|
+
url?: string;
|
|
107
|
+
path?: string;
|
|
108
|
+
mimeType: string;
|
|
109
|
+
content?: string;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 发送消息选项
|
|
114
|
+
*/
|
|
115
|
+
export interface SendMessageOptions {
|
|
116
|
+
id: string;
|
|
117
|
+
sessionId: string;
|
|
118
|
+
message: string;
|
|
119
|
+
attachments?: Attachment[];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface UserMessage {
|
|
123
|
+
role: 'user';
|
|
124
|
+
id: string;
|
|
125
|
+
content: string;
|
|
126
|
+
attachments?: Attachment[];
|
|
127
|
+
lastModified?: number;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export type AssistantBlock = TextBlock | ToolBlock | ErrorBlock | SubagentBlock;
|
|
131
|
+
|
|
132
|
+
export interface AssistantMessage {
|
|
133
|
+
role: 'assistant';
|
|
134
|
+
id: string;
|
|
135
|
+
blocks: AssistantBlock[];
|
|
136
|
+
status: 'pending' | 'running' | 'finished' | 'error' | 'aborted';
|
|
137
|
+
lastModified?: number;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export type ChatMessage = UserMessage | AssistantMessage;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP API 响应类型
|
|
3
|
+
*/
|
|
4
|
+
export interface HttpSuccessResponse<T = unknown> {
|
|
5
|
+
status: 'ok';
|
|
6
|
+
data: T;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface HttpErrorResponse {
|
|
10
|
+
status: 'error';
|
|
11
|
+
message: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type HttpResponse<T = unknown> = HttpSuccessResponse<T> | HttpErrorResponse;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Socket API 响应类型
|
|
18
|
+
*/
|
|
19
|
+
export interface SocketSuccessResponse<T = unknown> {
|
|
20
|
+
success: true;
|
|
21
|
+
data: T;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface SocketErrorResponse {
|
|
25
|
+
success: false;
|
|
26
|
+
errorMessage: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type SocketResponse<T = unknown> = SocketSuccessResponse<T> | SocketErrorResponse;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 文件类型
|
|
33
|
+
*/
|
|
34
|
+
export enum FileType {
|
|
35
|
+
Unknown = 0,
|
|
36
|
+
File = 1,
|
|
37
|
+
Directory = 2,
|
|
38
|
+
SymbolicLink = 64,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 文件状态信息
|
|
43
|
+
*/
|
|
44
|
+
export interface FileStat {
|
|
45
|
+
type: FileType;
|
|
46
|
+
size: number;
|
|
47
|
+
ctime: number;
|
|
48
|
+
mtime: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 目录项
|
|
53
|
+
*/
|
|
54
|
+
export type DirectoryItem = [string, FileType];
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 文件变化事件类型
|
|
58
|
+
*/
|
|
59
|
+
export type FileChangeType = 'add' | 'change' | 'unlink' | 'addDir' | 'unlinkDir';
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 文件变化事件
|
|
63
|
+
*/
|
|
64
|
+
export interface FileChangeEvent {
|
|
65
|
+
type: FileChangeType;
|
|
66
|
+
path: string;
|
|
67
|
+
/** 是否为二进制文件(仅在 add 和 change 事件中存在) */
|
|
68
|
+
isBinary?: boolean;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 端口状态类型
|
|
73
|
+
*/
|
|
74
|
+
export type PortStatusType = 'open' | 'close';
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 端口状态变化事件
|
|
78
|
+
*/
|
|
79
|
+
export interface PortStatusChangedEvent {
|
|
80
|
+
port: number;
|
|
81
|
+
type: PortStatusType;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 项目信息
|
|
86
|
+
*/
|
|
87
|
+
export interface ProjectInfo {
|
|
88
|
+
projectId: string;
|
|
89
|
+
workdir: string;
|
|
90
|
+
workspace: boolean;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* 项目文件信息
|
|
95
|
+
*/
|
|
96
|
+
export interface ProjectFile {
|
|
97
|
+
path: string;
|
|
98
|
+
// 可以根据实际需要添加更多字段
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* SDK 配置选项
|
|
103
|
+
*/
|
|
104
|
+
export interface SDKOptions {
|
|
105
|
+
/** 服务器地址,例如 'http://localhost:3030' */
|
|
106
|
+
url: string;
|
|
107
|
+
/** 项目 ID(可选,用于工作空间模式) */
|
|
108
|
+
projectId?: string;
|
|
109
|
+
/** 连接选项 */
|
|
110
|
+
options?: {
|
|
111
|
+
/** 自动连接 */
|
|
112
|
+
autoConnect?: boolean;
|
|
113
|
+
/** 重连选项 */
|
|
114
|
+
reconnection?: boolean;
|
|
115
|
+
/** 重连延迟 */
|
|
116
|
+
reconnectionDelay?: number;
|
|
117
|
+
/** 最大重连次数 */
|
|
118
|
+
reconnectionAttempts?: number;
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 导出 Agent 相关类型
|
|
123
|
+
export type {
|
|
124
|
+
TextBlock,
|
|
125
|
+
ToolBlock,
|
|
126
|
+
ErrorBlock,
|
|
127
|
+
SubagentBlock,
|
|
128
|
+
McpServerConfig,
|
|
129
|
+
McpServerStatus,
|
|
130
|
+
Attachment,
|
|
131
|
+
SendMessageOptions,
|
|
132
|
+
UserMessage,
|
|
133
|
+
AssistantBlock,
|
|
134
|
+
AssistantMessage,
|
|
135
|
+
ChatMessage,
|
|
136
|
+
} from './agent-types.js';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Socket } from 'socket.io-client';
|
|
2
|
+
import type { SocketResponse } from '../types/index.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Socket 事件处理器包装器
|
|
6
|
+
* 发送事件并等待响应
|
|
7
|
+
*/
|
|
8
|
+
export function createSocketHandler<P, R>(
|
|
9
|
+
socket: Socket,
|
|
10
|
+
eventName: string,
|
|
11
|
+
getPayload: () => Promise<P> | P
|
|
12
|
+
): Promise<R> {
|
|
13
|
+
return Promise.resolve(getPayload()).then((payload) => {
|
|
14
|
+
return new Promise<R>((resolve, reject) => {
|
|
15
|
+
socket.emit(eventName, payload, (response: SocketResponse<R>) => {
|
|
16
|
+
if (response.success) {
|
|
17
|
+
resolve(response.data);
|
|
18
|
+
} else {
|
|
19
|
+
reject(new Error(response.errorMessage));
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 监听 Socket 事件
|
|
28
|
+
*/
|
|
29
|
+
export function onSocketEvent<T>(socket: Socket, eventName: string, callback: (data: T) => void): () => void {
|
|
30
|
+
socket.on(eventName, callback);
|
|
31
|
+
return () => {
|
|
32
|
+
socket.off(eventName, callback);
|
|
33
|
+
};
|
|
34
|
+
}
|