This reverts commit 3c67ec0bdddeaba60d56beeca8bdba61ebe3ad3c.
Unified · Split
| @@ -11,7 +11,7 @@ import { · 10 unmodified lines | ||
| 11 | 11 | makeScopedKv, |
| 12 | 12 | migrate, |
| 13 | 13 | } from "@executor/storage-file"; |
| 14 | −import { withConfigFile, loadConfig, SECRET_REF_PREFIX, type ConfigHeaderValue } from "@executor/config"; | |
| 14 | +import { withConfigFile } from "@executor/config"; | |
| 15 | 15 | import { |
| 16 | 16 | openApiPlugin, |
| 17 | 17 | makeKvOperationStore, |
| @@ -69,7 +69,7 @@ export class ExecutorService extends Context.Tag("ExecutorService")< · 51 unmodified lines | ||
| 69 | 69 | // --------------------------------------------------------------------------- |
| 70 | 70 | |
| 71 | 71 | import { homedir } from "node:os"; |
| 72 | −import { dirname, join, resolve } from "node:path"; | |
| 72 | +import { join } from "node:path"; | |
| 73 | 73 | |
| 74 | 74 | const resolveDataDir = (): string => { |
| 75 | 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 | |
| 83 | 83 | const DB_PATH = `${DATA_DIR}/data.db`; |
| 84 | 84 | |
| 85 | −const 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 | − | |
| 96 | −const 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 | − | |
| 117 | −const 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 | 86 | // Executor Layer — SQLite-backed, scoped to ManagedRuntime lifetime |
| 149 | 87 | // --------------------------------------------------------------------------- |
| @@ -155,15 +93,15 @@ const ExecutorLayer = Layer.effect( · 5 unmodified lines | ||
| 155 | 93 | |
| 156 | 94 | yield* migrate.pipe(Effect.catchAll((e) => Effect.die(e))); |
| 157 | 95 | |
| 158 | − const executorRoot = resolveExecutorRoot(process.cwd()); | |
| 96 | + const cwd = process.cwd(); | |
| 159 | 97 | const kv = makeSqliteKv(sql); |
| 160 | − const config = makeKvConfig(kv, { cwd: executorRoot }); | |
| 161 | − const scopedKv = makeScopedKv(kv, executorRoot); | |
| 98 | + const config = makeKvConfig(kv, { cwd }); | |
| 99 | + const scopedKv = makeScopedKv(kv, cwd); | |
| 162 | 100 | |
| 163 | − const configPath = join(executorRoot, "executor.jsonc"); | |
| 101 | + const configPath = join(process.cwd(), "executor.jsonc"); | |
| 164 | 102 | const fsLayer = NodeFileSystem.layer; |
| 165 | 103 | |
| 166 | − const executor = yield* createExecutor({ | |
| 104 | + return yield* createExecutor({ | |
| 167 | 105 | ...config, |
| 168 | 106 | plugins: [ |
| 169 | 107 | openApiPlugin({ |
| @@ -200,65 +138,6 @@ const ExecutorLayer = Layer.effect( · 30 unmodified lines | ||
| 200 | 138 | }), |
| 201 | 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 | 142 | ).pipe(Layer.provide(SqliteClient.layer({ filename: DB_PATH }))); |
| 264 | 143 | |
File renamed without changes.