sandlot 0.1.2 → 0.1.3

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 (54) hide show
  1. package/README.md +138 -408
  2. package/dist/build-emitter.d.ts +31 -13
  3. package/dist/build-emitter.d.ts.map +1 -1
  4. package/dist/builder.d.ts +370 -0
  5. package/dist/builder.d.ts.map +1 -0
  6. package/dist/bundler.d.ts +1 -1
  7. package/dist/bundler.d.ts.map +1 -1
  8. package/dist/commands/compile.d.ts +13 -0
  9. package/dist/commands/compile.d.ts.map +1 -0
  10. package/dist/commands/index.d.ts +17 -0
  11. package/dist/commands/index.d.ts.map +1 -0
  12. package/dist/commands/packages.d.ts +17 -0
  13. package/dist/commands/packages.d.ts.map +1 -0
  14. package/dist/commands/run.d.ts +40 -0
  15. package/dist/commands/run.d.ts.map +1 -0
  16. package/dist/commands/types.d.ts +141 -0
  17. package/dist/commands/types.d.ts.map +1 -0
  18. package/dist/fs.d.ts +53 -49
  19. package/dist/fs.d.ts.map +1 -1
  20. package/dist/index.d.ts +5 -4
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +249 -427
  23. package/dist/internal.js +111 -87
  24. package/dist/runner.d.ts +314 -0
  25. package/dist/runner.d.ts.map +1 -0
  26. package/dist/sandbox-manager.d.ts +45 -21
  27. package/dist/sandbox-manager.d.ts.map +1 -1
  28. package/dist/sandbox.d.ts +144 -62
  29. package/dist/sandbox.d.ts.map +1 -1
  30. package/dist/shared-modules.d.ts +22 -3
  31. package/dist/shared-modules.d.ts.map +1 -1
  32. package/dist/shared-resources.d.ts +0 -3
  33. package/dist/shared-resources.d.ts.map +1 -1
  34. package/dist/typechecker.d.ts +1 -1
  35. package/package.json +2 -11
  36. package/src/build-emitter.ts +32 -29
  37. package/src/builder.ts +498 -0
  38. package/src/bundler.ts +24 -36
  39. package/src/commands/compile.ts +236 -0
  40. package/src/commands/index.ts +51 -0
  41. package/src/commands/packages.ts +154 -0
  42. package/src/commands/run.ts +245 -0
  43. package/src/commands/types.ts +172 -0
  44. package/src/fs.ts +82 -221
  45. package/src/index.ts +17 -12
  46. package/src/sandbox.ts +217 -149
  47. package/src/shared-modules.ts +74 -4
  48. package/src/shared-resources.ts +0 -3
  49. package/src/typechecker.ts +1 -1
  50. package/dist/react.d.ts +0 -159
  51. package/dist/react.d.ts.map +0 -1
  52. package/dist/react.js +0 -149
  53. package/src/commands.ts +0 -733
  54. package/src/sandbox-manager.ts +0 -409
package/dist/internal.js CHANGED
@@ -675,16 +675,18 @@ var GLOBAL_KEY = "__sandlot_shared_modules__";
675
675
 
676
676
  class SharedModuleRegistry {
677
677
  modules = new Map;
678
+ exportNames = new Map;
678
679
  constructor() {
679
680
  globalThis[GLOBAL_KEY] = this;
680
681
  }
681
682
  register(moduleId, module) {
682
683
  this.modules.set(moduleId, module);
684
+ this.exportNames.set(moduleId, introspectExports(module));
683
685
  return this;
684
686
  }
685
687
  registerAll(modules) {
686
688
  for (const [id, mod] of Object.entries(modules)) {
687
- this.modules.set(id, mod);
689
+ this.register(id, mod);
688
690
  }
689
691
  return this;
690
692
  }
@@ -705,13 +707,44 @@ class SharedModuleRegistry {
705
707
  list() {
706
708
  return [...this.modules.keys()];
707
709
  }
710
+ getExportNames(moduleId) {
711
+ return this.exportNames.get(moduleId) ?? [];
712
+ }
708
713
  clear() {
709
714
  this.modules.clear();
715
+ this.exportNames.clear();
710
716
  }
711
717
  get size() {
712
718
  return this.modules.size;
713
719
  }
714
720
  }
721
+ function introspectExports(module) {
722
+ if (module === null || module === undefined) {
723
+ return [];
724
+ }
725
+ if (typeof module !== "object" && typeof module !== "function") {
726
+ return [];
727
+ }
728
+ const exports = [];
729
+ for (const key of Object.keys(module)) {
730
+ if (isValidIdentifier(key)) {
731
+ exports.push(key);
732
+ }
733
+ }
734
+ return exports;
735
+ }
736
+ function isValidIdentifier(name) {
737
+ if (name.length === 0)
738
+ return false;
739
+ if (!/^[a-zA-Z_$]/.test(name))
740
+ return false;
741
+ if (!/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name))
742
+ return false;
743
+ const reserved = ["default", "class", "function", "var", "let", "const", "import", "export"];
744
+ if (reserved.includes(name))
745
+ return false;
746
+ return true;
747
+ }
715
748
  var defaultRegistry = null;
