sandlot 0.1.3 → 0.2.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.
Files changed (115) hide show
  1. package/dist/browser/bundler.d.ts +68 -0
  2. package/dist/browser/bundler.d.ts.map +1 -0
  3. package/dist/browser/executor.d.ts +46 -0
  4. package/dist/browser/executor.d.ts.map +1 -0
  5. package/dist/browser/index.d.ts +9 -0
  6. package/dist/browser/index.d.ts.map +1 -0
  7. package/dist/browser/index.js +2692 -0
  8. package/dist/browser/preset.d.ts +63 -0
  9. package/dist/browser/preset.d.ts.map +1 -0
  10. package/dist/commands/index.d.ts +20 -11
  11. package/dist/commands/index.d.ts.map +1 -1
  12. package/dist/commands/types.d.ts +31 -132
  13. package/dist/commands/types.d.ts.map +1 -1
  14. package/dist/core/bundler-utils.d.ts +142 -0
  15. package/dist/core/bundler-utils.d.ts.map +1 -0
  16. package/dist/core/esm-types-resolver.d.ts +125 -0
  17. package/dist/core/esm-types-resolver.d.ts.map +1 -0
  18. package/dist/core/executor.d.ts +35 -0
  19. package/dist/core/executor.d.ts.map +1 -0
  20. package/dist/{fs.d.ts → core/fs.d.ts} +27 -29
  21. package/dist/core/fs.d.ts.map +1 -0
  22. package/dist/core/sandbox.d.ts +30 -0
  23. package/dist/core/sandbox.d.ts.map +1 -0
  24. package/dist/core/sandlot.d.ts +30 -0
  25. package/dist/core/sandlot.d.ts.map +1 -0
  26. package/dist/core/shared-module-registry.d.ts +46 -0
  27. package/dist/core/shared-module-registry.d.ts.map +1 -0
  28. package/dist/core/typechecker.d.ts +60 -0
  29. package/dist/core/typechecker.d.ts.map +1 -0
  30. package/dist/index.d.ts +11 -16
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +1405 -2049
  33. package/dist/node/bundler.d.ts +48 -0
  34. package/dist/node/bundler.d.ts.map +1 -0
  35. package/dist/node/executor.d.ts +48 -0
  36. package/dist/node/executor.d.ts.map +1 -0
  37. package/dist/node/index.d.ts +9 -0
  38. package/dist/node/index.d.ts.map +1 -0
  39. package/dist/node/index.js +2646 -0
  40. package/dist/node/preset.d.ts +62 -0
  41. package/dist/node/preset.d.ts.map +1 -0
  42. package/dist/types.d.ts +525 -0
  43. package/dist/types.d.ts.map +1 -0
  44. package/package.json +27 -8
  45. package/src/browser/bundler.ts +294 -0
  46. package/src/browser/executor.ts +71 -0
  47. package/src/browser/index.ts +57 -0
  48. package/src/browser/preset.ts +179 -0
  49. package/src/commands/index.ts +526 -43
  50. package/src/commands/types.ts +82 -146
  51. package/src/core/bundler-utils.ts +630 -0
  52. package/src/core/esm-types-resolver.ts +432 -0
  53. package/src/core/executor.ts +161 -0
  54. package/src/{fs.ts → core/fs.ts} +59 -37
  55. package/src/core/sandbox.ts +621 -0
  56. package/src/core/sandlot.ts +77 -0
  57. package/src/core/shared-module-registry.ts +138 -0
  58. package/src/core/typechecker.ts +607 -0
  59. package/src/index.ts +104 -139
  60. package/src/node/bundler.ts +194 -0
  61. package/src/node/executor.ts +87 -0
  62. package/src/node/index.ts +39 -0
  63. package/src/node/preset.ts +178 -0
  64. package/src/types.ts +668 -0
  65. package/README.md +0 -243
  66. package/dist/build-emitter.d.ts +0 -47
  67. package/dist/build-emitter.d.ts.map +0 -1
  68. package/dist/builder.d.ts +0 -370
  69. package/dist/builder.d.ts.map +0 -1
  70. package/dist/bundler.d.ts +0 -148
  71. package/dist/bundler.d.ts.map +0 -1
  72. package/dist/commands/compile.d.ts +0 -13
  73. package/dist/commands/compile.d.ts.map +0 -1
  74. package/dist/commands/packages.d.ts +0 -17
  75. package/dist/commands/packages.d.ts.map +0 -1
  76. package/dist/commands/run.d.ts +0 -40
  77. package/dist/commands/run.d.ts.map +0 -1
  78. package/dist/commands.d.ts +0 -179
  79. package/dist/commands.d.ts.map +0 -1
  80. package/dist/fs.d.ts.map +0 -1
  81. package/dist/internal.d.ts +0 -79
  82. package/dist/internal.d.ts.map +0 -1
  83. package/dist/internal.js +0 -1976
  84. package/dist/loader.d.ts +0 -164
  85. package/dist/loader.d.ts.map +0 -1
  86. package/dist/packages.d.ts +0 -199
  87. package/dist/packages.d.ts.map +0 -1
  88. package/dist/runner.d.ts +0 -314
  89. package/dist/runner.d.ts.map +0 -1
  90. package/dist/sandbox-manager.d.ts +0 -261
  91. package/dist/sandbox-manager.d.ts.map +0 -1
  92. package/dist/sandbox.d.ts +0 -267
  93. package/dist/sandbox.d.ts.map +0 -1
  94. package/dist/shared-modules.d.ts +0 -148
  95. package/dist/shared-modules.d.ts.map +0 -1
  96. package/dist/shared-resources.d.ts +0 -102
  97. package/dist/shared-resources.d.ts.map +0 -1
  98. package/dist/ts-libs.d.ts +0 -98
  99. package/dist/ts-libs.d.ts.map +0 -1
  100. package/dist/typechecker.d.ts +0 -127
  101. package/dist/typechecker.d.ts.map +0 -1
  102. package/src/build-emitter.ts +0 -64
  103. package/src/builder.ts +0 -498
  104. package/src/bundler.ts +0 -542
  105. package/src/commands/compile.ts +0 -236
  106. package/src/commands/packages.ts +0 -154
  107. package/src/commands/run.ts +0 -245
  108. package/src/internal.ts +0 -119
  109. package/src/loader.ts +0 -229
  110. package/src/packages.ts +0 -936
  111. package/src/sandbox.ts +0 -396
  112. package/src/shared-modules.ts +0 -280
  113. package/src/shared-resources.ts +0 -166
  114. package/src/ts-libs.ts +0 -320
  115. package/src/typechecker.ts +0 -635
