History

remove legacy compatibility codepaths

Rhys Sullivan committed 7 months ago

Commit ddd3aaa1 parent e2977a021 files · +111 −1158Browse files

Unified · Split

21 files
  1. apps/executor/src/cli/main.ts +0 −207
  2. packages/hosts/mcp/src/paused-result.test.ts +1 −1
  3. packages/platform/sdk-file/src/config.test.ts +8 −54
  4. packages/platform/sdk-file/src/config.ts +0 −172
  5. packages/platform/sdk-file/src/executor-state-store.ts +1 −148
  6. packages/platform/sdk-file/src/index.ts +8 −5
  7. packages/platform/sdk-file/src/secret-material-providers.ts +53 −21
  8. packages/platform/sdk/src/local/secret-stores.ts +17 −13
  9. packages/platform/sdk/src/plugins.ts +2 −2
  10. packages/platform/sdk/src/runtime/execution/scope/tool-invoker.ts +1 −1
  11. packages/platform/sdk/src/runtime/index.ts +2 −0
  12. packages/platform/sdk/src/runtime/source-artifacts.ts +2 −27
  13. packages/platform/sdk/src/runtime/sources/executor-tools.test.ts +0 −68
  14. packages/platform/sdk/src/runtime/sources/executor-tools.ts +0 −146
  15. packages/platform/sdk/src/runtime/sources/source-store/plugin-local-config.ts +0 −83
  16. packages/platform/server/src/index.test.ts +15 −14
  17. plugins/google-discovery/sdk/index.ts +0 −50
  18. plugins/graphql/sdk/index.ts +0 −43
  19. plugins/mcp/sdk/index.ts +0 −56
  20. plugins/mcp/sdk/tools.test.ts +1 −1
  21. plugins/openapi/sdk/index.ts +0 −46
