History

Merge pull request #284 from RhysSullivan/worktree-publish-execution-cli

feat(release): publish execution, cli, and kernel packages to npm

Rhys Sullivan committed 7 months ago

Commit 599ae332 parents 96dc18a 905973b35 files · +772 −66Browse files

Showing the changes to packages (25 of 35 files). Show all

Unified · Split

25 files
  1. packages/core/cli/README.md +57 −0
  2. packages/core/cli/package.json +24 −3
  3. packages/core/cli/src/commands/generate.ts +1 −1
  4. packages/core/cli/src/generators/types.ts +1 −1
  5. packages/core/cli/src/utils/get-config.ts +1 −1
  6. packages/core/cli/tsup.config.ts +17 −0
  7. packages/core/execution/README.md +94 −0
  8. packages/core/execution/package.json +37 −4
  9. packages/core/execution/src/engine.ts +2 −4
  10. packages/core/execution/src/promise.ts +120 −0
  11. packages/core/execution/src/tool-invoker.test.ts +9 −6
  12. packages/core/execution/tsconfig.json +5 −1
  13. packages/core/execution/tsup.config.ts +13 −0
  14. packages/core/sdk/package.json +1 −0
  15. packages/core/storage-core/README.md +64 −0
  16. packages/core/storage-core/package.json +54 −5
  17. packages/core/storage-core/tsup.config.ts +14 −0
  18. packages/kernel/core/README.md +40 −0
  19. packages/kernel/core/package.json +28 −2
  20. packages/kernel/core/tsconfig.json +5 −1
  21. packages/kernel/core/tsup.config.ts +12 −0
  22. packages/kernel/runtime-quickjs/README.md +60 −0
  23. packages/kernel/runtime-quickjs/package.json +28 −2
  24. packages/kernel/runtime-quickjs/tsconfig.json +5 −1
  25. packages/kernel/runtime-quickjs/tsup.config.ts +12 −0
