@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.
Files changed (108) hide show
  1. package/dist/compilers/index.d.ts +24 -0
  2. package/dist/compilers/index.d.ts.map +1 -0
  3. package/dist/compilers/index.js +42 -0
  4. package/dist/compilers/index.js.map +1 -0
  5. package/dist/compilers/javascript.d.ts +117 -0
  6. package/dist/compilers/javascript.d.ts.map +1 -0
  7. package/dist/compilers/javascript.js +462 -0
  8. package/dist/compilers/javascript.js.map +1 -0
  9. package/dist/compilers/python.d.ts +140 -0
  10. package/dist/compilers/python.d.ts.map +1 -0
  11. package/dist/compilers/python.js +650 -0
  12. package/dist/compilers/python.js.map +1 -0
  13. package/dist/compilers/typescript.d.ts +99 -0
  14. package/dist/compilers/typescript.d.ts.map +1 -0
  15. package/dist/compilers/typescript.js +323 -0
  16. package/dist/compilers/typescript.js.map +1 -0
  17. package/dist/core/cell.d.ts +160 -0
  18. package/dist/core/cell.d.ts.map +1 -0
  19. package/dist/core/cell.js +319 -0
  20. package/dist/core/cell.js.map +1 -0
  21. package/dist/core/compiler.d.ts +126 -0
  22. package/dist/core/compiler.d.ts.map +1 -0
  23. package/dist/core/compiler.js +123 -0
  24. package/dist/core/compiler.js.map +1 -0
  25. package/dist/core/index.d.ts +19 -0
  26. package/dist/core/index.d.ts.map +1 -0
  27. package/dist/core/index.js +14 -0
  28. package/dist/core/index.js.map +1 -0
  29. package/dist/core/limits.d.ts +173 -0
  30. package/dist/core/limits.d.ts.map +1 -0
  31. package/dist/core/limits.js +440 -0
  32. package/dist/core/limits.js.map +1 -0
  33. package/dist/core/permissions.d.ts +103 -0
  34. package/dist/core/permissions.d.ts.map +1 -0
  35. package/dist/core/permissions.js +341 -0
  36. package/dist/core/permissions.js.map +1 -0
  37. package/dist/core/runtime.d.ts +127 -0
  38. package/dist/core/runtime.d.ts.map +1 -0
  39. package/dist/core/runtime.js +325 -0
  40. package/dist/core/runtime.js.map +1 -0
  41. package/dist/core/types.d.ts +380 -0
  42. package/dist/core/types.d.ts.map +1 -0
  43. package/dist/core/types.js +67 -0
  44. package/dist/core/types.js.map +1 -0
  45. package/dist/index.d.ts +145 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +279 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/multi/index.d.ts +9 -0
  50. package/dist/multi/index.d.ts.map +1 -0
  51. package/dist/multi/index.js +7 -0
  52. package/dist/multi/index.js.map +1 -0
  53. package/dist/multi/polyglot.d.ts +179 -0
  54. package/dist/multi/polyglot.d.ts.map +1 -0
  55. package/dist/multi/polyglot.js +319 -0
  56. package/dist/multi/polyglot.js.map +1 -0
  57. package/dist/runtimes/docker.d.ts +97 -0
  58. package/dist/runtimes/docker.d.ts.map +1 -0
  59. package/dist/runtimes/docker.js +368 -0
  60. package/dist/runtimes/docker.js.map +1 -0
  61. package/dist/runtimes/index.d.ts +11 -0
  62. package/dist/runtimes/index.d.ts.map +1 -0
  63. package/dist/runtimes/index.js +9 -0
  64. package/dist/runtimes/index.js.map +1 -0
  65. package/dist/runtimes/process.d.ts +47 -0
  66. package/dist/runtimes/process.d.ts.map +1 -0
  67. package/dist/runtimes/process.js +230 -0
  68. package/dist/runtimes/process.js.map +1 -0
  69. package/dist/session/index.d.ts +12 -0
  70. package/dist/session/index.d.ts.map +1 -0
  71. package/dist/session/index.js +9 -0
  72. package/dist/session/index.js.map +1 -0
  73. package/dist/session/kernel.d.ts +199 -0
  74. package/dist/session/kernel.d.ts.map +1 -0
  75. package/dist/session/kernel.js +400 -0
  76. package/dist/session/kernel.js.map +1 -0
  77. package/dist/session/notebook.d.ts +168 -0
  78. package/dist/session/notebook.d.ts.map +1 -0
  79. package/dist/session/notebook.js +499 -0
  80. package/dist/session/notebook.js.map +1 -0
  81. package/dist/session/repl.d.ts +159 -0
  82. package/dist/session/repl.d.ts.map +1 -0
  83. package/dist/session/repl.js +409 -0
  84. package/dist/session/repl.js.map +1 -0
  85. package/package.json +142 -0
  86. package/src/compilers/index.ts +80 -0
  87. package/src/compilers/javascript.ts +571 -0
  88. package/src/compilers/python.ts +785 -0
  89. package/src/compilers/typescript.ts +442 -0
  90. package/src/core/cell.ts +439 -0
  91. package/src/core/compiler.ts +250 -0
  92. package/src/core/index.ts +123 -0
  93. package/src/core/limits.ts +508 -0
  94. package/src/core/permissions.ts +409 -0
  95. package/src/core/runtime.ts +499 -0
  96. package/src/core/types.ts +528 -0
  97. package/src/global.d.ts +59 -0
  98. package/src/index.ts +515 -0
  99. package/src/multi/index.ts +22 -0
  100. package/src/multi/polyglot.ts +461 -0
  101. package/src/runtimes/docker.ts +501 -0
  102. package/src/runtimes/index.ts +21 -0
  103. package/src/runtimes/process.ts +316 -0
  104. package/src/session/index.ts +41 -0
  105. package/src/session/kernel.ts +553 -0
  106. package/src/session/notebook.ts +635 -0
  107. package/src/session/repl.ts +521 -0
  108. 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
+ }