History

Revert "Fix root executor config resolution"

This reverts commit 3c67ec0bdddeaba60d56beeca8bdba61ebe3ad3c.

Rhys Sullivan committed 7 months ago

Commit ec5fc2b1 parent 3c67ec02 files · +7 −128Browse files

Unified · Split

2 files
  1. apps/server/src/services/executor.ts +7 −128
  2. apps/web/executor.jsonc +0 −0
apps/server/src/services/executor.ts+7−128
@@ -11,7 +11,7 @@ import { · 10 unmodified lines
11 makeScopedKv,11 makeScopedKv,
12 migrate,12 migrate,
13} from "@executor/storage-file";13} from "@executor/storage-file";
14import { withConfigFile, loadConfig, SECRET_REF_PREFIX, type ConfigHeaderValue } from "@executor/config";14import { withConfigFile } from "@executor/config";
15import {15import {
16 openApiPlugin,16 openApiPlugin,
17 makeKvOperationStore,17 makeKvOperationStore,
@@ -69,7 +69,7 @@ export class ExecutorService extends Context.Tag("ExecutorService")< · 51 unmodified lines
69// ---------------------------------------------------------------------------69// ---------------------------------------------------------------------------
70 70
71import { homedir } from "node:os";71import { homedir } from "node:os";
72import { dirname, join, resolve } from "node:path";72import { join } from "node:path";
73 73
74const resolveDataDir = (): string => {74const resolveDataDir = (): string => {
75 if (process.env.EXECUTOR_DATA_DIR) return process.env.EXECUTOR_DATA_DIR;75 if (process.env.EXECUTOR_DATA_DIR) return process.env.EXECUTOR_DATA_DIR;
@@ -82,68 +82,6 @@ fs.mkdirSync(DATA_DIR, { recursive: true }); · 6 unmodified lines
82 82
83const DB_PATH = `${DATA_DIR}/data.db`;83const DB_PATH = `${DATA_DIR}/data.db`;
84 84
85const hasWorkspacePackage = (dir: string): boolean => {
86 try {
87 const path = join(dir, "package.json");
88 if (!fs.existsSync(path)) return false;
89 const parsed = JSON.parse(fs.readFileSync(path, "utf8")) as { workspaces?: unknown };
90 return Array.isArray(parsed.workspaces);
91 } catch {
92 return false;
93 }
94};
95
96const resolveExecutorRoot = (startDir: string): string => {
97 let current = resolve(startDir);
98 let fallback = current;
99
100 for (;;) {
101 if (fs.existsSync(join(current, "executor.jsonc"))) {
102 return current;
103 }
104
105 if (fs.existsSync(join(current, ".git")) || hasWorkspacePackage(current)) {
106 fallback = current;
107 }
108
109 const parent = dirname(current);
110 if (parent === current) {
111 return fallback;
112 }
113 current = parent;
114 }
115};
116
117const toInvocationHeaders = (
118 headers: Record<string, ConfigHeaderValue> | undefined,
119): Record<string, string | { readonly secretId: string; readonly prefix?: string }> | undefined => {
120 if (!headers) return undefined;
121
122 return Object.fromEntries(
123 Object.entries(headers).map(([key, value]) => {
124 if (typeof value === "string") {
125 return [
126 key,
127 value.startsWith(SECRET_REF_PREFIX)
128 ? { secretId: value.slice(SECRET_REF_PREFIX.length) }
129 : value,
130 ];
131 }
132
133 const rawValue = value.value;
134 return [
135 key,
136 rawValue.startsWith(SECRET_REF_PREFIX)
137 ? {
138 secretId: rawValue.slice(SECRET_REF_PREFIX.length),
139 ...(value.prefix ? { prefix: value.prefix } : {}),
140 }
141 : rawValue,
142 ];
143 }),
144 );
145};
146
147// ---------------------------------------------------------------------------85// ---------------------------------------------------------------------------
148// Executor Layer — SQLite-backed, scoped to ManagedRuntime lifetime86// Executor Layer — SQLite-backed, scoped to ManagedRuntime lifetime
149// ---------------------------------------------------------------------------87// ---------------------------------------------------------------------------
@@ -155,15 +93,15 @@ const ExecutorLayer = Layer.effect( · 5 unmodified lines
155 93
156 yield* migrate.pipe(Effect.catchAll((e) => Effect.die(e)));94 yield* migrate.pipe(Effect.catchAll((e) => Effect.die(e)));
157 95
158 const executorRoot = resolveExecutorRoot(process.cwd());96 const cwd = process.cwd();
159 const kv = makeSqliteKv(sql);97 const kv = makeSqliteKv(sql);
160 const config = makeKvConfig(kv, { cwd: executorRoot });98 const config = makeKvConfig(kv, { cwd });
161 const scopedKv = makeScopedKv(kv, executorRoot);99 const scopedKv = makeScopedKv(kv, cwd);
162 100
163 const configPath = join(executorRoot, "executor.jsonc");101 const configPath = join(process.cwd(), "executor.jsonc");
164 const fsLayer = NodeFileSystem.layer;102 const fsLayer = NodeFileSystem.layer;
165 103
166 const executor = yield* createExecutor({104 return yield* createExecutor({
167 ...config,105 ...config,
168 plugins: [106 plugins: [
169 openApiPlugin({107 openApiPlugin({
@@ -200,65 +138,6 @@ const ExecutorLayer = Layer.effect( · 30 unmodified lines
200 }),138 }),
201 ] as const,139 ] as const,
202 });140 });
203
204 const fileConfig = yield* loadConfig(configPath).pipe(
205 Effect.provide(fsLayer),
206 Effect.catchAll((e) => Effect.die(e)),
207 );
208
209 if (fileConfig?.sources) {
210 const existingSources = new Set((yield* executor.sources.list()).map((source) => source.id));
211
212 for (const source of fileConfig.sources) {
213 if (source.namespace && existingSources.has(source.namespace)) {
214 continue;
215 }
216
217 if (source.kind === "openapi") {
218 yield* executor.openapi.addSpec({
219 spec: source.spec,
220 ...(source.baseUrl ? { baseUrl: source.baseUrl } : {}),
221 ...(source.namespace ? { namespace: source.namespace } : {}),
222 ...(source.headers ? { headers: toInvocationHeaders(source.headers) } : {}),
223 }).pipe(Effect.catchAll((e) => Effect.die(e)));
224 continue;
225 }
226
227 if (source.kind === "graphql") {
228 yield* executor.graphql.addSource({
229 endpoint: source.endpoint,
230 ...(source.introspectionJson ? { introspectionJson: source.introspectionJson } : {}),
231 ...(source.namespace ? { namespace: source.namespace } : {}),
232 ...(source.headers ? { headers: toInvocationHeaders(source.headers) } : {}),
233 }).pipe(Effect.catchAll((e) => Effect.die(e)));
234 continue;
235 }
236
237 yield* executor.mcp.addSource(
238 source.transport === "stdio"
239 ? {
240 transport: "stdio",
241 name: source.name,
242 command: source.command,
243 ...(source.args ? { args: [...source.args] } : {}),
244 ...(source.env ? { env: source.env } : {}),
245 ...(source.cwd ? { cwd: source.cwd } : {}),
246 ...(source.namespace ? { namespace: source.namespace } : {}),
247 }
248 : {
249 transport: "remote",
250 name: source.name,
251 endpoint: source.endpoint,
252 ...(source.remoteTransport ? { remoteTransport: source.remoteTransport } : {}),
253 ...(source.queryParams ? { queryParams: source.queryParams } : {}),
254 ...(source.headers ? { headers: source.headers } : {}),
255 ...(source.namespace ? { namespace: source.namespace } : {}),
256 },
257 ).pipe(Effect.catchAll((e) => Effect.die(e)));
258 }
259 }
260
261 return executor;
262 }),141 }),
263).pipe(Layer.provide(SqliteClient.layer({ filename: DB_PATH })));142).pipe(Layer.provide(SqliteClient.layer({ filename: DB_PATH })));
264 143
apps/web/executor.jsoncrenamed from executor.jsonc+0−0

File renamed without changes.