apps/executor/src/cli/main.ts+0−207
@@ -90,7 +90,6 @@ import { · 89 unmodified lines
9090 import { decideInteractionHandling } from "./interaction-handling";
9191 import {
9292 renderMcpSessionSummary,
93− renderUpSummary,
9493 renderWebSessionSummary,
9594 } from "./session-summary";
9695 import {
@@ -415,8 +414,6 @@ const printRootHelp = (workflow: string) => · 318 unmodified lines
415414 " Execute code against the local executor server.",
416415 " resume",
417416 " Resume a paused execution.",
418− " up / down / status / doctor",
419− " Compatibility commands for the detached local daemon.",
420417 "",
421418 "TIP",
422419 "",
@@ -625,154 +622,11 @@ const waitForReachability = (baseUrl: string, expected: boolean) => · 202 unmodified lines
625622 return yield* failReachabilityTimeout({ baseUrl, expected });
626623 });
627624
628−type LocalServerStatus = {
629− baseUrl: string;
630− reachable: boolean;
631− pidFile: string;
632− pid: number | null;
633− pidRunning: boolean;
634− logFile: string;
635− localDataDir: string;
636− webAssetsDir: string | null;
637− installation: {
638− accountId: string;
639− workspaceId: string;
640− } | null;
641−};
642−
643−const getServerStatus = (
644− baseUrl: string,
645−): Effect.Effect<LocalServerStatus, Error, FileSystem.FileSystem> =>
646− Effect.gen(function* () {
647− const pidRecord = yield* readPidRecord();
648− const reachable = yield* isServerReachable(baseUrl);
649− const installation = reachable
650− ? yield* getBootstrapClient(baseUrl).pipe(
651− Effect.flatMap((client) => client.local.installation({})),
652− Effect.map((installation) => ({
653− accountId: installation.actorScopeId,
654− workspaceId: installation.scopeId,
655− })),
656− Effect.catchAll(() => Effect.succeed(null)),
657− )
658− : null;
659−
660− const pid = typeof pidRecord?.pid === "number" ? pidRecord.pid : null;
661− const pidRunning = pid !== null ? isPidRunning(pid) : false;
662− const logFile = pidRecord?.logFile ?? DEFAULT_SERVER_LOG_FILE;
663−
664− return {
665− baseUrl,
666− reachable,
667− pidFile: DEFAULT_SERVER_PID_FILE,
668− pid,
669− pidRunning,
670− logFile,
671− localDataDir: CLI_LOCAL_DATA_DIR,
672− webAssetsDir: resolveRuntimeWebAssetsDir(),
673− installation,
674− } satisfies LocalServerStatus;
675− });
676−
677−const renderStatus = (status: LocalServerStatus): string =>
678− [
679− `baseUrl: ${status.baseUrl}`,
680− `reachable: ${status.reachable ? "yes" : "no"}`,
681− `pid: ${status.pid ?? "none"}`,
682− `pidRunning: ${status.pidRunning ? "yes" : "no"}`,
683− `pidFile: ${status.pidFile}`,
684− `logFile: ${status.logFile}`,
685− `localDataDir: ${status.localDataDir}`,
686− `webAssetsDir: ${status.webAssetsDir ?? "missing"}`,
687− `workspaceId: ${status.installation?.workspaceId ?? "unavailable"}`,
688− ].join("\n");
689−
690−const getDoctorReport = (baseUrl: string) =>
691− getServerStatus(baseUrl).pipe(
692− Effect.map((status) => {
693− const checks = {
694− serverReachable: {
695− ok: status.reachable,
696− detail: status.reachable ? `reachable at ${status.baseUrl}` : `not reachable at ${status.baseUrl}`,
697− },
698− pidFile: {
699− ok: status.pid !== null,
700− detail: status.pid !== null ? `pid ${status.pid}` : `missing pid file at ${status.pidFile}`,
701− },
702− process: {
703− ok: status.pidRunning,
704− detail: status.pidRunning ? `pid ${status.pid}` : "no live daemon process recorded",
705− },
706− database: {
707− ok: status.localDataDir.length > 0,
708− detail: status.localDataDir,
709− },
710− webAssets: {
711− ok: status.webAssetsDir !== null,
712− detail: status.webAssetsDir ?? "missing bundled web assets",
713− },
714− installation: {
715− ok: status.installation !== null,
716− detail: status.installation
717− ? `workspace ${status.installation.workspaceId}`
718− : "local installation unavailable",
719− },
720− } as const;
721−
722− return {
723− ok: Object.values(checks).every((check) => check.ok),
724− status,
725− checks,
726− };
727− }),
728− );
729−
730−const printJson = (value: unknown) =>
731− Effect.sync(() => {
732− console.log(JSON.stringify(value, null, 2));
733− });
734−
735625 const printText = (value: string) =>
736626 Effect.sync(() => {
737627 console.log(value);
738628 });
739629
740−const stopServer = (baseUrl: string) =>
741− Effect.gen(function* () {
742− const fs = yield* FileSystem.FileSystem;
743− const removePidFile = fs.remove(DEFAULT_SERVER_PID_FILE, {
744− force: true,
745− }).pipe(Effect.ignore);
746− const pidRecord = yield* readPidRecord();
747− const pid = typeof pidRecord?.pid === "number" ? pidRecord.pid : null;
748−
749− if (pid === null) {
750− yield* removePidFile;
751− return false;
752− }
753−
754− if (!isPidRunning(pid)) {
755− yield* removePidFile;
756− return false;
757− }
758−
759−
760− yield* Effect.sync(() => {
761− process.kill(pid, "SIGTERM");
762− });
763−
764− yield* waitForReachability(baseUrl, false).pipe(
765− Effect.catchAll(() =>
766− removePidFile.pipe(
767− Effect.ignore,
768− Effect.zipRight(Effect.fail(executorAppEffectError("cli/main", `Timed out stopping local executor server pid ${pid}`))),
769− ),
770− ),
771− );
772−
773− return true;
774− });
775−
776630 const ensureServer = (baseUrl: string = DEFAULT_SERVER_BASE_URL) =>
777631 Effect.gen(function* () {
778632 const reachable = yield* isServerReachable(baseUrl);
@@ -1243,63 +1097,6 @@ const mcpCommand = Command.make( · 464 unmodified lines
12431097 : runForegroundSession({ kind: "mcp", port }),
12441098 ).pipe(Command.withDescription("Start a foreground MCP session, or run stdio MCP with --stdio"));
12451099
1246−const upCommand = Command.make(
1247− "up",
1248− {
1249− baseUrl: Options.text("base-url").pipe(Options.withDefault(DEFAULT_SERVER_BASE_URL)),
1250− },
1251− ({ baseUrl }) =>
1252− ensureServer(baseUrl).pipe(
1253− Effect.flatMap(({ started }) =>
1254− getServerStatus(baseUrl).pipe(
1255− Effect.flatMap((status) => printText(renderUpSummary({ started, status }))),
1256− )
1257− ),
1258− ),
1259−).pipe(Command.withDescription("Start the local executor server if needed and show how to use it"));
1260−
1261−const downCommand = Command.make(
1262− "down",
1263− {
1264− baseUrl: Options.text("base-url").pipe(Options.withDefault(DEFAULT_SERVER_BASE_URL)),
1265− },
1266− ({ baseUrl }) =>
1267− stopServer(baseUrl).pipe(
1268− Effect.flatMap((stopped) =>
1269− printText(stopped ? "Stopped local executor server." : "Local executor server is not running."),
1270− ),
1271− ),
1272−).pipe(Command.withDescription("Stop the local executor server"));
1273−
1274−const statusCommand = Command.make(
1275− "status",
1276− {
1277− baseUrl: Options.text("base-url").pipe(Options.withDefault(DEFAULT_SERVER_BASE_URL)),
1278− json: Options.boolean("json").pipe(Options.withDefault(false)),
1279− },
1280− ({ baseUrl, json }) =>
1281− getServerStatus(baseUrl).pipe(
1282− Effect.flatMap((status) => json ? printJson(status) : printText(renderStatus(status))),
1283− ),
1284−).pipe(Command.withDescription("Show local executor server status"));
1285−
1286−const doctorCommand = Command.make(
1287− "doctor",
1288− {
1289− baseUrl: Options.text("base-url").pipe(Options.withDefault(DEFAULT_SERVER_BASE_URL)),
1290− json: Options.boolean("json").pipe(Options.withDefault(false)),
1291− },
1292− ({ baseUrl, json }) =>
1293− getDoctorReport(baseUrl).pipe(
1294− Effect.flatMap((report) => json
1295− ? printJson(report)
1296− : printText([
1297− `ok: ${report.ok ? "yes" : "no"}`,
1298− ...Object.entries(report.checks).map(([name, check]) => `${name}: ${check.ok ? "ok" : "fail"} - ${check.detail}`),
1299− ].join("\n"))),
1300− ),
1301−).pipe(Command.withDescription("Check local executor install and daemon health"));
1302−
13031100 const callCommand = Command.make(
13041101 "call",
13051102 {
@@ -1386,10 +1183,6 @@ const root = Command.make("executor").pipe( · 80 unmodified lines
13861183 serverCommand,
13871184 webCommand,
13881185 mcpCommand,
1389− upCommand,
1390− downCommand,
1391− statusCommand,
1392− doctorCommand,
13931186 callCommand,
13941187 resumeCommand,
13951188 devCommand,
packages/hosts/mcp/src/paused-result.test.ts+1−1
@@ -38,7 +38,7 @@ const makeEnvelope = ( · 37 unmodified lines
3838 scopeId: "ws_123" as never,
3939 createdByScopeId: "acct_123" as never,
4040 status: "waiting_for_interaction",
41− code: "return await tools.executor.sources.add({ endpoint: 'https://mcp.axiom.co/mcp' });",
41+ code: "return await tools.executor.mcp.createSource({ name: 'Axiom', endpoint: 'https://mcp.axiom.co/mcp', transport: 'streamable-http', queryParams: null, headers: null, command: null, args: null, env: null, cwd: null, auth: { kind: 'none' } });",
4242 resultJson: null,
4343 errorText: null,
4444 logsJson: null,
packages/platform/sdk-file/src/config.test.ts+8−54
@@ -8,7 +8,6 @@ import * as Effect from "effect/Effect"; · 7 unmodified lines
88 import {
99 loadLocalExecutorConfig,
1010 mergeLocalExecutorConfigs,
11− migrateLegacyLocalExecutorConfigFile,
1211 resolveDefaultHomeConfigCandidates,
1312 resolveDefaultHomeStateDirectory,
1413 resolveLocalWorkspaceContext,
@@ -39,10 +38,15 @@ describe("local-config", () => { · 24 unmodified lines
3938 "sources": {
4039 "github": {
4140 "kind": "openapi",
42− "binding": {
41+ "config": {
4342 "specUrl": "https://example.com/openapi.json",
44− },
45− },
43+ "baseUrl": null,
44+ "auth": {
45+ "kind": "none"
46+ },
47+ "defaultHeaders": null
48+ }
49+ }
4650 },
4751 }
4852 `,
@@ -137,54 +141,4 @@ describe("local-config", () => { · 88 unmodified lines
137141
138142 expect(merged?.runtime).toBe("deno");
139143 });
140−
141− it.effect("migrates legacy preset source stubs before strict decode", () =>
142− Effect.gen(function* () {
143− const fs = yield* FileSystem.FileSystem;
144− const workspaceRoot = yield* makeWorkspaceRoot();
145− const homeConfigPath = join(workspaceRoot, "executor-home.jsonc");
146−
147− yield* fs.writeFileString(
148− homeConfigPath,
149− `{
150− "sources": {
151− "axiom": {
152− "name": "Axiom MCP",
153− "kind": "mcp"
154− },
155− "stripe-api": {
156− "name": "Stripe API",
157− "namespace": "stripe.api",
158− "kind": "openapi"
159− },
160− "kept": {
161− "name": "Kept",
162− "kind": "openapi",
163− "connection": {
164− "endpoint": "https://example.com"
165− },
166− "binding": {
167− "specUrl": "https://example.com/openapi.json"
168− }
169− }
170− }
171−}
172−`,
173− );
174−
175− const changed = yield* migrateLegacyLocalExecutorConfigFile(homeConfigPath);
176− const migratedContent = yield* fs.readFileString(homeConfigPath, "utf8");
177− const context = yield* resolveLocalWorkspaceContext({
178− workspaceRoot,
179− homeConfigPath,
180− });
181− const loaded = yield* loadLocalExecutorConfig(context);
182−
183− expect(changed).toBe(true);
184− expect(migratedContent).not.toContain("\"axiom\"");
185− expect(migratedContent).not.toContain("\"stripe-api\"");
186− expect(loaded.config?.sources?.kept?.kind).toBe("openapi");
187− expect(loaded.config?.sources?.axiom).toBeUndefined();
188− }).pipe(Effect.provide(NodeFileSystem.layer)),
189− );
190144 });
packages/platform/sdk-file/src/config.ts+0−172
@@ -33,9 +33,6 @@ export type FileLoadedExecutorConfig = LoadedLocalExecutorConfig & { · 32 unmodified lines
3333 export const encodeLocalExecutorConfig = (config: LocalExecutorConfig): string =>
3434 `${JSON.stringify(config, null, 2)}\n`;
3535
36−const encodeUnknownConfigDocument = (config: unknown): string =>
37− `${JSON.stringify(config, null, 2)}\n`;
38−
3936 export const resolveConfigRelativePath = (input: {
4037 path: string;
4138 scopeRoot: string;
@@ -226,130 +223,6 @@ const parseJsonc = (input: { path: string; content: string }): LocalExecutorConf · 184 unmodified lines
226223 }
227224 };
228225
229−const parseUnknownJsoncDocument = (input: {
230− path: string;
231− content: string;
232−}): unknown => {
233− const errors: JsoncParseError[] = [];
234−
235− try {
236− const parsed = parseJsoncDocument(input.content, errors, {
237− allowTrailingComma: true,
238− });
239− if (errors.length > 0) {
240− throw new LocalExecutorConfigDecodeError({
241− message: `Invalid executor config at ${input.path}: ${formatJsoncParseErrors(input.content, errors)}`,
242− path: input.path,
243− details: formatJsoncParseErrors(input.content, errors),
244− });
245− }
246−
247− return parsed;
248− } catch (cause) {
249− if (cause instanceof LocalExecutorConfigDecodeError) {
250− throw cause;
251− }
252− throw new LocalExecutorConfigDecodeError({
253− message: `Invalid executor config at ${input.path}: ${unknownLocalErrorDetails(cause)}`,
254− path: input.path,
255− details: unknownLocalErrorDetails(cause),
256− });
257− }
258−};
259−
260−const asRecord = (value: unknown): Record<string, unknown> | null =>
261− value !== null && typeof value === "object" && !Array.isArray(value)
262− ? value as Record<string, unknown>
263− : null;
264−
265−const migrateLegacySourceEntries = (
266− sources: unknown,
267−): {
268− sources: unknown;
269− changed: boolean;
270−} => {
271− const sourceMap = asRecord(sources);
272− if (!sourceMap) {
273− return {
274− sources,
275− changed: false,
276− };
277− }
278−
279− let changed = false;
280− const migratedEntries = Object.entries(sourceMap).flatMap(([key, value]) => {
281− const source = asRecord(value);
282− if (!source) {
283− return [[key, value] as const];
284− }
285−
286− const hasConnection = asRecord(source.connection) !== null;
287− const kind = typeof source.kind === "string" ? source.kind : null;
288− const isLegacyPresetStub =
289− kind !== null
290− && hasConnection === false;
291−
292− if (isLegacyPresetStub) {
293− changed = true;
294− return [];
295− }
296−
297− return [[key, value] as const];
298− });
299−
300− if (!changed) {
301− return {
302− sources,
303− changed: false,
304− };
305− }
306−
307− return {
308− sources: migratedEntries.length > 0
309− ? Object.fromEntries(migratedEntries)
310− : undefined,
311− changed: true,
312− };
313−};
314−
315−const migrateLegacyLocalExecutorConfigDocument = (
316− value: unknown,
317−): {
318− value: unknown;
319− changed: boolean;
320−} => {
321− const root = asRecord(value);
322− if (!root) {
323− return {
324− value,
325− changed: false,
326− };
327− }
328−
329− const migratedSources = migrateLegacySourceEntries(root.sources);
330− if (!migratedSources.changed) {
331− return {
332− value,
333− changed: false,
334− };
335− }
336−
337− const nextRoot: Record<string, unknown> = {
338− ...root,
339− };
340−
341− if (migratedSources.sources === undefined) {
342− delete nextRoot.sources;
343− } else {
344− nextRoot.sources = migratedSources.sources;
345− }
346−
347− return {
348− value: nextRoot,
349− changed: true,
350− };
351−};
352−
353226 const mergeSourceMaps = (
354227 base: Record<string, LocalConfigSource> | undefined,
355228 extra: Record<string, LocalConfigSource> | undefined,
@@ -553,51 +426,6 @@ export const readOptionalLocalExecutorConfig = ( · 197 unmodified lines
553426 });
554427 });
555428
556−export const migrateLegacyLocalExecutorConfigFile = (
557− path: string,
558−): Effect.Effect<
559− boolean,
560− LocalFileSystemError | LocalExecutorConfigDecodeError,
561− FileSystem.FileSystem
562−> =>
563− Effect.gen(function* () {
564− const fs = yield* FileSystem.FileSystem;
565− const exists = yield* fs.exists(path).pipe(
566− Effect.mapError(mapFileSystemError(path, "check config path")),
567− );
568− if (!exists) {
569− return false;
570− }
571−
572− const content = yield* fs.readFileString(path, "utf8").pipe(
573− Effect.mapError(mapFileSystemError(path, "read config")),
574− );
575− const parsed = parseUnknownJsoncDocument({ path, content });
576− const migrated = migrateLegacyLocalExecutorConfigDocument(parsed);
577−
578− if (!migrated.changed) {
579− return false;
580− }
581−
582− const decoded = decodeLocalExecutorConfig(migrated.value);
583− yield* fs.writeFileString(path, encodeUnknownConfigDocument(decoded)).pipe(
584− Effect.mapError(mapFileSystemError(path, "write config")),
585− );
586− return true;
587− });
588−
589−export const migrateLegacyLocalExecutorConfigs = (
590− context: ResolvedLocalWorkspaceContext,
591−): Effect.Effect<
592− void,
593− LocalFileSystemError | LocalExecutorConfigDecodeError,
594− FileSystem.FileSystem
595−> =>
596− Effect.gen(function* () {
597− yield* migrateLegacyLocalExecutorConfigFile(context.homeConfigPath);
598− yield* migrateLegacyLocalExecutorConfigFile(context.projectConfigPath);
599− });
600−
601429 export const loadLocalExecutorConfig = (
602430 context: ResolvedLocalWorkspaceContext,
603431 ): Effect.Effect<
packages/platform/sdk-file/src/executor-state-store.ts+1−148
@@ -28,8 +28,6 @@ import { · 27 unmodified lines
2828
2929 const LOCAL_EXECUTOR_STATE_VERSION = 1 as const;
3030 const LOCAL_EXECUTOR_STATE_BASENAME = "executor-state.json";
31−const LEGACY_LOCAL_SECRET_STORE_ID = "sts_builtin_local";
32−const LEGACY_KEYCHAIN_SECRET_STORE_ID = "sts_builtin_keychain";
3331
3432 const LocalExecutorStateSnapshotSchema = Schema.Struct({
3533 version: Schema.Literal(LOCAL_EXECUTOR_STATE_VERSION),
@@ -63,145 +61,6 @@ const defaultLocalExecutorStateSnapshot = (): LocalExecutorStateSnapshot => ({ · 27 unmodified lines
6361 const cloneValue = <T>(value: T): T =>
6462 JSON.parse(JSON.stringify(value)) as T;
6563
66−const asRecord = (
67− value: unknown,
68−): Record<string, unknown> | null =>
69− value !== null && typeof value === "object" && !Array.isArray(value)
70− ? (value as Record<string, unknown>)
71− : null;
72−
73−const legacySecretStoreIdForProviderId = (providerId: string): string =>
74− providerId === "local"
75− ? LEGACY_LOCAL_SECRET_STORE_ID
76− : providerId === "keychain"
77− ? LEGACY_KEYCHAIN_SECRET_STORE_ID
78− : `sts_legacy_${providerId}`;
79−
80−const legacySecretStoreNameForProviderId = (providerId: string): string => {
81− switch (providerId) {
82− case "local":
83− return "Local Store";
84− case "keychain":
85− return process.platform === "darwin"
86− ? "macOS Keychain"
87− : "Desktop Keyring";
88− default:
89− return `Legacy ${providerId}`;
90− }
91−};
92−
93−const migrateLegacyExecutorStateValue = (
94− value: unknown,
95− input: {
96− scopeId: string;
97− },
98−): {
99− value: unknown;
100− migrated: boolean;
101−} => {
102− if (Array.isArray(value)) {
103− let migrated = false;
104− const next = value.map((item) => {
105− const result = migrateLegacyExecutorStateValue(item, input);
106− migrated = migrated || result.migrated;
107− return result.value;
108− });
109− return { value: next, migrated };
110− }
111−
112− const record = asRecord(value);
113− if (record === null) {
114− return { value, migrated: false };
115− }
116−
117− let migrated = false;
118− const next: Record<string, unknown> = {};
119−
120− for (const [key, entry] of Object.entries(record)) {
121− let nextKey = key;
122− if (key === "workspaceId") {
123− nextKey = "scopeId";
124− migrated = true;
125− } else if (key === "actorAccountId") {
126− nextKey = "actorScopeId";
127− migrated = true;
128− } else if (key === "createdByAccountId") {
129− nextKey = "createdByScopeId";
130− migrated = true;
131− } else if (key === "workspaceOauthClients") {
132− nextKey = "scopeOauthClients";
133− migrated = true;
134− }
135−
136− const migratedEntry = migrateLegacyExecutorStateValue(entry, input);
137− migrated = migrated || migratedEntry.migrated;
138− next[nextKey] = migratedEntry.value;
139− }
140−
141− if (next.version === LOCAL_EXECUTOR_STATE_VERSION) {
142− const secretMaterialsValue = Array.isArray(next.secretMaterials)
143− ? next.secretMaterials
144− : [];
145− const secretStoresValue = Array.isArray(next.secretStores)
146− ? next.secretStores
147− : [];
148− const secretStoresById = new Map<string, Record<string, unknown>>();
149−
150− for (const entry of secretStoresValue) {
151− const record = asRecord(entry);
152− if (record !== null && typeof record.id === "string") {
153− secretStoresById.set(record.id, record);
154− }
155− }
156−
157− const migratedSecretMaterials = secretMaterialsValue.map((entry) => {
158− const record = asRecord(entry);
159− if (record === null) {
160− return entry;
161− }
162−
163− if (typeof record.providerId !== "string" || typeof record.storeId === "string") {
164− return entry;
165− }
166−
167− const providerId = record.providerId;
168− const storeId = legacySecretStoreIdForProviderId(providerId);
169− const createdAt =
170− typeof record.createdAt === "number" ? record.createdAt : 0;
171− const updatedAt =
172− typeof record.updatedAt === "number" ? record.updatedAt : createdAt;
173−
174− secretStoresById.set(storeId, {
175− id: storeId,
176− scopeId: input.scopeId,
177− name: legacySecretStoreNameForProviderId(providerId),
178− kind: providerId,
179− status: providerId === "local" || providerId === "keychain"
180− ? "connected"
181− : "error",
182− enabled: true,
183− createdAt,
184− updatedAt,
185− });
186−
187− migrated = true;
188− return {
189− ...record,
190− storeId,
191− };
192− });
193−
194− if (!Array.isArray(next.secretStores)) {
195− migrated = true;
196− }
197−
198− next.secretStores = [...secretStoresById.values()];
199− next.secretMaterials = migratedSecretMaterials;
200− }
201−
202− return { value: next, migrated };
203−};
204−
20564 const mapFileSystemError = (path: string, action: string) => (cause: unknown) =>
20665 new LocalFileSystemError({
20766 message: `Failed to ${action} ${path}: ${unknownLocalErrorDetails(cause)}`,
@@ -258,15 +117,9 @@ const readStateFromDisk = ( · 50 unmodified lines
258117 try: () => JSON.parse(content) as unknown,
259118 catch: mapFileSystemError(path, "parse executor state"),
260119 });
261− const migrated = migrateLegacyExecutorStateValue(parsed, {
262− scopeId: deriveLocalInstallation(context).scopeId,
263− });
264− const decoded = yield* decodeLocalExecutorStateSnapshot(migrated.value).pipe(
120+ const decoded = yield* decodeLocalExecutorStateSnapshot(parsed).pipe(
265121 Effect.mapError(mapFileSystemError(path, "decode executor state")),
266122 );
267− if (migrated.migrated) {
268− yield* writeStateToDisk(context, decoded);
269− }
270123 return decoded;
271124 });
272125
packages/platform/sdk-file/src/index.ts+8−5
@@ -27,11 +27,11 @@ import { · 26 unmodified lines
2727 type ExecutorRuntime,
2828 type ExecutorRuntimeOptions,
2929 type ResolveSecretMaterial,
30+ emptyExecutorPluginRegistry,
3031 } from "@executor/platform-sdk/runtime";
3132 import * as Effect from "effect/Effect";
3233 import {
3334 type LoadedLocalExecutorConfig,
34− migrateLegacyLocalExecutorConfigs,
3535 type ResolvedLocalWorkspaceContext,
3636 loadLocalExecutorConfig,
3737 resolveConfigRelativePath,
@@ -238,10 +238,6 @@ export const createLocalExecutorRepositoriesEffect = ( · 200 unmodified lines
238238 homeStateDirectory: options.homeStateDirectory,
239239 }),
240240 ).pipe(Effect.mapError(toError));
241− yield* bindFileSystem(
242− fileSystem,
243− migrateLegacyLocalExecutorConfigs(workspaceContext),
244− ).pipe(Effect.mapError(toError));
245241
246242 const executorStateStorage = createLocalExecutorStatePersistence(
247243 workspaceContext,
@@ -252,14 +248,17 @@ export const createLocalExecutorRepositoriesEffect = ( · 4 unmodified lines
252248 fileSystem,
253249 );
254250 const loadedConfig = yield* workspaceConfigStore.load();
251+ const pluginRegistry = runtimeOptions.pluginRegistry ?? emptyExecutorPluginRegistry();
255252 yield* provisionBuiltinSecretStores({
256253 executorState: executorStateStorage.executorState,
254+ pluginRegistry,
257255 scopeId: deriveLocalInstallation(workspaceContext).scopeId,
258256 });
259257 const resolveSecretMaterial: ResolveSecretMaterial =
260258 runtimeOptions.resolveSecretMaterial
261259 ?? createDefaultSecretMaterialResolver({
262260 executorState: executorStateStorage.executorState,
261+ pluginRegistry,
263262 });
264263
265264 return {
@@ -288,14 +287,17 @@ export const createLocalExecutorRepositoriesEffect = ( · 22 unmodified lines
288287 resolve: resolveSecretMaterial,
289288 store: createDefaultSecretMaterialStorer({
290289 executorState: executorStateStorage.executorState,
290+ pluginRegistry,
291291 resolveSecretMaterial,
292292 }),
293293 delete: createDefaultSecretMaterialDeleter({
294294 executorState: executorStateStorage.executorState,
295+ pluginRegistry,
295296 resolveSecretMaterial,
296297 }),
297298 update: createDefaultSecretMaterialUpdater({
298299 executorState: executorStateStorage.executorState,
300+ pluginRegistry,
299301 resolveSecretMaterial,
300302 }),
301303 },
@@ -308,6 +310,7 @@ export const createLocalExecutorRepositoriesEffect = ( · 6 unmodified lines
308310 instanceConfig: {
309311 resolve: createLocalInstanceConfigResolver({
310312 executorState: executorStateStorage.executorState,
313+ pluginRegistry,
311314 }),
312315 },
313316 close: executorStateStorage.close,
packages/platform/sdk-file/src/secret-material-providers.ts+53−21
@@ -4,6 +4,9 @@ import type { · 3 unmodified lines
44 InstanceConfig,
55 SecretProvider,
66 } from "@executor/platform-sdk/contracts";
7+import type {
8+ ExecutorSdkPluginRegistry,
9+} from "@executor/platform-sdk/plugins";
710 import type {
811 SecretMaterial,
912 SecretMaterialPurpose,
@@ -43,8 +46,10 @@ const trimOrNull = (value: string | null | undefined): string | null => { · 33 unmodified lines
4346 return trimmed.length > 0 ? trimmed : null;
4447 };
4548
46−const builtinSecretStoreContributions = () =>
47− registeredSecretStoreContributions()
49+const builtinSecretStoreContributions = (
50+ pluginRegistry: ExecutorSdkPluginRegistry,
51+) =>
52+ registeredSecretStoreContributions(pluginRegistry)
4853 .filter((entry) => entry.builtin !== undefined)
4954 .filter((entry) => entry.builtin?.enabled?.() ?? true)
5055 .map((entry) => ({
@@ -52,11 +57,17 @@ const builtinSecretStoreContributions = () => · 1 unmodified line
5257 builtin: entry.builtin!,
5358 }));
5459
55−const resolveStoreContribution = (store: SecretStore) =>
56− getSecretStoreContribution(store.kind);
57−
58−const loadStoreCapabilities = (store: SecretStore) =>
59− resolveStoreContribution(store).getCapabilities({
60+const resolveStoreContribution = (
61+ pluginRegistry: ExecutorSdkPluginRegistry,
62+ store: SecretStore,
63+) =>
64+ getSecretStoreContribution(pluginRegistry, store.kind);
65+
66+const loadStoreCapabilities = (
67+ pluginRegistry: ExecutorSdkPluginRegistry,
68+ store: SecretStore,
69+) =>
70+ resolveStoreContribution(pluginRegistry, store).getCapabilities({
6071 store,
6172 }) as Effect.Effect<{
6273 canCreateSecrets: boolean;
@@ -72,6 +83,7 @@ const parseDefaultStoreKind = (value: string | undefined): string | null => { · 9 unmodified lines
7283 };
7384
7485 const resolveDefaultStoreId = (
86+ pluginRegistry: ExecutorSdkPluginRegistry,
7587 stores: ReadonlyArray<{
7688 id: string;
7789 kind: string;
@@ -85,7 +97,7 @@ const resolveDefaultStoreId = ( · 7 unmodified lines
8597 }
8698 }
8799
88− const prioritizedBuiltins = builtinSecretStoreContributions()
100+ const prioritizedBuiltins = builtinSecretStoreContributions(pluginRegistry)
89101 .sort((left, right) =>
90102 (right.builtin.defaultPriority ?? 0) - (left.builtin.defaultPriority ?? 0)
91103 );
@@ -102,12 +114,13 @@ const resolveDefaultStoreId = ( · 10 unmodified lines
102114
103115 export const provisionBuiltinSecretStores = (input: {
104116 executorState: ExecutorStateStoreShape;
117+ pluginRegistry: ExecutorSdkPluginRegistry;
105118 scopeId: string;
106119 }) =>
107120 Effect.gen(function* () {
108121 const now = Date.now();
109122
110− for (const entry of builtinSecretStoreContributions()) {
123+ for (const entry of builtinSecretStoreContributions(input.pluginRegistry)) {
111124 const existing = yield* input.executorState.secretStores.getById(
112125 entry.builtin.storeId as SecretStore["id"],
113126 );
@@ -169,6 +182,7 @@ const provideSecretResolver = <A, E>( · 55 unmodified lines
169182
170183 export const createDefaultSecretMaterialResolver = (input: {
171184 executorState: ExecutorStateStoreShape;
185+ pluginRegistry: ExecutorSdkPluginRegistry;
172186 keychainServiceName?: string;
173187 }): ResolveSecretMaterial => {
174188 let resolveSecretMaterial!: ResolveSecretMaterial;
@@ -182,7 +196,7 @@ export const createDefaultSecretMaterialResolver = (input: { · 7 unmodified lines
182196 executorState: input.executorState,
183197 storeId: material.storeId,
184198 });
185− const contribution = resolveStoreContribution(store);
199+ const contribution = resolveStoreContribution(input.pluginRegistry, store);
186200 return yield* provideSecretResolver(
187201 contribution.resolveSecret({
188202 secret: material,
@@ -198,13 +212,14 @@ export const createDefaultSecretMaterialResolver = (input: { · 9 unmodified lines
198212
199213 export const createDefaultSecretMaterialStorer = (input: {
200214 executorState: ExecutorStateStoreShape;
215+ pluginRegistry: ExecutorSdkPluginRegistry;
201216 resolveSecretMaterial: ResolveSecretMaterial;
202217 keychainServiceName?: string;
203218 }): StoreSecretMaterial => {
204219 return ({ purpose, value, name, storeId }) =>
205220 Effect.gen(function* () {
206221 const stores = yield* input.executorState.secretStores.listAll();
207− const resolvedStoreId = storeId ?? resolveDefaultStoreId(stores);
222+ const resolvedStoreId = storeId ?? resolveDefaultStoreId(input.pluginRegistry, stores);
208223 if (resolvedStoreId === null) {
209224 return yield* runtimeEffectError(
210225 "local/secret-material-providers",
@@ -216,9 +231,9 @@ export const createDefaultSecretMaterialStorer = (input: { · 5 unmodified lines
216231 executorState: input.executorState,
217232 storeId: resolvedStoreId as SecretStore["id"],
218233 });
219− const contribution = resolveStoreContribution(store);
234+ const contribution = resolveStoreContribution(input.pluginRegistry, store);
220235
221− const capabilities = yield* loadStoreCapabilities(store);
236+ const capabilities = yield* loadStoreCapabilities(input.pluginRegistry, store);
222237 if (!capabilities.canCreateSecrets) {
223238 return yield* runtimeEffectError(
224239 "local/secret-material-providers",
@@ -258,6 +273,7 @@ export const createDefaultSecretMaterialStorer = (input: { · 33 unmodified lines
258273
259274 export const createDefaultSecretMaterialUpdater = (input: {
260275 executorState: ExecutorStateStoreShape;
276+ pluginRegistry: ExecutorSdkPluginRegistry;
261277 resolveSecretMaterial: ResolveSecretMaterial;
262278 keychainServiceName?: string;
263279 }): UpdateSecretMaterial => {
@@ -271,9 +287,9 @@ export const createDefaultSecretMaterialUpdater = (input: { · 7 unmodified lines
271287 executorState: input.executorState,
272288 storeId: material.storeId,
273289 });
274− const contribution = resolveStoreContribution(store);
290+ const contribution = resolveStoreContribution(input.pluginRegistry, store);
275291
276− const capabilities = yield* loadStoreCapabilities(store);
292+ const capabilities = yield* loadStoreCapabilities(input.pluginRegistry, store);
277293 if (!capabilities.canUpdateSecrets) {
278294 return yield* runtimeEffectError(
279295 "local/secret-material-providers",
@@ -313,6 +329,7 @@ export const createDefaultSecretMaterialUpdater = (input: { · 33 unmodified lines
313329
314330 export const createDefaultSecretMaterialDeleter = (input: {
315331 executorState: ExecutorStateStoreShape;
332+ pluginRegistry: ExecutorSdkPluginRegistry;
316333 resolveSecretMaterial: ResolveSecretMaterial;
317334 keychainServiceName?: string;
318335 }): DeleteSecretMaterial => {
@@ -326,8 +343,8 @@ export const createDefaultSecretMaterialDeleter = (input: { · 7 unmodified lines
326343 executorState: input.executorState,
327344 storeId: material.storeId,
328345 });
329− const contribution = resolveStoreContribution(store);
330− const capabilities = yield* loadStoreCapabilities(store);
346+ const contribution = resolveStoreContribution(input.pluginRegistry, store);
347+ const capabilities = yield* loadStoreCapabilities(input.pluginRegistry, store);
331348 const deleted = capabilities.canDeleteSecrets
332349 ? yield* provideSecretResolver(
333350 contribution.deleteSecret({
@@ -346,8 +363,10 @@ export const createDefaultSecretMaterialDeleter = (input: { · 12 unmodified lines
346363 });
347364 };
348365
349−const listAvailableSecretStorePlugins = (): SecretProvider[] => {
350− return registeredSecretStoreContributions().map((entry) => ({
366+const listAvailableSecretStorePlugins = (
367+ pluginRegistry: ExecutorSdkPluginRegistry,
368+): SecretProvider[] => {
369+ return registeredSecretStoreContributions(pluginRegistry).map((entry) => ({
351370 kind: entry.kind,
352371 displayName: entry.displayName,
353372 canCreate: entry.canCreate,
@@ -356,18 +375,20 @@ const listAvailableSecretStorePlugins = (): SecretProvider[] => { · 2 unmodified lines
356375
357376 export const createLocalInstanceConfigResolver = (input: {
358377 executorState: ExecutorStateStoreShape;
378+ pluginRegistry: ExecutorSdkPluginRegistry;
359379 }): ResolveInstanceConfig => () =>
360380 Effect.gen(function* () {
361381 const stores = yield* input.executorState.secretStores.listAll();
362382 return {
363383 platform: process.platform,
364− secretStorePlugins: listAvailableSecretStorePlugins(),
365− defaultSecretStoreId: resolveDefaultStoreId(stores),
384+ secretStorePlugins: listAvailableSecretStorePlugins(input.pluginRegistry),
385+ defaultSecretStoreId: resolveDefaultStoreId(input.pluginRegistry, stores),
366386 } satisfies InstanceConfig;
367387 });
368388
369389 export const SecretMaterialResolverLive = (input: {
370390 executorState: ExecutorStateStoreShape;
391+ pluginRegistry: ExecutorSdkPluginRegistry;
371392 resolveSecretMaterial?: ResolveSecretMaterial;
372393 keychainServiceName?: string;
373394 }) =>
@@ -380,6 +401,7 @@ export const SecretMaterialResolverLive = (input: { · 6 unmodified lines
380401
381402 export const SecretMaterialStorerLive = (input: {
382403 executorState: ExecutorStateStoreShape;
404+ pluginRegistry: ExecutorSdkPluginRegistry;
383405 resolveSecretMaterial: ResolveSecretMaterial;
384406 keychainServiceName?: string;
385407 }) =>
@@ -390,6 +412,7 @@ export const SecretMaterialStorerLive = (input: { · 4 unmodified lines
390412
391413 export const SecretMaterialDeleterLive = (input: {
392414 executorState: ExecutorStateStoreShape;
415+ pluginRegistry: ExecutorSdkPluginRegistry;
393416 resolveSecretMaterial: ResolveSecretMaterial;
394417 keychainServiceName?: string;
395418 }) =>
@@ -400,6 +423,7 @@ export const SecretMaterialDeleterLive = (input: { · 4 unmodified lines
400423
401424 export const SecretMaterialUpdaterLive = (input: {
402425 executorState: ExecutorStateStoreShape;
426+ pluginRegistry: ExecutorSdkPluginRegistry;
403427 resolveSecretMaterial: ResolveSecretMaterial;
404428 keychainServiceName?: string;
405429 }) =>
@@ -410,6 +434,7 @@ export const SecretMaterialUpdaterLive = (input: { · 4 unmodified lines
410434
411435 export const SecretMaterialLive = (input: {
412436 executorState: ExecutorStateStoreShape;
437+ pluginRegistry: ExecutorSdkPluginRegistry;
413438 resolveSecretMaterial?: ResolveSecretMaterial;
414439 keychainServiceName?: string;
415440 }) =>
@@ -421,8 +446,10 @@ export const SecretMaterialLive = (input: { · 5 unmodified lines
421446 input.resolveSecretMaterial
422447 ?? createDefaultSecretMaterialResolver({
423448 executorState: input.executorState,
449+ pluginRegistry: input.pluginRegistry,
424450 keychainServiceName: input.keychainServiceName,
425451 }),
452+ pluginRegistry: input.pluginRegistry,
426453 keychainServiceName: input.keychainServiceName,
427454 }),
428455 SecretMaterialDeleterLive({
@@ -431,8 +458,10 @@ export const SecretMaterialLive = (input: { · 2 unmodified lines
431458 input.resolveSecretMaterial
432459 ?? createDefaultSecretMaterialResolver({
433460 executorState: input.executorState,
461+ pluginRegistry: input.pluginRegistry,
434462 keychainServiceName: input.keychainServiceName,
435463 }),
464+ pluginRegistry: input.pluginRegistry,
436465 keychainServiceName: input.keychainServiceName,
437466 }),
438467 SecretMaterialUpdaterLive({
@@ -441,14 +470,17 @@ export const SecretMaterialLive = (input: { · 2 unmodified lines
441470 input.resolveSecretMaterial
442471 ?? createDefaultSecretMaterialResolver({
443472 executorState: input.executorState,
473+ pluginRegistry: input.pluginRegistry,
444474 keychainServiceName: input.keychainServiceName,
445475 }),
476+ pluginRegistry: input.pluginRegistry,
446477 keychainServiceName: input.keychainServiceName,
447478 }),
448479 );
449480
450481 export const LocalInstanceConfigLive = (input: {
451482 executorState: ExecutorStateStoreShape;
483+ pluginRegistry: ExecutorSdkPluginRegistry;
452484 }) =>
453485 Layer.succeed(
454486 LocalInstanceConfigService,
packages/platform/sdk/src/local/secret-stores.ts+17−13
@@ -18,6 +18,7 @@ import { · 17 unmodified lines
1818 ControlPlaneStorageError,
1919 } from "../errors";
2020 import {
21+ ExecutorPluginRegistryService,
2122 createManagedSecretStoreRecord,
2223 getManagedSecretStore,
2324 getSecretStoreContribution,
@@ -75,13 +76,15 @@ const asRecord = (value: unknown): Record<string, unknown> | null => · 51 unmodified lines
7576 ? value as Record<string, unknown>
7677 : null;
7778
78−const getSecretStoreContributionOption = (kind: string) => {
79− try {
80− return Option.some(getSecretStoreContribution(kind));
81− } catch {
82− return Option.none<typeof getSecretStoreContribution extends (kind: string) => infer T ? T : never>();
83− }
84−};
79+const getSecretStoreContributionOption = (kind: string) =>
80+ Effect.gen(function* () {
81+ const pluginRegistry = yield* ExecutorPluginRegistryService;
82+ try {
83+ return Option.some(getSecretStoreContribution(pluginRegistry, kind));
84+ } catch {
85+ return Option.none<typeof getSecretStoreContribution extends (registry: any, kind: string) => infer T ? T : never>();
86+ }
87+ });
8588
8689 const defaultCapabilities: SecretStoreCapabilities = {
8790 canCreateSecrets: false,
@@ -95,7 +98,7 @@ const loadStoreCapabilities = ( · 7 unmodified lines
9598 store: SecretStore,
9699 )=>
97100 Effect.gen(function* () {
98− const contribution = getSecretStoreContributionOption(store.kind);
101+ const contribution = yield* getSecretStoreContributionOption(store.kind);
99102 if (Option.isNone(contribution)) {
100103 return defaultCapabilities;
101104 }
@@ -183,8 +186,9 @@ export const createLocalSecretStore = (payload: CreateSecretStorePayload) => · 81 unmodified lines
183186 ),
184187 ),
185188 );
189+ const pluginRegistry = yield* ExecutorPluginRegistryService;
186190 const contribution = yield* Effect.try({
187− try: () => getSecretStoreContribution(payload.kind),
191+ try: () => getSecretStoreContribution(pluginRegistry, payload.kind),
188192 catch: (cause) =>
189193 cause instanceof Error ? cause : new Error(String(cause)),
190194 }).pipe(
@@ -254,7 +258,7 @@ export const updateLocalSecretStore = (input: { · 63 unmodified lines
254258 ),
255259 );
256260
257− const contribution = getSecretStoreContributionOption(store.kind);
261+ const contribution = yield* getSecretStoreContributionOption(store.kind);
258262 const configRecord = input.payload.config === undefined
259263 ? null
260264 : asRecord(input.payload.config);
@@ -318,7 +322,7 @@ export const deleteLocalSecretStore = (storeId: string) => · 57 unmodified lines
318322 });
319323 }
320324
321− const contribution = getSecretStoreContributionOption(store.value.kind);
325+ const contribution = yield* getSecretStoreContributionOption(store.value.kind);
322326 if (Option.isNone(contribution)) {
323327 return yield* new ControlPlaneBadRequestError({
324328 operation: "secretStores.delete",
@@ -359,7 +363,7 @@ export const browseLocalSecretStore = (input: { · 34 unmodified lines
359363 ),
360364 );
361365
362− const contribution = getSecretStoreContributionOption(store.kind);
366+ const contribution = yield* getSecretStoreContributionOption(store.kind);
363367 const capabilities = yield* loadStoreCapabilities(store);
364368 if (Option.isNone(contribution) || !capabilities.canBrowseSecrets) {
365369 return yield* new ControlPlaneBadRequestError({
@@ -399,7 +403,7 @@ export const importLocalSecretFromStore = (input: { · 33 unmodified lines
399403 ),
400404 );
401405
402− const contribution = getSecretStoreContributionOption(store.kind);
406+ const contribution = yield* getSecretStoreContributionOption(store.kind);
403407 if (Option.isNone(contribution)) {
404408 return yield* new ControlPlaneBadRequestError({
405409 operation: "secretStores.import",
packages/platform/sdk/src/plugins.ts+2−2
@@ -1402,7 +1402,7 @@ export const defineExecutorSecretStorePlugin = < · 1401 unmodified lines
14021402 ...pluginInput,
14031403 secretStore: createExecutorSecretStorePluginApi(
14041404 input.secretStore,
1405− pluginInput.host as ExecutorSecretStorePluginInternalHost,
1405+ pluginInput.host as unknown as ExecutorSecretStorePluginInternalHost,
14061406 ),
14071407 })
14081408 : undefined,
@@ -1412,7 +1412,7 @@ export const defineExecutorSecretStorePlugin = < · 3 unmodified lines
14121412 ...pluginInput,
14131413 secretStore: createExecutorSecretStorePluginApi(
14141414 input.secretStore,
1415− pluginInput.host as ExecutorSecretStorePluginInternalHost,
1415+ pluginInput.host as unknown as ExecutorSecretStorePluginInternalHost,
14161416 ),
14171417 })
14181418 : undefined,
packages/platform/sdk/src/runtime/execution/scope/tool-invoker.ts+1−1
@@ -156,7 +156,7 @@ export const createScopeToolInvoker = (input: { · 155 unmodified lines
156156 return catalog;
157157 },
158158 });
159− const hasLocalToolsSourceContribution = registeredSourceContributions()
159+ const hasLocalToolsSourceContribution = registeredSourceContributions(input.pluginRegistry)
160160 .some((source) => source.kind === "local-tools");
161161 const authoredTools = mergeToolMaps([
162162 systemTools,
packages/platform/sdk/src/runtime/index.ts+2−0
@@ -146,6 +146,8 @@ export type { · 145 unmodified lines
146146 LocalToolRuntimeLoaderShape,
147147 } from "./local-tool-runtime";
148148 export {
149+ createExecutorPluginRegistry,
150+ emptyExecutorPluginRegistry,
149151 registeredSourceContributions,
150152 registeredSecretStoreContributions,
151153 registeredManagementToolContributions,
packages/platform/sdk/src/runtime/source-artifacts.ts+2−27
@@ -31,7 +31,6 @@ import type { · 30 unmodified lines
3131 ExecutorSdkPluginRegistry,
3232 } from "../plugins";
3333
34−const LEGACY_LOCAL_SOURCE_ARTIFACT_VERSION = 3 as const;
3534 const LOCAL_SOURCE_ARTIFACT_VERSION = 4 as const;
3635
3736 export const LocalSourceArtifactSchema = Schema.Struct({
@@ -45,15 +44,6 @@ export const LocalSourceArtifactSchema = Schema.Struct({ · 7 unmodified lines
4544
4645 export type LocalSourceArtifact = typeof LocalSourceArtifactSchema.Type;
4746
48−const ReadableLegacyLocalSourceArtifactSchema = Schema.Struct({
49− version: Schema.Literal(LEGACY_LOCAL_SOURCE_ARTIFACT_VERSION),
50− sourceId: SourceIdSchema,
51− catalogId: SourceCatalogIdSchema,
52− generatedAt: TimestampMsSchema,
53− revision: StoredSourceCatalogRevisionRecordSchema,
54− snapshot: Schema.Unknown,
55−});
56−
5747 const ReadableLocalSourceArtifactSchema = Schema.Struct({
5848 version: Schema.Literal(LOCAL_SOURCE_ARTIFACT_VERSION),
5949 sourceId: SourceIdSchema,
@@ -63,30 +53,15 @@ const ReadableLocalSourceArtifactSchema = Schema.Struct({ · 3 unmodified lines
6353 snapshot: Schema.Unknown,
6454 });
6555
66−type ReadableLegacyLocalSourceArtifact =
67− typeof ReadableLegacyLocalSourceArtifactSchema.Type;
6856 type ReadableLocalSourceArtifact =
6957 typeof ReadableLocalSourceArtifactSchema.Type;
7058
7159 const decodeReadableLocalSourceArtifactOption = Schema.decodeUnknownOption(
7260 Schema.parseJson(
73− Schema.Union(
74− ReadableLocalSourceArtifactSchema,
75− ReadableLegacyLocalSourceArtifactSchema,
76− ),
61+ ReadableLocalSourceArtifactSchema,
7762 ),
7863 );
7964
80−const normalizeLocalSourceArtifact = (
81− artifact: ReadableLocalSourceArtifact | ReadableLegacyLocalSourceArtifact,
82−): Omit<LocalSourceArtifact, "snapshot"> & { snapshot: unknown } =>
83− artifact.version === LOCAL_SOURCE_ARTIFACT_VERSION
84− ? artifact
85− : {
86− ...artifact,
87− version: LOCAL_SOURCE_ARTIFACT_VERSION,
88− };
89−
9065 const mutableRecord = <K extends string, V>(
9166 value: Readonly<Record<K, V>>,
9267 ): Record<K, V> => value as Record<K, V>;
@@ -188,7 +163,7 @@ export const decodeStoredLocalSourceArtifact = ( · 95 unmodified lines
188163 return null;
189164 }
190165
191− const artifact = normalizeLocalSourceArtifact(decodedArtifact.value);
166+ const artifact = decodedArtifact.value;
192167 const snapshot = decodeCatalogSnapshotV1Option(artifact.snapshot);
193168 if (snapshot === null) {
194169 return null;
packages/platform/sdk/src/runtime/sources/executor-tools.test.ts+0−68
@@ -219,72 +219,4 @@ describe("executor internal tools", () => { · 218 unmodified lines
219219 expect(stored.has((created as { id: string }).id)).toBe(false);
220220 }).pipe(Effect.provide(NodeFileSystem.layer)),
221221 );
222−
223− it.scoped("keeps executor.sources.add as a compatibility alias", () =>
224− Effect.gen(function* () {
225− const fs = yield* FileSystem.FileSystem;
226− const workspaceRoot = yield* fs.makeTempDirectory({
227− prefix: "executor-add-alias-",
228− });
229− const specServer = yield* Effect.acquireRelease(
230− Effect.tryPromise({
231− try: () => startStaticSpecServer(),
232− catch: (cause) =>
233− cause instanceof Error ? cause : new Error(String(cause)),
234− }),
235− (server) =>
236− Effect.promise(() => server.close()).pipe(Effect.orDie),
237− );
238− const executor = yield* Effect.acquireRelease(
239− createLocalExecutorEffect({
240− localDataDir: ":memory:",
241− workspaceRoot,
242− plugins: [
243− openApiSdkPlugin({
244− storage: {
245− get: () => Effect.succeed(null),
246− put: () => Effect.void,
247− remove: () => Effect.void,
248− },
249− }),
250− ] as const,
251− }),
252− (openedExecutor) =>
253− Effect.promise(() => openedExecutor.close()).pipe(
254− Effect.orDie,
255− Effect.zipRight(
256− fs.remove(workspaceRoot, {
257− recursive: true,
258− force: true,
259− }),
260− ),
261− ),
262− );
263−
264− const environment = yield* resolveExecutionEnvironment(executor);
265− const aliasTool = yield* environment.catalog!.getToolByPath({
266− path: "executor.sources.add",
267− includeSchemas: false,
268− });
269− expect(aliasTool?.path).toBe("executor.sources.add");
270−
271− const created = yield* environment.toolInvoker.invoke({
272− path: "executor.sources.add",
273− args: {
274− kind: "openapi",
275− name: "Alias API",
276− specUrl: specServer.specUrl,
277− baseUrl: null,
278− auth: {
279− kind: "none",
280− },
281− },
282− });
283−
284− expect(created).toMatchObject({
285− kind: "openapi",
286− name: "Alias API",
287− });
288− }).pipe(Effect.provide(NodeFileSystem.layer)),
289− );
290222 });
packages/platform/sdk/src/runtime/sources/executor-tools.ts+0−146
@@ -7,7 +7,6 @@ import { · 6 unmodified lines
77 } from "#schema";
88 import * as Effect from "effect/Effect";
99 import * as Layer from "effect/Layer";
10−import * as Option from "effect/Option";
1110 import * as Schema from "effect/Schema";
1211
1312 import type {
@@ -22,7 +21,6 @@ import { · 8 unmodified lines
2221 createManagedSourceRecord,
2322 } from "../../sources/operations";
2423 import {
25− deriveSchemaJson,
2624 deriveSchemaTypeSignature,
2725 } from "../catalog/schema-type-signature";
2826 import {
@@ -75,54 +73,6 @@ type RegisteredSourceContribution = · 46 unmodified lines
7573 type RegisteredManagementToolContribution =
7674 ExecutorSdkPluginRegistry["managementTools"][number];
7775
78−const createExecutorSourcesAddSchema = (
79− sources: ReadonlyArray<RegisteredSourceContribution>,
80−): Schema.Schema<any, any, never> => {
81− if (sources.length === 0) {
82− return Schema.Unknown;
83− }
84−
85− if (sources.length === 1) {
86− return sources[0]!.inputSchema;
87− }
88−
89− return Schema.Union(
90− ...(sources.map((source) => source.inputSchema) as [
91− Schema.Schema<any, any, never>,
92− Schema.Schema<any, any, never>,
93− ...Array<Schema.Schema<any, any, never>>,
94− ]),
95− );
96−};
97−
98−export const getExecutorSourcesAddInputHint = (
99− pluginRegistry: ExecutorSdkPluginRegistry,
100−): string =>
101− deriveSchemaTypeSignature(
102− createExecutorSourcesAddSchema(
103− registeredSourceContributions(pluginRegistry),
104− ),
105− 340,
106− );
107−
108−export const EXECUTOR_SOURCES_ADD_OUTPUT_SIGNATURE = deriveSchemaTypeSignature(
109− SourceSchema,
110− 260,
111−);
112−
113−export const getExecutorSourcesAddInputSchemaJson = (
114− pluginRegistry: ExecutorSdkPluginRegistry,
115−): Record<string, unknown> =>
116− deriveSchemaJson(
117− createExecutorSourcesAddSchema(
118− registeredSourceContributions(pluginRegistry),
119− ),
120− ) ?? {};
121−
122−export const EXECUTOR_SOURCES_ADD_OUTPUT_SCHEMA = deriveSchemaJson(
123− SourceSchema,
124−) ?? {};
125−
12676 const coreSourceManagementHelpLines = (): readonly string[] => [
12777 "- executor.sources.list",
12878 `- executor.sources.get: ${deriveSchemaTypeSignature(SourceIdInputSchema, 180)}`,
@@ -147,53 +97,9 @@ export const getExecutorInternalToolHelpLines = ( · 18 unmodified lines
14797 `- ${tool.path}: ${deriveSchemaTypeSignature(tool.inputSchema, 260)}`
14898 ),
14999 ]),
150− ...(sources.length === 0
151− ? []
152− : [
153− "Legacy compatibility tool:",
154− `- executor.sources.add: ${deriveSchemaTypeSignature(
155− createExecutorSourcesAddSchema(sources),
156− 340,
157− )}`,
158− ]),
159− ];
160−};
161−
162−export const getExecutorSourcesAddHelpLines = (
163− pluginRegistry: ExecutorSdkPluginRegistry,
164−): readonly string[] => {
165− const sources = registeredSourceContributions(pluginRegistry);
166− if (sources.length === 0) {
167− return ["No source plugins are registered in this build."] as const;
168− }
169−
170− return [
171− "Source add input shapes:",
172− ...sources.flatMap((source) => [
173− `- ${source.displayName}: ${deriveSchemaTypeSignature(
174− source.inputSchema,
175− source.inputSignatureWidth ?? 260,
176− )}`,
177− ...(source.helpText ?? []).map((line) => ` ${line}`),
178− ]),
179100 ];
180101 };
181102
182−export const buildExecutorSourcesAddDescription = (
183− pluginRegistry: ExecutorSdkPluginRegistry,
184−): string => {
185− const sources = registeredSourceContributions(pluginRegistry);
186− if (sources.length === 0) {
187− return "No source plugins are registered in this build.";
188− }
189−
190− return [
191− "Legacy compatibility alias for creating a source.",
192− "Prefer plugin-specific tools such as executor.openapi.createSource or executor.mcp.createSource.",
193− ...getExecutorSourcesAddHelpLines(pluginRegistry),
194− ].join("\n");
195−};
196−
197103 const createSourceConnectorHost = (input: {
198104 scopeId: ScopeId;
199105 actorScopeId: ScopeId;
@@ -297,28 +203,6 @@ const runExecutorToolEffect = async <A>( · 97 unmodified lines
297203 );
298204 };
299205
300−const resolveSourceContribution = (
301− sources: ReadonlyArray<RegisteredSourceContribution>,
302− args: unknown,
303−):
304− | {
305− source: RegisteredSourceContribution;
306− parsedArgs: unknown;
307− }
308− | null => {
309− for (const source of sources) {
310− const parsed = Schema.decodeUnknownOption(source.inputSchema)(args);
311− if (Option.isSome(parsed)) {
312− return {
313− source,
314− parsedArgs: parsed.value,
315− };
316− }
317− }
318−
319− return null;
320−};
321−
322206 const toSerializableValue = <A>(value: A): A =>
323207 JSON.parse(JSON.stringify(value)) as A;
324208
@@ -549,36 +433,6 @@ export const createExecutorToolMap = (input: { · 224 unmodified lines
549433 }),
550434 };
551435
552− if (sources.length > 0) {
553− coreTools["executor.sources.add"] = toTool({
554− tool: {
555− description: buildExecutorSourcesAddDescription(input.pluginRegistry),
556− inputSchema: Schema.standardSchemaV1(
557− createExecutorSourcesAddSchema(sources),
558− ),
559− outputSchema: Schema.standardSchemaV1(SourceSchema),
560− execute: async (args: unknown): Promise<Source> => {
561− const matched = resolveSourceContribution(sources, args);
562− if (matched === null) {
563− throw new Error(
564− "executor.sources.add input did not match a registered source plugin.",
565− );
566− }
567−
568− const createdSource = await runExecutorToolEffect(
569− matched.source.createSource({
570− args: matched.parsedArgs,
571− host,
572− }),
573− runtime,
574− );
575−
576− return toSerializableValue(createdSource);
577− },
578− },
579− });
580− }
581−
582436 return {
583437 ...coreTools,
584438 ...pluginToolMap,
packages/platform/sdk/src/runtime/sources/source-store/plugin-local-config.ts+0−83
@@ -1,23 +1,12 @@
11 import type {
2− LocalConfigSecretInput,
32 LocalConfigSource,
4− LocalExecutorConfig,
5− SecretRef,
63 Source,
74 } from "#schema";
8−import {
9− LocalConfigSecretInputSchema,
10−} from "#schema";
11−import * as Option from "effect/Option";
125 import * as Schema from "effect/Schema";
136
14−import {
15− toConfigSecretProviderId,
16−} from "../../scope/config-secrets";
177 import {
188 cloneJson,
199 configSourceBaseFromLocalSource,
20− trimOrNull,
2110 } from "./config";
2211
2312 export const createPluginLocalConfigEntrySchema = <
@@ -49,75 +38,3 @@ export const pluginLocalConfigSourceFromConfig = <TConfig>(input: { · 25 unmodified lines
4938 kind: input.source.kind as LocalConfigSource["kind"],
5039 config: cloneJson(input.config),
5140 });
52−
53−const decodeLocalConfigSecretInputOption = Schema.decodeUnknownOption(
54− LocalConfigSecretInputSchema,
55−);
56−
57−const resolveDefaultConfigSecretProviderAlias = (
58− config: LocalExecutorConfig | null | undefined,
59−): string | null => {
60− const defaultAlias = trimOrNull(config?.secrets?.defaults?.env);
61− if (defaultAlias !== null && config?.secrets?.providers?.[defaultAlias]) {
62− return defaultAlias;
63− }
64−
65− return config?.secrets?.providers?.default ? "default" : null;
66−};
67−
68−export const secretRefFromLocalConfigSecretInput = (input: {
69− auth: LocalConfigSecretInput;
70− loadedConfig: LocalExecutorConfig | null;
71−}): SecretRef => {
72− if (typeof input.auth === "string") {
73− const providerAlias = resolveDefaultConfigSecretProviderAlias(
74− input.loadedConfig,
75− );
76−
77− return {
78− providerId: providerAlias ? toConfigSecretProviderId(providerAlias) : "env",
79− handle: input.auth,
80− };
81− }
82−
83− return {
84− providerId:
85− input.auth.provider === "params"
86− ? "params"
87− : input.auth.provider
88− ? toConfigSecretProviderId(input.auth.provider)
89− : input.auth.source === "params"
90− ? "params"
91− : "env",
92− handle: input.auth.id,
93− };
94−};
95−
96−export const decodeCurrentOrLegacyLocalConfigAuth = <TAuth>(input: {
97− auth: unknown;
98− authSchema: Schema.Schema<TAuth, any, never>;
99− loadedConfig: LocalExecutorConfig | null;
100− onLegacySecretRef: (ref: SecretRef) => TAuth;
101− fallback: TAuth;
102−}): TAuth => {
103− if (input.auth === undefined) {
104− return input.fallback;
105− }
106−
107− const current = Schema.decodeUnknownOption(input.authSchema)(input.auth);
108− if (Option.isSome(current)) {
109− return current.value;
110− }
111−
112− const legacy = decodeLocalConfigSecretInputOption(input.auth);
113− if (Option.isSome(legacy)) {
114− return input.onLegacySecretRef(
115− secretRefFromLocalConfigSecretInput({
116− auth: legacy.value,
117− loadedConfig: input.loadedConfig,
118− }),
119− );
120− }
121−
122− throw new Error("Unsupported local source auth configuration.");
123−};
packages/platform/server/src/index.test.ts+15−14
@@ -264,7 +264,7 @@ const writeConfiguredLocalMcpSource = (input: { · 263 unmodified lines
264264 });
265265 }).pipe(Effect.provide(NodeFileSystem.layer));
266266
267−const writeLegacyConfiguredWorkspaceSources = (input: {
267+const writeConfiguredWorkspaceSources = (input: {
268268 workspaceRoot: string;
269269 sources: Record<string, LocalConfigSource>;
270270 }) =>
@@ -288,8 +288,8 @@ const writeLegacyConfiguredWorkspaceSources = (input: { · 17 unmodified lines
288288 }).pipe(Effect.provide(NodeFileSystem.layer));
289289
290290 const writeMissingSourceCatalogArtifact = (input: {
291− context: Effect.Effect.Success<ReturnType<typeof writeLegacyConfiguredWorkspaceSources>>["context"];
292− installation: Effect.Effect.Success<ReturnType<typeof writeLegacyConfiguredWorkspaceSources>>["installation"];
291+ context: Effect.Effect.Success<ReturnType<typeof writeConfiguredWorkspaceSources>>["context"];
292+ installation: Effect.Effect.Success<ReturnType<typeof writeConfiguredWorkspaceSources>>["installation"];
293293 source: {
294294 id: string;
295295 name: string;
@@ -1632,7 +1632,7 @@ describe("local-executor-server", () => { · 1336 unmodified lines
16321632 15_000,
16331633 );
16341634
1635− it.scoped("adds an OpenAPI source via executor.sources.add and calls it end to end", () =>
1635+ it.scoped("adds an OpenAPI source via executor.openapi.createSource and calls it end to end", () =>
16361636 Effect.gen(function* () {
16371637 const openApiServer = yield* Effect.acquireRelease(
16381638 Effect.promise(() => startOpenApiDemoServer()),
@@ -1645,8 +1645,7 @@ describe("local-executor-server", () => { · 6 unmodified lines
16451645 workspaceId: installation.scopeId,
16461646 },
16471647 payload: {
1648− code: `return await tools.executor.sources.add({
1649− kind: "openapi",
1648+ code: `return await tools.executor.openapi.createSource({
16501649 name: "GitHub",
16511650 specUrl: ${JSON.stringify(openApiServer.specUrl)},
16521651 baseUrl: ${JSON.stringify(openApiServer.baseUrl)},
@@ -1831,16 +1830,14 @@ describe("local-executor-server", () => { · 178 unmodified lines
18311830 (server) => Effect.promise(() => server.close()).pipe(Effect.orDie),
18321831 );
18331832
1834− const workspace = yield* writeLegacyConfiguredWorkspaceSources({
1833+ const workspace = yield* writeConfiguredWorkspaceSources({
18351834 workspaceRoot,
18361835 sources: {
18371836 deepwiki: {
18381837 kind: "mcp",
18391838 name: "DeepWiki MCP",
1840− connection: {
1839+ config: {
18411840 endpoint: demoServer.endpoint,
1842− },
1843− binding: {
18441841 transport: "streamable-http",
18451842 queryParams: null,
18461843 headers: null,
@@ -1848,16 +1845,20 @@ describe("local-executor-server", () => { · 1 unmodified line
18481845 args: null,
18491846 env: null,
18501847 cwd: null,
1848+ auth: {
1849+ kind: "none",
1850+ },
18511851 },
18521852 },
18531853 vercel: {
18541854 kind: "openapi",
18551855 name: "Vercel API",
1856− connection: {
1857− endpoint: openApiServer.baseUrl,
1858− },
1859− binding: {
1856+ config: {
18601857 specUrl: openApiServer.specUrl,
1858+ baseUrl: openApiServer.baseUrl,
1859+ auth: {
1860+ kind: "none",
1861+ },
18611862 defaultHeaders: null,
18621863 },
18631864 },
plugins/google-discovery/sdk/index.ts+0−50
@@ -18,7 +18,6 @@ import { · 17 unmodified lines
1818 } from "@executor/platform-sdk/plugins";
1919 import {
2020 createPluginLocalConfigEntrySchema,
21− decodeCurrentOrLegacyLocalConfigAuth,
2221 pluginLocalConfigSourceFromConfig,
2322 SecretMaterialDeleterService,
2423 SecretMaterialResolverService,
@@ -103,29 +102,6 @@ const decodeGoogleDiscoveryCurrentLocalConfigOption = Schema.decodeUnknownOption · 78 unmodified lines
103102 config: GoogleDiscoveryStoredSourceDataSchema,
104103 }),
105104 );
106−const decodeGoogleDiscoveryLegacyLocalConfigOption = Schema.decodeUnknownOption(
107− Schema.Struct({
108− kind: Schema.Literal(GOOGLE_DISCOVERY_SOURCE_KIND),
109− name: Schema.optional(Schema.String),
110− namespace: Schema.optional(Schema.String),
111− enabled: Schema.optional(Schema.Boolean),
112− connection: Schema.Struct({
113− endpoint: Schema.optional(Schema.NullOr(Schema.String)),
114− auth: Schema.optional(Schema.Unknown),
115− }),
116− binding: Schema.Struct({
117− service: Schema.String,
118− version: Schema.String,
119− discoveryUrl: Schema.optional(Schema.NullOr(Schema.String)),
120− defaultHeaders: Schema.optional(
121− Schema.NullOr(Schema.Record({ key: Schema.String, value: Schema.String })),
122− ),
123− scopes: Schema.optional(Schema.Array(Schema.String)),
124− }),
125− config: Schema.optional(Schema.Unknown),
126− }),
127−);
128−
129105 export type GoogleDiscoverySourceStorage = {
130106 get: (input: {
131107 scopeId: string;
@@ -582,32 +558,6 @@ const googleDiscoveryStoredSourceDataFromLocalConfig = (input: { · 450 unmodified lines
582558 return current.value.config;
583559 }
584560
585− const legacy = decodeGoogleDiscoveryLegacyLocalConfigOption(input.config);
586− if (Option.isSome(legacy)) {
587− return storedSourceDataFromInput({
588− name:
589− legacy.value.name
590− ?? `${legacy.value.binding.service} ${legacy.value.binding.version}`,
591− service: legacy.value.binding.service,
592− version: legacy.value.binding.version,
593− discoveryUrl: legacy.value.binding.discoveryUrl ?? null,
594− defaultHeaders: legacy.value.binding.defaultHeaders ?? null,
595− scopes: legacy.value.binding.scopes ?? [],
596− auth: decodeCurrentOrLegacyLocalConfigAuth({
597− auth: legacy.value.connection.auth,
598− authSchema: GoogleDiscoveryConnectionAuthSchema,
599− loadedConfig: input.loadedConfig,
600− onLegacySecretRef: (tokenSecretRef) => ({
601− kind: "bearer",
602− tokenSecretRef,
603− }),
604− fallback: {
605− kind: "none",
606− },
607− }),
608− });
609− }
610−
611561 throw new Error("Unsupported Google Discovery local source config.");
612562 };
613563
plugins/graphql/sdk/index.ts+0−43
@@ -24,7 +24,6 @@ import { · 23 unmodified lines
2424 import {
2525 SecretMaterialResolverService,
2626 createPluginLocalConfigEntrySchema,
27− decodeCurrentOrLegacyLocalConfigAuth,
2827 pluginLocalConfigSourceFromConfig,
2928 provideExecutorRuntime,
3029 runtimeEffectError,
@@ -158,25 +157,6 @@ const decodeGraphqlCurrentLocalConfigOption = Schema.decodeUnknownOption( · 127 unmodified lines
158157 }),
159158 );
160159
161−const decodeGraphqlLegacyLocalConfigOption = Schema.decodeUnknownOption(
162− Schema.Struct({
163− kind: Schema.Literal("graphql"),
164− name: Schema.optional(Schema.String),
165− namespace: Schema.optional(Schema.String),
166− enabled: Schema.optional(Schema.Boolean),
167− connection: Schema.Struct({
168− endpoint: Schema.String,
169− auth: Schema.optional(Schema.Unknown),
170− }),
171− binding: Schema.Struct({
172− defaultHeaders: Schema.optional(
173− Schema.NullOr(Schema.Record({ key: Schema.String, value: Schema.String })),
174− ),
175− }),
176− config: Schema.optional(Schema.Unknown),
177− }),
178−);
179−
180160 const withoutUndefinedEntries = (
181161 record: Readonly<Record<string, unknown>>,
182162 ): Record<string, unknown> =>
@@ -363,29 +343,6 @@ const graphqlStoredSourceDataFromLocalConfig = (input: { · 180 unmodified lines
363343 return normalizeStoredSourceData(current.value.config);
364344 }
365345
366− const legacy = decodeGraphqlLegacyLocalConfigOption(input.config);
367− if (Option.isSome(legacy)) {
368− return storedSourceDataFromInput({
369− name: legacy.value.name ?? "GraphQL",
370− endpoint: legacy.value.connection.endpoint,
371− defaultHeaders: legacy.value.binding.defaultHeaders ?? null,
372− auth: decodeCurrentOrLegacyLocalConfigAuth({
373− auth: legacy.value.connection.auth,
374− authSchema: GraphqlConnectionAuthSchema,
375− loadedConfig: input.loadedConfig,
376− onLegacySecretRef: (tokenSecretRef) => ({
377− kind: "bearer",
378− tokenSecretRef,
379− headerName: null,
380− prefix: null,
381− }),
382− fallback: {
383− kind: "none",
384− },
385− }),
386− });
387− }
388−
389346 throw new Error("Unsupported GraphQL local source config.");
390347 };
391348
plugins/mcp/sdk/index.ts+0−56
@@ -249,37 +249,12 @@ const normalizeStringArray = ( · 248 unmodified lines
249249 return normalized.length > 0 ? normalized : null;
250250 };
251251
252−const decodeMcpAuthOption = Schema.decodeUnknownOption(McpConnectionAuthSchema);
253252 const decodeMcpCurrentLocalConfigOption = Schema.decodeUnknownOption(
254253 createPluginLocalConfigEntrySchema({
255254 kind: "mcp",
256255 config: McpStoredSourceDataSchema,
257256 }),
258257 );
259−const decodeMcpLegacyLocalConfigOption = Schema.decodeUnknownOption(
260− Schema.Struct({
261− kind: Schema.Literal("mcp"),
262− name: Schema.optional(Schema.String),
263− namespace: Schema.optional(Schema.String),
264− enabled: Schema.optional(Schema.Boolean),
265− connection: Schema.optional(
266− Schema.Struct({
267− endpoint: Schema.optional(Schema.NullOr(Schema.String)),
268− auth: Schema.optional(Schema.Unknown),
269− }),
270− ),
271− binding: Schema.Struct({
272− transport: Schema.optional(Schema.NullOr(SourceTransportSchema)),
273− queryParams: Schema.optional(Schema.NullOr(StringMapSchema)),
274− headers: Schema.optional(Schema.NullOr(StringMapSchema)),
275− command: Schema.optional(Schema.NullOr(Schema.String)),
276− args: Schema.optional(Schema.NullOr(StringArraySchema)),
277− env: Schema.optional(Schema.NullOr(StringMapSchema)),
278− cwd: Schema.optional(Schema.NullOr(Schema.String)),
279− }),
280− config: Schema.optional(Schema.Unknown),
281− }),
282−);
283258
284259 const normalizeStoredSourceData = (
285260 input: McpConnectInput | McpSourceConfigPayload,
@@ -399,37 +374,6 @@ const mcpStoredSourceDataFromLocalConfig = ( · 113 unmodified lines
399374 return Effect.succeed(current.value.config);
400375 }
401376
402− const legacy = decodeMcpLegacyLocalConfigOption(config);
403− if (Option.isSome(legacy)) {
404− const auth = decodeMcpAuthOption(legacy.value.connection?.auth);
405− if (
406− legacy.value.connection?.auth !== undefined &&
407− Option.isNone(auth)
408− ) {
409− return runtimeEffectError(
410− "plugins/mcp/sdk",
411− "Unsupported MCP auth configuration in local source config.",
412− );
413− }
414−
415− return normalizeStoredSourceData({
416− name: legacy.value.name ?? "MCP",
417− endpoint: legacy.value.connection?.endpoint ?? null,
418− transport: legacy.value.binding.transport ?? null,
419− queryParams: legacy.value.binding.queryParams ?? null,
420− headers: legacy.value.binding.headers ?? null,
421− command: legacy.value.binding.command ?? null,
422− args: legacy.value.binding.args ?? null,
423− env: legacy.value.binding.env ?? null,
424− cwd: legacy.value.binding.cwd ?? null,
425− auth: Option.isSome(auth)
426− ? auth.value
427− : {
428− kind: "none",
429− },
430− });
431− }
432−
433377 return runtimeEffectError(
434378 "plugins/mcp/sdk",
435379 "Unsupported MCP local source config.",
plugins/mcp/sdk/tools.test.ts+1−1
@@ -500,7 +500,7 @@ describe("codemode-mcp", () => { · 499 unmodified lines
500500 action: "accept" as const,
501501 };
502502 }),
503− path: "executor.sources.add" as ToolPath,
503+ path: "executor.mcp.createSource" as ToolPath,
504504 sourceKey: "executor",
505505 args: {
506506 endpoint: "https://example.com/mcp",
plugins/openapi/sdk/index.ts+0−46
@@ -19,7 +19,6 @@ import { · 18 unmodified lines
1919 } from "@executor/platform-sdk/plugins";
2020 import {
2121 createPluginLocalConfigEntrySchema,
22− decodeCurrentOrLegacyLocalConfigAuth,
2322 pluginLocalConfigSourceFromConfig,
2423 runtimeEffectError,
2524 SecretMaterialResolverService,
@@ -163,26 +162,6 @@ const decodeOpenApiCurrentLocalConfigOption = Schema.decodeUnknownOption( · 137 unmodified lines
163162 }),
164163 );
165164
166−const decodeOpenApiLegacyLocalConfigOption = Schema.decodeUnknownOption(
167− Schema.Struct({
168− kind: Schema.Literal("openapi"),
169− name: Schema.optional(Schema.String),
170− namespace: Schema.optional(Schema.String),
171− enabled: Schema.optional(Schema.Boolean),
172− connection: Schema.Struct({
173− endpoint: Schema.optional(Schema.NullOr(Schema.String)),
174− auth: Schema.optional(Schema.Unknown),
175− }),
176− binding: Schema.Struct({
177− specUrl: Schema.String,
178− defaultHeaders: Schema.optional(
179− Schema.NullOr(Schema.Record({ key: Schema.String, value: Schema.String })),
180− ),
181− }),
182− config: Schema.optional(Schema.Unknown),
183− }),
184−);
185−
186165 const createStoredSourceData = (
187166 input: OpenApiConnectInput,
188167 ): OpenApiStoredSourceData => ({
@@ -224,31 +203,6 @@ const openApiStoredSourceDataFromLocalConfig = (input: { · 35 unmodified lines
224203 });
225204 }
226205
227− const legacy = decodeOpenApiLegacyLocalConfigOption(input.config);
228− if (Option.isSome(legacy)) {
229− return normalizeStoredSourceData({
230− specUrl: legacy.value.binding.specUrl.trim(),
231− baseUrl: legacy.value.connection.endpoint?.trim() || null,
232− auth: decodeCurrentOrLegacyLocalConfigAuth({
233− auth: legacy.value.connection.auth,
234− authSchema: OpenApiConnectionAuthSchema,
235− loadedConfig: input.loadedConfig,
236− onLegacySecretRef: (tokenSecretRef) => ({
237− kind: "bearer",
238− tokenSecretRef,
239− headerName: null,
240− prefix: null,
241− }),
242− fallback: {
243− kind: "none",
244− },
245− }),
246− defaultHeaders: legacy.value.binding.defaultHeaders ?? null,
247− etag: null,
248− lastSyncAt: null,
249− });
250− }
251−
252206 throw new Error("Unsupported OpenAPI local source config.");
253207 };
254208