9e0d3976e1
Co-authored-by: Frank <frank@anoma.ly> Co-authored-by: Aarav Sareen <96787824+arvsrn@users.noreply.github.com> Co-authored-by: Brendan Allan <git@brendonovich.dev> Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com> Co-authored-by: Jack <jack@anoma.ly> Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com> Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com> Co-authored-by: James Long <longster@gmail.com> Co-authored-by: Dustin Deus <deusdustin@gmail.com> Co-authored-by: starptech <starptech@starptechs-MBP.fritz.box> Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com> Co-authored-by: 𝓛𝓲𝓽𝓽𝓵𝓮 𝓕𝓻𝓪𝓷𝓴 <little-frank@opencord.local> Co-authored-by: Dax <mail@thdxr.com> Co-authored-by: usrnk1 <7547651+usrnk1@users.noreply.github.com> Co-authored-by: Jay <53023+jayair@users.noreply.github.com> Co-authored-by: runvip <164729189+runvip@users.noreply.github.com> Co-authored-by: opencode <opencode@sst.dev> Co-authored-by: Julian Coy <julian@ex-machina.co> Co-authored-by: Vladimir Glafirov <vglafirov@gitlab.com> Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com> Co-authored-by: Kit Langton <kit.langton@gmail.com> Co-authored-by: Simon Klee <hello@simonklee.dk> Co-authored-by: Jay <air@live.ca> Co-authored-by: David Hill <1879069+iamdavidhill@users.noreply.github.com>
38 lines
1.2 KiB
TypeScript
38 lines
1.2 KiB
TypeScript
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
|
import { Context, Effect, Layer } from "effect"
|
|
import open from "open"
|
|
|
|
export interface Interface {
|
|
readonly open: (url: string) => Effect.Effect<void, Error>
|
|
}
|
|
|
|
export class Service extends Context.Service<Service, Interface>()("@opencode/McpBrowser") {}
|
|
|
|
const layer = Layer.succeed(
|
|
Service,
|
|
Service.of({
|
|
open: Effect.fn("McpBrowser.open")(function* (url: string) {
|
|
const subprocess = yield* Effect.tryPromise({
|
|
try: () => open(url),
|
|
catch: (error) => (error instanceof Error ? error : new Error(String(error))),
|
|
})
|
|
yield* Effect.callback<void, Error>((resume) => {
|
|
const timer = setTimeout(() => resume(Effect.void), 500)
|
|
subprocess.on("error", (error) => {
|
|
clearTimeout(timer)
|
|
resume(Effect.fail(error))
|
|
})
|
|
subprocess.on("exit", (code) => {
|
|
if (code === null || code === 0) return
|
|
clearTimeout(timer)
|
|
resume(Effect.fail(new Error(`Browser open failed with exit code ${code}`)))
|
|
})
|
|
})
|
|
}),
|
|
}),
|
|
)
|
|
|
|
export const node = LayerNode.make({ service: Service, layer, deps: [] })
|
|
|
|
export * as McpBrowser from "./browser"
|