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
commit 8c94e9005f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
590 changed files with 15772 additions and 5530 deletions

View file

@ -1,6 +1,7 @@
import { describe, expect } from "bun:test"
import path from "path"
import * as fs from "fs/promises"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Cause, Effect, Exit, Layer } from "effect"
import { ApplyPatchTool } from "../../src/tool/apply_patch"
import { LSP } from "@/lsp/lsp"
@ -14,13 +15,8 @@ import { SessionID, MessageID } from "../../src/session/schema"
import { testEffect } from "../lib/effect"
const it = testEffect(
Layer.mergeAll(
LSP.defaultLayer,
FSUtil.defaultLayer,
Format.defaultLayer,
EventV2Bridge.defaultLayer,
Truncate.defaultLayer,
Agent.defaultLayer,
LayerNode.compile(
LayerNode.group([LSP.node, FSUtil.node, Format.node, EventV2Bridge.node, Truncate.node, Agent.node]),
),
)

View file

@ -1,6 +1,7 @@
import { afterEach, describe, expect } from "bun:test"
import path from "path"
import fs from "fs/promises"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Cause, Deferred, Effect, Exit, Fiber, Layer } from "effect"
import { EditTool } from "../../src/tool/edit"
import { disposeAllInstances, TestInstance } from "../fixture/fixture"
@ -30,13 +31,8 @@ afterEach(async () => {
await disposeAllInstances()
})
const layer = Layer.mergeAll(
LSP.defaultLayer,
FSUtil.defaultLayer,
Format.defaultLayer,
EventV2Bridge.defaultLayer,
Truncate.defaultLayer,
Agent.defaultLayer,
const layer = LayerNode.compile(
LayerNode.group([LSP.node, FSUtil.node, Format.node, EventV2Bridge.node, Truncate.node, Agent.node]),
)
const it = testEffect(layer)

View file

@ -1,4 +1,5 @@
import { PermissionV1 } from "@opencode-ai/core/v1/permission"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { describe, expect } from "bun:test"
import path from "path"
import { Effect } from "effect"
@ -11,7 +12,7 @@ import type { Permission } from "../../src/permission"
import { SessionID, MessageID } from "../../src/session/schema"
import { testEffect } from "../lib/effect"
const it = testEffect(CrossSpawnSpawner.defaultLayer)
const it = testEffect(LayerNode.compile(CrossSpawnSpawner.node))
const baseCtx: Omit<Tool.Context, "ask"> = {
sessionID: SessionID.make("ses_test"),

View file

@ -1,6 +1,7 @@
import { PermissionV1 } from "@opencode-ai/core/v1/permission"
import { describe, expect } from "bun:test"
import path from "path"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Cause, Effect, Exit, Layer } from "effect"
import { GlobTool } from "../../src/tool/glob"
import { SessionID, MessageID } from "../../src/session/schema"
@ -20,13 +21,8 @@ import { Permission } from "../../src/permission"
import type * as Tool from "../../src/tool/tool"
const toolLayer = (flags: Partial<RuntimeFlags.Info> = {}) =>
Layer.mergeAll(
CrossSpawnSpawner.defaultLayer,
FSUtil.defaultLayer,
Ripgrep.defaultLayer,
Truncate.defaultLayer,
Agent.defaultLayer,
Git.defaultLayer,
LayerNode.compile(
LayerNode.group([CrossSpawnSpawner.node, FSUtil.node, Ripgrep.node, Truncate.node, Agent.node, Git.node]),
)
const it = testEffect(toolLayer())

View file

@ -3,6 +3,7 @@ import { describe, expect } from "bun:test"
import fs from "fs/promises"
import os from "os"
import path from "path"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Effect, Layer } from "effect"
import { GrepTool } from "../../src/tool/grep"
import { provideInstance, testInstanceStoreLayer, TestInstance, tmpdirScoped } from "../fixture/fixture"
@ -22,13 +23,8 @@ import { Git } from "@/git"
import { Filesystem } from "@/util/filesystem"
const toolLayer = (flags: Partial<RuntimeFlags.Info> = {}) =>
Layer.mergeAll(
CrossSpawnSpawner.defaultLayer,
FSUtil.defaultLayer,
Ripgrep.defaultLayer,
Truncate.defaultLayer,
Agent.defaultLayer,
Git.defaultLayer,
LayerNode.compile(
LayerNode.group([CrossSpawnSpawner.node, FSUtil.node, Ripgrep.node, Truncate.node, Agent.node, Git.node]),
)
const it = testEffect(toolLayer())

View file

@ -1,5 +1,6 @@
import { PermissionV1 } from "@opencode-ai/core/v1/permission"
import { afterEach, describe, expect } from "bun:test"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Effect, Layer } from "effect"
import path from "path"
import { Agent } from "../../src/agent/agent"
@ -56,7 +57,9 @@ const lsp = Layer.succeed(
)
const it = testEffect(
Layer.mergeAll(Agent.defaultLayer, FSUtil.defaultLayer, CrossSpawnSpawner.defaultLayer, Truncate.defaultLayer, lsp),
LayerNode.compile(LayerNode.group([Agent.node, FSUtil.node, CrossSpawnSpawner.node, Truncate.node, LSP.node]), [
[LSP.node, lsp],
]),
)
const init = Effect.fn("LspToolTest.init")(function* () {

View file

@ -1,10 +1,10 @@
import { describe, expect } from "bun:test"
import { Effect, Fiber, Layer, Queue } from "effect"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Effect, Fiber, Queue } from "effect"
import { QuestionTool } from "../../src/tool/question"
import { Question } from "../../src/question"
import { SessionID, MessageID } from "../../src/session/schema"
import { Agent } from "../../src/agent/agent"
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import { Truncate } from "@/tool/truncate"
import { testEffect } from "../lib/effect"
import { EventV2Bridge } from "../../src/event-v2-bridge"
@ -21,12 +21,7 @@ const ctx = {
}
const it = testEffect(
Layer.mergeAll(
Question.layer.pipe(Layer.provideMerge(EventV2Bridge.defaultLayer)),
CrossSpawnSpawner.defaultLayer,
Truncate.defaultLayer,
Agent.defaultLayer,
),
LayerNode.compile(LayerNode.group([Question.node, EventV2Bridge.node, Truncate.node, Agent.node])),
)
const pending = Effect.fn("QuestionToolTest.pending")(function* (question: Question.Interface) {

View file

@ -1,5 +1,6 @@
import { PermissionV1 } from "@opencode-ai/core/v1/permission"
import { afterEach, describe, expect } from "bun:test"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Cause, Effect, Exit, Layer, Stream } from "effect"
import path from "path"
import { Agent } from "../../src/agent/agent"
@ -44,14 +45,16 @@ const ctx = {
}
const readLayer = (flags: Partial<RuntimeFlags.Info> = {}) =>
Layer.mergeAll(
Agent.defaultLayer,
FSUtil.defaultLayer,
CrossSpawnSpawner.defaultLayer,
Instruction.defaultLayer,
LSP.defaultLayer,
Ripgrep.defaultLayer,
Truncate.defaultLayer,
LayerNode.compile(
LayerNode.group([
Agent.node,
FSUtil.node,
CrossSpawnSpawner.node,
Instruction.node,
LSP.node,
Ripgrep.node,
Truncate.node,
]),
)
const it = testEffect(Layer.mergeAll(readLayer(), testInstanceStoreLayer))

View file

@ -50,22 +50,12 @@ const brokenPluginLayer = Layer.succeed(
const root = LayerNode.group([ToolRegistry.node, Agent.node])
const replacements = [
LayerNode.replace(Config.layer, configLayer),
LayerNode.replace(RuntimeFlags.defaultLayer, RuntimeFlags.layer()),
]
[Config.node, configLayer],
[RuntimeFlags.node, RuntimeFlags.layer()],
] as const
const it = testEffect(LayerNode.compile(root, new Map(replacements.map((item) => [item.source, item.replacement]))))
const withBrokenPlugin = testEffect(
LayerNode.compile(
root,
new Map(
[...replacements, LayerNode.replace(Plugin.layer, brokenPluginLayer)].map((item) => [
item.source,
item.replacement,
]),
),
),
)
const it = testEffect(LayerNode.compile(root, replacements))
const withBrokenPlugin = testEffect(LayerNode.compile(root, [...replacements, [Plugin.node, brokenPluginLayer]]))
afterEach(async () => {
await disposeAllInstances()

View file

@ -1,5 +1,6 @@
import { PermissionV1 } from "@opencode-ai/core/v1/permission"
import { describe, expect } from "bun:test"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Cause, Effect, Exit, Layer } from "effect"
import type * as Scope from "effect/Scope"
import os from "os"
@ -22,13 +23,17 @@ import { RuntimeFlags } from "@/effect/runtime-flags"
import { InstanceStore } from "@/project/instance-store"
const shellLayer = Layer.mergeAll(
CrossSpawnSpawner.defaultLayer,
FSUtil.defaultLayer,
Plugin.defaultLayer,
Truncate.defaultLayer,
Config.defaultLayer,
Agent.defaultLayer,
RuntimeFlags.defaultLayer,
LayerNode.compile(
LayerNode.group([
CrossSpawnSpawner.node,
FSUtil.node,
Plugin.node,
Truncate.node,
Config.node,
Agent.node,
RuntimeFlags.node,
]),
),
testInstanceStoreLayer,
)
const it = testEffect(shellLayer)

View file

@ -1,5 +1,6 @@
import { PermissionV1 } from "@opencode-ai/core/v1/permission"
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Ripgrep } from "@opencode-ai/core/ripgrep"
import { Cause, Effect, Exit, Layer } from "effect"
import { afterEach, describe, expect } from "bun:test"
@ -26,9 +27,7 @@ afterEach(async () => {
await disposeAllInstances()
})
const node = CrossSpawnSpawner.defaultLayer
const it = testEffect(Layer.mergeAll(ToolRegistry.defaultLayer, node).pipe(Layer.provide(Ripgrep.defaultLayer)))
const it = testEffect(LayerNode.compile(LayerNode.group([ToolRegistry.node, CrossSpawnSpawner.node, Ripgrep.node])))
describe("tool.skill", () => {
it.instance("execute returns skill content block with files", () =>

View file

@ -1,6 +1,8 @@
import { afterEach, describe, expect } from "bun:test"
import { SessionV1 } from "@opencode-ai/core/v1/session"
import { Database } from "@opencode-ai/core/database/database"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { SessionProjector } from "@opencode-ai/core/session/projector"
import { Deferred, Effect, Exit, Fiber, Layer } from "effect"
import { Agent } from "../../src/agent/agent"
import { Job } from "@/job"
@ -33,20 +35,25 @@ const ref = {
}
const layer = (flags: Partial<RuntimeFlags.Info> = {}) =>
Layer.mergeAll(
Agent.defaultLayer,
Job.defaultLayer,
EventV2Bridge.defaultLayer,
Config.defaultLayer,
CrossSpawnSpawner.defaultLayer,
Session.defaultLayer,
SessionRunState.defaultLayer,
SessionStatus.defaultLayer,
Truncate.defaultLayer,
ToolRegistry.defaultLayer,
Database.defaultLayer,
RuntimeFlags.layer(flags),
).pipe(Layer.provide(Ripgrep.defaultLayer))
LayerNode.compile(
LayerNode.group([
Agent.node,
Job.node,
EventV2Bridge.node,
Config.node,
CrossSpawnSpawner.node,
Session.node,
SessionProjector.node,
SessionRunState.node,
SessionStatus.node,
Truncate.node,
ToolRegistry.node,
Database.node,
RuntimeFlags.node,
Ripgrep.node,
]),
[[RuntimeFlags.node, RuntimeFlags.layer(flags)]],
)
const it = testEffect(layer())
const background = testEffect(layer({ experimentalBackgroundSubagents: true }))

View file

@ -1,12 +1,13 @@
import { describe, expect } from "bun:test"
import { Cause, Effect, Exit, Layer, Schema } from "effect"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Cause, Effect, Exit, Schema } from "effect"
import { Agent } from "../../src/agent/agent"
import { MessageID, SessionID } from "../../src/session/schema"
import { Tool } from "@/tool/tool"
import { Truncate } from "@/tool/truncate"
import { testEffect } from "../lib/effect"
const it = testEffect(Layer.mergeAll(Truncate.defaultLayer, Agent.defaultLayer))
const it = testEffect(LayerNode.compile(LayerNode.group([Truncate.node, Agent.node])))
const params = Schema.Struct({ input: Schema.String })

View file

@ -1,8 +1,9 @@
import { describe, test, expect } from "bun:test"
import { ConfigV1 } from "@opencode-ai/core/v1/config/config"
import { NodeFileSystem } from "@effect/platform-node"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { filesystem } from "@opencode-ai/core/effect/app-node-platform"
import { FSUtil } from "@opencode-ai/core/fs-util"
import { Effect, FileSystem, Layer } from "effect"
import { Effect, FileSystem } from "effect"
import { Truncate } from "@/tool/truncate"
import { Config } from "@/config/config"
import { Identifier } from "../../src/id/id"
@ -15,15 +16,12 @@ import { TestConfig } from "../fixture/config"
const FIXTURES_DIR = path.join(import.meta.dir, "fixtures")
const ROOT = path.resolve(import.meta.dir, "..", "..")
const it = testEffect(Layer.mergeAll(Truncate.defaultLayer, NodeFileSystem.layer, FSUtil.defaultLayer))
const it = testEffect(LayerNode.compile(LayerNode.group([Truncate.node, FSUtil.node, filesystem])))
const configuredLayer = (cfg: ConfigV1.Info) =>
Layer.mergeAll(
Truncate.defaultLayer,
NodeFileSystem.layer,
FSUtil.defaultLayer,
TestConfig.layer({ get: () => Effect.succeed(cfg) }),
)
LayerNode.compile(LayerNode.group([Truncate.node, FSUtil.node, filesystem, Config.node]), [
[Config.node, TestConfig.layer({ get: () => Effect.succeed(cfg) })],
])
const configuredIt = (cfg: ConfigV1.Info) => testEffect(configuredLayer(cfg))
describe("Truncate", () => {

View file

@ -1,6 +1,8 @@
import { describe, expect } from "bun:test"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { httpClient } from "@opencode-ai/core/effect/app-node-platform"
import { Effect, Layer } from "effect"
import { FetchHttpClient } from "effect/unstable/http"
import { FetchHttpClient, HttpClient } from "effect/unstable/http"
import { Agent } from "../../src/agent/agent"
import { Truncate } from "@/tool/truncate"
import { WebFetchTool } from "../../src/tool/webfetch"
@ -8,7 +10,11 @@ import { SessionID, MessageID } from "../../src/session/schema"
import { Tool } from "@/tool/tool"
import { testEffect } from "../lib/effect"
const it = testEffect(Layer.mergeAll(FetchHttpClient.layer, Truncate.defaultLayer, Agent.defaultLayer))
const it = testEffect(
LayerNode.compile(LayerNode.group([httpClient, Truncate.node, Agent.node]), [
[httpClient, FetchHttpClient.layer as Layer.Layer<HttpClient.HttpClient>],
]),
)
const ctx = {
sessionID: SessionID.make("ses_test"),

View file

@ -1,4 +1,5 @@
import { afterEach, describe, expect } from "bun:test"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { Effect, Layer } from "effect"
import path from "path"
import fs from "fs/promises"
@ -31,14 +32,16 @@ afterEach(async () => {
})
const it = testEffect(
Layer.mergeAll(
LSP.defaultLayer,
FSUtil.defaultLayer,
EventV2Bridge.defaultLayer,
Format.defaultLayer,
CrossSpawnSpawner.defaultLayer,
Truncate.defaultLayer,
Agent.defaultLayer,
LayerNode.compile(
LayerNode.group([
LSP.node,
FSUtil.node,
EventV2Bridge.node,
Format.node,
CrossSpawnSpawner.node,
Truncate.node,
Agent.node,
]),
),
)