feat(api): add experimental wellknown connections

This commit is contained in:
Dax Raad 2026-07-15 22:52:55 -04:00
commit 5fb0470b44
33 changed files with 1070 additions and 138 deletions

View file

@ -8,7 +8,9 @@ import { ConfigModel } from "@opencode-ai/core/config/model"
import { Config as ConfigSchema } from "@opencode-ai/schema/config"
import { ConfigProvider } from "@opencode-ai/core/config/provider"
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
import { makeGlobalNode } from "@opencode-ai/core/effect/app-node"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Credential } from "@opencode-ai/core/credential"
import { ConfigMigrateV1 } from "@opencode-ai/core/v1/config/migrate"
import { ConfigV1 } from "@opencode-ai/core/v1/config/config"
import { FSUtil } from "@opencode-ai/core/fs-util"
@ -19,6 +21,8 @@ import { Location } from "@opencode-ai/core/location"
import { Project } from "@opencode-ai/core/project"
import { ProviderV2 } from "@opencode-ai/core/provider"
import { AbsolutePath } from "@opencode-ai/core/schema"
import { WellKnown } from "@opencode-ai/core/wellknown"
import { Integration } from "@opencode-ai/schema/integration"
import { location } from "../fixture/location"
import { tmpdir } from "../fixture/tmpdir"
import { testEffect } from "../lib/effect"
@ -26,12 +30,46 @@ import { testEffect } from "../lib/effect"
const it = testEffect(Layer.empty)
const selection = Schema.decodeUnknownSync(ConfigModel.Selection)
const emptyCredentialNode = makeGlobalNode({
service: Credential.Service,
layer: Layer.succeed(
Credential.Service,
Credential.Service.of({
all: () => Effect.succeed([]),
list: () => Effect.succeed([]),
get: () => Effect.succeed(undefined),
create: () => Effect.die("unused Credential.create"),
update: () => Effect.die("unused Credential.update"),
remove: () => Effect.die("unused Credential.remove"),
}),
),
deps: [],
})
const emptyWellknownNode = makeGlobalNode({
service: WellKnown.Service,
layer: Layer.succeed(
WellKnown.Service,
WellKnown.Service.of({
entries: () => Effect.succeed([]),
snapshot: () => [],
add: () => Effect.die("unused Wellknown.add"),
remove: () => Effect.die("unused Wellknown.remove"),
changes: Stream.empty,
resolve: () => Effect.die("unused Wellknown.resolve"),
}),
),
deps: [],
})
function testLayer(
directory: string,
globalDirectory = path.join(directory, "global"),
projectDirectory = directory,
vcs?: Project.Vcs,
watcher?: Layer.Layer<Watcher.Service>,
credentialNode = emptyCredentialNode,
wellknownNode = emptyWellknownNode,
) {
const locationLayer = Layer.succeed(
Location.Service,
@ -45,6 +83,8 @@ function testLayer(
return AppNodeBuilder.build(LayerNode.group([Config.node, EventV2.node]), [
[Location.node, locationLayer],
[Global.node, Global.layerWith({ config: globalDirectory, home: path.join(globalDirectory, "home") })],
[Credential.node, credentialNode],
[WellKnown.node, wellknownNode],
...(watcher ? ([[Watcher.node, watcher]] as const) : []),
])
}
@ -125,6 +165,86 @@ describe("Config", () => {
}),
)
it.live("loads authenticated wellknown config at highest priority", () =>
Effect.acquireUseRelease(
Effect.promise(() => tmpdir()),
(tmp) =>
Effect.gen(function* () {
const global = path.join(tmp.path, "global")
const project = path.join(tmp.path, "project")
yield* Effect.promise(async () => {
await fs.mkdir(global, { recursive: true })
await fs.mkdir(project, { recursive: true })
await fs.writeFile(path.join(global, "opencode.json"), JSON.stringify({ shell: "global" }))
await fs.writeFile(path.join(project, "opencode.json"), JSON.stringify({ shell: "project" }))
})
const integrationID = Integration.ID.make("https://example.com")
let key = "secret"
const credentialNode = makeGlobalNode({
service: Credential.Service,
layer: Layer.succeed(
Credential.Service,
Credential.Service.of({
all: () => Effect.die("unused Credential.all"),
list: () =>
Effect.succeed([
new Credential.Info({
id: Credential.ID.create(),
integrationID,
label: "default",
value: Credential.Key.make({ type: "key", key }),
}),
]),
get: () => Effect.die("unused Credential.get"),
create: () => Effect.die("unused Credential.create"),
update: () => Effect.die("unused Credential.update"),
remove: () => Effect.die("unused Credential.remove"),
}),
),
deps: [],
})
const entry: WellKnown.Entry = {
origin: "https://example.com",
integrationID,
manifest: { auth: { command: ["login"], env: "TOKEN" } },
}
const wellknownNode = makeGlobalNode({
service: WellKnown.Service,
layer: Layer.succeed(
WellKnown.Service,
WellKnown.Service.of({
entries: () => Effect.succeed([entry]),
snapshot: () => [entry],
add: () => Effect.die("unused Wellknown.add"),
remove: () => Effect.die("unused Wellknown.remove"),
changes: Stream.empty,
resolve: (_entry, variables) => Effect.succeed([{ shell: variables.TOKEN }]),
}),
),
deps: [],
})
return yield* Effect.gen(function* () {
const config = yield* Config.Service
const events = yield* EventV2.Service
expect(Config.latest(yield* config.entries(), "shell")).toBe("secret")
const updated = yield* events
.subscribe(ConfigSchema.Event.Updated)
.pipe(Stream.take(1), Stream.runCollect, Effect.forkScoped)
yield* Effect.yieldNow
key = "next"
yield* events.publish(Integration.Event.ConnectionUpdated, { integrationID })
expect(yield* Fiber.join(updated)).toHaveLength(1)
expect(Config.latest(yield* config.entries(), "shell")).toBe("next")
}).pipe(
Effect.provide(testLayer(project, global, project, undefined, undefined, credentialNode, wellknownNode)),
)
}),
(tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
),
)
it.effect("detects v1 configuration from any v1-only top-level key", () =>
Effect.sync(() => {
expect(ConfigMigrateV1.isV1({ snapshot: false })).toBe(true)
@ -282,9 +402,7 @@ describe("Config", () => {
const config = yield* Config.Service
yield* config.entries()
expect(targets).toEqual([
{ type: "directory", path: AbsolutePath.make(path.join(tmp.path, "global")) },
])
expect(targets).toEqual([{ type: "directory", path: AbsolutePath.make(path.join(tmp.path, "global")) }])
}).pipe(Effect.provide(testLayer(tmp.path, undefined, undefined, undefined, watcher)))
}),
),

View file

@ -181,7 +181,7 @@ describe("Integration", () => {
command: [
process.execPath,
"-e",
'console.log("https://example.com/login"); await Bun.sleep(50); console.log("secret")',
'console.error("https://example.com/login"); await Bun.sleep(50); console.log("secret")',
],
},
}),
@ -192,7 +192,7 @@ describe("Integration", () => {
integrations.command.status({ integrationID, attemptID: attempt.attemptID }),
(status) => status.status === "pending" && status.message?.includes("https://example.com/login") === true,
)
expect(pending).toMatchObject({ status: "pending", message: "https://example.com/login" })
expect(pending).toMatchObject({ status: "pending", message: "https://example.com/login\n" })
expect(
yield* eventually(

View file

@ -0,0 +1,25 @@
import { describe, expect } from "bun:test"
import { Effect } from "effect"
import { KV } from "@opencode-ai/core/kv"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { testEffect } from "./lib/effect"
const it = testEffect(LayerNode.compile(KV.node))
describe("KV", () => {
it.effect("stores, replaces, and removes JSON values", () =>
Effect.gen(function* () {
const kv = yield* KV.Service
expect(yield* kv.get("wellknown:sources")).toBeUndefined()
yield* kv.set("wellknown:sources", ["https://example.com"])
expect(yield* kv.get("wellknown:sources")).toEqual(["https://example.com"])
yield* kv.set("wellknown:sources", ["https://example.com", "https://example.org"])
expect(yield* kv.get("wellknown:sources")).toEqual(["https://example.com", "https://example.org"])
yield* kv.remove("wellknown:sources")
expect(yield* kv.get("wellknown:sources")).toBeUndefined()
}),
)
})

View file

@ -0,0 +1,82 @@
import { expect } from "bun:test"
import { Effect, Fiber, Stream } from "effect"
import { FetchHttpClient } from "effect/unstable/http"
import { KV } from "@opencode-ai/core/kv"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { WellKnown } from "@opencode-ai/core/wellknown"
import { testEffect } from "./lib/effect"
const it = testEffect(FetchHttpClient.layer)
const serviceIt = testEffect(LayerNode.compile(LayerNode.group([WellKnown.node, KV.node])))
it.live("loads embedded and remote configuration", () =>
Effect.acquireUseRelease(
Effect.sync(() =>
Bun.serve({
port: 0,
fetch(request) {
const url = new URL(request.url)
if (url.pathname === "/.well-known/opencode") {
return Response.json({
auth: { command: ["login"], env: "TOKEN" },
config: { model: "embedded/model" },
remote_config: {
url: `${url.origin}/config/{env:TOKEN}`,
headers: { authorization: "Bearer {env:TOKEN}" },
},
})
}
if (url.pathname === "/config/secret" && request.headers.get("authorization") === "Bearer secret") {
return Response.json({ config: { model: "remote/model" } })
}
return new Response("Not found", { status: 404 })
},
}),
),
(server) =>
Effect.gen(function* () {
const origin = server.url.origin
expect(yield* WellKnown.inspect(`${origin}/`)).toEqual({
auth: { command: ["login"], env: "TOKEN" },
config: { model: "embedded/model" },
remote_config: {
url: `${origin}/config/{env:TOKEN}`,
headers: { authorization: "Bearer {env:TOKEN}" },
},
})
expect(yield* WellKnown.resolve({ origin, variables: { TOKEN: "secret" } })).toEqual([
{ model: "embedded/model" },
{ model: "remote/model" },
])
}),
(server) => Effect.promise(() => server.stop(true)),
),
)
serviceIt.live("persists sources in one KV value", () =>
Effect.acquireUseRelease(
Effect.sync(() =>
Bun.serve({
port: 0,
fetch: () => Response.json({ auth: { command: ["login"], env: "TOKEN" } }),
}),
),
(server) =>
Effect.gen(function* () {
const wellknown = yield* WellKnown.Service
const kv = yield* KV.Service
const changed = yield* wellknown.changes.pipe(Stream.take(1), Stream.runCollect, Effect.forkScoped)
const entry = yield* wellknown.add(`${server.url.origin}/`)
expect(entry.origin).toBe(server.url.origin)
expect(yield* kv.get("wellknown:sources")).toEqual([server.url.origin])
expect(yield* wellknown.entries()).toEqual([entry])
expect(yield* Fiber.join(changed)).toHaveLength(1)
yield* wellknown.remove(server.url.origin)
expect(yield* kv.get("wellknown:sources")).toEqual([])
expect(yield* wellknown.entries()).toEqual([])
}),
(server) => Effect.promise(() => server.stop(true)),
),
)