@@ -1,51 +1,534 @@
1
1
  /**
2
- * Command factories for sandbox bash environments.
2
+ * Command factories for v2 sandbox bash environments.
3
3
  *
4
- * Pure factories that create commands for type checking, bundling,
5
- * package management, and code execution.
6
- * No global state - all dependencies are passed in explicitly.
4
+ * Provides a `sandlot` command with subcommands:
5
+ * - sandlot build Build the project
6
+ * - sandlot typecheck Type check without building
7
+ * - sandlot install Install packages
8
+ * - sandlot uninstall Remove packages
9
+ * - sandlot help Show help
7
10
  */
8
11
 
9
- // Types and utilities
10
- export {
11
- type CommandDeps,
12
- type BuildOutput,
13
- type ValidateFn,
14
- type RunContext,
15
- type RunOptions,
16
- type RunResult,
17
- formatEsbuildMessages,
18
- } from "./types";
19
-
20
- // Compile commands (tsc, build)
21
- export { createTscCommand, createBuildCommand } from "./compile";
22
-
23
- // Package management commands (install, uninstall, list)
24
- export {
25
- createInstallCommand,
26
- createUninstallCommand,
27
- createListCommand,
28
- } from "./packages";
29
-
30
- // Run command
31
- export { createRunCommand } from "./run";
32
-
33
- // Re-import for createDefaultCommands
34
- import type { CommandDeps } from "./types";
35
- import { createTscCommand, createBuildCommand } from "./compile";
36
- import { createInstallCommand, createUninstallCommand, createListCommand } from "./packages";
37
- import { createRunCommand } from "./run";
12
+ import { defineCommand, type CommandContext } from "just-bash/browser";
13
+ import type { SandboxRef } from "./types";
14
+ export type { SandboxRef } from "./types";
15
+ export { formatSize, formatDiagnostics, formatBundleErrors } from "./types";
38
16
 
