@poncho-ai/harness 0.36.0 → 0.36.2

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.
@@ -1,727 +0,0 @@
1
- // src/isolate/run-code-tool.ts
2
- import { defineTool } from "@poncho-ai/sdk";
3
-
4
- // src/isolate/runtime.ts
5
- var ivmModule;
6
- async function loadIvm() {
7
- if (ivmModule) return ivmModule;
8
- try {
9
- const mod = await import("isolated-vm");
10
- ivmModule = mod.default ?? mod;
11
- return ivmModule;
12
- } catch {
13
- throw new Error(
14
- "Code execution requires isolated-vm. Run: pnpm add isolated-vm"
15
- );
16
- }
17
- }
18
- function buildRuntimePreamble() {
19
- return `
20
- // --- console capture ---
21
- const __stdout = [];
22
- const __stderr = [];
23
- let __outputBytes = 0;
24
- const __outputLimit = typeof __OUTPUT_LIMIT === "number" ? __OUTPUT_LIMIT : 65536;
25
-
26
- function __serialize(v) {
27
- if (typeof v === "string") return v;
28
- try {
29
- const seen = new WeakSet();
30
- return JSON.stringify(v, function(_k, val) {
31
- if (typeof val === "object" && val !== null) {
32
- if (seen.has(val)) return "[Circular]";
33
- seen.add(val);
34
- }
35
- return val;
36
- }, 2);
37
- } catch { return String(v); }
38
- }
39
-
40
- function __capture(arr, args) {
41
- const line = Array.from(args).map(__serialize).join(" ");
42
- const bytes = line.length;
43
- if (__outputBytes + bytes > __outputLimit) {
44
- arr.push("[output truncated at " + __outputLimit + " bytes]");
45
- __outputBytes = __outputLimit;
46
- return;
47
- }
48
- __outputBytes += bytes;
49
- arr.push(line);
50
- }
51
-
52
- const console = {
53
- log: function() { __capture(__stdout, arguments); },
54
- info: function() { __capture(__stdout, arguments); },
55
- warn: function() { __capture(__stderr, arguments); },
56
- error: function() { __capture(__stderr, arguments); },
57
- debug: function() { __capture(__stdout, arguments); },
58
- };
59
- `;
60
- }
61
- function createIsolateRuntime(config) {
62
- return {
63
- async execute(code, bindings, preamble, signal) {
64
- const ivm = await loadIvm();
65
- const isolate = new ivm.Isolate({
66
- memoryLimit: config.memoryLimit
67
- });
68
- let abortHandler;
69
- let aborted = false;
70
- if (signal) {
71
- if (signal.aborted) {
72
- isolate.dispose();
73
- return {
74
- stdout: "",
75
- stderr: "",
76
- error: { message: "Execution cancelled", name: "AbortError" },
77
- executionTimeMs: 0
78
- };
79
- }
80
- abortHandler = () => {
81
- aborted = true;
82
- isolate.dispose();
83
- };
84
- signal.addEventListener("abort", abortHandler, { once: true });
85
- }
86
- const t0 = performance.now();
87
- try {
88
- const context = await isolate.createContext();
89
- const jail = context.global;
90
- jail.setSync("__OUTPUT_LIMIT", config.outputLimit);
91
- const bindingNames = Object.keys(bindings);
92
- const wrapperDecls = [];
93
- for (const name of bindingNames) {
94
- const binding = bindings[name];
95
- const ref = new ivm.Reference(async (inputJson) => {
96
- const input = JSON.parse(inputJson);
97
- const result2 = await binding.handler(input);
98
- return JSON.stringify(result2 ?? null);
99
- });
100
- jail.setSync(`__binding_${name}`, ref);
101
- wrapperDecls.push(
102
- `async function ${name}(input) {
103
- const raw = await __binding_${name}.apply(undefined, [JSON.stringify(input)], { result: { promise: true, copy: true } });
104
- return JSON.parse(raw);
105
- }`
106
- );
107
- }
108
- const runtimePreamble = buildRuntimePreamble() + "\n" + wrapperDecls.join("\n");
109
- await context.eval(runtimePreamble, { filename: "<runtime>" });
110
- if (preamble) {
111
- await context.eval(preamble, { filename: "<libraries>" });
112
- }
113
- const wrapped = `(async () => {
114
- ${code}
115
- })()`;
116
- const rawResult = await context.eval(wrapped, {
117
- filename: "<user-code>",
118
- promise: true,
119
- copy: true,
120
- timeout: config.timeout
121
- });
122
- const stdout = await context.eval("__stdout.join('\\n')", { copy: true });
123
- const stderr = await context.eval("__stderr.join('\\n')", { copy: true });
124
- let result;
125
- try {
126
- result = rawResult === void 0 || rawResult === null ? rawResult : JSON.parse(JSON.stringify(rawResult));
127
- } catch {
128
- result = void 0;
129
- }
130
- return {
131
- result,
132
- stdout,
133
- stderr,
134
- executionTimeMs: performance.now() - t0
135
- };
136
- } catch (err) {
137
- const elapsed = performance.now() - t0;
138
- if (aborted) {
139
- return {
140
- stdout: "",
141
- stderr: "",
142
- error: { message: "Execution cancelled", name: "AbortError" },
143
- executionTimeMs: elapsed
144
- };
145
- }
146
- const error = err instanceof Error ? err : new Error(String(err));
147
- const parsed = parseV8Error(error);
148
- return {
149
- stdout: "",
150
- stderr: "",
151
- error: parsed,
152
- executionTimeMs: elapsed
153
- };
154
- } finally {
155
- if (abortHandler && signal) {
156
- signal.removeEventListener("abort", abortHandler);
157
- }
158
- try {
159
- isolate.dispose();
160
- } catch {
161
- }
162
- }
163
- }
164
- };
165
- }
166
- function parseV8Error(error) {
167
- const result = {
168
- message: error.message,
169
- name: error.name
170
- };
171
- const match = error.stack?.match(/<user-code>:(\d+):(\d+)/);
172
- if (match) {
173
- const rawLine = parseInt(match[1], 10);
174
- result.line = Math.max(1, rawLine - 1);
175
- result.column = parseInt(match[2], 10);
176
- }
177
- return result;
178
- }
179
-
180
- // src/isolate/bindings.ts
181
- function createVfsBindings(adapter) {
182
- return {
183
- fs_read: {
184
- description: "Read a text file from the VFS",
185
- inputSchema: {
186
- type: "object",
187
- properties: { path: { type: "string", description: "Absolute path in the VFS" } },
188
- required: ["path"]
189
- },
190
- handler: async (input) => {
191
- const content = await adapter.readFile(input.path);
192
- return content;
193
- }
194
- },
195
- fs_write: {
196
- description: "Write a text file to the VFS",
197
- inputSchema: {
198
- type: "object",
199
- properties: {
200
- path: { type: "string", description: "Absolute path in the VFS" },
201
- content: { type: "string", description: "Text content to write" }
202
- },
203
- required: ["path", "content"]
204
- },
205
- handler: async (input) => {
206
- await adapter.writeFile(input.path, input.content);
207
- }
208
- },
209
- fs_read_binary: {
210
- description: "Read a binary file from the VFS (returns base64)",
211
- inputSchema: {
212
- type: "object",
213
- properties: { path: { type: "string", description: "Absolute path in the VFS" } },
214
- required: ["path"]
215
- },
216
- handler: async (input) => {
217
- const buf = await adapter.readFileBuffer(input.path);
218
- return Buffer.from(buf).toString("base64");
219
- }
220
- },
221
- fs_write_binary: {
222
- description: "Write a binary file to the VFS (content is base64-encoded)",
223
- inputSchema: {
224
- type: "object",
225
- properties: {
226
- path: { type: "string", description: "Absolute path in the VFS" },
227
- content: { type: "string", description: "Base64-encoded binary content" }
228
- },
229
- required: ["path", "content"]
230
- },
231
- handler: async (input) => {
232
- const buf = Buffer.from(input.content, "base64");
233
- await adapter.writeFile(input.path, buf);
234
- }
235
- },
236
- fs_list: {
237
- description: "List files and directories at a path",
238
- inputSchema: {
239
- type: "object",
240
- properties: { path: { type: "string", description: "Directory path in the VFS" } },
241
- required: ["path"]
242
- },
243
- handler: async (input) => {
244
- return await adapter.readdir(input.path);
245
- }
246
- },
247
- fs_exists: {
248
- description: "Check if a file or directory exists",
249
- inputSchema: {
250
- type: "object",
251
- properties: { path: { type: "string", description: "Absolute path in the VFS" } },
252
- required: ["path"]
253
- },
254
- handler: async (input) => {
255
- return await adapter.exists(input.path);
256
- }
257
- },
258
- fs_delete: {
259
- description: "Delete a file or directory",
260
- inputSchema: {
261
- type: "object",
262
- properties: { path: { type: "string", description: "Absolute path in the VFS" } },
263
- required: ["path"]
264
- },
265
- handler: async (input) => {
266
- await adapter.rm(input.path, { force: true });
267
- }
268
- },
269
- fs_mkdir: {
270
- description: "Create a directory (recursive)",
271
- inputSchema: {
272
- type: "object",
273
- properties: { path: { type: "string", description: "Directory path to create" } },
274
- required: ["path"]
275
- },
276
- handler: async (input) => {
277
- await adapter.mkdir(input.path, { recursive: true });
278
- }
279
- },
280
- fs_stat: {
281
- description: "Get file/directory metadata (size, type, mtime)",
282
- inputSchema: {
283
- type: "object",
284
- properties: { path: { type: "string", description: "Absolute path in the VFS" } },
285
- required: ["path"]
286
- },
287
- handler: async (input) => {
288
- const stat = await adapter.stat(input.path);
289
- return {
290
- isFile: stat.isFile,
291
- isDirectory: stat.isDirectory,
292
- size: stat.size,
293
- mtime: stat.mtime.toISOString()
294
- };
295
- }
296
- }
297
- };
298
- }
299
- function createFetchBinding(allowedDomains) {
300
- const domainSet = new Set(allowedDomains.map((d) => d.toLowerCase()));
301
- return {
302
- description: `HTTP fetch restricted to: ${allowedDomains.join(", ")}`,
303
- inputSchema: {
304
- type: "object",
305
- properties: {
306
- url: { type: "string", description: "URL to fetch" },
307
- method: { type: "string", description: "HTTP method (default: GET)" },
308
- headers: {
309
- type: "object",
310
- description: "Request headers",
311
- additionalProperties: { type: "string" }
312
- },
313
- body: { type: "string", description: "Request body" }
314
- },
315
- required: ["url"]
316
- },
317
- handler: async (input) => {
318
- const url = new URL(input.url);
319
- if (!domainSet.has(url.hostname.toLowerCase())) {
320
- throw new Error(
321
- `Fetch blocked: domain "${url.hostname}" is not in the allowed list [${allowedDomains.join(", ")}]`
322
- );
323
- }
324
- const resp = await fetch(input.url, {
325
- method: input.method ?? "GET",
326
- headers: input.headers ?? void 0,
327
- body: input.body ?? void 0
328
- });
329
- const body = await resp.text();
330
- const headers = {};
331
- resp.headers.forEach((v, k) => {
332
- headers[k] = v;
333
- });
334
- return { status: resp.status, headers, body };
335
- }
336
- };
337
- }
338
- function mergeBuilderBindings(configBindings) {
339
- return { ...configBindings };
340
- }
341
-
342
- // src/isolate/run-code-tool.ts
343
- var esbuildTransform;
344
- async function loadEsbuild() {
345
- if (esbuildTransform) return esbuildTransform;
346
- try {
347
- const mod = await import("esbuild");
348
- esbuildTransform = mod.transform;
349
- return esbuildTransform;
350
- } catch {
351
- throw new Error(
352
- "Code execution requires esbuild for TypeScript stripping. Run: pnpm add esbuild"
353
- );
354
- }
355
- }
356
- async function stripTypeScript(code) {
357
- const transform = await loadEsbuild();
358
- const result = await transform(code, { loader: "ts" });
359
- return result.code;
360
- }
361
- var ALLOWED_EXTENSIONS = /* @__PURE__ */ new Set([".js", ".ts", ".mjs", ".mts"]);
362
- function hasAllowedExtension(path) {
363
- const dot = path.lastIndexOf(".");
364
- if (dot === -1) return false;
365
- return ALLOWED_EXTENSIONS.has(path.slice(dot).toLowerCase());
366
- }
367
- function createRunCodeTool(opts) {
368
- const { config, bashManager, libraryPreamble, description } = opts;
369
- const memoryLimit = config.memoryLimit ?? 128;
370
- const timeout = config.timeLimit ?? 1e4;
371
- const outputLimit = config.outputLimit ?? 65536;
372
- const codeLimit = config.codeLimit ?? 102400;
373
- const runtime = createIsolateRuntime({
374
- memoryLimit,
375
- timeout,
376
- outputLimit
377
- });
378
- const staticBindings = {};
379
- if (config.apis?.fetch) {
380
- staticBindings.fetch = createFetchBinding(config.apis.fetch.allowedDomains);
381
- }
382
- if (config.bindings) {
383
- Object.assign(staticBindings, mergeBuilderBindings(config.bindings));
384
- }
385
- return defineTool({
386
- name: "run_code",
387
- description,
388
- inputSchema: {
389
- type: "object",
390
- properties: {
391
- code: {
392
- type: "string",
393
- description: "JavaScript or TypeScript code to execute"
394
- },
395
- file: {
396
- type: "string",
397
- description: "Path to a .js/.ts file in the VFS to execute instead of inline code"
398
- }
399
- },
400
- additionalProperties: false
401
- },
402
- handler: async (input, context) => {
403
- const code = input.code;
404
- const file = input.file;
405
- if (code && file) {
406
- return { error: "Provide either `code` or `file`, not both." };
407
- }
408
- if (!code && !file) {
409
- return { error: "Provide either `code` (inline) or `file` (VFS path)." };
410
- }
411
- let source;
412
- if (file) {
413
- if (!hasAllowedExtension(file)) {
414
- return {
415
- error: `File must have a .js, .ts, .mjs, or .mts extension. Got: "${file}"`
416
- };
417
- }
418
- const tenantId2 = context.tenantId ?? "__default__";
419
- const adapter2 = bashManager.getAdapter(tenantId2);
420
- try {
421
- source = await adapter2.readFile(file);
422
- } catch (err) {
423
- return {
424
- error: `Failed to read file "${file}": ${err instanceof Error ? err.message : String(err)}`
425
- };
426
- }
427
- } else {
428
- source = code;
429
- }
430
- if (source.length > codeLimit) {
431
- return {
432
- error: `Code exceeds size limit: ${source.length} bytes > ${codeLimit} byte max.`
433
- };
434
- }
435
- let jsCode;
436
- try {
437
- jsCode = await stripTypeScript(source);
438
- } catch (err) {
439
- const msg = err instanceof Error ? err.message : String(err);
440
- return { error: `TypeScript parse error: ${msg}` };
441
- }
442
- const tenantId = context.tenantId ?? "__default__";
443
- const adapter = bashManager.getAdapter(tenantId);
444
- const vfsBindings = createVfsBindings(adapter);
445
- const allBindings = {
446
- ...vfsBindings,
447
- ...staticBindings
448
- };
449
- const result = await runtime.execute(
450
- jsCode,
451
- allBindings,
452
- libraryPreamble,
453
- context.abortSignal
454
- );
455
- if (result.error) {
456
- return {
457
- error: result.error.message,
458
- errorName: result.error.name,
459
- line: result.error.line,
460
- column: result.error.column,
461
- stdout: result.stdout || void 0,
462
- stderr: result.stderr || void 0,
463
- executionTimeMs: result.executionTimeMs
464
- };
465
- }
466
- return {
467
- result: result.result,
468
- stdout: result.stdout || void 0,
469
- stderr: result.stderr || void 0,
470
- executionTimeMs: result.executionTimeMs
471
- };
472
- }
473
- });
474
- }
475
-
476
- // src/isolate/type-stubs.ts
477
- function generateIsolateTypeStubs(config) {
478
- const lines = [];
479
- lines.push(
480
- "// Filesystem (persistent virtual filesystem, all async)",
481
- "declare function fs_read(input: { path: string }): Promise<string>;",
482
- "declare function fs_write(input: { path: string; content: string }): Promise<void>;",
483
- "declare function fs_read_binary(input: { path: string }): Promise<string>; // returns base64",
484
- "declare function fs_write_binary(input: { path: string; content: string }): Promise<void>; // content is base64",
485
- "declare function fs_list(input: { path: string }): Promise<string[]>;",
486
- "declare function fs_exists(input: { path: string }): Promise<boolean>;",
487
- "declare function fs_delete(input: { path: string }): Promise<void>;",
488
- "declare function fs_mkdir(input: { path: string }): Promise<void>;",
489
- "declare function fs_stat(input: { path: string }): Promise<{ isFile: boolean; isDirectory: boolean; size: number; mtime: string }>;"
490
- );
491
- if (config.apis?.fetch) {
492
- const domains = config.apis.fetch.allowedDomains.join(", ");
493
- lines.push(
494
- "",
495
- `// HTTP fetch (restricted to: ${domains})`,
496
- "declare function fetch(input: { url: string; method?: string; headers?: Record<string, string>; body?: string }): Promise<{ status: number; headers: Record<string, string>; body: string }>;"
497
- );
498
- }
499
- if (config.bindings) {
500
- const entries = Object.entries(config.bindings);
501
- if (entries.length > 0) {
502
- lines.push("", "// Custom bindings");
503
- for (const [name, binding] of entries) {
504
- lines.push(formatBindingStub(name, binding));
505
- }
506
- }
507
- }
508
- lines.push(
509
- "",
510
- "// Console (output captured and returned in tool result)",
511
- "declare const console: { log(...args: unknown[]): void; error(...args: unknown[]): void; warn(...args: unknown[]): void; info(...args: unknown[]): void; debug(...args: unknown[]): void; };"
512
- );
513
- if (config.libraries?.length) {
514
- lines.push(
515
- "",
516
- `// Pre-bundled libraries (use require())`,
517
- `declare function require(name: ${config.libraries.map((l) => `"${l}"`).join(" | ")}): any;`
518
- );
519
- }
520
- return lines.join("\n");
521
- }
522
- function buildRunCodeDescription(config) {
523
- const parts = [
524
- "Execute JavaScript/TypeScript code in a sandboxed V8 isolate.",
525
- "",
526
- "Input: provide either `code` (inline string) or `file` (path to a .js/.ts file in the VFS).",
527
- "",
528
- "Available APIs inside the isolate (all async, all take a single object argument):",
529
- "- fs_read({path}) / fs_write({path, content}) / fs_read_binary({path}) / fs_write_binary({path, content})",
530
- "- fs_list({path}) / fs_exists({path}) / fs_delete({path}) / fs_mkdir({path}) / fs_stat({path})",
531
- "- console.log() / console.error() -- output captured and returned (not async)"
532
- ];
533
- if (config.apis?.fetch) {
534
- parts.push(
535
- `- fetch({url, method?, headers?, body?}) -- restricted to: ${config.apis.fetch.allowedDomains.join(", ")}`
536
- );
537
- }
538
- if (config.bindings) {
539
- for (const [name, binding] of Object.entries(config.bindings)) {
540
- parts.push(`- ${name}({...}) -- ${binding.description}`);
541
- }
542
- }
543
- if (config.libraries?.length) {
544
- parts.push(
545
- "",
546
- `Pre-bundled libraries (use require()):`,
547
- `- ${config.libraries.join(", ")}`
548
- );
549
- }
550
- const memoryLimit = config.memoryLimit ?? 128;
551
- const timeLimit = config.timeLimit ?? 1e4;
552
- const codeLimit = config.codeLimit ?? 102400;
553
- parts.push(
554
- "",
555
- "Notes:",
556
- "- Code is wrapped in an async IIFE. Use `return` to return a value.",
557
- "- Files written during execution persist even if the code throws an error.",
558
- "- TypeScript is supported (type annotations are stripped before execution).",
559
- `- Execution timeout: ${timeLimit / 1e3}s. Memory limit: ${memoryLimit}MB. Max code size: ${Math.round(codeLimit / 1024)}KB.`
560
- );
561
- return parts.join("\n");
562
- }
563
- function formatBindingStub(name, binding) {
564
- const schema = binding.inputSchema;
565
- const props = schema.properties ?? {};
566
- const required = new Set(schema.required ?? []);
567
- const params = Object.entries(props).map(([k, v]) => {
568
- const opt = required.has(k) ? "" : "?";
569
- const tsType = jsonSchemaToTsType(v);
570
- return `${k}${opt}: ${tsType}`;
571
- }).join("; ");
572
- return `declare function ${name}(input: { ${params} }): Promise<unknown>; // ${binding.description}`;
573
- }
574
- function jsonSchemaToTsType(schema) {
575
- switch (schema.type) {
576
- case "string":
577
- return "string";
578
- case "number":
579
- case "integer":
580
- return "number";
581
- case "boolean":
582
- return "boolean";
583
- case "array":
584
- return "unknown[]";
585
- case "object":
586
- return "Record<string, unknown>";
587
- default:
588
- return "unknown";
589
- }
590
- }
591
-
592
- // src/isolate/bundler.ts
593
- import { resolve } from "path";
594
- import { existsSync, readFileSync } from "fs";
595
- var esbuildBuild;
596
- async function loadEsbuild2() {
597
- if (esbuildBuild) return esbuildBuild;
598
- try {
599
- const mod = await import("esbuild");
600
- esbuildBuild = mod.build;
601
- return esbuildBuild;
602
- } catch {
603
- throw new Error(
604
- "Library bundling requires esbuild. Run: pnpm add esbuild"
605
- );
606
- }
607
- }
608
- var BLOCKED_BUILTINS = /* @__PURE__ */ new Set([
609
- "fs",
610
- "fs/promises",
611
- "net",
612
- "tls",
613
- "child_process",
614
- "cluster",
615
- "dgram",
616
- "dns",
617
- "http",
618
- "http2",
619
- "https",
620
- "inspector",
621
- "module",
622
- "os",
623
- "perf_hooks",
624
- "readline",
625
- "repl",
626
- "stream",
627
- "tty",
628
- "v8",
629
- "vm",
630
- "worker_threads",
631
- "wasi"
632
- ]);
633
- function blockedBuiltinsPlugin() {
634
- return {
635
- name: "blocked-builtins",
636
- setup(build) {
637
- const filter = new RegExp(
638
- `^(node:)?(${[...BLOCKED_BUILTINS].join("|")})$`
639
- );
640
- build.onResolve({ filter }, (args) => ({
641
- path: args.path,
642
- namespace: "blocked-builtin"
643
- }));
644
- build.onLoad(
645
- { filter: /.*/, namespace: "blocked-builtin" },
646
- (args) => {
647
- const name = args.path.replace(/^node:/, "");
648
- return {
649
- contents: `throw new Error("Module '${name}' is not available in the isolate. Use the injected fs_* functions instead.");`,
650
- loader: "js"
651
- };
652
- }
653
- );
654
- }
655
- };
656
- }
657
- async function bundleLibraries(libraries, projectDir) {
658
- if (libraries.length === 0) return null;
659
- const build = await loadEsbuild2();
660
- const chunks = [];
661
- const moduleEntries = [];
662
- for (const lib of libraries) {
663
- const pkgPath = resolve(projectDir, "node_modules", lib, "package.json");
664
- if (!existsSync(pkgPath)) {
665
- throw new Error(
666
- `Library '${lib}' is declared in isolate.libraries but not installed. Run: pnpm add ${lib}`
667
- );
668
- }
669
- let version = "unknown";
670
- try {
671
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
672
- version = pkg.version ?? "unknown";
673
- } catch {
674
- }
675
- const safeName = lib.replace(/[^a-zA-Z0-9_]/g, "_");
676
- const globalName = `__lib_${safeName}`;
677
- const result = await build({
678
- entryPoints: [lib],
679
- bundle: true,
680
- write: false,
681
- format: "iife",
682
- globalName,
683
- platform: "neutral",
684
- target: "es2022",
685
- // Resolve from the project's node_modules
686
- nodePaths: [resolve(projectDir, "node_modules")],
687
- plugins: [blockedBuiltinsPlugin()],
688
- logLevel: "silent",
689
- minify: false
690
- });
691
- if (result.outputFiles?.[0]) {
692
- chunks.push(
693
- `// --- ${lib}@${version} ---
694
- ${result.outputFiles[0].text}`
695
- );
696
- moduleEntries.push(` ${JSON.stringify(lib)}: ${globalName}`);
697
- } else {
698
- throw new Error(
699
- `Failed to bundle library '${lib}': esbuild produced no output.`
700
- );
701
- }
702
- }
703
- const requireShim = `
704
- // --- require() shim ---
705
- var __modules = {
706
- ${moduleEntries.join(",\n")}
707
- };
708
- function require(name) {
709
- var mod = __modules[name];
710
- if (!mod) throw new Error('Module "' + name + '" is not available. Available: ${libraries.join(", ")}');
711
- // Handle both default and namespace exports
712
- if (mod && mod.default !== undefined && Object.keys(mod).length === 1) return mod.default;
713
- return mod;
714
- }
715
- `;
716
- return chunks.join("\n\n") + "\n\n" + requireShim;
717
- }
718
- export {
719
- buildRunCodeDescription,
720
- bundleLibraries,
721
- createFetchBinding,
722
- createIsolateRuntime,
723
- createRunCodeTool,
724
- createVfsBindings,
725
- generateIsolateTypeStubs,
726
- mergeBuilderBindings
727
- };