refactor(core): rename app node modules (#34238)
This commit is contained in:
@@ -16,8 +16,8 @@
|
|||||||
"opencode": "./bin/opencode"
|
"opencode": "./bin/opencode"
|
||||||
},
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
"./effect/layer-node": "./src/effect/layer-node/index.ts",
|
"./effect/layer-node": "./src/effect/layer-node.ts",
|
||||||
"./effect/node": "./src/effect/node.ts",
|
"./effect/app-node": "./src/effect/app-node.ts",
|
||||||
"./session/runner": "./src/session/runner/index.ts",
|
"./session/runner": "./src/session/runner/index.ts",
|
||||||
"./system-context": "./src/system-context/index.ts",
|
"./system-context": "./src/system-context/index.ts",
|
||||||
"./*": "./src/*.ts"
|
"./*": "./src/*.ts"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as AgentV2 from "./agent"
|
export * as AgentV2 from "./agent"
|
||||||
|
|
||||||
import { makeLocationNode } from "./effect/node"
|
import { makeLocationNode } from "./effect/app-node"
|
||||||
import { Array, Context, Effect, Layer, Types } from "effect"
|
import { Array, Context, Effect, Layer, Types } from "effect"
|
||||||
import { Agent } from "@opencode-ai/schema/agent"
|
import { Agent } from "@opencode-ai/schema/agent"
|
||||||
import { State } from "./state"
|
import { State } from "./state"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as AISDK from "./aisdk"
|
export * as AISDK from "./aisdk"
|
||||||
|
|
||||||
import { makeLocationNode } from "./effect/node"
|
import { makeLocationNode } from "./effect/app-node"
|
||||||
import type { LanguageModelV3 } from "@ai-sdk/provider"
|
import type { LanguageModelV3 } from "@ai-sdk/provider"
|
||||||
import { Cause, Context, Effect, Layer, Schema, Scope } from "effect"
|
import { Cause, Context, Effect, Layer, Schema, Scope } from "effect"
|
||||||
import { ModelV2 } from "./model"
|
import { ModelV2 } from "./model"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ export * as BackgroundJob from "./background-job"
|
|||||||
|
|
||||||
import { Cause, Clock, Context, Deferred, Effect, Exit, Layer, Scope, SynchronizedRef } from "effect"
|
import { Cause, Clock, Context, Deferred, Effect, Exit, Layer, Scope, SynchronizedRef } from "effect"
|
||||||
import { Identifier } from "./id/id"
|
import { Identifier } from "./id/id"
|
||||||
import { makeGlobalNode } from "./effect/node"
|
import { makeGlobalNode } from "./effect/app-node"
|
||||||
|
|
||||||
export type Status = "running" | "completed" | "error" | "cancelled"
|
export type Status = "running" | "completed" | "error" | "cancelled"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as Catalog from "./catalog"
|
export * as Catalog from "./catalog"
|
||||||
|
|
||||||
import { makeLocationNode } from "./effect/node"
|
import { makeLocationNode } from "./effect/app-node"
|
||||||
import { Array, Context, Effect, Layer, Option, Order, pipe, Schema } from "effect"
|
import { Array, Context, Effect, Layer, Option, Order, pipe, Schema } from "effect"
|
||||||
import { Catalog } from "@opencode-ai/schema/catalog"
|
import { Catalog } from "@opencode-ai/schema/catalog"
|
||||||
import { ModelV2 } from "./model"
|
import { ModelV2 } from "./model"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as CommandV2 from "./command"
|
export * as CommandV2 from "./command"
|
||||||
|
|
||||||
import { makeLocationNode } from "./effect/node"
|
import { makeLocationNode } from "./effect/app-node"
|
||||||
import { Context, Effect, Layer, Types } from "effect"
|
import { Context, Effect, Layer, Types } from "effect"
|
||||||
import { Command } from "@opencode-ai/schema/command"
|
import { Command } from "@opencode-ai/schema/command"
|
||||||
import { State } from "./state"
|
import { State } from "./state"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as Config from "./config"
|
export * as Config from "./config"
|
||||||
|
|
||||||
import { makeLocationNode } from "./effect/node"
|
import { makeLocationNode } from "./effect/app-node"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { type ParseError, parse } from "jsonc-parser"
|
import { type ParseError, parse } from "jsonc-parser"
|
||||||
import { Context, Effect, Layer, Option, Schema } from "effect"
|
import { Context, Effect, Layer, Option, Schema } from "effect"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Context, Effect, Layer, Schema } from "effect"
|
|||||||
import { Credential } from "@opencode-ai/schema/credential"
|
import { Credential } from "@opencode-ai/schema/credential"
|
||||||
import { Integration } from "@opencode-ai/schema/integration"
|
import { Integration } from "@opencode-ai/schema/integration"
|
||||||
import { Database } from "./database/database"
|
import { Database } from "./database/database"
|
||||||
import { makeGlobalNode } from "./effect/node"
|
import { makeGlobalNode } from "./effect/app-node"
|
||||||
import { CredentialTable } from "./credential/sql"
|
import { CredentialTable } from "./credential/sql"
|
||||||
|
|
||||||
export const ID = Credential.ID
|
export const ID = Credential.ID
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ import {
|
|||||||
import * as NodeChildProcess from "node:child_process"
|
import * as NodeChildProcess from "node:child_process"
|
||||||
import { PassThrough } from "node:stream"
|
import { PassThrough } from "node:stream"
|
||||||
import launch from "cross-spawn"
|
import launch from "cross-spawn"
|
||||||
import { makeGlobalNode } from "./effect/node"
|
import { makeGlobalNode } from "./effect/app-node"
|
||||||
import { filesystem, path } from "./effect/layer-node-platform"
|
import { filesystem, path } from "./effect/app-node-platform"
|
||||||
|
|
||||||
const toError = (err: unknown): Error => (err instanceof globalThis.Error ? err : new globalThis.Error(String(err)))
|
const toError = (err: unknown): Error => (err instanceof globalThis.Error ? err : new globalThis.Error(String(err)))
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { Flag } from "../flag/flag"
|
|||||||
import { isAbsolute, join } from "path"
|
import { isAbsolute, join } from "path"
|
||||||
import { DatabaseMigration } from "./migration"
|
import { DatabaseMigration } from "./migration"
|
||||||
import { InstallationChannel } from "../installation/version"
|
import { InstallationChannel } from "../installation/version"
|
||||||
import { makeGlobalNode } from "../effect/node"
|
import { makeGlobalNode } from "../effect/app-node"
|
||||||
|
|
||||||
const makeDatabase = EffectDrizzleSqlite.makeWithDefaults()
|
const makeDatabase = EffectDrizzleSqlite.makeWithDefaults()
|
||||||
type DatabaseShape = Effect.Success<typeof makeDatabase>
|
type DatabaseShape = Effect.Success<typeof makeDatabase>
|
||||||
|
|||||||
+7
-7
@@ -1,24 +1,24 @@
|
|||||||
import { Layer } from "effect"
|
import { Layer } from "effect"
|
||||||
import { buildLocationServiceMap } from "../location-services"
|
import { buildLocationServiceMap } from "../location-services"
|
||||||
import { LocationServiceMap } from "../location-service-map"
|
import { LocationServiceMap } from "../location-service-map"
|
||||||
import { LayerNode, LayerNodeTree } from "./layer-node"
|
import { LayerNode } from "./layer-node"
|
||||||
import { makeGlobalNode } from "./node"
|
import { makeGlobalNode } from "./app-node"
|
||||||
|
|
||||||
export function build<A, E>(root: LayerNode.Node<A, E, any>, replacements?: readonly LayerNode.Replacement[]) {
|
export function build<A, E>(root: LayerNode.Node<A, E, any>, replacements?: readonly LayerNode.Replacement[]) {
|
||||||
const replacementMap = new Map(replacements?.map((item) => [item.source, item.replacement]))
|
const replacementMap = new Map(replacements?.map((item) => [item.source, item.replacement]))
|
||||||
|
|
||||||
if (!LayerNodeTree.hasUnbound(root, LocationServiceMap.node)) {
|
if (!LayerNode.hasUnbound(root, LocationServiceMap.node)) {
|
||||||
// If the location service map is not needed, we shouldn't pull it
|
// If the location service map is not needed, we shouldn't pull it
|
||||||
// in. Compile the graph normally
|
// in. Compile the graph normally
|
||||||
return LayerNodeTree.compile(root, replacementMap)
|
return LayerNode.compile(root, replacementMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
const locationMap = buildLocationServiceMap(replacementMap)
|
const locationMap = buildLocationServiceMap(replacementMap)
|
||||||
const locationMapNode = makeGlobalNode({ service: LocationServiceMap.Service, layer: locationMap, deps: [] })
|
const locationMapNode = makeGlobalNode({ service: LocationServiceMap.Service, layer: locationMap, deps: [] })
|
||||||
|
|
||||||
const app = LayerNodeTree.bind(root, LocationServiceMap.node, locationMapNode)
|
const app = LayerNode.bind(root, LocationServiceMap.node, locationMapNode)
|
||||||
|
|
||||||
return LayerNodeTree.compile(app, replacementMap)
|
return LayerNode.compile(app, replacementMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
export * as NodeBuild from "./node-build"
|
export * as NodeBuild from "./app-node-builder"
|
||||||
+2
-2
@@ -3,7 +3,7 @@ import { LLMClient, RequestExecutor } from "@opencode-ai/llm/route"
|
|||||||
import { FileSystem, Path } from "effect"
|
import { FileSystem, Path } from "effect"
|
||||||
import { FetchHttpClient } from "effect/unstable/http"
|
import { FetchHttpClient } from "effect/unstable/http"
|
||||||
import { HttpClient } from "effect/unstable/http"
|
import { HttpClient } from "effect/unstable/http"
|
||||||
import { makeGlobalNode } from "./node"
|
import { makeGlobalNode } from "./app-node"
|
||||||
|
|
||||||
export const filesystem = makeGlobalNode({ service: FileSystem.FileSystem, layer: NodeFileSystem.layer, deps: [] })
|
export const filesystem = makeGlobalNode({ service: FileSystem.FileSystem, layer: NodeFileSystem.layer, deps: [] })
|
||||||
export const path = makeGlobalNode({ service: Path.Path, layer: NodePath.layer, deps: [] })
|
export const path = makeGlobalNode({ service: Path.Path, layer: NodePath.layer, deps: [] })
|
||||||
@@ -15,4 +15,4 @@ export const requestExecutor = makeGlobalNode({
|
|||||||
})
|
})
|
||||||
export const llmClient = makeGlobalNode({ service: LLMClient.Service, layer: LLMClient.layer, deps: [requestExecutor] })
|
export const llmClient = makeGlobalNode({ service: LLMClient.Service, layer: LLMClient.layer, deps: [requestExecutor] })
|
||||||
|
|
||||||
export * as LayerNodePlatform from "./layer-node-platform"
|
export * as LayerNodePlatform from "./app-node-platform"
|
||||||
@@ -11,4 +11,4 @@ export type LocationNode<A, E = never> = LayerNode.Node<A, E, (typeof tags.value
|
|||||||
export const makeGlobalNode = tags.make("global")
|
export const makeGlobalNode = tags.make("global")
|
||||||
export const makeLocationNode = tags.make("location")
|
export const makeLocationNode = tags.make("location")
|
||||||
|
|
||||||
export * as Node from "./node"
|
export * as Node from "./app-node"
|
||||||
+177
-31
@@ -1,6 +1,7 @@
|
|||||||
import { Brand, Context, Layer } from "effect"
|
import { Brand, Context, Layer } from "effect"
|
||||||
|
|
||||||
type AnyNode = Node<unknown, unknown, any>
|
type AnyNode = Node<unknown, unknown, any>
|
||||||
|
type RuntimeLayer = Layer.Layer<never, unknown, unknown>
|
||||||
type NodeList<Item extends AnyNode = AnyNode> = readonly [] | readonly [Item, ...Item[]]
|
type NodeList<Item extends AnyNode = AnyNode> = readonly [] | readonly [Item, ...Item[]]
|
||||||
export type Output<Item> = [Item] extends [never] ? never : Item extends Node<infer A, unknown, any> ? A : never
|
export type Output<Item> = [Item] extends [never] ? never : Item extends Node<infer A, unknown, any> ? A : never
|
||||||
export type Error<Item> = [Item] extends [never] ? never : Item extends Node<unknown, infer E, any> ? E : never
|
export type Error<Item> = [Item] extends [never] ? never : Item extends Node<unknown, infer E, any> ? E : never
|
||||||
@@ -34,6 +35,39 @@ type NodeIdentity =
|
|||||||
| { readonly name: string; readonly service?: never }
|
| { readonly name: string; readonly service?: never }
|
||||||
type DistributiveOmit<A, K extends PropertyKey> = A extends unknown ? Omit<A, K> : never
|
type DistributiveOmit<A, K extends PropertyKey> = A extends unknown ? Omit<A, K> : never
|
||||||
|
|
||||||
|
export type TagConfig = Readonly<Record<string, readonly string[]>>
|
||||||
|
type TagNames<Config extends TagConfig> = keyof Config & string
|
||||||
|
type NodeInTags<Names extends string> = Node<unknown, unknown, Tag<Names> | undefined>
|
||||||
|
type CheckTags<Items extends NodeList, Names extends string> = [Exclude<Items[number], NodeInTags<Names>>] extends [
|
||||||
|
never,
|
||||||
|
]
|
||||||
|
? unknown
|
||||||
|
: { readonly "Invalid tag dependencies": Exclude<Items[number], NodeInTags<Names>> }
|
||||||
|
|
||||||
|
export interface Tags<Config extends TagConfig> {
|
||||||
|
readonly values: { readonly [Name in TagNames<Config>]: Tag<Name> }
|
||||||
|
readonly make: <Name extends TagNames<Config>>(
|
||||||
|
name: Name,
|
||||||
|
) => <const Implementation extends Layer.Any, const Items extends NodeList>(
|
||||||
|
input: DistributiveOmit<MakeInput<Implementation, Items, Tag<Name>>, "tag"> &
|
||||||
|
CheckTags<Items, Name | Extract<Config[Name][number], string>>,
|
||||||
|
) => Node<Layer.Success<Implementation>, Layer.Error<Implementation> | Error<Items[number]>, Tag<Name>>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function tags<const Config extends { readonly [Name in keyof Config]: readonly (keyof Config & string)[] }>(
|
||||||
|
config: Config,
|
||||||
|
): Tags<Config> {
|
||||||
|
const names = Object.keys(config) as TagNames<Config>[]
|
||||||
|
const values = Object.fromEntries(names.map((name) => [name, makeTag(name)])) as Tags<Config>["values"]
|
||||||
|
return {
|
||||||
|
values,
|
||||||
|
make: ((name: TagNames<Config>) => (input: DistributiveOmit<MakeInput<Layer.Any, NodeList, Tag>, "tag">) =>
|
||||||
|
make({ ...input, tag: values[name] })) as Tags<Config>["make"],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nodes ---------------------------------------------------------------------
|
||||||
|
|
||||||
type MakeInput<
|
type MakeInput<
|
||||||
Implementation extends Layer.Any,
|
Implementation extends Layer.Any,
|
||||||
Items extends NodeList,
|
Items extends NodeList,
|
||||||
@@ -77,37 +111,6 @@ export function group<const Items extends readonly AnyNode[]>(
|
|||||||
return { kind: "group", name: "group", dependencies }
|
return { kind: "group", name: "group", dependencies }
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TagConfig = Readonly<Record<string, readonly string[]>>
|
|
||||||
type TagNames<Config extends TagConfig> = keyof Config & string
|
|
||||||
type NodeInTags<Names extends string> = Node<unknown, unknown, Tag<Names> | undefined>
|
|
||||||
type CheckTags<Items extends NodeList, Names extends string> = [Exclude<Items[number], NodeInTags<Names>>] extends [
|
|
||||||
never,
|
|
||||||
]
|
|
||||||
? unknown
|
|
||||||
: { readonly "Invalid tag dependencies": Exclude<Items[number], NodeInTags<Names>> }
|
|
||||||
|
|
||||||
export interface Tags<Config extends TagConfig> {
|
|
||||||
readonly values: { readonly [Name in TagNames<Config>]: Tag<Name> }
|
|
||||||
readonly make: <Name extends TagNames<Config>>(
|
|
||||||
name: Name,
|
|
||||||
) => <const Implementation extends Layer.Any, const Items extends NodeList>(
|
|
||||||
input: DistributiveOmit<MakeInput<Implementation, Items, Tag<Name>>, "tag"> &
|
|
||||||
CheckTags<Items, Name | Extract<Config[Name][number], string>>,
|
|
||||||
) => Node<Layer.Success<Implementation>, Layer.Error<Implementation> | Error<Items[number]>, Tag<Name>>
|
|
||||||
}
|
|
||||||
|
|
||||||
export function tags<const Config extends { readonly [Name in keyof Config]: readonly (keyof Config & string)[] }>(
|
|
||||||
config: Config,
|
|
||||||
): Tags<Config> {
|
|
||||||
const names = Object.keys(config) as TagNames<Config>[]
|
|
||||||
const values = Object.fromEntries(names.map((name) => [name, makeTag(name)])) as Tags<Config>["values"]
|
|
||||||
return {
|
|
||||||
values,
|
|
||||||
make: ((name: TagNames<Config>) => (input: DistributiveOmit<MakeInput<Layer.Any, NodeList, Tag>, "tag">) =>
|
|
||||||
make({ ...input, tag: values[name] })) as Tags<Config>["make"],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type Replacement = {
|
export type Replacement = {
|
||||||
readonly source: Layer.Any
|
readonly source: Layer.Any
|
||||||
readonly replacement: Layer.Any
|
readonly replacement: Layer.Any
|
||||||
@@ -124,4 +127,147 @@ export function replace<A, E, R, E2>(
|
|||||||
return { source, replacement }
|
return { source, replacement }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tree -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
type Visit<Result> = (node: AnyNode, context: VisitContext<Result>) => Result
|
||||||
|
|
||||||
|
type VisitContext<Result> = {
|
||||||
|
readonly cache: Map<AnyNode, Result>
|
||||||
|
readonly visit: (node: AnyNode) => Result
|
||||||
|
}
|
||||||
|
|
||||||
|
function walk<Result>(
|
||||||
|
root: AnyNode,
|
||||||
|
visit: Visit<Result>,
|
||||||
|
options: {
|
||||||
|
readonly cache?: Map<AnyNode, Result>
|
||||||
|
readonly resolve?: (node: AnyNode) => AnyNode
|
||||||
|
readonly detectCycles?: boolean
|
||||||
|
} = {},
|
||||||
|
) {
|
||||||
|
const cache = options.cache ?? new Map<AnyNode, Result>()
|
||||||
|
const visiting = new Set<AnyNode>()
|
||||||
|
const stack: AnyNode[] = []
|
||||||
|
|
||||||
|
const recur = (node: AnyNode): Result => {
|
||||||
|
const target = options.resolve?.(node) ?? node
|
||||||
|
const cached = cache.get(target)
|
||||||
|
if (cached !== undefined || cache.has(target)) return cached!
|
||||||
|
|
||||||
|
if (options.detectCycles !== false && visiting.has(target)) {
|
||||||
|
const start = stack.indexOf(target)
|
||||||
|
throw new Error(
|
||||||
|
`Cycle detected in layer tree: ${[...stack.slice(start), target].map((item) => item.name).join(" -> ")}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
visiting.add(target)
|
||||||
|
stack.push(target)
|
||||||
|
try {
|
||||||
|
const result = visit(target, { cache, visit: recur })
|
||||||
|
if (!cache.has(target)) cache.set(target, result)
|
||||||
|
return result
|
||||||
|
} finally {
|
||||||
|
stack.pop()
|
||||||
|
visiting.delete(target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return recur(root)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hoist<A, E, T extends Tag>(
|
||||||
|
root: Node<A, E, any>,
|
||||||
|
tag: T,
|
||||||
|
): {
|
||||||
|
readonly node: Node<A, E>
|
||||||
|
readonly hoisted: Node<unknown, E>
|
||||||
|
} {
|
||||||
|
const hoisted = new Map<string, AnyNode>()
|
||||||
|
|
||||||
|
const node = walk<AnyNode>(root, (node, context) => {
|
||||||
|
if (node.kind === "group") {
|
||||||
|
return { ...node, dependencies: node.dependencies.map(context.visit) }
|
||||||
|
}
|
||||||
|
if (node.tag === tag) {
|
||||||
|
const existing = hoisted.get(node.name)
|
||||||
|
if (existing && existing !== node) {
|
||||||
|
throw new Error(`Tag ${tag} has conflicting implementations for ${node.name}`)
|
||||||
|
}
|
||||||
|
hoisted.set(node.name, node)
|
||||||
|
return group([])
|
||||||
|
}
|
||||||
|
if (node.kind === "unbound") {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
return { ...node, dependencies: node.dependencies.map(context.visit) }
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
node: node as Node<A, E>,
|
||||||
|
hoisted: group(Array.from(hoisted.values())) as Node<unknown, E>,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function compile<A, E>(
|
||||||
|
root: Node<A, E, any>,
|
||||||
|
replacements?: ReadonlyMap<Layer.Any, Layer.Any>,
|
||||||
|
): Layer.Layer<A, E> {
|
||||||
|
const cache = new Map<AnyNode, RuntimeLayer>()
|
||||||
|
const compileNode = (node: AnyNode) =>
|
||||||
|
walk<RuntimeLayer>(
|
||||||
|
node,
|
||||||
|
(node, context) => {
|
||||||
|
if (node.kind === "unbound") throw new Error(`Unbound layer node: ${node.name}`)
|
||||||
|
const dependencies = node.dependencies.flatMap(flatten).map(context.visit)
|
||||||
|
const implementation = (replacements?.get(node.implementation!) ?? node.implementation!) as RuntimeLayer
|
||||||
|
return dependencies.length === 0
|
||||||
|
? implementation
|
||||||
|
: implementation.pipe(Layer.provide(dependencies as [RuntimeLayer, ...RuntimeLayer[]]))
|
||||||
|
},
|
||||||
|
{ cache },
|
||||||
|
)
|
||||||
|
const layers = flatten(root).map((node) => compileNode(node))
|
||||||
|
const layer = layers.reduce<RuntimeLayer>((result, layer) => layer.pipe(Layer.provideMerge(result)), Layer.empty)
|
||||||
|
return layer as Layer.Layer<A, E>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hasUnbound(root: Node<unknown, unknown, any>, source: AnyNode): boolean {
|
||||||
|
if (source.kind !== "unbound") throw new Error(`Cannot check non-unbound layer node: ${source.name}`)
|
||||||
|
return walk<boolean>(root, (node, context) => {
|
||||||
|
if (node === source) return true
|
||||||
|
return node.dependencies.some(context.visit)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bind<A, E, T extends Tag | undefined>(
|
||||||
|
root: Node<A, E, T>,
|
||||||
|
source: AnyNode,
|
||||||
|
replacement: AnyNode,
|
||||||
|
): Node<A, E, T> {
|
||||||
|
if (source.kind !== "unbound") throw new Error(`Cannot bind non-unbound layer node: ${source.name}`)
|
||||||
|
if (source.name !== replacement.name) {
|
||||||
|
throw new Error(`Cannot bind ${source.name} to ${replacement.name}`)
|
||||||
|
}
|
||||||
|
if (source.tag !== replacement.tag) {
|
||||||
|
throw new Error(`Cannot bind ${source.name} across tags`)
|
||||||
|
}
|
||||||
|
return walk<AnyNode>(
|
||||||
|
root,
|
||||||
|
(target, context) => {
|
||||||
|
if (target.kind === "unbound") return target
|
||||||
|
const dependencies: AnyNode[] = []
|
||||||
|
const clone = { ...target, dependencies }
|
||||||
|
context.cache.set(target, clone)
|
||||||
|
dependencies.push(...target.dependencies.map(context.visit))
|
||||||
|
return clone
|
||||||
|
},
|
||||||
|
{ detectCycles: false, resolve: (node) => (node === source ? replacement : node) },
|
||||||
|
) as Node<A, E, T>
|
||||||
|
}
|
||||||
|
|
||||||
|
function flatten(node: AnyNode): readonly AnyNode[] {
|
||||||
|
return node.kind === "group" ? node.dependencies.flatMap(flatten) : [node]
|
||||||
|
}
|
||||||
|
|
||||||
export * as LayerNode from "./layer-node"
|
export * as LayerNode from "./layer-node"
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
export * from "./layer-node"
|
|
||||||
export * as LayerNodeTree from "./layer-node-tree"
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
import { Layer } from "effect"
|
|
||||||
import { LayerNode } from "./layer-node"
|
|
||||||
|
|
||||||
type AnyNode = LayerNode.Node<unknown, unknown, any>
|
|
||||||
type RuntimeLayer = Layer.Layer<never, unknown, unknown>
|
|
||||||
type Visit<Result> = (node: AnyNode, context: VisitContext<Result>) => Result
|
|
||||||
|
|
||||||
type VisitContext<Result> = {
|
|
||||||
readonly cache: Map<AnyNode, Result>
|
|
||||||
readonly visit: (node: AnyNode) => Result
|
|
||||||
}
|
|
||||||
|
|
||||||
function walk<Result>(
|
|
||||||
root: AnyNode,
|
|
||||||
visit: Visit<Result>,
|
|
||||||
options: {
|
|
||||||
readonly cache?: Map<AnyNode, Result>
|
|
||||||
readonly resolve?: (node: AnyNode) => AnyNode
|
|
||||||
readonly detectCycles?: boolean
|
|
||||||
} = {},
|
|
||||||
) {
|
|
||||||
const cache = options.cache ?? new Map<AnyNode, Result>()
|
|
||||||
const visiting = new Set<AnyNode>()
|
|
||||||
const stack: AnyNode[] = []
|
|
||||||
|
|
||||||
const recur = (node: AnyNode): Result => {
|
|
||||||
const target = options.resolve?.(node) ?? node
|
|
||||||
const cached = cache.get(target)
|
|
||||||
if (cached !== undefined || cache.has(target)) return cached!
|
|
||||||
|
|
||||||
if (options.detectCycles !== false && visiting.has(target)) {
|
|
||||||
const start = stack.indexOf(target)
|
|
||||||
throw new Error(
|
|
||||||
`Cycle detected in layer tree: ${[...stack.slice(start), target].map((item) => item.name).join(" -> ")}`,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
visiting.add(target)
|
|
||||||
stack.push(target)
|
|
||||||
try {
|
|
||||||
const result = visit(target, { cache, visit: recur })
|
|
||||||
if (!cache.has(target)) cache.set(target, result)
|
|
||||||
return result
|
|
||||||
} finally {
|
|
||||||
stack.pop()
|
|
||||||
visiting.delete(target)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return recur(root)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function hoist<A, E, T extends LayerNode.Tag>(
|
|
||||||
root: LayerNode.Node<A, E, any>,
|
|
||||||
tag: T,
|
|
||||||
): {
|
|
||||||
readonly node: LayerNode.Node<A, E>
|
|
||||||
readonly hoisted: LayerNode.Node<unknown, E>
|
|
||||||
} {
|
|
||||||
const hoisted = new Map<string, AnyNode>()
|
|
||||||
|
|
||||||
const node = walk<AnyNode>(root, (node, context) => {
|
|
||||||
if (node.kind === "group") {
|
|
||||||
return { ...node, dependencies: node.dependencies.map(context.visit) }
|
|
||||||
}
|
|
||||||
if (node.tag === tag) {
|
|
||||||
const existing = hoisted.get(node.name)
|
|
||||||
if (existing && existing !== node) {
|
|
||||||
throw new Error(`Tag ${tag} has conflicting implementations for ${node.name}`)
|
|
||||||
}
|
|
||||||
hoisted.set(node.name, node)
|
|
||||||
return LayerNode.group([])
|
|
||||||
}
|
|
||||||
if (node.kind === "unbound") {
|
|
||||||
return node
|
|
||||||
}
|
|
||||||
return { ...node, dependencies: node.dependencies.map(context.visit) }
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
|
||||||
node: node as LayerNode.Node<A, E>,
|
|
||||||
hoisted: LayerNode.group(Array.from(hoisted.values())) as LayerNode.Node<unknown, E>,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function compile<A, E>(
|
|
||||||
root: LayerNode.Node<A, E, any>,
|
|
||||||
replacements?: ReadonlyMap<Layer.Any, Layer.Any>,
|
|
||||||
): Layer.Layer<A, E> {
|
|
||||||
const cache = new Map<AnyNode, RuntimeLayer>()
|
|
||||||
const compileNode = (node: AnyNode) =>
|
|
||||||
walk<RuntimeLayer>(
|
|
||||||
node,
|
|
||||||
(node, context) => {
|
|
||||||
if (node.kind === "unbound") throw new Error(`Unbound layer node: ${node.name}`)
|
|
||||||
const dependencies = node.dependencies.flatMap(flatten).map(context.visit)
|
|
||||||
const implementation = (replacements?.get(node.implementation!) ?? node.implementation!) as RuntimeLayer
|
|
||||||
return dependencies.length === 0
|
|
||||||
? implementation
|
|
||||||
: implementation.pipe(Layer.provide(dependencies as [RuntimeLayer, ...RuntimeLayer[]]))
|
|
||||||
},
|
|
||||||
{ cache },
|
|
||||||
)
|
|
||||||
const layers = flatten(root).map((node) => compileNode(node))
|
|
||||||
const layer = layers.reduce<RuntimeLayer>((result, layer) => layer.pipe(Layer.provideMerge(result)), Layer.empty)
|
|
||||||
return layer as Layer.Layer<A, E>
|
|
||||||
}
|
|
||||||
|
|
||||||
export function hasUnbound(root: LayerNode.Node<unknown, unknown, any>, source: AnyNode): boolean {
|
|
||||||
if (source.kind !== "unbound") throw new Error(`Cannot check non-unbound layer node: ${source.name}`)
|
|
||||||
return walk<boolean>(root, (node, context) => {
|
|
||||||
if (node === source) return true
|
|
||||||
return node.dependencies.some(context.visit)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function bind<A, E, T extends LayerNode.Tag | undefined>(
|
|
||||||
root: LayerNode.Node<A, E, T>,
|
|
||||||
source: AnyNode,
|
|
||||||
replacement: AnyNode,
|
|
||||||
): LayerNode.Node<A, E, T> {
|
|
||||||
if (source.kind !== "unbound") throw new Error(`Cannot bind non-unbound layer node: ${source.name}`)
|
|
||||||
if (source.name !== replacement.name) {
|
|
||||||
throw new Error(`Cannot bind ${source.name} to ${replacement.name}`)
|
|
||||||
}
|
|
||||||
if (source.tag !== replacement.tag) {
|
|
||||||
throw new Error(`Cannot bind ${source.name} across tags`)
|
|
||||||
}
|
|
||||||
return walk<AnyNode>(
|
|
||||||
root,
|
|
||||||
(target, context) => {
|
|
||||||
if (target.kind === "unbound") return target
|
|
||||||
const dependencies: AnyNode[] = []
|
|
||||||
const clone = { ...target, dependencies }
|
|
||||||
context.cache.set(target, clone)
|
|
||||||
dependencies.push(...target.dependencies.map(context.visit))
|
|
||||||
return clone
|
|
||||||
},
|
|
||||||
{ detectCycles: false, resolve: (node) => (node === source ? replacement : node) },
|
|
||||||
) as LayerNode.Node<A, E, T>
|
|
||||||
}
|
|
||||||
|
|
||||||
function flatten(node: AnyNode): readonly AnyNode[] {
|
|
||||||
return node.kind === "group" ? node.dependencies.flatMap(flatten) : [node]
|
|
||||||
}
|
|
||||||
|
|
||||||
export * as LayerNodeTree from "./layer-node-tree"
|
|
||||||
@@ -7,7 +7,7 @@ import { and, asc, eq, gt, inArray } from "drizzle-orm"
|
|||||||
import { Database } from "./database/database"
|
import { Database } from "./database/database"
|
||||||
import { EventSequenceTable, EventTable } from "./event/sql"
|
import { EventSequenceTable, EventTable } from "./event/sql"
|
||||||
import { Location } from "./location"
|
import { Location } from "./location"
|
||||||
import { makeGlobalNode } from "./effect/node"
|
import { makeGlobalNode } from "./effect/app-node"
|
||||||
import { isDeepStrictEqual } from "node:util"
|
import { isDeepStrictEqual } from "node:util"
|
||||||
import { Durable } from "@opencode-ai/schema/durable-event-manifest"
|
import { Durable } from "@opencode-ai/schema/durable-event-manifest"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as FileMutation from "./file-mutation"
|
export * as FileMutation from "./file-mutation"
|
||||||
|
|
||||||
import { makeLocationNode } from "./effect/node"
|
import { makeLocationNode } from "./effect/app-node"
|
||||||
import { Context, Effect, Layer, Schema } from "effect"
|
import { Context, Effect, Layer, Schema } from "effect"
|
||||||
import { dirname } from "path"
|
import { dirname } from "path"
|
||||||
import { KeyedMutex } from "./effect/keyed-mutex"
|
import { KeyedMutex } from "./effect/keyed-mutex"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as FileSystem from "./filesystem"
|
export * as FileSystem from "./filesystem"
|
||||||
|
|
||||||
import { makeLocationNode } from "./effect/node"
|
import { makeLocationNode } from "./effect/app-node"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { Context, Effect, Layer, Schema } from "effect"
|
import { Context, Effect, Layer, Schema } from "effect"
|
||||||
import { FSUtil } from "./fs-util"
|
import { FSUtil } from "./fs-util"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as FileSystemSearch from "./search"
|
export * as FileSystemSearch from "./search"
|
||||||
|
|
||||||
import { makeLocationNode } from "../effect/node"
|
import { makeLocationNode } from "../effect/app-node"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { Context, Effect, Layer, Scope } from "effect"
|
import { Context, Effect, Layer, Scope } from "effect"
|
||||||
import { Fff } from "#fff"
|
import { Fff } from "#fff"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ export * as Watcher from "./watcher"
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { createWrapper } from "@parcel/watcher/wrapper"
|
import { createWrapper } from "@parcel/watcher/wrapper"
|
||||||
import type ParcelWatcher from "@parcel/watcher"
|
import type ParcelWatcher from "@parcel/watcher"
|
||||||
import { makeLocationNode } from "../effect/node"
|
import { makeLocationNode } from "../effect/app-node"
|
||||||
import { Cause, Context, Effect, Layer } from "effect"
|
import { Cause, Context, Effect, Layer } from "effect"
|
||||||
import { FileSystemWatcher } from "@opencode-ai/schema/filesystem-watcher"
|
import { FileSystemWatcher } from "@opencode-ai/schema/filesystem-watcher"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import { Context, Effect, FileSystem, Layer, Schema } from "effect"
|
|||||||
import type { PlatformError } from "effect/PlatformError"
|
import type { PlatformError } from "effect/PlatformError"
|
||||||
import { Glob } from "./util/glob"
|
import { Glob } from "./util/glob"
|
||||||
import { serviceUse } from "./effect/service-use"
|
import { serviceUse } from "./effect/service-use"
|
||||||
import { makeGlobalNode } from "./effect/node"
|
import { makeGlobalNode } from "./effect/app-node"
|
||||||
import { filesystem } from "./effect/layer-node-platform"
|
import { filesystem } from "./effect/app-node-platform"
|
||||||
|
|
||||||
export namespace FSUtil {
|
export namespace FSUtil {
|
||||||
export class FileSystemError extends Schema.TaggedErrorClass<FileSystemError>()("FileSystemError", {
|
export class FileSystemError extends Schema.TaggedErrorClass<FileSystemError>()("FileSystemError", {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { ChildProcess } from "effect/unstable/process"
|
|||||||
import { AbsolutePath, RelativePath } from "./schema"
|
import { AbsolutePath, RelativePath } from "./schema"
|
||||||
import { FSUtil } from "./fs-util"
|
import { FSUtil } from "./fs-util"
|
||||||
import { AppProcess } from "./process"
|
import { AppProcess } from "./process"
|
||||||
import { makeGlobalNode } from "./effect/node"
|
import { makeGlobalNode } from "./effect/app-node"
|
||||||
import { File } from "./file"
|
import { File } from "./file"
|
||||||
import { KeyedMutex } from "./effect/keyed-mutex"
|
import { KeyedMutex } from "./effect/keyed-mutex"
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import os from "os"
|
|||||||
import { Context, Effect, Layer } from "effect"
|
import { Context, Effect, Layer } from "effect"
|
||||||
import { Flock } from "./util/flock"
|
import { Flock } from "./util/flock"
|
||||||
import { Flag } from "./flag/flag"
|
import { Flag } from "./flag/flag"
|
||||||
import { makeGlobalNode } from "./effect/node"
|
import { makeGlobalNode } from "./effect/app-node"
|
||||||
|
|
||||||
const app = "opencode"
|
const app = "opencode"
|
||||||
const data = path.join(xdgData!, app)
|
const data = path.join(xdgData!, app)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as Image from "./image"
|
export * as Image from "./image"
|
||||||
|
|
||||||
import { makeLocationNode } from "./effect/node"
|
import { makeLocationNode } from "./effect/app-node"
|
||||||
import { Context, Effect, Layer, Schema } from "effect"
|
import { Context, Effect, Layer, Schema } from "effect"
|
||||||
import { Config } from "./config"
|
import { Config } from "./config"
|
||||||
import { FileSystem } from "./filesystem"
|
import { FileSystem } from "./filesystem"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { Location } from "./location"
|
|||||||
import { AbsolutePath } from "./schema"
|
import { AbsolutePath } from "./schema"
|
||||||
import { SystemContext } from "./system-context/index"
|
import { SystemContext } from "./system-context/index"
|
||||||
import { SystemContextRegistry } from "./system-context/registry"
|
import { SystemContextRegistry } from "./system-context/registry"
|
||||||
import { makeLocationNode } from "./effect/node"
|
import { makeLocationNode } from "./effect/app-node"
|
||||||
|
|
||||||
class File extends Schema.Class<File>("InstructionContext.File")({
|
class File extends Schema.Class<File>("InstructionContext.File")({
|
||||||
path: AbsolutePath,
|
path: AbsolutePath,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as Integration from "./integration"
|
export * as Integration from "./integration"
|
||||||
|
|
||||||
import { makeLocationNode } from "./effect/node"
|
import { makeLocationNode } from "./effect/app-node"
|
||||||
import {
|
import {
|
||||||
Cause,
|
Cause,
|
||||||
Clock,
|
Clock,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as LocationMutation from "./location-mutation"
|
export * as LocationMutation from "./location-mutation"
|
||||||
|
|
||||||
import { makeLocationNode } from "./effect/node"
|
import { makeLocationNode } from "./effect/app-node"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { Context, Effect, Layer, Schema } from "effect"
|
import { Context, Effect, Layer, Schema } from "effect"
|
||||||
import { FSUtil } from "./fs-util"
|
import { FSUtil } from "./fs-util"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Context, Effect, Layer, LayerMap } from "effect"
|
import { Context, Effect, Layer, LayerMap } from "effect"
|
||||||
import { LayerNode } from "./effect/layer-node"
|
import { LayerNode } from "./effect/layer-node"
|
||||||
import { Node } from "./effect/node"
|
import { Node } from "./effect/app-node"
|
||||||
import { Location } from "./location"
|
import { Location } from "./location"
|
||||||
import type { LocationError, LocationServices } from "./location-services"
|
import type { LocationError, LocationServices } from "./location-services"
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import { AISDK } from "./aisdk"
|
|||||||
import { Catalog } from "./catalog"
|
import { Catalog } from "./catalog"
|
||||||
import { CommandV2 } from "./command"
|
import { CommandV2 } from "./command"
|
||||||
import { Config } from "./config"
|
import { Config } from "./config"
|
||||||
import { LayerNode, LayerNodeTree } from "./effect/layer-node"
|
import { LayerNode } from "./effect/layer-node"
|
||||||
import { Node } from "./effect/node"
|
import { Node } from "./effect/app-node"
|
||||||
import { FileMutation } from "./file-mutation"
|
import { FileMutation } from "./file-mutation"
|
||||||
import { FileSystem } from "./filesystem"
|
import { FileSystem } from "./filesystem"
|
||||||
import { FileSystemSearch } from "./filesystem/search"
|
import { FileSystemSearch } from "./filesystem/search"
|
||||||
@@ -88,11 +88,11 @@ export function buildLocationServiceMap(
|
|||||||
LocationServiceMap.Service,
|
LocationServiceMap.Service,
|
||||||
LayerMap.make(
|
LayerMap.make(
|
||||||
(ref: Location.Ref) => {
|
(ref: Location.Ref) => {
|
||||||
const location = LayerNodeTree.hoist(
|
const location = LayerNode.hoist(
|
||||||
LayerNodeTree.bind(locationServices, Location.node, Location.boundNode(ref)),
|
LayerNode.bind(locationServices, Location.node, Location.boundNode(ref)),
|
||||||
Node.tags.values.global,
|
Node.tags.values.global,
|
||||||
)
|
)
|
||||||
return LayerNodeTree.compile(location.node, replacements).pipe(
|
return LayerNode.compile(location.node, replacements).pipe(
|
||||||
Layer.fresh,
|
Layer.fresh,
|
||||||
Layer.tap(() =>
|
Layer.tap(() =>
|
||||||
Effect.logInfo("booting location services", {
|
Effect.logInfo("booting location services", {
|
||||||
@@ -100,7 +100,7 @@ export function buildLocationServiceMap(
|
|||||||
workspaceID: ref.workspaceID,
|
workspaceID: ref.workspaceID,
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
Layer.provide(LayerNodeTree.compile(location.hoisted, replacements)),
|
Layer.provide(LayerNode.compile(location.hoisted, replacements)),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
{ idleTimeToLive: "60 minutes" },
|
{ idleTimeToLive: "60 minutes" },
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Context, Effect, Layer } from "effect"
|
|||||||
import { Info, Ref, response } from "@opencode-ai/schema/location"
|
import { Info, Ref, response } from "@opencode-ai/schema/location"
|
||||||
import { Project } from "./project"
|
import { Project } from "./project"
|
||||||
import { LayerNode } from "./effect/layer-node"
|
import { LayerNode } from "./effect/layer-node"
|
||||||
import { makeLocationNode, tags } from "./effect/node"
|
import { makeLocationNode, tags } from "./effect/app-node"
|
||||||
|
|
||||||
export * as Location from "./location"
|
export * as Location from "./location"
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import { Hash } from "./util/hash"
|
|||||||
import { FSUtil } from "./fs-util"
|
import { FSUtil } from "./fs-util"
|
||||||
import { InstallationChannel, InstallationVersion } from "./installation/version"
|
import { InstallationChannel, InstallationVersion } from "./installation/version"
|
||||||
import { EventV2 } from "./event"
|
import { EventV2 } from "./event"
|
||||||
import { makeGlobalNode } from "./effect/node"
|
import { makeGlobalNode } from "./effect/app-node"
|
||||||
import { httpClient } from "./effect/layer-node-platform"
|
import { httpClient } from "./effect/app-node-platform"
|
||||||
|
|
||||||
export const CatalogModelStatus = Schema.Literals(["alpha", "beta", "deprecated"])
|
export const CatalogModelStatus = Schema.Literals(["alpha", "beta", "deprecated"])
|
||||||
export type CatalogModelStatus = typeof CatalogModelStatus.Type
|
export type CatalogModelStatus = typeof CatalogModelStatus.Type
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import { NodeFileSystem } from "@effect/platform-node"
|
|||||||
import { FSUtil } from "./fs-util"
|
import { FSUtil } from "./fs-util"
|
||||||
import { Global } from "./global"
|
import { Global } from "./global"
|
||||||
import { EffectFlock } from "./util/effect-flock"
|
import { EffectFlock } from "./util/effect-flock"
|
||||||
import { makeGlobalNode } from "./effect/node"
|
import { makeGlobalNode } from "./effect/app-node"
|
||||||
import { filesystem } from "./effect/layer-node-platform"
|
import { filesystem } from "./effect/app-node-platform"
|
||||||
import { makeRuntime } from "./effect/runtime"
|
import { makeRuntime } from "./effect/runtime"
|
||||||
import { NpmConfig } from "./npm-config"
|
import { NpmConfig } from "./npm-config"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as PermissionV2 from "./permission"
|
export * as PermissionV2 from "./permission"
|
||||||
|
|
||||||
import { makeLocationNode } from "./effect/node"
|
import { makeLocationNode } from "./effect/app-node"
|
||||||
import { Context, Deferred, Effect as EffectRuntime, Layer, Schema } from "effect"
|
import { Context, Deferred, Effect as EffectRuntime, Layer, Schema } from "effect"
|
||||||
import { Permission } from "@opencode-ai/schema/permission"
|
import { Permission } from "@opencode-ai/schema/permission"
|
||||||
import { EventV2 } from "./event"
|
import { EventV2 } from "./event"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ export * as PermissionSaved from "./saved"
|
|||||||
import { eq } from "drizzle-orm"
|
import { eq } from "drizzle-orm"
|
||||||
import { Context, Effect, Layer, Schema } from "effect"
|
import { Context, Effect, Layer, Schema } from "effect"
|
||||||
import { Database } from "../database/database"
|
import { Database } from "../database/database"
|
||||||
import { makeGlobalNode } from "../effect/node"
|
import { makeGlobalNode } from "../effect/app-node"
|
||||||
import { ProjectV2 } from "../project"
|
import { ProjectV2 } from "../project"
|
||||||
import { PermissionTable } from "./sql"
|
import { PermissionTable } from "./sql"
|
||||||
import { PermissionSaved } from "@opencode-ai/schema/permission-saved"
|
import { PermissionSaved } from "@opencode-ai/schema/permission-saved"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as PluginV2 from "./plugin"
|
export * as PluginV2 from "./plugin"
|
||||||
|
|
||||||
import { makeLocationNode } from "./effect/node"
|
import { makeLocationNode } from "./effect/app-node"
|
||||||
import { Context, Deferred, Effect, Exit, Layer, Scope } from "effect"
|
import { Context, Deferred, Effect, Exit, Layer, Scope } from "effect"
|
||||||
import type { Plugin as PluginRuntime } from "@opencode-ai/plugin/v2/effect"
|
import type { Plugin as PluginRuntime } from "@opencode-ai/plugin/v2/effect"
|
||||||
import { Plugin } from "@opencode-ai/schema/plugin"
|
import { Plugin } from "@opencode-ai/schema/plugin"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export * as PluginInternal from "./internal"
|
export * as PluginInternal from "./internal"
|
||||||
|
|
||||||
import { makeLocationNode } from "../effect/node"
|
import { makeLocationNode } from "../effect/app-node"
|
||||||
import { httpClient } from "../effect/layer-node-platform"
|
import { httpClient } from "../effect/app-node-platform"
|
||||||
import type { PluginContext } from "@opencode-ai/plugin/v2/effect"
|
import type { PluginContext } from "@opencode-ai/plugin/v2/effect"
|
||||||
import { Effect, Layer, Scope } from "effect"
|
import { Effect, Layer, Scope } from "effect"
|
||||||
import { AgentV2 } from "../agent"
|
import { AgentV2 } from "../agent"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as Policy from "./policy"
|
export * as Policy from "./policy"
|
||||||
|
|
||||||
import { makeLocationNode } from "./effect/node"
|
import { makeLocationNode } from "./effect/app-node"
|
||||||
import { Context, Effect as EffectRuntime, Layer, Schema } from "effect"
|
import { Context, Effect as EffectRuntime, Layer, Schema } from "effect"
|
||||||
import { Wildcard } from "./util/wildcard"
|
import { Wildcard } from "./util/wildcard"
|
||||||
import { Location } from "./location"
|
import { Location } from "./location"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { PlatformError } from "effect/PlatformError"
|
|||||||
import { ChildProcess } from "effect/unstable/process"
|
import { ChildProcess } from "effect/unstable/process"
|
||||||
import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner"
|
import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner"
|
||||||
import { CrossSpawnSpawner } from "./cross-spawn-spawner"
|
import { CrossSpawnSpawner } from "./cross-spawn-spawner"
|
||||||
import { makeGlobalNode } from "./effect/node"
|
import { makeGlobalNode } from "./effect/app-node"
|
||||||
|
|
||||||
export class AppProcessError extends Schema.TaggedErrorClass<AppProcessError>()("AppProcessError", {
|
export class AppProcessError extends Schema.TaggedErrorClass<AppProcessError>()("AppProcessError", {
|
||||||
command: Schema.String,
|
command: Schema.String,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import path from "path"
|
|||||||
import { AbsolutePath } from "./schema"
|
import { AbsolutePath } from "./schema"
|
||||||
import { FSUtil } from "./fs-util"
|
import { FSUtil } from "./fs-util"
|
||||||
import { Git } from "./git"
|
import { Git } from "./git"
|
||||||
import { makeGlobalNode } from "./effect/node"
|
import { makeGlobalNode } from "./effect/app-node"
|
||||||
import { Hash } from "./util/hash"
|
import { Hash } from "./util/hash"
|
||||||
import { ProjectDirectories } from "./project/directories"
|
import { ProjectDirectories } from "./project/directories"
|
||||||
import { ProjectSchema } from "./project/schema"
|
import { ProjectSchema } from "./project/schema"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import path from "path"
|
|||||||
import { AbsolutePath } from "../schema"
|
import { AbsolutePath } from "../schema"
|
||||||
import { FSUtil } from "../fs-util"
|
import { FSUtil } from "../fs-util"
|
||||||
import { Git } from "../git"
|
import { Git } from "../git"
|
||||||
import { makeLocationNode } from "../effect/node"
|
import { makeLocationNode } from "../effect/app-node"
|
||||||
import { Project } from "../project"
|
import { Project } from "../project"
|
||||||
import { ProjectDirectories } from "./directories"
|
import { ProjectDirectories } from "./directories"
|
||||||
import { makeGitWorktreeStrategy } from "./copy-strategies"
|
import { makeGitWorktreeStrategy } from "./copy-strategies"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ export * as ProjectDirectories from "./directories"
|
|||||||
import { and, asc, desc, eq, isNotNull, isNull, ne, or } from "drizzle-orm"
|
import { and, asc, desc, eq, isNotNull, isNull, ne, or } from "drizzle-orm"
|
||||||
import { Context, Effect, Layer, Schema } from "effect"
|
import { Context, Effect, Layer, Schema } from "effect"
|
||||||
import { Database } from "../database/database"
|
import { Database } from "../database/database"
|
||||||
import { makeGlobalNode } from "../effect/node"
|
import { makeGlobalNode } from "../effect/app-node"
|
||||||
import { AbsolutePath, optional } from "../schema"
|
import { AbsolutePath, optional } from "../schema"
|
||||||
import { ProjectSchema } from "./schema"
|
import { ProjectSchema } from "./schema"
|
||||||
import { ProjectDirectoryTable } from "./sql"
|
import { ProjectDirectoryTable } from "./sql"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as Pty from "./pty"
|
export * as Pty from "./pty"
|
||||||
|
|
||||||
import { makeLocationNode } from "./effect/node"
|
import { makeLocationNode } from "./effect/app-node"
|
||||||
import type { Disp, Proc } from "#pty"
|
import type { Disp, Proc } from "#pty"
|
||||||
import { Context, Effect, Layer, Schema, Types } from "effect"
|
import { Context, Effect, Layer, Schema, Types } from "effect"
|
||||||
import { Pty } from "@opencode-ai/schema/pty"
|
import { Pty } from "@opencode-ai/schema/pty"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { WorkspaceV2 } from "../workspace"
|
|||||||
import { PtyTicket } from "@opencode-ai/schema/pty-ticket"
|
import { PtyTicket } from "@opencode-ai/schema/pty-ticket"
|
||||||
import { PtyID } from "./schema"
|
import { PtyID } from "./schema"
|
||||||
import { Cache, Context, Duration, Effect, Layer } from "effect"
|
import { Cache, Context, Duration, Effect, Layer } from "effect"
|
||||||
import { makeGlobalNode } from "../effect/node"
|
import { makeGlobalNode } from "../effect/app-node"
|
||||||
|
|
||||||
const DEFAULT_TTL = Duration.seconds(60)
|
const DEFAULT_TTL = Duration.seconds(60)
|
||||||
const CAPACITY = 10_000
|
const CAPACITY = 10_000
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as QuestionV2 from "./question"
|
export * as QuestionV2 from "./question"
|
||||||
|
|
||||||
import { makeLocationNode } from "./effect/node"
|
import { makeLocationNode } from "./effect/app-node"
|
||||||
import { Context, Deferred, Effect, Layer, Schema } from "effect"
|
import { Context, Deferred, Effect, Layer, Schema } from "effect"
|
||||||
import { Question } from "@opencode-ai/schema/question"
|
import { Question } from "@opencode-ai/schema/question"
|
||||||
import { EventV2 } from "./event"
|
import { EventV2 } from "./event"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as Reference from "./reference"
|
export * as Reference from "./reference"
|
||||||
|
|
||||||
import { makeLocationNode } from "./effect/node"
|
import { makeLocationNode } from "./effect/app-node"
|
||||||
import { Context, Effect, Layer, Scope, Types } from "effect"
|
import { Context, Effect, Layer, Scope, Types } from "effect"
|
||||||
import { Reference } from "@opencode-ai/schema/reference"
|
import { Reference } from "@opencode-ai/schema/reference"
|
||||||
import { Global } from "./global"
|
import { Global } from "./global"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as ReferenceGuidance from "./guidance"
|
export * as ReferenceGuidance from "./guidance"
|
||||||
|
|
||||||
import { makeLocationNode } from "../effect/node"
|
import { makeLocationNode } from "../effect/app-node"
|
||||||
import { Context, Effect, Layer, Schema } from "effect"
|
import { Context, Effect, Layer, Schema } from "effect"
|
||||||
import { Reference } from "../reference"
|
import { Reference } from "../reference"
|
||||||
import { SystemContext } from "../system-context/index"
|
import { SystemContext } from "../system-context/index"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Git } from "./git"
|
|||||||
import { Global } from "./global"
|
import { Global } from "./global"
|
||||||
import { Repository } from "./repository"
|
import { Repository } from "./repository"
|
||||||
import { AbsolutePath } from "./schema"
|
import { AbsolutePath } from "./schema"
|
||||||
import { makeGlobalNode } from "./effect/node"
|
import { makeGlobalNode } from "./effect/app-node"
|
||||||
import { EffectFlock } from "./util/effect-flock"
|
import { EffectFlock } from "./util/effect-flock"
|
||||||
|
|
||||||
export type Result = {
|
export type Result = {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ export * as Ripgrep from "./ripgrep"
|
|||||||
import { Context, Effect, Fiber, Layer, Schema, Stream } from "effect"
|
import { Context, Effect, Fiber, Layer, Schema, Stream } from "effect"
|
||||||
import { ChildProcess } from "effect/unstable/process"
|
import { ChildProcess } from "effect/unstable/process"
|
||||||
import { Entry, Match } from "@opencode-ai/schema/filesystem"
|
import { Entry, Match } from "@opencode-ai/schema/filesystem"
|
||||||
import { makeGlobalNode } from "./effect/node"
|
import { makeGlobalNode } from "./effect/app-node"
|
||||||
import { AppProcess, collectStream, waitForAbort } from "./process"
|
import { AppProcess, collectStream, waitForAbort } from "./process"
|
||||||
import { NonNegativeInt, PositiveInt, RelativePath } from "./schema"
|
import { NonNegativeInt, PositiveInt, RelativePath } from "./schema"
|
||||||
import { RipgrepBinary } from "./ripgrep/binary"
|
import { RipgrepBinary } from "./ripgrep/binary"
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/unstable/
|
|||||||
import { ChildProcess } from "effect/unstable/process"
|
import { ChildProcess } from "effect/unstable/process"
|
||||||
import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner"
|
import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner"
|
||||||
import { CrossSpawnSpawner } from "../cross-spawn-spawner"
|
import { CrossSpawnSpawner } from "../cross-spawn-spawner"
|
||||||
import { makeGlobalNode } from "../effect/node"
|
import { makeGlobalNode } from "../effect/app-node"
|
||||||
import { httpClient } from "../effect/layer-node-platform"
|
import { httpClient } from "../effect/app-node-platform"
|
||||||
import { FSUtil } from "../fs-util"
|
import { FSUtil } from "../fs-util"
|
||||||
import { Global } from "../global"
|
import { Global } from "../global"
|
||||||
import { which } from "../util/which"
|
import { which } from "../util/which"
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import { fromRow } from "./session/info"
|
|||||||
import { SessionRunner } from "./session/runner/index"
|
import { SessionRunner } from "./session/runner/index"
|
||||||
import { SessionStore } from "./session/store"
|
import { SessionStore } from "./session/store"
|
||||||
import { SessionExecution } from "./session/execution"
|
import { SessionExecution } from "./session/execution"
|
||||||
import { makeGlobalNode } from "./effect/node"
|
import { makeGlobalNode } from "./effect/app-node"
|
||||||
import { LocationServiceMap } from "./location-service-map"
|
import { LocationServiceMap } from "./location-service-map"
|
||||||
import { MessageDecodeError } from "./session/error"
|
import { MessageDecodeError } from "./session/error"
|
||||||
import { SessionEvent } from "./session/event"
|
import { SessionEvent } from "./session/event"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ export * as SessionExecution from "./execution"
|
|||||||
|
|
||||||
import { Context, Effect, Layer } from "effect"
|
import { Context, Effect, Layer } from "effect"
|
||||||
import { LayerNode } from "../effect/layer-node"
|
import { LayerNode } from "../effect/layer-node"
|
||||||
import { Node } from "../effect/node"
|
import { Node } from "../effect/app-node"
|
||||||
import { SessionRunner } from "./runner/index"
|
import { SessionRunner } from "./runner/index"
|
||||||
import { SessionSchema } from "./schema"
|
import { SessionSchema } from "./schema"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Cause, Effect, Layer } from "effect"
|
import { Cause, Effect, Layer } from "effect"
|
||||||
import { LocationServiceMap } from "../../location-service-map"
|
import { LocationServiceMap } from "../../location-service-map"
|
||||||
import { makeGlobalNode } from "../../effect/node"
|
import { makeGlobalNode } from "../../effect/app-node"
|
||||||
import { SessionRunCoordinator } from "../run-coordinator"
|
import { SessionRunCoordinator } from "../run-coordinator"
|
||||||
import { SessionRunner } from "../runner"
|
import { SessionRunner } from "../runner"
|
||||||
import { SessionSchema } from "../schema"
|
import { SessionSchema } from "../schema"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { and, desc, eq, gt, or, sql } from "drizzle-orm"
|
|||||||
import { DateTime, Effect, Layer, Schema } from "effect"
|
import { DateTime, Effect, Layer, Schema } from "effect"
|
||||||
import { Database } from "../database/database"
|
import { Database } from "../database/database"
|
||||||
import { EventV2 } from "../event"
|
import { EventV2 } from "../event"
|
||||||
import { makeGlobalNode } from "../effect/node"
|
import { makeGlobalNode } from "../effect/app-node"
|
||||||
import { SessionEvent } from "./event"
|
import { SessionEvent } from "./event"
|
||||||
import { SessionV1 } from "../v1/session"
|
import { SessionV1 } from "../v1/session"
|
||||||
import { WorkspaceTable } from "../control-plane/workspace.sql"
|
import { WorkspaceTable } from "../control-plane/workspace.sql"
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ import { createLLMEventPublisher } from "./publish-llm-event"
|
|||||||
import { toLLMMessages } from "./to-llm-message"
|
import { toLLMMessages } from "./to-llm-message"
|
||||||
import { MAX_STEPS_PROMPT } from "./max-steps"
|
import { MAX_STEPS_PROMPT } from "./max-steps"
|
||||||
import { Snapshot } from "../../snapshot"
|
import { Snapshot } from "../../snapshot"
|
||||||
import { makeLocationNode } from "../../effect/node"
|
import { makeLocationNode } from "../../effect/app-node"
|
||||||
import { llmClient } from "../../effect/layer-node-platform"
|
import { llmClient } from "../../effect/app-node-platform"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs one durable coding-agent Session until it settles.
|
* Runs one durable coding-agent Session until it settles.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as SessionRunnerModel from "./model"
|
export * as SessionRunnerModel from "./model"
|
||||||
|
|
||||||
import { makeLocationNode } from "../../effect/node"
|
import { makeLocationNode } from "../../effect/app-node"
|
||||||
import { type Model } from "@opencode-ai/llm"
|
import { type Model } from "@opencode-ai/llm"
|
||||||
import * as AnthropicMessages from "@opencode-ai/llm/protocols/anthropic-messages"
|
import * as AnthropicMessages from "@opencode-ai/llm/protocols/anthropic-messages"
|
||||||
import * as OpenAICompatibleChat from "@opencode-ai/llm/protocols/openai-compatible-chat"
|
import * as OpenAICompatibleChat from "@opencode-ai/llm/protocols/openai-compatible-chat"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ export * as SessionStore from "./store"
|
|||||||
import { eq } from "drizzle-orm"
|
import { eq } from "drizzle-orm"
|
||||||
import { Context, Effect, Layer, Schema } from "effect"
|
import { Context, Effect, Layer, Schema } from "effect"
|
||||||
import { Database } from "../database/database"
|
import { Database } from "../database/database"
|
||||||
import { makeGlobalNode } from "../effect/node"
|
import { makeGlobalNode } from "../effect/app-node"
|
||||||
import { SessionHistory } from "./history"
|
import { SessionHistory } from "./history"
|
||||||
import { MessageDecodeError } from "./error"
|
import { MessageDecodeError } from "./error"
|
||||||
import { SessionMessage } from "./message"
|
import { SessionMessage } from "./message"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { asc, eq } from "drizzle-orm"
|
|||||||
import { Context, Effect, Layer } from "effect"
|
import { Context, Effect, Layer } from "effect"
|
||||||
import { SessionTodo } from "@opencode-ai/schema/session-todo"
|
import { SessionTodo } from "@opencode-ai/schema/session-todo"
|
||||||
import { Database } from "../database/database"
|
import { Database } from "../database/database"
|
||||||
import { makeLocationNode } from "../effect/node"
|
import { makeLocationNode } from "../effect/app-node"
|
||||||
import { EventV2 } from "../event"
|
import { EventV2 } from "../event"
|
||||||
import { SessionSchema } from "./schema"
|
import { SessionSchema } from "./schema"
|
||||||
import { TodoTable } from "./sql"
|
import { TodoTable } from "./sql"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as SkillV2 from "./skill"
|
export * as SkillV2 from "./skill"
|
||||||
|
|
||||||
import { makeLocationNode } from "./effect/node"
|
import { makeLocationNode } from "./effect/app-node"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { Context, Effect, Layer, Schema, Types } from "effect"
|
import { Context, Effect, Layer, Schema, Types } from "effect"
|
||||||
import { Skill } from "@opencode-ai/schema/skill"
|
import { Skill } from "@opencode-ai/schema/skill"
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import { Context, Effect, Layer, Schedule, Schema } from "effect"
|
|||||||
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
||||||
import { FSUtil } from "../fs-util"
|
import { FSUtil } from "../fs-util"
|
||||||
import { Global } from "../global"
|
import { Global } from "../global"
|
||||||
import { makeGlobalNode } from "../effect/node"
|
import { makeGlobalNode } from "../effect/app-node"
|
||||||
import { httpClient } from "../effect/layer-node-platform"
|
import { httpClient } from "../effect/app-node-platform"
|
||||||
import { AbsolutePath } from "../schema"
|
import { AbsolutePath } from "../schema"
|
||||||
|
|
||||||
const skillConcurrency = 4
|
const skillConcurrency = 4
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as SkillGuidance from "./guidance"
|
export * as SkillGuidance from "./guidance"
|
||||||
|
|
||||||
import { makeLocationNode } from "../effect/node"
|
import { makeLocationNode } from "../effect/app-node"
|
||||||
import { Context, Effect, Layer, Schema } from "effect"
|
import { Context, Effect, Layer, Schema } from "effect"
|
||||||
import { AgentV2 } from "../agent"
|
import { AgentV2 } from "../agent"
|
||||||
import { PermissionV2 } from "../permission"
|
import { PermissionV2 } from "../permission"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as Snapshot from "./snapshot"
|
export * as Snapshot from "./snapshot"
|
||||||
|
|
||||||
import { makeLocationNode } from "./effect/node"
|
import { makeLocationNode } from "./effect/app-node"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { Context, Effect, Layer, Schema } from "effect"
|
import { Context, Effect, Layer, Schema } from "effect"
|
||||||
import { Config } from "./config"
|
import { Config } from "./config"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as SystemContextBuiltIns from "./builtins"
|
export * as SystemContextBuiltIns from "./builtins"
|
||||||
|
|
||||||
import { makeLocationNode } from "../effect/node"
|
import { makeLocationNode } from "../effect/app-node"
|
||||||
import { DateTime, Effect, Layer, Schema } from "effect"
|
import { DateTime, Effect, Layer, Schema } from "effect"
|
||||||
import { Location } from "../location"
|
import { Location } from "../location"
|
||||||
import { SystemContext } from "./index"
|
import { SystemContext } from "./index"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ export * as SystemContextRegistry from "./registry"
|
|||||||
|
|
||||||
import { Context, Effect, Layer, Ref, Scope } from "effect"
|
import { Context, Effect, Layer, Ref, Scope } from "effect"
|
||||||
import { SystemContext } from "./index"
|
import { SystemContext } from "./index"
|
||||||
import { makeLocationNode } from "../effect/node"
|
import { makeLocationNode } from "../effect/app-node"
|
||||||
|
|
||||||
export interface Entry {
|
export interface Entry {
|
||||||
readonly key: SystemContext.Key
|
readonly key: SystemContext.Key
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Context, Duration, Effect, Layer, Option, Schedule, Schema } from "effe
|
|||||||
import { Config } from "./config"
|
import { Config } from "./config"
|
||||||
import { FSUtil } from "./fs-util"
|
import { FSUtil } from "./fs-util"
|
||||||
import { Global } from "./global"
|
import { Global } from "./global"
|
||||||
import { makeGlobalNode, makeLocationNode } from "./effect/node"
|
import { makeGlobalNode, makeLocationNode } from "./effect/app-node"
|
||||||
import { SessionSchema } from "./session/schema"
|
import { SessionSchema } from "./session/schema"
|
||||||
import { Identifier } from "./util/identifier"
|
import { Identifier } from "./util/identifier"
|
||||||
import type { ToolOutput } from "@opencode-ai/llm"
|
import type { ToolOutput } from "@opencode-ai/llm"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ export * as ApplicationTools from "./application-tools"
|
|||||||
import { Context, Effect, Layer, Scope } from "effect"
|
import { Context, Effect, Layer, Scope } from "effect"
|
||||||
import { State } from "../state"
|
import { State } from "../state"
|
||||||
import { Tool } from "./tool"
|
import { Tool } from "./tool"
|
||||||
import { makeGlobalNode } from "../effect/node"
|
import { makeGlobalNode } from "../effect/app-node"
|
||||||
|
|
||||||
type Data = {
|
type Data = {
|
||||||
readonly entries: Map<string, Entry>
|
readonly entries: Map<string, Entry>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export * as BuiltInTools from "./builtins"
|
export * as BuiltInTools from "./builtins"
|
||||||
|
|
||||||
import { makeLocationNode } from "../effect/node"
|
import { makeLocationNode } from "../effect/app-node"
|
||||||
import { Layer } from "effect"
|
import { Layer } from "effect"
|
||||||
import { BashTool } from "./bash"
|
import { BashTool } from "./bash"
|
||||||
import { ApplyPatchTool } from "./apply-patch"
|
import { ApplyPatchTool } from "./apply-patch"
|
||||||
@@ -28,7 +28,7 @@ import { QuestionV2 } from "../question"
|
|||||||
import { SkillV2 } from "../skill"
|
import { SkillV2 } from "../skill"
|
||||||
import { SessionTodo } from "../session/todo"
|
import { SessionTodo } from "../session/todo"
|
||||||
import { ToolRegistry } from "./registry"
|
import { ToolRegistry } from "./registry"
|
||||||
import { httpClient } from "../effect/layer-node-platform"
|
import { httpClient } from "../effect/app-node-platform"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Composes only the shipped Location-scoped built-in tool transforms.
|
* Composes only the shipped Location-scoped built-in tool transforms.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { pathToFileURL } from "url"
|
|||||||
import { Context, Effect, Layer, Option, Schema } from "effect"
|
import { Context, Effect, Layer, Option, Schema } from "effect"
|
||||||
import { FileSystem } from "../filesystem"
|
import { FileSystem } from "../filesystem"
|
||||||
import { FSUtil } from "../fs-util"
|
import { FSUtil } from "../fs-util"
|
||||||
import { makeLocationNode } from "../effect/node"
|
import { makeLocationNode } from "../effect/app-node"
|
||||||
import { AbsolutePath, PositiveInt, RelativePath } from "../schema"
|
import { AbsolutePath, PositiveInt, RelativePath } from "../schema"
|
||||||
|
|
||||||
export const MAX_READ_LINES = 2_000
|
export const MAX_READ_LINES = 2_000
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { Wildcard } from "../util/wildcard"
|
|||||||
import { ApplicationTools } from "./application-tools"
|
import { ApplicationTools } from "./application-tools"
|
||||||
import { definition, permission, settle, validateName, type AnyTool, type RegistrationError } from "./tool"
|
import { definition, permission, settle, validateName, type AnyTool, type RegistrationError } from "./tool"
|
||||||
import { Tools } from "./tools"
|
import { Tools } from "./tools"
|
||||||
import { makeLocationNode } from "../effect/node"
|
import { makeLocationNode } from "../effect/app-node"
|
||||||
|
|
||||||
export type ExecuteInput = {
|
export type ExecuteInput = {
|
||||||
readonly sessionID: SessionSchema.ID
|
readonly sessionID: SessionSchema.ID
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import type { FileSystem, Scope } from "effect"
|
|||||||
import type { PlatformError } from "effect/PlatformError"
|
import type { PlatformError } from "effect/PlatformError"
|
||||||
import { FSUtil } from "../fs-util"
|
import { FSUtil } from "../fs-util"
|
||||||
import { Global } from "../global"
|
import { Global } from "../global"
|
||||||
import { makeGlobalNode } from "../effect/node"
|
import { makeGlobalNode } from "../effect/app-node"
|
||||||
import { Hash } from "./hash"
|
import { Hash } from "./hash"
|
||||||
|
|
||||||
export namespace EffectFlock {
|
export namespace EffectFlock {
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { test } from "bun:test"
|
import { test } from "bun:test"
|
||||||
import { Context, Effect, Layer } from "effect"
|
import { Context, Effect, Layer } from "effect"
|
||||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { LayerNodeTree } from "@opencode-ai/core/effect/layer-node"
|
import { makeGlobalNode, makeLocationNode } from "@opencode-ai/core/effect/app-node"
|
||||||
import { makeGlobalNode, makeLocationNode } from "@opencode-ai/core/effect/node"
|
|
||||||
|
|
||||||
class A extends Context.Service<A, {}>()("test/LayerNodeA") {}
|
class A extends Context.Service<A, {}>()("test/LayerNodeA") {}
|
||||||
class B extends Context.Service<B, {}>()("test/LayerNodeB") {}
|
class B extends Context.Service<B, {}>()("test/LayerNodeB") {}
|
||||||
@@ -16,7 +15,7 @@ class OtherError {
|
|||||||
|
|
||||||
const tags = LayerNode.tags({ app: [] })
|
const tags = LayerNode.tags({ app: [] })
|
||||||
const make = tags.make("app")
|
const make = tags.make("app")
|
||||||
const build = <A, E>(root: LayerNode.Node<A, E, any>) => LayerNodeTree.compile(root) as Layer.Layer<A, E>
|
const build = <A, E>(root: LayerNode.Node<A, E, any>) => LayerNode.compile(root) as Layer.Layer<A, E>
|
||||||
const aLayer = Layer.succeed(A, A.of({}))
|
const aLayer = Layer.succeed(A, A.of({}))
|
||||||
const bLayer = Layer.effect(B, Effect.as(A, B.of({})))
|
const bLayer = Layer.effect(B, Effect.as(A, B.of({})))
|
||||||
const cLayer = Layer.effect(
|
const cLayer = Layer.effect(
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import { Context, Effect, Layer } from "effect"
|
import { Context, Effect, Layer } from "effect"
|
||||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { LayerNodeTree } from "@opencode-ai/core/effect/layer-node"
|
|
||||||
|
|
||||||
class Value extends Context.Service<Value, { readonly value: string }>()("test/LayerNodeValue") {}
|
class Value extends Context.Service<Value, { readonly value: string }>()("test/LayerNodeValue") {}
|
||||||
class Greeting extends Context.Service<Greeting, { readonly value: string }>()("test/LayerNodeGreeting") {}
|
class Greeting extends Context.Service<Greeting, { readonly value: string }>()("test/LayerNodeGreeting") {}
|
||||||
@@ -14,7 +13,7 @@ class App extends Context.Service<App, { readonly run: Effect.Effect<string[]> }
|
|||||||
const tags = LayerNode.tags({ app: [] })
|
const tags = LayerNode.tags({ app: [] })
|
||||||
const make = tags.make("app")
|
const make = tags.make("app")
|
||||||
const build = <A, E>(root: LayerNode.Node<A, E, any>, replacements?: readonly LayerNode.Replacement[]) =>
|
const build = <A, E>(root: LayerNode.Node<A, E, any>, replacements?: readonly LayerNode.Replacement[]) =>
|
||||||
LayerNodeTree.compile(root, new Map(replacements?.map((item) => [item.source, item.replacement]))) as Layer.Layer<
|
LayerNode.compile(root, new Map(replacements?.map((item) => [item.source, item.replacement]))) as Layer.Layer<
|
||||||
A,
|
A,
|
||||||
E
|
E
|
||||||
>
|
>
|
||||||
@@ -31,7 +30,7 @@ describe("layer node", () => {
|
|||||||
const value = LayerNode.make({ service: Value, layer: valueLayer, deps: [] })
|
const value = LayerNode.make({ service: Value, layer: valueLayer, deps: [] })
|
||||||
const greeting = LayerNode.make({ service: Greeting, layer: greetingLayer, deps: [value] })
|
const greeting = LayerNode.make({ service: Greeting, layer: greetingLayer, deps: [value] })
|
||||||
const program = Effect.map(Greeting, (item) => item.value).pipe(
|
const program = Effect.map(Greeting, (item) => item.value).pipe(
|
||||||
Effect.provide(LayerNodeTree.compile(LayerNode.group([greeting]))),
|
Effect.provide(LayerNode.compile(LayerNode.group([greeting]))),
|
||||||
)
|
)
|
||||||
expect(await Effect.runPromise(program)).toBe("hello production")
|
expect(await Effect.runPromise(program)).toBe("hello production")
|
||||||
})
|
})
|
||||||
@@ -71,9 +70,9 @@ describe("layer node", () => {
|
|||||||
const unbound = LayerNode.unbound(Value, tags.values.app)
|
const unbound = LayerNode.unbound(Value, tags.values.app)
|
||||||
const greeting = make({ service: Greeting, layer: greetingLayer, deps: [unbound] })
|
const greeting = make({ service: Greeting, layer: greetingLayer, deps: [unbound] })
|
||||||
const tree = LayerNode.group([greeting])
|
const tree = LayerNode.group([greeting])
|
||||||
expect(() => LayerNodeTree.compile(tree)).toThrow("Unbound layer node: test/LayerNodeValue")
|
expect(() => LayerNode.compile(tree)).toThrow("Unbound layer node: test/LayerNodeValue")
|
||||||
const bound = LayerNodeTree.bind(tree, unbound, value)
|
const bound = LayerNode.bind(tree, unbound, value)
|
||||||
const layer = LayerNodeTree.compile(bound) as Layer.Layer<Greeting>
|
const layer = LayerNode.compile(bound) as Layer.Layer<Greeting>
|
||||||
const program = Effect.map(Greeting, (item) => item.value).pipe(Effect.provide(layer))
|
const program = Effect.map(Greeting, (item) => item.value).pipe(Effect.provide(layer))
|
||||||
expect(await Effect.runPromise(program)).toBe("hello production")
|
expect(await Effect.runPromise(program)).toBe("hello production")
|
||||||
})
|
})
|
||||||
@@ -155,15 +154,15 @@ describe("layer node", () => {
|
|||||||
deps: [users],
|
deps: [users],
|
||||||
})
|
})
|
||||||
|
|
||||||
const result = LayerNodeTree.hoist(LayerNode.group([app]), tags.values.global)
|
const result = LayerNode.hoist(LayerNode.group([app]), tags.values.global)
|
||||||
expect(result.node.dependencies[0]?.dependencies[0]?.dependencies[0]).toMatchObject({
|
expect(result.node.dependencies[0]?.dependencies[0]?.dependencies[0]).toMatchObject({
|
||||||
kind: "group",
|
kind: "group",
|
||||||
dependencies: [],
|
dependencies: [],
|
||||||
})
|
})
|
||||||
expect(result.hoisted.dependencies).toEqual([database])
|
expect(result.hoisted.dependencies).toEqual([database])
|
||||||
|
|
||||||
const layer = LayerNodeTree.compile(result.node).pipe(
|
const layer = LayerNode.compile(result.node).pipe(
|
||||||
Layer.provide(LayerNodeTree.compile(result.hoisted)),
|
Layer.provide(LayerNode.compile(result.hoisted)),
|
||||||
) as unknown as Layer.Layer<App>
|
) as unknown as Layer.Layer<App>
|
||||||
const program = Effect.gen(function* () {
|
const program = Effect.gen(function* () {
|
||||||
return yield* (yield* App).run
|
return yield* (yield* App).run
|
||||||
@@ -197,7 +196,7 @@ describe("layer node", () => {
|
|||||||
deps: [second],
|
deps: [second],
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(() => LayerNodeTree.hoist(LayerNode.group([left, right]), tags.values.global)).toThrow(
|
expect(() => LayerNode.hoist(LayerNode.group([left, right]), tags.values.global)).toThrow(
|
||||||
"Tag global has conflicting implementations for test/GraphDatabase",
|
"Tag global has conflicting implementations for test/GraphDatabase",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -216,7 +215,7 @@ describe("layer node", () => {
|
|||||||
layer: Layer.effect(Users, Effect.as(Database, Users.of({ list: Effect.succeed([]) }))),
|
layer: Layer.effect(Users, Effect.as(Database, Users.of({ list: Effect.succeed([]) }))),
|
||||||
deps: [LayerNode.group([database])],
|
deps: [LayerNode.group([database])],
|
||||||
})
|
})
|
||||||
const result = LayerNodeTree.hoist(LayerNode.group([users]), tags.values.global)
|
const result = LayerNode.hoist(LayerNode.group([users]), tags.values.global)
|
||||||
|
|
||||||
expect(result.node.dependencies[0]?.dependencies[0]?.dependencies[0]).toMatchObject({
|
expect(result.node.dependencies[0]?.dependencies[0]?.dependencies[0]).toMatchObject({
|
||||||
kind: "group",
|
kind: "group",
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import { Context, Effect, Layer, LayerMap, Option } from "effect"
|
import { Context, Effect, Layer, LayerMap, Option } from "effect"
|
||||||
import { LayerNode, LayerNodeTree } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { Node } from "@opencode-ai/core/effect/node"
|
import { Node } from "@opencode-ai/core/effect/app-node"
|
||||||
import { NodeBuild } from "@opencode-ai/core/effect/node-build"
|
import { NodeBuild } from "@opencode-ai/core/effect/app-node-builder"
|
||||||
import { Location } from "@opencode-ai/core/location"
|
import { Location } from "@opencode-ai/core/location"
|
||||||
import { LocationServiceMap } from "@opencode-ai/core/location-service-map"
|
import { LocationServiceMap } from "@opencode-ai/core/location-service-map"
|
||||||
import type { LocationError, LocationServices } from "@opencode-ai/core/location-services"
|
import type { LocationError, LocationServices } from "@opencode-ai/core/location-services"
|
||||||
@@ -62,7 +62,7 @@ describe("node build", () => {
|
|||||||
}) as unknown as Effect.Effect<LayerMap.LayerMap<Location.Ref, LocationServices, LocationError>, never, CycleB>
|
}) as unknown as Effect.Effect<LayerMap.LayerMap<Location.Ref, LocationServices, LocationError>, never, CycleB>
|
||||||
const mapLayer = Layer.effect(LocationServiceMap.Service, mapEffect)
|
const mapLayer = Layer.effect(LocationServiceMap.Service, mapEffect)
|
||||||
const map = Node.makeGlobalNode({ service: LocationServiceMap.Service, layer: mapLayer, deps: [b] })
|
const map = Node.makeGlobalNode({ service: LocationServiceMap.Service, layer: mapLayer, deps: [b] })
|
||||||
const graph = LayerNodeTree.bind(LayerNode.group([a]), LocationServiceMap.node, map)
|
const graph = LayerNode.bind(LayerNode.group([a]), LocationServiceMap.node, map)
|
||||||
|
|
||||||
expect(() => NodeBuild.build(graph)).toThrow("Cycle detected in layer tree")
|
expect(() => NodeBuild.build(graph)).toThrow("Cycle detected in layer tree")
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ import { tmpdir } from "node:os"
|
|||||||
import path from "node:path"
|
import path from "node:path"
|
||||||
import { Effect, Exit, Fiber, Stream } from "effect"
|
import { Effect, Exit, Fiber, Stream } from "effect"
|
||||||
import { ChildProcess } from "effect/unstable/process"
|
import { ChildProcess } from "effect/unstable/process"
|
||||||
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { AppProcess } from "@opencode-ai/core/process"
|
import { AppProcess } from "@opencode-ai/core/process"
|
||||||
import { testEffect } from "../lib/effect"
|
import { testEffect } from "../lib/effect"
|
||||||
|
|
||||||
const it = testEffect(AppProcess.defaultLayer)
|
const it = testEffect(LayerNode.compile(AppProcess.node))
|
||||||
|
|
||||||
const NODE = process.execPath
|
const NODE = process.execPath
|
||||||
const cmd = (...args: string[]) => ChildProcess.make(NODE, args)
|
const cmd = (...args: string[]) => ChildProcess.make(NODE, args)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { httpClient } from "@opencode-ai/core/effect/layer-node-platform"
|
import { httpClient } from "@opencode-ai/core/effect/app-node-platform"
|
||||||
import { Cache, Clock, Duration, Effect, Layer, Option, Schema, SchemaGetter, Context } from "effect"
|
import { Cache, Clock, Duration, Effect, Layer, Option, Schema, SchemaGetter, Context } from "effect"
|
||||||
import { serviceUse } from "@opencode-ai/core/effect/service-use"
|
import { serviceUse } from "@opencode-ai/core/effect/service-use"
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { httpClient } from "@opencode-ai/core/effect/layer-node-platform"
|
import { httpClient } from "@opencode-ai/core/effect/app-node-platform"
|
||||||
import { serviceUse } from "@opencode-ai/core/effect/service-use"
|
import { serviceUse } from "@opencode-ai/core/effect/service-use"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { pathToFileURL } from "url"
|
import { pathToFileURL } from "url"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { httpClient } from "@opencode-ai/core/effect/layer-node-platform"
|
import { httpClient } from "@opencode-ai/core/effect/app-node-platform"
|
||||||
import { Context, Effect, FiberMap, Iterable, Layer, Schema, Stream } from "effect"
|
import { Context, Effect, FiberMap, Iterable, Layer, Schema, Stream } from "effect"
|
||||||
import { serviceUse } from "@opencode-ai/core/effect/service-use"
|
import { serviceUse } from "@opencode-ai/core/effect/service-use"
|
||||||
import { FetchHttpClient, HttpBody, HttpClient, HttpClientError, HttpClientRequest } from "effect/unstable/http"
|
import { FetchHttpClient, HttpBody, HttpClient, HttpClientError, HttpClientRequest } from "effect/unstable/http"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { httpClient } from "@opencode-ai/core/effect/layer-node-platform"
|
import { httpClient } from "@opencode-ai/core/effect/app-node-platform"
|
||||||
import { Effect, Layer, Schema, Context, Stream } from "effect"
|
import { Effect, Layer, Schema, Context, Stream } from "effect"
|
||||||
import { serviceUse } from "@opencode-ai/core/effect/service-use"
|
import { serviceUse } from "@opencode-ai/core/effect/service-use"
|
||||||
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
||||||
|
|||||||
@@ -52,8 +52,7 @@ import { RuntimeFlags } from "@/effect/runtime-flags"
|
|||||||
import { MoveSession } from "@opencode-ai/core/control-plane/move-session"
|
import { MoveSession } from "@opencode-ai/core/control-plane/move-session"
|
||||||
import { Database } from "@opencode-ai/core/database/database"
|
import { Database } from "@opencode-ai/core/database/database"
|
||||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { LayerNodeTree } from "@opencode-ai/core/effect/layer-node"
|
import { httpClient } from "@opencode-ai/core/effect/app-node-platform"
|
||||||
import { httpClient } from "@opencode-ai/core/effect/layer-node-platform"
|
|
||||||
import { EventV2 } from "@opencode-ai/core/event"
|
import { EventV2 } from "@opencode-ai/core/event"
|
||||||
import { ModelsDev } from "@opencode-ai/core/models-dev"
|
import { ModelsDev } from "@opencode-ai/core/models-dev"
|
||||||
import { Npm } from "@opencode-ai/core/npm"
|
import { Npm } from "@opencode-ai/core/npm"
|
||||||
@@ -302,7 +301,7 @@ export function createRoutes(
|
|||||||
),
|
),
|
||||||
Layer.provide(locationServiceMapLayer),
|
Layer.provide(locationServiceMapLayer),
|
||||||
|
|
||||||
Layer.provide(LayerNodeTree.compile(app)),
|
Layer.provide(LayerNode.compile(app)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { httpClient } from "@opencode-ai/core/effect/layer-node-platform"
|
import { httpClient } from "@opencode-ai/core/effect/app-node-platform"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { SessionV1 } from "@opencode-ai/core/v1/session"
|
import { SessionV1 } from "@opencode-ai/core/v1/session"
|
||||||
import { Effect, Layer, Context } from "effect"
|
import { Effect, Layer, Context } from "effect"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { llmClient } from "@opencode-ai/core/effect/layer-node-platform"
|
import { llmClient } from "@opencode-ai/core/effect/app-node-platform"
|
||||||
import { PermissionV1 } from "@opencode-ai/core/v1/permission"
|
import { PermissionV1 } from "@opencode-ai/core/v1/permission"
|
||||||
import { Provider } from "@/provider/provider"
|
import { Provider } from "@/provider/provider"
|
||||||
import { SessionV1 } from "@opencode-ai/core/v1/session"
|
import { SessionV1 } from "@opencode-ai/core/v1/session"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { httpClient } from "@opencode-ai/core/effect/layer-node-platform"
|
import { httpClient } from "@opencode-ai/core/effect/app-node-platform"
|
||||||
import type * as SDK from "@opencode-ai/sdk/v2"
|
import type * as SDK from "@opencode-ai/sdk/v2"
|
||||||
import { serviceUse } from "@opencode-ai/core/effect/service-use"
|
import { serviceUse } from "@opencode-ai/core/effect/service-use"
|
||||||
import { Effect, Exit, Layer, Option, Schema, Scope, Context, Stream } from "effect"
|
import { Effect, Exit, Layer, Option, Schema, Scope, Context, Stream } from "effect"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { httpClient, path } from "@opencode-ai/core/effect/layer-node-platform"
|
import { httpClient, path } from "@opencode-ai/core/effect/app-node-platform"
|
||||||
import { NodePath } from "@effect/platform-node"
|
import { NodePath } from "@effect/platform-node"
|
||||||
import { Effect, Layer, Path, Schema, Context } from "effect"
|
import { Effect, Layer, Path, Schema, Context } from "effect"
|
||||||
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { httpClient } from "@opencode-ai/core/effect/layer-node-platform"
|
import { httpClient } from "@opencode-ai/core/effect/app-node-platform"
|
||||||
import { Ripgrep } from "@opencode-ai/core/ripgrep"
|
import { Ripgrep } from "@opencode-ai/core/ripgrep"
|
||||||
import { PlanExitTool } from "./plan"
|
import { PlanExitTool } from "./plan"
|
||||||
import { Session } from "@/session/session"
|
import { Session } from "@/session/session"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { path } from "@opencode-ai/core/effect/layer-node-platform"
|
import { path } from "@opencode-ai/core/effect/app-node-platform"
|
||||||
import { Global } from "@opencode-ai/core/global"
|
import { Global } from "@opencode-ai/core/global"
|
||||||
import { InstanceLayer } from "@/project/instance-layer"
|
import { InstanceLayer } from "@/project/instance-layer"
|
||||||
import { InstanceStore } from "@/project/instance-store"
|
import { InstanceStore } from "@/project/instance-store"
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
import { $ } from "bun"
|
import { $ } from "bun"
|
||||||
import { LayerNodeTree } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { describe, expect } from "bun:test"
|
import { describe, expect } from "bun:test"
|
||||||
import fs from "fs/promises"
|
import fs from "fs/promises"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { Effect } from "effect"
|
import { Effect } from "effect"
|
||||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
|
||||||
import { Git } from "../../src/git"
|
import { Git } from "../../src/git"
|
||||||
import { tmpdir } from "../fixture/fixture"
|
import { tmpdir } from "../fixture/fixture"
|
||||||
import { testEffect } from "../lib/effect"
|
import { testEffect } from "../lib/effect"
|
||||||
|
|
||||||
const weird = process.platform === "win32" ? "space file.txt" : "tab\tfile.txt"
|
const weird = process.platform === "win32" ? "space file.txt" : "tab\tfile.txt"
|
||||||
const it = testEffect(LayerNodeTree.compile(LayerNode.group([Git.node])))
|
const it = testEffect(LayerNode.compile(LayerNode.group([Git.node])))
|
||||||
|
|
||||||
const scopedTmpdir = (options?: Parameters<typeof tmpdir>[0]) =>
|
const scopedTmpdir = (options?: Parameters<typeof tmpdir>[0]) =>
|
||||||
Effect.acquireRelease(
|
Effect.acquireRelease(
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import { LayerNodeTree } from "@opencode-ai/core/effect/layer-node"
|
|
||||||
import { SessionV1 } from "@opencode-ai/core/v1/session"
|
|
||||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
|
import { SessionV1 } from "@opencode-ai/core/v1/session"
|
||||||
import { SessionProjector } from "@opencode-ai/core/session/projector"
|
import { SessionProjector } from "@opencode-ai/core/session/projector"
|
||||||
import { Effect, Option } from "effect"
|
import { Effect, Option } from "effect"
|
||||||
import { Session as SessionNs } from "@/session/session"
|
import { Session as SessionNs } from "@/session/session"
|
||||||
@@ -13,7 +12,7 @@ import { testEffect } from "../lib/effect"
|
|||||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||||
import { ModelV2 } from "@opencode-ai/core/model"
|
import { ModelV2 } from "@opencode-ai/core/model"
|
||||||
|
|
||||||
const it = testEffect(LayerNodeTree.compile(LayerNode.group([SessionNs.node, MessageV2.node, SessionProjector.node])))
|
const it = testEffect(LayerNode.compile(LayerNode.group([SessionNs.node, MessageV2.node, SessionProjector.node])))
|
||||||
|
|
||||||
const withSession = <A, E, R>(
|
const withSession = <A, E, R>(
|
||||||
fn: (input: { session: SessionNs.Interface; sessionID: SessionID }) => Effect.Effect<A, E, R>,
|
fn: (input: { session: SessionNs.Interface; sessionID: SessionID }) => Effect.Effect<A, E, R>,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { SessionV1 } from "@opencode-ai/core/v1/session"
|
import { SessionV1 } from "@opencode-ai/core/v1/session"
|
||||||
import { Database } from "@opencode-ai/core/database/database"
|
import { Database } from "@opencode-ai/core/database/database"
|
||||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { LayerNodeTree } from "@opencode-ai/core/effect/layer-node"
|
|
||||||
import { EventV2Bridge } from "@/event-v2-bridge"
|
import { EventV2Bridge } from "@/event-v2-bridge"
|
||||||
import { expect } from "bun:test"
|
import { expect } from "bun:test"
|
||||||
import { tool } from "ai"
|
import { tool } from "ai"
|
||||||
@@ -180,7 +179,7 @@ const replacements = [
|
|||||||
LayerNode.replace(SessionSummary.layer, summary),
|
LayerNode.replace(SessionSummary.layer, summary),
|
||||||
LayerNode.replace(RuntimeFlags.defaultLayer, RuntimeFlags.layer({ experimentalEventSystem: true })),
|
LayerNode.replace(RuntimeFlags.defaultLayer, RuntimeFlags.layer({ experimentalEventSystem: true })),
|
||||||
]
|
]
|
||||||
const env = LayerNodeTree.compile(
|
const env = LayerNode.compile(
|
||||||
LayerNode.group([root, LayerNode.make({ service: TestLLMServer, layer: TestLLMServer.layer, deps: [] })]),
|
LayerNode.group([root, LayerNode.make({ service: TestLLMServer, layer: TestLLMServer.layer, deps: [] })]),
|
||||||
new Map(replacements.map((item) => [item.source, item.replacement])),
|
new Map(replacements.map((item) => [item.source, item.replacement])),
|
||||||
)
|
)
|
||||||
@@ -207,7 +206,7 @@ const providerErrorLLM = Layer.succeed(
|
|||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
const providerErrorEnv = LayerNodeTree.compile(
|
const providerErrorEnv = LayerNode.compile(
|
||||||
root,
|
root,
|
||||||
new Map(
|
new Map(
|
||||||
[...replacements, LayerNode.replace(LLM.layer, providerErrorLLM)].map((item) => [item.source, item.replacement]),
|
[...replacements, LayerNode.replace(LLM.layer, providerErrorLLM)].map((item) => [item.source, item.replacement]),
|
||||||
@@ -229,7 +228,7 @@ const fragmentFailureLLM = Layer.succeed(
|
|||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
const fragmentFailureEnv = LayerNodeTree.compile(
|
const fragmentFailureEnv = LayerNode.compile(
|
||||||
root,
|
root,
|
||||||
new Map(
|
new Map(
|
||||||
[...replacements, LayerNode.replace(LLM.layer, fragmentFailureLLM)].map((item) => [item.source, item.replacement]),
|
[...replacements, LayerNode.replace(LLM.layer, fragmentFailureLLM)].map((item) => [item.source, item.replacement]),
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import { LayerNodeTree } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { SessionV1 } from "@opencode-ai/core/v1/session"
|
import { SessionV1 } from "@opencode-ai/core/v1/session"
|
||||||
import type { NamedError } from "@opencode-ai/core/util/error"
|
import type { NamedError } from "@opencode-ai/core/util/error"
|
||||||
import { APICallError } from "ai"
|
import { APICallError } from "ai"
|
||||||
import { setTimeout as sleep } from "node:timers/promises"
|
import { setTimeout as sleep } from "node:timers/promises"
|
||||||
import { Effect, Schedule, Schema } from "effect"
|
import { Effect, Schedule, Schema } from "effect"
|
||||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
|
||||||
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
||||||
import { SessionRetry } from "../../src/session/retry"
|
import { SessionRetry } from "../../src/session/retry"
|
||||||
import { MessageV2 } from "../../src/session/message-v2"
|
import { MessageV2 } from "../../src/session/message-v2"
|
||||||
@@ -17,7 +16,7 @@ import { ProviderV2 } from "@opencode-ai/core/provider"
|
|||||||
|
|
||||||
const providerID = ProviderV2.ID.make("test")
|
const providerID = ProviderV2.ID.make("test")
|
||||||
const retryProvider = "test"
|
const retryProvider = "test"
|
||||||
const it = testEffect(LayerNodeTree.compile(LayerNode.group([SessionStatus.node, CrossSpawnSpawner.node])))
|
const it = testEffect(LayerNode.compile(LayerNode.group([SessionStatus.node, CrossSpawnSpawner.node])))
|
||||||
|
|
||||||
function apiError(headers?: Record<string, string>): SessionV1.APIError {
|
function apiError(headers?: Record<string, string>): SessionV1.APIError {
|
||||||
return Schema.decodeUnknownSync(SessionV1.APIError.Schema)(
|
return Schema.decodeUnknownSync(SessionV1.APIError.Schema)(
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
import { expect } from "bun:test"
|
import { expect } from "bun:test"
|
||||||
import { Effect, Layer } from "effect"
|
import { Effect, Layer } from "effect"
|
||||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { LayerNodeTree } from "@opencode-ai/core/effect/layer-node"
|
|
||||||
import fs from "fs/promises"
|
import fs from "fs/promises"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { Session } from "@/session/session"
|
import { Session } from "@/session/session"
|
||||||
@@ -88,7 +87,7 @@ const root = LayerNode.group([
|
|||||||
LayerNode.make({ service: TestLLMServer, layer: TestLLMServer.layer, deps: [] }),
|
LayerNode.make({ service: TestLLMServer, layer: TestLLMServer.layer, deps: [] }),
|
||||||
])
|
])
|
||||||
const it = testEffect(
|
const it = testEffect(
|
||||||
LayerNodeTree.compile(
|
LayerNode.compile(
|
||||||
root,
|
root,
|
||||||
new Map(
|
new Map(
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ import { beforeEach, describe, expect } from "bun:test"
|
|||||||
import { Effect, Exit, Layer, Option } from "effect"
|
import { Effect, Exit, Layer, Option } from "effect"
|
||||||
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
||||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { LayerNodeTree } from "@opencode-ai/core/effect/layer-node"
|
import { httpClient } from "@opencode-ai/core/effect/app-node-platform"
|
||||||
import { httpClient } from "@opencode-ai/core/effect/layer-node-platform"
|
|
||||||
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
||||||
import { SessionProjector } from "@opencode-ai/core/session/projector"
|
import { SessionProjector } from "@opencode-ai/core/session/projector"
|
||||||
|
|
||||||
@@ -20,7 +19,7 @@ import { provideTmpdirInstance } from "../fixture/fixture"
|
|||||||
import { resetDatabase } from "../fixture/db"
|
import { resetDatabase } from "../fixture/db"
|
||||||
import { pollWithTimeout, testEffect } from "../lib/effect"
|
import { pollWithTimeout, testEffect } from "../lib/effect"
|
||||||
|
|
||||||
const env = LayerNodeTree.compile(LayerNode.group([CrossSpawnSpawner.node]))
|
const env = LayerNode.compile(LayerNode.group([CrossSpawnSpawner.node]))
|
||||||
const it = testEffect(env)
|
const it = testEffect(env)
|
||||||
|
|
||||||
const json = (req: Parameters<typeof HttpClientResponse.fromWeb>[0], body: unknown, status = 200) =>
|
const json = (req: Parameters<typeof HttpClientResponse.fromWeb>[0], body: unknown, status = 200) =>
|
||||||
@@ -36,7 +35,7 @@ const none = HttpClient.make(() => Effect.die("unexpected http call"))
|
|||||||
|
|
||||||
function requestLayer(client: HttpClient.HttpClient) {
|
function requestLayer(client: HttpClient.HttpClient) {
|
||||||
const replacement = LayerNode.replace(FetchHttpClient.layer, Layer.succeed(HttpClient.HttpClient, client))
|
const replacement = LayerNode.replace(FetchHttpClient.layer, Layer.succeed(HttpClient.HttpClient, client))
|
||||||
return LayerNodeTree.compile(
|
return LayerNode.compile(
|
||||||
LayerNode.group([ShareNext.node, AccountRepo.node]),
|
LayerNode.group([ShareNext.node, AccountRepo.node]),
|
||||||
new Map([[replacement.source, replacement.replacement]]),
|
new Map([[replacement.source, replacement.replacement]]),
|
||||||
)
|
)
|
||||||
@@ -44,7 +43,7 @@ function requestLayer(client: HttpClient.HttpClient) {
|
|||||||
|
|
||||||
function integrationLayer(client: HttpClient.HttpClient) {
|
function integrationLayer(client: HttpClient.HttpClient) {
|
||||||
const replacement = LayerNode.replace(FetchHttpClient.layer, Layer.succeed(HttpClient.HttpClient, client))
|
const replacement = LayerNode.replace(FetchHttpClient.layer, Layer.succeed(HttpClient.HttpClient, client))
|
||||||
return LayerNodeTree.compile(
|
return LayerNode.compile(
|
||||||
LayerNode.group([
|
LayerNode.group([
|
||||||
ShareNext.node,
|
ShareNext.node,
|
||||||
EventV2Bridge.node,
|
EventV2Bridge.node,
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import fs from "fs/promises"
|
|||||||
import { fileURLToPath, pathToFileURL } from "url"
|
import { fileURLToPath, pathToFileURL } from "url"
|
||||||
import { Effect, Layer, Result, Schema } from "effect"
|
import { Effect, Layer, Result, Schema } from "effect"
|
||||||
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { LayerNodeTree } from "@opencode-ai/core/effect/layer-node"
|
|
||||||
import { ToolRegistry } from "@/tool/registry"
|
import { ToolRegistry } from "@/tool/registry"
|
||||||
import { Tool } from "@/tool/tool"
|
import { Tool } from "@/tool/tool"
|
||||||
import { disposeAllInstances, TestInstance } from "../fixture/fixture"
|
import { disposeAllInstances, TestInstance } from "../fixture/fixture"
|
||||||
@@ -55,9 +54,9 @@ const replacements = [
|
|||||||
LayerNode.replace(RuntimeFlags.defaultLayer, RuntimeFlags.layer()),
|
LayerNode.replace(RuntimeFlags.defaultLayer, RuntimeFlags.layer()),
|
||||||
]
|
]
|
||||||
|
|
||||||
const it = testEffect(LayerNodeTree.compile(root, new Map(replacements.map((item) => [item.source, item.replacement]))))
|
const it = testEffect(LayerNode.compile(root, new Map(replacements.map((item) => [item.source, item.replacement]))))
|
||||||
const withBrokenPlugin = testEffect(
|
const withBrokenPlugin = testEffect(
|
||||||
LayerNodeTree.compile(
|
LayerNode.compile(
|
||||||
root,
|
root,
|
||||||
new Map(
|
new Map(
|
||||||
[...replacements, LayerNode.replace(Plugin.layer, brokenPluginLayer)].map((item) => [
|
[...replacements, LayerNode.replace(Plugin.layer, brokenPluginLayer)].map((item) => [
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export * as PtyEnvironment from "./pty-environment"
|
export * as PtyEnvironment from "./pty-environment"
|
||||||
|
|
||||||
import { Context, Effect, Layer } from "effect"
|
import { Context, Effect, Layer } from "effect"
|
||||||
import { makeGlobalNode } from "@opencode-ai/core/effect/node"
|
import { makeGlobalNode } from "@opencode-ai/core/effect/app-node"
|
||||||
|
|
||||||
export interface Interface {
|
export interface Interface {
|
||||||
readonly get: (input: { directory: string; cwd: string }) => Effect.Effect<Record<string, string>>
|
readonly get: (input: { directory: string; cwd: string }) => Effect.Effect<Record<string, string>>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Database } from "@opencode-ai/core/database/database"
|
import { Database } from "@opencode-ai/core/database/database"
|
||||||
import { LayerNode, LayerNodeTree } from "@opencode-ai/core/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
||||||
import { httpClient } from "@opencode-ai/core/effect/layer-node-platform"
|
import { httpClient } from "@opencode-ai/core/effect/app-node-platform"
|
||||||
import { NodeBuild } from "@opencode-ai/core/effect/node-build"
|
import { NodeBuild } from "@opencode-ai/core/effect/app-node-builder"
|
||||||
import { EventV2 } from "@opencode-ai/core/event"
|
import { EventV2 } from "@opencode-ai/core/event"
|
||||||
import { Credential } from "@opencode-ai/core/credential"
|
import { Credential } from "@opencode-ai/core/credential"
|
||||||
import { PermissionSaved } from "@opencode-ai/core/permission/saved"
|
import { PermissionSaved } from "@opencode-ai/core/permission/saved"
|
||||||
@@ -50,7 +50,7 @@ export function createEmbeddedRoutes() {
|
|||||||
|
|
||||||
function makeRoutes<AuthError, AuthServices>(auth: Layer.Layer<ServerAuth.Config, AuthError, AuthServices>) {
|
function makeRoutes<AuthError, AuthServices>(auth: Layer.Layer<ServerAuth.Config, AuthError, AuthServices>) {
|
||||||
const serviceLayer = NodeBuild.build(
|
const serviceLayer = NodeBuild.build(
|
||||||
LayerNodeTree.bind(applicationServices, SessionExecution.node, SessionExecutionLocal.node),
|
LayerNode.bind(applicationServices, SessionExecution.node, SessionExecutionLocal.node),
|
||||||
)
|
)
|
||||||
|
|
||||||
return HttpApiBuilder.layer(Api, { openapiPath: "/openapi.json" }).pipe(
|
return HttpApiBuilder.layer(Api, { openapiPath: "/openapi.json" }).pipe(
|
||||||
|
|||||||
Reference in New Issue
Block a user