@wasm-idle/terminal 1.0.0-next.0 → 1.0.0

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 CHANGED
@@ -22,3 +22,32 @@ pnpm add wasm-idle @wasm-idle/terminal svelte
22
22
 
23
23
  Compiler and language-runtime payloads are not included in this package. Configure their external
24
24
  URLs through the injected playground binding.
25
+
26
+ ## Stop lifecycle
27
+
28
+ `TerminalControl.stop()` does not resolve until the active sandbox's `kill()` or `terminate()`
29
+ operation resolves. Sandbox implementations may return either `void` or `Promise<void>` from those
30
+ methods; an asynchronous implementation must keep its promise pending until runtime resources are
31
+ released.
32
+
33
+ The C/C++ and Rust LLDB sandboxes use this contract to wait for both LLDB and WAMR worker teardown.
34
+ Callers can therefore await `stop()` before launching another debug session without overlapping the
35
+ previous session's workers or receiving its late events.
36
+
37
+ ## Interactive runs
38
+
39
+ Set `interactive: true` only for a run that remains under explicit user control and has a working
40
+ stop/dispose path. The shared execution boundary then omits the wall-clock deadline only for the
41
+ final `run(..., prepare = false)` call. Runtime loading and `prepare()` keep their configured
42
+ deadlines, and AbortSignal cancellation, output/diagnostic limits, exclusive sandbox ownership, and
43
+ teardown remain enforced. wasm-idle uses this contract for Debug runs, which may stay paused at a
44
+ breakpoint indefinitely; ordinary Run requests remain time-bounded.
45
+
46
+ ## Input generations
47
+
48
+ Input submitted while `prepare()` is still running remains queued for the matching `run()` when the
49
+ same language and runtime assets reuse that sandbox. `stop()`, `clear()`, `destroy()`, runtime
50
+ restart, component teardown, and a language or asset change discard queued input and EOF state
51
+ before retiring the sandbox. A later debug session therefore cannot consume stdin entered for an
52
+ older generation. Clipboard reads are asynchronous, so pasted text is accepted only if the input
53
+ generation that requested it is still current when the browser returns the clipboard contents.
@@ -1,12 +1,16 @@
1
1
  <script lang="ts">
2
2
  import {
3
+ RuntimeProgressController,
4
+ TimeoutError,
3
5
  createRuntimeAssetsKey,
4
- phaseProgress,
5
- progressBandsForLanguage,
6
6
  type DebugCommand,
7
- type DebugSessionEvent
7
+ type DebugDataBreakpoint,
8
+ type DebugDataBreakpointInfoArguments,
9
+ type DebugSessionEvent,
10
+ type ProgressLike
8
11
  } from '@wasm-idle/core';
9
12
  import { onMount } from 'svelte';
13
+ import { SvelteMap } from 'svelte/reactivity';
10
14
  import '@xterm/xterm/css/xterm.css';
11
15
  import type { Terminal as TerminalType } from '@xterm/xterm';
12
16
  import registerAllPlugins from './plugin/index.js';
@@ -55,7 +59,9 @@
55
59
  input = '',
56
60
  inputCursor = 0,
57
61
  pendingSandboxInput: string[] = [],
62
+ pendingDebugBreakpoints = new SvelteMap<string, number[]>(),
58
63
  pendingSandboxEof = false,
64
+ sandboxInputGeneration = 0,
59
65
  sandbox: BoundSandbox,
60
66
  sandboxAcceptingInput = false,
61
67
  first = true,
@@ -63,15 +69,91 @@
63
69
  plugin = $state(),
64
70
  ll: string | null = null,
65
71
  loadedRuntimeAssetsKey: string | undefined = undefined,
66
- stopRequested = false;
72
+ stopRequested = false,
73
+ progressLifecycleCounter = 0,
74
+ activeExecutionProgress: ProgressLike | undefined,
75
+ activeExecutionLanguage: string | undefined,
76
+ preparedExecution:
77
+ | {
78
+ key: string;
79
+ sandbox: BoundSandbox;
80
+ }
81
+ | undefined;
82
+ let preparedExecutionGeneration = 0;
83
+ let lastExecutionError: unknown;
84
+ const progressController = new RuntimeProgressController();
85
+ const terminalOutputReadinessLanguages = new Set([
86
+ 'C',
87
+ 'CPP',
88
+ 'OBJC',
89
+ 'RUST',
90
+ 'GO',
91
+ 'D',
92
+ 'CSHARP',
93
+ 'FSHARP',
94
+ 'VBNET',
95
+ 'FORTRAN',
96
+ 'COBOL',
97
+ 'OCAML',
98
+ 'HASKELL'
99
+ ]);
100
+
101
+ function clearPreparedExecution() {
102
+ preparedExecution = undefined;
103
+ }
104
+
105
+ function invalidatePreparedExecution() {
106
+ preparedExecutionGeneration += 1;
107
+ clearPreparedExecution();
108
+ return preparedExecutionGeneration;
109
+ }
67
110
 
