@ebowwa/sandbox 0.1.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/dist/compilers/index.d.ts +24 -0
- package/dist/compilers/index.d.ts.map +1 -0
- package/dist/compilers/index.js +42 -0
- package/dist/compilers/index.js.map +1 -0
- package/dist/compilers/javascript.d.ts +117 -0
- package/dist/compilers/javascript.d.ts.map +1 -0
- package/dist/compilers/javascript.js +462 -0
- package/dist/compilers/javascript.js.map +1 -0
- package/dist/compilers/python.d.ts +140 -0
- package/dist/compilers/python.d.ts.map +1 -0
- package/dist/compilers/python.js +650 -0
- package/dist/compilers/python.js.map +1 -0
- package/dist/compilers/typescript.d.ts +99 -0
- package/dist/compilers/typescript.d.ts.map +1 -0
- package/dist/compilers/typescript.js +323 -0
- package/dist/compilers/typescript.js.map +1 -0
- package/dist/core/cell.d.ts +160 -0
- package/dist/core/cell.d.ts.map +1 -0
- package/dist/core/cell.js +319 -0
- package/dist/core/cell.js.map +1 -0
- package/dist/core/compiler.d.ts +126 -0
- package/dist/core/compiler.d.ts.map +1 -0
- package/dist/core/compiler.js +123 -0
- package/dist/core/compiler.js.map +1 -0
- package/dist/core/index.d.ts +19 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +14 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/limits.d.ts +173 -0
- package/dist/core/limits.d.ts.map +1 -0
- package/dist/core/limits.js +440 -0
- package/dist/core/limits.js.map +1 -0
- package/dist/core/permissions.d.ts +103 -0
- package/dist/core/permissions.d.ts.map +1 -0
- package/dist/core/permissions.js +341 -0
- package/dist/core/permissions.js.map +1 -0
- package/dist/core/runtime.d.ts +127 -0
- package/dist/core/runtime.d.ts.map +1 -0
- package/dist/core/runtime.js +325 -0
- package/dist/core/runtime.js.map +1 -0
- package/dist/core/types.d.ts +380 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +67 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +145 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +279 -0
- package/dist/index.js.map +1 -0
- package/dist/multi/index.d.ts +9 -0
- package/dist/multi/index.d.ts.map +1 -0
- package/dist/multi/index.js +7 -0
- package/dist/multi/index.js.map +1 -0
- package/dist/multi/polyglot.d.ts +179 -0
- package/dist/multi/polyglot.d.ts.map +1 -0
- package/dist/multi/polyglot.js +319 -0
- package/dist/multi/polyglot.js.map +1 -0
- package/dist/runtimes/docker.d.ts +97 -0
- package/dist/runtimes/docker.d.ts.map +1 -0
- package/dist/runtimes/docker.js +368 -0
- package/dist/runtimes/docker.js.map +1 -0
- package/dist/runtimes/index.d.ts +11 -0
- package/dist/runtimes/index.d.ts.map +1 -0
- package/dist/runtimes/index.js +9 -0
- package/dist/runtimes/index.js.map +1 -0
- package/dist/runtimes/process.d.ts +47 -0
- package/dist/runtimes/process.d.ts.map +1 -0
- package/dist/runtimes/process.js +230 -0
- package/dist/runtimes/process.js.map +1 -0
- package/dist/session/index.d.ts +12 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +9 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/kernel.d.ts +199 -0
- package/dist/session/kernel.d.ts.map +1 -0
- package/dist/session/kernel.js +400 -0
- package/dist/session/kernel.js.map +1 -0
- package/dist/session/notebook.d.ts +168 -0
- package/dist/session/notebook.d.ts.map +1 -0
- package/dist/session/notebook.js +499 -0
- package/dist/session/notebook.js.map +1 -0
- package/dist/session/repl.d.ts +159 -0
- package/dist/session/repl.d.ts.map +1 -0
- package/dist/session/repl.js +409 -0
- package/dist/session/repl.js.map +1 -0
- package/package.json +142 -0
- package/src/compilers/index.ts +80 -0
- package/src/compilers/javascript.ts +571 -0
- package/src/compilers/python.ts +785 -0
- package/src/compilers/typescript.ts +442 -0
- package/src/core/cell.ts +439 -0
- package/src/core/compiler.ts +250 -0
- package/src/core/index.ts +123 -0
- package/src/core/limits.ts +508 -0
- package/src/core/permissions.ts +409 -0
- package/src/core/runtime.ts +499 -0
- package/src/core/types.ts +528 -0
- package/src/global.d.ts +59 -0
- package/src/index.ts +515 -0
- package/src/multi/index.ts +22 -0
- package/src/multi/polyglot.ts +461 -0
- package/src/runtimes/docker.ts +501 -0
- package/src/runtimes/index.ts +21 -0
- package/src/runtimes/process.ts +316 -0
- package/src/session/index.ts +41 -0
- package/src/session/kernel.ts +553 -0
- package/src/session/notebook.ts +635 -0
- package/src/session/repl.ts +521 -0
- package/src/wasm2wasm.d.ts +35 -0
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kernel Primitive
|
|
3
|
+
*
|
|
4
|
+
* Language-specific execution session with state persistence.
|
|
5
|
+
* Provides REPL-like interactive execution for a single language.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
Language,
|
|
10
|
+
Kernel,
|
|
11
|
+
ExecutionResult,
|
|
12
|
+
ExecutionOptions,
|
|
13
|
+
CompletionResult,
|
|
14
|
+
InspectResult,
|
|
15
|
+
Permissions,
|
|
16
|
+
Limits,
|
|
17
|
+
Cell,
|
|
18
|
+
} from "../core/types.js";
|
|
19
|
+
import type { ICompiler, CompileResult } from "../core/compiler.js";
|
|
20
|
+
import type { IRuntime, ExecutionRequest } from "../core/runtime.js";
|
|
21
|
+
import { PermissionChecker, createPermissions } from "../core/permissions.js";
|
|
22
|
+
import { LimitsParser, LimitsEnforcer, DEFAULT_LIMITS } from "../core/limits.js";
|
|
23
|
+
import { v4 as uuid } from "uuid";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Kernel state
|
|
27
|
+
*/
|
|
28
|
+
export type KernelState =
|
|
29
|
+
| "starting"
|
|
30
|
+
| "ready"
|
|
31
|
+
| "busy"
|
|
32
|
+
| "error"
|
|
33
|
+
| "shutting_down"
|
|
34
|
+
| "dead";
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Kernel options
|
|
38
|
+
*/
|
|
39
|
+
export interface KernelOptions {
|
|
40
|
+
/** Kernel ID */
|
|
41
|
+
id?: string;
|
|
42
|
+
/** Display name */
|
|
43
|
+
displayName?: string;
|
|
44
|
+
/** Language */
|
|
45
|
+
language: Language;
|
|
46
|
+
/** Compiler for this language */
|
|
47
|
+
compiler: ICompiler;
|
|
48
|
+
/** Runtime for execution */
|
|
49
|
+
runtime: IRuntime;
|
|
50
|
+
/** Permissions */
|
|
51
|
+
permissions?: Permissions;
|
|
52
|
+
/** Resource limits */
|
|
53
|
+
limits?: Limits;
|
|
54
|
+
/** Environment variables */
|
|
55
|
+
env?: Record<string, string>;
|
|
56
|
+
/** Working directory */
|
|
57
|
+
cwd?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Kernel statistics
|
|
62
|
+
*/
|
|
63
|
+
export interface KernelStats {
|
|
64
|
+
/** Total executions */
|
|
65
|
+
executions: number;
|
|
66
|
+
/** Successful executions */
|
|
67
|
+
successes: number;
|
|
68
|
+
/** Failed executions */
|
|
69
|
+
failures: number;
|
|
70
|
+
/** Total execution time (ms) */
|
|
71
|
+
totalTime: number;
|
|
72
|
+
/** Average execution time (ms) */
|
|
73
|
+
avgTime: number;
|
|
74
|
+
/** Memory high water mark */
|
|
75
|
+
memoryHighWater: number;
|
|
76
|
+
/** Last execution time */
|
|
77
|
+
lastExecution?: Date;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Base Kernel Implementation
|
|
82
|
+
*
|
|
83
|
+
* Provides core kernel functionality with state management.
|
|
84
|
+
*/
|
|
85
|
+
export class BaseKernel implements Kernel {
|
|
86
|
+
readonly language: Language;
|
|
87
|
+
readonly displayName: string;
|
|
88
|
+
|
|
89
|
+
private id: string;
|
|
90
|
+
private state: KernelState = "starting";
|
|
91
|
+
private kernelState = new Map<string, unknown>();
|
|
92
|
+
private exports = new Map<string, unknown>();
|
|
93
|
+
private compiler: ICompiler;
|
|
94
|
+
private runtime: IRuntime;
|
|
95
|
+
private permissions: Permissions;
|
|
96
|
+
private limits: Limits;
|
|
97
|
+
private env: Record<string, string>;
|
|
98
|
+
private cwd?: string;
|
|
99
|
+
private stats: KernelStats = {
|
|
100
|
+
executions: 0,
|
|
101
|
+
successes: 0,
|
|
102
|
+
failures: 0,
|
|
103
|
+
totalTime: 0,
|
|
104
|
+
avgTime: 0,
|
|
105
|
+
memoryHighWater: 0,
|
|
106
|
+
};
|
|
107
|
+
private permissionChecker: PermissionChecker;
|
|
108
|
+
|
|
109
|
+
constructor(options: KernelOptions) {
|
|
110
|
+
this.id = options.id ?? uuid();
|
|
111
|
+
this.language = options.language;
|
|
112
|
+
this.displayName = options.displayName ?? `${options.language} kernel`;
|
|
113
|
+
this.compiler = options.compiler;
|
|
114
|
+
this.runtime = options.runtime;
|
|
115
|
+
this.permissions = options.permissions ?? {};
|
|
116
|
+
this.limits = options.limits ?? {};
|
|
117
|
+
this.env = options.env ?? {};
|
|
118
|
+
this.cwd = options.cwd;
|
|
119
|
+
this.permissionChecker = new PermissionChecker(this.permissions);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Get kernel ID
|
|
124
|
+
*/
|
|
125
|
+
getId(): string {
|
|
126
|
+
return this.id;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Get current execution state
|
|
131
|
+
*/
|
|
132
|
+
getExecutionState(): KernelState {
|
|
133
|
+
return this.state;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Get kernel state (variables)
|
|
138
|
+
*/
|
|
139
|
+
getState(): Map<string, unknown> {
|
|
140
|
+
return new Map(this.kernelState);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get exports
|
|
145
|
+
*/
|
|
146
|
+
getExports(): Map<string, unknown> {
|
|
147
|
+
return new Map(this.exports);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Get statistics
|
|
152
|
+
*/
|
|
153
|
+
getStats(): KernelStats {
|
|
154
|
+
return { ...this.stats };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Start the kernel
|
|
159
|
+
*/
|
|
160
|
+
async start(): Promise<void> {
|
|
161
|
+
this.state = "starting";
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
// Check if compiler is available
|
|
165
|
+
if (!(await this.compiler.isAvailable())) {
|
|
166
|
+
throw new Error(`Compiler for ${this.language} is not available`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Initialize runtime
|
|
170
|
+
await this.runtime.init();
|
|
171
|
+
|
|
172
|
+
// Check if runtime is available
|
|
173
|
+
if (!(await this.runtime.isAvailable())) {
|
|
174
|
+
throw new Error(`Runtime ${this.runtime.name} is not available`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
this.state = "ready";
|
|
178
|
+
} catch (error) {
|
|
179
|
+
this.state = "error";
|
|
180
|
+
throw error;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Check if kernel is running
|
|
186
|
+
*/
|
|
187
|
+
isRunning(): boolean {
|
|
188
|
+
return this.state === "ready" || this.state === "busy";
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Get display name
|
|
193
|
+
*/
|
|
194
|
+
getDisplayName(): string {
|
|
195
|
+
return this.displayName;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Get language
|
|
200
|
+
*/
|
|
201
|
+
getLanguage(): Language {
|
|
202
|
+
return this.language;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Execute code
|
|
207
|
+
*/
|
|
208
|
+
async execute(
|
|
209
|
+
code: string,
|
|
210
|
+
options?: ExecutionOptions
|
|
211
|
+
): Promise<ExecutionResult> {
|
|
212
|
+
if (this.state !== "ready" && this.state !== "busy") {
|
|
213
|
+
return this.createErrorResult(
|
|
214
|
+
`Kernel is not ready (state: ${this.state})`,
|
|
215
|
+
"runtime"
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
this.state = "busy";
|
|
220
|
+
const startTime = Date.now();
|
|
221
|
+
|
|
222
|
+
try {
|
|
223
|
+
// Parse limits
|
|
224
|
+
const parsedLimits = LimitsParser.parse(this.limits);
|
|
225
|
+
const enforcer = new LimitsEnforcer(parsedLimits);
|
|
226
|
+
enforcer.start();
|
|
227
|
+
|
|
228
|
+
// Check for abort signal
|
|
229
|
+
if (options?.signal?.aborted) {
|
|
230
|
+
return this.createErrorResult("Execution cancelled", "cancel");
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Compile
|
|
234
|
+
const compiled = await this.compiler.compile(
|
|
235
|
+
code,
|
|
236
|
+
this.permissions,
|
|
237
|
+
this.limits,
|
|
238
|
+
{ optimize: true }
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
// Create execution request
|
|
242
|
+
const request: ExecutionRequest = {
|
|
243
|
+
wasm: compiled,
|
|
244
|
+
entrypoint: options?.entrypoint,
|
|
245
|
+
args: options?.args,
|
|
246
|
+
input: options?.input,
|
|
247
|
+
state: this.kernelState,
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
// Execute
|
|
251
|
+
const result = await this.runtime.execute(request, {
|
|
252
|
+
permissions: this.permissions,
|
|
253
|
+
limits: this.limits,
|
|
254
|
+
env: this.env,
|
|
255
|
+
cwd: this.cwd,
|
|
256
|
+
signal: options?.signal,
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// Update state if successful
|
|
260
|
+
if (result.success && result.state) {
|
|
261
|
+
for (const [key, value] of result.state) {
|
|
262
|
+
this.kernelState.set(key, value);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Update exports
|
|
267
|
+
if (result.exports) {
|
|
268
|
+
for (const [key, value] of result.exports) {
|
|
269
|
+
this.exports.set(key, value);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Update stats
|
|
274
|
+
this.updateStats(result, Date.now() - startTime);
|
|
275
|
+
|
|
276
|
+
this.state = "ready";
|
|
277
|
+
return result;
|
|
278
|
+
} catch (error) {
|
|
279
|
+
this.state = "ready";
|
|
280
|
+
const result = this.createErrorResult(
|
|
281
|
+
error instanceof Error ? error.message : String(error),
|
|
282
|
+
"runtime"
|
|
283
|
+
);
|
|
284
|
+
this.updateStats(result, Date.now() - startTime);
|
|
285
|
+
return result;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Complete code at position (autocomplete)
|
|
291
|
+
*/
|
|
292
|
+
async complete(
|
|
293
|
+
code: string,
|
|
294
|
+
position: number
|
|
295
|
+
): Promise<CompletionResult> {
|
|
296
|
+
// Basic implementation - override in language-specific kernels
|
|
297
|
+
const beforeCursor = code.slice(0, position);
|
|
298
|
+
const match = beforeCursor.match(/(\w+)$/);
|
|
299
|
+
const prefix = match ? match[1] : "";
|
|
300
|
+
|
|
301
|
+
// Get completions from state
|
|
302
|
+
const matches: string[] = [];
|
|
303
|
+
|
|
304
|
+
for (const key of this.kernelState.keys()) {
|
|
305
|
+
if (key.startsWith(prefix)) {
|
|
306
|
+
matches.push(key);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
for (const key of this.exports.keys()) {
|
|
311
|
+
if (key.startsWith(prefix)) {
|
|
312
|
+
matches.push(key);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return {
|
|
317
|
+
matches,
|
|
318
|
+
cursorStart: position - prefix.length,
|
|
319
|
+
cursorEnd: position,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Inspect object at position
|
|
325
|
+
*/
|
|
326
|
+
async inspect(
|
|
327
|
+
code: string,
|
|
328
|
+
position: number
|
|
329
|
+
): Promise<InspectResult> {
|
|
330
|
+
// Basic implementation - override in language-specific kernels
|
|
331
|
+
const beforeCursor = code.slice(0, position);
|
|
332
|
+
const match = beforeCursor.match(/(\w+)$/);
|
|
333
|
+
const name = match ? match[1] : "";
|
|
334
|
+
|
|
335
|
+
if (!name) {
|
|
336
|
+
return { found: false };
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const value = this.kernelState.get(name) ?? this.exports.get(name);
|
|
340
|
+
|
|
341
|
+
if (value === undefined) {
|
|
342
|
+
return { found: false };
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return {
|
|
346
|
+
found: true,
|
|
347
|
+
details: {
|
|
348
|
+
type: typeof value,
|
|
349
|
+
documentation: undefined,
|
|
350
|
+
signature: undefined,
|
|
351
|
+
},
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Restart kernel (clear state)
|
|
357
|
+
*/
|
|
358
|
+
async restart(): Promise<void> {
|
|
359
|
+
this.kernelState.clear();
|
|
360
|
+
this.exports.clear();
|
|
361
|
+
this.state = "ready";
|
|
362
|
+
|
|
363
|
+
// Reset stats
|
|
364
|
+
this.stats = {
|
|
365
|
+
executions: 0,
|
|
366
|
+
successes: 0,
|
|
367
|
+
failures: 0,
|
|
368
|
+
totalTime: 0,
|
|
369
|
+
avgTime: 0,
|
|
370
|
+
memoryHighWater: 0,
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Shutdown kernel
|
|
376
|
+
*/
|
|
377
|
+
async shutdown(): Promise<void> {
|
|
378
|
+
this.state = "shutting_down";
|
|
379
|
+
|
|
380
|
+
try {
|
|
381
|
+
await this.runtime.terminate();
|
|
382
|
+
} catch {
|
|
383
|
+
// Ignore errors during shutdown
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
this.kernelState.clear();
|
|
387
|
+
this.exports.clear();
|
|
388
|
+
this.state = "dead";
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Interrupt current execution
|
|
393
|
+
*/
|
|
394
|
+
interrupt(): void {
|
|
395
|
+
// Override in implementations that support interruption
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Set environment variable
|
|
400
|
+
*/
|
|
401
|
+
setEnv(key: string, value: string): void {
|
|
402
|
+
this.env[key] = value;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Get environment variable
|
|
407
|
+
*/
|
|
408
|
+
getEnv(key: string): string | undefined {
|
|
409
|
+
return this.env[key];
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Update permissions
|
|
414
|
+
*/
|
|
415
|
+
setPermissions(permissions: Permissions): void {
|
|
416
|
+
this.permissions = permissions;
|
|
417
|
+
this.permissionChecker = new PermissionChecker(permissions);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Update limits
|
|
422
|
+
*/
|
|
423
|
+
setLimits(limits: Limits): void {
|
|
424
|
+
this.limits = limits;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Create error result
|
|
429
|
+
*/
|
|
430
|
+
private createErrorResult(
|
|
431
|
+
message: string,
|
|
432
|
+
type: "compile" | "runtime" | "permission" | "limit" | "timeout" | "cancel"
|
|
433
|
+
): ExecutionResult {
|
|
434
|
+
return {
|
|
435
|
+
success: false,
|
|
436
|
+
error: { message, type },
|
|
437
|
+
metrics: {
|
|
438
|
+
duration: 0,
|
|
439
|
+
memoryUsed: 0,
|
|
440
|
+
},
|
|
441
|
+
output: { stdout: [], stderr: [], displays: [] },
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Update statistics
|
|
447
|
+
*/
|
|
448
|
+
private updateStats(result: ExecutionResult, duration: number): void {
|
|
449
|
+
this.stats.executions++;
|
|
450
|
+
this.stats.totalTime += duration;
|
|
451
|
+
this.stats.avgTime = this.stats.totalTime / this.stats.executions;
|
|
452
|
+
this.stats.lastExecution = new Date();
|
|
453
|
+
|
|
454
|
+
if (result.success) {
|
|
455
|
+
this.stats.successes++;
|
|
456
|
+
} else {
|
|
457
|
+
this.stats.failures++;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
const memoryUsed = result.metrics.memoryUsed;
|
|
461
|
+
if (memoryUsed > this.stats.memoryHighWater) {
|
|
462
|
+
this.stats.memoryHighWater = memoryUsed;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Kernel Manager
|
|
469
|
+
*
|
|
470
|
+
* Manages multiple kernels across languages.
|
|
471
|
+
*/
|
|
472
|
+
export class KernelManager {
|
|
473
|
+
private kernels = new Map<string, BaseKernel>();
|
|
474
|
+
private languageKernels = new Map<Language, Set<string>>();
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Create and register a kernel
|
|
478
|
+
*/
|
|
479
|
+
async createKernel(options: KernelOptions): Promise<BaseKernel> {
|
|
480
|
+
const kernel = new BaseKernel(options);
|
|
481
|
+
await kernel.start();
|
|
482
|
+
|
|
483
|
+
this.kernels.set(kernel.getId(), kernel);
|
|
484
|
+
|
|
485
|
+
if (!this.languageKernels.has(options.language)) {
|
|
486
|
+
this.languageKernels.set(options.language, new Set());
|
|
487
|
+
}
|
|
488
|
+
this.languageKernels.get(options.language)!.add(kernel.getId());
|
|
489
|
+
|
|
490
|
+
return kernel;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Get kernel by ID
|
|
495
|
+
*/
|
|
496
|
+
getKernel(id: string): BaseKernel | undefined {
|
|
497
|
+
return this.kernels.get(id);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Get kernels by language
|
|
502
|
+
*/
|
|
503
|
+
getKernelsByLanguage(language: Language): BaseKernel[] {
|
|
504
|
+
const ids = this.languageKernels.get(language);
|
|
505
|
+
if (!ids) return [];
|
|
506
|
+
|
|
507
|
+
return Array.from(ids)
|
|
508
|
+
.map(id => this.kernels.get(id))
|
|
509
|
+
.filter((k): k is BaseKernel => k !== undefined);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Get all kernels
|
|
514
|
+
*/
|
|
515
|
+
getAllKernels(): BaseKernel[] {
|
|
516
|
+
return Array.from(this.kernels.values());
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Shutdown a kernel
|
|
521
|
+
*/
|
|
522
|
+
async shutdownKernel(id: string): Promise<void> {
|
|
523
|
+
const kernel = this.kernels.get(id);
|
|
524
|
+
if (!kernel) return;
|
|
525
|
+
|
|
526
|
+
await kernel.shutdown();
|
|
527
|
+
|
|
528
|
+
// Remove from language index
|
|
529
|
+
const langSet = this.languageKernels.get(kernel.language);
|
|
530
|
+
if (langSet) {
|
|
531
|
+
langSet.delete(id);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
this.kernels.delete(id);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Shutdown all kernels
|
|
539
|
+
*/
|
|
540
|
+
async shutdownAll(): Promise<void> {
|
|
541
|
+
const shutdowns = Array.from(this.kernels.keys()).map(id =>
|
|
542
|
+
this.shutdownKernel(id)
|
|
543
|
+
);
|
|
544
|
+
await Promise.all(shutdowns);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Get kernel count
|
|
549
|
+
*/
|
|
550
|
+
get count(): number {
|
|
551
|
+
return this.kernels.size;
|
|
552
|
+
}
|
|
553
|
+
}
|