packages/core/cli/README.md+57−0
@@ -0,0 +1,57 @@
1# @executor/cli
2
3Command-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
8bun add -d @executor/cli
9# or
10npm install --save-dev @executor/cli
11```
12
13The binary is installed as `executor`.
14
15## Quick start
16
17Create an `executor.config.ts` alongside your app code:
18
19```ts
20import { defineExecutorConfig } from "@executor/sdk";
21import { mcpPlugin } from "@executor/plugin-mcp";
22import { openApiPlugin } from "@executor/plugin-openapi";
23
24export default defineExecutorConfig({
25 dialect: "postgres",
26 plugins: [mcpPlugin(), openApiPlugin()],
27});
28```
29
30Then generate a Drizzle schema from it:
31
32```sh
33bunx executor generate --output ./src/db/executor-schema.ts
34# or
35npx executor generate --output ./src/db/executor-schema.ts
36```
37
38The 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```
43executor 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
49Run `executor --help` to see the current command list.
50
51## Status
52
53Pre-`1.0`. APIs may still change between beta releases. Part of the [executor monorepo](https://github.com/RhysSullivan/executor).
54
55## License
56
57MIT
packages/core/cli/package.json+24−3
@@ -2,7 +2,16 @@ · 1 unmodified line
2 "name": "@executor/cli",2 "name": "@executor/cli",
3 "version": "0.0.1",3 "version": "0.0.1",
4 "description": "CLI for the executor SDK — schema generation, migrations",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 "license": "MIT",9 "license": "MIT",
10 "repository": {
11 "type": "git",
12 "url": "git+https://github.com/RhysSullivan/executor.git",
13 "directory": "packages/core/cli"
14 },
6 "type": "module",15 "type": "module",
7 "bin": {16 "bin": {
8 "executor": "./dist/index.js"17 "executor": "./dist/index.js"
@@ -13,19 +22,31 @@ · 4 unmodified lines
13 "exports": {22 "exports": {
14 ".": "./src/index.ts"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 "scripts": {36 "scripts": {
17 "build": "tsup src/index.ts --format esm --dts",37 "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)",
18 "dev": "node --import jiti/register src/index.ts",38 "dev": "node --import jiti/register src/index.ts",
19 "test": "vitest run",39 "test": "vitest run",
20 "typecheck": "tsc --noEmit"40 "typecheck": "tsc --noEmit"
21 },41 },
22 "dependencies": {42 "dependencies": {
23 "@executor/sdk": "workspace:*",
24 "@executor/storage-core": "workspace:*",
25 "commander": "^12.1.0",43 "commander": "^12.1.0",
44 "effect": "catalog:",
26 "jiti": "^2.6.1"45 "jiti": "^2.6.1"
27 },46 },
28 "devDependencies": {47 "devDependencies": {
48 "@executor/sdk": "workspace:*",
49 "@executor/storage-core": "workspace:*",
29 "@types/node": "catalog:",50 "@types/node": "catalog:",
30 "tsup": "catalog:",51 "tsup": "catalog:",
31 "typescript": "catalog:",52 "typescript": "catalog:",
packages/core/cli/src/commands/generate.ts+1−1
@@ -2,7 +2,7 @@ import { existsSync } from "node:fs"; · 1 unmodified line
2import fs from "node:fs/promises";2import fs from "node:fs/promises";
3import path from "node:path";3import path from "node:path";
4import { Command } from "commander";4import { Command } from "commander";
5import { collectSchemas } from "@executor/sdk";5import { collectSchemas } from "@executor/sdk/core";
6import { getConfig } from "../utils/get-config.js";6import { getConfig } from "../utils/get-config.js";
7import { generateDrizzleSchema } from "../generators/drizzle.js";7import { generateDrizzleSchema } from "../generators/drizzle.js";
8 8
packages/core/cli/src/generators/types.ts+1−1
@@ -1,5 +1,5 @@
1import type { DBSchema } from "@executor/storage-core";1import type { DBSchema } from "@executor/storage-core";
2import type { ExecutorDialect } from "@executor/sdk";2import type { ExecutorDialect } from "@executor/sdk/core";
3 3
4export interface SchemaGeneratorResult {4export interface SchemaGeneratorResult {
5 code?: string;5 code?: string;
packages/core/cli/src/utils/get-config.ts+1−1
@@ -1,7 +1,7 @@
1import { existsSync } from "node:fs";1import { existsSync } from "node:fs";
2import path from "node:path";2import path from "node:path";
3import { createJiti } from "jiti";3import { createJiti } from "jiti";
4import type { ExecutorCliConfig } from "@executor/sdk";4import type { ExecutorCliConfig } from "@executor/sdk/core";
5 5
6const defaultPaths = [6const defaultPaths = [
7 "executor.config.ts",7 "executor.config.ts",
packages/core/cli/tsup.config.ts+17−0
@@ -0,0 +1,17 @@
1import { defineConfig } from "tsup";
2
3export 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});
packages/core/execution/README.md+94−0
@@ -0,0 +1,94 @@
1# @executor/execution
2
3Sandboxed 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
5Supports 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
10bun add @executor/sdk @executor/execution @executor/runtime-quickjs
11# or
12npm 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
20import { createExecutor } from "@executor/sdk";
21import { createExecutionEngine } from "@executor/execution";
22import { makeQuickJsExecutor } from "@executor/runtime-quickjs";
23
24const executor = await createExecutor({
25 scope: { name: "my-app" },
26});
27
28const engine = createExecutionEngine({
29 executor,
30 codeExecutor: makeQuickJsExecutor({
31 timeoutMs: 2_000,
32 memoryLimitBytes: 32 * 1024 * 1024,
33 }),
34});
35
36const 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
50console.log(result);
51// { result: 12, logs: [...] }
52```
53
54## Pause/resume for elicitation
55
56When the host doesn't support inline elicitation, use `executeWithPause` to intercept the first request as a pause point:
57
58```ts
59const started = await engine.executeWithPause(code);
60
61if (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
74const 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
82If 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
85import { createExecutionEngine } from "@executor/execution";
86```
87
88## Status
89
90Pre-`1.0`. APIs may still change between beta releases. Part of the [executor monorepo](https://github.com/RhysSullivan/executor).
91
92## License
93
94MIT
packages/core/execution/package.json+37−4
@@ -1,26 +1,59 @@
1{1{
2 "name": "@executor/execution",2 "name": "@executor/execution",
3 "version": "1.4.3",3 "version": "0.0.1",
4 "private": true,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 "type": "module",17 "type": "module",
6 "exports": {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 "scripts": {39 "scripts": {
40 "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)",
10 "typecheck": "tsgo --noEmit",41 "typecheck": "tsgo --noEmit",
11 "test": "vitest run",42 "test": "vitest run",
12 "typecheck:slow": "bunx tsc --noEmit -p tsconfig.json"43 "typecheck:slow": "bunx tsc --noEmit -p tsconfig.json"
13 },44 },
14 "dependencies": {45 "dependencies": {
15 "@executor/codemode-core": "workspace:*",46 "@executor/codemode-core": "workspace:*",
16 "@executor/runtime-quickjs": "workspace:*",
17 "@executor/sdk": "workspace:*",47 "@executor/sdk": "workspace:*",
18 "effect": "catalog:"48 "effect": "catalog:"
19 },49 },
20 "devDependencies": {50 "devDependencies": {
21 "@effect/vitest": "catalog:",51 "@effect/vitest": "catalog:",
52 "@executor/runtime-quickjs": "workspace:*",
22 "@types/node": "catalog:",53 "@types/node": "catalog:",
23 "bun-types": "catalog:",54 "bun-types": "catalog:",
55 "tsup": "catalog:",
56 "typescript": "catalog:",
24 "vitest": "catalog:"57 "vitest": "catalog:"
25 }58 }
26}59}
packages/core/execution/src/engine.ts+2−4
@@ -8,7 +8,6 @@ import type { · 7 unmodified lines
8 ElicitationContext,8 ElicitationContext,
9} from "@executor/sdk";9} from "@executor/sdk";
10import type { CodeExecutor, ExecuteResult, SandboxToolInvoker } from "@executor/codemode-core";10import type { CodeExecutor, ExecuteResult, SandboxToolInvoker } from "@executor/codemode-core";
11import { makeQuickJsExecutor } from "@executor/runtime-quickjs";
12 11
13import {12import {
14 makeExecutorToolInvoker,13 makeExecutorToolInvoker,
@@ -25,7 +24,7 @@ import { buildExecuteDescription } from "./description"; · 10 unmodified lines
25 24
26export type ExecutionEngineConfig = {25export type ExecutionEngineConfig = {
27 readonly executor: Executor;26 readonly executor: Executor;
28 readonly codeExecutor?: CodeExecutor;27 readonly codeExecutor: CodeExecutor;
29};28};
30 29
31export type ExecutionResult =30export type ExecutionResult =
@@ -292,8 +291,7 @@ const runEffect = <A>(effect: Effect.Effect<A, unknown>): Promise<A> => · 260 unmodified lines
292 Effect.runPromise(effect as Effect.Effect<A, never>);291 Effect.runPromise(effect as Effect.Effect<A, never>);
293 292
294export const createExecutionEngine = (config: ExecutionEngineConfig): ExecutionEngine => {293export const createExecutionEngine = (config: ExecutionEngineConfig): ExecutionEngine => {
295 const { executor } = config;294 const { executor, codeExecutor } = config;
296 const codeExecutor = config.codeExecutor ?? makeQuickJsExecutor();
297 const pausedExecutions = new Map<string, InternalPausedExecution>();295 const pausedExecutions = new Map<string, InternalPausedExecution>();
298 let nextId = 0;296 let nextId = 0;
299 297
packages/core/execution/src/promise.ts+120−0
@@ -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
11import { Effect } from "effect";
12
13import type {
14 ElicitationContext,
15 ElicitationResponse,
16 Executor as PromiseExecutor,
17} from "@executor/sdk";
18import type { CodeExecutor, ExecuteResult } from "@executor/codemode-core";
19
20import {
21 createExecutionEngine as createEffectExecutionEngine,
22 type ExecutionResult,
23 type PausedExecution,
24 type ResumeResponse,
25} from "./engine";
26
27export type ElicitationHandler = (
28 ctx: ElicitationContext,
29) => Promise<ElicitationResponse>;
30
31export type ExecutionEngineConfig = {
32 readonly executor: PromiseExecutor;
33 readonly codeExecutor: CodeExecutor;
34};
35
36export 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 */
54const 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
87export 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
112export {
113 formatExecuteResult,
114 formatPausedExecution,
115} from "./engine";
116
117export type { ExecutionResult, PausedExecution, ResumeResponse };
118
119export { buildExecuteDescription } from "./description";
120export { ExecutionToolError } from "./errors";
packages/core/execution/src/tool-invoker.test.ts+9−6
@@ -8,9 +8,12 @@ import { · 7 unmodified lines
8 definePlugin,8 definePlugin,
9 makeTestConfig,9 makeTestConfig,
10} from "@executor/sdk";10} from "@executor/sdk";
11import { makeQuickJsExecutor } from "@executor/runtime-quickjs";
11import { createExecutionEngine } from "./engine";12import { createExecutionEngine } from "./engine";
12import { describeTool, searchTools } from "./tool-invoker";13import { describeTool, searchTools } from "./tool-invoker";
13 14
15const codeExecutor = makeQuickJsExecutor();
16
14const RepoInputSchema = {17const RepoInputSchema = {
15 type: "object",18 type: "object",
16 properties: {19 properties: {
@@ -148,7 +151,7 @@ describe("tool discovery", () => { · 131 unmodified lines
148 expect(crmOnly.map((match) => match.path)).toEqual(["crm.listContacts"]);151 expect(crmOnly.map((match) => match.path)).toEqual(["crm.listContacts"]);
149 152
150 const sandboxResult = yield* Effect.promise(() =>153 const sandboxResult = yield* Effect.promise(() =>
151 createExecutionEngine({ executor }).execute(154 createExecutionEngine({ executor, codeExecutor }).execute(
152 'return await tools.search({ namespace: "crm", query: "create contact", limit: 5 });',155 'return await tools.search({ namespace: "crm", query: "create contact", limit: 5 });',
153 { onElicitation: acceptAll },156 { onElicitation: acceptAll },
154 ),157 ),
@@ -165,7 +168,7 @@ describe("tool discovery", () => { · 10 unmodified lines
165 const executor = yield* makeSearchExecutor();168 const executor = yield* makeSearchExecutor();
166 169
167 const listed = yield* Effect.promise(() =>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 onElicitation: acceptAll,172 onElicitation: acceptAll,
170 }),173 }),
171 );174 );
@@ -178,7 +181,7 @@ describe("tool discovery", () => { · 6 unmodified lines
178 );181 );
179 182
180 const searched = yield* Effect.promise(() =>183 const searched = yield* Effect.promise(() =>
181 createExecutionEngine({ executor }).execute(184 createExecutionEngine({ executor, codeExecutor }).execute(
182 'return await tools.search({ query: "list contacts", namespace: "crm", limit: 5 });',185 'return await tools.search({ query: "list contacts", namespace: "crm", limit: 5 });',
183 { onElicitation: acceptAll },186 { onElicitation: acceptAll },
184 ),187 ),
@@ -205,7 +208,7 @@ describe("tool discovery", () => { · 20 unmodified lines
205 it.effect("rejects malformed discover calls inside the sandbox", () =>208 it.effect("rejects malformed discover calls inside the sandbox", () =>
206 Effect.gen(function* () {209 Effect.gen(function* () {
207 const executor = yield* makeSearchExecutor();210 const executor = yield* makeSearchExecutor();
208 const engine = createExecutionEngine({ executor });211 const engine = createExecutionEngine({ executor, codeExecutor });
209 212
210 const invalid = yield* Effect.promise(() =>213 const invalid = yield* Effect.promise(() =>
211 engine.execute(214 engine.execute(
@@ -327,7 +330,7 @@ describe("pause/resume with multiple elicitations", () => { · 115 unmodified lines
327 () =>330 () =>
328 Effect.gen(function* () {331 Effect.gen(function* () {
329 const executor = yield* makeElicitingExecutor();332 const executor = yield* makeElicitingExecutor();
330 const engine = createExecutionEngine({ executor });333 const engine = createExecutionEngine({ executor, codeExecutor });
331 334
332 const code = "return await tools.api.multiApproval({});";335 const code = "return await tools.api.multiApproval({});";
333 336
@@ -361,7 +364,7 @@ describe("pause/resume with multiple elicitations", () => { · 27 unmodified lines
361 // sandbox fiber.364 // sandbox fiber.
362 it("resume returns across separate runPromise boundaries for a single-elicit tool (HTTP-like)", async () => {365 it("resume returns across separate runPromise boundaries for a single-elicit tool (HTTP-like)", async () => {
363 const executor = await Effect.runPromise(makeElicitingExecutor());366 const executor = await Effect.runPromise(makeElicitingExecutor());
364 const engine = createExecutionEngine({ executor });367 const engine = createExecutionEngine({ executor, codeExecutor });
365 368
366 const code = "return await tools.api.singleApproval({});";369 const code = "return await tools.api.singleApproval({});";
367 370
packages/core/execution/tsconfig.json+5−1
@@ -5,7 +5,11 @@ · 4 unmodified lines
5 "moduleResolution": "Bundler",5 "moduleResolution": "Bundler",
6 "strict": true,6 "strict": true,
7 "skipLibCheck": true,7 "skipLibCheck": true,
8 "noEmit": true,8 "outDir": "dist",
9 "rootDir": "src",
10 "declaration": true,
11 "declarationMap": true,
12 "sourceMap": true,
9 "lib": ["ES2022"],13 "lib": ["ES2022"],
10 "types": ["bun-types", "node"],14 "types": ["bun-types", "node"],
11 "noUnusedLocals": true,15 "noUnusedLocals": true,
packages/core/execution/tsup.config.ts+13−0
@@ -0,0 +1,13 @@
1import { defineConfig } from "tsup";
2
3export 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});
packages/core/sdk/package.json+1−0
@@ -17,6 +17,7 @@ · 16 unmodified lines
17 "type": "module",17 "type": "module",
18 "exports": {18 "exports": {
19 ".": "./src/index.ts",19 ".": "./src/index.ts",
20 "./core": "./src/index.ts",
20 "./promise": "./src/promise.ts"21 "./promise": "./src/promise.ts"
21 },22 },
22 "publishConfig": {23 "publishConfig": {
packages/core/storage-core/README.md+64−0
@@ -0,0 +1,64 @@
1# @executor/storage-core
2
3Storage 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
5Most 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
10bun add @executor/storage-core
11# or
12npm install @executor/storage-core
13```
14
15## Usage
16
17Implement an adapter:
18
19```ts
20import { createAdapter, type DBAdapter } from "@executor/storage-core";
21
22const myAdapter: DBAdapter = createAdapter({
23 // ... your backend's query / mutation hooks
24});
25```
26
27Or grab typed query helpers for an existing schema:
28
29```ts
30import { typedAdapter, type DBSchema } from "@executor/storage-core";
31
32const schema = {
33 secrets: {
34 fields: {
35 id: { type: "string", required: true },
36 value: { type: "string", required: true },
37 },
38 },
39} satisfies DBSchema;
40
41const db = typedAdapter(myAdapter, schema);
42```
43
44## Conformance tests
45
46If you're building an adapter, use the shared conformance suite to verify your backend matches the contract:
47
48```ts
49import { describeDbAdapterConformance } from "@executor/storage-core/testing";
50
51describeDbAdapterConformance({
52 makeAdapter: async () => myAdapter,
53});
54```
55
56The 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
60Pre-`1.0`. APIs may still change between beta releases. Part of the [executor monorepo](https://github.com/RhysSullivan/executor).
61
62## License
63
64MIT
packages/core/storage-core/package.json+54−5
@@ -1,25 +1,74 @@
1{1{
2 "name": "@executor/storage-core",2 "name": "@executor/storage-core",
3 "version": "0.0.0",3 "version": "0.0.1",
4 "private": true,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 "type": "module",17 "type": "module",
6 "exports": {18 "exports": {
7 ".": "./src/index.ts",19 ".": "./src/index.ts",
8 "./testing": "./src/testing/conformance.ts",20 "./testing": "./src/testing/conformance.ts",
9 "./testing/memory": "./src/testing/memory.ts"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 "scripts": {46 "scripts": {
47 "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)",
12 "test": "vitest run",48 "test": "vitest run",
13 "typecheck": "tsgo --noEmit",49 "typecheck": "tsgo --noEmit",
14 "typecheck:slow": "tsc --noEmit"50 "typecheck:slow": "tsc --noEmit"
15 },51 },
16 "dependencies": {52 "dependencies": {
17 "@effect/vitest": "catalog:",
18 "@standard-schema/spec": "^1.0.0",53 "@standard-schema/spec": "^1.0.0",
19 "effect": "catalog:",54 "effect": "catalog:"
55 },
56 "peerDependencies": {
57 "@effect/vitest": "catalog:",
20 "vitest": "catalog:"58 "vitest": "catalog:"
21 },59 },
60 "peerDependenciesMeta": {
61 "@effect/vitest": {
62 "optional": true
63 },
64 "vitest": {
65 "optional": true
66 }
67 },
22 "devDependencies": {68 "devDependencies": {
23 "typescript": "catalog:"69 "@effect/vitest": "catalog:",
70 "tsup": "catalog:",
71 "typescript": "catalog:",
72 "vitest": "catalog:"
24 }73 }
25}74}
packages/core/storage-core/tsup.config.ts+14−0
@@ -0,0 +1,14 @@
1import { defineConfig } from "tsup";
2
3export 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});
packages/kernel/core/README.md+40−0
@@ -0,0 +1,40 @@
1# @executor/codemode-core
2
3Core 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
5Most 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
10bun add @executor/codemode-core
11# or
12npm install @executor/codemode-core
13```
14
15## Usage
16
17Implement a runtime that satisfies `CodeExecutor`:
18
19```ts
20import type { CodeExecutor, SandboxToolInvoker } from "@executor/codemode-core";
21import { Effect } from "effect";
22
23export 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
32The 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
36Pre-`1.0`. APIs may still change between beta releases. Part of the [executor monorepo](https://github.com/RhysSullivan/executor).
37
38## License
39
40MIT
packages/kernel/core/package.json+28−2
@@ -1,12 +1,36 @@
1{1{
2 "name": "@executor/codemode-core",2 "name": "@executor/codemode-core",
3 "version": "1.4.3",3 "version": "0.0.1",
4 "private": true,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 "type": "module",17 "type": "module",
6 "exports": {18 "exports": {
7 ".": "./src/index.ts"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 "scripts": {32 "scripts": {
33 "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)",
10 "typecheck": "tsgo --noEmit",34 "typecheck": "tsgo --noEmit",
11 "test": "vitest run",35 "test": "vitest run",
12 "test:watch": "vitest",36 "test:watch": "vitest",
@@ -22,6 +46,8 @@ · 9 unmodified lines
22 "devDependencies": {46 "devDependencies": {
23 "@types/node": "catalog:",47 "@types/node": "catalog:",
24 "bun-types": "catalog:",48 "bun-types": "catalog:",
49 "tsup": "catalog:",
50 "typescript": "catalog:",
25 "vitest": "catalog:"51 "vitest": "catalog:"
26 }52 }
27}53}
packages/kernel/core/tsconfig.json+5−1
@@ -5,7 +5,11 @@ · 4 unmodified lines
5 "moduleResolution": "Bundler",5 "moduleResolution": "Bundler",
6 "strict": true,6 "strict": true,
7 "skipLibCheck": true,7 "skipLibCheck": true,
8 "noEmit": true,8 "outDir": "dist",
9 "rootDir": "src",
10 "declaration": true,
11 "declarationMap": true,
12 "sourceMap": true,
9 "lib": ["ES2022"],13 "lib": ["ES2022"],
10 "types": ["bun-types", "node"],14 "types": ["bun-types", "node"],
11 "noUnusedLocals": true,15 "noUnusedLocals": true,
packages/kernel/core/tsup.config.ts+12−0
@@ -0,0 +1,12 @@
1import { defineConfig } from "tsup";
2
3export 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});
packages/kernel/runtime-quickjs/README.md+60−0
@@ -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
8bun add @executor/execution @executor/runtime-quickjs
9# or
10npm install @executor/execution @executor/runtime-quickjs
11```
12
13## Usage
14
15Pass a `makeQuickJsExecutor()` as the `codeExecutor` when building the execution engine:
16
17```ts
18import { createExecutor } from "@executor/sdk";
19import { createExecutionEngine } from "@executor/execution";
20import { makeQuickJsExecutor } from "@executor/runtime-quickjs";
21
22const executor = await createExecutor({ scope: { name: "my-app" } });
23
24const 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
45import { setQuickJSModule } from "@executor/runtime-quickjs";
46import { newQuickJSAsyncWASMModuleFromVariant } from "quickjs-emscripten";
47import variant from "@jitl/quickjs-ng-wasmfile-release-sync";
48
49setQuickJSModule(await newQuickJSAsyncWASMModuleFromVariant(variant));
50```
51
52Use this when you want a different WASM variant (e.g. debug builds, QuickJS-NG) than the default bundled one.
53
54## Status
55
56Pre-`1.0`. APIs may still change between beta releases. Part of the [executor monorepo](https://github.com/RhysSullivan/executor).
57
58## License
59
60MIT
packages/kernel/runtime-quickjs/package.json+28−2
@@ -1,12 +1,36 @@
1{1{
2 "name": "@executor/runtime-quickjs",2 "name": "@executor/runtime-quickjs",
3 "version": "1.4.3",3 "version": "0.0.1",
4 "private": true,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 "type": "module",17 "type": "module",
6 "exports": {18 "exports": {
7 ".": "./src/index.ts"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 "scripts": {32 "scripts": {
33 "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)",
10 "typecheck": "tsgo --noEmit",34 "typecheck": "tsgo --noEmit",
11 "test": "vitest run",35 "test": "vitest run",
12 "test:watch": "vitest",36 "test:watch": "vitest",
@@ -21,6 +45,8 @@ · 8 unmodified lines
21 "@effect/vitest": "catalog:",45 "@effect/vitest": "catalog:",
22 "@types/node": "catalog:",46 "@types/node": "catalog:",
23 "bun-types": "catalog:",47 "bun-types": "catalog:",
48 "tsup": "catalog:",
49 "typescript": "catalog:",
24 "vitest": "catalog:"50 "vitest": "catalog:"
25 }51 }
26}52}
packages/kernel/runtime-quickjs/tsconfig.json+5−1
@@ -5,7 +5,11 @@ · 4 unmodified lines
5 "moduleResolution": "Bundler",5 "moduleResolution": "Bundler",
6 "strict": true,6 "strict": true,
7 "skipLibCheck": true,7 "skipLibCheck": true,
8 "noEmit": true,8 "outDir": "dist",
9 "rootDir": "src",
10 "declaration": true,
11 "declarationMap": true,
12 "sourceMap": true,
9 "lib": ["ES2022"],13 "lib": ["ES2022"],
10 "types": ["bun-types", "node"],14 "types": ["bun-types", "node"],
11 "noUnusedLocals": true,15 "noUnusedLocals": true,
packages/kernel/runtime-quickjs/tsup.config.ts+12−0
@@ -0,0 +1,12 @@
1import { defineConfig } from "tsup";
2
3export 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});

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t