feat(core): add opencode integration (#33555)

This commit is contained in:
Dax
2026-06-23 19:45:02 -04:00
committed by GitHub
parent c17b9557f1
commit cf80b5c470
26 changed files with 1065 additions and 443 deletions
+3 -45
View File
@@ -13,12 +13,11 @@ import { Env } from "../env"
import { applyEdits, modify } from "jsonc-parser"
import { InstallationLocal, InstallationVersion } from "@opencode-ai/core/installation/version"
import { existsSync } from "fs"
import { Account } from "@/account/account"
import { isRecord } from "@/util/record"
import type { ConsoleState } from "@opencode-ai/core/v1/config/console-state"
import { FSUtil } from "@opencode-ai/core/fs-util"
import { InstanceState } from "@/effect/instance-state"
import { Context, Duration, Effect, Exit, Fiber, Layer, Option, Schema } from "effect"
import { Context, Duration, Effect, Exit, Fiber, Layer, Schema } from "effect"
import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/unstable/http"
import { EffectFlock } from "@opencode-ai/core/util/effect-flock"
import { containsPath, type InstanceContext } from "../project/instance-context"
@@ -177,7 +176,6 @@ export const layer = Layer.effect(
Effect.gen(function* () {
const fs = yield* FSUtil.Service
const authSvc = yield* Auth.Service
const accountSvc = yield* Account.Service
const env = yield* Env.Service
const npmSvc = yield* Npm.Service
const http = yield* HttpClient.HttpClient
@@ -316,7 +314,6 @@ export const layer = Layer.effect(
let result: Info = {}
const authEnv: Record<string, string> = {}
const consoleManagedProviders = new Set<string>()
let activeOrgName: string | undefined
const pluginScopeForSource = Effect.fnUntraced(function* (source: string) {
@@ -474,44 +471,6 @@ export const layer = Layer.effect(
yield* Effect.logDebug("loaded custom config from OPENCODE_CONFIG_CONTENT")
}
const activeAccount = Option.getOrUndefined(
yield* accountSvc.active().pipe(Effect.catch(() => Effect.succeed(Option.none()))),
)
if (activeAccount?.active_org_id) {
const accountID = activeAccount.id
const orgID = activeAccount.active_org_id
const url = activeAccount.url
yield* Effect.gen(function* () {
const [configOpt, tokenOpt] = yield* Effect.all(
[accountSvc.config(accountID, orgID), accountSvc.token(accountID)],
{ concurrency: 2 },
)
if (Option.isSome(tokenOpt)) {
process.env["OPENCODE_CONSOLE_TOKEN"] = tokenOpt.value
yield* env.set("OPENCODE_CONSOLE_TOKEN", tokenOpt.value)
}
if (Option.isSome(configOpt)) {
const source = `${url}/api/config`
const next = yield* loadConfig(JSON.stringify(configOpt.value), {
dir: path.dirname(source),
source,
})
for (const providerID of Object.keys(next.provider ?? {})) {
consoleManagedProviders.add(providerID)
}
yield* merge(source, next, "global")
}
}).pipe(
Effect.withSpan("Config.loadActiveOrgConfig"),
Effect.catch((err) =>
Effect.logDebug("failed to fetch remote account config", {
error: err instanceof Error ? err.message : String(err),
}),
),
)
}
const managedDir = ConfigManaged.managedConfigDir()
if (existsSync(managedDir)) {
for (const file of ["opencode.json", "opencode.jsonc"]) {
@@ -587,7 +546,7 @@ export const layer = Layer.effect(
directories,
deps,
consoleState: {
consoleManagedProviders: Array.from(consoleManagedProviders),
consoleManagedProviders: [],
activeOrgName,
switchableOrgCount: 0,
},
@@ -676,11 +635,10 @@ export const defaultLayer = layer.pipe(
Layer.provide(FSUtil.defaultLayer),
Layer.provide(Env.defaultLayer),
Layer.provide(Auth.defaultLayer),
Layer.provide(Account.defaultLayer),
Layer.provide(Npm.defaultLayer),
Layer.provide(FetchHttpClient.layer),
)
export const node = LayerNode.make(layer, [FSUtil.node, Auth.node, Account.node, Env.node, Npm.node, httpClient])
export const node = LayerNode.make(layer, [FSUtil.node, Auth.node, Env.node, Npm.node, httpClient])
export * as Config from "./config"
@@ -1,6 +1,9 @@
import { Schema } from "effect"
import { HttpApi } from "effect/unstable/httpapi"
import { EventV2 } from "@opencode-ai/core/event"
import { Credential } from "@opencode-ai/core/credential"
import { Integration } from "@opencode-ai/core/integration"
import { SkillV2 } from "@opencode-ai/core/skill"
import { InstanceDisposed } from "@/server/event"
import { Question } from "@/question"
import { ConfigApi } from "./groups/config"
@@ -72,7 +75,16 @@ export const OpenCodeHttpApi = HttpApi.make("opencode")
.addHttpApi(InstanceHttpApi)
.addHttpApi(Api)
.addHttpApi(PtyConnectApi)
.annotate(HttpApi.AdditionalSchemas, [EventSchema, Question.Replied, Question.Rejected])
.annotate(HttpApi.AdditionalSchemas, [
EventSchema,
Question.Replied,
Question.Rejected,
Credential.Value,
Integration.Inputs,
Integration.Method,
Integration.Ref,
SkillV2.Source,
])
export type RootHttpApiType = typeof RootHttpApi
export type InstanceHttpApiType = typeof InstanceHttpApi