History

Merge remote-tracking branch 'origin/codex/batch17-core-executor-boundaries' into codex/effect-lint-integration

Rhys Sullivan committed 6 months ago

Commit cd10e672 parents 36b20f5 44315a81 file · +340 −591Browse files

Unified · Split

packages/core/sdk/src/executor.ts+340−591
@@ -10,10 +10,7 @@ import { · 9 unmodified lines
1010 type TypedAdapter,
1111 } from "@executor-js/storage-core";
1212
13−import {
14− pluginBlobStore,
15− type BlobStore,
16−} from "./blob";
13+import { pluginBlobStore, type BlobStore } from "./blob";
1714 import {
1815 ConnectionProviderState,
1916 ConnectionRef,
@@ -81,11 +78,7 @@ import type { · 61 unmodified lines
8178 StorageDeps,
8279 } from "./plugin";
8380 import type { Scope } from "./scope";
84−import {
85− SecretRef,
86− SetSecretInput,
87− type SecretProvider,
88−} from "./secrets";
81+import { SecretRef, SetSecretInput, type SecretProvider } from "./secrets";
8982 import { Usage } from "./usages";
9083 import {
9184 ToolSchema,
@@ -126,9 +119,7 @@ export interface InvokeOptions { · 34 unmodified lines
126119 const acceptAllHandler: ElicitationHandler = () =>
127120 Effect.succeed(new ElicitationResponse({ action: "accept" }));
128121
129−const resolveElicitationHandler = (
130− onElicitation: OnElicitation,
131−): ElicitationHandler =>
122+const resolveElicitationHandler = (onElicitation: OnElicitation): ElicitationHandler =>
132123 onElicitation === "accept-all" ? acceptAllHandler : onElicitation;
133124
134125 // ---------------------------------------------------------------------------
@@ -148,16 +139,12 @@ export type Executor<TPlugins extends readonly AnyPlugin[] = []> = { · 13 unmodified lines
148139 readonly scopes: readonly Scope[];
149140
150141 readonly tools: {
151− readonly list: (
152− filter?: ToolListFilter,
153− ) => Effect.Effect<readonly Tool[], StorageFailure>;
142+ readonly list: (filter?: ToolListFilter) => Effect.Effect<readonly Tool[], StorageFailure>;
154143 /** Fetch a tool's full schema view: JSON schemas with `$defs`
155144 * attached from the core `definition` table, plus TypeScript
156145 * preview strings rendered from them. Returns `null` for unknown
157146 * tool ids. */
158− readonly schema: (
159− toolId: string,
160− ) => Effect.Effect<ToolSchema | null, StorageFailure>;
147+ readonly schema: (toolId: string) => Effect.Effect<ToolSchema | null, StorageFailure>;
161148 /** Every `$defs` entry across every source, grouped by source id.
162149 * Used for bulk schema export and downstream TypeScript rendering. */
163150 readonly definitions: () => Effect.Effect<
@@ -206,12 +193,8 @@ export type Executor<TPlugins extends readonly AnyPlugin[] = []> = { · 42 unmodified lines
206193 * only, never calls the provider. Use this for UI state ("secret
207194 * missing, prompt to add") to avoid keychain permission prompts
208195 * or 1password IPC roundtrips on a pre-flight check. */
209− readonly status: (
210− id: string,
211− ) => Effect.Effect<"resolved" | "missing", StorageFailure>;
212− readonly set: (
213− input: SetSecretInput,
214− ) => Effect.Effect<SecretRef, StorageFailure>;
196+ readonly status: (id: string) => Effect.Effect<"resolved" | "missing", StorageFailure>;
197+ readonly set: (input: SetSecretInput) => Effect.Effect<SecretRef, StorageFailure>;
215198 /** Delete a bare (non-connection-owned) secret. Connection-owned
216199 * secrets are rejected with `SecretOwnedByConnectionError` — use
217200 * `connections.remove` instead. Refuses with `SecretInUseError`
@@ -219,37 +202,24 @@ export type Executor<TPlugins extends readonly AnyPlugin[] = []> = { · 1 unmodified line
219202 * show the `usages(id)` list and ask the user to detach first. */
220203 readonly remove: (
221204 id: string,
222− ) => Effect.Effect<
223− void,
224− SecretOwnedByConnectionError | SecretInUseError | StorageFailure
225− >;
205+ ) => Effect.Effect<void, SecretOwnedByConnectionError | SecretInUseError | StorageFailure>;
226206 readonly list: () => Effect.Effect<readonly SecretRef[], StorageFailure>;
227207 /** All places this secret is referenced — fans out across every
228208 * plugin's `usagesForSecret`. Used by the Secrets-tab "Used by"
229209 * list and by `remove` for its RESTRICT check. */
230− readonly usages: (
231− id: string,
232− ) => Effect.Effect<readonly Usage[], StorageFailure>;
210+ readonly usages: (id: string) => Effect.Effect<readonly Usage[], StorageFailure>;
233211 readonly providers: () => Effect.Effect<readonly string[]>;
234212 };
235213
236214 readonly connections: {
237− readonly get: (
238− id: string,
239− ) => Effect.Effect<ConnectionRef | null, StorageFailure>;
215+ readonly get: (id: string) => Effect.Effect<ConnectionRef | null, StorageFailure>;
240216 readonly list: () => Effect.Effect<readonly ConnectionRef[], StorageFailure>;
241217 readonly create: (
242218 input: CreateConnectionInput,
243− ) => Effect.Effect<
244− ConnectionRef,
245− ConnectionProviderNotRegisteredError | StorageFailure
246− >;
219+ ) => Effect.Effect<ConnectionRef, ConnectionProviderNotRegisteredError | StorageFailure>;
247220 readonly updateTokens: (
248221 input: UpdateConnectionTokensInput,
249− ) => Effect.Effect<
250− ConnectionRef,
251− ConnectionNotFoundError | StorageFailure
252− >;
222+ ) => Effect.Effect<ConnectionRef, ConnectionNotFoundError | StorageFailure>;
253223 readonly setIdentityLabel: (
254224 id: string,
255225 label: string | null,
@@ -267,14 +237,10 @@ export type Executor<TPlugins extends readonly AnyPlugin[] = []> = { · 11 unmodified lines
267237 >;
268238 /** Refuses with `ConnectionInUseError` if any plugin reports the
269239 * connection as in use. */
270− readonly remove: (
271− id: string,
272− ) => Effect.Effect<void, ConnectionInUseError | StorageFailure>;
240+ readonly remove: (id: string) => Effect.Effect<void, ConnectionInUseError | StorageFailure>;
273241 /** All places this connection is referenced — fans out across every
274242 * plugin's `usagesForConnection`. */
275− readonly usages: (
276− id: string,
277− ) => Effect.Effect<readonly Usage[], StorageFailure>;
243+ readonly usages: (id: string) => Effect.Effect<readonly Usage[], StorageFailure>;
278244 readonly providers: () => Effect.Effect<readonly string[]>;
279245 };
280246
@@ -289,28 +255,20 @@ export type Executor<TPlugins extends readonly AnyPlugin[] = []> = { · 8 unmodified lines
289255 readonly list: () => Effect.Effect<readonly ToolPolicy[], StorageFailure>;
290256 /** Create a new policy. Defaults to the top of the target scope's
291257 * list (highest precedence) when `position` is omitted. */
292− readonly create: (
293− input: CreateToolPolicyInput,
294− ) => Effect.Effect<ToolPolicy, StorageFailure>;
295− readonly update: (
296− input: UpdateToolPolicyInput,
297− ) => Effect.Effect<ToolPolicy, StorageFailure>;
258+ readonly create: (input: CreateToolPolicyInput) => Effect.Effect<ToolPolicy, StorageFailure>;
259+ readonly update: (input: UpdateToolPolicyInput) => Effect.Effect<ToolPolicy, StorageFailure>;
298260 readonly remove: (id: string) => Effect.Effect<void, StorageFailure>;
299261 /** Resolve the effective policy for a tool id by walking the scope-
300262 * stacked policy list with first-match-wins semantics. Returns
301263 * `undefined` when no rule matches (caller falls back to the
302264 * plugin's `resolveAnnotations` output). */
303− readonly resolve: (
304− toolId: string,
305− ) => Effect.Effect<PolicyMatch | undefined, StorageFailure>;
265+ readonly resolve: (toolId: string) => Effect.Effect<PolicyMatch | undefined, StorageFailure>;
306266 };
307267
308268 readonly close: () => Effect.Effect<void, StorageFailure>;
309269 } & PluginExtensions<TPlugins>;
310270
311−export interface ExecutorConfig<
312− TPlugins extends readonly AnyPlugin[] = [],
313−> {
271+export interface ExecutorConfig<TPlugins extends readonly AnyPlugin[] = []> {
314272 /**
315273 * Precedence-ordered scope stack. Innermost first; typical shape is
316274 * `[userInOrgScope, orgScope]`. Reads on scoped tables walk the
@@ -339,18 +297,19 @@ export interface ExecutorConfig< · 22 unmodified lines
339297 // manifest) before constructing the executor.
340298 // ---------------------------------------------------------------------------
341299
342−export const collectSchemas = (
343− plugins: readonly AnyPlugin[],
344−): DBSchema => {
300+export const collectSchemas = (plugins: readonly AnyPlugin[]): DBSchema => {
345301 const merged: Record<string, DBSchema[string]> = { ...coreSchema };
346302 for (const plugin of plugins) {
347303 if (!plugin.schema) continue;
348304 for (const [modelKey, model] of Object.entries(plugin.schema)) {
349305 if (merged[modelKey]) {
350− throw new Error(
351− `Duplicate model "${modelKey}" contributed by plugin "${plugin.id}"` +
306+ // oxlint-disable-next-line executor/no-try-catch-or-throw -- boundary: collectSchemas is a synchronous configuration API
307+ throw new StorageError({
308+ message:
309+ `Duplicate model "${modelKey}" contributed by plugin "${plugin.id}"` +
352310 ` (reserved by core or another plugin)`,
353− );
311+ cause: undefined,
312+ });
354313 }
355314 merged[modelKey] = model as DBSchema[string];
356315 }
@@ -375,10 +334,7 @@ const rowToSource = (row: SourceRow): Source => ({ · 18 unmodified lines
375334 runtime: false,
376335 });
377336
378−const staticDeclToSource = (
379− decl: StaticSourceDecl,
380− pluginId: string,
381−): Source => ({
337+const staticDeclToSource = (decl: StaticSourceDecl, pluginId: string): Source => ({
382338 id: decl.id,
383339 scopeId: undefined,
384340 kind: decl.kind,
@@ -394,17 +350,12 @@ const staticDeclToSource = ( · 9 unmodified lines
394350 const decodeJsonColumn = (value: unknown): unknown => {
395351 if (value === null || value === undefined) return undefined;
396352 if (typeof value !== "string") return value;
397− try {
398− return JSON.parse(value);
399− } catch {
400− return value;
401− }
353+ return Schema.decodeUnknownOption(Schema.UnknownFromJsonString)(value).pipe(
354+ Option.getOrElse(() => value),
355+ );
402356 };
403357
404−const rowToTool = (
405− row: ToolRow,
406− annotations?: ToolAnnotations,
407−): Tool => ({
358+const rowToTool = (row: ToolRow, annotations?: ToolAnnotations): Tool => ({
408359 id: row.id,
409360 sourceId: row.source_id,
410361 pluginId: row.plugin_id,
@@ -579,10 +530,9 @@ const toolMatchesFilter = (tool: Tool, filter: ToolListFilter): boolean => { · 168 unmodified lines
579530 // query through the same sql.begin connection. This is what makes nested
580531 // writes atomic on postgres + Hyperdrive without deadlocking a pool of 1.
581532 // ---------------------------------------------------------------------------
582−const activeAdapterRef = Context.Reference<DBTransactionAdapter | null>(
583− "executor/ActiveAdapter",
584− { defaultValue: () => null },
585−);
533+const activeAdapterRef = Context.Reference<DBTransactionAdapter | null>("executor/ActiveAdapter", {
534+ defaultValue: () => null,
535+});
586536
587537 // A `DBAdapter` whose methods dispatch to the active adapter (tx handle or
588538 // root) on every call. Stable identity for consumers (plugin storage,
@@ -593,7 +543,7 @@ const buildAdapterRouter = (root: DBAdapter): DBAdapter => { · 4 unmodified lines
593543 use: (active: DBTransactionAdapter) => Effect.Effect<A, E>,
594544 ): Effect.Effect<A, E> =>
595545 Effect.flatMap(Effect.service(activeAdapterRef), (active) =>
596− use((active ?? (root as DBTransactionAdapter))),
546+ use(active ?? (root as DBTransactionAdapter)),
597547 );
598548
599549 return {
@@ -646,27 +596,21 @@ interface PluginRuntime { · 46 unmodified lines
646596 readonly ctx: PluginCtx<unknown>;
647597 }
648598
649−export const createExecutor = <
650− const TPlugins extends readonly AnyPlugin[] = [],
651−>(
599+export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = []>(
652600 config: ExecutorConfig<TPlugins>,
653−): Effect.Effect<Executor<TPlugins>, Error> =>
601+): Effect.Effect<Executor<TPlugins>, StorageFailure> =>
654602 Effect.gen(function* () {
655603 const defaultPlugins = (): TPlugins => {
656604 const empty: readonly AnyPlugin[] = [];
657605 return empty as TPlugins;
658606 };
659− const {
660− scopes,
661− adapter: rootAdapter,
662− blobs,
663− plugins = defaultPlugins(),
664− } = config;
607+ const { scopes, adapter: rootAdapter, blobs, plugins = defaultPlugins() } = config;
665608
666609 if (scopes.length === 0) {
667− return yield* Effect.fail(
668− new Error("createExecutor requires a non-empty scopes array"),
669− );
610+ return yield* new StorageError({
611+ message: "createExecutor requires a non-empty scopes array",
612+ cause: undefined,
613+ });
670614 }
671615
672616 // Scope-wrap the root adapter so every read on a tenant-scoped
@@ -677,12 +621,8 @@ export const createExecutor = < · 4 unmodified lines
677621 // visible. Only tables whose schema declares `scope_id` are
678622 // scoped.
679623 const schema = collectSchemas(plugins);
680− const scopeIds = scopes.map((s) => s.id as string);
681− const scopedRoot = scopeAdapter(
682− rootAdapter,
683− { scopes: scopeIds },
684− schema,
685− );
624+ const scopeIds = scopes.map((s) => s.id);
625+ const scopedRoot = scopeAdapter(rootAdapter, { scopes: scopeIds }, schema);
686626 const adapter = buildAdapterRouter(scopedRoot);
687627 const core = typedAdapter<CoreSchema>(adapter);
688628
@@ -703,9 +643,7 @@ export const createExecutor = < · 14 unmodified lines
703643 ["google-discovery:google", "oauth2"],
704644 ["google-discovery:oauth2", "oauth2"],
705645 ]);
706− const resolveConnectionProvider = (
707− key: string,
708− ): ConnectionProvider | undefined => {
646+ const resolveConnectionProvider = (key: string): ConnectionProvider | undefined => {
709647 const direct = connectionProviders.get(key);
710648 if (direct) return direct;
711649 const canonical = connectionProviderAliases.get(key);
@@ -760,8 +698,12 @@ export const createExecutor = < · 48 unmodified lines
760698 // Rows whose scope isn't in the stack get pushed to the end (they
761699 // shouldn't reach us — the adapter filters by `scope_id IN (stack)` —
762700 // but guarding here means a stray row can't silently win).
763− const scopeRank = (row: { scope_id: unknown }) =>
764− scopePrecedence.get(row.scope_id as string) ?? Infinity;
701+ const rowScopeId = (row: { readonly scope_id: unknown }) =>
702+ typeof row.scope_id === "string" ? row.scope_id : null;
703+ const scopeRank = (row: { readonly scope_id: unknown }) => {
704+ const scopeId = rowScopeId(row);
705+ return scopeId === null ? Infinity : (scopePrecedence.get(scopeId) ?? Infinity);
706+ };
765707
766708 // Pick the innermost-scope row on a findOne-by-id against a scoped
767709 // model. The scope-wrapped adapter returns rows from every scope in
@@ -770,9 +712,7 @@ export const createExecutor = < · 2 unmodified lines
770712 // and wrong when a user has shadowed an outer default. Callers that
771713 // need a single logical row (invoke, tool schema, source removal)
772714 // must go through this path so the innermost write always wins.
773− const findInnermost = <T extends { scope_id: unknown }>(
774− rows: readonly T[],
775− ): T | null => {
715+ const findInnermost = <T extends { scope_id: unknown }>(rows: readonly T[]): T | null => {
776716 if (rows.length === 0) return null;
777717 let winner: T | undefined;
778718 let best = Infinity;
@@ -786,9 +726,7 @@ export const createExecutor = < · 7 unmodified lines
786726 return winner ?? null;
787727 };
788728
789− const secretRowsForId = (
790− id: string,
791− ): Effect.Effect<readonly SecretRow[], StorageFailure> =>
729+ const secretRowsForId = (id: string): Effect.Effect<readonly SecretRow[], StorageFailure> =>
792730 core.findMany({
793731 model: "secret",
794732 where: [{ field: "id", value: id }],
@@ -799,15 +737,11 @@ export const createExecutor = < · 4 unmodified lines
799737 rows: readonly SecretRow[],
800738 ): Effect.Effect<string | null, StorageFailure> =>
801739 Effect.gen(function* () {
802− const ordered = [...rows].sort(
803− (a, b) =>
804− (scopePrecedence.get(a.scope_id as string) ?? Infinity) -
805− (scopePrecedence.get(b.scope_id as string) ?? Infinity),
806− );
740+ const ordered = [...rows].sort((a, b) => scopeRank(a) - scopeRank(b));
807741 for (const row of ordered) {
808− const provider = secretProviders.get(row.provider as string);
742+ const provider = secretProviders.get(row.provider);
809743 if (!provider) continue;
810− const value = yield* provider.get(id, row.scope_id as string);
744+ const value = yield* provider.get(id, row.scope_id);
811745 if (value !== null) return value;
812746 }
813747
@@ -819,14 +753,10 @@ export const createExecutor = < · 5 unmodified lines
819753 // enumeration fallback doesn't know which scope the value
820754 // lives in; flat providers ignore the arg.
821755 const fallbackScope = scopeIds[0]!;
822− const candidates = [...secretProviders.values()].filter(
823− (p) => p.list,
824− );
756+ const candidates = [...secretProviders.values()].filter((p) => p.list);
825757 const values = yield* Effect.all(
826758 candidates.map((p) =>
827− p
828− .get(id, fallbackScope)
829− .pipe(Effect.catch(() => Effect.succeed(null))),
759+ p.get(id, fallbackScope).pipe(Effect.catch(() => Effect.succeed(null))),
830760 ),
831761 { concurrency: "unbounded" },
832762 );
@@ -844,51 +774,40 @@ export const createExecutor = < · 11 unmodified lines
844774 // must not expose them even if a token secret id is leaked.
845775 const rows = yield* secretRowsForId(id);
846776 const owned = rows.find((row) => row.owned_by_connection_id);
847− if (owned) {
848− return yield* Effect.fail(
849− new SecretOwnedByConnectionError({
850− secretId: SecretId.make(id),
851− connectionId: ConnectionId.make(
852− owned.owned_by_connection_id as string,
853− ),
854− }),
855− );
777+ const ownedByConnectionId = owned?.owned_by_connection_id;
778+ if (ownedByConnectionId) {
779+ return yield* new SecretOwnedByConnectionError({
780+ secretId: SecretId.make(id),
781+ connectionId: ConnectionId.make(ownedByConnectionId),
782+ });
856783 }
857784 return yield* resolveSecretValueFromRows(id, rows);
858785 });
859786
860− const connectionSecretGet = (
861− id: string,
862− ): Effect.Effect<string | null, StorageFailure> =>
787+ const connectionSecretGet = (id: string): Effect.Effect<string | null, StorageFailure> =>
863788 Effect.gen(function* () {
864789 const rows = yield* secretRowsForId(id);
865790 return yield* resolveSecretValueFromRows(id, rows);
866791 });
867792
868793 const secretRouteHasBackingValue = (row: SecretRow) => {
869− const provider = secretProviders.get(row.provider as string);
794+ const provider = secretProviders.get(row.provider);
870795 if (!provider?.has) return Effect.succeed(true);
871− return provider
872− .has(row.id as string, row.scope_id as string)
873− .pipe(Effect.catch(() => Effect.succeed(false)));
796+ return provider.has(row.id, row.scope_id).pipe(Effect.catch(() => Effect.succeed(false)));
874797 };
875798
876− const secretsSet = (
877− input: SetSecretInput,
878− ): Effect.Effect<SecretRef, StorageFailure> =>
799+ const secretsSet = (input: SetSecretInput): Effect.Effect<SecretRef, StorageFailure> =>
879800 Effect.gen(function* () {
880801 // Validate the write target up front. The adapter would reject
881802 // an out-of-stack scope too, but catching it here gives a
882803 // clearer error before we touch the provider.
883− if (!scopeIds.includes(input.scope as string)) {
884− return yield* Effect.fail(
885− new StorageError({
886− message:
887− `secrets.set targets scope "${input.scope}" which is not ` +
888− `in the executor's scope stack [${scopeIds.join(", ")}].`,
889− cause: undefined,
890− }),
891− );
804+ if (!scopeIds.includes(input.scope)) {
805+ return yield* new StorageError({
806+ message:
807+ `secrets.set targets scope "${input.scope}" which is not ` +
808+ `in the executor's scope stack [${scopeIds.join(", ")}].`,
809+ cause: undefined,
810+ });
892811 }
893812
894813 // Pick provider: explicit or first-writable. Misconfiguration
@@ -899,12 +818,10 @@ export const createExecutor = < · 4 unmodified lines
899818 if (input.provider) {
900819 target = secretProviders.get(input.provider);
901820 if (!target) {
902− return yield* Effect.fail(
903− new StorageError({
904− message: `Unknown secret provider: ${input.provider}`,
905− cause: undefined,
906− }),
907− );
821+ return yield* new StorageError({
822+ message: `Unknown secret provider: ${input.provider}`,
823+ cause: undefined,
824+ });
908825 }
909826 } else {
910827 for (const provider of secretProviders.values()) {
@@ -914,24 +831,20 @@ export const createExecutor = < · 3 unmodified lines
914831 }
915832 }
916833 if (!target) {
917− return yield* Effect.fail(
918− new StorageError({
919− message: "No writable secret providers registered",
920− cause: undefined,
921− }),
922− );
834+ return yield* new StorageError({
835+ message: "No writable secret providers registered",
836+ cause: undefined,
837+ });
923838 }
924839 }
925840 if (!target.writable || !target.set) {
926− return yield* Effect.fail(
927− new StorageError({
928− message: `Secret provider "${target.key}" is read-only`,
929− cause: undefined,
930− }),
931− );
841+ return yield* new StorageError({
842+ message: `Secret provider "${target.key}" is read-only`,
843+ cause: undefined,
844+ });
932845 }
933846
934− yield* target.set(input.id, input.value, input.scope as string);
847+ yield* target.set(input.id, input.value, input.scope);
935848
936849 // Upsert metadata row in the core `secret` table at the
937850 // caller-named scope. Pin the delete to `scope_id = input.scope`
@@ -979,9 +892,7 @@ export const createExecutor = < · 41 unmodified lines
979892 // errors fail the whole call so a transient plugin failure can't be
980893 // mistaken for "no usages" and let through a delete that creates
981894 // dangling refs.
982− const secretsUsagesStrict = (
983− id: string,
984− ): Effect.Effect<readonly Usage[], StorageFailure> =>
895+ const secretsUsagesStrict = (id: string): Effect.Effect<readonly Usage[], StorageFailure> =>
985896 Effect.gen(function* () {
986897 const secretId = SecretId.make(id);
987898 const perPlugin = yield* Effect.all(
@@ -1006,9 +917,7 @@ export const createExecutor = < · 18 unmodified lines
1006917 return perPlugin.flat();
1007918 });
1008919
1009− const secretsUsages = (
1010− id: string,
1011− ): Effect.Effect<readonly Usage[], StorageFailure> =>
920+ const secretsUsages = (id: string): Effect.Effect<readonly Usage[], StorageFailure> =>
1012921 Effect.gen(function* () {
1013922 const secretId = SecretId.make(id);
1014923 const perPlugin = yield* Effect.all(
@@ -1020,10 +929,9 @@ export const createExecutor = < · 5 unmodified lines
1020929 args: { secretId },
1021930 }).pipe(
1022931 Effect.catchCause((cause: unknown) =>
1023− Effect.logWarning(
1024− `usagesForSecret failed for plugin ${r.plugin.id}`,
1025− cause,
1026− ).pipe(Effect.as([] as readonly Usage[])),
932+ Effect.logWarning(`usagesForSecret failed for plugin ${r.plugin.id}`, cause).pipe(
933+ Effect.as([] as readonly Usage[]),
934+ ),
1027935 ),
1028936 ),
1029937 ),
@@ -1032,9 +940,7 @@ export const createExecutor = < · 2 unmodified lines
1032940 return perPlugin.flat();
1033941 });
1034942
1035− const connectionsUsagesStrict = (
1036− id: string,
1037− ): Effect.Effect<readonly Usage[], StorageFailure> =>
943+ const connectionsUsagesStrict = (id: string): Effect.Effect<readonly Usage[], StorageFailure> =>
1038944 Effect.gen(function* () {
1039945 const connectionId = ConnectionId.make(id);
1040946 const perPlugin = yield* Effect.all(
@@ -1059,9 +965,7 @@ export const createExecutor = < · 18 unmodified lines
1059965 return perPlugin.flat();
1060966 });
1061967
1062− const connectionsUsages = (
1063− id: string,
1064− ): Effect.Effect<readonly Usage[], StorageFailure> =>
968+ const connectionsUsages = (id: string): Effect.Effect<readonly Usage[], StorageFailure> =>
1065969 Effect.gen(function* () {
1066970 const connectionId = ConnectionId.make(id);
1067971 const perPlugin = yield* Effect.all(
@@ -1087,10 +991,7 @@ export const createExecutor = < · 19 unmodified lines
1087991
1088992 const secretsRemove = (
1089993 id: string,
1090− ): Effect.Effect<
1091− void,
1092− SecretOwnedByConnectionError | SecretInUseError | StorageFailure
1093− > =>
994+ ): Effect.Effect<void, SecretOwnedByConnectionError | SecretInUseError | StorageFailure> =>
1094995 Effect.gen(function* () {
1095996 // Remove is shadowing-aware: drop only the innermost-scope row.
1096997 // Removing a user-scope override on a secret that also has an
@@ -1107,14 +1008,10 @@ export const createExecutor = < · 10 unmodified lines
11071008 // Refuse to delete connection-owned secrets. The connection owns
11081009 // the lifecycle — callers must go through connections.remove.
11091010 if (target && target.owned_by_connection_id) {
1110− return yield* Effect.fail(
1111− new SecretOwnedByConnectionError({
1112− secretId: SecretId.make(id),
1113− connectionId: ConnectionId.make(
1114− target.owned_by_connection_id as string,
1115− ),
1116− }),
1117− );
1011+ return yield* new SecretOwnedByConnectionError({
1012+ secretId: SecretId.make(id),
1013+ connectionId: ConnectionId.make(target.owned_by_connection_id),
1014+ });
11181015 }
11191016 // RESTRICT: refuse if any source/binding still references this
11201017 // secret AND deleting the innermost row would leave the reference
@@ -1129,16 +1026,13 @@ export const createExecutor = < · 8 unmodified lines
11291026 if (willDangle) {
11301027 const usages = yield* secretsUsagesStrict(id);
11311028 if (usages.length > 0) {
1132− return yield* Effect.fail(
1133− new SecretInUseError({
1134− secretId: SecretId.make(id),
1135− usageCount: usages.length,
1136− }),
1137− );
1029+ return yield* new SecretInUseError({
1030+ secretId: SecretId.make(id),
1031+ usageCount: usages.length,
1032+ });
11381033 }
11391034 }
1140− const targetScope = (target?.scope_id as string | undefined) ??
1141− scopeIds[0]!;
1035+ const targetScope = target?.scope_id ?? scopeIds[0]!;
11421036
11431037 const deleters = [...secretProviders.values()].filter(
11441038 (p): p is typeof p & { delete: NonNullable<typeof p.delete> } =>
@@ -1195,19 +1089,15 @@ export const createExecutor = < · 50 unmodified lines
11951089 // leak them back in below.
11961090 const allRows = yield* core.findMany({ model: "secret" });
11971091 const connectionOwnedIds = new Set(
1198− allRows
1199− .filter((r) => r.owned_by_connection_id)
1200− .map((r) => r.id as string),
1092+ allRows.filter((r) => r.owned_by_connection_id).map((r) => r.id),
12011093 );
12021094 const rows = allRows.filter((r) => !r.owned_by_connection_id);
1203− const precedence = new Map<string, number>();
1204− scopeIds.forEach((id, index) => precedence.set(id, index));
1205− const pick = (row: typeof rows[number]) => {
1095+ const pick = (row: (typeof rows)[number]) => {
12061096 const existing = byId.get(row.id);
1207− const incomingScope = row.scope_id as string;
1208− const incomingRank = precedence.get(incomingScope) ?? Number.MAX_SAFE_INTEGER;
1097+ const incomingScope = row.scope_id;
1098+ const incomingRank = scopeRank(row);
12091099 if (existing) {
1210− const existingRank = precedence.get(existing.scopeId as string) ?? Number.MAX_SAFE_INTEGER;
1100+ const existingRank = scopePrecedence.get(existing.scopeId) ?? Infinity;
12111101 if (existingRank <= incomingRank) return;
12121102 }
12131103 byId.set(
@@ -1217,10 +1107,7 @@ export const createExecutor = < · 3 unmodified lines
12171107 scopeId: ScopeId.make(incomingScope),
12181108 name: row.name,
12191109 provider: row.provider,
1220− createdAt:
1221− row.created_at instanceof Date
1222− ? row.created_at
1223− : new Date(row.created_at as string),
1110+ createdAt: row.created_at instanceof Date ? row.created_at : new Date(row.created_at),
12241111 }),
12251112 );
12261113 };
@@ -1235,17 +1122,13 @@ export const createExecutor = < · 8 unmodified lines
12351122 // whole list. Merge in registration order afterwards so the
12361123 // "first provider wins" precedence stays deterministic.
12371124 const attribution = scopes[0]!.id;
1238− const listers = [...secretProviders.entries()].filter(
1239− ([, p]) => p.list,
1240− );
1125+ const listers = [...secretProviders.entries()].filter(([, p]) => p.list);
12411126 const lists = yield* Effect.all(
12421127 listers.map(([key, p]) =>
1243− p
1244− .list!()
1245− .pipe(
1246− Effect.catch(() => Effect.succeed([] as const)),
1247− Effect.map((entries) => ({ key, entries })),
1248− ),
1128+ p.list!().pipe(
1129+ Effect.catch(() => Effect.succeed([] as const)),
1130+ Effect.map((entries) => ({ key, entries })),
1131+ ),
12491132 ),
12501133 { concurrency: "unbounded" },
12511134 );
@@ -1294,35 +1177,22 @@ export const createExecutor = < · 42 unmodified lines
12941177 // behavior under the new SDK orchestration stays identical.
12951178 const CONNECTION_REFRESH_SKEW_MS = 60_000;
12961179
1297− const decodeProviderState = Schema.decodeUnknownOption(
1298− ConnectionProviderState,
1299− );
1180+ const decodeProviderState = Schema.decodeUnknownOption(ConnectionProviderState);
13001181
13011182 const rowToConnection = (row: ConnectionRow): ConnectionRef =>
13021183 new ConnectionRef({
1303− id: ConnectionId.make(row.id as string),
1304− scopeId: ScopeId.make(row.scope_id as string),
1305− provider: row.provider as string,
1306− identityLabel: (row.identity_label as string | null | undefined) ?? null,
1307− accessTokenSecretId: SecretId.make(row.access_token_secret_id as string),
1184+ id: ConnectionId.make(row.id),
1185+ scopeId: ScopeId.make(row.scope_id),
1186+ provider: row.provider,
1187+ identityLabel: row.identity_label ?? null,
1188+ accessTokenSecretId: SecretId.make(row.access_token_secret_id),
13081189 refreshTokenSecretId:
1309− row.refresh_token_secret_id != null
1310− ? SecretId.make(row.refresh_token_secret_id as string)
1311− : null,
1312− expiresAt:
1313− row.expires_at != null ? Number(row.expires_at as number) : null,
1314− oauthScope: (row.scope as string | null | undefined) ?? null,
1315− providerState: Option.getOrNull(
1316− decodeProviderState(decodeJsonColumn(row.provider_state)),
1317− ),
1318− createdAt:
1319− row.created_at instanceof Date
1320− ? row.created_at
1321− : new Date(row.created_at as string),
1322− updatedAt:
1323− row.updated_at instanceof Date
1324− ? row.updated_at
1325− : new Date(row.updated_at as string),
1190+ row.refresh_token_secret_id != null ? SecretId.make(row.refresh_token_secret_id) : null,
1191+ expiresAt: row.expires_at != null ? Number(row.expires_at) : null,
1192+ oauthScope: row.scope ?? null,
1193+ providerState: Option.getOrNull(decodeProviderState(decodeJsonColumn(row.provider_state))),
1194+ createdAt: row.created_at instanceof Date ? row.created_at : new Date(row.created_at),
1195+ updatedAt: row.updated_at instanceof Date ? row.updated_at : new Date(row.updated_at),
13261196 });
13271197
13281198 const findInnermostConnectionRow = (
@@ -1336,29 +1206,24 @@ export const createExecutor = < · 7 unmodified lines
13361206 return findInnermost(rows as readonly ConnectionRow[]);
13371207 });
13381208
1339− const connectionsGet = (
1340− id: string,
1341− ): Effect.Effect<ConnectionRef | null, StorageFailure> =>
1209+ const connectionsGet = (id: string): Effect.Effect<ConnectionRef | null, StorageFailure> =>
13421210 Effect.gen(function* () {
13431211 const row = yield* findInnermostConnectionRow(id);
13441212 return row ? rowToConnection(row) : null;
13451213 });
13461214
1347− const connectionsList = (): Effect.Effect<
1348− readonly ConnectionRef[],
1349− StorageFailure
1350− > =>
1215+ const connectionsList = (): Effect.Effect<readonly ConnectionRef[], StorageFailure> =>
13511216 Effect.gen(function* () {
13521217 const rows = yield* core.findMany({ model: "connection" });
13531218 // Dedup by id, innermost scope wins — same rule as sources/tools.
13541219 const byId = new Map<string, ConnectionRow>();
13551220 const byIdRank = new Map<string, number>();
13561221 for (const row of rows as readonly ConnectionRow[]) {
1357− const rank = scopeRank(row as { scope_id: unknown });
1358− const existing = byIdRank.get(row.id as string);
1222+ const rank = scopeRank(row);
1223+ const existing = byIdRank.get(row.id);
13591224 if (existing === undefined || rank < existing) {
1360− byId.set(row.id as string, row);
1361− byIdRank.set(row.id as string, rank);
1225+ byId.set(row.id, row);
1226+ byIdRank.set(row.id, rank);
13621227 }
13631228 }
13641229 return [...byId.values()].map(rowToConnection);
@@ -1367,33 +1232,27 @@ export const createExecutor = < · 2 unmodified lines
13671232 // Write a secret value through a specific provider, bypassing the
13681233 // bare-secrets ownership check so the SDK can stamp
13691234 // `owned_by_connection_id` atomically alongside a connection row.
1370− const writeOwnedSecret = (
1371− params: {
1372− id: string;
1373− scope: string;
1374− name: string;
1375− value: string;
1376− provider: string;
1377− ownedByConnectionId: string;
1378− },
1379− ): Effect.Effect<void, StorageFailure> =>
1235+ const writeOwnedSecret = (params: {
1236+ id: string;
1237+ scope: string;
1238+ name: string;
1239+ value: string;
1240+ provider: string;
1241+ ownedByConnectionId: string;
1242+ }): Effect.Effect<void, StorageFailure> =>
13801243 Effect.gen(function* () {
13811244 const target = secretProviders.get(params.provider);
13821245 if (!target) {
1383− return yield* Effect.fail(
1384− new StorageError({
1385− message: `Unknown secret provider: ${params.provider}`,
1386− cause: undefined,
1387− }),
1388− );
1246+ return yield* new StorageError({
1247+ message: `Unknown secret provider: ${params.provider}`,
1248+ cause: undefined,
1249+ });
13891250 }
13901251 if (!target.writable || !target.set) {
1391− return yield* Effect.fail(
1392− new StorageError({
1393− message: `Secret provider "${target.key}" is read-only`,
1394− cause: undefined,
1395− }),
1396− );
1252+ return yield* new StorageError({
1253+ message: `Secret provider "${target.key}" is read-only`,
1254+ cause: undefined,
1255+ });
13971256 }
13981257 yield* target.set(params.id, params.value, params.scope);
13991258
@@ -1426,50 +1285,39 @@ export const createExecutor = < · 26 unmodified lines
14261285 if (requested) {
14271286 const p = secretProviders.get(requested);
14281287 if (!p) {
1429− return yield* Effect.fail(
1430− new StorageError({
1431− message: `Unknown secret provider: ${requested}`,
1432− cause: undefined,
1433− }),
1434− );
1288+ return yield* new StorageError({
1289+ message: `Unknown secret provider: ${requested}`,
1290+ cause: undefined,
1291+ });
14351292 }
14361293 return p;
14371294 }
14381295 for (const p of secretProviders.values()) {
14391296 if (p.writable && p.set) return p;
14401297 }
1441− return yield* Effect.fail(
1442− new StorageError({
1443− message: "No writable secret providers registered",
1444− cause: undefined,
1445− }),
1446− );
1298+ return yield* new StorageError({
1299+ message: "No writable secret providers registered",
1300+ cause: undefined,
1301+ });
14471302 });
14481303
14491304 const connectionsCreate = (
14501305 input: CreateConnectionInput,
1451− ): Effect.Effect<
1452− ConnectionRef,
1453− ConnectionProviderNotRegisteredError | StorageFailure
1454− > =>
1306+ ): Effect.Effect<ConnectionRef, ConnectionProviderNotRegisteredError | StorageFailure> =>
14551307 Effect.gen(function* () {
1456− if (!scopeIds.includes(input.scope as string)) {
1457− return yield* Effect.fail(
1458− new StorageError({
1459− message:
1460− `connections.create targets scope "${input.scope}" which is not ` +
1461− `in the executor's scope stack [${scopeIds.join(", ")}].`,
1462− cause: undefined,
1463− }),
1464− );
1308+ if (!scopeIds.some((scopeId) => scopeId === input.scope)) {
1309+ return yield* new StorageError({
1310+ message:
1311+ `connections.create targets scope "${input.scope}" which is not ` +
1312+ `in the executor's scope stack [${scopeIds.join(", ")}].`,
1313+ cause: undefined,
1314+ });
14651315 }
14661316 if (!resolveConnectionProvider(input.provider)) {
1467− return yield* Effect.fail(
1468− new ConnectionProviderNotRegisteredError({
1469− provider: input.provider,
1470− connectionId: input.id,
1471− }),
1472− );
1317+ return yield* new ConnectionProviderNotRegisteredError({
1318+ provider: input.provider,
1319+ connectionId: input.id,
1320+ });
14731321 }
14741322
14751323 const writable = yield* pickWritableProvider();
@@ -1484,40 +1332,39 @@ export const createExecutor = < · 8 unmodified lines
14841332 yield* core.delete({
14851333 model: "connection",
14861334 where: [
1487− { field: "id", value: input.id as string },
1488− { field: "scope_id", value: input.scope as string },
1335+ { field: "id", value: input.id },
1336+ { field: "scope_id", value: input.scope },
14891337 ],
14901338 });
14911339
14921340 yield* writeOwnedSecret({
1493− id: input.accessToken.secretId as string,
1494− scope: input.scope as string,
1341+ id: input.accessToken.secretId,
1342+ scope: input.scope,
14951343 name: input.accessToken.name,
14961344 value: input.accessToken.value,
14971345 provider: writable.key,
1498− ownedByConnectionId: input.id as string,
1346+ ownedByConnectionId: input.id,
14991347 });
15001348 if (input.refreshToken) {
15011349 yield* writeOwnedSecret({
1502− id: input.refreshToken.secretId as string,
1503− scope: input.scope as string,
1350+ id: input.refreshToken.secretId,
1351+ scope: input.scope,
15041352 name: input.refreshToken.name,
15051353 value: input.refreshToken.value,
15061354 provider: writable.key,
1507− ownedByConnectionId: input.id as string,
1355+ ownedByConnectionId: input.id,
15081356 });
15091357 }
15101358
15111359 yield* core.create({
15121360 model: "connection",
15131361 data: {
1514− id: input.id as string,
1515− scope_id: input.scope as string,
1362+ id: input.id,
1363+ scope_id: input.scope,
15161364 provider: input.provider,
15171365 identity_label: input.identityLabel ?? undefined,
1518− access_token_secret_id: input.accessToken.secretId as string,
1519− refresh_token_secret_id:
1520− input.refreshToken?.secretId ?? undefined,
1366+ access_token_secret_id: input.accessToken.secretId,
1367+ refresh_token_secret_id: input.refreshToken?.secretId ?? undefined,
15211368 expires_at: input.expiresAt ?? undefined,
15221369 scope: input.oauthScope ?? undefined,
15231370 provider_state: input.providerState ?? undefined,
@@ -1533,8 +1380,7 @@ export const createExecutor = < · 9 unmodified lines
15331380 provider: input.provider,
15341381 identityLabel: input.identityLabel,
15351382 accessTokenSecretId: input.accessToken.secretId,
1536− refreshTokenSecretId:
1537− input.refreshToken?.secretId ?? null,
1383+ refreshTokenSecretId: input.refreshToken?.secretId ?? null,
15381384 expiresAt: input.expiresAt,
15391385 oauthScope: input.oauthScope,
15401386 providerState: input.providerState,
@@ -1552,53 +1398,41 @@ export const createExecutor = < · 11 unmodified lines
15521398 // configs still resolve.
15531399 const connectionsUpdateTokens = (
15541400 input: UpdateConnectionTokensInput,
1555− ): Effect.Effect<
1556− ConnectionRef,
1557− ConnectionNotFoundError | StorageFailure
1558− > =>
1401+ ): Effect.Effect<ConnectionRef, ConnectionNotFoundError | StorageFailure> =>
15591402 Effect.gen(function* () {
1560− const row = yield* findInnermostConnectionRow(input.id as string);
1403+ const row = yield* findInnermostConnectionRow(input.id);
15611404 if (!row) {
1562− return yield* Effect.fail(
1563− new ConnectionNotFoundError({ connectionId: input.id }),
1564− );
1405+ return yield* new ConnectionNotFoundError({ connectionId: input.id });
15651406 }
15661407 const writable = yield* pickWritableProvider();
1567− const accessName =
1568− `Connection ${input.id as string} access token`;
1569− const refreshName =
1570− `Connection ${input.id as string} refresh token`;
1408+ const accessName = `Connection ${input.id} access token`;
1409+ const refreshName = `Connection ${input.id} refresh token`;
15711410
15721411 return yield* adapter.transaction(() =>
15731412 Effect.gen(function* () {
15741413 yield* writeOwnedSecret({
1575− id: row.access_token_secret_id as string,
1576− scope: row.scope_id as string,
1414+ id: row.access_token_secret_id,
1415+ scope: row.scope_id,
15771416 name: accessName,
15781417 value: input.accessToken,
15791418 provider: writable.key,
1580− ownedByConnectionId: row.id as string,
1419+ ownedByConnectionId: row.id,
15811420 });
15821421 const rotatedRefresh = input.refreshToken ?? undefined;
1583− if (
1584− rotatedRefresh &&
1585− row.refresh_token_secret_id
1586− ) {
1422+ if (rotatedRefresh && row.refresh_token_secret_id) {
15871423 yield* writeOwnedSecret({
1588− id: row.refresh_token_secret_id as string,
1589− scope: row.scope_id as string,
1424+ id: row.refresh_token_secret_id,
1425+ scope: row.scope_id,
15901426 name: refreshName,
15911427 value: rotatedRefresh,
15921428 provider: writable.key,
1593− ownedByConnectionId: row.id as string,
1429+ ownedByConnectionId: row.id,
15941430 });
15951431 }
15961432 const now = new Date();
15971433 const patch: Record<string, unknown> = { updated_at: now };
1598− if (input.expiresAt !== undefined)
1599− patch.expires_at = input.expiresAt ?? undefined;
1600− if (input.oauthScope !== undefined)
1601− patch.scope = input.oauthScope ?? undefined;
1434+ if (input.expiresAt !== undefined) patch.expires_at = input.expiresAt ?? undefined;
1435+ if (input.oauthScope !== undefined) patch.scope = input.oauthScope ?? undefined;
16021436 if (input.providerState !== undefined)
16031437 patch.provider_state = input.providerState ?? undefined;
16041438 if (input.identityLabel !== undefined)
@@ -1606,18 +1440,16 @@ export const createExecutor = < · 1 unmodified line
16061440 yield* core.update({
16071441 model: "connection",
16081442 where: [
1609− { field: "id", value: row.id as string },
1610− { field: "scope_id", value: row.scope_id as string },
1443+ { field: "id", value: row.id },
1444+ { field: "scope_id", value: row.scope_id },
16111445 ],
16121446 update: patch,
16131447 });
1614− const updated = yield* findInnermostConnectionRow(
1615− row.id as string,
1616− );
1448+ const updated = yield* findInnermostConnectionRow(row.id);
16171449 if (!updated) {
1618− return yield* Effect.fail(
1619− new ConnectionNotFoundError({ connectionId: input.id }),
1620− );
1450+ return yield* new ConnectionNotFoundError({
1451+ connectionId: input.id,
1452+ });
16211453 }
16221454 return rowToConnection(updated);
16231455 }),
@@ -1631,17 +1463,15 @@ export const createExecutor = < · 7 unmodified lines
16311463 Effect.gen(function* () {
16321464 const row = yield* findInnermostConnectionRow(id);
16331465 if (!row) {
1634− return yield* Effect.fail(
1635− new ConnectionNotFoundError({
1636− connectionId: ConnectionId.make(id),
1637− }),
1638− );
1466+ return yield* new ConnectionNotFoundError({
1467+ connectionId: ConnectionId.make(id),
1468+ });
16391469 }
16401470 yield* core.update({
16411471 model: "connection",
16421472 where: [
16431473 { field: "id", value: id },
1644− { field: "scope_id", value: row.scope_id as string },
1474+ { field: "scope_id", value: row.scope_id },
16451475 ],
16461476 update: {
16471477 identity_label: label ?? undefined,
@@ -1667,15 +1497,13 @@ export const createExecutor = < · 19 unmodified lines
16671497 if (willDangle) {
16681498 const usages = yield* connectionsUsagesStrict(id);
16691499 if (usages.length > 0) {
1670− return yield* Effect.fail(
1671− new ConnectionInUseError({
1672− connectionId: ConnectionId.make(id),
1673− usageCount: usages.length,
1674− }),
1675− );
1500+ return yield* new ConnectionInUseError({
1501+ connectionId: ConnectionId.make(id),
1502+ usageCount: usages.length,
1503+ });
16761504 }
16771505 }
1678− const scope = row.scope_id as string;
1506+ const scope = row.scope_id;
16791507 yield* adapter.transaction(() =>
16801508 Effect.gen(function* () {
16811509 // Find every owned secret at this scope and drop through
@@ -1697,14 +1525,16 @@ export const createExecutor = < · 15 unmodified lines
16971525 for (const secret of owned) {
16981526 yield* Effect.all(
16991527 deleters.map((p) =>
1700− p.delete(secret.id as string, scope).pipe(
1701− Effect.catchCause((cause) =>
1702− Effect.logWarning(
1703− `Failed to delete connection-owned secret from provider ${p.key}`,
1704− cause,
1705− ).pipe(Effect.as(false)),
1528+ p
1529+ .delete(secret.id, scope)
1530+ .pipe(
1531+ Effect.catchCause((cause) =>
1532+ Effect.logWarning(
1533+ `Failed to delete connection-owned secret from provider ${p.key}`,
1534+ cause,
1535+ ).pipe(Effect.as(false)),
1536+ ),
17061537 ),
1707− ),
17081538 ),
17091539 { concurrency: "unbounded" },
17101540 );
@@ -1743,26 +1573,20 @@ export const createExecutor = < · 32 unmodified lines
17431573 // The actual work of a single refresh cycle, factored out so the
17441574 // concurrency gate (`connectionsAccessToken`) stays readable. Runs
17451575 // for the fiber that wins the `refreshInFlight` race.
1746− const performRefresh = (
1747− ref: ConnectionRef,
1748− ): Effect.Effect<string, AccessTokenError> =>
1576+ const performRefresh = (ref: ConnectionRef): Effect.Effect<string, AccessTokenError> =>
17491577 Effect.gen(function* () {
17501578 const provider = resolveConnectionProvider(ref.provider);
17511579 if (!provider) {
1752− return yield* Effect.fail(
1753− new ConnectionProviderNotRegisteredError({
1754− provider: ref.provider,
1755− connectionId: ref.id,
1756− }),
1757− );
1580+ return yield* new ConnectionProviderNotRegisteredError({
1581+ provider: ref.provider,
1582+ connectionId: ref.id,
1583+ });
17581584 }
17591585 if (!provider.refresh) {
1760− return yield* Effect.fail(
1761− new ConnectionRefreshNotSupportedError({
1762− connectionId: ref.id,
1763− provider: ref.provider,
1764− }),
1765− );
1586+ return yield* new ConnectionRefreshNotSupportedError({
1587+ connectionId: ref.id,
1588+ provider: ref.provider,
1589+ });
17661590 }
17671591
17681592 const refreshTokenValue = ref.refreshTokenSecretId
@@ -1774,31 +1598,28 @@ export const createExecutor = < · 5 unmodified lines
17741598 // stored refresh token can't recover. Translate into the
17751599 // caller-visible "re-authenticate" error so the UI can
17761600 // prompt sign-in instead of silently retrying.
1777− const rawResult: Result.Result<
1778− ConnectionRefreshResult,
1779− ConnectionRefreshError
1780− > = yield* Effect.result(
1781− provider.refresh({
1782− connectionId: ref.id,
1783− scopeId: ref.scopeId,
1784− identityLabel: ref.identityLabel,
1785− refreshToken: refreshTokenValue,
1786− providerState: ref.providerState,
1787− oauthScope: ref.oauthScope,
1788− }),
1789− );
1601+ const rawResult: Result.Result<ConnectionRefreshResult, ConnectionRefreshError> =
1602+ yield* Effect.result(
1603+ provider.refresh({
1604+ connectionId: ref.id,
1605+ scopeId: ref.scopeId,
1606+ identityLabel: ref.identityLabel,
1607+ refreshToken: refreshTokenValue,
1608+ providerState: ref.providerState,
1609+ oauthScope: ref.oauthScope,
1610+ }),
1611+ );
17901612 if (Result.isFailure(rawResult)) {
17911613 const err = rawResult.failure;
17921614 if (err.reauthRequired) {
1793− return yield* Effect.fail(
1794− new ConnectionReauthRequiredError({
1795− connectionId: err.connectionId,
1796− provider: ref.provider,
1797− message: err.message,
1798− }),
1799− );
1615+ return yield* new ConnectionReauthRequiredError({
1616+ connectionId: err.connectionId,
1617+ provider: ref.provider,
1618+ // oxlint-disable-next-line executor/no-unknown-error-message -- typed: ConnectionRefreshError.message is provider-facing domain data, not an unknown caught error
1619+ message: err["message"],
1620+ });
18001621 }
1801− return yield* Effect.fail(err);
1622+ return yield* err;
18021623 }
18031624 const result = rawResult.success;
18041625
@@ -1826,28 +1647,21 @@ export const createExecutor = < · 21 unmodified lines
18261647 // observes the Deferred and awaits its completion. The Deferred is
18271648 // pulled out of the map before the refresh result resolves so
18281649 // later invokes don't reuse a completed slot.
1829− const connectionsAccessToken = (
1830− id: string,
1831− ): Effect.Effect<string, AccessTokenError> =>
1650+ const connectionsAccessToken = (id: string): Effect.Effect<string, AccessTokenError> =>
18321651 Effect.gen(function* () {
18331652 const row = yield* findInnermostConnectionRow(id);
18341653 if (!row) {
1835− return yield* Effect.fail(
1836− new ConnectionNotFoundError({
1837− connectionId: ConnectionId.make(id),
1838− }),
1839− );
1654+ return yield* new ConnectionNotFoundError({
1655+ connectionId: ConnectionId.make(id),
1656+ });
18401657 }
18411658 const ref = rowToConnection(row);
18421659 const now = Date.now();
18431660 const needsRefresh =
1844− ref.expiresAt !== null &&
1845− ref.expiresAt - CONNECTION_REFRESH_SKEW_MS <= now;
1661+ ref.expiresAt !== null && ref.expiresAt - CONNECTION_REFRESH_SKEW_MS <= now;
18461662
18471663 if (!needsRefresh) {
1848− const current = yield* connectionSecretGet(
1849− ref.accessTokenSecretId,
1850− );
1664+ const current = yield* connectionSecretGet(ref.accessTokenSecretId);
18511665 if (current !== null) return current;
18521666 // Fall through to refresh if the stored token vanished — a
18531667 // genuinely-missing secret with no way to refresh is a
@@ -1901,17 +1715,12 @@ export const createExecutor = < · 47 unmodified lines
19011715 rawAdapter: adapter,
19021716 secretsGet: (id) =>
19031717 secretsGet(id).pipe(
1904− Effect.catchTag("SecretOwnedByConnectionError", () =>
1905− Effect.succeed(null),
1906− ),
1718+ Effect.catchTag("SecretOwnedByConnectionError", () => Effect.succeed(null)),
19071719 ),
19081720 secretsSet: (input) => secretsSet(input),
19091721 connectionsCreate: (input) => connectionsCreate(input),
19101722 });
1911− connectionProviders.set(
1912− oauthBundle.connectionProvider.key,
1913− oauthBundle.connectionProvider,
1914− );
1723+ connectionProviders.set(oauthBundle.connectionProvider.key, oauthBundle.connectionProvider);
19151724
19161725 // ------------------------------------------------------------------
19171726 // Plugin wiring — build ctx, run extension, populate static pools,
@@ -1919,9 +1728,10 @@ export const createExecutor = < · 1 unmodified line
19191728 // ------------------------------------------------------------------
19201729 for (const plugin of plugins) {
19211730 if (runtimes.has(plugin.id)) {
1922− return yield* Effect.fail(
1923− new Error(`Duplicate plugin id: ${plugin.id}`),
1924− );
1731+ return yield* new StorageError({
1732+ message: `Duplicate plugin id: ${plugin.id}`,
1733+ cause: undefined,
1734+ });
19251735 }
19261736
19271737 // Plugin-facing typed view. `StorageError` and `UniqueViolationError`
@@ -1957,22 +1767,18 @@ export const createExecutor = < · 29 unmodified lines
19571767 // share the same string space. Fails as `StorageError`
19581768 // so the HTTP edge surfaces it as `InternalError(traceId)`.
19591769 if (staticSources.has(input.id)) {
1960− return yield* Effect.fail(
1961− new StorageError({
1962− message: `Source id "${input.id}" collides with a static source`,
1963− cause: undefined,
1964− }),
1965− );
1770+ return yield* new StorageError({
1771+ message: `Source id "${input.id}" collides with a static source`,
1772+ cause: undefined,
1773+ });
19661774 }
19671775 for (const tool of input.tools) {
19681776 const fqid = `${input.id}.${tool.name}`;
19691777 if (staticTools.has(fqid)) {
1970− return yield* Effect.fail(
1971− new StorageError({
1972− message: `Tool id "${fqid}" collides with a static tool`,
1973− cause: undefined,
1974− }),
1975− );
1778+ return yield* new StorageError({
1779+ message: `Tool id "${fqid}" collides with a static tool`,
1780+ cause: undefined,
1781+ });
19761782 }
19771783 }
19781784 // Wrap in adapter.transaction so a standalone register()
@@ -1981,9 +1787,7 @@ export const createExecutor = < · 2 unmodified lines
19811787 // the router short-circuits to the active tx handle
19821788 // instead of opening a nested sql.begin — that nested
19831789 // sql.begin is the postgres.js + pool=1 deadlock path.
1984− yield* adapter.transaction(() =>
1985− writeSourceInput(core, plugin.id, input),
1986− );
1790+ yield* adapter.transaction(() => writeSourceInput(core, plugin.id, input));
19871791 }),
19881792 unregister: (sourceId: string) =>
19891793 // `unregister` is scoped to a specific source row — look up
@@ -2001,32 +1805,28 @@ export const createExecutor = < · 11 unmodified lines
20011805 });
20021806 const row = findInnermost(rows);
20031807 if (!row) return;
2004− yield* deleteSourceById(
2005− core,
2006− sourceId,
2007− row.scope_id as string,
2008− );
1808+ yield* deleteSourceById(core, sourceId, row.scope_id);
20091809 }),
20101810 ),
20111811 update: (input) =>
2012− core.update({
2013− model: "source",
2014− where: [
2015− { field: "id", value: input.id },
2016− { field: "scope_id", value: input.scope },
2017− ],
2018− update: {
2019− ...(input.name !== undefined ? { name: input.name } : {}),
2020− ...(input.url !== undefined ? { url: input.url ?? undefined } : {}),
2021− updated_at: new Date(),
2022− },
2023− }).pipe(Effect.asVoid),
1812+ core
1813+ .update({
1814+ model: "source",
1815+ where: [
1816+ { field: "id", value: input.id },
1817+ { field: "scope_id", value: input.scope },
1818+ ],
1819+ update: {
1820+ ...(input.name !== undefined ? { name: input.name } : {}),
1821+ ...(input.url !== undefined ? { url: input.url ?? undefined } : {}),
1822+ updated_at: new Date(),
1823+ },
1824+ })
1825+ .pipe(Effect.asVoid),
20241826 },
20251827 definitions: {
20261828 register: (input: DefinitionsInput) =>
2027− adapter.transaction(() =>
2028− writeDefinitions(core, plugin.id, input),
2029− ),
1829+ adapter.transaction(() => writeDefinitions(core, plugin.id, input)),
20301830 },
20311831 },
20321832 secrets: {
@@ -2040,8 +1840,7 @@ export const createExecutor = < · 7 unmodified lines
20401840 list: () => connectionsListForCtx(),
20411841 create: (input) => connectionsCreate(input),
20421842 updateTokens: (input) => connectionsUpdateTokens(input),
2043− setIdentityLabel: (id, label) =>
2044− connectionsSetIdentityLabel(id, label),
1843+ setIdentityLabel: (id, label) => connectionsSetIdentityLabel(id, label),
20451844 accessToken: (id) => connectionsAccessToken(id),
20461845 remove: (id) => connectionsRemove(id),
20471846 },
@@ -2052,45 +1851,36 @@ export const createExecutor = < · 4 unmodified lines
20521851 // propagate unchanged; storage failures also stay typed
20531852 // (`StorageFailure`) so the HTTP edge wrapper can translate them.
20541853 transaction: <A, E>(effect: Effect.Effect<A, E>) =>
2055− adapter.transaction(() => effect) as Effect.Effect<
2056− A,
2057− E | StorageFailure
2058− >,
1854+ adapter.transaction(() => effect) as Effect.Effect<A, E | StorageFailure>,
20591855 };
20601856
20611857 // Build extension FIRST so it's available as `self` when resolving
20621858 // staticSources. Field ordering in the plugin spec matters — TS
20631859 // infers TExtension from `extension`'s return type, then NoInfer
20641860 // locks `self` to that inferred type on `staticSources`.
2065− const extension: object = plugin.extension
2066− ? plugin.extension(ctx)
2067− : {};
1861+ const extension: object = plugin.extension ? plugin.extension(ctx) : {};
20681862 if (plugin.extension) {
20691863 extensions[plugin.id] = extension;
20701864 }
20711865
20721866 // Resolve static declarations to the in-memory pools. NO DB WRITES.
2073− const decls = plugin.staticSources
2074− ? plugin.staticSources(extension)
2075− : [];
1867+ const decls = plugin.staticSources ? plugin.staticSources(extension) : [];
20761868 for (const source of decls) {
20771869 if (staticSources.has(source.id)) {
2078− return yield* Effect.fail(
2079− new Error(
2080− `Duplicate static source id: ${source.id} (plugin ${plugin.id})`,
2081− ),
2082− );
1870+ return yield* new StorageError({
1871+ message: `Duplicate static source id: ${source.id} (plugin ${plugin.id})`,
1872+ cause: undefined,
1873+ });
20831874 }
20841875 staticSources.set(source.id, { source, pluginId: plugin.id });
20851876
20861877 for (const tool of source.tools) {
20871878 const fqid = `${source.id}.${tool.name}`;
20881879 if (staticTools.has(fqid)) {
2089− return yield* Effect.fail(
2090− new Error(
2091− `Duplicate static tool id: ${fqid} (plugin ${plugin.id})`,
2092− ),
2093− );
1880+ return yield* new StorageError({
1881+ message: `Duplicate static tool id: ${fqid} (plugin ${plugin.id})`,
1882+ cause: undefined,
1883+ });
20941884 }
20951885 staticTools.set(fqid, {
20961886 source,
@@ -2111,11 +1901,10 @@ export const createExecutor = < · 14 unmodified lines
21111901 const providers = Effect.isEffect(raw) ? yield* raw : raw;
21121902 for (const provider of providers) {
21131903 if (secretProviders.has(provider.key)) {
2114− return yield* Effect.fail(
2115− new Error(
2116− `Duplicate secret provider key: ${provider.key} (from plugin ${plugin.id})`,
2117− ),
2118− );
1904+ return yield* new StorageError({
1905+ message: `Duplicate secret provider key: ${provider.key} (from plugin ${plugin.id})`,
1906+ cause: undefined,
1907+ });
21191908 }
21201909 secretProviders.set(provider.key, provider);
21211910 }
@@ -2129,11 +1918,10 @@ export const createExecutor = < · 7 unmodified lines
21291918 const providers = Effect.isEffect(raw) ? yield* raw : raw;
21301919 for (const provider of providers) {
21311920 if (connectionProviders.has(provider.key)) {
2132− return yield* Effect.fail(
2133− new Error(
2134− `Duplicate connection provider key: ${provider.key} (from plugin ${plugin.id})`,
2135− ),
2136− );
1921+ return yield* new StorageError({
1922+ message: `Duplicate connection provider key: ${provider.key} (from plugin ${plugin.id})`,
1923+ cause: undefined,
1924+ });
21371925 }
21381926 connectionProviders.set(provider.key, provider);
21391927 }
@@ -2151,7 +1939,7 @@ export const createExecutor = < · 11 unmodified lines
21511939 // two rows — their override and the outer default — which is
21521940 // inconsistent with how `secrets.list` and every other list
21531941 // surface dedup shadowed entries.
2154− const byId = new Map<string, typeof dynamic[number]>();
1942+ const byId = new Map<string, (typeof dynamic)[number]>();
21551943 const byIdRank = new Map<string, number>();
21561944 for (const row of dynamic) {
21571945 const rank = scopeRank(row);
@@ -2201,10 +1989,7 @@ export const createExecutor = < · 43 unmodified lines
22011989 [...groups],
22021990 ([key, groupRows]) =>
22031991 Effect.gen(function* () {
2204− const [pluginId, sourceId] = key.split("\u0000") as [
2205− string,
2206− string,
2207− ];
1992+ const [pluginId, sourceId] = key.split("\u0000") as [string, string];
22081993 const runtime = runtimes.get(pluginId);
22091994 if (!runtime?.plugin.resolveAnnotations) return undefined;
22101995 return yield* runtime.plugin.resolveAnnotations({
@@ -2228,14 +2013,12 @@ export const createExecutor = < · 17 unmodified lines
22282013 Effect.gen(function* () {
22292014 const dynamic = yield* core.findMany({
22302015 model: "tool",
2231− where: filter?.sourceId
2232− ? [{ field: "source_id", value: filter.sourceId }]
2233− : undefined,
2016+ where: filter?.sourceId ? [{ field: "source_id", value: filter.sourceId }] : undefined,
22342017 });
22352018 // Dedup by tool id, innermost scope winning — same reason as
22362019 // `listSources` above: a shadowed id must surface as one entry
22372020 // (the inner one), not two.
2238− const byId = new Map<string, typeof dynamic[number]>();
2021+ const byId = new Map<string, (typeof dynamic)[number]>();
22392022 const byIdRank = new Map<string, number>();
22402023 for (const row of dynamic) {
22412024 const rank = scopeRank(row);
@@ -2261,9 +2044,7 @@ export const createExecutor = < · 19 unmodified lines
22612044 for (const row of dynamicDeduped) {
22622045 out.push(rowToTool(row, annotations.get(row.id)));
22632046 }
2264− const filtered = filter
2265− ? out.filter((t) => toolMatchesFilter(t, filter))
2266− : out;
2047+ const filtered = filter ? out.filter((t) => toolMatchesFilter(t, filter)) : out;
22672048
22682049 // Drop tools blocked by user policy unless the caller explicitly
22692050 // asked to see them (the settings UI does, agent surfaces don't).
@@ -2306,7 +2087,7 @@ export const createExecutor = < · 36 unmodified lines
23062087 model: "definition",
23072088 where: [{ field: "source_id", value: sourceId }],
23082089 });
2309− const winners = new Map<string, { row: typeof defRows[number]; rank: number }>();
2090+ const winners = new Map<string, { row: (typeof defRows)[number]; rank: number }>();
23102091 for (const row of defRows) {
23112092 const rank = scopeRank(row);
23122093 const existing = winners.get(row.name);
@@ -2432,7 +2213,7 @@ export const createExecutor = < · 119 unmodified lines
24322213 const toolsDefinitions = () =>
24332214 Effect.gen(function* () {
24342215 const rows = yield* core.findMany({ model: "definition" });
2435− const winners = new Map<string, { row: typeof rows[number]; rank: number }>();
2216+ const winners = new Map<string, { row: (typeof rows)[number]; rank: number }>();
24362217 for (const row of rows) {
24372218 const key = `${row.source_id}\u0000${row.name}`;
24382219 const rank = scopeRank(row);
@@ -2453,19 +2234,13 @@ export const createExecutor = < · 14 unmodified lines
24532234 return out;
24542235 });
24552236
2456− const defaultElicitationHandler = resolveElicitationHandler(
2457− config.onElicitation,
2458− );
2237+ const defaultElicitationHandler = resolveElicitationHandler(config.onElicitation);
24592238 const pickHandler = (options: InvokeOptions | undefined): ElicitationHandler =>
24602239 options?.onElicitation
24612240 ? resolveElicitationHandler(options.onElicitation)
24622241 : defaultElicitationHandler;
24632242
2464− const buildElicit = (
2465− toolId: string,
2466− args: unknown,
2467− handler: ElicitationHandler,
2468− ): Elicit => {
2243+ const buildElicit = (toolId: string, args: unknown, handler: ElicitationHandler): Elicit => {
24692244 return (request: ElicitationRequest) =>
24702245 Effect.gen(function* () {
24712246 const tid = ToolId.make(toolId);
@@ -2494,8 +2269,7 @@ export const createExecutor = < · 22 unmodified lines
24942269 // used as today.
24952270 // ------------------------------------------------------------------
24962271
2497− const loadAllPolicies = () =>
2498− core.findMany({ model: "tool_policy" });
2272+ const loadAllPolicies = () => core.findMany({ model: "tool_policy" });
24992273
25002274 const resolveToolPolicyForId = (toolId: string) =>
25012275 Effect.gen(function* () {
@@ -2539,13 +2313,13 @@ export const createExecutor = < · 37 unmodified lines
25392313 }
25402314 });
25412315
2542− const invokeTool = (
2543− toolId: string,
2544− args: unknown,
2545− options?: InvokeOptions,
2546− ) => {
2316+ const invokeTool = (toolId: string, args: unknown, options?: InvokeOptions) => {
25472317 const handler = pickHandler(options);
25482318 return Effect.gen(function* () {
2319+ const formatInvocationCauseMessage = (cause: unknown): string => {
2320+ // oxlint-disable-next-line executor/no-instanceof-error, executor/no-unknown-error-message -- boundary: preserve public invoke error message wrapping for unknown plugin failures
2321+ return cause instanceof Error ? cause.message : String(cause);
2322+ };
25492323 const wrapInvocationError = <A, E>(
25502324 effect: Effect.Effect<A, E>,
25512325 ): Effect.Effect<A, ToolInvocationError> =>
@@ -2554,8 +2328,7 @@ export const createExecutor = < · 2 unmodified lines
25542328 (cause) =>
25552329 new ToolInvocationError({
25562330 toolId: ToolId.make(toolId),
2557− message:
2558− cause instanceof Error ? cause.message : String(cause),
2331+ message: formatInvocationCauseMessage(cause),
25592332 cause,
25602333 }),
25612334 ),
@@ -2583,13 +2356,9 @@ export const createExecutor = < · 21 unmodified lines
25832356 "executor.source_kind": staticEntry.source.kind,
25842357 "executor.plugin_id": staticEntry.pluginId,
25852358 });
2586− yield* enforceApproval(
2587− staticEntry.tool.annotations,
2588− toolId,
2589− args,
2590− policy,
2591− handler,
2592− ).pipe(Effect.withSpan("executor.tool.enforce_approval"));
2359+ yield* enforceApproval(staticEntry.tool.annotations, toolId, args, policy, handler).pipe(
2360+ Effect.withSpan("executor.tool.enforce_approval"),
2361+ );
25932362 return yield* wrapInvocationError(
25942363 staticEntry.tool.handler({
25952364 ctx: staticEntry.ctx,
@@ -2702,14 +2471,10 @@ export const createExecutor = < · 106 unmodified lines
27022471 yield* runtime.plugin.removeSource({
27032472 ctx: runtime.ctx,
27042473 sourceId,
2705− scope: sourceRow.scope_id as string,
2474+ scope: sourceRow.scope_id,
27062475 });
27072476 }
2708− yield* deleteSourceById(
2709− core,
2710− sourceId,
2711− sourceRow.scope_id as string,
2712− );
2477+ yield* deleteSourceById(core, sourceId, sourceRow.scope_id);
27132478 }),
27142479 );
27152480 });
@@ -2730,7 +2495,7 @@ export const createExecutor = < · 14 unmodified lines
27302495 yield* runtime.plugin.refreshSource({
27312496 ctx: runtime.ctx,
27322497 sourceId,
2733− scope: sourceRow.scope_id as string,
2498+ scope: sourceRow.scope_id,
27342499 });
27352500 }
27362501 });
@@ -2739,9 +2504,7 @@ export const createExecutor = < · 2 unmodified lines
27392504 // `detect` hook. Collect all non-null results. Plugin-level detect
27402505 // implementations should swallow fetch errors and return null, so
27412506 // one flaky plugin doesn't block the whole dispatch.
2742− const detectionConfidenceScore = (
2743− confidence: SourceDetectionResult["confidence"],
2744− ) => {
2507+ const detectionConfidenceScore = (confidence: SourceDetectionResult["confidence"]) => {
27452508 switch (confidence) {
27462509 case "high":
27472510 return 3;
@@ -2763,24 +2526,19 @@ export const createExecutor = < · 15 unmodified lines
27632526 if (result) results.push(result);
27642527 }
27652528 return results.sort(
2766− (a, b) =>
2767− detectionConfidenceScore(b.confidence) -
2768− detectionConfidenceScore(a.confidence),
2529+ (a, b) => detectionConfidenceScore(b.confidence) - detectionConfidenceScore(a.confidence),
27692530 );
27702531 });
27712532
27722533 // Per-source definitions accessor — one query, one mapping pass.
2773− const sourceDefinitions = (sourceId: string) =>
2774− loadDefinitionsForSource(sourceId);
2534+ const sourceDefinitions = (sourceId: string) => loadDefinitionsForSource(sourceId);
27752535
27762536 // Existence check for user-facing secret pickers. Core `secret`
27772537 // rows are routing metadata; when a provider can answer `has()`,
27782538 // confirm the backing value still exists. Providers without `has()`
27792539 // remain conservative so keychain/1password don't need to return
27802540 // the value or prompt just to populate picker/status UI.
2781− const secretsStatus = (
2782− id: string,
2783− ): Effect.Effect<"resolved" | "missing", StorageFailure> =>
2541+ const secretsStatus = (id: string): Effect.Effect<"resolved" | "missing", StorageFailure> =>
27842542 Effect.gen(function* () {
27852543 const rows = yield* secretRowsForId(id);
27862544 if (rows.some((row) => row.owned_by_connection_id)) return "missing";
@@ -2853,7 +2611,7 @@ export const createExecutor = < · 66 unmodified lines
28532611 });
28542612 let min: string | null = null;
28552613 for (const row of existing) {
2856− const p = row.position as string;
2614+ const p = row.position;
28572615 if (min === null || p < min) min = p;
28582616 }
28592617 position = generateKeyBetween(null, min);
@@ -2923,13 +2681,13 @@ export const createExecutor = < · 63 unmodified lines
29232681 model: "tool_policy",
29242682 where: [
29252683 { field: "id", value: input.id },
2926− { field: "scope_id", value: row.scope_id as string },
2684+ { field: "scope_id", value: row.scope_id },
29272685 ],
29282686 update: {
2929− pattern: updated.pattern as string,
2930− action: updated.action as string,
2931− position: updated.position as string,
2932− updated_at: updated.updated_at as Date,
2687+ pattern: updated.pattern,
2688+ action: updated.action,
2689+ position: updated.position,
2690+ updated_at: updated.updated_at,
29332691 },
29342692 });
29352693 return rowToToolPolicy(updated);
@@ -2944,9 +2702,7 @@ export const createExecutor = < · 8 unmodified lines
29442702 .pipe(Effect.asVoid, Effect.withSpan("executor.policies.remove"));
29452703
29462704 const policiesResolve = (toolId: string) =>
2947− resolveToolPolicyForId(toolId).pipe(
2948− Effect.withSpan("executor.policies.resolve"),
2949− );
2705+ resolveToolPolicyForId(toolId).pipe(Effect.withSpan("executor.policies.resolve"));
29502706
29512707 const close = () =>
29522708 Effect.gen(function* () {
@@ -2984,10 +2740,7 @@ export const createExecutor = < · 31 unmodified lines
29842740 remove: secretsRemove,
29852741 list: secretsList,
29862742 usages: secretsUsages,
2987− providers: () =>
2988− Effect.sync(
2989− () => Array.from(secretProviders.keys()) as readonly string[],
2990− ),
2743+ providers: () => Effect.sync(() => Array.from(secretProviders.keys()) as readonly string[]),
29912744 },
29922745 connections: {
29932746 get: connectionsGet,
@@ -2999,10 +2752,7 @@ export const createExecutor = < · 5 unmodified lines
29992752 remove: connectionsRemove,
30002753 usages: connectionsUsages,
30012754 providers: () =>
3002− Effect.sync(
3003− () =>
3004− Array.from(connectionProviders.keys()) as readonly string[],
3005− ),
2755+ Effect.sync(() => Array.from(connectionProviders.keys()) as readonly string[]),
30062756 },
30072757 oauth: oauthBundle.service,
30082758 policies: {
@@ -3020,7 +2770,6 @@ export const createExecutor = < · 11 unmodified lines
30202770 // those leak via the helper functions and won't be cleaned until
30212771 // every plugin tightens its surface to typed errors. The runtime
30222772 // shape matches `Executor<TPlugins>`.
3023− const toExecutor = (value: unknown): Executor<TPlugins> =>
3024− value as Executor<TPlugins>;
2773+ const toExecutor = (value: unknown): Executor<TPlugins> => value as Executor<TPlugins>;
30252774 return toExecutor(Object.assign(base, extensions));
30262775 });