feat(release): publish execution, cli, and kernel packages to npm
Unified · Split
| @@ -2,20 +2,33 @@ · 1 unmodified line | ||
| 2 | 2 | "$schema": "https://unpkg.com/@changesets/config@3.1.3/schema.json", |
| 3 | 3 | "changelog": false, |
| 4 | 4 | "commit": false, |
| 5 | − "fixed": [], | |
| 5 | + "fixed": [ | |
| 6 | + [ | |
| 7 | + "@executor/sdk", | |
| 8 | + "@executor/storage-core", | |
| 9 | + "@executor/codemode-core", | |
| 10 | + "@executor/runtime-quickjs", | |
| 11 | + "@executor/execution", | |
| 12 | + "@executor/cli", | |
| 13 | + "@executor/plugin-file-secrets", | |
| 14 | + "@executor/plugin-google-discovery", | |
| 15 | + "@executor/plugin-graphql", | |
| 16 | + "@executor/plugin-keychain", | |
| 17 | + "@executor/plugin-mcp", | |
| 18 | + "@executor/plugin-onepassword", | |
| 19 | + "@executor/plugin-openapi" | |
| 20 | + ] | |
| 21 | + ], | |
| 6 | 22 | "linked": [], |
| 7 | 23 | "access": "public", |
| 8 | 24 | "baseBranch": "main", |
| 9 | 25 | "updateInternalDependencies": "patch", |
| 10 | 26 | "ignore": [ |
| 11 | 27 | "@executor/local", |
| 12 | − "@executor/execution", | |
| 13 | 28 | "@executor/storage-file", |
| 14 | 29 | "@executor/host-mcp", |
| 15 | − "@executor/codemode-core", | |
| 16 | 30 | "@executor/ir", |
| 17 | 31 | "@executor/runtime-deno-subprocess", |
| 18 | − "@executor/runtime-quickjs", | |
| 19 | 32 | "@executor/marketing", |
| 20 | 33 | "@executor/runtime-dynamic-worker", |
| 21 | 34 | "@executor/runtime-secure-exec", |
| @@ -23,14 +36,6 @@ · 1 unmodified line | ||
| 23 | 36 | "@executor/api", |
| 24 | 37 | "@executor/config", |
| 25 | 38 | "@executor/storage-postgres", |
| 26 | − "@executor/sdk", | |
| 27 | − "@executor/plugin-file-secrets", | |
| 28 | − "@executor/plugin-google-discovery", | |
| 29 | − "@executor/plugin-graphql", | |
| 30 | − "@executor/plugin-keychain", | |
| 31 | − "@executor/plugin-mcp", | |
| 32 | − "@executor/plugin-onepassword", | |
| 33 | − "@executor/plugin-openapi", | |
| 34 | 39 | "@executor/plugin-workos-vault", |
| 35 | 40 | "@executor/example-promise-sdk" |
| 36 | 41 | ] |
| @@ -41,6 +41,7 @@ import * as Cause from "effect/Cause"; · 40 unmodified lines | ||
| 41 | 41 | |
| 42 | 42 | import { ExecutorApi } from "@executor/api"; |
| 43 | 43 | import { startServer, runMcpStdioServer, getExecutor } from "@executor/local"; |
| 44 | +import { makeQuickJsExecutor } from "@executor/runtime-quickjs"; | |
| 44 | 45 | |
| 45 | 46 | // Embedded web UI — baked into compiled binaries via `with { type: "file" }` |
| 46 | 47 | import embeddedWebUI from "./embedded-web-ui.gen"; |
| @@ -154,7 +155,9 @@ const runForegroundSession = (input: { · 107 unmodified lines | ||
| 154 | 155 | const runStdioMcpSession = () => |
| 155 | 156 | Effect.gen(function* () { |
| 156 | 157 | const executor = yield* Effect.promise(() => getExecutor()); |
| 157 | − yield* Effect.promise(() => runMcpStdioServer({ executor })); | |
| 158 | + yield* Effect.promise(() => | |
| 159 | + runMcpStdioServer({ executor, codeExecutor: makeQuickJsExecutor() }), | |
| 160 | + ); | |
| 158 | 161 | }); |
| 159 | 162 | |
| 160 | 163 | // --------------------------------------------------------------------------- |
| @@ -38,6 +38,7 @@ · 37 unmodified lines | ||
| 38 | 38 | "@executor/plugin-workos-vault": "workspace:*", |
| 39 | 39 | "@executor/react": "workspace:*", |
| 40 | 40 | "@executor/runtime-dynamic-worker": "workspace:*", |
| 41 | + "@executor/runtime-quickjs": "workspace:*", | |
| 41 | 42 | "@executor/sdk": "workspace:*", |
| 42 | 43 | "@executor/storage-core": "workspace:*", |
| 43 | 44 | "@executor/storage-postgres": "workspace:*", |
| @@ -23,6 +23,7 @@ import type { ClientCapabilities } from "@modelcontextprotocol/sdk/types.js"; · 22 unmodified lines | ||
| 23 | 23 | |
| 24 | 24 | import { createExecutorMcpServer } from "@executor/host-mcp"; |
| 25 | 25 | import { createExecutionEngine } from "@executor/execution"; |
| 26 | +import { makeQuickJsExecutor } from "@executor/runtime-quickjs"; | |
| 26 | 27 | import { |
| 27 | 28 | ElicitationResponse, |
| 28 | 29 | FormElicitation, |
| @@ -134,7 +135,7 @@ const openSession = ( · 105 unmodified lines | ||
| 134 | 135 | Effect.acquireRelease( |
| 135 | 136 | Effect.gen(function* () { |
| 136 | 137 | const executor = yield* buildScopedExecutor(orgId, `Org ${orgId}`, options); |
| 137 | − const engine = createExecutionEngine({ executor }); | |
| 138 | + const engine = createExecutionEngine({ executor, codeExecutor: makeQuickJsExecutor() }); | |
| 138 | 139 | const mcpServer = yield* Effect.promise(() => createExecutorMcpServer({ engine })); |
| 139 | 140 | const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); |
| 140 | 141 | const client = new Client( |
| @@ -31,6 +31,7 @@ import { · 30 unmodified lines | ||
| 31 | 31 | ExecutorService, |
| 32 | 32 | } from "@executor/api/server"; |
| 33 | 33 | import { createExecutionEngine } from "@executor/execution"; |
| 34 | +import { makeQuickJsExecutor } from "@executor/runtime-quickjs"; | |
| 34 | 35 | import { |
| 35 | 36 | Scope, |
| 36 | 37 | ScopeId, |
| @@ -215,7 +216,7 @@ const TestApiLive = HttpApiBuilder.api(ProtectedCloudApi).pipe( · 178 unmodified lines | ||
| 215 | 216 | const buildAppForScope = (scopeId: string, scopeName: string) => |
| 216 | 217 | Effect.gen(function* () { |
| 217 | 218 | const executor = yield* createTestScopedExecutor(scopeId, scopeName); |
| 218 | − const engine = createExecutionEngine({ executor }); | |
| 219 | + const engine = createExecutionEngine({ executor, codeExecutor: makeQuickJsExecutor() }); | |
| 219 | 220 | const services = Layer.mergeAll( |
| 220 | 221 | Layer.succeed(ExecutorService, executor), |
| 221 | 222 | Layer.succeed(ExecutionEngineService, engine), |
| @@ -33,6 +33,7 @@ · 32 unmodified lines | ||
| 33 | 33 | "@executor/plugin-onepassword": "workspace:*", |
| 34 | 34 | "@executor/plugin-openapi": "workspace:*", |
| 35 | 35 | "@executor/react": "workspace:*", |
| 36 | + "@executor/runtime-quickjs": "workspace:*", | |
| 36 | 37 | "@executor/sdk": "workspace:*", |
| 37 | 38 | "@executor/storage-file": "workspace:*", |
| 38 | 39 | "@modelcontextprotocol/sdk": "^1.12.1", |
| @@ -10,6 +10,7 @@ import { Context, Effect, Layer, ManagedRuntime } from "effect"; · 9 unmodified lines | ||
| 10 | 10 | import { addGroup } from "@executor/api"; |
| 11 | 11 | import { CoreHandlers, ExecutorService, ExecutionEngineService } from "@executor/api/server"; |
| 12 | 12 | import { createExecutionEngine } from "@executor/execution"; |
| 13 | +import { makeQuickJsExecutor } from "@executor/runtime-quickjs"; | |
| 13 | 14 | import { |
| 14 | 15 | OpenApiGroup, |
| 15 | 16 | OpenApiHandlers, |
| @@ -78,7 +79,7 @@ const closeServerHandlers = async (handlers: ServerHandlers): Promise<void> => { · 62 unmodified lines | ||
| 78 | 79 | |
| 79 | 80 | export const createServerHandlers = async (): Promise<ServerHandlers> => { |
| 80 | 81 | const executor = await getExecutor(); |
| 81 | − const engine = createExecutionEngine({ executor }); | |
| 82 | + const engine = createExecutionEngine({ executor, codeExecutor: makeQuickJsExecutor() }); | |
| 82 | 83 | |
| 83 | 84 | const pluginExtensions = Layer.mergeAll( |
| 84 | 85 | Layer.succeed(OpenApiExtensionService, executor.openapi), |
| @@ -61,6 +61,7 @@ · 60 unmodified lines | ||
| 61 | 61 | "@executor/plugin-workos-vault": "workspace:*", |
| 62 | 62 | "@executor/react": "workspace:*", |
| 63 | 63 | "@executor/runtime-dynamic-worker": "workspace:*", |
| 64 | + "@executor/runtime-quickjs": "workspace:*", | |
| 64 | 65 | "@executor/sdk": "workspace:*", |
| 65 | 66 | "@executor/storage-core": "workspace:*", |
| 66 | 67 | "@executor/storage-postgres": "workspace:*", |
| @@ -139,6 +140,7 @@ · 72 unmodified lines | ||
| 139 | 140 | "@executor/plugin-onepassword": "workspace:*", |
| 140 | 141 | "@executor/plugin-openapi": "workspace:*", |
| 141 | 142 | "@executor/react": "workspace:*", |
| 143 | + "@executor/runtime-quickjs": "workspace:*", | |
| 142 | 144 | "@executor/sdk": "workspace:*", |
| 143 | 145 | "@executor/storage-file": "workspace:*", |
| 144 | 146 | "@modelcontextprotocol/sdk": "^1.12.1", |
| @@ -242,12 +244,13 @@ · 97 unmodified lines | ||
| 242 | 244 | "executor": "./dist/index.js", |
| 243 | 245 | }, |
| 244 | 246 | "dependencies": { |
| 245 | − "@executor/sdk": "workspace:*", | |
| 246 | − "@executor/storage-core": "workspace:*", | |
| 247 | 247 | "commander": "^12.1.0", |
| 248 | + "effect": "catalog:", | |
| 248 | 249 | "jiti": "^2.6.1", |
| 249 | 250 | }, |
| 250 | 251 | "devDependencies": { |
| 252 | + "@executor/sdk": "workspace:*", | |
| 253 | + "@executor/storage-core": "workspace:*", | |
| 251 | 254 | "@types/node": "catalog:", |
| 252 | 255 | "tsup": "catalog:", |
| 253 | 256 | "typescript": "catalog:", |
| @@ -284,17 +287,19 @@ · 30 unmodified lines | ||
| 284 | 287 | }, |
| 285 | 288 | "packages/core/execution": { |
| 286 | 289 | "name": "@executor/execution", |
| 287 | − "version": "1.4.3", | |
| 290 | + "version": "0.0.1", | |
| 288 | 291 | "dependencies": { |
| 289 | 292 | "@executor/codemode-core": "workspace:*", |
| 290 | − "@executor/runtime-quickjs": "workspace:*", | |
| 291 | 293 | "@executor/sdk": "workspace:*", |
| 292 | 294 | "effect": "catalog:", |
| 293 | 295 | }, |
| 294 | 296 | "devDependencies": { |
| 295 | 297 | "@effect/vitest": "catalog:", |
| 298 | + "@executor/runtime-quickjs": "workspace:*", | |
| 296 | 299 | "@types/node": "catalog:", |
| 297 | 300 | "bun-types": "catalog:", |
| 301 | + "tsup": "catalog:", | |
| 302 | + "typescript": "catalog:", | |
| 298 | 303 | "vitest": "catalog:", |
| 299 | 304 | }, |
| 300 | 305 | }, |
| @@ -315,16 +320,25 @@ · 14 unmodified lines | ||
| 315 | 320 | }, |
| 316 | 321 | "packages/core/storage-core": { |
| 317 | 322 | "name": "@executor/storage-core", |
| 318 | − "version": "0.0.0", | |
| 323 | + "version": "0.0.1", | |
| 319 | 324 | "dependencies": { |
| 320 | − "@effect/vitest": "catalog:", | |
| 321 | 325 | "@standard-schema/spec": "^1.0.0", |
| 322 | 326 | "effect": "catalog:", |
| 323 | − "vitest": "catalog:", | |
| 324 | 327 | }, |
| 325 | 328 | "devDependencies": { |
| 329 | + "@effect/vitest": "catalog:", | |
| 330 | + "tsup": "catalog:", | |
| 326 | 331 | "typescript": "catalog:", |
| 332 | + "vitest": "catalog:", | |
| 327 | 333 | }, |
| 334 | + "peerDependencies": { | |
| 335 | + "@effect/vitest": "catalog:", | |
| 336 | + "vitest": "catalog:", | |
| 337 | + }, | |
| 338 | + "optionalPeers": [ | |
| 339 | + "@effect/vitest", | |
| 340 | + "vitest", | |
| 341 | + ], | |
| 328 | 342 | }, |
| 329 | 343 | "packages/core/storage-drizzle": { |
| 330 | 344 | "name": "@executor/storage-drizzle", |
| @@ -397,7 +411,7 @@ · 66 unmodified lines | ||
| 397 | 411 | }, |
| 398 | 412 | "packages/kernel/core": { |
| 399 | 413 | "name": "@executor/codemode-core", |
| 400 | − "version": "1.4.3", | |
| 414 | + "version": "0.0.1", | |
| 401 | 415 | "dependencies": { |
| 402 | 416 | "@babel/parser": "^7.29.2", |
| 403 | 417 | "@standard-schema/spec": "^1.0.0", |
| @@ -408,6 +422,8 @@ · 4 unmodified lines | ||
| 408 | 422 | "devDependencies": { |
| 409 | 423 | "@types/node": "catalog:", |
| 410 | 424 | "bun-types": "catalog:", |
| 425 | + "tsup": "catalog:", | |
| 426 | + "typescript": "catalog:", | |
| 411 | 427 | "vitest": "catalog:", |
| 412 | 428 | }, |
| 413 | 429 | }, |
| @@ -455,7 +471,7 @@ · 41 unmodified lines | ||
| 455 | 471 | }, |
| 456 | 472 | "packages/kernel/runtime-quickjs": { |
| 457 | 473 | "name": "@executor/runtime-quickjs", |
| 458 | − "version": "1.4.3", | |
| 474 | + "version": "0.0.1", | |
| 459 | 475 | "dependencies": { |
| 460 | 476 | "@executor/codemode-core": "workspace:*", |
| 461 | 477 | "effect": "catalog:", |
| @@ -465,6 +481,8 @@ · 3 unmodified lines | ||
| 465 | 481 | "@effect/vitest": "catalog:", |
| 466 | 482 | "@types/node": "catalog:", |
| 467 | 483 | "bun-types": "catalog:", |
| 484 | + "tsup": "catalog:", | |
| 485 | + "typescript": "catalog:", | |
| 468 | 486 | "vitest": "catalog:", |
| 469 | 487 | }, |
| 470 | 488 | }, |
| @@ -33,7 +33,7 @@ · 32 unmodified lines | ||
| 33 | 33 | "dev:cli": "bun run apps/cli/src/main.ts", |
| 34 | 34 | "test": "turbo run test", |
| 35 | 35 | "test:release:bootstrap": "vitest run tests/release-bootstrap-smoke.test.ts", |
| 36 | − "build:packages": "bun run --filter='@executor/sdk' build && bun run --filter='@executor/plugin-*' build", | |
| 36 | + "build:packages": "bun run --filter='@executor/storage-core' build && bun run --filter='@executor/codemode-core' build && bun run --filter='@executor/runtime-quickjs' build && bun run --filter='@executor/sdk' build && bun run --filter='@executor/execution' build && bun run --filter='@executor/cli' build && bun run --filter='@executor/plugin-*' build", | |
| 37 | 37 | "typecheck": "turbo run typecheck", |
| 38 | 38 | "typecheck:slow": "turbo run typecheck:slow", |
| 39 | 39 | "ci": "bun run lint && bun run typecheck && bun run test", |
| @@ -0,0 +1,57 @@ | ||
| 1 | +# @executor/cli | |
| 2 | + | |
| 3 | +Command-line tool for `@executor/sdk` projects. Generates Drizzle schema files from the plugins registered in your `executor.config.ts` so database migrations stay in sync with the executor you actually run. | |
| 4 | + | |
| 5 | +## Install | |
| 6 | + | |
| 7 | +```sh | |
| 8 | +bun add -d @executor/cli | |
| 9 | +# or | |
| 10 | +npm install --save-dev @executor/cli | |
| 11 | +``` | |
| 12 | + | |
| 13 | +The binary is installed as `executor`. | |
| 14 | + | |
| 15 | +## Quick start | |
| 16 | + | |
| 17 | +Create an `executor.config.ts` alongside your app code: | |
| 18 | + | |
| 19 | +```ts | |
| 20 | +import { defineExecutorConfig } from "@executor/sdk"; | |
| 21 | +import { mcpPlugin } from "@executor/plugin-mcp"; | |
| 22 | +import { openApiPlugin } from "@executor/plugin-openapi"; | |
| 23 | + | |
| 24 | +export default defineExecutorConfig({ | |
| 25 | + dialect: "postgres", | |
| 26 | + plugins: [mcpPlugin(), openApiPlugin()], | |
| 27 | +}); | |
| 28 | +``` | |
| 29 | + | |
| 30 | +Then generate a Drizzle schema from it: | |
| 31 | + | |
| 32 | +```sh | |
| 33 | +bunx executor generate --output ./src/db/executor-schema.ts | |
| 34 | +# or | |
| 35 | +npx executor generate --output ./src/db/executor-schema.ts | |
| 36 | +``` | |
| 37 | + | |
| 38 | +The generator walks every plugin in the config, collects their schema contributions, and emits a single Drizzle schema file ready to hand to `drizzle-kit`. | |
| 39 | + | |
| 40 | +## Commands | |
| 41 | + | |
| 42 | +``` | |
| 43 | +executor generate [options] | |
| 44 | + --cwd <dir> Project directory (default: cwd) | |
| 45 | + --config <path> Path to executor.config.ts (default: auto-discover) | |
| 46 | + --output <path> Output file for the generated schema | |
| 47 | +``` | |
| 48 | + | |
| 49 | +Run `executor --help` to see the current command list. | |
| 50 | + | |
| 51 | +## Status | |
| 52 | + | |
| 53 | +Pre-`1.0`. APIs may still change between beta releases. Part of the [executor monorepo](https://github.com/RhysSullivan/executor). | |
| 54 | + | |
| 55 | +## License | |
| 56 | + | |
| 57 | +MIT | |
| @@ -2,7 +2,16 @@ · 1 unmodified line | ||
| 2 | 2 | "name": "@executor/cli", |
| 3 | 3 | "version": "0.0.1", |
| 4 | 4 | "description": "CLI for the executor SDK — schema generation, migrations", |
| 5 | + "homepage": "https://github.com/RhysSullivan/executor/tree/main/packages/core/cli", | |
| 6 | + "bugs": { | |
| 7 | + "url": "https://github.com/RhysSullivan/executor/issues" | |
| 8 | + }, | |
| 5 | 9 | "license": "MIT", |
| 10 | + "repository": { | |
| 11 | + "type": "git", | |
| 12 | + "url": "git+https://github.com/RhysSullivan/executor.git", | |
| 13 | + "directory": "packages/core/cli" | |
| 14 | + }, | |
| 6 | 15 | "type": "module", |
| 7 | 16 | "bin": { |
| 8 | 17 | "executor": "./dist/index.js" |
| @@ -13,19 +22,31 @@ · 4 unmodified lines | ||
| 13 | 22 | "exports": { |
| 14 | 23 | ".": "./src/index.ts" |
| 15 | 24 | }, |
| 25 | + "publishConfig": { | |
| 26 | + "access": "public", | |
| 27 | + "exports": { | |
| 28 | + ".": { | |
| 29 | + "import": { | |
| 30 | + "types": "./dist/index.d.ts", | |
| 31 | + "default": "./dist/index.js" | |
| 32 | + } | |
| 33 | + } | |
| 34 | + } | |
| 35 | + }, | |
| 16 | 36 | "scripts": { |
| 17 | − "build": "tsup src/index.ts --format esm --dts", | |
| 37 | + "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | |
| 18 | 38 | "dev": "node --import jiti/register src/index.ts", |
| 19 | 39 | "test": "vitest run", |
| 20 | 40 | "typecheck": "tsc --noEmit" |
| 21 | 41 | }, |
| 22 | 42 | "dependencies": { |
| 23 | − "@executor/sdk": "workspace:*", | |
| 24 | − "@executor/storage-core": "workspace:*", | |
| 25 | 43 | "commander": "^12.1.0", |
| 44 | + "effect": "catalog:", | |
| 26 | 45 | "jiti": "^2.6.1" |
| 27 | 46 | }, |
| 28 | 47 | "devDependencies": { |
| 48 | + "@executor/sdk": "workspace:*", | |
| 49 | + "@executor/storage-core": "workspace:*", | |
| 29 | 50 | "@types/node": "catalog:", |
| 30 | 51 | "tsup": "catalog:", |
| 31 | 52 | "typescript": "catalog:", |
| @@ -2,7 +2,7 @@ import { existsSync } from "node:fs"; · 1 unmodified line | ||
| 2 | 2 | import fs from "node:fs/promises"; |
| 3 | 3 | import path from "node:path"; |
| 4 | 4 | import { Command } from "commander"; |
| 5 | −import { collectSchemas } from "@executor/sdk"; | |
| 5 | +import { collectSchemas } from "@executor/sdk/core"; | |
| 6 | 6 | import { getConfig } from "../utils/get-config.js"; |
| 7 | 7 | import { generateDrizzleSchema } from "../generators/drizzle.js"; |
| 8 | 8 | |
| @@ -1,5 +1,5 @@ | ||
| 1 | 1 | import type { DBSchema } from "@executor/storage-core"; |
| 2 | −import type { ExecutorDialect } from "@executor/sdk"; | |
| 2 | +import type { ExecutorDialect } from "@executor/sdk/core"; | |
| 3 | 3 | |
| 4 | 4 | export interface SchemaGeneratorResult { |
| 5 | 5 | code?: string; |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | import { existsSync } from "node:fs"; |
| 2 | 2 | import path from "node:path"; |
| 3 | 3 | import { createJiti } from "jiti"; |
| 4 | −import type { ExecutorCliConfig } from "@executor/sdk"; | |
| 4 | +import type { ExecutorCliConfig } from "@executor/sdk/core"; | |
| 5 | 5 | |
| 6 | 6 | const defaultPaths = [ |
| 7 | 7 | "executor.config.ts", |
| @@ -0,0 +1,17 @@ | ||
| 1 | +import { defineConfig } from "tsup"; | |
| 2 | + | |
| 3 | +export default defineConfig({ | |
| 4 | + entry: { | |
| 5 | + index: "src/index.ts", | |
| 6 | + }, | |
| 7 | + format: ["esm"], | |
| 8 | + dts: false, | |
| 9 | + sourcemap: true, | |
| 10 | + clean: true, | |
| 11 | + external: [ | |
| 12 | + /^effect/, | |
| 13 | + /^@effect\//, | |
| 14 | + "commander", | |
| 15 | + "jiti", | |
| 16 | + ], | |
| 17 | +}); | |
| @@ -0,0 +1,94 @@ | ||
| 1 | +# @executor/execution | |
| 2 | + | |
| 3 | +Sandboxed JavaScript execution for an executor. Hands a `tools.<namespace>.<name>(...)` proxy into a code sandbox so an agent (or any caller) can run generated TypeScript/JavaScript that invokes the executor's registered tools. | |
| 4 | + | |
| 5 | +Supports pause/resume for elicitation-driven flows: tools that need user input (OAuth, form fill, approval) suspend the sandbox, surface a `PausedExecution`, and resume on a `ResumeResponse`. | |
| 6 | + | |
| 7 | +## Install | |
| 8 | + | |
| 9 | +```sh | |
| 10 | +bun add @executor/sdk @executor/execution @executor/runtime-quickjs | |
| 11 | +# or | |
| 12 | +npm install @executor/sdk @executor/execution @executor/runtime-quickjs | |
| 13 | +``` | |
| 14 | + | |
| 15 | +`@executor/runtime-quickjs` is the sandbox runtime. It's not a dependency of `@executor/execution` — you bring your own so consumers with a different runtime don't ship ~13 MB of WASM they never use. | |
| 16 | + | |
| 17 | +## Usage | |
| 18 | + | |
| 19 | +```ts | |
| 20 | +import { createExecutor } from "@executor/sdk"; | |
| 21 | +import { createExecutionEngine } from "@executor/execution"; | |
| 22 | +import { makeQuickJsExecutor } from "@executor/runtime-quickjs"; | |
| 23 | + | |
| 24 | +const executor = await createExecutor({ | |
| 25 | + scope: { name: "my-app" }, | |
| 26 | +}); | |
| 27 | + | |
| 28 | +const engine = createExecutionEngine({ | |
| 29 | + executor, | |
| 30 | + codeExecutor: makeQuickJsExecutor({ | |
| 31 | + timeoutMs: 2_000, | |
| 32 | + memoryLimitBytes: 32 * 1024 * 1024, | |
| 33 | + }), | |
| 34 | +}); | |
| 35 | + | |
| 36 | +const result = await engine.execute( | |
| 37 | + ` | |
| 38 | + const pets = await tools.petstore.findPetsByStatus({ status: "available" }); | |
| 39 | + return pets.length; | |
| 40 | + `, | |
| 41 | + { | |
| 42 | + onElicitation: async (ctx) => { | |
| 43 | + // A tool asked for user input mid-execution. Your UI decides what to do. | |
| 44 | + console.log("tool needs input:", ctx.request); | |
| 45 | + return { action: "decline" }; | |
| 46 | + }, | |
| 47 | + }, | |
| 48 | +); | |
| 49 | + | |
| 50 | +console.log(result); | |
| 51 | +// { result: 12, logs: [...] } | |
| 52 | +``` | |
| 53 | + | |
| 54 | +## Pause/resume for elicitation | |
| 55 | + | |
| 56 | +When the host doesn't support inline elicitation, use `executeWithPause` to intercept the first request as a pause point: | |
| 57 | + | |
| 58 | +```ts | |
| 59 | +const started = await engine.executeWithPause(code); | |
| 60 | + | |
| 61 | +if (started.status === "paused") { | |
| 62 | + const { id, elicitationContext } = started.execution; | |
| 63 | + // Render the elicitation request in your UI. Later: | |
| 64 | + const resumed = await engine.resume(id, { | |
| 65 | + action: "accept", | |
| 66 | + content: { name: "Ada" }, | |
| 67 | + }); | |
| 68 | +} | |
| 69 | +``` | |
| 70 | + | |
| 71 | +## Workflow description for LLMs | |
| 72 | + | |
| 73 | +```ts | |
| 74 | +const docs = await engine.getDescription(); | |
| 75 | +// Returns the canonical "use tools.search(), then tools.describe.tool(), then call …" | |
| 76 | +// workflow prose + per-namespace tool listing. Feed this to an LLM so it knows | |
| 77 | +// how to drive the sandbox. | |
| 78 | +``` | |
| 79 | + | |
| 80 | +## Using with Effect | |
| 81 | + | |
| 82 | +If you're building on `@executor/sdk` (the raw Effect entry), import from the `/core` subpath. The returned engine is Effect-native: `execute`, `executeWithPause`, and `resume` all become `Effect.Effect<...>`, and `onElicitation` is an `ElicitationHandler` returning `Effect.Effect<ElicitationResponse>`. | |
| 83 | + | |
| 84 | +```ts | |
| 85 | +import { createExecutionEngine } from "@executor/execution"; | |
| 86 | +``` | |
| 87 | + | |
| 88 | +## Status | |
| 89 | + | |
| 90 | +Pre-`1.0`. APIs may still change between beta releases. Part of the [executor monorepo](https://github.com/RhysSullivan/executor). | |
| 91 | + | |
| 92 | +## License | |
| 93 | + | |
| 94 | +MIT | |
| @@ -1,26 +1,59 @@ | ||
| 1 | 1 | { |
| 2 | 2 | "name": "@executor/execution", |
| 3 | − "version": "1.4.3", | |
| 4 | − "private": true, | |
| 3 | + "version": "0.0.1", | |
| 4 | + "homepage": "https://github.com/RhysSullivan/executor/tree/main/packages/core/execution", | |
| 5 | + "bugs": { | |
| 6 | + "url": "https://github.com/RhysSullivan/executor/issues" | |
| 7 | + }, | |
| 8 | + "license": "MIT", | |
| 9 | + "repository": { | |
| 10 | + "type": "git", | |
| 11 | + "url": "git+https://github.com/RhysSullivan/executor.git", | |
| 12 | + "directory": "packages/core/execution" | |
| 13 | + }, | |
| 14 | + "files": [ | |
| 15 | + "dist" | |
| 16 | + ], | |
| 5 | 17 | "type": "module", |
| 6 | 18 | "exports": { |
| 7 | − ".": "./src/index.ts" | |
| 19 | + ".": "./src/index.ts", | |
| 20 | + "./promise": "./src/promise.ts" | |
| 21 | + }, | |
| 22 | + "publishConfig": { | |
| 23 | + "access": "public", | |
| 24 | + "exports": { | |
| 25 | + ".": { | |
| 26 | + "import": { | |
| 27 | + "types": "./dist/promise.d.ts", | |
| 28 | + "default": "./dist/index.js" | |
| 29 | + } | |
| 30 | + }, | |
| 31 | + "./core": { | |
| 32 | + "import": { | |
| 33 | + "types": "./dist/index.d.ts", | |
| 34 | + "default": "./dist/core.js" | |
| 35 | + } | |
| 36 | + } | |
| 37 | + } | |
| 8 | 38 | }, |
| 9 | 39 | "scripts": { |
| 40 | + "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | |
| 10 | 41 | "typecheck": "tsgo --noEmit", |
| 11 | 42 | "test": "vitest run", |
| 12 | 43 | "typecheck:slow": "bunx tsc --noEmit -p tsconfig.json" |
| 13 | 44 | }, |
| 14 | 45 | "dependencies": { |
| 15 | 46 | "@executor/codemode-core": "workspace:*", |
| 16 | − "@executor/runtime-quickjs": "workspace:*", | |
| 17 | 47 | "@executor/sdk": "workspace:*", |
| 18 | 48 | "effect": "catalog:" |
| 19 | 49 | }, |
| 20 | 50 | "devDependencies": { |
| 21 | 51 | "@effect/vitest": "catalog:", |
| 52 | + "@executor/runtime-quickjs": "workspace:*", | |
| 22 | 53 | "@types/node": "catalog:", |
| 23 | 54 | "bun-types": "catalog:", |
| 55 | + "tsup": "catalog:", | |
| 56 | + "typescript": "catalog:", | |
| 24 | 57 | "vitest": "catalog:" |
| 25 | 58 | } |
| 26 | 59 | } |
| @@ -8,7 +8,6 @@ import type { · 7 unmodified lines | ||
| 8 | 8 | ElicitationContext, |
| 9 | 9 | } from "@executor/sdk"; |
| 10 | 10 | import type { CodeExecutor, ExecuteResult, SandboxToolInvoker } from "@executor/codemode-core"; |
| 11 | −import { makeQuickJsExecutor } from "@executor/runtime-quickjs"; | |
| 12 | 11 | |
| 13 | 12 | import { |
| 14 | 13 | makeExecutorToolInvoker, |
| @@ -25,7 +24,7 @@ import { buildExecuteDescription } from "./description"; · 10 unmodified lines | ||
| 25 | 24 | |
| 26 | 25 | export type ExecutionEngineConfig = { |
| 27 | 26 | readonly executor: Executor; |
| 28 | − readonly codeExecutor?: CodeExecutor; | |
| 27 | + readonly codeExecutor: CodeExecutor; | |
| 29 | 28 | }; |
| 30 | 29 | |
| 31 | 30 | export type ExecutionResult = |
| @@ -292,8 +291,7 @@ const runEffect = <A>(effect: Effect.Effect<A, unknown>): Promise<A> => · 260 unmodified lines | ||
| 292 | 291 | Effect.runPromise(effect as Effect.Effect<A, never>); |
| 293 | 292 | |
| 294 | 293 | export const createExecutionEngine = (config: ExecutionEngineConfig): ExecutionEngine => { |
| 295 | − const { executor } = config; | |
| 296 | − const codeExecutor = config.codeExecutor ?? makeQuickJsExecutor(); | |
| 294 | + const { executor, codeExecutor } = config; | |
| 297 | 295 | const pausedExecutions = new Map<string, InternalPausedExecution>(); |
| 298 | 296 | let nextId = 0; |
| 299 | 297 | |
| @@ -0,0 +1,120 @@ | ||
| 1 | +// --------------------------------------------------------------------------- | |
| 2 | +// @executor/execution/promise — Promise-native surface for the execution | |
| 3 | +// engine. Accepts a Promise-style Executor (from @executor/sdk) and an | |
| 4 | +// async `onElicitation` handler — no Effect imports required by callers. | |
| 5 | +// | |
| 6 | +// Under the hood the engine is Effect-based, so we wrap the incoming | |
| 7 | +// Promise executor into the minimal Effect shape the engine consumes, | |
| 8 | +// and bridge the elicitation handler via `Effect.tryPromise`. | |
| 9 | +// --------------------------------------------------------------------------- | |
| 10 | + | |
| 11 | +import { Effect } from "effect"; | |
| 12 | + | |
| 13 | +import type { | |
| 14 | + ElicitationContext, | |
| 15 | + ElicitationResponse, | |
| 16 | + Executor as PromiseExecutor, | |
| 17 | +} from "@executor/sdk"; | |
| 18 | +import type { CodeExecutor, ExecuteResult } from "@executor/codemode-core"; | |
| 19 | + | |
| 20 | +import { | |
| 21 | + createExecutionEngine as createEffectExecutionEngine, | |
| 22 | + type ExecutionResult, | |
| 23 | + type PausedExecution, | |
| 24 | + type ResumeResponse, | |
| 25 | +} from "./engine"; | |
| 26 | + | |
| 27 | +export type ElicitationHandler = ( | |
| 28 | + ctx: ElicitationContext, | |
| 29 | +) => Promise<ElicitationResponse>; | |
| 30 | + | |
| 31 | +export type ExecutionEngineConfig = { | |
| 32 | + readonly executor: PromiseExecutor; | |
| 33 | + readonly codeExecutor: CodeExecutor; | |
| 34 | +}; | |
| 35 | + | |
| 36 | +export type ExecutionEngine = { | |
| 37 | + readonly execute: ( | |
| 38 | + code: string, | |
| 39 | + options: { readonly onElicitation: ElicitationHandler }, | |
| 40 | + ) => Promise<ExecuteResult>; | |
| 41 | + readonly executeWithPause: (code: string) => Promise<ExecutionResult>; | |
| 42 | + readonly resume: ( | |
| 43 | + executionId: string, | |
| 44 | + response: ResumeResponse, | |
| 45 | + ) => Promise<ExecutionResult | null>; | |
| 46 | + readonly getDescription: () => Promise<string>; | |
| 47 | +}; | |
| 48 | + | |
| 49 | +/** | |
| 50 | + * Wrap a Promise-style executor into the Effect shape the engine consumes. | |
| 51 | + * Only the four method families the engine actually touches need wrapping: | |
| 52 | + * `tools.{invoke,list,schema}` and `sources.list`. | |
| 53 | + */ | |
| 54 | +const wrapPromiseExecutor = (pe: PromiseExecutor): any => ({ | |
| 55 | + scope: (pe as any).scope, | |
| 56 | + tools: { | |
| 57 | + invoke: (id: unknown, args: unknown, options: unknown) => | |
| 58 | + Effect.tryPromise({ | |
| 59 | + try: () => (pe.tools as any).invoke(id, args, options), | |
| 60 | + catch: (cause) => cause, | |
| 61 | + }), | |
| 62 | + list: (filter?: unknown) => | |
| 63 | + Effect.tryPromise({ | |
| 64 | + try: () => (pe.tools as any).list(filter), | |
| 65 | + catch: (cause) => cause, | |
| 66 | + }).pipe(Effect.orDie), | |
| 67 | + schema: (id: unknown) => | |
| 68 | + Effect.tryPromise({ | |
| 69 | + try: () => (pe.tools as any).schema(id), | |
| 70 | + catch: (cause) => cause, | |
| 71 | + }), | |
| 72 | + definitions: () => | |
| 73 | + Effect.tryPromise({ | |
| 74 | + try: () => (pe.tools as any).definitions(), | |
| 75 | + catch: (cause) => cause, | |
| 76 | + }).pipe(Effect.orDie), | |
| 77 | + }, | |
| 78 | + sources: { | |
| 79 | + list: () => | |
| 80 | + Effect.tryPromise({ | |
| 81 | + try: () => (pe.sources as any).list(), | |
| 82 | + catch: (cause) => cause, | |
| 83 | + }).pipe(Effect.orDie), | |
| 84 | + }, | |
| 85 | +}); | |
| 86 | + | |
| 87 | +export const createExecutionEngine = ( | |
| 88 | + config: ExecutionEngineConfig, | |
| 89 | +): ExecutionEngine => { | |
| 90 | + const engine = createEffectExecutionEngine({ | |
| 91 | + executor: wrapPromiseExecutor(config.executor), | |
| 92 | + codeExecutor: config.codeExecutor, | |
| 93 | + }); | |
| 94 | + return { | |
| 95 | + execute: (code, options) => | |
| 96 | + engine.execute(code, { | |
| 97 | + onElicitation: (ctx) => | |
| 98 | + Effect.tryPromise(() => options.onElicitation(ctx)).pipe( | |
| 99 | + Effect.orDie, | |
| 100 | + ), | |
| 101 | + }), | |
| 102 | + executeWithPause: (code) => engine.executeWithPause(code), | |
| 103 | + resume: (executionId, response) => engine.resume(executionId, response), | |
| 104 | + getDescription: () => engine.getDescription(), | |
| 105 | + }; | |
| 106 | +}; | |
| 107 | + | |
| 108 | +// --------------------------------------------------------------------------- | |
| 109 | +// Re-exports — plain types/helpers that don't carry Effect signatures. | |
| 110 | +// --------------------------------------------------------------------------- | |
| 111 | + | |
| 112 | +export { | |
| 113 | + formatExecuteResult, | |
| 114 | + formatPausedExecution, | |
| 115 | +} from "./engine"; | |
| 116 | + | |
| 117 | +export type { ExecutionResult, PausedExecution, ResumeResponse }; | |
| 118 | + | |
| 119 | +export { buildExecuteDescription } from "./description"; | |
| 120 | +export { ExecutionToolError } from "./errors"; | |
| @@ -8,9 +8,12 @@ import { · 7 unmodified lines | ||
| 8 | 8 | definePlugin, |
| 9 | 9 | makeTestConfig, |
| 10 | 10 | } from "@executor/sdk"; |
| 11 | +import { makeQuickJsExecutor } from "@executor/runtime-quickjs"; | |
| 11 | 12 | import { createExecutionEngine } from "./engine"; |
| 12 | 13 | import { describeTool, searchTools } from "./tool-invoker"; |
| 13 | 14 | |
| 15 | +const codeExecutor = makeQuickJsExecutor(); | |
| 16 | + | |
| 14 | 17 | const RepoInputSchema = { |
| 15 | 18 | type: "object", |
| 16 | 19 | properties: { |
| @@ -148,7 +151,7 @@ describe("tool discovery", () => { · 131 unmodified lines | ||
| 148 | 151 | expect(crmOnly.map((match) => match.path)).toEqual(["crm.listContacts"]); |
| 149 | 152 | |
| 150 | 153 | const sandboxResult = yield* Effect.promise(() => |
| 151 | − createExecutionEngine({ executor }).execute( | |
| 154 | + createExecutionEngine({ executor, codeExecutor }).execute( | |
| 152 | 155 | 'return await tools.search({ namespace: "crm", query: "create contact", limit: 5 });', |
| 153 | 156 | { onElicitation: acceptAll }, |
| 154 | 157 | ), |
| @@ -165,7 +168,7 @@ describe("tool discovery", () => { · 10 unmodified lines | ||
| 165 | 168 | const executor = yield* makeSearchExecutor(); |
| 166 | 169 | |
| 167 | 170 | const listed = yield* Effect.promise(() => |
| 168 | − createExecutionEngine({ executor }).execute("return await tools.executor.sources.list();", { | |
| 171 | + createExecutionEngine({ executor, codeExecutor }).execute("return await tools.executor.sources.list();", { | |
| 169 | 172 | onElicitation: acceptAll, |
| 170 | 173 | }), |
| 171 | 174 | ); |
| @@ -178,7 +181,7 @@ describe("tool discovery", () => { · 6 unmodified lines | ||
| 178 | 181 | ); |
| 179 | 182 | |
| 180 | 183 | const searched = yield* Effect.promise(() => |
| 181 | − createExecutionEngine({ executor }).execute( | |
| 184 | + createExecutionEngine({ executor, codeExecutor }).execute( | |
| 182 | 185 | 'return await tools.search({ query: "list contacts", namespace: "crm", limit: 5 });', |
| 183 | 186 | { onElicitation: acceptAll }, |
| 184 | 187 | ), |
| @@ -205,7 +208,7 @@ describe("tool discovery", () => { · 20 unmodified lines | ||
| 205 | 208 | it.effect("rejects malformed discover calls inside the sandbox", () => |
| 206 | 209 | Effect.gen(function* () { |
| 207 | 210 | const executor = yield* makeSearchExecutor(); |
| 208 | − const engine = createExecutionEngine({ executor }); | |
| 211 | + const engine = createExecutionEngine({ executor, codeExecutor }); | |
| 209 | 212 | |
| 210 | 213 | const invalid = yield* Effect.promise(() => |
| 211 | 214 | engine.execute( |
| @@ -327,7 +330,7 @@ describe("pause/resume with multiple elicitations", () => { · 115 unmodified lines | ||
| 327 | 330 | () => |
| 328 | 331 | Effect.gen(function* () { |
| 329 | 332 | const executor = yield* makeElicitingExecutor(); |
| 330 | − const engine = createExecutionEngine({ executor }); | |
| 333 | + const engine = createExecutionEngine({ executor, codeExecutor }); | |
| 331 | 334 | |
| 332 | 335 | const code = "return await tools.api.multiApproval({});"; |
| 333 | 336 | |
| @@ -361,7 +364,7 @@ describe("pause/resume with multiple elicitations", () => { · 27 unmodified lines | ||
| 361 | 364 | // sandbox fiber. |
| 362 | 365 | it("resume returns across separate runPromise boundaries for a single-elicit tool (HTTP-like)", async () => { |
| 363 | 366 | const executor = await Effect.runPromise(makeElicitingExecutor()); |
| 364 | − const engine = createExecutionEngine({ executor }); | |
| 367 | + const engine = createExecutionEngine({ executor, codeExecutor }); | |
| 365 | 368 | |
| 366 | 369 | const code = "return await tools.api.singleApproval({});"; |
| 367 | 370 | |
| @@ -5,7 +5,11 @@ · 4 unmodified lines | ||
| 5 | 5 | "moduleResolution": "Bundler", |
| 6 | 6 | "strict": true, |
| 7 | 7 | "skipLibCheck": true, |
| 8 | − "noEmit": true, | |
| 8 | + "outDir": "dist", | |
| 9 | + "rootDir": "src", | |
| 10 | + "declaration": true, | |
| 11 | + "declarationMap": true, | |
| 12 | + "sourceMap": true, | |
| 9 | 13 | "lib": ["ES2022"], |
| 10 | 14 | "types": ["bun-types", "node"], |
| 11 | 15 | "noUnusedLocals": true, |
| @@ -0,0 +1,13 @@ | ||
| 1 | +import { defineConfig } from "tsup"; | |
| 2 | + | |
| 3 | +export default defineConfig({ | |
| 4 | + entry: { | |
| 5 | + index: "src/promise.ts", | |
| 6 | + core: "src/index.ts", | |
| 7 | + }, | |
| 8 | + format: ["esm"], | |
| 9 | + dts: false, | |
| 10 | + sourcemap: true, | |
| 11 | + clean: true, | |
| 12 | + external: [/^@executor\//, /^effect/, /^@effect\//], | |
| 13 | +}); | |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | "type": "module", |
| 18 | 18 | "exports": { |
| 19 | 19 | ".": "./src/index.ts", |
| 20 | + "./core": "./src/index.ts", | |
| 20 | 21 | "./promise": "./src/promise.ts" |
| 21 | 22 | }, |
| 22 | 23 | "publishConfig": { |
| @@ -0,0 +1,64 @@ | ||
| 1 | +# @executor/storage-core | |
| 2 | + | |
| 3 | +Storage adapter interface for the executor. Defines the shared `DBAdapter`, `DBSchema`, and query-operator types every persistence backend implements, plus helpers for typed queries and an in-memory conformance test suite. | |
| 4 | + | |
| 5 | +Most callers don't depend on this directly — `@executor/sdk` re-exports the public surface. Install this when you're authoring a new storage adapter and want to conform to the contract. | |
| 6 | + | |
| 7 | +## Install | |
| 8 | + | |
| 9 | +```sh | |
| 10 | +bun add @executor/storage-core | |
| 11 | +# or | |
| 12 | +npm install @executor/storage-core | |
| 13 | +``` | |
| 14 | + | |
| 15 | +## Usage | |
| 16 | + | |
| 17 | +Implement an adapter: | |
| 18 | + | |
| 19 | +```ts | |
| 20 | +import { createAdapter, type DBAdapter } from "@executor/storage-core"; | |
| 21 | + | |
| 22 | +const myAdapter: DBAdapter = createAdapter({ | |
| 23 | + // ... your backend's query / mutation hooks | |
| 24 | +}); | |
| 25 | +``` | |
| 26 | + | |
| 27 | +Or grab typed query helpers for an existing schema: | |
| 28 | + | |
| 29 | +```ts | |
| 30 | +import { typedAdapter, type DBSchema } from "@executor/storage-core"; | |
| 31 | + | |
| 32 | +const schema = { | |
| 33 | + secrets: { | |
| 34 | + fields: { | |
| 35 | + id: { type: "string", required: true }, | |
| 36 | + value: { type: "string", required: true }, | |
| 37 | + }, | |
| 38 | + }, | |
| 39 | +} satisfies DBSchema; | |
| 40 | + | |
| 41 | +const db = typedAdapter(myAdapter, schema); | |
| 42 | +``` | |
| 43 | + | |
| 44 | +## Conformance tests | |
| 45 | + | |
| 46 | +If you're building an adapter, use the shared conformance suite to verify your backend matches the contract: | |
| 47 | + | |
| 48 | +```ts | |
| 49 | +import { describeDbAdapterConformance } from "@executor/storage-core/testing"; | |
| 50 | + | |
| 51 | +describeDbAdapterConformance({ | |
| 52 | + makeAdapter: async () => myAdapter, | |
| 53 | +}); | |
| 54 | +``` | |
| 55 | + | |
| 56 | +The suite runs against any `describe` from your test runner. `vitest` and `@effect/vitest` are declared as optional peer dependencies — install whichever you use. | |
| 57 | + | |
| 58 | +## Status | |
| 59 | + | |
| 60 | +Pre-`1.0`. APIs may still change between beta releases. Part of the [executor monorepo](https://github.com/RhysSullivan/executor). | |
| 61 | + | |
| 62 | +## License | |
| 63 | + | |
| 64 | +MIT | |
| @@ -1,25 +1,74 @@ | ||
| 1 | 1 | { |
| 2 | 2 | "name": "@executor/storage-core", |
| 3 | − "version": "0.0.0", | |
| 4 | − "private": true, | |
| 3 | + "version": "0.0.1", | |
| 4 | + "homepage": "https://github.com/RhysSullivan/executor/tree/main/packages/core/storage-core", | |
| 5 | + "bugs": { | |
| 6 | + "url": "https://github.com/RhysSullivan/executor/issues" | |
| 7 | + }, | |
| 8 | + "license": "MIT", | |
| 9 | + "repository": { | |
| 10 | + "type": "git", | |
| 11 | + "url": "git+https://github.com/RhysSullivan/executor.git", | |
| 12 | + "directory": "packages/core/storage-core" | |
| 13 | + }, | |
| 14 | + "files": [ | |
| 15 | + "dist" | |
| 16 | + ], | |
| 5 | 17 | "type": "module", |
| 6 | 18 | "exports": { |
| 7 | 19 | ".": "./src/index.ts", |
| 8 | 20 | "./testing": "./src/testing/conformance.ts", |
| 9 | 21 | "./testing/memory": "./src/testing/memory.ts" |
| 10 | 22 | }, |
| 23 | + "publishConfig": { | |
| 24 | + "access": "public", | |
| 25 | + "exports": { | |
| 26 | + ".": { | |
| 27 | + "import": { | |
| 28 | + "types": "./dist/index.d.ts", | |
| 29 | + "default": "./dist/index.js" | |
| 30 | + } | |
| 31 | + }, | |
| 32 | + "./testing": { | |
| 33 | + "import": { | |
| 34 | + "types": "./dist/testing/conformance.d.ts", | |
| 35 | + "default": "./dist/testing/conformance.js" | |
| 36 | + } | |
| 37 | + }, | |
| 38 | + "./testing/memory": { | |
| 39 | + "import": { | |
| 40 | + "types": "./dist/testing/memory.d.ts", | |
| 41 | + "default": "./dist/testing/memory.js" | |
| 42 | + } | |
| 43 | + } | |
| 44 | + } | |
| 45 | + }, | |
| 11 | 46 | "scripts": { |
| 47 | + "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | |
| 12 | 48 | "test": "vitest run", |
| 13 | 49 | "typecheck": "tsgo --noEmit", |
| 14 | 50 | "typecheck:slow": "tsc --noEmit" |
| 15 | 51 | }, |
| 16 | 52 | "dependencies": { |
| 17 | − "@effect/vitest": "catalog:", | |
| 18 | 53 | "@standard-schema/spec": "^1.0.0", |
| 19 | − "effect": "catalog:", | |
| 54 | + "effect": "catalog:" | |
| 55 | + }, | |
| 56 | + "peerDependencies": { | |
| 57 | + "@effect/vitest": "catalog:", | |
| 20 | 58 | "vitest": "catalog:" |
| 21 | 59 | }, |
| 60 | + "peerDependenciesMeta": { | |
| 61 | + "@effect/vitest": { | |
| 62 | + "optional": true | |
| 63 | + }, | |
| 64 | + "vitest": { | |
| 65 | + "optional": true | |
| 66 | + } | |
| 67 | + }, | |
| 22 | 68 | "devDependencies": { |
| 23 | − "typescript": "catalog:" | |
| 69 | + "@effect/vitest": "catalog:", | |
| 70 | + "tsup": "catalog:", | |
| 71 | + "typescript": "catalog:", | |
| 72 | + "vitest": "catalog:" | |
| 24 | 73 | } |
| 25 | 74 | } |
| @@ -0,0 +1,14 @@ | ||
| 1 | +import { defineConfig } from "tsup"; | |
| 2 | + | |
| 3 | +export default defineConfig({ | |
| 4 | + entry: { | |
| 5 | + index: "src/index.ts", | |
| 6 | + "testing/conformance": "src/testing/conformance.ts", | |
| 7 | + "testing/memory": "src/testing/memory.ts", | |
| 8 | + }, | |
| 9 | + format: ["esm"], | |
| 10 | + dts: false, | |
| 11 | + sourcemap: true, | |
| 12 | + clean: true, | |
| 13 | + external: [/^@executor\//, /^effect/, /^@effect\//, "vitest"], | |
| 14 | +}); | |
| @@ -0,0 +1,40 @@ | ||
| 1 | +# @executor/codemode-core | |
| 2 | + | |
| 3 | +Core primitives for "code mode" — the pattern where an LLM writes TypeScript/JavaScript that calls into a pre-registered set of tools, executed in a sandbox. This package provides the shared type surface (`Tool`, `SandboxToolInvoker`, `CodeExecutor`), JSON Schema helpers, and error types used by every runtime that implements the contract. | |
| 4 | + | |
| 5 | +Most callers depend on this transitively through `@executor/execution` and a sandbox runtime like `@executor/runtime-quickjs`. Install directly when you're authoring a new runtime. | |
| 6 | + | |
| 7 | +## Install | |
| 8 | + | |
| 9 | +```sh | |
| 10 | +bun add @executor/codemode-core | |
| 11 | +# or | |
| 12 | +npm install @executor/codemode-core | |
| 13 | +``` | |
| 14 | + | |
| 15 | +## Usage | |
| 16 | + | |
| 17 | +Implement a runtime that satisfies `CodeExecutor`: | |
| 18 | + | |
| 19 | +```ts | |
| 20 | +import type { CodeExecutor, SandboxToolInvoker } from "@executor/codemode-core"; | |
| 21 | +import { Effect } from "effect"; | |
| 22 | + | |
| 23 | +export const makeMyRuntime = (): CodeExecutor => ({ | |
| 24 | + execute: (code: string, invoker: SandboxToolInvoker) => | |
| 25 | + Effect.gen(function* () { | |
| 26 | + // Spin up your sandbox, expose `invoker` as `tools.<path>(...)`, run the code, | |
| 27 | + // collect logs, and return an ExecuteResult. | |
| 28 | + }), | |
| 29 | +}); | |
| 30 | +``` | |
| 31 | + | |
| 32 | +The runtime is passed a `SandboxToolInvoker` that bridges sandbox-side tool calls back to the executor. The sandbox-visible API is whatever you decide — `@executor/runtime-quickjs` exposes a `tools` proxy object; a runtime targeting Cloudflare Workers might use something else. | |
| 33 | + | |
| 34 | +## Status | |
| 35 | + | |
| 36 | +Pre-`1.0`. APIs may still change between beta releases. Part of the [executor monorepo](https://github.com/RhysSullivan/executor). | |
| 37 | + | |
| 38 | +## License | |
| 39 | + | |
| 40 | +MIT | |
| @@ -1,12 +1,36 @@ | ||
| 1 | 1 | { |
| 2 | 2 | "name": "@executor/codemode-core", |
| 3 | − "version": "1.4.3", | |
| 4 | − "private": true, | |
| 3 | + "version": "0.0.1", | |
| 4 | + "homepage": "https://github.com/RhysSullivan/executor/tree/main/packages/kernel/core", | |
| 5 | + "bugs": { | |
| 6 | + "url": "https://github.com/RhysSullivan/executor/issues" | |
| 7 | + }, | |
| 8 | + "license": "MIT", | |
| 9 | + "repository": { | |
| 10 | + "type": "git", | |
| 11 | + "url": "git+https://github.com/RhysSullivan/executor.git", | |
| 12 | + "directory": "packages/kernel/core" | |
| 13 | + }, | |
| 14 | + "files": [ | |
| 15 | + "dist" | |
| 16 | + ], | |
| 5 | 17 | "type": "module", |
| 6 | 18 | "exports": { |
| 7 | 19 | ".": "./src/index.ts" |
| 8 | 20 | }, |
| 21 | + "publishConfig": { | |
| 22 | + "access": "public", | |
| 23 | + "exports": { | |
| 24 | + ".": { | |
| 25 | + "import": { | |
| 26 | + "types": "./dist/index.d.ts", | |
| 27 | + "default": "./dist/index.js" | |
| 28 | + } | |
| 29 | + } | |
| 30 | + } | |
| 31 | + }, | |
| 9 | 32 | "scripts": { |
| 33 | + "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | |
| 10 | 34 | "typecheck": "tsgo --noEmit", |
| 11 | 35 | "test": "vitest run", |
| 12 | 36 | "test:watch": "vitest", |
| @@ -22,6 +46,8 @@ · 9 unmodified lines | ||
| 22 | 46 | "devDependencies": { |
| 23 | 47 | "@types/node": "catalog:", |
| 24 | 48 | "bun-types": "catalog:", |
| 49 | + "tsup": "catalog:", | |
| 50 | + "typescript": "catalog:", | |
| 25 | 51 | "vitest": "catalog:" |
| 26 | 52 | } |
| 27 | 53 | } |
| @@ -5,7 +5,11 @@ · 4 unmodified lines | ||
| 5 | 5 | "moduleResolution": "Bundler", |
| 6 | 6 | "strict": true, |
| 7 | 7 | "skipLibCheck": true, |
| 8 | − "noEmit": true, | |
| 8 | + "outDir": "dist", | |
| 9 | + "rootDir": "src", | |
| 10 | + "declaration": true, | |
| 11 | + "declarationMap": true, | |
| 12 | + "sourceMap": true, | |
| 9 | 13 | "lib": ["ES2022"], |
| 10 | 14 | "types": ["bun-types", "node"], |
| 11 | 15 | "noUnusedLocals": true, |
| @@ -0,0 +1,12 @@ | ||
| 1 | +import { defineConfig } from "tsup"; | |
| 2 | + | |
| 3 | +export default defineConfig({ | |
| 4 | + entry: { | |
| 5 | + index: "src/index.ts", | |
| 6 | + }, | |
| 7 | + format: ["esm"], | |
| 8 | + dts: false, | |
| 9 | + sourcemap: true, | |
| 10 | + clean: true, | |
| 11 | + external: [/^@executor\//, /^effect/, /^@effect\//], | |
| 12 | +}); | |
| @@ -0,0 +1,60 @@ | ||
| 1 | +# @executor/runtime-quickjs | |
| 2 | + | |
| 3 | +[QuickJS](https://github.com/justjake/quickjs-emscripten) sandbox runtime for `@executor/execution`. Runs untrusted TypeScript/JavaScript in a WASM-backed interpreter with configurable timeout, memory limit, and stack size — safe enough to execute LLM-generated code that calls your registered tools. | |
| 4 | + | |
| 5 | +## Install | |
| 6 | + | |
| 7 | +```sh | |
| 8 | +bun add @executor/execution @executor/runtime-quickjs | |
| 9 | +# or | |
| 10 | +npm install @executor/execution @executor/runtime-quickjs | |
| 11 | +``` | |
| 12 | + | |
| 13 | +## Usage | |
| 14 | + | |
| 15 | +Pass a `makeQuickJsExecutor()` as the `codeExecutor` when building the execution engine: | |
| 16 | + | |
| 17 | +```ts | |
| 18 | +import { createExecutor } from "@executor/sdk"; | |
| 19 | +import { createExecutionEngine } from "@executor/execution"; | |
| 20 | +import { makeQuickJsExecutor } from "@executor/runtime-quickjs"; | |
| 21 | + | |
| 22 | +const executor = await createExecutor({ scope: { name: "my-app" } }); | |
| 23 | + | |
| 24 | +const engine = createExecutionEngine({ | |
| 25 | + executor, | |
| 26 | + codeExecutor: makeQuickJsExecutor({ | |
| 27 | + timeoutMs: 2_000, | |
| 28 | + memoryLimitBytes: 32 * 1024 * 1024, | |
| 29 | + maxStackSizeBytes: 1 * 1024 * 1024, | |
| 30 | + }), | |
| 31 | +}); | |
| 32 | +``` | |
| 33 | + | |
| 34 | +### Options | |
| 35 | + | |
| 36 | +| Option | Default | Description | | |
| 37 | +| ------------------- | ---------- | -------------------------------------------- | | |
| 38 | +| `timeoutMs` | `5_000` | Max wall-clock time per execution | | |
| 39 | +| `memoryLimitBytes` | `64 * 1MB` | Max memory the VM can allocate | | |
| 40 | +| `maxStackSizeBytes` | `1 * 1MB` | Max call-stack depth | | |
| 41 | + | |
| 42 | +### Swapping the QuickJS build | |
| 43 | + | |
| 44 | +```ts | |
| 45 | +import { setQuickJSModule } from "@executor/runtime-quickjs"; | |
| 46 | +import { newQuickJSAsyncWASMModuleFromVariant } from "quickjs-emscripten"; | |
| 47 | +import variant from "@jitl/quickjs-ng-wasmfile-release-sync"; | |
| 48 | + | |
| 49 | +setQuickJSModule(await newQuickJSAsyncWASMModuleFromVariant(variant)); | |
| 50 | +``` | |
| 51 | + | |
| 52 | +Use this when you want a different WASM variant (e.g. debug builds, QuickJS-NG) than the default bundled one. | |
| 53 | + | |
| 54 | +## Status | |
| 55 | + | |
| 56 | +Pre-`1.0`. APIs may still change between beta releases. Part of the [executor monorepo](https://github.com/RhysSullivan/executor). | |
| 57 | + | |
| 58 | +## License | |
| 59 | + | |
| 60 | +MIT | |
| @@ -1,12 +1,36 @@ | ||
| 1 | 1 | { |
| 2 | 2 | "name": "@executor/runtime-quickjs", |
| 3 | − "version": "1.4.3", | |
| 4 | − "private": true, | |
| 3 | + "version": "0.0.1", | |
| 4 | + "homepage": "https://github.com/RhysSullivan/executor/tree/main/packages/kernel/runtime-quickjs", | |
| 5 | + "bugs": { | |
| 6 | + "url": "https://github.com/RhysSullivan/executor/issues" | |
| 7 | + }, | |
| 8 | + "license": "MIT", | |
| 9 | + "repository": { | |
| 10 | + "type": "git", | |
| 11 | + "url": "git+https://github.com/RhysSullivan/executor.git", | |
| 12 | + "directory": "packages/kernel/runtime-quickjs" | |
| 13 | + }, | |
| 14 | + "files": [ | |
| 15 | + "dist" | |
| 16 | + ], | |
| 5 | 17 | "type": "module", |
| 6 | 18 | "exports": { |
| 7 | 19 | ".": "./src/index.ts" |
| 8 | 20 | }, |
| 21 | + "publishConfig": { | |
| 22 | + "access": "public", | |
| 23 | + "exports": { | |
| 24 | + ".": { | |
| 25 | + "import": { | |
| 26 | + "types": "./dist/index.d.ts", | |
| 27 | + "default": "./dist/index.js" | |
| 28 | + } | |
| 29 | + } | |
| 30 | + } | |
| 31 | + }, | |
| 9 | 32 | "scripts": { |
| 33 | + "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | |
| 10 | 34 | "typecheck": "tsgo --noEmit", |
| 11 | 35 | "test": "vitest run", |
| 12 | 36 | "test:watch": "vitest", |
| @@ -21,6 +45,8 @@ · 8 unmodified lines | ||
| 21 | 45 | "@effect/vitest": "catalog:", |
| 22 | 46 | "@types/node": "catalog:", |
| 23 | 47 | "bun-types": "catalog:", |
| 48 | + "tsup": "catalog:", | |
| 49 | + "typescript": "catalog:", | |
| 24 | 50 | "vitest": "catalog:" |
| 25 | 51 | } |
| 26 | 52 | } |
| @@ -5,7 +5,11 @@ · 4 unmodified lines | ||
| 5 | 5 | "moduleResolution": "Bundler", |
| 6 | 6 | "strict": true, |
| 7 | 7 | "skipLibCheck": true, |
| 8 | − "noEmit": true, | |
| 8 | + "outDir": "dist", | |
| 9 | + "rootDir": "src", | |
| 10 | + "declaration": true, | |
| 11 | + "declarationMap": true, | |
| 12 | + "sourceMap": true, | |
| 9 | 13 | "lib": ["ES2022"], |
| 10 | 14 | "types": ["bun-types", "node"], |
| 11 | 15 | "noUnusedLocals": true, |
| @@ -0,0 +1,12 @@ | ||
| 1 | +import { defineConfig } from "tsup"; | |
| 2 | + | |
| 3 | +export default defineConfig({ | |
| 4 | + entry: { | |
| 5 | + index: "src/index.ts", | |
| 6 | + }, | |
| 7 | + format: ["esm"], | |
| 8 | + dts: false, | |
| 9 | + sourcemap: true, | |
| 10 | + clean: true, | |
| 11 | + external: [/^@executor\//, /^effect/, /^@effect\//, "quickjs-emscripten"], | |
| 12 | +}); | |
| @@ -38,7 +38,12 @@ const PUBLISHED_SCOPE = "@executor-js"; · 37 unmodified lines | ||
| 38 | 38 | * directory under `packages/plugins/` does not accidentally ship to npm. |
| 39 | 39 | */ |
| 40 | 40 | const PUBLIC_PACKAGE_DIRS = [ |
| 41 | + "packages/core/storage-core", | |
| 42 | + "packages/kernel/core", | |
| 43 | + "packages/kernel/runtime-quickjs", | |
| 41 | 44 | "packages/core/sdk", |
| 45 | + "packages/core/execution", | |
| 46 | + "packages/core/cli", | |
| 42 | 47 | "packages/plugins/file-secrets", |
| 43 | 48 | "packages/plugins/google-discovery", |
| 44 | 49 | "packages/plugins/graphql", |
| @@ -267,13 +272,13 @@ const applyPublishConfig = async (pkgDir: string): Promise<() => Promise<void>> · 222 unmodified lines | ||
| 267 | 272 | |
| 268 | 273 | const publishPackage = async ( |
| 269 | 274 | pkgDir: string, |
| 270 | − channel: Channel, | |
| 271 | 275 | dryRun: boolean, |
| 272 | 276 | publishable: ReadonlySet<string>, |
| 273 | 277 | publishableVersions: ReadonlyMap<string, string>, |
| 274 | 278 | ) => { |
| 275 | 279 | const { name: internalName, version } = await readPackageMeta(pkgDir); |
| 276 | 280 | const publishedName = internalName.replace(`${INTERNAL_SCOPE}/`, `${PUBLISHED_SCOPE}/`); |
| 281 | + const channel = resolveChannel(version); | |
| 277 | 282 | |
| 278 | 283 | if (!existsSync(join(pkgDir, "dist"))) { |
| 279 | 284 | throw new Error(`Missing dist/ in ${pkgDir}. Did you run 'bun run build:packages'?`); |
| @@ -326,12 +331,10 @@ const publishPackage = async ( · 46 unmodified lines | ||
| 326 | 331 | const main = async () => { |
| 327 | 332 | const { dryRun } = parseArgs(process.argv.slice(2)); |
| 328 | 333 | |
| 329 | − // Use the sdk package version as the source of truth for the channel. All | |
| 330 | − // published packages version together (they're not in the changeset ignore | |
| 331 | − // list), so they share a release channel. | |
| 332 | − const sdkMeta = await readPackageMeta(join(repoRoot, "packages/core/sdk")); | |
| 333 | − const channel = resolveChannel(sdkMeta.version); | |
| 334 | − console.log(`Publishing ${PUBLISHED_SCOPE} packages (${channel})${dryRun ? " [dry-run]" : ""}`); | |
| 334 | + // Each package's own version determines its dist-tag (pre-release versions | |
| 335 | + // with `-` publish to `beta`, everything else to `latest`). Packages are | |
| 336 | + // only skipped when their current version is already on npm. | |
| 337 | + console.log(`Publishing ${PUBLISHED_SCOPE} packages${dryRun ? " [dry-run]" : ""}`); | |
| 335 | 338 | |
| 336 | 339 | await $`bun run build:packages`.cwd(repoRoot); |
| 337 | 340 | |
| @@ -351,7 +354,7 @@ const main = async () => { · 13 unmodified lines | ||
| 351 | 354 | } |
| 352 | 355 | |
| 353 | 356 | for (const relDir of PUBLIC_PACKAGE_DIRS) { |
| 354 | − await publishPackage(join(repoRoot, relDir), channel, dryRun, publishable, publishableVersions); | |
| 357 | + await publishPackage(join(repoRoot, relDir), dryRun, publishable, publishableVersions); | |
| 355 | 358 | } |
| 356 | 359 | }; |
| 357 | 360 | |