chore: merge dev into v2 (#34788)

Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com>
Co-authored-by: Kit Langton <kit.langton@gmail.com>
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: Affan Ali <93028901+affanali2k3@users.noreply.github.com>
Co-authored-by: affanali2k3 <affanalikhanxx@gmail.com>
Co-authored-by: Frank <frank@anoma.ly>
Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: 𝓛𝓲𝓽𝓽𝓵𝓮 𝓕𝓻𝓪𝓷𝓴 <little-frank@opencord.local>
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: Jay V <air@live.ca>
Co-authored-by: Dax Raad <d@ironbay.co>
Co-authored-by: Aarav Sareen <96787824+arvsrn@users.noreply.github.com>
Co-authored-by: OpeOginni <107570612+OpeOginni@users.noreply.github.com>
Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
Co-authored-by: Ben Guthrie <benjee.012@gmail.com>
Co-authored-by: Dax <mail@thdxr.com>
Co-authored-by: Filip <34747899+neriousy@users.noreply.github.com>
Co-authored-by: Max Anderson <max.a.anderson95@gmail.com>
Co-authored-by: Brendan Allan <git@brendonovich.dev>
Co-authored-by: Jack <jack@anoma.ly>
Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com>
Co-authored-by: Dustin Deus <deusdustin@gmail.com>
Co-authored-by: starptech <starptech@starptechs-MBP.fritz.box>
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
Co-authored-by: usrnk1 <7547651+usrnk1@users.noreply.github.com>
Co-authored-by: Jay <53023+jayair@users.noreply.github.com>
Co-authored-by: runvip <164729189+runvip@users.noreply.github.com>
Co-authored-by: opencode <opencode@sst.dev>
Co-authored-by: Julian Coy <julian@ex-machina.co>
Co-authored-by: Vladimir Glafirov <vglafirov@gitlab.com>
This commit is contained in:
James Long
2026-07-01 17:12:00 -04:00
committed by GitHub
co-authored by Brendan Allan Kit Langton opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com> Affan Ali affanali2k3 Frank opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com> 𝓛𝓲𝓽𝓽𝓵𝓮 𝓕𝓻𝓪𝓷𝓴 Aiden Cline Jay V Dax Raad Aarav Sareen OpeOginni Luke Parker Ben Guthrie Dax Filip Max Anderson Brendan Allan Jack Shoubhit Dash Dustin Deus starptech Aiden Cline usrnk1 Jay runvip opencode Julian Coy Vladimir Glafirov
parent 932a40cfd9
commit 8c94e9005f
590 changed files with 15772 additions and 5530 deletions
+8 -8
View File
@@ -1,8 +1,8 @@
import { expect, test } from "bun:test"
import { setTimeout as sleep } from "node:timers/promises"
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
import { Effect, Layer } from "effect"
import { FSUtil } from "@opencode-ai/core/fs-util"
import { EffectFlock } from "@opencode-ai/core/util/effect-flock"
import { McpAuth } from "../../src/mcp/auth"
function authFile() {
@@ -10,7 +10,7 @@ function authFile() {
let activeWrites = 0
let sawOverlap = false
const layer = Layer.effect(
const fsLayer = Layer.effect(
FSUtil.Service,
Effect.gen(function* () {
const fs = yield* FSUtil.Service
@@ -41,14 +41,14 @@ function authFile() {
: fs.writeJson(file, value, mode),
})
}),
).pipe(Layer.provide(FSUtil.defaultLayer))
).pipe(Layer.provide(AppNodeBuilder.build(FSUtil.node)))
return { layer, raw: () => raw }
return { fsLayer, raw: () => raw }
}
function authService(layer: Layer.Layer<FSUtil.Service>) {
function authService(fsLayer: Layer.Layer<FSUtil.Service>) {
return McpAuth.Service.use((auth) => Effect.succeed(auth)).pipe(
Effect.provide(McpAuth.layer.pipe(Layer.provide(EffectFlock.defaultLayer), Layer.provide(layer))),
Effect.provide(AppNodeBuilder.build(McpAuth.node, [[FSUtil.node, fsLayer]])),
)
}
@@ -57,8 +57,8 @@ test("serializes concurrent auth file updates across service instances", async (
await Effect.runPromise(
Effect.gen(function* () {
const first = yield* authService(file.layer)
const second = yield* authService(file.layer)
const first = yield* authService(file.fsLayer)
const second = yield* authService(file.fsLayer)
yield* Effect.all(
[
@@ -0,0 +1,47 @@
import { describe, expect, test } from "bun:test"
import type { Client } from "@modelcontextprotocol/sdk/client/index.js"
import { McpCatalog } from "@/mcp/catalog"
const options = { toolCallId: "call_mcp", abortSignal: new AbortController().signal } as any
function clientReturning(result: unknown) {
return {
callTool: async () => result,
} as unknown as Client
}
function mcpTool() {
return {
name: "screenshot",
description: "Take a screenshot",
inputSchema: {
type: "object",
properties: {},
additionalProperties: false,
},
} as any
}
describe("McpCatalog.convertTool", () => {
test("preserves content when structuredContent is also present", async () => {
const content = [{ type: "image" as const, mimeType: "image/png", data: "AAAA" }]
const structuredContent = { image: { mimeType: "image/png", data: "AAAA" } }
const converted = McpCatalog.convertTool(mcpTool(), clientReturning({ content, structuredContent }))
const output = await converted.execute?.({}, options)
expect(output).toMatchObject({ content, structuredContent })
})
test("falls back to structuredContent only when content is absent", async () => {
const structuredContent = { results: [{ title: "one" }] }
const converted = McpCatalog.convertTool(mcpTool(), clientReturning({ content: [], structuredContent }))
const output = await converted.execute?.({}, options)
expect(output).toMatchObject({
structuredContent,
content: [{ type: "text", text: JSON.stringify(structuredContent) }],
})
})
})
+2 -1
View File
@@ -1,4 +1,5 @@
import { describe, expect, mock, beforeEach } from "bun:test"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Effect } from "effect"
import { testEffect } from "../lib/effect"
@@ -46,7 +47,7 @@ beforeEach(() => {
// Import MCP after mocking
const { MCP } = await import("../../src/mcp/index")
const it = testEffect(MCP.defaultLayer)
const it = testEffect(LayerNode.compile(MCP.node))
describe("mcp.headers", () => {
it.instance("headers are passed to transports when oauth is enabled (default)", () =>
+2 -1
View File
@@ -2,6 +2,7 @@ import path from "node:path"
import { pathToFileURL } from "node:url"
import { expect, mock, beforeEach } from "bun:test"
import { ListRootsRequestSchema, ToolListChangedNotificationSchema } from "@modelcontextprotocol/sdk/types.js"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Cause, Effect, Exit } from "effect"
import type { MCP as MCPNS } from "../../src/mcp/index"
import { testEffect } from "../lib/effect"
@@ -275,7 +276,7 @@ beforeEach(() => {
const { MCP } = await import("../../src/mcp/index")
const { McpOAuthCallback } = await import("../../src/mcp/oauth-callback")
const it = testEffect(MCP.defaultLayer)
const it = testEffect(LayerNode.compile(MCP.node))
function statusName(status: Record<string, MCPNS.Status> | MCPNS.Status, server: string) {
if ("status" in status) return status.status
@@ -1,4 +1,5 @@
import { expect, mock, beforeEach } from "bun:test"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Effect, Layer } from "effect"
import { testEffect } from "../lib/effect"
@@ -155,15 +156,8 @@ const { FSUtil } = await import("@opencode-ai/core/fs-util")
const { CrossSpawnSpawner } = await import("@opencode-ai/core/cross-spawn-spawner")
const mcpTest = testEffect(
Layer.mergeAll(
MCP.layer.pipe(
Layer.provide(McpAuth.defaultLayer),
Layer.provideMerge(EventV2Bridge.defaultLayer),
Layer.provide(Config.defaultLayer),
Layer.provide(CrossSpawnSpawner.defaultLayer),
Layer.provide(FSUtil.defaultLayer),
),
McpAuth.defaultLayer,
LayerNode.compile(
LayerNode.group([MCP.node, McpAuth.node, EventV2Bridge.node, Config.node, CrossSpawnSpawner.node, FSUtil.node]),
),
)
@@ -1,5 +1,6 @@
import { expect, mock, beforeEach } from "bun:test"
import { EventEmitter } from "events"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Deferred, Effect, Layer, Option } from "effect"
import { awaitWithTimeout, testEffect } from "../lib/effect"
import type { MCP as MCPNS } from "../../src/mcp/index"
@@ -122,12 +123,8 @@ const { McpOAuthCallback } = await import("../../src/mcp/oauth-callback")
const { FSUtil } = await import("@opencode-ai/core/fs-util")
const { CrossSpawnSpawner } = await import("@opencode-ai/core/cross-spawn-spawner")
const mcpTest = testEffect(
MCP.layer.pipe(
Layer.provide(McpAuth.defaultLayer),
Layer.provideMerge(EventV2Bridge.defaultLayer),
Layer.provide(Config.defaultLayer),
Layer.provide(CrossSpawnSpawner.defaultLayer),
Layer.provide(FSUtil.defaultLayer),
LayerNode.compile(
LayerNode.group([MCP.node, McpAuth.node, EventV2Bridge.node, Config.node, CrossSpawnSpawner.node, FSUtil.node]),
),
)
const service = MCP.Service as unknown as Effect.Effect<MCPNS.Interface, never, never>