mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-13 19:46:16 +03:00
98 lines
4.1 KiB
TypeScript
98 lines
4.1 KiB
TypeScript
import { Config } from "@opencode/core/config"
|
|
import { ConfigIntegration } from "@opencode/core/config/integration"
|
|
import { ConfigPolicyPlugin } from "@opencode/core/config/plugin/policy"
|
|
import { Integration } from "@opencode/core/integration"
|
|
import { Mcp } from "@opencode/core/mcp/index"
|
|
import { Skill } from "@opencode/core/skill"
|
|
import { Info } from "@opencode/schema/config"
|
|
import { ConfigPolicy } from "@opencode/schema/config/policy"
|
|
import { ID } from "@opencode/schema/event"
|
|
import { Credential } from "@opencode/core/credential"
|
|
import { WebSearch } from "@opencode/core/websearch"
|
|
import { Effect, Schema, Stream } from "effect"
|
|
import { host } from "../plugin/host"
|
|
|
|
/** A connected organization's policy as the OpenCode Console delivers it: an integration config document. */
|
|
export function organizationPolicy(policies: ConfigPolicy.Info[], organization?: string) {
|
|
return new ConfigIntegration.Document({
|
|
type: "document",
|
|
integrationID: Integration.ID.make("opencode"),
|
|
connection: { type: "env", name: "OPENCODE_API_KEY" },
|
|
organization,
|
|
info: Schema.decodeUnknownSync(Info)({ policies }),
|
|
})
|
|
}
|
|
|
|
/** Replaces the connected organization's policy, or removes it; publish `Event.Updated` to make plugins reload. */
|
|
export const setOrganizationPolicy = Effect.fn(function* (policies: ConfigPolicy.Info[] | undefined) {
|
|
const config = yield* Config.Service
|
|
yield* config.integration?.(Integration.ID.make("opencode"), policies && organizationPolicy(policies)) ?? Effect.void
|
|
})
|
|
|
|
// Exercise the real policy plugin against supplied catalogs without unrelated provider/permission setup.
|
|
export const registerIntegrationPolicy = Effect.fn(function* (input: {
|
|
mcp?: Mcp.Interface
|
|
skill?: Skill.Interface
|
|
events?: Stream.Stream<{ readonly type: string }, unknown>
|
|
}) {
|
|
yield* ConfigPolicyPlugin.Plugin.effect(
|
|
host({
|
|
event: {
|
|
subscribe: () =>
|
|
(input.events ?? Stream.never).pipe(
|
|
Stream.filter((event) => event.type === "config.updated"),
|
|
Stream.map(() => ({ id: ID.create(), created: Date.now(), type: "config.updated" as const, data: {} })),
|
|
),
|
|
},
|
|
provider: {
|
|
list: () => Effect.die("unused provider.list"),
|
|
get: () => Effect.die("unused provider.get"),
|
|
transform: () => Effect.succeed({ dispose: Effect.void }),
|
|
reload: () => Effect.void,
|
|
},
|
|
mcp: {
|
|
list: () => Effect.die("unused mcp.list"),
|
|
transform: (callback) => input.mcp?.transform(callback) ?? Effect.succeed({ dispose: Effect.void }),
|
|
reload: () => input.mcp?.reload() ?? Effect.void,
|
|
},
|
|
skill: {
|
|
list: () => Effect.die("unused skill.list"),
|
|
transform: (callback) => input.skill?.transform(callback) ?? Effect.succeed({ dispose: Effect.void }),
|
|
reload: () => input.skill?.reload() ?? Effect.void,
|
|
},
|
|
permission: {
|
|
hook: () => Effect.succeed({ dispose: Effect.void }),
|
|
list: () => Effect.die("unused permission.list"),
|
|
get: () => Effect.die("unused permission.get"),
|
|
reply: () => Effect.die("unused permission.reply"),
|
|
assert: () => Effect.die("unused permission.assert"),
|
|
},
|
|
}),
|
|
).pipe(
|
|
Effect.provideService(
|
|
Credential.Service,
|
|
Credential.Service.of({
|
|
all: () => Effect.succeed([]),
|
|
list: () => Effect.succeed([]),
|
|
get: () => Effect.succeed(undefined),
|
|
lock: () => Effect.die("unused Credential.lock"),
|
|
create: () => Effect.die("unused Credential.create"),
|
|
activate: () => Effect.die("unused Credential.activate"),
|
|
update: () => Effect.die("unused Credential.update"),
|
|
remove: () => Effect.die("unused Credential.remove"),
|
|
}),
|
|
),
|
|
Effect.provideService(
|
|
WebSearch.Service,
|
|
WebSearch.Service.of({
|
|
providers: () => Effect.die("unused WebSearch.providers"),
|
|
default: () => Effect.die("unused WebSearch.default"),
|
|
select: () => Effect.die("unused WebSearch.select"),
|
|
query: () => Effect.die("unused WebSearch.query"),
|
|
transform: () => Effect.succeed({ dispose: Effect.void }),
|
|
reload: () => Effect.void,
|
|
}),
|
|
),
|
|
)
|
|
})
|