Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .oxlintrc.jsonc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"ignorePatterns": [".astro/"],
"rules": {
"typescript/no-explicit-any": "error",
},
Expand Down
5 changes: 3 additions & 2 deletions apps/cli/src/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ const buildBinaries = async (targets: Target[], mode: BuildMode) => {
entrypoints: [join(cliRoot, "src/main.ts")],
minify: mode === "production",
compile: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Bun compile target string is dynamically constructed
target: bunTarget(target) as any,
outfile: join(binDir, binaryName(target)),
},
Expand Down Expand Up @@ -554,8 +555,8 @@ const repositoryUrl = typeof packageJson.repository === "string"
? packageJson.repository
: packageJson.repository && packageJson.repository.url;
const githubBase = String(packageJson.homepage || repositoryUrl || "https://github.com/RhysSullivan/executor")
.replace(/^git\+/, "")
.replace(/\.git$/, "");
.replace(/^git[+]/, "")
.replace(/.git$/, "");
const version = packageJson.version;

const platformMap = { darwin: "darwin", linux: "linux", win32: "windows" };
Expand Down
18 changes: 12 additions & 6 deletions apps/cli/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,19 @@ if (typeof Bun !== "undefined" && (await Bun.file(wasmOnDisk).exists())) {
const variant = {
type: "sync" as const,
importFFI: () =>
import("@jitl/quickjs-wasmfile-release-sync/ffi").then((m: any) => m.QuickJSFFI),
import("@jitl/quickjs-wasmfile-release-sync/ffi").then(
(m: Record<string, unknown>) => m.QuickJSFFI,
),
importModuleLoader: () =>
import("@jitl/quickjs-wasmfile-release-sync/emscripten-module").then((m: any) => {
const original = m.default;
return (moduleArg: any = {}) => original({ ...moduleArg, wasmBinary });
}),
import("@jitl/quickjs-wasmfile-release-sync/emscripten-module").then(
(m: Record<string, unknown>) => {
const original = m.default as (...args: unknown[]) => unknown;
return (moduleArg: Record<string, unknown> = {}) =>
original({ ...moduleArg, wasmBinary });
},
),
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- quickjs-emscripten variant type is not publicly exported
const mod = await newQuickJSWASMModule(variant as any);
setQuickJSModule(mod);
}
Expand Down Expand Up @@ -200,7 +206,7 @@ const callCommand = Command.make(
}
} else {
console.log(result.text);
const executionId = (result.structured as any)?.executionId;
const executionId = (result.structured as Record<string, unknown> | undefined)?.executionId;
if (executionId) {
console.log(
`\nTo resume:\n ${cliPrefix} resume --execution-id ${executionId} --action accept`,
Expand Down
6 changes: 3 additions & 3 deletions apps/cloud/src/auth/workos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const make = Effect.gen(function* () {
cookiePassword,
});

const result = yield* use((wos) => session.authenticate());
const result = yield* use(() => session.authenticate());

if (result.authenticated) {
return {
Expand All @@ -58,7 +58,7 @@ const make = Effect.gen(function* () {
if (result.reason === "no_session_cookie_provided") return null;

// Try refreshing
const refreshed = yield* use((wos) => session.refresh()).pipe(
const refreshed = yield* use(() => session.refresh()).pipe(
Effect.orElseSucceed(() => ({ authenticated: false as const })),
);

Expand Down Expand Up @@ -117,7 +117,7 @@ const make = Effect.gen(function* () {
sessionData,
cookiePassword,
});
const refreshed = yield* use((wos) =>
const refreshed = yield* use(() =>
session.refresh(organizationId ? { organizationId } : undefined),
);
if (!refreshed.authenticated || !("sealedSession" in refreshed)) return null;
Expand Down
2 changes: 0 additions & 2 deletions apps/cloud/src/mcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
import { env } from "cloudflare:workers";
import { createRemoteJWKSet, jwtVerify } from "jose";

import type { McpSessionInit } from "./mcp-session";

// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion apps/cloud/src/routes/__root.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { HeadContent, Outlet, Scripts, createRootRoute } from "@tanstack/react-router";
import { HeadContent, Scripts, createRootRoute } from "@tanstack/react-router";
import { AutumnProvider } from "autumn-js/react";
import { ExecutorProvider } from "@executor/react/api/provider";
import { AuthProvider, useAuth } from "../web/auth";
Expand Down
1 change: 0 additions & 1 deletion apps/cloud/src/routes/billing_.plans.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ function PlansPage() {
const isCanceling = eligibility?.canceling ?? false;
const isCurrent = status === "active" && !isCanceling;
const isScheduled = status === "scheduled";
const isActionable = action !== "none";
const label = isCanceling ? "Resume" : (ACTION_LABELS[action] ?? "Select");
const isUpgradeAction = action === "upgrade" || action === "activate";

Expand Down
9 changes: 3 additions & 6 deletions apps/cloud/src/web/shell.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Link, Outlet, useLocation } from "@tanstack/react-router";
import { useEffect, useRef, useState } from "react";
import { useAtomRefresh, useAtomValue, Result } from "@effect-atom/atom-react";
import { sourcesAtom, toolsAtom } from "@executor/react/api/atoms";
import { useAtomValue, Result } from "@effect-atom/atom-react";
import { sourcesAtom } from "@executor/react/api/atoms";
import { useScope } from "@executor/react/api/scope-context";
import { Button } from "@executor/react/components/button";

import { AUTH_PATHS } from "../auth/api";
import { useAuth } from "./auth";

Expand Down Expand Up @@ -169,9 +169,6 @@ function SidebarContent(props: { pathname: string; onNavigate?: () => void; show
export function Shell() {
const location = useLocation();
const pathname = location.pathname;
const scopeId = useScope();
const refreshSources = useAtomRefresh(sourcesAtom(scopeId));
const refreshTools = useAtomRefresh(toolsAtom(scopeId));
const lastPathname = useRef(pathname);
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
if (lastPathname.current !== pathname) {
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/scripts/bundle-cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Builds the executor CLI binary and copies it into the desktop app's
* resources/ folder so electron-builder can bundle it as a sidecar.
*/
const { execSync, spawnSync } = require("node:child_process");
const { spawnSync } = require("node:child_process");
const { existsSync, mkdirSync, cpSync, chmodSync } = require("node:fs");
const { resolve, join } = require("node:path");

Expand Down
2 changes: 1 addition & 1 deletion apps/local/src/routes/__root.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { Outlet, createRootRoute } from "@tanstack/react-router";
import { createRootRoute } from "@tanstack/react-router";
import { ExecutorProvider } from "@executor/react/api/provider";
import { Shell } from "../web/shell";

Expand Down
4 changes: 2 additions & 2 deletions packages/core/api/src/handlers/secrets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const refToResponse = (ref: {

export const SecretsHandlers = HttpApiBuilder.group(ExecutorApi, "secrets", (handlers) =>
handlers
.handle("list", ({ path }) =>
.handle("list", () =>
Effect.gen(function* () {
const executor = yield* ExecutorService;
const refs = yield* executor.secrets.list();
Expand All @@ -37,7 +37,7 @@ export const SecretsHandlers = HttpApiBuilder.group(ExecutorApi, "secrets", (han
return { secretId: path.secretId, status };
}),
)
.handle("set", ({ path, payload }) =>
.handle("set", ({ payload }) =>
Effect.gen(function* () {
const executor = yield* ExecutorService;
const ref = yield* executor.secrets.set({
Expand Down
4 changes: 2 additions & 2 deletions packages/core/api/src/handlers/sources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { ExecutorService } from "../services";

export const SourcesHandlers = HttpApiBuilder.group(ExecutorApi, "sources", (handlers) =>
handlers
.handle("list", ({ path }) =>
.handle("list", () =>
Effect.gen(function* () {
const executor = yield* ExecutorService;
const sources = yield* executor.sources.list();
Expand Down Expand Up @@ -49,7 +49,7 @@ export const SourcesHandlers = HttpApiBuilder.group(ExecutorApi, "sources", (han
}));
}),
)
.handle("detect", ({ path, payload }) =>
.handle("detect", ({ payload }) =>
Effect.gen(function* () {
const executor = yield* ExecutorService;
const results = yield* executor.sources.detect(payload.url);
Expand Down
2 changes: 1 addition & 1 deletion packages/core/api/src/handlers/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { ExecutorService } from "../services";

export const ToolsHandlers = HttpApiBuilder.group(ExecutorApi, "tools", (handlers) =>
handlers
.handle("list", ({ path }) =>
.handle("list", () =>
Effect.gen(function* () {
const executor = yield* ExecutorService;
const tools = yield* executor.tools.list();
Expand Down
35 changes: 29 additions & 6 deletions packages/core/config/src/config-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,41 +157,64 @@ interface StoreWithSource<TSource> {
removeSource: (namespace: string) => Effect.Effect<void>;
}

interface OpenApiSource {
namespace: string;
name: string;
config: { spec: string; baseUrl?: string; namespace?: string; headers?: Record<string, unknown> };
}

interface GraphqlSource {
namespace: string;
name: string;
config: {
endpoint: string;
introspectionJson?: string;
namespace?: string;
headers?: Record<string, unknown>;
};
}

interface McpSource {
namespace: string;
name: string;
config: { transport: string; [key: string]: unknown };
}

/**
* Wrap a plugin store so putSource/removeSource also write to executor.jsonc.
* Preserves the full store type — only the two methods are intercepted.
*/
export const withConfigFile = {
openapi: <TStore extends StoreWithSource<{ namespace: string; name: string; config: any }>>(
openapi: <TStore extends StoreWithSource<OpenApiSource>>(
inner: TStore,
configPath: string,
fsLayer: Layer.Layer<FileSystem.FileSystem>,
): TStore =>
({
...inner,
putSource: wrapPutSource(inner.putSource, configPath, openApiToSourceConfig as any, fsLayer),
putSource: wrapPutSource(inner.putSource, configPath, openApiToSourceConfig, fsLayer),
removeSource: wrapRemoveSource(inner.removeSource, configPath, fsLayer),
}) as TStore,

graphql: <TStore extends StoreWithSource<{ namespace: string; name: string; config: any }>>(
graphql: <TStore extends StoreWithSource<GraphqlSource>>(
inner: TStore,
configPath: string,
fsLayer: Layer.Layer<FileSystem.FileSystem>,
): TStore =>
({
...inner,
putSource: wrapPutSource(inner.putSource, configPath, graphqlToSourceConfig as any, fsLayer),
putSource: wrapPutSource(inner.putSource, configPath, graphqlToSourceConfig, fsLayer),
removeSource: wrapRemoveSource(inner.removeSource, configPath, fsLayer),
}) as TStore,

mcp: <TStore extends StoreWithSource<{ namespace: string; name: string; config: any }>>(
mcp: <TStore extends StoreWithSource<McpSource>>(
inner: TStore,
configPath: string,
fsLayer: Layer.Layer<FileSystem.FileSystem>,
): TStore =>
({
...inner,
putSource: wrapPutSource(inner.putSource, configPath, mcpToSourceConfig as any, fsLayer),
putSource: wrapPutSource(inner.putSource, configPath, mcpToSourceConfig, fsLayer),
removeSource: wrapRemoveSource(inner.removeSource, configPath, fsLayer),
}) as TStore,
};
1 change: 1 addition & 0 deletions packages/core/env/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ describe("createEnv", () => {
},
);

// oxlint-disable-next-line no-constant-condition -- compile-time-only type check
if (false) {
createEnv(
{
Expand Down
14 changes: 6 additions & 8 deletions packages/core/execution/src/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,14 @@ export const formatPausedExecution = (
structured: Record<string, unknown>;
} => {
const req = paused.elicitationContext.request;
const lines: string[] = [`Execution paused: ${(req as any).message}`];
const lines: string[] = [`Execution paused: ${req.message}`];

if (req._tag === "UrlElicitation") {
lines.push(`\nOpen this URL in a browser:\n${(req as any).url}`);
lines.push(`\nOpen this URL in a browser:\n${req.url}`);
lines.push("\nAfter the browser flow, resume with the executionId below:");
} else {
lines.push("\nResume with the executionId below and a response matching the requested schema:");
const schema = (req as any).requestedSchema;
const schema = req.requestedSchema;
if (schema && Object.keys(schema).length > 0) {
lines.push(`\nRequested schema:\n${JSON.stringify(schema, null, 2)}`);
}
Expand All @@ -125,11 +125,9 @@ export const formatPausedExecution = (
executionId: paused.id,
interaction: {
kind: req._tag === "UrlElicitation" ? "url" : "form",
message: (req as any).message,
...(req._tag === "UrlElicitation" ? { url: (req as any).url } : {}),
...(req._tag === "FormElicitation"
? { requestedSchema: (req as any).requestedSchema }
: {}),
message: req.message,
...(req._tag === "UrlElicitation" ? { url: req.url } : {}),
...(req._tag === "FormElicitation" ? { requestedSchema: req.requestedSchema } : {}),
},
},
};
Expand Down
1 change: 0 additions & 1 deletion packages/core/sdk/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
ElicitationResponse,
Source,
type MemoryToolContext,
type ToolId,
type InvokeOptions,
SecretId,
} from "./index";
Expand Down
3 changes: 2 additions & 1 deletion packages/core/sdk/src/plugins/in-memory-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,9 +267,9 @@ export function tool<TInput, TOutput>(
// Plugin factory
// ---------------------------------------------------------------------------

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const inMemoryToolsPlugin = (config: {
readonly namespace?: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Schema.Schema is invariant; `any` required to accept arbitrary MemoryToolDefinition types
readonly tools: readonly MemoryToolDefinition<any, any>[];
}) => {
const ns = config.namespace ?? "memory";
Expand Down Expand Up @@ -303,6 +303,7 @@ export const inMemoryToolsPlugin = (config: {

return {
extension: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Schema.Schema is invariant; `any` required to accept arbitrary MemoryToolDefinition types
addTools: (newTools: readonly MemoryToolDefinition<any, any>[]) =>
Effect.gen(function* () {
const newResults = newTools.map((t) => buildRegistration(ns, t));
Expand Down
Loading