39
17
  /**
40
- * Create all default sandbox commands
18
+ * Create the main `sandlot` command with all subcommands.
19
+ *
20
+ * The sandlot command is a dispatcher that routes to subcommand handlers.
21
+ */
22
+ export function createSandlotCommand(sandboxRef: SandboxRef) {
23
+ return defineCommand("sandlot", async (args, ctx: CommandContext) => {
24
+ const subcommand = args[0];
25
+
26
+ // No subcommand or help
27
+ if (!subcommand || subcommand === "help" || subcommand === "--help" || subcommand === "-h") {
28
+ return showHelp();
29
+ }
30
+
31
+ // Dispatch to subcommand handlers
32
+ switch (subcommand) {
33
+ case "build":
34
+ return handleBuild(sandboxRef, args.slice(1));
35
+
36
+ case "typecheck":
37
+ case "tsc":
38
+ return handleTypecheck(sandboxRef, args.slice(1));
39
+
40
+ case "install":
41
+ case "add":
42
+ case "i":
43
+ return handleInstall(sandboxRef, args.slice(1));
44
+
45
+ case "uninstall":
46
+ case "remove":
47
+ case "rm":
48
+ return handleUninstall(sandboxRef, args.slice(1));
49
+
50
+ case "run":
51
+ return handleRun(sandboxRef, args.slice(1));
52
+
53
+ default:
54
+ return {
55
+ stdout: "",
56
+ stderr: `Unknown command: sandlot ${subcommand}\n\nRun 'sandlot help' for available commands.\n`,
57
+ exitCode: 1,
58
+ };
59
+ }
60
+ });
61
+ }
62
+
63
+ // =============================================================================
64
+ // Help
65
+ // =============================================================================
66
+
67
+ function showHelp() {
68
+ return {
69
+ stdout: `sandlot - In-browser TypeScript sandbox
70
+
71
+ Usage: sandlot <command> [options]
72
+
73
+ Commands:
74
+ build Build the project (typecheck, bundle)
75
+ run Build and execute code
76
+ typecheck Type check without building (alias: tsc)
77
+ install Install packages (aliases: add, i)
78
+ uninstall Remove packages (aliases: remove, rm)
79
+ help Show this help message
80
+
81
+ Run 'sandlot <command> --help' for command-specific options.
82
+
83
+ Examples:
84
+ sandlot build
85
+ sandlot run
86
+ sandlot run --skip-typecheck --timeout 5000
87
+ sandlot install react react-dom
88
+ sandlot typecheck
89
+ `,
90
+ stderr: "",
91
+ exitCode: 0,
92
+ };
93
+ }
94
+
95
+ // =============================================================================
96
+ // Build
97
+ // =============================================================================
98
+
99
+ import { formatSize, formatDiagnostics, formatBundleErrors } from "./types";
100
+
101
+ async function handleBuild(sandboxRef: SandboxRef, args: (string | undefined)[]) {
102
+ let entryPoint: string | undefined;
103
+ let skipTypecheck = false;
104
+ let minify = false;
105
+ let format: "esm" | "iife" | "cjs" = "esm";
106
+
107
+ for (let i = 0; i < args.length; i++) {
108
+ const arg = args[i];
109
+ if (arg === "--skip-typecheck" || arg === "-s") {
110
+ skipTypecheck = true;
111
+ } else if (arg === "--minify" || arg === "-m") {
112
+ minify = true;
113
+ } else if ((arg === "--format" || arg === "-f") && args[i + 1]) {
114
+ const f = args[++i]!.toLowerCase();
115
+ if (f === "esm" || f === "iife" || f === "cjs") {
116
+ format = f;
117
+ }
118
+ } else if ((arg === "--entry" || arg === "-e") && args[i + 1]) {
119
+ entryPoint = args[++i];
120
+ } else if (arg === "--help" || arg === "-h") {
121
+ return {
122
+ stdout: `Usage: sandlot build [options]
123
+
124
+ Options:
125
+ --entry, -e <path> Entry point (default: from package.json main)
126
+ --skip-typecheck, -s Skip type checking
127
+ --minify, -m Minify output
128
+ --format, -f <fmt> Output format (esm|iife|cjs)
129
+ --help, -h Show this help message
130
+
131
+ Examples:
132
+ sandlot build
133
+ sandlot build --entry /src/main.ts
134
+ sandlot build --skip-typecheck --minify
135
+ `,
136
+ stderr: "",
137
+ exitCode: 0,
138
+ };
139
+ } else if (arg && !arg.startsWith("-") && !entryPoint) {
140
+ entryPoint = arg;
141
+ }
142
+ }
143
+
144
+ const result = await sandboxRef.build({
145
+ entryPoint,
146
+ skipTypecheck,
147
+ minify,
148
+ format,
149
+ });
150
+
151
+ // Handle build failure
152
+ if (!result.success) {
153
+ let stderr = `Build failed`;
154
+
155
+ switch (result.phase) {
156
+ case "entry":
157
+ stderr = `Build failed: ${result.message}\n`;
158
+ break;
159
+
160
+ case "typecheck":
161
+ if (result.diagnostics) {
162
+ const errors = result.diagnostics.filter((d) => d.severity === "error");
163
+ stderr = `Build failed: Type check errors\n\n${formatDiagnostics(errors)}\n`;
164
+ } else {
165
+ stderr = `Build failed: Type check errors\n`;
166
+ }
167
+ break;
168
+
169
+ case "bundle":
170
+ if (result.bundleErrors && result.bundleErrors.length > 0) {
171
+ stderr = `Build failed: Bundle errors\n\n${formatBundleErrors(result.bundleErrors)}\n`;
172
+ } else {
173
+ stderr = `Build failed: Bundle error\n`;
174
+ }
175
+ break;
176
+
177
+ default:
178
+ stderr = `Build failed: Unknown error\n`;
179
+ }
180
+
181
+ return {
182
+ stdout: "",
183
+ stderr,
184
+ exitCode: 1,
185
+ };
186
+ }
187
+
188
+ // Build succeeded
189
+ let output = `Build successful!\n`;
190
+ output += `Size: ${formatSize(result.code.length)}\n`;
191
+ output += `Files: ${result.includedFiles.length}\n`;
192
+
193
+ if (result.warnings.length > 0) {
194
+ output += `\nWarnings:\n`;
195
+ for (const warning of result.warnings) {
196
+ if (warning.location) {
197
+ output += ` ${warning.location.file}:${warning.location.line}: ${warning.text}\n`;
198
+ } else {
199
+ output += ` ${warning.text}\n`;
200
+ }
201
+ }
202
+ }
203
+
204
+ return {
205
+ stdout: output,
206
+ stderr: "",
207
+ exitCode: 0,
208
+ };
209
+ }
210
+
211
+ // =============================================================================
212
+ // Typecheck
213
+ // =============================================================================
214
+
215
+ async function handleTypecheck(sandboxRef: SandboxRef, args: (string | undefined)[]) {
216
+ let entryPoint: string | undefined;
217
+
218
+ for (let i = 0; i < args.length; i++) {
219
+ const arg = args[i];
220
+ if ((arg === "--entry" || arg === "-e") && args[i + 1]) {
221
+ entryPoint = args[++i];
222
+ } else if (arg === "--help" || arg === "-h") {
223
+ return {
224
+ stdout: `Usage: sandlot typecheck [options]
225
+
226
+ Options:
227
+ --entry, -e <path> Entry point (default: from package.json main)
228
+ --help, -h Show this help message
229
+
230
+ Aliases: sandlot tsc
231
+
232
+ Examples:
233
+ sandlot typecheck
234
+ sandlot typecheck --entry /src/main.ts
235
+ `,
236
+ stderr: "",
237
+ exitCode: 0,
238
+ };
239
+ } else if (arg && !arg.startsWith("-") && !entryPoint) {
240
+ entryPoint = arg;
241
+ }
242
+ }
243
+
244
+ try {
245
+ const result = await sandboxRef.typecheck({ entryPoint });
246
+
247
+ if (!result.success) {
248
+ const errors = result.diagnostics.filter((d) => d.severity === "error");
249
+ const formatted = formatDiagnostics(errors);
250
+ return {
251
+ stdout: "",
252
+ stderr: `Type check failed:\n${formatted}\n`,
253
+ exitCode: 1,
254
+ };
255
+ }
256
+
257
+ const warnings = result.diagnostics.filter((d) => d.severity === "warning");
258
+ let output = `Type check passed.\n`;
259
+
260
+ if (warnings.length > 0) {
261
+ output += `\nWarnings:\n${formatDiagnostics(warnings)}\n`;
262
+ }
263
+
264
+ return {
265
+ stdout: output,
266
+ stderr: "",
267
+ exitCode: 0,
268
+ };
269
+ } catch (err) {
270
+ const message = err instanceof Error ? err.message : String(err);
271
+ return {
272
+ stdout: "",
273
+ stderr: `Type check error: ${message}\n`,
274
+ exitCode: 1,
275
+ };
276
+ }
277
+ }
278
+
279
+ // =============================================================================
280
+ // Install
281
+ // =============================================================================
282
+
283
+ async function handleInstall(sandboxRef: SandboxRef, args: (string | undefined)[]) {
284
+ // Check for help
285
+ if (args.includes("--help") || args.includes("-h")) {
286
+ return {
287
+ stdout: `Usage: sandlot install <package>[@version] [...packages]
288
+
289
+ Examples:
290
+ sandlot install react
291
+ sandlot install lodash@4.17.21
292
+ sandlot install @tanstack/react-query@5
293
+ sandlot install react react-dom
294
+
295
+ Aliases: sandlot add, sandlot i
296
+ `,
297
+ stderr: "",
298
+ exitCode: 0,
299
+ };
300
+ }
301
+
302
+ const packages = args.filter((a): a is string => !!a && !a.startsWith("-"));
303
+
304
+ if (packages.length === 0) {
305
+ return {
306
+ stdout: "",
307
+ stderr: `Usage: sandlot install <package>[@version] [...packages]\n\nRun 'sandlot install --help' for more information.\n`,
308
+ exitCode: 1,
309
+ };
310
+ }
311
+
312
+ const results: string[] = [];
313
+ let hasError = false;
314
+
315
+ for (const packageSpec of packages) {
316
+ try {
317
+ const result = await sandboxRef.install(packageSpec);
318
+
319
+ let status = `+ ${result.name}@${result.version}`;
320
+ if (result.typesInstalled) {
321
+ status += ` (${result.typeFilesCount} type file${result.typeFilesCount !== 1 ? "s" : ""})`;
322
+ if (result.fromCache) {
323
+ status += " [cached]";
324
+ }
325
+ } else if (result.typesError) {
326
+ status += ` (no types: ${result.typesError})`;
327
+ }
328
+ results.push(status);
329
+ } catch (err) {
330
+ hasError = true;
331
+ const message = err instanceof Error ? err.message : String(err);
332
+ results.push(`x ${packageSpec}: ${message}`);
333
+ }
334
+ }
335
+
336
+ const output = results.join("\n") + "\n";
337
+
338
+ return hasError
339
+ ? { stdout: "", stderr: output, exitCode: 1 }
340
+ : { stdout: output, stderr: "", exitCode: 0 };
341
+ }
342
+
343
+ // =============================================================================
344
+ // Uninstall
345
+ // =============================================================================
346
+
347
+ async function handleUninstall(sandboxRef: SandboxRef, args: (string | undefined)[]) {
348
+ // Check for help
349
+ if (args.includes("--help") || args.includes("-h")) {
350
+ return {
351
+ stdout: `Usage: sandlot uninstall <package> [...packages]
352
+
353
+ Examples:
354
+ sandlot uninstall lodash
355
+ sandlot uninstall react react-dom
356
+
357
+ Aliases: sandlot remove, sandlot rm
358
+ `,
359
+ stderr: "",
360
+ exitCode: 0,
361
+ };
362
+ }
363
+
364
+ const packages = args.filter((a): a is string => !!a && !a.startsWith("-"));
365
+
366
+ if (packages.length === 0) {
367
+ return {
368
+ stdout: "",
369
+ stderr: `Usage: sandlot uninstall <package> [...packages]\n\nRun 'sandlot uninstall --help' for more information.\n`,
370
+ exitCode: 1,
371
+ };
372
+ }
373
+
374
+ const results: string[] = [];
375
+ let hasError = false;
376
+
377
+ for (const packageName of packages) {
378
+ try {
379
+ const result = await sandboxRef.uninstall(packageName);
380
+ if (result.removed) {
381
+ results.push(`- ${result.name}`);
382
+ } else {
383
+ results.push(`x ${packageName}: not installed`);
384
+ hasError = true;
385
+ }
386
+ } catch (err) {
387
+ hasError = true;
388
+ const message = err instanceof Error ? err.message : String(err);
389
+ results.push(`x ${packageName}: ${message}`);
390
+ }
391
+ }
392
+
393
+ const output = results.join("\n") + "\n";
394
+
395
+ return hasError
396
+ ? { stdout: "", stderr: output, exitCode: 1 }
397
+ : { stdout: output, stderr: "", exitCode: 0 };
398
+ }
399
+
400
+ // =============================================================================
401
+ // Run
402
+ // =============================================================================
403
+
404
+ async function handleRun(sandboxRef: SandboxRef, args: (string | undefined)[]) {
405
+ let entryPoint: string | undefined;
406
+ let skipTypecheck = false;
407
+ let timeout = 30000;
408
+ let entryExport: "main" | "default" = "main";
409
+
410
+ for (let i = 0; i < args.length; i++) {
411
+ const arg = args[i];
412
+ if (arg === "--skip-typecheck" || arg === "-s") {
413
+ skipTypecheck = true;
414
+ } else if ((arg === "--timeout" || arg === "-t") && args[i + 1]) {
415
+ const t = parseInt(args[++i]!, 10);
416
+ if (!isNaN(t)) timeout = t;
417
+ } else if ((arg === "--entry" || arg === "-e") && args[i + 1]) {
418
+ entryPoint = args[++i];
419
+ } else if ((arg === "--export" || arg === "-x") && args[i + 1]) {
420
+ const e = args[++i]!.toLowerCase();
421
+ if (e === "main" || e === "default") {
422
+ entryExport = e;
423
+ }
424
+ } else if (arg === "--help" || arg === "-h") {
425
+ return {
426
+ stdout: `Usage: sandlot run [options]
427
+
428
+ Options:
429
+ --entry, -e <path> Entry point (default: from package.json main)
430
+ --skip-typecheck, -s Skip type checking
431
+ --timeout, -t <ms> Execution timeout (default: 30000, 0 = none)
432
+ --export, -x <name> Export to call: main or default (default: main)
433
+ --help, -h Show this help message
434
+
435
+ Examples:
436
+ sandlot run
437
+ sandlot run --entry /src/main.ts
438
+ sandlot run --skip-typecheck --timeout 5000
439
+ sandlot run --export default
440
+ `,
441
+ stderr: "",
442
+ exitCode: 0,
443
+ };
444
+ } else if (arg && !arg.startsWith("-") && !entryPoint) {
445
+ entryPoint = arg;
446
+ }
447
+ }
448
+
449
+ try {
450
+ const result = await sandboxRef.run({
451
+ entryPoint,
452
+ skipTypecheck,
453
+ timeout,
454
+ entryExport,
455
+ });
456
+
457
+ // Handle failure
458
+ if (!result.success) {
459
+ let stderr = "";
460
+
461
+ // Build failure
462
+ if (result.buildFailure) {
463
+ stderr = `Run failed: Build error in ${result.buildFailure.phase} phase`;
464
+ if (result.buildFailure.message) {
465
+ stderr += `\n${result.buildFailure.message}`;
466
+ }
467
+ stderr += "\n";
468
+ } else {
469
+ // Execution failure
470
+ stderr = `Run failed: ${result.error ?? "Unknown error"}\n`;
471
+ }
472
+
473
+ // Include any logs that were captured before failure
474
+ let stdout = "";
475
+ if (result.logs.length > 0) {
476
+ stdout = result.logs.join("\n") + "\n";
477
+ }
478
+
479
+ return {
480
+ stdout,
481
+ stderr,
482
+ exitCode: 1,
483
+ };
484
+ }
485
+
486
+ // Success
487
+ let output = "";
488
+
489
+ // Output captured logs
490
+ if (result.logs.length > 0) {
491
+ output = result.logs.join("\n") + "\n";
492
+ }
493
+
494
+ // Output return value if present
495
+ if (result.returnValue !== undefined) {
496
+ const returnStr =
497
+ typeof result.returnValue === "object"
498
+ ? JSON.stringify(result.returnValue, null, 2)
499
+ : String(result.returnValue);
500
+ output += `[return] ${returnStr}\n`;
501
+ }
502
+
503
+ // Execution time
504
+ if (result.executionTimeMs !== undefined) {
505
+ output += `\nCompleted in ${result.executionTimeMs.toFixed(2)}ms\n`;
506
+ }
507
+
508
+ return {
509
+ stdout: output,
510
+ stderr: "",
511
+ exitCode: 0,
512
+ };
513
+ } catch (err) {
514
+ const message = err instanceof Error ? err.message : String(err);
515
+ return {
516
+ stdout: "",
517
+ stderr: `Run error: ${message}\n`,
518
+ exitCode: 1,
519
+ };
520
+ }
521
+ }
522
+
523
+ // =============================================================================
524
+ // Default Commands Factory
525
+ // =============================================================================
526
+
527
+ /**
528
+ * Create all default sandbox commands.
529
+ *
530
+ * Currently just the `sandlot` command which dispatches to subcommands.
41
531
  */
42
- export function createDefaultCommands(deps: CommandDeps) {
43
- return [
44
- createTscCommand(deps),
45
- createBuildCommand(deps),
46
- createRunCommand(deps),
47
- createInstallCommand(deps),
48
- createUninstallCommand(deps),
49
- createListCommand(deps),
50
- ];
532
+ export function createDefaultCommands(sandboxRef: SandboxRef) {
533
+ return [createSandlotCommand(sandboxRef)];
51
534
  }