716
749
  function getSharedModuleRegistry() {
717
750
  if (!defaultRegistry) {
@@ -731,6 +764,9 @@ function unregisterSharedModule(moduleId) {
731
764
  function clearSharedModules() {
732
765
  getSharedModuleRegistry().clear();
733
766
  }
767
+ function getSharedModuleExports(moduleId) {
768
+ return getSharedModuleRegistry().getExportNames(moduleId);
769
+ }
734
770
  function getSharedModuleRuntimeCode(moduleId) {
735
771
  return `
736
772
  (function() {
@@ -745,7 +781,21 @@ function getSharedModuleRuntimeCode(moduleId) {
745
781
  })()
746
782
  `.trim();
747
783
  }
748
- // src/commands.ts
784
+ // src/commands/types.ts
785
+ function formatEsbuildMessages(messages) {
786
+ if (messages.length === 0)
787
+ return "";
788
+ return messages.map((msg) => {
789
+ if (msg.location) {
790
+ const { file, line, column } = msg.location;
791
+ const loc = file ? `${file}${line ? `:${line}` : ""}${column ? `:${column}` : ""}` : "";
792
+ return loc ? `${loc}: ${msg.text}` : msg.text;
793
+ }
794
+ return msg.text;
795
+ }).join(`
796
+ `);
797
+ }
798
+ // src/commands/compile.ts
749
799
  import { defineCommand } from "just-bash/browser";
750
800
 
751
801
  // src/typechecker.ts
@@ -1262,55 +1312,12 @@ ${generateNamedExports(args.path)}
1262
1312
  };
1263
1313
  }
1264
1314
  function generateNamedExports(moduleId) {
1265
- const knownExports = {
1266
- react: [
1267
- "useState",
1268
- "useEffect",
1269
- "useContext",
1270
- "useReducer",
1271
- "useCallback",
1272
- "useMemo",
1273
- "useRef",
1274
- "useImperativeHandle",
1275
- "useLayoutEffect",
1276
- "useDebugValue",
1277
- "useDeferredValue",
1278
- "useTransition",
1279
- "useId",
1280
- "useSyncExternalStore",
1281
- "useInsertionEffect",
1282
- "useOptimistic",
1283
- "useActionState",
1284
- "createElement",
1285
- "cloneElement",
1286
- "createContext",
1287
- "forwardRef",
1288
- "lazy",
1289
- "memo",
1290
- "startTransition",
1291
- "Children",
1292
- "Component",
1293
- "PureComponent",
1294
- "Fragment",
1295
- "Profiler",
1296
- "StrictMode",
1297
- "Suspense",
1298
- "version",
1299
- "isValidElement"
1300
- ],
1301
- "react-dom": ["createPortal", "flushSync", "version"],
1302
- "react-dom/client": ["createRoot", "hydrateRoot"],
1303
- "react-dom/server": ["renderToString", "renderToStaticMarkup", "renderToPipeableStream"]
1304
- };
1305
- const exports = knownExports[moduleId];
1306
- if (!exports) {
1307
- return `
1308
- // Dynamic re-export for unknown module
1309
- export const __moduleProxy__ = __sandlot_mod__;
1310
- `;
1311
- }
1312
- return exports.map((name) => `export const ${name} = __sandlot_mod__.${name};`).join(`
1315
+ const exports = getSharedModuleExports(moduleId);
1316
+ if (exports.length > 0) {
1317
+ return exports.map((name) => `export const ${name} = __sandlot_mod__.${name};`).join(`
1313
1318
  `);
1319
+ }
1320
+ return `// No exports discovered for "${moduleId}" - use default import or call registerSharedModules() first`;
1314
1321
  }
1315
1322
  async function bundle(options) {
1316
1323
  await initBundler();
@@ -1353,7 +1360,8 @@ async function bundle(options) {
1353
1360
  globalName,
1354
1361
  target,
1355
1362
  external,
1356
- plugins: [plugin]
1363
+ plugins: [plugin],
1364
+ jsx: "automatic"
1357
1365
  });
1358
1366
  const code = result.outputFiles?.[0]?.text ?? "";
1359
1367
  return {
@@ -1376,20 +1384,7 @@ async function bundleAndImport(options) {
1376
1384
  }
1377
1385
  }
1378
1386
 
1379
- // src/commands.ts
1380
- function formatEsbuildMessages(messages) {
1381
- if (messages.length === 0)
1382
- return "";
1383
- return messages.map((msg) => {
1384
- if (msg.location) {
1385
- const { file, line, column } = msg.location;
1386
- const loc = file ? `${file}${line ? `:${line}` : ""}${column ? `:${column}` : ""}` : "";
1387
- return loc ? `${loc}: ${msg.text}` : msg.text;
1388
- }
1389
- return msg.text;
1390
- }).join(`
1391
- `);
1392
- }
1387
+ // src/commands/compile.ts
1393
1388
  function createTscCommand(deps) {
1394
1389
  const { fs, libFiles, tsconfigPath } = deps;
1395
1390
  return defineCommand("tsc", async (args, _ctx) => {
@@ -1454,7 +1449,7 @@ ${formatDiagnosticsForAgent(result.diagnostics.filter((d) => d.category === "war
1454
1449
  });
1455
1450
  }
1456
1451
  function createBuildCommand(deps) {
1457
- const { fs, libFiles, tsconfigPath, onBuild, sharedModules } = deps;
1452
+ const { fs, libFiles, tsconfigPath, onBuild, getValidation, sharedModules } = deps;
1458
1453
  return defineCommand("build", async (args, _ctx) => {
1459
1454
  let entryPoint = null;
1460
1455
  let skipTypecheck = false;
@@ -1526,8 +1521,39 @@ ${formatted}
1526
1521
  minify,
1527
1522
  sharedModules
1528
1523
  });
1524
+ let loadedModule;
1525
+ try {
1526
+ loadedModule = await loadModule(bundleResult);
1527
+ } catch (err) {
1528
+ const errorMessage = err instanceof Error ? err.message : String(err);
1529
+ return {
1530
+ stdout: "",
1531
+ stderr: `Build failed: Module failed to load.
1532
+
1533
+ ${errorMessage}
1534
+ `,
1535
+ exitCode: 1
1536
+ };
1537
+ }
1538
+ const validateFn = getValidation?.();
1539
+ let validatedModule = loadedModule;
1540
+ if (validateFn) {
1541
+ try {
1542
+ validatedModule = validateFn(loadedModule);
1543
+ } catch (err) {
1544
+ const errorMessage = err instanceof Error ? err.message : String(err);
1545
+ return {
1546
+ stdout: "",
1547
+ stderr: `Build failed: Validation error.
1548
+
1549
+ ${errorMessage}
1550
+ `,
1551
+ exitCode: 1
1552
+ };
1553
+ }
1554
+ }
1529
1555
  if (onBuild) {
1530
- await onBuild(bundleResult);
1556
+ await onBuild({ bundle: bundleResult, module: validatedModule });
1531
1557
  }
1532
1558
  let output = `Build successful!
1533
1559
  `;
@@ -1543,6 +1569,15 @@ ${formatted}
1543
1569
  }
1544
1570
  output += `Bundled: ${bundleResult.includedFiles.length} file(s)
1545
1571
  `;
1572
+ const exportNames = Object.keys(loadedModule).filter((k) => !k.startsWith("__"));
1573
+ if (exportNames.length > 0) {
1574
+ output += `Exports: ${exportNames.join(", ")}
1575
+ `;
1576
+ }
1577
+ if (validateFn) {
1578
+ output += `Validation: passed
1579
+ `;
1580
+ }
1546
1581
  if (bundleResult.warnings.length > 0) {
1547
1582
  output += `
1548
1583
  Build warnings:
@@ -1574,9 +1609,11 @@ ${formatDiagnosticsForAgent(warnings)}
1574
1609
  }
1575
1610
  });
1576
1611
  }
1612
+ // src/commands/packages.ts
1613
+ import { defineCommand as defineCommand2 } from "just-bash/browser";
1577
1614
  function createInstallCommand(deps) {
1578
1615
  const { fs, typesCache } = deps;
1579
- return defineCommand("install", async (args, _ctx) => {
1616
+ return defineCommand2("install", async (args, _ctx) => {
1580
1617
  if (args.length === 0) {
1581
1618
  return {
1582
1619
  stdout: "",
@@ -1630,7 +1667,7 @@ Examples:
1630
1667
  }
1631
1668
  function createUninstallCommand(deps) {
1632
1669
  const { fs } = deps;
1633
- return defineCommand("uninstall", async (args, _ctx) => {
1670
+ return defineCommand2("uninstall", async (args, _ctx) => {
1634
1671
  if (args.length === 0) {
1635
1672
  return {
1636
1673
  stdout: "",
@@ -1675,7 +1712,7 @@ function createUninstallCommand(deps) {
1675
1712
  }
1676
1713
  function createListCommand(deps) {
1677
1714
  const { fs } = deps;
1678
- return defineCommand("list", async (_args, _ctx) => {
1715
+ return defineCommand2("list", async (_args, _ctx) => {
1679
1716
  try {
1680
1717
  const packages = await listPackages(fs);
1681
1718
  if (packages.length === 0) {
@@ -1705,9 +1742,11 @@ function createListCommand(deps) {
1705
1742
  }
1706
1743
  });
1707
1744
  }
1745
+ // src/commands/run.ts
1746
+ import { defineCommand as defineCommand3 } from "just-bash/browser";
1708
1747
  function createRunCommand(deps) {
1709
1748
  const { fs, libFiles, tsconfigPath, runOptions = {}, sharedModules } = deps;
1710
- return defineCommand("run", async (args, _ctx) => {
1749
+ return defineCommand3("run", async (args, _ctx) => {
1711
1750
  let entryPoint = null;
1712
1751
  let skipTypecheck = runOptions.skipTypecheck ?? false;
1713
1752
  let timeout = runOptions.timeout ?? 30000;
@@ -1884,6 +1923,7 @@ ${err.stack}` : "";
1884
1923
  }
1885
1924
  });
1886
1925
  }
1926
+ // src/commands/index.ts
1887
1927
  function createDefaultCommands(deps) {
1888
1928
  return [
1889
1929
  createTscCommand(deps),
@@ -1897,9 +1937,7 @@ function createDefaultCommands(deps) {
1897
1937
  // src/build-emitter.ts
1898
1938
  class BuildEmitter {
1899
1939
  listeners = new Set;
1900
- lastResult = null;
1901
1940
  emit = async (result) => {
1902
- this.lastResult = result;
1903
1941
  const promises = [];
1904
1942
  for (const listener of this.listeners) {
1905
1943
  const ret = listener(result);
@@ -1915,20 +1953,6 @@ class BuildEmitter {
1915
1953
  this.listeners.delete(callback);
1916
1954
  };
1917
1955
  }
1918
- waitFor() {
1919
- if (this.lastResult) {
1920
- const result = this.lastResult;
1921
- this.lastResult = null;
1922
- return Promise.resolve(result);
1923
- }
1924
- return new Promise((resolve) => {
1925
- const unsub = this.on((result) => {
1926
- unsub();
1927
- this.lastResult = null;
1928
- resolve(result);
1929
- });
1930
- });
1931
- }
1932
1956
  }
1933
1957
  export {
1934
1958
  revokeModuleUrl,
@@ -0,0 +1,314 @@
1
+ /**
2
+ * High-level runner for sandbox-based agent workflows.
3
+ *
4
+ * Provides simple wrappers that handle sandbox creation and build result capture,
5
+ * letting the caller focus on their agent logic.
6
+ */
7
+ import { type Sandbox, type SandboxOptions } from "./sandbox";
8
+ import type { BundleResult } from "./bundler";
9
+ /**
10
+ * Options for building with a sandbox (one-off usage).
11
+ */
12
+ export interface BuildWithSandboxOptions<T> {
13
+ /**
14
+ * Existing sandbox to use. If not provided, a new sandbox is created.
15
+ *
16
+ * Use this when you want to:
17
+ * - Reuse a sandbox across multiple builds
18
+ * - Pre-configure the sandbox with specific files or settings
19
+ * - Share a sandbox between different operations
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * const sandbox = await createSandbox({
24
+ * initialFiles: { '/src/index.ts': 'export const x = 1;' },
25
+ * });
26
+ *
27
+ * const result = await buildWithSandbox({
28
+ * sandbox,
29
+ * build: async (sb) => { ... },
30
+ * });
31
+ * ```
32
+ */
33
+ sandbox?: Sandbox;
34
+ /**
35
+ * Options for creating a new sandbox (only used if `sandbox` is not provided).
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * const result = await buildWithSandbox({
40
+ * sandboxOptions: {
41
+ * initialFiles: { '/src/index.ts': 'export const x = 1;' },
42
+ * sharedModules: ['react', 'react-dom/client'],
43
+ * },
44
+ * build: async (sandbox) => { ... },
45
+ * });
46
+ * ```
47
+ */
48
+ sandboxOptions?: SandboxOptions;
49
+ /**
50
+ * The function to run with the sandbox.
51
+ *
52
+ * This receives the sandbox and can do anything with it—run bash commands,
53
+ * write files, execute an agent loop, etc.
54
+ *
55
+ * The return value becomes `result` in the output.
56
+ *
57
+ * @example
58
+ * ```ts
59
+ * const { result, bundle } = await buildWithSandbox({
60
+ * build: async (sandbox) => {
61
+ * await sandbox.bash.exec('echo "hello" > /test.txt');
62
+ * const buildResult = await sandbox.bash.exec('build /src/index.ts');
63
+ * return { buildExitCode: buildResult.exitCode };
64
+ * },
65
+ * });
66
+ * ```
67
+ */
68
+ build: (sandbox: Sandbox) => Promise<T>;
69
+ }
70
+ /**
71
+ * Result of building with a sandbox.
72
+ */
73
+ export interface BuildResult<T> {
74
+ /**
75
+ * Whatever the `build` function returned, or `undefined` if it threw.
76
+ */
77
+ result: T | undefined;
78
+ /**
79
+ * The error thrown by the `build` function, or `null` if it succeeded.
80
+ *
81
+ * When an error occurs, the bundle and module may still be available
82
+ * if a build succeeded before the error was thrown.
83
+ */
84
+ error: Error | null;
85
+ /**
86
+ * The last successful build result, or null if no build succeeded.
87
+ *
88
+ * This captures the bundle from any successful `build` command executed
89
+ * during the run. If multiple builds succeed, this contains the last one.
90
+ *
91
+ * **Important**: This is available even if the `build` function threw an error,
92
+ * as long as a build succeeded before the error occurred.
93
+ */
94
+ bundle: BundleResult | null;
95
+ /**
96
+ * The loaded module exports, or null if no bundle or loading failed.
97
+ *
98
+ * When a build succeeds, the bundle is automatically loaded and the
99
+ * exports are available here. Use type assertions or runtime checks
100
+ * to access specific exports.
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * const run = await buildWithSandbox({ build: myAgent });
105
+ *
106
+ * if (run.module) {
107
+ * const App = run.module.App as React.ComponentType;
108
+ * return <App />;
109
+ * }
110
+ * ```
111
+ */
112
+ module: Record<string, unknown> | null;
113
+ /**
114
+ * Error that occurred while loading the module, or null if loading succeeded.
115
+ *
116
+ * This is separate from `error` (agent error) to distinguish:
117
+ * - Agent failed → `error` is set, `module` may still be available
118
+ * - Agent succeeded but load failed → `moduleError` is set
119
+ * - No bundle produced → both `module` and `moduleError` are null
120
+ */
121
+ moduleError: Error | null;
122
+ /**
123
+ * The sandbox that was used.
124
+ *
125
+ * Useful when the wrapper created an ephemeral sandbox—you can inspect
126
+ * its state, save it, or reuse it for another build.
127
+ */
128
+ sandbox: Sandbox;
129
+ }
130
+ /**
131
+ * Build with a sandbox, automatically capturing build results.
132
+ *
133
+ * This is the recommended way to use sandlot for one-off builds. It:
134
+ * 1. Creates a sandbox (or uses one you provide)
135
+ * 2. Sets up build result capture
136
+ * 3. Runs your function
137
+ * 4. Returns everything: your result, the bundle (if any), and the sandbox
138
+ *
139
+ * For reusable agent workflows, see `createBuilder()` which wraps this
140
+ * function and adds prompt support.
141
+ *
142
+ * The caller handles their own timeout/cancellation logic—this wrapper
143
+ * stays minimal and doesn't impose opinions on error handling.
144
+ *
145
+ * @example Basic usage with an agent
146
+ * ```ts
147
+ * import { buildWithSandbox } from 'sandlot';
148
+ *
149
+ * const run = await buildWithSandbox({
150
+ * build: async (sandbox) => {
151
+ * const agent = new MyAgent({
152
+ * tools: {
153
+ * bash: (command: string) => sandbox.bash.exec(command),
154
+ * },
155
+ * });
156
+ *
157
+ * return agent.run('Create a React component that shows "Hello"');
158
+ * },
159
+ * });
160
+ *
161
+ * // Module is auto-loaded if build succeeded
162
+ * if (run.module) {
163
+ * const App = run.module.App as React.ComponentType;
164
+ * return <App />;
165
+ * }
166
+ * ```
167
+ *
168
+ * @example Handling all failure modes
169
+ * ```ts
170
+ * const run = await buildWithSandbox({
171
+ * build: async (sandbox) => myAgent.run('...'),
172
+ * });
173
+ *
174
+ * // Check what happened
175
+ * if (run.error) {
176
+ * console.log('Agent failed:', run.error.message);
177
+ * }
178
+ * if (run.moduleError) {
179
+ * console.log('Module failed to load:', run.moduleError.message);
180
+ * }
181
+ *
182
+ * // Module available even if agent errored (if build succeeded first)
183
+ * if (run.module) {
184
+ * const App = run.module.App as React.ComponentType;
185
+ * return <App />;
186
+ * }
187
+ *
188
+ * // No module - check why
189
+ * if (!run.bundle) {
190
+ * console.log('No build was produced');
191
+ * }
192
+ * ```
193
+ */
194
+ export declare function buildWithSandbox<T>(options: BuildWithSandboxOptions<T>): Promise<BuildResult<T>>;
195
+ /**
196
+ * Options for creating a reusable builder function.
197
+ */
198
+ export interface CreateBuilderOptions<T> {
199
+ /**
200
+ * Existing sandbox to reuse across all calls.
201
+ *
202
+ * When provided, the same sandbox is used for every call to the returned
203
+ * builder function. Files and state persist between runs—useful for
204
+ * iterative workflows where you want to build on previous work.
205
+ *
206
+ * @example
207
+ * ```ts
208
+ * const sandbox = await createSandbox({
209
+ * initialFiles: { '/src/utils.ts': 'export const PI = 3.14;' },
210
+ * });
211
+ *
212
+ * const runAgent = createBuilder({
213
+ * sandbox, // Reused across all calls
214
+ * build: async (sb, prompt) => myAgent.run(sb, prompt),
215
+ * });
216
+ *
217
+ * await runAgent("Create a circle component"); // Uses existing utils.ts
218
+ * await runAgent("Add a square component"); // Still has circle + utils
219
+ * ```
220
+ */
221
+ sandbox?: Sandbox;
222
+ /**
223
+ * Options for creating fresh sandboxes (only used if `sandbox` is not provided).
224
+ *
225
+ * Each call to the returned builder function creates a new sandbox with
226
+ * these options. Use this when you want isolated runs.
227
+ *
228
+ * @example
229
+ * ```ts
230
+ * const runAgent = createBuilder({
231
+ * sandboxOptions: {
232
+ * sharedModules: ['react', 'react-dom/client'],
233
+ * },
234
+ * build: async (sandbox, prompt) => myAgent.run(sandbox, prompt),
235
+ * });
236
+ *
237
+ * // Each call gets a fresh sandbox
238
+ * await runAgent("Create a counter"); // Fresh sandbox
239
+ * await runAgent("Create a todo list"); // Another fresh sandbox
240
+ * ```
241
+ */
242
+ sandboxOptions?: SandboxOptions;
243
+ /**
244
+ * The function to build with the sandbox and prompt.
245
+ *
246
+ * This receives the sandbox and the prompt string, and should return
247
+ * whatever result your agent produces.
248
+ *
249
+ * @example
250
+ * ```ts
251
+ * const runAgent = createBuilder({
252
+ * build: async (sandbox, prompt) => {
253
+ * const agent = new MyAgent({
254
+ * tools: { bash: sandbox.bash.exec },
255
+ * });
256
+ * return agent.run(prompt);
257
+ * },
258
+ * });
259
+ * ```
260
+ */
261
+ build: (sandbox: Sandbox, prompt: string) => Promise<T>;
262
+ }
263
+ /**
264
+ * Create a reusable builder function for running prompts in a sandbox.
265
+ *
266
+ * This wraps `buildWithSandbox()` to create a convenient function that
267
+ * just takes a prompt. Define your agent logic once, then call it with
268
+ * different prompts.
269
+ *
270
+ * **Sandbox behavior:**
271
+ * - If you provide `sandbox`: The same sandbox is reused for every call
272
+ * (files persist, good for iteration)
273
+ * - If you provide `sandboxOptions` (or nothing): A fresh sandbox is created
274
+ * for each call (isolated runs)
275
+ *
276
+ * @example Basic usage
277
+ * ```ts
278
+ * import { createBuilder } from 'sandlot';
279
+ *
280
+ * const runAgent = createBuilder({
281
+ * sandboxOptions: { sharedModules: ['react', 'react-dom/client'] },
282
+ * build: async (sandbox, prompt) => {
283
+ * const agent = new MyAgent({ tools: { bash: sandbox.bash.exec } });
284
+ * return agent.run(prompt);
285
+ * },
286
+ * });
287
+ *
288
+ * // Use it multiple times with different prompts
289
+ * const result1 = await runAgent("Create a counter component");
290
+ * const result2 = await runAgent("Create a todo list");
291
+ *
292
+ * if (result1.module?.App) {
293
+ * const Counter = result1.module.App as React.ComponentType;
294
+ * }
295
+ * ```
296
+ *
297
+ * @example Iterative workflow with shared sandbox
298
+ * ```ts
299
+ * const sandbox = await createSandbox();
300
+ *
301
+ * const runAgent = createBuilder({
302
+ * sandbox, // Same sandbox for all calls
303
+ * build: async (sb, prompt) => myAgent.run(sb, prompt),
304
+ * });
305
+ *
306
+ * // First prompt creates initial component
307
+ * await runAgent("Create a button component");
308
+ *
309
+ * // Second prompt can build on the first
310
+ * await runAgent("Add a click counter to the button");
311
+ * ```
312
+ */
313
+ export declare function createBuilder<T>(options: CreateBuilderOptions<T>): (prompt: string) => Promise<BuildResult<T>>;
314
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAiB,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAC7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAG9C;;GAEG;AACH,MAAM,WAAW,uBAAuB,CAAC,CAAC;IACxC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;;;;;;;;OAaG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAEhC;;;;;;;;;;;;;;;;;;OAkBG;IACH,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;CACzC;AAED;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B;;OAEG;IACH,MAAM,EAAE,CAAC,GAAG,SAAS,CAAC;IAEtB;;;;;OAKG;IACH,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAEpB;;;;;;;;OAQG;IACH,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAE5B;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAEvC;;;;;;;OAOG;IACH,WAAW,EAAE,KAAK,GAAG,IAAI,CAAC;IAE1B;;;;;OAKG;IACH,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EACtC,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,GAClC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAsCzB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB,CAAC,CAAC;IACrC;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAEhC;;;;;;;;;;;;;;;;;OAiBG;IACH,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;CACzD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC7B,OAAO,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAC/B,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAW7C"}