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.
- package/README.md +138 -408
- package/dist/build-emitter.d.ts +31 -13
- package/dist/build-emitter.d.ts.map +1 -1
- package/dist/builder.d.ts +370 -0
- package/dist/builder.d.ts.map +1 -0
- package/dist/bundler.d.ts +1 -1
- package/dist/bundler.d.ts.map +1 -1
- package/dist/commands/compile.d.ts +13 -0
- package/dist/commands/compile.d.ts.map +1 -0
- package/dist/commands/index.d.ts +17 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/packages.d.ts +17 -0
- package/dist/commands/packages.d.ts.map +1 -0
- package/dist/commands/run.d.ts +40 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/types.d.ts +141 -0
- package/dist/commands/types.d.ts.map +1 -0
- package/dist/fs.d.ts +53 -49
- package/dist/fs.d.ts.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +249 -427
- package/dist/internal.js +111 -87
- package/dist/runner.d.ts +314 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/sandbox-manager.d.ts +45 -21
- package/dist/sandbox-manager.d.ts.map +1 -1
- package/dist/sandbox.d.ts +144 -62
- package/dist/sandbox.d.ts.map +1 -1
- package/dist/shared-modules.d.ts +22 -3
- package/dist/shared-modules.d.ts.map +1 -1
- package/dist/shared-resources.d.ts +0 -3
- package/dist/shared-resources.d.ts.map +1 -1
- package/dist/typechecker.d.ts +1 -1
- package/package.json +2 -11
- package/src/build-emitter.ts +32 -29
- package/src/builder.ts +498 -0
- package/src/bundler.ts +24 -36
- package/src/commands/compile.ts +236 -0
- package/src/commands/index.ts +51 -0
- package/src/commands/packages.ts +154 -0
- package/src/commands/run.ts +245 -0
- package/src/commands/types.ts +172 -0
- package/src/fs.ts +82 -221
- package/src/index.ts +17 -12
- package/src/sandbox.ts +217 -149
- package/src/shared-modules.ts +74 -4
- package/src/shared-resources.ts +0 -3
- package/src/typechecker.ts +1 -1
- package/dist/react.d.ts +0 -159
- package/dist/react.d.ts.map +0 -1
- package/dist/react.js +0 -149
- package/src/commands.ts +0 -733
- 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.
|
|
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
|
|
1266
|
-
|
|
1267
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,
|
package/dist/runner.d.ts
ADDED
|
@@ -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"}
|