| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677 |
- export * as ConfigReferencePlugin from "./reference.js"
- import { define } from "@opencode-ai/plugin/effect/plugin"
- import { Document } from "@opencode-ai/schema/config"
- import { ConfigReference } from "@opencode-ai/schema/config/reference"
- import path from "path"
- import { Effect, Stream } from "effect"
- import { Config } from "../../config.js"
- import { Reference } from "../../reference.js"
- import { AbsolutePath } from "../../schema.js"
- import { Global } from "@opencode-ai/util/global"
- import { Location } from "../../location.js"
- export const Plugin = define({
- id: "opencode.config.reference",
- effect: Effect.fn(function* (ctx) {
- const config = yield* Config.Service
- const location = yield* Location.Service
- const global = yield* Global.Service
- const loaded = { entries: yield* config.entries() }
- yield* ctx.reference.transform((draft) => {
- const entries = new Map<string, Reference.Source>()
- for (const doc of loaded.entries.filter((entry): entry is Document => entry.type === "document")) {
- const directory = doc.path ? path.dirname(doc.path) : location.directory
- for (const [name, entry] of Object.entries(doc.info.references ?? {})) {
- if (!validAlias(name)) continue
- const description = typeof entry === "string" ? undefined : entry.description
- const hidden = typeof entry === "string" ? undefined : entry.hidden
- entries.set(
- name,
- local(entry)
- ? Reference.LocalSource.make({
- type: "local",
- path: AbsolutePath.make(
- localPath(directory, global.home, typeof entry === "string" ? entry : entry.path),
- ),
- ...(description === undefined ? {} : { description }),
- ...(hidden === undefined ? {} : { hidden }),
- })
- : Reference.GitSource.make({
- type: "git",
- repository: typeof entry === "string" ? entry : entry.repository,
- ...(entry.branch === undefined ? {} : { branch: entry.branch }),
- ...(description === undefined ? {} : { description }),
- ...(hidden === undefined ? {} : { hidden }),
- }),
- )
- }
- }
- for (const [name, source] of entries) draft.add(name, source)
- })
- yield* ctx.event.subscribe("config.updated").pipe(
- Stream.runForEach(() =>
- config.entries().pipe(
- Effect.tap((entries) => Effect.sync(() => (loaded.entries = entries))),
- Effect.andThen(ctx.reference.reload()),
- ),
- ),
- Effect.forkScoped({ startImmediately: true }),
- )
- }),
- })
- function validAlias(name: string) {
- return name.length > 0 && !/[\/\s`,]/.test(name)
- }
- function local(entry: ConfigReference.Entry): entry is string | ConfigReference.Local {
- return typeof entry === "string"
- ? entry.startsWith(".") || entry.startsWith("/") || entry.startsWith("~")
- : "path" in entry
- }
- function localPath(directory: string, home: string, value: string) {
- if (value.startsWith("~/")) return path.join(home, value.slice(2))
- return path.isAbsolute(value) ? value : path.resolve(directory, value)
- }
|