68
- function writeTerminalOutput(text: string) {
111
+ function executionPreparationKey(
112
+ language: string,
113
+ code: string,
114
+ log: boolean,
115
+ args: string[],
116
+ options: TerminalExecutionOptions
117
+ ) {
118
+ try {
119
+ const keyOptions = { ...options };
120
+ delete keyOptions.signal;
121
+ return JSON.stringify([language, code, log, args, keyOptions]);
122
+ } catch {
123
+ return undefined;
124
+ }
125
+ }
126
+
127
+ function activityOnlyProgress(progress: ProgressLike | undefined) {
128
+ if (!progress) return undefined;
129
+ return {
130
+ set: progress.set,
131
+ report: (event: Parameters<NonNullable<ProgressLike['report']>>[0]) => {
132
+ if (event.kind === 'activity') progress.report?.(event);
133
+ }
134
+ } satisfies ProgressLike;
135
+ }
136
+
137
+ function writeTerminalOutput(text: string, executionOutput = false) {
69
138
  if (!text) return;
139
+ if (
140
+ executionOutput &&
141
+ activeExecutionLanguage &&
142
+ terminalOutputReadinessLanguages.has(activeExecutionLanguage)
143
+ ) {
144
+ activeExecutionProgress?.report?.({
145
+ kind: 'ready',
146
+ state: 'running',
147
+ reason: 'stdout',
148
+ label: 'Program output received'
149
+ });
150
+ }
70
151
  debugOutput += text;
71
152
  term?.write(text);
72
153
  }
73
154
 
74
155
  function wait() {
156
+ if (term) return Promise.resolve();
75
157
  return new Promise<void>((r) => {
76
158
  const i = setInterval(() => {
77
159
  if (term) {
@@ -91,7 +173,12 @@
91
173
  let _tc = ++tc;
92
174
  await wait();
93
175
  sandboxAcceptingInput = false;
94
- if (sandbox && requiresSandboxReset) await sandbox.clear();
176
+ if (requiresSandboxReset) clearPreparedExecution();
177
+ if (sandbox && requiresSandboxReset) {
178
+ discardPendingSandboxInput();
179
+ await sandbox.clear();
180
+ discardPendingSandboxInput();
181
+ }
95
182
  input = '';
96
183
  inputCursor = 0;
97
184
  finish = false;
@@ -102,10 +189,21 @@
102
189
  loadedRuntimeAssetsKey = currentRuntimeAssetsKey;
103
190
  }
104
191
  sandbox.image = onimage;
105
- sandbox.ondebug = ondebug;
192
+ sandbox.ondebug = (event) => {
193
+ if (event.type === 'pause') {
194
+ activeExecutionProgress?.report?.({
195
+ kind: 'ready',
196
+ state: 'paused',
197
+ reason: 'debug-paused',
198
+ label: 'Debugger paused'
199
+ });
200
+ }
201
+ ondebug?.(event);
202
+ };
106
203
  sandbox.oncompilerdiagnostic = oncompilediagnostic;
107
204
  sandbox.output = (output: string) =>
108
- _tc === tc && writeTerminalOutput(output.replaceAll('\n', '\r\n'));
205
+ _tc === tc && writeTerminalOutput(output.replaceAll('\n', '\r\n'), true);
206
+ return requiresSandboxReset;
109
207
  }
110
208
 
111
209
  function flushPendingSandboxInput() {
@@ -121,12 +219,33 @@
121
219
  }
122
220
  }
123
221
 
222
+ function discardPendingSandboxInput() {
223
+ sandboxInputGeneration += 1;
224
+ pendingSandboxInput = [];
225
+ pendingSandboxEof = false;
226
+ }
227
+
124
228
  function submitSandboxEof() {
125
229
  if (sandbox && sandboxAcceptingInput) sandbox.eof?.();
126
230
  else pendingSandboxEof = true;
127
231
  }
128
232
 
129
- function runSandbox<T>(pr: Promise<T>, reportFinish = true) {
233
+ function finishSandboxRun() {
234
+ sandboxAcceptingInput = false;
235
+ stopRequested = false;
236
+ onfinish?.();
237
+ finish = true;
238
+ if (term) term.options.cursorBlink = false;
239
+ }
240
+
241
+ function isTimeoutError(error: unknown) {
242
+ return (
243
+ error instanceof TimeoutError ||
244
+ (error instanceof Error && error.name === 'TimeoutError')
245
+ );
246
+ }
247
+
248
+ function runSandbox<T>(pr: Promise<T>, reportFinish = true, finalize = true) {
130
249
  return pr
131
250
  .then((x) => {
132
251
  if (reportFinish) {
@@ -137,19 +256,37 @@
137
256
  return x;
138
257
  })
139
258
  .catch((msg) => {
259
+ lastExecutionError = msg;
140
260
  if (stopRequested) return false;
261
+ if (isTimeoutError(msg)) {
262
+ writeTerminalOutput(`\r\n\x1B[1;3;31m${msg}\u001B[?25l`);
263
+ throw msg;
264
+ }
141
265
  writeTerminalOutput(`\r\n\x1B[1;3;31m${msg}\u001B[?25l`);
142
266
  return false;
143
267
  })
144
268
  .finally(() => {
145
- sandboxAcceptingInput = false;
146
- stopRequested = false;
147
- onfinish?.();
148
- finish = true;
149
- if (term) term.options.cursorBlink = false;
269
+ if (finalize) finishSandboxRun();
150
270
  });
151
271
  }
152
272
 
273
+ async function withProgressLifecycle<T>(
274
+ language: string,
275
+ progress: ProgressLike | undefined,
276
+ operation: (progress: ProgressLike | undefined) => Promise<T>
277
+ ) {
278
+ const lifecycle = progressController.begin(
279
+ `${language}:${++progressLifecycleCounter}`,
280
+ progress,
281
+ `Loading ${language} runtime`
282
+ );
283
+ try {
284
+ return await operation(lifecycle.progress);
285
+ } finally {
286
+ lifecycle.end();
287
+ }
288
+ }
289
+
153
290
  async function initTerm(blink = true) {
154
291
  await wait();
155
292
  if (!term) return;
@@ -242,8 +379,12 @@
242
379
  }
243
380
 
244
381
  const terminalControl: TerminalControl = {
382
+ getExecutionError: () => lastExecutionError,
245
383
  async clear() {
246
384
  await wait();
385
+ lastExecutionError = undefined;
386
+ invalidatePreparedExecution();
387
+ discardPendingSandboxInput();
247
388
  term?.reset();
248
389
  term?.write(`\u001B[?25l\x1b[0m\x1b[?25h`);
249
390
  if (term) term.options.cursorBlink = false;
@@ -251,90 +392,259 @@
251
392
  input = '';
252
393
  inputCursor = 0;
253
394
  sandboxAcceptingInput = false;
254
- pendingSandboxEof = false;
255
395
  first = true;
256
396
  await new Promise((r) => setTimeout(r, 100));
397
+ discardPendingSandboxInput();
257
398
  },
258
399
  async prepare(
259
400
  language: string,
260
401
  code: string,
261
402
  log = true,
262
- prog?: { set?: (value: number, stage?: string) => void },
403
+ prog?: ProgressLike,
263
404
  args: string[] = [],
264
405
  options: TerminalExecutionOptions = {}
265
406
  ) {
266
- prog?.set?.(0, `Loading ${language} runtime`);
267
- const progressBands = progressBandsForLanguage(language);
268
- const loadProgress = phaseProgress(
269
- prog,
270
- progressBands.load[0],
271
- progressBands.load[1],
272
- `Loading ${language} runtime`
273
- );
274
- const prepareProgress = phaseProgress(
275
- prog,
276
- progressBands.prepare[0],
277
- progressBands.prepare[1],
278
- `Preparing ${language} program`
279
- );
280
- await Promise.all([
281
- initSandbox(language).then(() =>
282
- sandbox.load(code, log, args, options, loadProgress)
283
- ),
284
- initTerm(false)
285
- ]);
286
- prepareProgress?.set?.(0, `Preparing ${language} program`);
287
- const prepared = !!(await runSandbox(
288
- sandbox.run(code, true, log, prepareProgress, args, options),
289
- false
290
- ));
291
- if (prepared) prepareProgress?.set?.(1, `${language} runtime ready`);
292
- return prepared;
407
+ return await withProgressLifecycle(language, prog, async (runProgress) => {
408
+ const preparationGeneration = invalidatePreparedExecution();
409
+ const prepareProgress = activityOnlyProgress(runProgress);
410
+ await Promise.all([
411
+ initSandbox(language).then(() =>
412
+ sandbox.load(code, log, args, options, prepareProgress)
413
+ ),
414
+ initTerm(false)
415
+ ]);
416
+ const preparationSandbox = sandbox;
417
+ runProgress?.report?.({
418
+ kind: 'activity',
419
+ phase: 'starting',
420
+ label: `Preparing ${language} program`
421
+ });
422
+ const prepared = !!(await runSandbox(
423
+ preparationSandbox.run(code, true, log, prepareProgress, args, options),
424
+ false
425
+ ));
426
+ const preparationKey = executionPreparationKey(language, code, log, args, options);
427
+ if (
428
+ prepared &&
429
+ preparationKey &&
430
+ preparationGeneration === preparedExecutionGeneration &&
431
+ preparationSandbox === sandbox
432
+ ) {
433
+ preparedExecution = { key: preparationKey, sandbox: preparationSandbox };
434
+ }
435
+ return prepared;
436
+ });
293
437
  },
294
438
  async run(
295
439
  language: string,
296
440
  code: string,
297
441
  log = true,
298
- prog?: { set?: (value: number, stage?: string) => void },
442
+ prog?: ProgressLike,
299
443
  args: string[] = [],
300
444
  options: TerminalExecutionOptions = {}
301
445
  ) {
302
- await Promise.all([
303
- initSandbox(language).then(() => sandbox.load(code, log, args, options, prog)),
304
- initTerm()
305
- ]);
306
- sandboxAcceptingInput = true;
307
- flushPendingSandboxInput();
308
- return await runSandbox(sandbox.run(code, false, log, prog, args, options));
446
+ return await withProgressLifecycle(language, prog, async (runProgress) => {
447
+ let executionRunWillFinalize = false;
448
+ const preparedCandidate = preparedExecution;
449
+ const executionGeneration = invalidatePreparedExecution();
450
+ pendingDebugBreakpoints.clear();
451
+ for (const { sourcePath, lines } of options.sourceBreakpoints || []) {
452
+ pendingDebugBreakpoints.set(sourcePath, [...lines]);
453
+ }
454
+ const [sandboxWasReset] = await Promise.all([
455
+ initSandbox(language).then(async (wasReset) => {
456
+ await sandbox.load(
457
+ code,
458
+ log,
459
+ args,
460
+ options,
461
+ activityOnlyProgress(runProgress)
462
+ );
463
+ return wasReset;
464
+ }),
465
+ initTerm()
466
+ ]);
467
+ const executionOptions = {
468
+ ...options,
469
+ sourceBreakpoints: Array.from(
470
+ pendingDebugBreakpoints,
471
+ ([sourcePath, lines]) => ({
472
+ sourcePath,
473
+ lines: [...lines]
474
+ })
475
+ )
476
+ };
477
+ const preparationKey = executionPreparationKey(language, code, log, args, options);
478
+ const mayUsePreparedOutput =
479
+ executionGeneration === preparedExecutionGeneration &&
480
+ !sandboxWasReset &&
481
+ !!preparationKey &&
482
+ preparedCandidate?.sandbox === sandbox &&
483
+ preparedCandidate.key === preparationKey;
484
+ try {
485
+ if (terminalOutputReadinessLanguages.has(language) && !mayUsePreparedOutput) {
486
+ const prepareProgress = activityOnlyProgress(runProgress);
487
+ runProgress?.report?.({
488
+ kind: 'activity',
489
+ phase: 'starting',
490
+ label: `Preparing ${language} program`
491
+ });
492
+ const prepared = !!(await runSandbox(
493
+ sandbox.run(code, true, log, prepareProgress, args, options),
494
+ false,
495
+ false
496
+ ));
497
+ if (!prepared) {
498
+ runProgress?.report?.({
499
+ kind: 'settled',
500
+ outcome: options.signal?.aborted ? 'cancelled' : 'failed',
501
+ label: `${language} run ended`
502
+ });
503
+ return false;
504
+ }
505
+ }
506
+
507
+ activeExecutionProgress = runProgress;
508
+ activeExecutionLanguage = language;
509
+ sandboxAcceptingInput = true;
510
+ flushPendingSandboxInput();
511
+ executionRunWillFinalize = true;
512
+ const result = await runSandbox(
513
+ sandbox.run(code, false, log, runProgress, args, executionOptions)
514
+ );
515
+ if (result === false) {
516
+ runProgress?.report?.({
517
+ kind: 'settled',
518
+ outcome: options.signal?.aborted ? 'cancelled' : 'failed',
519
+ label: `${language} run ended`
520
+ });
521
+ } else {
522
+ runProgress?.report?.({
523
+ kind: 'ready',
524
+ state: 'running',
525
+ reason: 'result',
526
+ label: `${language} run completed`
527
+ });
528
+ runProgress?.report?.({
529
+ kind: 'settled',
530
+ outcome: 'completed',
531
+ label: `${language} run completed`
532
+ });
533
+ }
534
+ return result;
535
+ } catch (error) {
536
+ if (isTimeoutError(error)) {
537
+ runProgress?.report?.({
538
+ kind: 'settled',
539
+ outcome: 'timed-out',
540
+ label: `${language} run timed out`
541
+ });
542
+ }
543
+ throw error;
544
+ } finally {
545
+ if (!executionRunWillFinalize) finishSandboxRun();
546
+ if (activeExecutionProgress === runProgress) {
547
+ activeExecutionProgress = undefined;
548
+ activeExecutionLanguage = undefined;
549
+ }
550
+ }
551
+ });
309
552
  },
310
553
  async destroy() {
311
554
  await wait();
555
+ progressController.invalidate();
556
+ invalidatePreparedExecution();
312
557
  sandboxAcceptingInput = false;
313
- pendingSandboxEof = false;
558
+ discardPendingSandboxInput();
314
559
  term?.dispose();
315
560
  if (sandbox) await sandbox.clear();
561
+ discardPendingSandboxInput();
562
+ },
563
+ async restartRuntime() {
564
+ await wait();
565
+ if (!sandbox) return;
566
+ progressController.invalidate();
567
+ invalidatePreparedExecution();
568
+ sandboxAcceptingInput = false;
569
+ discardPendingSandboxInput();
570
+ input = '';
571
+ inputCursor = 0;
572
+ finish = true;
573
+ stopRequested = false;
574
+ tc += 1;
575
+ if (sandbox.restart) await sandbox.restart();
576
+ else await sandbox.clear();
577
+ discardPendingSandboxInput();
316
578
  },
317
579
  async stop() {
318
580
  await wait();
581
+ progressController.invalidate();
582
+ invalidatePreparedExecution();
319
583
  stopRequested = true;
320
584
  finish = true;
321
585
  sandboxAcceptingInput = false;
322
- pendingSandboxEof = false;
323
- if (sandbox?.kill) sandbox.kill();
324
- else sandbox?.terminate?.();
586
+ discardPendingSandboxInput();
587
+ if (sandbox?.kill) await sandbox.kill();
588
+ else await sandbox?.terminate?.();
589
+ discardPendingSandboxInput();
325
590
  },
326
591
  async debugCommand(command: DebugCommand) {
327
592
  await wait();
328
- sandbox.debugCommand?.(command);
593
+ await sandbox.debugCommand?.(command);
594
+ },
595
+ async debugPause() {
596
+ await wait();
597
+ await sandbox.debugPause?.();
329
598
  },
330
- async setBreakpoints(lines: number[]) {
599
+ async setBreakpoints(lines: number[], sourcePath?: string) {
600
+ pendingDebugBreakpoints.set(sourcePath || '', [...lines]);
331
601
  await wait();
332
- sandbox?.setBreakpoints?.(lines);
602
+ await sandbox?.setBreakpoints?.(lines, sourcePath);
333
603
  },
334
604
  async debugEvaluate(expression: string) {
335
605
  await wait();
336
606
  return (await sandbox.debugEvaluate?.(expression)) || '?';
337
607
  },
608
+ async debugVariables(variablesReference: number, start?: number, count?: number) {
609
+ await wait();
610
+ return (await sandbox.debugVariables?.(variablesReference, start, count)) || [];
611
+ },
612
+ async debugScopes(frameId: number) {
613
+ await wait();
614
+ return (await sandbox.debugScopes?.(frameId)) ?? [];
615
+ },
616
+ async debugFrameScopes(frameId: number) {
617
+ await wait();
618
+ return (await sandbox.debugFrameScopes?.(frameId)) ?? [];
619
+ },
620
+ async debugFrameName(frameId: number) {
621
+ await wait();
622
+ return (await sandbox.debugFrameName?.(frameId)) ?? null;
623
+ },
624
+ async debugReadMemory(memoryReference: string, offset: number, count: number) {
625
+ await wait();
626
+ return (await sandbox.debugReadMemory?.(memoryReference, offset, count)) ?? null;
627
+ },
628
+ async debugWriteMemory(
629
+ memoryReference: string,
630
+ offset: number,
631
+ data: Uint8Array,
632
+ allowPartial?: boolean
633
+ ) {
634
+ await wait();
635
+ return (
636
+ (await sandbox.debugWriteMemory?.(memoryReference, offset, data, allowPartial)) ??
637
+ null
638
+ );
639
+ },
640
+ async debugDataBreakpointInfo(arguments_: DebugDataBreakpointInfoArguments) {
641
+ await wait();
642
+ return (await sandbox.debugDataBreakpointInfo?.(arguments_)) ?? null;
643
+ },
644
+ async debugSetDataBreakpoints(breakpoints: DebugDataBreakpoint[]) {
645
+ await wait();
646
+ return (await sandbox.debugSetDataBreakpoints?.(breakpoints)) ?? [];
647
+ },
338
648
  async waitForInput() {
339
649
  await waitForInput();
340
650
  },
@@ -477,9 +787,14 @@
477
787
  submitSandboxEof();
478
788
  } else if ((ev.ctrlKey || ev.metaKey) && ev.key.toLowerCase() === 'v') {
479
789
  ev.preventDefault();
480
- navigator.clipboard.readText().then((text) => {
481
- applyPastedText(text);
482
- });
790
+ const generation = sandboxInputGeneration;
791
+ navigator.clipboard
792
+ .readText()
793
+ .then((text) => {
794
+ if (generation !== sandboxInputGeneration) return;
795
+ applyPastedText(text);
796
+ })
797
+ .catch(() => {});
483
798
  }
484
799
  });
485
800
  plugin = await registerAllPlugins(term);
@@ -488,8 +803,12 @@
488
803
  });
489
804
 
490
805
  return async () => {
806
+ progressController.invalidate();
807
+ invalidatePreparedExecution();
808
+ discardPendingSandboxInput();
491
809
  term?.dispose();
492
810
  if (sandbox) await sandbox.clear();
811
+ discardPendingSandboxInput();
493
812
  };
494
813
  });
495
814
  </script>
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import Terminal from './Terminal.svelte';
2
2
  import registerAllPlugins from './plugin/index.js';
3
3
  import Theme from './theme.js';
4
- import type { BoundSandbox, CompilerDiagnostic, CompilerDiagnosticSeverity, DebugCommand, DebugFrame, DebugSessionEvent, DebugVariable, PlaygroundBinding, SandboxExecutionOptions, TerminalControl, TerminalExecutionOptions } from './types.js';
4
+ import type { BoundSandbox, CompilerDiagnostic, CompilerDiagnosticSeverity, DebugCommand, DebugFrame, DebugMemory, DebugSessionEvent, DebugVariable, DebugWriteMemoryResult, PlaygroundBinding, SandboxExecutionOptions, TerminalControl, TerminalExecutionOptions } from './types.js';
5
5
  export { Terminal, Theme, registerAllPlugins };
6
- export type { BoundSandbox, CompilerDiagnostic, CompilerDiagnosticSeverity, DebugCommand, DebugFrame, DebugSessionEvent, DebugVariable, PlaygroundBinding, SandboxExecutionOptions, TerminalControl, TerminalExecutionOptions };
6
+ export type { BoundSandbox, CompilerDiagnostic, CompilerDiagnosticSeverity, DebugCommand, DebugFrame, DebugMemory, DebugSessionEvent, DebugVariable, DebugWriteMemoryResult, PlaygroundBinding, SandboxExecutionOptions, TerminalControl, TerminalExecutionOptions };
7
7
  export default Terminal;
package/dist/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { BoundSandbox as CoreBoundSandbox, DebugCommand, PlaygroundBinding as CorePlaygroundBinding, ProgressLike, SandboxExecutionOptions as CoreSandboxExecutionOptions, TerminalControl as CoreTerminalControl } from '@wasm-idle/core';
1
+ import type { BoundSandbox as CoreBoundSandbox, DebugCommand, DebugSourceBreakpoints, PlaygroundBinding as CorePlaygroundBinding, ProgressLike, SandboxExecutionOptions as CoreSandboxExecutionOptions, TerminalControl as CoreTerminalControl } from '@wasm-idle/core';
2
2
  export type CompilerDiagnosticSeverity = 'error' | 'warning' | 'other';
3
3
  export interface CompilerDiagnostic {
4
4
  fileName?: string | null;
@@ -9,6 +9,7 @@ export interface CompilerDiagnostic {
9
9
  message: string;
10
10
  }
11
11
  export type RustTargetTriple = 'wasm32-wasip1' | 'wasm32-wasip2' | 'wasm32-wasip3';
12
+ export type BrowserDebugMode = 'none' | 'trace' | 'lldb';
12
13
  export type GoTarget = 'wasip1/wasm' | 'wasip2/wasm' | 'wasip3/wasm' | 'js/wasm';
13
14
  export type TinyGoTarget = 'wasm' | 'wasip1' | 'wasip2' | 'wasip3';
14
15
  export type OcamlBackend = 'js' | 'wasm';
@@ -19,10 +20,16 @@ export interface SandboxWorkspaceFile {
19
20
  content: string;
20
21
  }
21
22
  export interface SandboxExecutionOptions {
23
+ debugMode?: BrowserDebugMode;
24
+ /** @deprecated Use debugMode. */
22
25
  debug?: boolean;
26
+ /** Keep the final run alive until the host explicitly stops or disposes it. */
27
+ interactive?: boolean;
23
28
  breakpoints?: number[];
29
+ sourceBreakpoints?: DebugSourceBreakpoints[];
24
30
  pauseOnEntry?: boolean;
25
31
  stdin?: string;
32
+ signal?: AbortSignal;
26
33
  activePath?: string;
27
34
  debugPath?: string;
28
35
  workspaceFiles?: SandboxWorkspaceFile[];
@@ -47,8 +54,10 @@ export interface PlaygroundBinding extends Pick<CorePlaygroundBinding, 'runtimeA
47
54
  load: (language: string) => Promise<BoundSandbox>;
48
55
  }
49
56
  export interface TerminalControl extends Omit<CoreTerminalControl, 'prepare' | 'run' | 'debugCommand'> {
57
+ /** The original failure when the compatibility runner resolves false. */
58
+ getExecutionError?: () => unknown;
50
59
  prepare: (language: string, code: string, log?: boolean, progress?: ProgressLike, args?: string[], options?: TerminalExecutionOptions) => Promise<boolean>;
51
60
  run: (language: string, code: string, log?: boolean, progress?: ProgressLike, args?: string[], options?: TerminalExecutionOptions) => Promise<boolean | string>;
52
61
  debugCommand: (command: DebugCommand) => Promise<void>;
53
62
  }
54
- export type { DebugCommand, DebugFrame, DebugSessionEvent, DebugVariable, ProgressLike } from '@wasm-idle/core';
63
+ export type { DebugCommand, DebugFrame, DebugMemory, DebugResolvedBreakpoint, DebugSessionEvent, DebugScope, DebugVariable, DebugWriteMemoryResult, ProgressLike } from '@wasm-idle/core';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wasm-idle/terminal",
3
- "version": "1.0.0-next.0",
3
+ "version": "1.0.0",
4
4
  "description": "Svelte terminal component for wasm-idle playground bindings",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -19,10 +19,10 @@
19
19
  ],
20
20
  "publishConfig": {
21
21
  "access": "public",
22
- "tag": "next"
22
+ "tag": "latest"
23
23
  },
24
24
  "peerDependencies": {
25
- "@wasm-idle/core": "1.0.0-next.0",
25
+ "@wasm-idle/core": "1.0.0",
26
26
  "svelte": "^5.0.0"
27
27
  },
28
28
  "dependencies": {
@@ -33,7 +33,7 @@
33
33
  "@xterm/addon-web-links": "^0.12.0",
34
34
  "@xterm/addon-webgl": "^0.19.0",
35
35
  "@xterm/xterm": "^6.0.0",
36
- "@wasm-idle/core": "1.0.0-next.0"
36
+ "@wasm-idle/core": "1.0.0"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@sveltejs/package": "^2.5.7",