@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.
@@ -0,0 +1,64 @@
1
+ import { createSocketHandler, onSocketEvent } from '../utils/socket.js';
2
+ /**
3
+ * 项目模块
4
+ */
5
+ export class ProjectModule {
6
+ constructor(socket, baseUrl, projectId) {
7
+ this.socket = socket;
8
+ this.baseUrl = baseUrl;
9
+ this.projectId = projectId;
10
+ }
11
+ /**
12
+ * 获取查询参数
13
+ */
14
+ getQueryParams() {
15
+ if (this.projectId) {
16
+ return `projectId=${encodeURIComponent(this.projectId)}`;
17
+ }
18
+ return '';
19
+ }
20
+ /**
21
+ * 获取项目信息
22
+ */
23
+ async getInfo() {
24
+ const url = `${this.baseUrl}/project/info${this.projectId ? `?${this.getQueryParams()}` : ''}`;
25
+ const response = await fetch(url);
26
+ const result = await response.json();
27
+ if (result.status === 'error') {
28
+ throw new Error(result.message);
29
+ }
30
+ return result.data;
31
+ }
32
+ /**
33
+ * 获取项目文件列表
34
+ */
35
+ async getFiles() {
36
+ const url = `${this.baseUrl}/project/files${this.projectId ? `?${this.getQueryParams()}` : ''}`;
37
+ const response = await fetch(url);
38
+ const result = await response.json();
39
+ if (result.status === 'error') {
40
+ throw new Error(result.message);
41
+ }
42
+ return result.data.files;
43
+ }
44
+ /**
45
+ * 开始监听项目变化
46
+ */
47
+ async watch() {
48
+ return createSocketHandler(this.socket, 'project:watch', () => undefined);
49
+ }
50
+ /**
51
+ * 停止监听项目变化
52
+ */
53
+ async unwatch() {
54
+ return createSocketHandler(this.socket, 'project:unwatch', () => undefined);
55
+ }
56
+ /**
57
+ * 监听项目文件变化
58
+ * @param callback 文件变化回调函数
59
+ * @returns 取消监听的函数
60
+ */
61
+ onFileChange(callback) {
62
+ return onSocketEvent(this.socket, 'project:file-change', callback);
63
+ }
64
+ }
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Agent 消息块类型
3
+ * 这些类型原本来自 wave-agent-sdk,现在复制到项目中以避免外部依赖
4
+ */
5
+ /**
6
+ * 文本块
7
+ */
8
+ export interface TextBlock {
9
+ type: 'text';
10
+ content: string;
11
+ customCommandContent?: string;
12
+ source?: 'user' | 'hook';
13
+ }
14
+ /**
15
+ * 工具块
16
+ */
17
+ export interface ToolBlock {
18
+ type: 'tool';
19
+ parameters?: string;
20
+ result?: string;
21
+ shortResult?: string;
22
+ images?: Array<{
23
+ data: string;
24
+ mediaType?: string;
25
+ }>;
26
+ id?: string;
27
+ name?: string;
28
+ /**
29
+ * Tool execution stage:
30
+ * - 'start': Tool call initiated (from AI service streaming)
31
+ * - 'streaming': Tool parameters being streamed (from AI service)
32
+ * - 'running': Tool execution in progress (from AI manager)
33
+ * - 'end': Tool execution completed (from AI manager)
34
+ */
35
+ stage: 'start' | 'streaming' | 'running' | 'end';
36
+ success?: boolean;
37
+ error?: string | Error;
38
+ compactParams?: string;
39
+ parametersChunk?: string;
40
+ }
41
+ /**
42
+ * 错误块
43
+ */
44
+ export interface ErrorBlock {
45
+ type: 'error';
46
+ content: string;
47
+ }
48
+ export interface SubagentConfiguration {
49
+ name: string;
50
+ description: string;
51
+ tools?: string[];
52
+ model?: string;
53
+ systemPrompt: string;
54
+ filePath: string;
55
+ scope: 'project' | 'user';
56
+ priority: number;
57
+ }
58
+ /**
59
+ * 子代理块
60
+ */
61
+ export interface SubagentBlock {
62
+ type: 'subagent';
63
+ subagentId: string;
64
+ subagentName: string;
65
+ status: 'active' | 'completed' | 'error' | 'aborted';
66
+ configuration: SubagentConfiguration;
67
+ blocks: AssistantBlock[];
68
+ }
69
+ /**
70
+ * MCP 服务器配置
71
+ */
72
+ export interface McpServerConfig {
73
+ command: string;
74
+ args?: string[];
75
+ env?: Record<string, string>;
76
+ }
77
+ /**
78
+ * MCP 服务器状态
79
+ */
80
+ export interface McpServerStatus {
81
+ name: string;
82
+ config: McpServerConfig;
83
+ status: 'disconnected' | 'connected' | 'connecting' | 'error';
84
+ tools?: Array<{
85
+ name: string;
86
+ description?: string;
87
+ inputSchema: Record<string, unknown>;
88
+ }>;
89
+ toolCount?: number;
90
+ capabilities?: string[];
91
+ lastConnected?: number;
92
+ error?: string;
93
+ }
94
+ /**
95
+ * 附件接口
96
+ */
97
+ export interface Attachment {
98
+ url?: string;
99
+ path?: string;
100
+ mimeType: string;
101
+ content?: string;
102
+ }
103
+ /**
104
+ * 发送消息选项
105
+ */
106
+ export interface SendMessageOptions {
107
+ id: string;
108
+ sessionId: string;
109
+ message: string;
110
+ attachments?: Attachment[];
111
+ }
112
+ export interface UserMessage {
113
+ role: 'user';
114
+ id: string;
115
+ content: string;
116
+ attachments?: Attachment[];
117
+ lastModified?: number;
118
+ }
119
+ export type AssistantBlock = TextBlock | ToolBlock | ErrorBlock | SubagentBlock;
120
+ export interface AssistantMessage {
121
+ role: 'assistant';
122
+ id: string;
123
+ blocks: AssistantBlock[];
124
+ status: 'pending' | 'running' | 'finished' | 'error' | 'aborted';
125
+ lastModified?: number;
126
+ }
127
+ export type ChatMessage = UserMessage | AssistantMessage;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Agent 消息块类型
3
+ * 这些类型原本来自 wave-agent-sdk,现在复制到项目中以避免外部依赖
4
+ */
5
+ export {};
@@ -0,0 +1,105 @@
1
+ /**
2
+ * HTTP API 响应类型
3
+ */
4
+ export interface HttpSuccessResponse<T = unknown> {
5
+ status: 'ok';
6
+ data: T;
7
+ }
8
+ export interface HttpErrorResponse {
9
+ status: 'error';
10
+ message: string;
11
+ }
12
+ export type HttpResponse<T = unknown> = HttpSuccessResponse<T> | HttpErrorResponse;
13
+ /**
14
+ * Socket API 响应类型
15
+ */
16
+ export interface SocketSuccessResponse<T = unknown> {
17
+ success: true;
18
+ data: T;
19
+ }
20
+ export interface SocketErrorResponse {
21
+ success: false;
22
+ errorMessage: string;
23
+ }
24
+ export type SocketResponse<T = unknown> = SocketSuccessResponse<T> | SocketErrorResponse;
25
+ /**
26
+ * 文件类型
27
+ */
28
+ export declare enum FileType {
29
+ Unknown = 0,
30
+ File = 1,
31
+ Directory = 2,
32
+ SymbolicLink = 64
33
+ }
34
+ /**
35
+ * 文件状态信息
36
+ */
37
+ export interface FileStat {
38
+ type: FileType;
39
+ size: number;
40
+ ctime: number;
41
+ mtime: number;
42
+ }
43
+ /**
44
+ * 目录项
45
+ */
46
+ export type DirectoryItem = [string, FileType];
47
+ /**
48
+ * 文件变化事件类型
49
+ */
50
+ export type FileChangeType = 'add' | 'change' | 'unlink' | 'addDir' | 'unlinkDir';
51
+ /**
52
+ * 文件变化事件
53
+ */
54
+ export interface FileChangeEvent {
55
+ type: FileChangeType;
56
+ path: string;
57
+ /** 是否为二进制文件(仅在 add 和 change 事件中存在) */
58
+ isBinary?: boolean;
59
+ }
60
+ /**
61
+ * 端口状态类型
62
+ */
63
+ export type PortStatusType = 'open' | 'close';
64
+ /**
65
+ * 端口状态变化事件
66
+ */
67
+ export interface PortStatusChangedEvent {
68
+ port: number;
69
+ type: PortStatusType;
70
+ }
71
+ /**
72
+ * 项目信息
73
+ */
74
+ export interface ProjectInfo {
75
+ projectId: string;
76
+ workdir: string;
77
+ workspace: boolean;
78
+ }
79
+ /**
80
+ * 项目文件信息
81
+ */
82
+ export interface ProjectFile {
83
+ path: string;
84
+ }
85
+ /**
86
+ * SDK 配置选项
87
+ */
88
+ export interface SDKOptions {
89
+ /** 服务器地址,例如 'http://localhost:3030' */
90
+ url: string;
91
+ /** 项目 ID(可选,用于工作空间模式) */
92
+ projectId?: string;
93
+ /** 连接选项 */
94
+ options?: {
95
+ /** 自动连接 */
96
+ autoConnect?: boolean;
97
+ /** 重连选项 */
98
+ reconnection?: boolean;
99
+ /** 重连延迟 */
100
+ reconnectionDelay?: number;
101
+ /** 最大重连次数 */
102
+ reconnectionAttempts?: number;
103
+ };
104
+ }
105
+ export type { TextBlock, ToolBlock, ErrorBlock, SubagentBlock, McpServerConfig, McpServerStatus, Attachment, SendMessageOptions, UserMessage, AssistantBlock, AssistantMessage, ChatMessage, } from './agent-types.js';
@@ -0,0 +1,10 @@
1
+ /**
2
+ * 文件类型
3
+ */
4
+ export var FileType;
5
+ (function (FileType) {
6
+ FileType[FileType["Unknown"] = 0] = "Unknown";
7
+ FileType[FileType["File"] = 1] = "File";
8
+ FileType[FileType["Directory"] = 2] = "Directory";
9
+ FileType[FileType["SymbolicLink"] = 64] = "SymbolicLink";
10
+ })(FileType || (FileType = {}));
@@ -0,0 +1,10 @@
1
+ import type { Socket } from 'socket.io-client';
2
+ /**
3
+ * Socket 事件处理器包装器
4
+ * 发送事件并等待响应
5
+ */
6
+ export declare function createSocketHandler<P, R>(socket: Socket, eventName: string, getPayload: () => Promise<P> | P): Promise<R>;
7
+ /**
8
+ * 监听 Socket 事件
9
+ */
10
+ export declare function onSocketEvent<T>(socket: Socket, eventName: string, callback: (data: T) => void): () => void;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Socket 事件处理器包装器
3
+ * 发送事件并等待响应
4
+ */
5
+ export function createSocketHandler(socket, eventName, getPayload) {
6
+ return Promise.resolve(getPayload()).then((payload) => {
7
+ return new Promise((resolve, reject) => {
8
+ socket.emit(eventName, payload, (response) => {
9
+ if (response.success) {
10
+ resolve(response.data);
11
+ }
12
+ else {
13
+ reject(new Error(response.errorMessage));
14
+ }
15
+ });
16
+ });
17
+ });
18
+ }
19
+ /**
20
+ * 监听 Socket 事件
21
+ */
22
+ export function onSocketEvent(socket, eventName, callback) {
23
+ socket.on(eventName, callback);
24
+ return () => {
25
+ socket.off(eventName, callback);
26
+ };
27
+ }
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@lcap/wave-sandbox-sdk",
3
+ "version": "0.0.1",
4
+ "description": "SDK for Wave Sandbox Client",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "files": [
9
+ "dist",
10
+ "src",
11
+ "README.md"
12
+ ],
13
+ "dependencies": {
14
+ "socket.io-client": "^4.8.1"
15
+ },
16
+ "devDependencies": {
17
+ "rimraf": "^6.1.2",
18
+ "tsc-alias": "^1.8.16",
19
+ "tsx": "^4.21.0",
20
+ "vitest": "^3.2.4"
21
+ },
22
+ "engines": {
23
+ "node": ">=16.0.0"
24
+ },
25
+ "license": "MIT",
26
+ "scripts": {
27
+ "build": "rimraf dist && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
28
+ "type-check": "tsc --noEmit",
29
+ "dev": "tsc -p tsconfig.build.json --watch & tsc-alias -p tsconfig.build.json --watch",
30
+ "test": "vitest run",
31
+ "lint": "eslint --cache",
32
+ "format": "prettier --write ."
33
+ }
34
+ }
package/src/client.ts ADDED
@@ -0,0 +1,152 @@
1
+ import { io, type Socket } from 'socket.io-client';
2
+ import { ExecModule } from './modules/exec.js';
3
+ import { FileSystemModule } from './modules/file-system.js';
4
+ import { PortModule } from './modules/port.js';
5
+ import { ProjectModule } from './modules/project.js';
6
+ import { AgentModule } from './modules/agent.js';
7
+ import type { SDKOptions } from './types/index.js';
8
+
9
+ /**
10
+ * Wave Sandbox SDK 客户端
11
+ */
12
+ export class WaveSandboxClient {
13
+ private socket: Socket;
14
+ public readonly exec: ExecModule;
15
+ public readonly fileSystem: FileSystemModule;
16
+ /** 文件系统模块的简写别名 */
17
+ public get fs(): FileSystemModule {
18
+ return this.fileSystem;
19
+ }
20
+ public readonly port: PortModule;
21
+ public readonly project: ProjectModule;
22
+ public readonly agent: AgentModule;
23
+
24
+ constructor(options: SDKOptions) {
25
+ const { url, projectId, options: socketOptions } = options;
26
+
27
+ const uri = new URL(url);
28
+ let pathname = uri.pathname;
29
+
30
+ if (pathname.endsWith('/')) {
31
+ pathname = pathname.slice(0, pathname.length - 1);
32
+ }
33
+
34
+ pathname = pathname + '/socket.io/';
35
+
36
+ // 构建 Socket.IO 连接选项
37
+ const connectOptions = {
38
+ autoConnect: socketOptions?.autoConnect ?? true,
39
+ reconnection: socketOptions?.reconnection ?? true,
40
+ reconnectionDelay: socketOptions?.reconnectionDelay ?? 1000,
41
+ reconnectionAttempts: socketOptions?.reconnectionAttempts ?? 5,
42
+ query: projectId ? { projectId } : undefined,
43
+ path: pathname,
44
+ };
45
+
46
+ // 创建 Socket.IO 连接
47
+ this.socket = io(uri.host, connectOptions);
48
+
49
+ // 初始化各个模块
50
+ this.exec = new ExecModule(this.socket);
51
+ this.fileSystem = new FileSystemModule(this.socket, url, projectId);
52
+ this.port = new PortModule(this.socket);
53
+ this.project = new ProjectModule(this.socket, url, projectId);
54
+ this.agent = new AgentModule(this.socket, url, projectId);
55
+ }
56
+
57
+ /**
58
+ * 连接到服务器
59
+ */
60
+ connect(): void {
61
+ if (!this.socket.connected) {
62
+ this.socket.connect();
63
+ }
64
+ }
65
+
66
+ /**
67
+ * 断开连接
68
+ */
69
+ disconnect(): void {
70
+ this.socket.disconnect();
71
+ }
72
+
73
+ /**
74
+ * 检查是否已连接
75
+ */
76
+ get connected(): boolean {
77
+ return this.socket.connected;
78
+ }
79
+
80
+ /**
81
+ * 获取 Socket ID
82
+ */
83
+ get id(): string | undefined {
84
+ return this.socket.id;
85
+ }
86
+
87
+ /**
88
+ * 监听连接事件
89
+ */
90
+ onConnect(callback: () => void): () => void {
91
+ this.socket.on('connect', callback);
92
+ return () => {
93
+ this.socket.off('connect', callback);
94
+ };
95
+ }
96
+
97
+ /**
98
+ * 监听断开连接事件
99
+ */
100
+ onDisconnect(callback: () => void): () => void {
101
+ this.socket.on('disconnect', callback);
102
+ return () => {
103
+ this.socket.off('disconnect', callback);
104
+ };
105
+ }
106
+
107
+ /**
108
+ * 监听错误事件
109
+ */
110
+ onError(callback: (error: Error) => void): () => void {
111
+ this.socket.on('error', callback);
112
+ return () => {
113
+ this.socket.off('error', callback);
114
+ };
115
+ }
116
+
117
+ /**
118
+ * 监听重连尝试事件
119
+ * @param callback 回调函数,参数为当前重连尝试次数
120
+ */
121
+ onReconnectAttempt(callback: (attempt: number) => void): () => void {
122
+ this.socket.io.on('reconnect_attempt', callback);
123
+ return () => {
124
+ this.socket.io.off('reconnect_attempt', callback);
125
+ };
126
+ }
127
+
128
+ /**
129
+ * 监听重连成功事件
130
+ * @param callback 回调函数,参数为重连尝试次数
131
+ */
132
+ onReconnect(callback: (attempt: number) => void): () => void {
133
+ this.socket.io.on('reconnect', callback);
134
+ return () => {
135
+ this.socket.io.off('reconnect', callback);
136
+ };
137
+ }
138
+
139
+ /**
140
+ * 监听重连失败事件(达到最大重连次数后触发)
141
+ */
142
+ onReconnectFailed(callback: () => void): () => void {
143
+ this.socket.io.on('reconnect_failed', callback);
144
+ return () => {
145
+ this.socket.io.off('reconnect_failed', callback);
146
+ };
147
+ }
148
+
149
+ getSocket(): Socket {
150
+ return this.socket;
151
+ }
152
+ }
package/src/index.ts ADDED
@@ -0,0 +1,60 @@
1
+ export { WaveSandboxClient } from './client.js';
2
+ export type { SDKOptions } from './types/index.js';
3
+ export type {
4
+ HttpSuccessResponse,
5
+ HttpErrorResponse,
6
+ HttpResponse,
7
+ SocketSuccessResponse,
8
+ SocketErrorResponse,
9
+ SocketResponse,
10
+ FileType,
11
+ FileStat,
12
+ DirectoryItem,
13
+ FileChangeType,
14
+ FileChangeEvent,
15
+ PortStatusType,
16
+ PortStatusChangedEvent,
17
+ ProjectInfo,
18
+ ProjectFile,
19
+ TextBlock,
20
+ ToolBlock,
21
+ ErrorBlock,
22
+ SubagentBlock,
23
+ McpServerConfig,
24
+ McpServerStatus,
25
+ } from './types/index.js';
26
+
27
+ // 导出各个模块(可选,用于高级用法)
28
+ export { ExecModule } from './modules/exec.js';
29
+ export { FileSystemModule } from './modules/file-system.js';
30
+ export { PortModule } from './modules/port.js';
31
+ export { ProjectModule } from './modules/project.js';
32
+ export { AgentModule } from './modules/agent.js';
33
+ export type {
34
+ Attachment,
35
+ SendMessageOptions,
36
+ ProcessQueueItem,
37
+ MessageQueueChangedEvent,
38
+ MessageSendEvent,
39
+ MessageRunningEvent,
40
+ MessageFinishedEvent,
41
+ InitializingEvent,
42
+ InitializedEvent,
43
+ MessageBlockAddedEvent,
44
+ MessageBlockUpdatedEvent,
45
+ MessageToolBlockUpdatedEvent,
46
+ MessageSubagentBlockAddEvent,
47
+ MessageSubagentBlockStatusUpdatedEvent,
48
+ MessageSubagentBlockContentUpdatedEvent,
49
+ MessageSubagentToolBlockUpdatedEvent,
50
+ MessageErrorBlockAddedEvent,
51
+ MessageCommandOutputMessageAddedEvent,
52
+ MessageCommandOutputMessageUpdatedEvent,
53
+ MessageCommandOutputMessageCompletedEvent,
54
+ McpServersChangeEvent,
55
+ DocumentParseStartEvent,
56
+ DocumentParseCompleteEvent,
57
+ DocumentParseErrorEvent,
58
+ AgentEventMap,
59
+ AgentEventName,
60
+ } from './modules/agent.js';