@intella/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 +492 -0
- package/examples/claude-code/README.md +178 -0
- package/examples/claude-code/advanced-config.ts +55 -0
- package/examples/claude-code/basic-usage.ts +56 -0
- package/examples/claude-code/model-comparison.ts +50 -0
- package/examples/claude-code/orchestration.ts +70 -0
- package/examples/claude-code/streaming.ts +69 -0
- package/examples/claude-code/tsconfig.json +19 -0
- package/examples/code-extractor/README.md +77 -0
- package/examples/code-extractor/example.ts +145 -0
- package/examples/filesystem/basic-usage.ts +84 -0
- package/examples/integrated-task/README.md +68 -0
- package/examples/integrated-task/integrated-usage.ts +193 -0
- package/examples/integrated-task/simple-example.ts +51 -0
- package/examples/integrated-task/tsconfig.json +19 -0
- package/examples/sandbox/basic-usage.ts +173 -0
- package/package.json +56 -0
- package/src/agent-manager.ts +104 -0
- package/src/agents/base-agent.ts +166 -0
- package/src/agents/claude-agent.ts +77 -0
- package/src/agents/codex-agent.ts +72 -0
- package/src/agents/intella-lite-agent.ts +55 -0
- package/src/agents/opencode-agent.ts +45 -0
- package/src/filesystem/agentfs-provider.ts +328 -0
- package/src/filesystem/base-provider.ts +98 -0
- package/src/filesystem/index.ts +5 -0
- package/src/filesystem/memory-provider.ts +267 -0
- package/src/filesystem-manager.ts +213 -0
- package/src/index.ts +66 -0
- package/src/orchestrator.ts +177 -0
- package/src/sandbox/base-provider.ts +184 -0
- package/src/sandbox/daytona-provider.ts +462 -0
- package/src/sandbox/e2b-provider.ts +419 -0
- package/src/sandbox/modal-provider.ts +597 -0
- package/src/sandbox-manager.ts +175 -0
- package/src/sdk.ts +401 -0
- package/src/types.ts +451 -0
- package/src/utils/code-extractor.ts +194 -0
- package/tsconfig.json +25 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
FilesystemProviderType,
|
|
3
|
+
FilesystemConfig,
|
|
4
|
+
IFilesystemProvider,
|
|
5
|
+
FileStats,
|
|
6
|
+
DirectoryEntry,
|
|
7
|
+
ToolCallMetadata,
|
|
8
|
+
} from './types.js';
|
|
9
|
+
import { AgentFSProvider } from './filesystem/agentfs-provider.js';
|
|
10
|
+
import { MemoryFilesystemProvider } from './filesystem/memory-provider.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Filesystem Manager
|
|
14
|
+
* Manages filesystem provider instances and configurations
|
|
15
|
+
*/
|
|
16
|
+
export class FilesystemManager {
|
|
17
|
+
private providers: Map<FilesystemProviderType, IFilesystemProvider> = new Map();
|
|
18
|
+
private defaultProviderType: FilesystemProviderType | null = null;
|
|
19
|
+
private currentProvider: IFilesystemProvider | null = null;
|
|
20
|
+
|
|
21
|
+
constructor() {
|
|
22
|
+
// Initialize default providers
|
|
23
|
+
this.registerProvider('agentfs', new AgentFSProvider());
|
|
24
|
+
this.registerProvider('memory', new MemoryFilesystemProvider());
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Register or update a filesystem provider instance
|
|
29
|
+
*/
|
|
30
|
+
registerProvider(type: FilesystemProviderType, provider: IFilesystemProvider): void {
|
|
31
|
+
if (provider.type !== type) {
|
|
32
|
+
throw new Error(`Provider type mismatch: expected ${type}, got ${provider.type}`);
|
|
33
|
+
}
|
|
34
|
+
this.providers.set(type, provider);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Get a filesystem provider instance
|
|
39
|
+
*/
|
|
40
|
+
getProvider(type?: FilesystemProviderType): IFilesystemProvider {
|
|
41
|
+
if (type) {
|
|
42
|
+
const provider = this.providers.get(type);
|
|
43
|
+
if (!provider) {
|
|
44
|
+
throw new Error(`Filesystem provider ${type} is not registered`);
|
|
45
|
+
}
|
|
46
|
+
return provider;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Return current provider if set, otherwise default
|
|
50
|
+
if (this.currentProvider) {
|
|
51
|
+
return this.currentProvider;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (this.defaultProviderType) {
|
|
55
|
+
const provider = this.providers.get(this.defaultProviderType);
|
|
56
|
+
if (provider) {
|
|
57
|
+
return provider;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
throw new Error('No filesystem provider is initialized. Call initializeFilesystem() first.');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Initialize a filesystem provider
|
|
66
|
+
*/
|
|
67
|
+
async initializeFilesystem(
|
|
68
|
+
type: FilesystemProviderType,
|
|
69
|
+
config?: FilesystemConfig
|
|
70
|
+
): Promise<IFilesystemProvider> {
|
|
71
|
+
const provider = this.getProvider(type);
|
|
72
|
+
await provider.initialize(config);
|
|
73
|
+
this.currentProvider = provider;
|
|
74
|
+
if (!this.defaultProviderType) {
|
|
75
|
+
this.defaultProviderType = type;
|
|
76
|
+
}
|
|
77
|
+
return provider;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Check if filesystem is initialized
|
|
82
|
+
*/
|
|
83
|
+
isInitialized(): boolean {
|
|
84
|
+
if (this.currentProvider) {
|
|
85
|
+
return this.currentProvider.isInitialized();
|
|
86
|
+
}
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Close the current filesystem provider
|
|
92
|
+
*/
|
|
93
|
+
async closeFilesystem(): Promise<void> {
|
|
94
|
+
if (this.currentProvider) {
|
|
95
|
+
await this.currentProvider.close();
|
|
96
|
+
this.currentProvider = null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* List all available filesystem providers
|
|
102
|
+
*/
|
|
103
|
+
listProviders(): FilesystemProviderType[] {
|
|
104
|
+
return Array.from(this.providers.keys());
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Check if a provider is registered
|
|
109
|
+
*/
|
|
110
|
+
hasProvider(type: FilesystemProviderType): boolean {
|
|
111
|
+
return this.providers.has(type);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Set the default provider type
|
|
116
|
+
*/
|
|
117
|
+
setDefaultProvider(type: FilesystemProviderType): void {
|
|
118
|
+
if (!this.providers.has(type)) {
|
|
119
|
+
throw new Error(`Filesystem provider ${type} is not registered`);
|
|
120
|
+
}
|
|
121
|
+
this.defaultProviderType = type;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Get the default provider type
|
|
126
|
+
*/
|
|
127
|
+
getDefaultProviderType(): FilesystemProviderType | null {
|
|
128
|
+
return this.defaultProviderType;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Get current provider type
|
|
133
|
+
*/
|
|
134
|
+
getCurrentProviderType(): FilesystemProviderType | null {
|
|
135
|
+
return this.currentProvider?.type || null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Convenience methods that delegate to current provider
|
|
139
|
+
async readFile(path: string): Promise<Buffer | string> {
|
|
140
|
+
return this.getProvider().readFile(path);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async writeFile(path: string, data: Buffer | string): Promise<void> {
|
|
144
|
+
return this.getProvider().writeFile(path, data);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async appendFile(path: string, data: Buffer | string): Promise<void> {
|
|
148
|
+
return this.getProvider().appendFile(path, data);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async exists(path: string): Promise<boolean> {
|
|
152
|
+
return this.getProvider().exists(path);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async stat(path: string): Promise<FileStats> {
|
|
156
|
+
return this.getProvider().stat(path);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async readdir(path: string): Promise<DirectoryEntry[]> {
|
|
160
|
+
return this.getProvider().readdir(path);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async mkdir(path: string, recursive?: boolean): Promise<void> {
|
|
164
|
+
return this.getProvider().mkdir(path, recursive);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async unlink(path: string, recursive?: boolean): Promise<void> {
|
|
168
|
+
return this.getProvider().unlink(path, recursive);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async copy(src: string, dest: string): Promise<void> {
|
|
172
|
+
return this.getProvider().copy(src, dest);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async move(src: string, dest: string): Promise<void> {
|
|
176
|
+
return this.getProvider().move(src, dest);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async get(key: string): Promise<unknown> {
|
|
180
|
+
return this.getProvider().get(key);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async set(key: string, value: unknown): Promise<void> {
|
|
184
|
+
return this.getProvider().set(key, value);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async delete(key: string): Promise<void> {
|
|
188
|
+
return this.getProvider().delete(key);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async listKeys(prefix?: string): Promise<string[]> {
|
|
192
|
+
return this.getProvider().listKeys(prefix);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async hasKey(key: string): Promise<boolean> {
|
|
196
|
+
return this.getProvider().hasKey(key);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async recordToolCall(metadata: ToolCallMetadata): Promise<void> {
|
|
200
|
+
return this.getProvider().recordToolCall(metadata);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async getToolCallHistory(filter?: {
|
|
204
|
+
tool?: string;
|
|
205
|
+
status?: ToolCallMetadata['status'];
|
|
206
|
+
since?: number;
|
|
207
|
+
until?: number;
|
|
208
|
+
limit?: number;
|
|
209
|
+
}): Promise<ToolCallMetadata[]> {
|
|
210
|
+
return this.getProvider().getToolCallHistory(filter);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Main SDK exports
|
|
2
|
+
export { IntellaSDK } from './sdk.js';
|
|
3
|
+
|
|
4
|
+
// Type exports
|
|
5
|
+
export type {
|
|
6
|
+
AgentType,
|
|
7
|
+
AgentConfig,
|
|
8
|
+
TaskRequest,
|
|
9
|
+
TaskResponse,
|
|
10
|
+
StreamChunk,
|
|
11
|
+
OrchestrationStrategy,
|
|
12
|
+
OrchestrationRequest,
|
|
13
|
+
OrchestrationResponse,
|
|
14
|
+
IAgent,
|
|
15
|
+
FilesystemProviderType,
|
|
16
|
+
FilesystemConfig,
|
|
17
|
+
FileStats,
|
|
18
|
+
DirectoryEntry,
|
|
19
|
+
ToolCallMetadata,
|
|
20
|
+
IFilesystemProvider,
|
|
21
|
+
SandboxProviderType,
|
|
22
|
+
SandboxConfig,
|
|
23
|
+
SandboxExecutionResult,
|
|
24
|
+
SandboxInfo,
|
|
25
|
+
CommandResult,
|
|
26
|
+
ISandboxProvider,
|
|
27
|
+
TextPart,
|
|
28
|
+
FilePart,
|
|
29
|
+
MessageContent,
|
|
30
|
+
} from './types.js';
|
|
31
|
+
|
|
32
|
+
// Agent exports
|
|
33
|
+
export { BaseAgent } from './agents/base-agent.js';
|
|
34
|
+
export { IntellaLiteAgent } from './agents/intella-lite-agent.js';
|
|
35
|
+
export { ClaudeAgent } from './agents/claude-agent.js';
|
|
36
|
+
export { CodexAgent } from './agents/codex-agent.js';
|
|
37
|
+
export { OpenCodeAgent } from './agents/opencode-agent.js';
|
|
38
|
+
|
|
39
|
+
// Manager and orchestrator exports
|
|
40
|
+
export { AgentManager } from './agent-manager.js';
|
|
41
|
+
export { Orchestrator } from './orchestrator.js';
|
|
42
|
+
export { FilesystemManager } from './filesystem-manager.js';
|
|
43
|
+
export { SandboxManager } from './sandbox-manager.js';
|
|
44
|
+
|
|
45
|
+
// Filesystem provider exports
|
|
46
|
+
export {
|
|
47
|
+
BaseFilesystemProvider,
|
|
48
|
+
AgentFSProvider,
|
|
49
|
+
MemoryFilesystemProvider,
|
|
50
|
+
} from './filesystem/index.js';
|
|
51
|
+
|
|
52
|
+
// Sandbox provider exports
|
|
53
|
+
export { BaseSandboxProvider } from './sandbox/base-provider.js';
|
|
54
|
+
export { E2BSandboxProvider } from './sandbox/e2b-provider.js';
|
|
55
|
+
export { DaytonaSandboxProvider } from './sandbox/daytona-provider.js';
|
|
56
|
+
export { ModalSandboxProvider } from './sandbox/modal-provider.js';
|
|
57
|
+
|
|
58
|
+
// Utility exports
|
|
59
|
+
export {
|
|
60
|
+
extractCodeBlocks,
|
|
61
|
+
extractCodeBlock,
|
|
62
|
+
extractCode,
|
|
63
|
+
type CodeBlock,
|
|
64
|
+
type ExtractCodeBlocksOptions,
|
|
65
|
+
} from './utils/code-extractor.js';
|
|
66
|
+
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
TaskRequest,
|
|
3
|
+
OrchestrationRequest,
|
|
4
|
+
OrchestrationResponse,
|
|
5
|
+
} from './types.js';
|
|
6
|
+
import { AgentManager } from './agent-manager.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Orchestrator
|
|
10
|
+
* Coordinates multiple agents for task execution
|
|
11
|
+
*/
|
|
12
|
+
export class Orchestrator {
|
|
13
|
+
private agentManager: AgentManager;
|
|
14
|
+
|
|
15
|
+
constructor(agentManager: AgentManager) {
|
|
16
|
+
this.agentManager = agentManager;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Execute orchestration with multiple agents
|
|
21
|
+
*/
|
|
22
|
+
async orchestrate(request: OrchestrationRequest): Promise<OrchestrationResponse> {
|
|
23
|
+
switch (request.strategy) {
|
|
24
|
+
case 'sequential':
|
|
25
|
+
return this.sequentialOrchestration(request);
|
|
26
|
+
case 'parallel':
|
|
27
|
+
return this.parallelOrchestration(request);
|
|
28
|
+
case 'conditional':
|
|
29
|
+
return this.conditionalOrchestration(request);
|
|
30
|
+
default:
|
|
31
|
+
throw new Error(`Unknown orchestration strategy: ${request.strategy}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Sequential orchestration: agents work in sequence, passing results
|
|
37
|
+
*/
|
|
38
|
+
private async sequentialOrchestration(
|
|
39
|
+
request: OrchestrationRequest
|
|
40
|
+
): Promise<OrchestrationResponse> {
|
|
41
|
+
const { task, agents, options } = request;
|
|
42
|
+
const agentResponses: OrchestrationResponse['agentResponses'] = [];
|
|
43
|
+
let currentTask: TaskRequest = { ...task };
|
|
44
|
+
let accumulatedResult = '';
|
|
45
|
+
|
|
46
|
+
for (const agentType of agents) {
|
|
47
|
+
const agent = this.agentManager.getAgent(agentType);
|
|
48
|
+
|
|
49
|
+
// If passing results, include previous results in the prompt
|
|
50
|
+
if (options?.passResults && accumulatedResult) {
|
|
51
|
+
currentTask = {
|
|
52
|
+
...currentTask,
|
|
53
|
+
prompt: `${currentTask.prompt}\n\nPrevious results:\n${accumulatedResult}`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const response = await agent.execute(currentTask);
|
|
58
|
+
agentResponses.push({
|
|
59
|
+
agentType,
|
|
60
|
+
response: response.text,
|
|
61
|
+
metadata: response.metadata,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
accumulatedResult = response.text;
|
|
65
|
+
|
|
66
|
+
// Update task for next iteration if passing results
|
|
67
|
+
if (options?.passResults) {
|
|
68
|
+
currentTask = {
|
|
69
|
+
...task,
|
|
70
|
+
prompt: response.text,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
result: accumulatedResult,
|
|
77
|
+
agentResponses,
|
|
78
|
+
strategy: 'sequential',
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Parallel orchestration: agents work simultaneously, results combined
|
|
84
|
+
*/
|
|
85
|
+
private async parallelOrchestration(
|
|
86
|
+
request: OrchestrationRequest
|
|
87
|
+
): Promise<OrchestrationResponse> {
|
|
88
|
+
const { task, agents, options } = request;
|
|
89
|
+
|
|
90
|
+
// Execute all agents in parallel
|
|
91
|
+
const responses = await Promise.all(
|
|
92
|
+
agents.map(async (agentType) => {
|
|
93
|
+
const agent = this.agentManager.getAgent(agentType);
|
|
94
|
+
const response = await agent.execute(task);
|
|
95
|
+
return {
|
|
96
|
+
agentType,
|
|
97
|
+
response: response.text,
|
|
98
|
+
metadata: response.metadata,
|
|
99
|
+
};
|
|
100
|
+
})
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
// Combine results based on strategy
|
|
104
|
+
const combineStrategy = options?.combineStrategy || 'merge';
|
|
105
|
+
let result: string;
|
|
106
|
+
|
|
107
|
+
switch (combineStrategy) {
|
|
108
|
+
case 'merge':
|
|
109
|
+
result = responses.map((r) => r.response).join('\n\n---\n\n');
|
|
110
|
+
break;
|
|
111
|
+
case 'first':
|
|
112
|
+
result = responses[0]?.response || '';
|
|
113
|
+
break;
|
|
114
|
+
case 'best':
|
|
115
|
+
// For now, just use the first response
|
|
116
|
+
// This could be enhanced with ranking/scoring logic
|
|
117
|
+
result = responses[0]?.response || '';
|
|
118
|
+
break;
|
|
119
|
+
default:
|
|
120
|
+
result = responses.map((r) => r.response).join('\n\n---\n\n');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
result,
|
|
125
|
+
agentResponses: responses,
|
|
126
|
+
strategy: 'parallel',
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Conditional orchestration: route to agents based on task characteristics
|
|
132
|
+
*/
|
|
133
|
+
private async conditionalOrchestration(
|
|
134
|
+
request: OrchestrationRequest
|
|
135
|
+
): Promise<OrchestrationResponse> {
|
|
136
|
+
const { task, agents, options } = request;
|
|
137
|
+
|
|
138
|
+
// Use custom router if provided, otherwise use first agent
|
|
139
|
+
const router = options?.router || (() => agents[0]);
|
|
140
|
+
const selectedAgentType = router(task);
|
|
141
|
+
|
|
142
|
+
if (!agents.includes(selectedAgentType)) {
|
|
143
|
+
throw new Error(
|
|
144
|
+
`Router selected agent ${selectedAgentType} which is not in the agents list`
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const agent = this.agentManager.getAgent(selectedAgentType);
|
|
149
|
+
const response = await agent.execute(task);
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
result: response.text,
|
|
153
|
+
agentResponses: [
|
|
154
|
+
{
|
|
155
|
+
agentType: selectedAgentType,
|
|
156
|
+
response: response.text,
|
|
157
|
+
metadata: response.metadata,
|
|
158
|
+
},
|
|
159
|
+
],
|
|
160
|
+
strategy: 'conditional',
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Register a custom orchestration strategy
|
|
166
|
+
* This allows extending the orchestrator with custom strategies
|
|
167
|
+
*/
|
|
168
|
+
async addCustomStrategy(
|
|
169
|
+
name: string,
|
|
170
|
+
strategy: (request: OrchestrationRequest) => Promise<OrchestrationResponse>
|
|
171
|
+
): Promise<void> {
|
|
172
|
+
// Store custom strategies (implementation can be extended)
|
|
173
|
+
// For now, this is a placeholder for future extensibility
|
|
174
|
+
(this as any)[`${name}Orchestration`] = strategy;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
SandboxProviderType,
|
|
3
|
+
SandboxConfig,
|
|
4
|
+
CommandResult,
|
|
5
|
+
CodeExecutionResult,
|
|
6
|
+
ISandboxProvider,
|
|
7
|
+
SandboxInfo,
|
|
8
|
+
} from '../types.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Base sandbox provider
|
|
12
|
+
* Abstract implementation that provides common functionality
|
|
13
|
+
*/
|
|
14
|
+
export abstract class BaseSandboxProvider implements ISandboxProvider {
|
|
15
|
+
protected initialized = false;
|
|
16
|
+
protected config: SandboxConfig = {};
|
|
17
|
+
protected sandboxId: string | null = null;
|
|
18
|
+
protected client: any | null = null;
|
|
19
|
+
public readonly type: SandboxProviderType;
|
|
20
|
+
|
|
21
|
+
constructor(type: SandboxProviderType, config?: SandboxConfig) {
|
|
22
|
+
this.type = type;
|
|
23
|
+
if (config) {
|
|
24
|
+
this.config = { ...this.config, ...config };
|
|
25
|
+
if(this.getClient) {
|
|
26
|
+
this.client = this.getClient();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
abstract getClient(): any;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Initialize/create a sandbox
|
|
35
|
+
* If fromSandboxId is provided in config, will call fromSandbox instead
|
|
36
|
+
*/
|
|
37
|
+
async initialize(config?: SandboxConfig): Promise<void> {
|
|
38
|
+
if (config) {
|
|
39
|
+
this.config = { ...this.config, ...config };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// If fromSandboxId is provided, use fromSandbox instead of creating new
|
|
43
|
+
if (this.config.fromSandboxId) {
|
|
44
|
+
return this.fromSandbox(this.config.fromSandboxId, config);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Otherwise, call the provider-specific initialization
|
|
48
|
+
return this.initializeSandbox(config);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Provider-specific initialization (creates new sandbox)
|
|
53
|
+
*/
|
|
54
|
+
protected abstract initializeSandbox(config?: SandboxConfig): Promise<void>;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Connect to an existing sandbox by ID
|
|
58
|
+
*/
|
|
59
|
+
abstract fromSandbox(sandboxId: string, config?: SandboxConfig): Promise<any>;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Check if sandbox is initialized
|
|
63
|
+
*/
|
|
64
|
+
isInitialized(): boolean {
|
|
65
|
+
return this.initialized;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Close/cleanup the sandbox
|
|
70
|
+
*/
|
|
71
|
+
abstract close(): Promise<void>;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Get sandbox ID
|
|
75
|
+
*/
|
|
76
|
+
getSandboxId(): string | null {
|
|
77
|
+
return this.sandboxId;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Execute a command in the sandbox
|
|
82
|
+
*/
|
|
83
|
+
abstract executeCommand(
|
|
84
|
+
command: string,
|
|
85
|
+
options?: {
|
|
86
|
+
cwd?: string;
|
|
87
|
+
env?: Record<string, string>;
|
|
88
|
+
timeout?: number;
|
|
89
|
+
}
|
|
90
|
+
): Promise<CommandResult>;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Run code (e.g., Python, JavaScript) in the sandbox
|
|
94
|
+
*/
|
|
95
|
+
abstract runCode(
|
|
96
|
+
code: string,
|
|
97
|
+
options?: {
|
|
98
|
+
language?: string;
|
|
99
|
+
env?: Record<string, string>;
|
|
100
|
+
timeout?: number;
|
|
101
|
+
onStdout?: (data: string) => void;
|
|
102
|
+
onStderr?: (data: string) => void;
|
|
103
|
+
}
|
|
104
|
+
): Promise<CodeExecutionResult>;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Upload a file to the sandbox
|
|
108
|
+
*/
|
|
109
|
+
abstract uploadFile(localPath: string, remotePath: string): Promise<void>;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Download a file from the sandbox
|
|
113
|
+
*/
|
|
114
|
+
abstract downloadFile(remotePath: string, localPath: string): Promise<void>;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Read a file from the sandbox
|
|
118
|
+
*/
|
|
119
|
+
abstract readFile(path: string): Promise<string>;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Write a file to the sandbox
|
|
123
|
+
*/
|
|
124
|
+
abstract writeFile(path: string, content: string): Promise<void>;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* List files in a directory
|
|
128
|
+
*/
|
|
129
|
+
abstract listFiles(path: string): Promise<string[]>;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Check if a file exists
|
|
133
|
+
*/
|
|
134
|
+
abstract fileExists(path: string): Promise<boolean>;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Delete a file
|
|
138
|
+
*/
|
|
139
|
+
abstract deleteFile(path: string): Promise<void>;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Get sandbox status
|
|
143
|
+
*/
|
|
144
|
+
abstract getStatus(): Promise<{
|
|
145
|
+
isRunning: boolean;
|
|
146
|
+
createdAt?: number;
|
|
147
|
+
[key: string]: unknown;
|
|
148
|
+
}>;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Get detailed sandbox information
|
|
152
|
+
*/
|
|
153
|
+
abstract getInfo(sandboxId?: string): Promise<SandboxInfo>;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Ensure sandbox is initialized before operation
|
|
157
|
+
*/
|
|
158
|
+
protected ensureInitialized(): void {
|
|
159
|
+
if (!this.initialized) {
|
|
160
|
+
throw new Error(
|
|
161
|
+
`Sandbox provider ${this.type} is not initialized. Call initialize() first.`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Normalize path (remove leading/trailing slashes, handle ..)
|
|
168
|
+
*/
|
|
169
|
+
protected normalizePath(path: string): string {
|
|
170
|
+
return path
|
|
171
|
+
.split('/')
|
|
172
|
+
.filter((segment) => segment !== '' && segment !== '.')
|
|
173
|
+
.reduce((acc, segment) => {
|
|
174
|
+
if (segment === '..') {
|
|
175
|
+
acc.pop();
|
|
176
|
+
} else {
|
|
177
|
+
acc.push(segment);
|
|
178
|
+
}
|
|
179
|
+
return acc;
|
|
180
|
+
}, [] as string[])
|
|
181
|
+
.join('/');
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|