mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-24 18:46:26 +00:00
Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bc9f6ea09 | ||
|
|
aa8c1f6dac | ||
|
|
23c3a1461c | ||
|
|
50a8539e4b | ||
|
|
7b47589225 | ||
|
|
84275c6e9d | ||
|
|
793ea52fa7 | ||
|
|
40380ad9b5 |
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@opencode-ai/plugin": patch
|
||||
"@opencode-ai/core": patch
|
||||
---
|
||||
|
||||
Compile Effect-authored plugins to the runtime-neutral Promise and Standard Schema plugin contract.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"@opencode-ai/plugin": patch
|
||||
---
|
||||
|
||||
Export the Effect runtime used by Effect plugins and safely adapt its tool schemas across host module instances.
|
||||
@@ -89,6 +89,12 @@ jobs:
|
||||
working-directory: packages/codemode
|
||||
run: bun run script/publish.ts --dry-run
|
||||
|
||||
- name: Verify packed workerd SDK
|
||||
if: runner.os == 'Linux'
|
||||
timeout-minutes: 15
|
||||
working-directory: packages/sdk
|
||||
run: bun run verify:package
|
||||
|
||||
- name: Verify compiled service lifecycle
|
||||
if: always()
|
||||
timeout-minutes: 10
|
||||
|
||||
@@ -579,7 +579,6 @@
|
||||
"@opencode-ai/protocol": "workspace:*",
|
||||
"@opencode-ai/schema": "workspace:*",
|
||||
"@standard-schema/spec": "catalog:",
|
||||
"effect": "catalog:",
|
||||
"zod": "catalog:",
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -590,19 +589,22 @@
|
||||
"@tsconfig/node22": "catalog:",
|
||||
"@types/node": "catalog:",
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"effect": "catalog:",
|
||||
"solid-js": "catalog:",
|
||||
"typescript": "catalog:",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opencode-ai/theme": "workspace:*",
|
||||
"@opentui/core": ">=0.5.7",
|
||||
"@opentui/solid": ">=0.5.7",
|
||||
"@opentui/core": ">=0.5.8",
|
||||
"@opentui/solid": ">=0.5.8",
|
||||
"effect": "catalog:",
|
||||
"solid-js": ">=1.9.0",
|
||||
},
|
||||
"optionalPeers": [
|
||||
"@opencode-ai/theme",
|
||||
"@opentui/core",
|
||||
"@opentui/solid",
|
||||
"effect",
|
||||
"solid-js",
|
||||
],
|
||||
},
|
||||
@@ -1090,9 +1092,9 @@
|
||||
"@npmcli/arborist": "9.4.0",
|
||||
"@octokit/rest": "22.0.0",
|
||||
"@openauthjs/openauth": "0.0.0-20250322224806",
|
||||
"@opentui/core": "0.5.7",
|
||||
"@opentui/keymap": "0.5.7",
|
||||
"@opentui/solid": "0.5.7",
|
||||
"@opentui/core": "0.5.8",
|
||||
"@opentui/keymap": "0.5.8",
|
||||
"@opentui/solid": "0.5.8",
|
||||
"@pierre/diffs": "1.2.10",
|
||||
"@playwright/test": "1.59.1",
|
||||
"@sentry/solid": "10.36.0",
|
||||
@@ -2218,27 +2220,27 @@
|
||||
|
||||
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.43.0", "", {}, "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg=="],
|
||||
|
||||
"@opentui/core": ["@opentui/core@0.5.7", "", { "dependencies": { "bun-ffi-structs": "0.3.1", "diff": "9.0.0", "marked": "17.0.1", "string-width": "7.2.0", "strip-ansi": "7.1.2" }, "optionalDependencies": { "@opentui/core-darwin-arm64": "0.5.7", "@opentui/core-darwin-x64": "0.5.7", "@opentui/core-linux-arm64": "0.5.7", "@opentui/core-linux-arm64-musl": "0.5.7", "@opentui/core-linux-x64": "0.5.7", "@opentui/core-linux-x64-musl": "0.5.7", "@opentui/core-win32-arm64": "0.5.7", "@opentui/core-win32-x64": "0.5.7" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-/XDabTkfBs2Wy2FhlC4jvzbpphYAs4SlnCRKYEvi+metlXNTSAshSs43wqZ9O4IPd0E4EcQqdfeQ0sdc3yPpYw=="],
|
||||
"@opentui/core": ["@opentui/core@0.5.8", "", { "dependencies": { "bun-ffi-structs": "0.3.1", "diff": "9.0.0", "marked": "17.0.1", "string-width": "7.2.0", "strip-ansi": "7.1.2" }, "optionalDependencies": { "@opentui/core-darwin-arm64": "0.5.8", "@opentui/core-darwin-x64": "0.5.8", "@opentui/core-linux-arm64": "0.5.8", "@opentui/core-linux-arm64-musl": "0.5.8", "@opentui/core-linux-x64": "0.5.8", "@opentui/core-linux-x64-musl": "0.5.8", "@opentui/core-win32-arm64": "0.5.8", "@opentui/core-win32-x64": "0.5.8" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-GbZ+nSLYZqxj2Z5TU19Mx6IsAvVsn2+7WEXz+6OlMGoootvt3TxP3vWwfGI0jWk9qp1ftRlML1JPNEkzy+9I8g=="],
|
||||
|
||||
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.5.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-75TDJgFD6hDoCElIX35Yg3TIRF/jhrtVQO/9snhjGuTsZ7bd0W88jUlvSXSNhqB3CX431rwgi47B+asWPDI1lQ=="],
|
||||
"@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.5.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-c9Y1FBrSnA4sKUCMETsrLYOmsMTyJae8mU9cE6M4o9rXcr3ZLPA7o9AkPA3S0+kH+kZ0o1Fn0wLejgNxvEp5mg=="],
|
||||
|
||||
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.5.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-j+Dwu2yV8zahBFjnVIssYdPrHz/+pkd7xWxI+nHjV41V3c+scvH6vJY1U85VCVaoQs/zCH5xAJbmAAn7Sgeh8g=="],
|
||||
"@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.5.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-oZ/6Iz1KN+4volMFKmmvziYJhMgyyJ99LfK1S+uPRyIRqzT3CESoJ58D4h04M1g0dHeHE4PvkU1p3uQKrXiP3g=="],
|
||||
|
||||
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.5.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-gWO9NWaivXRPc0XhEbxehj3ApyC1SW8Bf1cnHnME1zhw/EZNCNE3TQHgKwOnnNKtvlbhzLQjOI4OqyPYV8UcEQ=="],
|
||||
"@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.5.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-N6i/ocrsTjIq9aUQyrfJkqUo+tc4P5ZS6xz38Cm1MhtDzwBE+CrNIJdHfoJfmRLhJkYHlw6Z0ToICn8ZNj4Bpw=="],
|
||||
|
||||
"@opentui/core-linux-arm64-musl": ["@opentui/core-linux-arm64-musl@0.5.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-RumSHTasIAWU7jPBKiTuEZG/m+prfQKCHhL3JAQnBLgp7eAB20XZGfSLVWDBgxkyKq1rHCUgLtZktC5ZAyKfTA=="],
|
||||
"@opentui/core-linux-arm64-musl": ["@opentui/core-linux-arm64-musl@0.5.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-eFMB41AWODaYf8PsCx3vtTMX33tFgtSpR9tKNnUErCXlcnZ+WCRHVaJ9F6DrVNX3ir6HmgbwAmaWXvaVF+kLtg=="],
|
||||
|
||||
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.5.7", "", { "os": "linux", "cpu": "x64" }, "sha512-fXDmrIlfp9xaoVkk3BNn3yUO/b7plBSOfUh2oWOezRA6E/g5z+hTO1alGFQCy+VV+1kfA6iuYadAww0xNtfACg=="],
|
||||
"@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.5.8", "", { "os": "linux", "cpu": "x64" }, "sha512-/2QM7/wMnML/sxchzbwgoU5tUu/7k836/kSOKMti8opjuecv1K+WWNKGXufhTNeRcXFZaba5rsCdYrf3VqnVsQ=="],
|
||||
|
||||
"@opentui/core-linux-x64-musl": ["@opentui/core-linux-x64-musl@0.5.7", "", { "os": "linux", "cpu": "x64" }, "sha512-1opDV+W7C1F4iWivCNKuYl5Hen+IeFXAuUPm3hVyN0UtdcP8LESpFJTr8QRwHpGSE9Jz1K2g2S2ipzI3u5mhgw=="],
|
||||
"@opentui/core-linux-x64-musl": ["@opentui/core-linux-x64-musl@0.5.8", "", { "os": "linux", "cpu": "x64" }, "sha512-YXo+qUHYmep2uvv3ECvTeqr10aD7+lBsavYmsTLBzS5hHabbzlQ10oX/99nIRPC3Au1BMWD6d6zQP5czPx23eg=="],
|
||||
|
||||
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.5.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-gbiZUyttjq8s+bsnsaopygWN7LTS/RyzD6GOmpgOB2TVitvo0P6mxM+AebBGuu/7xri17Rqaxf3uqrgdKiJAeg=="],
|
||||
"@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.5.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-7qBdhEAlh4tLFzW7nWLPlREtNiF6NZMDMi+4uDpUlAMhRavLr6wjcIcgfhNAF/puq06DjuZlPTwaMCgB3qOuwA=="],
|
||||
|
||||
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.5.7", "", { "os": "win32", "cpu": "x64" }, "sha512-bDwon45lUxbV3rMcekTCg4mXcBu9uhdG6HLeLK5TVZf05/h+Ibkf2UeZ8A2jjQt+MK6jpYmxWwDCVCTzZ7EU7Q=="],
|
||||
"@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.5.8", "", { "os": "win32", "cpu": "x64" }, "sha512-Z76YaTKnmRDSHKdKa7iTBCXBQdInQLq7UG3qIE84nvyHCDtkhYtPWOaCzDisSgXC8Y6hJt6NiFbaNjQyxPkfpQ=="],
|
||||
|
||||
"@opentui/keymap": ["@opentui/keymap@0.5.7", "", { "dependencies": { "@opentui/core": "0.5.7" }, "peerDependencies": { "@opentui/react": "0.5.7", "@opentui/solid": "0.5.7", "react": ">=19.2.0", "solid-js": "1.9.12" }, "optionalPeers": ["@opentui/react", "@opentui/solid", "react", "solid-js"] }, "sha512-BqfSbjlLuctnew2aoPPdK3wpzJfEPp7ttLBkTu1wJTkps9AcfUgXqwloqvY4DUKjUBNFYYEpU/0CPxI4Blj4MA=="],
|
||||
"@opentui/keymap": ["@opentui/keymap@0.5.8", "", { "dependencies": { "@opentui/core": "0.5.8" }, "peerDependencies": { "@opentui/react": "0.5.8", "@opentui/solid": "0.5.8", "react": ">=19.2.0", "solid-js": "1.9.12" }, "optionalPeers": ["@opentui/react", "@opentui/solid", "react", "solid-js"] }, "sha512-KQHKRnLZroSZIbHmGmSeDPsXi7Yykdu9x9ACmDzBFkgPGx0EIuXHqRcmrqmUaX485MQEZuCD9t6FdDsOMGyIFg=="],
|
||||
|
||||
"@opentui/solid": ["@opentui/solid@0.5.7", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.5.7", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.12", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.12" } }, "sha512-qrKAZd9xt4D67LXZUARg1Aw0dwEWi29GyOxpM6abqmyExGPMS7jih5Z9oMQJ9EXsouDKpW7Mejjq7WbX2AaecQ=="],
|
||||
"@opentui/solid": ["@opentui/solid@0.5.8", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.5.8", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.12", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.12" } }, "sha512-L0NxuAU8XT+jlE5G90oA3kspqkof48b0hmzi5XLw+1gxnkxrkTb+YfKys+GzVK4UqhgwY9aW+TeDfrKbnfwCMw=="],
|
||||
|
||||
"@oslojs/asn1": ["@oslojs/asn1@1.0.0", "", { "dependencies": { "@oslojs/binary": "1.0.0" } }, "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA=="],
|
||||
|
||||
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"nodeModules": {
|
||||
"x86_64-linux": "sha256-LvDHCOm8OAZfvb0I0L6AbdOevRoQmEJnnqrSgAiNHv8=",
|
||||
"aarch64-linux": "sha256-O0L0iHjb4cwl9xWHIna8VFHyQzoAKzfY8oMpVNayMOg=",
|
||||
"aarch64-darwin": "sha256-ETP8FE71NqufYDUbR7tBdsMEOVQ44wLmsZBeZiSRBRY=",
|
||||
"x86_64-darwin": "sha256-WUcoLldDriT3QxcdlnBQhuPrxDNub0EDvvZXk/pDMpY="
|
||||
"x86_64-linux": "sha256-phyTF0/jQZ3L0B66PSLdpH//kyPc1M6j5a40wCSx7TA=",
|
||||
"aarch64-linux": "sha256-1Zb/Is0ujIslCbPPusAVhcuzAPyIauQyeIIRRGtzpAk=",
|
||||
"aarch64-darwin": "sha256-DDsVm7z+PSDry6QqrwVDFSmEnq6jIKb709Y4ymAv9f8=",
|
||||
"x86_64-darwin": "sha256-S+5LI2J+WRhRP7jp2PAv6AesXk238wEYoyIO1oKdF3w="
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -49,9 +49,9 @@
|
||||
"@octokit/rest": "22.0.0",
|
||||
"@hono/standard-validator": "0.2.0",
|
||||
"@hono/zod-validator": "0.4.2",
|
||||
"@opentui/core": "0.5.7",
|
||||
"@opentui/keymap": "0.5.7",
|
||||
"@opentui/solid": "0.5.7",
|
||||
"@opentui/core": "0.5.8",
|
||||
"@opentui/keymap": "0.5.8",
|
||||
"@opentui/solid": "0.5.8",
|
||||
"@tanstack/solid-virtual": "3.13.37",
|
||||
"@shikijs/stream": "4.2.0",
|
||||
"@standard-schema/spec": "1.1.0",
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import { Argument, Flag } from "effect/unstable/cli"
|
||||
import { Argument, Flag, GlobalFlag } from "effect/unstable/cli"
|
||||
import { Schema } from "effect"
|
||||
import { Spec } from "../framework/spec"
|
||||
|
||||
export const PrintLogs = GlobalFlag.setting("print-logs")({
|
||||
flag: Flag.boolean("print-logs").pipe(
|
||||
Flag.withDescription("Print logs to stderr (server logs require --standalone)"),
|
||||
Flag.withDefault(false),
|
||||
),
|
||||
})
|
||||
|
||||
declare const OPENCODE_CLI_NAME: string | undefined
|
||||
|
||||
const ServerParams = {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Effect, FileSystem, Scope } from "effect"
|
||||
import { Command } from "effect/unstable/cli"
|
||||
import { PrintLogs } from "../commands/commands"
|
||||
import { Spec } from "./spec"
|
||||
import { Global } from "@opencode-ai/util/global"
|
||||
import { Updater } from "../services/updater"
|
||||
@@ -77,7 +78,11 @@ export function handlers<const Root extends Spec.Any>(root: Root, handlers: Hand
|
||||
}
|
||||
|
||||
export function run(commands: Spec.Any, handlers: ReadonlyArray<LazyHandler>, options: { readonly version: string }) {
|
||||
return Command.run(provide(commands, handlers), options) as Effect.Effect<void, unknown, Command.Environment>
|
||||
return Command.run(provide(commands, handlers).pipe(Command.withGlobalFlags([PrintLogs])), options) as Effect.Effect<
|
||||
void,
|
||||
unknown,
|
||||
Command.Environment
|
||||
>
|
||||
}
|
||||
|
||||
function provide(node: Spec.Any, handlers: ReadonlyArray<LazyHandler>): ProvidedCommand {
|
||||
@@ -86,6 +91,7 @@ function provide(node: Spec.Any, handlers: ReadonlyArray<LazyHandler>): Provided
|
||||
? node.spec.pipe(
|
||||
Command.withHandler((input) =>
|
||||
Effect.gen(function* () {
|
||||
if (yield* PrintLogs) process.env.OPENCODE_PRINT_LOGS = "1"
|
||||
const module = yield* Effect.promise(handler.load)
|
||||
return yield* module.default(input)
|
||||
}),
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import "./plugin-runtime.promise"
|
||||
import "./plugin-runtime.effect"
|
||||
|
||||
process.stdout.on("error", (error) => {
|
||||
if ("code" in error && error.code === "EPIPE") return
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import {
|
||||
Agent,
|
||||
Command,
|
||||
Connection,
|
||||
Credential,
|
||||
Effect,
|
||||
Integration,
|
||||
Mcp,
|
||||
Model,
|
||||
Plugin,
|
||||
Provider,
|
||||
Reference,
|
||||
Schema,
|
||||
Skill,
|
||||
WebSearch,
|
||||
} from "@opencode-ai/plugin/effect"
|
||||
import { Tool } from "@opencode-ai/schema/tool"
|
||||
|
||||
const key = Symbol.for("opencode.plugin.v2.effect")
|
||||
;(globalThis as typeof globalThis & { [key]?: unknown })[key] = {
|
||||
Agent,
|
||||
Command,
|
||||
Connection,
|
||||
Credential,
|
||||
Effect,
|
||||
Integration,
|
||||
Mcp,
|
||||
Model,
|
||||
Plugin,
|
||||
Provider,
|
||||
Reference,
|
||||
Schema,
|
||||
Skill,
|
||||
WebSearch,
|
||||
Tool: { Error: Tool.Error },
|
||||
}
|
||||
@@ -4,13 +4,11 @@ import {
|
||||
Connection,
|
||||
Credential,
|
||||
Integration,
|
||||
Mcp,
|
||||
Model,
|
||||
Plugin,
|
||||
Provider,
|
||||
Reference,
|
||||
Skill,
|
||||
WebSearch,
|
||||
} from "@opencode-ai/plugin"
|
||||
|
||||
const key = Symbol.for("opencode.plugin.v2.promise")
|
||||
@@ -20,11 +18,9 @@ const key = Symbol.for("opencode.plugin.v2.promise")
|
||||
Connection,
|
||||
Credential,
|
||||
Integration,
|
||||
Mcp,
|
||||
Model,
|
||||
Plugin,
|
||||
Provider,
|
||||
Reference,
|
||||
Skill,
|
||||
WebSearch,
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ function command(password: string, options: Options) {
|
||||
// The server treats EOF on this pipe as the end of its ownership lease.
|
||||
// The OS closes it even when the TUI is killed before Effect finalizers run.
|
||||
stdin: "pipe",
|
||||
stderr: "ignore",
|
||||
stderr: process.env.OPENCODE_PRINT_LOGS === "1" ? "inherit" : "ignore",
|
||||
killSignal: "SIGTERM",
|
||||
forceKillAfter: "3 seconds",
|
||||
})
|
||||
|
||||
@@ -127,28 +127,15 @@ export const Command = sdk.Command
|
||||
export const Connection = sdk.Connection
|
||||
export const Credential = sdk.Credential
|
||||
export const Integration = sdk.Integration
|
||||
export const Mcp = sdk.Mcp
|
||||
export const Model = sdk.Model
|
||||
export const Plugin = sdk.Plugin
|
||||
export const Provider = sdk.Provider
|
||||
export const Reference = sdk.Reference
|
||||
export const Skill = sdk.Skill
|
||||
export const WebSearch = sdk.WebSearch`
|
||||
const effectModule = promiseModule
|
||||
.replace("opencode.plugin.v2.promise", "opencode.plugin.v2.effect")
|
||||
.replace("Promise plugin", "Effect plugin")
|
||||
.concat("\nexport const Effect = sdk.Effect\nexport const Schema = sdk.Schema")
|
||||
export const Skill = sdk.Skill`
|
||||
const promisePluginModule = `const sdk = globalThis[Symbol.for("opencode.plugin.v2.promise")]
|
||||
if (!sdk) throw new Error("OpenCode Promise plugin SDK is unavailable")
|
||||
export const define = sdk.Plugin.define`
|
||||
const effectPluginModule = promisePluginModule
|
||||
.replace("opencode.plugin.v2.promise", "opencode.plugin.v2.effect")
|
||||
.replace("Promise plugin", "Effect plugin")
|
||||
const promiseToolModule = `export {}`
|
||||
const effectToolModule = `const sdk = globalThis[Symbol.for("opencode.plugin.v2.effect")]
|
||||
if (!sdk) throw new Error("OpenCode Effect plugin SDK is unavailable")
|
||||
export const Error = sdk.Tool.Error
|
||||
`
|
||||
return `#!/usr/bin/env -S node ${nodeExecArgv.join(" ")}
|
||||
import __cjs_mod__ from "node:module"
|
||||
import { chmodSync as __ocChmod, existsSync as __ocExists, lstatSync as __ocLstat, mkdirSync as __ocMkdir, renameSync as __ocRename, rmSync as __ocRm, writeFileSync as __ocWrite } from "node:fs"
|
||||
@@ -163,17 +150,11 @@ const __ocPluginModules = ${JSON.stringify({
|
||||
"@opencode-ai/plugin": "opencode:plugin-v2",
|
||||
"@opencode-ai/plugin/promise/plugin": "opencode:plugin-promise-plugin",
|
||||
"@opencode-ai/plugin/promise/tool": "opencode:plugin-promise-tool",
|
||||
"@opencode-ai/plugin/effect": "opencode:plugin-v2-effect",
|
||||
"@opencode-ai/plugin/effect/plugin": "opencode:plugin-v2-effect-plugin",
|
||||
"@opencode-ai/plugin/effect/tool": "opencode:plugin-v2-effect-tool",
|
||||
})}
|
||||
const __ocPluginSources = ${JSON.stringify({
|
||||
"opencode:plugin-v2": promiseModule,
|
||||
"opencode:plugin-promise-plugin": promisePluginModule,
|
||||
"opencode:plugin-promise-tool": promiseToolModule,
|
||||
"opencode:plugin-v2-effect": effectModule,
|
||||
"opencode:plugin-v2-effect-plugin": effectPluginModule,
|
||||
"opencode:plugin-v2-effect-tool": effectToolModule,
|
||||
})}
|
||||
__cjs_mod__.registerHooks({
|
||||
resolve(__ocSpecifier, __ocContext, __ocNextResolve) {
|
||||
|
||||
@@ -32,3 +32,38 @@ const result = await Bun.build({
|
||||
},
|
||||
})
|
||||
if (!result.success) throw new AggregateError(result.logs, "Failed to build Core")
|
||||
|
||||
// Bun's Node target eagerly creates its shared require helper, so every split
|
||||
// entry evaluates import.meta.url even when it never requires a module. Keep
|
||||
// the helper lazy until Bun stops hoisting it into workerd-reachable chunks.
|
||||
// https://github.com/oven-sh/bun/issues/12615
|
||||
const eagerRequire = "var __require = /* @__PURE__ */ createRequire(import.meta.url);"
|
||||
const lazyRequire = `var __require = (specifier) => createRequire(import.meta.url ?? "file:///worker.js")(specifier);
|
||||
__require.resolve = (specifier, options) => createRequire(import.meta.url ?? "file:///worker.js").resolve(specifier, options);`
|
||||
const rewritten = await Promise.all(
|
||||
result.outputs.map(async (output) => {
|
||||
if (!output.path.endsWith(".js")) return false
|
||||
const source = await output.text()
|
||||
|
||||
const generatedUses = source
|
||||
.replace(/import\s*\{[^}]*\b__require\b[^}]*\}\s*from\s*["'][^"']+["'];/g, "")
|
||||
.replace(/export\s*\{[^}]*\b__require\b[^}]*\};/g, "")
|
||||
.replace(eagerRequire, "")
|
||||
if (/\bnew\s+__require\s*\(/.test(generatedUses))
|
||||
throw new Error(`Unsupported generated require constructor in ${output.path}`)
|
||||
const unsupported = generatedUses
|
||||
.replace(/\b__require\.resolve\s*\(/g, "")
|
||||
.replace(/\b__require\s*\(/g, "")
|
||||
if (/\b__require\b/.test(unsupported)) throw new Error(`Unsupported generated require usage in ${output.path}`)
|
||||
|
||||
if (!source.includes(eagerRequire)) return false
|
||||
if (source.indexOf(eagerRequire) !== source.lastIndexOf(eagerRequire))
|
||||
throw new Error(`Multiple eager require helpers in ${output.path}`)
|
||||
const rewrittenSource = source.replace(eagerRequire, lazyRequire)
|
||||
if (rewrittenSource.includes(eagerRequire)) throw new Error(`Failed to rewrite eager require helper in ${output.path}`)
|
||||
await Bun.write(output.path, rewrittenSource)
|
||||
return true
|
||||
}),
|
||||
)
|
||||
if (rewritten.filter(Boolean).length !== 1)
|
||||
throw new Error("Expected exactly one eager require helper; Bun may have fixed #12615 and made this shim removable")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as ConfigAgentPlugin from "./agent.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Document, Info, type Entry } from "@opencode-ai/schema/config"
|
||||
import { ConfigAgent } from "@opencode-ai/schema/config/agent"
|
||||
import path from "path"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as ConfigCommandPlugin from "./command.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Info, type Entry } from "@opencode-ai/schema/config"
|
||||
import { ConfigCommand } from "@opencode-ai/schema/config/command"
|
||||
import path from "path"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as ConfigCompactionPlugin from "./compaction.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Effect } from "effect"
|
||||
import { Config } from "../../config.js"
|
||||
import { SessionCompaction } from "../../session/compaction.js"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as ConfigFormatterPlugin from "./formatter.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { FSUtil } from "@opencode-ai/util/fs-util"
|
||||
import { Global } from "@opencode-ai/util/global"
|
||||
import { Npm } from "@opencode-ai/util/npm"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as ConfigImagePlugin from "./image.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Effect } from "effect"
|
||||
import { Config } from "../../config.js"
|
||||
import { Image } from "../../image.js"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as ConfigInstructionPlugin from "./instruction.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { FSUtil } from "@opencode-ai/util/fs-util"
|
||||
import { Global } from "@opencode-ai/util/global"
|
||||
import { dirname, join } from "path"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as ConfigLocationWatcherPlugin from "./location-watcher.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Effect } from "effect"
|
||||
import { Config } from "../../config.js"
|
||||
import { LocationWatcherPolicy } from "../../filesystem/location-watcher-policy.js"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as ConfigMCPPlugin from "./mcp.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Document, type Entry } from "@opencode-ai/schema/config"
|
||||
import { Mcp } from "@opencode-ai/schema/mcp"
|
||||
import { Effect, Stream } from "effect"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as ConfigPolicyPlugin from "./policy.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Document } from "@opencode-ai/schema/config"
|
||||
import { Effect } from "effect"
|
||||
import { Config } from "../../config.js"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as ConfigProviderPlugin from "./provider.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Document, type Entry } from "@opencode-ai/schema/config"
|
||||
import { Money } from "@opencode-ai/schema/money"
|
||||
import { Effect } from "effect"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as ConfigReferencePlugin from "./reference.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Document } from "@opencode-ai/schema/config"
|
||||
import { ConfigReference } from "@opencode-ai/schema/config/reference"
|
||||
import path from "path"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as ConfigShellPlugin from "./shell.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Effect } from "effect"
|
||||
import { Config } from "../../config.js"
|
||||
import { ShellSelect } from "../../shell/select.js"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as ConfigSkillPlugin from "./skill.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import type { Entry } from "@opencode-ai/schema/config"
|
||||
import { FSUtil } from "@opencode-ai/util/fs-util"
|
||||
import { Global } from "@opencode-ai/util/global"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as ConfigSnapshotPlugin from "./snapshot.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Effect } from "effect"
|
||||
import { Config } from "../../config.js"
|
||||
import { Snapshot } from "../../snapshot.js"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as ConfigToolOutputPlugin from "./tool-output.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Effect } from "effect"
|
||||
import { Config } from "../../config.js"
|
||||
import { ToolOutput } from "../../tool-output.js"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as ConfigWebSearchPlugin from "./websearch.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Effect } from "effect"
|
||||
import { Config } from "../../config.js"
|
||||
import { ConfigEntryObserver } from "./entry-observer.js"
|
||||
|
||||
@@ -572,7 +572,7 @@ function cacheKey(source: string) {
|
||||
}
|
||||
|
||||
export function bodyDigest(text: string) {
|
||||
return new Bun.CryptoHasher("sha256").update(text).digest("hex")
|
||||
return Hash.sha256(text)
|
||||
}
|
||||
|
||||
export const layer = (options?: Options) =>
|
||||
|
||||
@@ -2,7 +2,7 @@ export * as Plugin from "./plugin.js"
|
||||
export { Event, ID, Info, Source } from "@opencode-ai/schema/plugin"
|
||||
|
||||
import { Plugin } from "@opencode-ai/schema/plugin"
|
||||
import type { Plugin as PluginDefinition } from "@opencode-ai/plugin/effect/plugin"
|
||||
import type { Plugin as PluginDefinition } from "@opencode-ai/core/plugin/definition"
|
||||
import { makeLocationNode } from "@opencode-ai/util/effect/app-node"
|
||||
import { App } from "./app.js"
|
||||
import { Cause, Context, Effect, Exit, Layer, Logger, References, Scope, Semaphore } from "effect"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as AgentPlugin from "./agent.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Effect } from "effect"
|
||||
import { Agent } from "../agent.js"
|
||||
import { Permission } from "../permission.js"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as CommandPlugin from "./command.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Effect } from "effect"
|
||||
import { Location } from "../location.js"
|
||||
import PROMPT_INITIALIZE from "./command/initialize.txt"
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import type { Context as PluginContext, Plugin as PluginDefinition } from "@opencode-ai/plugin/effect/plugin"
|
||||
import type { Scope } from "effect"
|
||||
|
||||
export type Context = PluginContext
|
||||
export type Plugin<R = Scope.Scope> = PluginDefinition<R>
|
||||
|
||||
export function define<R>(plugin: PluginDefinition<R>) {
|
||||
return plugin
|
||||
}
|
||||
|
||||
export namespace Plugin {
|
||||
export type Context = PluginContext
|
||||
export type Plugin<R = Scope.Scope> = PluginDefinition<R>
|
||||
export const define = <R>(plugin: PluginDefinition<R>) => plugin
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as PluginHost from "./host.js"
|
||||
|
||||
import { Plugin } from "@opencode-ai/plugin/effect"
|
||||
import { Plugin } from "@opencode-ai/core/plugin/definition"
|
||||
import type { IntegrationMethodRegistration } from "@opencode-ai/plugin/effect/integration"
|
||||
import { EventManifest } from "@opencode-ai/schema/event-manifest"
|
||||
import { Mcp } from "@opencode-ai/schema/mcp"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as PluginInternal from "./internal.js"
|
||||
|
||||
import type { Plugin } from "@opencode-ai/plugin/effect/plugin"
|
||||
import type { Plugin } from "@opencode-ai/core/plugin/definition"
|
||||
import { LayerNode } from "@opencode-ai/util/effect/layer-node"
|
||||
import { httpClient } from "@opencode-ai/util/effect/app-node-platform"
|
||||
import { AppProcess } from "@opencode-ai/util/process"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as MCPCodeModeExclusionPlugin from "./mcp-codemode-exclusion.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Effect } from "effect"
|
||||
|
||||
// These servers provide Code Mode, so expose them directly instead of nesting them inside OpenCode Code Mode.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Integration } from "@opencode-ai/schema/integration"
|
||||
import { Effect, Stream } from "effect"
|
||||
import { Bus } from "../bus.js"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export * as PlanPlugin from "./plan.js"
|
||||
|
||||
import { Message, ToolFailure } from "@opencode-ai/ai"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Global } from "@opencode-ai/util/global"
|
||||
import { Effect, Stream } from "effect"
|
||||
import path from "path"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Effect } from "effect"
|
||||
import type { LanguageModelV3 } from "@ai-sdk/provider"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Provider } from "../../provider.js"
|
||||
|
||||
type MantleSDK = {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Effect } from "effect"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Provider } from "../../provider.js"
|
||||
|
||||
export const AnthropicPlugin = define({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Effect } from "effect"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Form } from "@opencode-ai/schema/form"
|
||||
import { Model } from "../../model.js"
|
||||
import { Provider } from "../../provider.js"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Effect } from "effect"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Provider } from "../../provider.js"
|
||||
|
||||
export const CerebrasPlugin = define({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import os from "os"
|
||||
import { App } from "../../app.js"
|
||||
import { Effect, Option, Schema } from "effect"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Form } from "@opencode-ai/schema/form"
|
||||
import { Provider } from "../../provider.js"
|
||||
import { iife } from "../../util/iife.js"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import os from "os"
|
||||
import { App } from "../../app.js"
|
||||
import { Effect } from "effect"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Form } from "@opencode-ai/schema/form"
|
||||
import { Provider } from "../../provider.js"
|
||||
import { iife } from "../../util/iife.js"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Effect } from "effect"
|
||||
import { pathToFileURL } from "url"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Npm } from "@opencode-ai/util/npm"
|
||||
import { importModule } from "@opencode-ai/util/runtime-import"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import type { AISDKHooks } from "@opencode-ai/plugin/effect/aisdk"
|
||||
import { Effect } from "effect"
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { App } from "../../app.js"
|
||||
import { Agent } from "../../agent.js"
|
||||
import { Integration } from "../../integration.js"
|
||||
import { Model } from "../../model.js"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Provider } from "../../provider.js"
|
||||
import type { PluginInternal } from "../internal.js"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import os from "os"
|
||||
import { App } from "../../app.js"
|
||||
import { Effect } from "effect"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Provider } from "../../provider.js"
|
||||
|
||||
export const GitLabPlugin = define({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Effect } from "effect"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Provider } from "../../provider.js"
|
||||
|
||||
function resolveProject(options: Record<string, any>) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Effect } from "effect"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Provider } from "../../provider.js"
|
||||
|
||||
export const KiloPlugin = define({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Effect } from "effect"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Integration } from "../../integration.js"
|
||||
import { Provider } from "../../provider.js"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Document, type Entry } from "@opencode-ai/schema/config"
|
||||
import { Duration, Effect, Schedule, Schema, Semaphore, Stream } from "effect"
|
||||
import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Effect } from "effect"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Provider } from "../../provider.js"
|
||||
|
||||
export const NvidiaPlugin = define({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Document, type Entry } from "@opencode-ai/schema/config"
|
||||
import { Duration, Effect, Schedule, Schema, Semaphore, Stream } from "effect"
|
||||
import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Effect } from "effect"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
|
||||
export const OpenAICompatiblePlugin = define({
|
||||
id: "opencode.provider.openai.compatible",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { IntegrationOAuthMethodRegistration } from "@opencode-ai/plugin/effect/integration"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Deferred, Effect, Option, Schema, Semaphore, Stream } from "effect"
|
||||
import { App } from "../../app.js"
|
||||
import { Credential } from "../../credential.js"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Duration, Effect, Schema, Semaphore, Stream } from "effect"
|
||||
import type { Scope } from "effect"
|
||||
import type { IntegrationOAuthMethodRegistration } from "@opencode-ai/plugin/effect/integration"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
||||
import { Bus } from "../../bus.js"
|
||||
import { Credential } from "../../credential.js"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Effect } from "effect"
|
||||
import { Model } from "../../model.js"
|
||||
import { Provider } from "../../provider.js"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
|
||||
export const OpenRouterPlugin = define({
|
||||
id: "opencode.provider.openrouter",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Effect } from "effect"
|
||||
import { pathToFileURL } from "url"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Npm } from "@opencode-ai/util/npm"
|
||||
import { Provider } from "../../provider.js"
|
||||
import { importModule } from "@opencode-ai/util/runtime-import"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Effect } from "effect"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Provider } from "../../provider.js"
|
||||
|
||||
type FetchLike = (url: string | URL | Request, init?: RequestInit) => Promise<Response>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Effect } from "effect"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Provider } from "../../provider.js"
|
||||
|
||||
export const VercelPlugin = define({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Document, type Entry } from "@opencode-ai/schema/config"
|
||||
import { Duration, Effect, Schedule, Schema, Semaphore, Stream } from "effect"
|
||||
import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { IntegrationOAuthMethodRegistration } from "@opencode-ai/plugin/effect/integration"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Clock, Effect, Option, Schema } from "effect"
|
||||
import { App } from "../../app.js"
|
||||
import { Credential } from "../../credential.js"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Effect } from "effect"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Provider } from "../../provider.js"
|
||||
|
||||
export const ZenmuxPlugin = define({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as SdkPlugins from "./sdk.js"
|
||||
|
||||
import type { Plugin } from "@opencode-ai/plugin/effect/plugin"
|
||||
import type { Plugin } from "@opencode-ai/core/plugin/definition"
|
||||
import { Context, Effect, Layer } from "effect"
|
||||
import { makeGlobalNode } from "@opencode-ai/util/effect/app-node"
|
||||
import { Bus } from "../bus.js"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
export * as SkillPlugin from "./skill.js"
|
||||
|
||||
import { define, type Context } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define, type Context } from "@opencode-ai/core/plugin/definition"
|
||||
import { Effect } from "effect"
|
||||
import { AbsolutePath } from "../schema.js"
|
||||
import { Skill } from "../skill.js"
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
export * as PluginSupervisor from "./supervisor.js"
|
||||
export { Service, type Interface } from "./supervisor-service.js"
|
||||
|
||||
import type { Plugin as PluginDefinition } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { instanceSafeContext } from "@opencode-ai/plugin/effect/tool-schema"
|
||||
import { Event } from "@opencode-ai/schema/config"
|
||||
import { Cause, Effect, Latch, Layer, Schema, Stream } from "effect"
|
||||
import { Cause, Effect, Latch, Layer, Predicate, Schema, Stream } from "effect"
|
||||
import path from "path"
|
||||
import { pathToFileURL } from "url"
|
||||
import { ConfigPluginSource } from "../config/plugin/source.js"
|
||||
@@ -19,22 +17,13 @@ import { importModule } from "@opencode-ai/util/runtime-import"
|
||||
import { Service } from "./supervisor-service.js"
|
||||
|
||||
const PluginModule = Schema.Struct({
|
||||
default: Schema.Union([
|
||||
Schema.Struct({
|
||||
id: Schema.String,
|
||||
tui: Schema.optional(Schema.Boolean),
|
||||
effect: Schema.declare<PluginDefinition["effect"]>(
|
||||
(input): input is PluginDefinition["effect"] => typeof input === "function",
|
||||
),
|
||||
}),
|
||||
Schema.Struct({
|
||||
id: Schema.String,
|
||||
tui: Schema.optional(Schema.Boolean),
|
||||
setup: Schema.declare<Parameters<typeof PluginPromise.fromPromise>[0]["setup"]>(
|
||||
(input): input is Parameters<typeof PluginPromise.fromPromise>[0]["setup"] => typeof input === "function",
|
||||
),
|
||||
}),
|
||||
]),
|
||||
default: Schema.Struct({
|
||||
id: Schema.String,
|
||||
tui: Schema.optional(Schema.Boolean),
|
||||
setup: Schema.declare<Parameters<typeof PluginPromise.fromPromise>[0]["setup"]>(
|
||||
(input): input is Parameters<typeof PluginPromise.fromPromise>[0]["setup"] => typeof input === "function",
|
||||
),
|
||||
}),
|
||||
})
|
||||
|
||||
const resolve = Effect.fn("PluginSupervisor.resolve")(function* (
|
||||
@@ -120,14 +109,24 @@ const load = Effect.fn("PluginSupervisor.load")(function* (
|
||||
: `${entrypoint}?mtime=${operation.mtime}`
|
||||
yield* Effect.log({ msg: "loading plugin", id: operation.target, entrypoint: source })
|
||||
const mod = yield* Effect.promise(() => importModule(source))
|
||||
if (
|
||||
Predicate.isObject(mod) &&
|
||||
Predicate.isObject(mod.default) &&
|
||||
"effect" in mod.default &&
|
||||
!("setup" in mod.default)
|
||||
) {
|
||||
return yield* Effect.fail(
|
||||
new Error("Effect plugins must be exported through Plugin.define from @opencode-ai/plugin/effect"),
|
||||
)
|
||||
}
|
||||
const value = (yield* Schema.decodeUnknownEffect(PluginModule)(mod)).default
|
||||
const plugin = "effect" in value ? value : PluginPromise.fromPromise(value)
|
||||
const plugin = PluginPromise.fromPromise(value)
|
||||
return {
|
||||
id: plugin.id,
|
||||
tui: plugin.tui,
|
||||
version: JSON.stringify(operation),
|
||||
source: pluginSource(operation.target),
|
||||
effect: (host) => plugin.effect(instanceSafeContext({ ...host, options: operation.options })),
|
||||
effect: (host) => plugin.effect({ ...host, options: operation.options }),
|
||||
} satisfies Plugin.Versioned
|
||||
})
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as SystemPromptPlugin from "./system-prompt.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Effect } from "effect"
|
||||
|
||||
import PROMPT_ANTHROPIC from "./system-prompt/anthropic.txt"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export * as VariantPlugin from "./variant.js"
|
||||
|
||||
import { Effect } from "effect"
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Model } from "../model.js"
|
||||
import { Provider } from "../provider.js"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as WarmingPlugin from "./warming.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Clock, Duration, Effect, Scope } from "effect"
|
||||
import { Config } from "../config.js"
|
||||
import { SessionSchema } from "../session/schema.js"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as WebSearchExa from "./exa.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Effect, Schema, Scope } from "effect"
|
||||
import { HttpClient } from "effect/unstable/http"
|
||||
import { WebSearchMcp } from "./mcp.js"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as WebSearchFirecrawl from "./firecrawl.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Effect, Option, Schema, Scope } from "effect"
|
||||
import { HttpClient } from "effect/unstable/http"
|
||||
import { App } from "../../app.js"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as WebSearchParallel from "./parallel.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Effect, Schema, Scope } from "effect"
|
||||
import { HttpClient } from "effect/unstable/http"
|
||||
import { App } from "../../app.js"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as WebSearchTavily from "./tavily.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Duration, Effect, Schema, Scope } from "effect"
|
||||
import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
||||
import { App } from "../../app.js"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export * as SessionMessage from "./message.js"
|
||||
export * as SessionMessage from "@opencode-ai/schema/session-message"
|
||||
export * from "@opencode-ai/schema/session-message"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export * as SessionSchema from "./schema.js"
|
||||
export * as SessionSchema from "@opencode-ai/schema/session"
|
||||
|
||||
import { Session } from "@opencode-ai/schema/session"
|
||||
|
||||
|
||||
@@ -49,7 +49,12 @@ type ToolRow = {
|
||||
duration: number | null
|
||||
}
|
||||
|
||||
type ToolSummaryRow = { status: string | null; count: number }
|
||||
type ToolSummaryRow = {
|
||||
calls: number
|
||||
succeeded: number
|
||||
failed: number
|
||||
unfinished: number
|
||||
}
|
||||
|
||||
type ModelAggregate = {
|
||||
model: Model.Ref
|
||||
@@ -188,25 +193,38 @@ export const get = Effect.fn("SessionStats.get")(function* (input: Input = {}) {
|
||||
(range) => {
|
||||
if (toolMode === "summary")
|
||||
return db
|
||||
.all<ToolSummaryRow>(
|
||||
.get<ToolSummaryRow>(
|
||||
sql`
|
||||
SELECT json_extract(content.value, '$.state.status') AS status, count(*) AS count
|
||||
FROM ${SessionMessageTable} AS message
|
||||
JOIN ${SessionTable} AS session ON session.id = message.session_id,
|
||||
json_each(message.data, '$.content') AS content
|
||||
WHERE message.type = 'assistant'
|
||||
AND message.time_created >= ${range.from}
|
||||
AND message.time_created < ${range.to}
|
||||
AND (session.fork_session_id IS NULL OR message.time_created >= session.time_created)
|
||||
AND json_extract(content.value, '$.type') = 'tool'
|
||||
${project}
|
||||
GROUP BY status
|
||||
WITH calls AS MATERIALIZED (
|
||||
SELECT json_extract(content.value, '$.state.status') AS status
|
||||
FROM ${SessionMessageTable} AS message
|
||||
JOIN ${SessionTable} AS session ON session.id = message.session_id,
|
||||
json_each(message.data, '$.content') AS content
|
||||
WHERE message.type = 'assistant'
|
||||
AND message.time_created >= ${range.from}
|
||||
AND message.time_created < ${range.to}
|
||||
AND (session.fork_session_id IS NULL OR message.time_created >= session.time_created)
|
||||
AND json_extract(content.value, '$.type') = 'tool'
|
||||
${project}
|
||||
)
|
||||
SELECT
|
||||
count(*) AS calls,
|
||||
count(*) FILTER (WHERE status = 'completed') AS succeeded,
|
||||
count(*) FILTER (WHERE status = 'error') AS failed,
|
||||
count(*) FILTER (WHERE status IS NULL OR status NOT IN ('completed', 'error')) AS unfinished
|
||||
FROM calls
|
||||
`,
|
||||
)
|
||||
.pipe(
|
||||
Effect.orDie,
|
||||
Effect.tap((rows) =>
|
||||
Effect.sync(() => rows.forEach((row) => addToolStatus(toolTotals, row.status, row.count))),
|
||||
Effect.tap((row) =>
|
||||
Effect.sync(() => {
|
||||
if (!row) return
|
||||
toolTotals.calls += row.calls
|
||||
toolTotals.succeeded += row.succeeded
|
||||
toolTotals.failed += row.failed
|
||||
toolTotals.unfinished += row.unfinished
|
||||
}),
|
||||
),
|
||||
Effect.asVoid,
|
||||
)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
export * as EditTool from "./edit.js"
|
||||
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/effect/plugin"
|
||||
import type { Context as PluginContext } from "@opencode-ai/core/plugin/definition"
|
||||
import { ToolFailure } from "@opencode-ai/ai"
|
||||
import { FileDiff } from "@opencode-ai/schema/file-diff"
|
||||
import { Bom } from "@opencode-ai/util/bom"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export * as GlobTool from "./glob.js"
|
||||
|
||||
import { ToolFailure } from "@opencode-ai/ai"
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/effect/plugin"
|
||||
import type { Context as PluginContext } from "@opencode-ai/core/plugin/definition"
|
||||
import { Effect, Schema } from "effect"
|
||||
import path from "path"
|
||||
import { Environment } from "../../environment/index.js"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as GrepTool from "./grep.js"
|
||||
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/effect/plugin"
|
||||
import type { Context as PluginContext } from "@opencode-ai/core/plugin/definition"
|
||||
import { ToolFailure } from "@opencode-ai/ai"
|
||||
import { Effect, Schema } from "effect"
|
||||
import path from "path"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as PatchTool from "./patch.js"
|
||||
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/effect/plugin"
|
||||
import type { Context as PluginContext } from "@opencode-ai/core/plugin/definition"
|
||||
import { ToolFailure } from "@opencode-ai/ai"
|
||||
import { FileDiff } from "@opencode-ai/schema/file-diff"
|
||||
import { Effect, Result, Schema } from "effect"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as QuestionTool from "./question.js"
|
||||
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/effect/plugin"
|
||||
import type { Context as PluginContext } from "@opencode-ai/core/plugin/definition"
|
||||
import { ToolFailure } from "@opencode-ai/ai"
|
||||
import { Effect, Schema } from "effect"
|
||||
import { Form } from "../../form.js"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as ReadTool from "./read.js"
|
||||
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/effect/plugin"
|
||||
import type { Context as PluginContext } from "@opencode-ai/core/plugin/definition"
|
||||
import { basename, dirname, join } from "path"
|
||||
import { ToolFailure } from "@opencode-ai/ai"
|
||||
import { Effect, Schema } from "effect"
|
||||
|
||||
@@ -2,7 +2,7 @@ export * as ShellTool from "./shell.js"
|
||||
|
||||
import path from "path"
|
||||
import { ToolFailure } from "@opencode-ai/ai"
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/effect/plugin"
|
||||
import type { Context as PluginContext } from "@opencode-ai/core/plugin/definition"
|
||||
import { Deferred, Effect, Schema, Scope } from "effect"
|
||||
import { Config } from "../../config.js"
|
||||
import { Environment } from "../../environment/index.js"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as SkillTool from "./skill.js"
|
||||
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/effect/plugin"
|
||||
import type { Context as PluginContext } from "@opencode-ai/core/plugin/definition"
|
||||
import path from "path"
|
||||
import { ToolFailure } from "@opencode-ai/ai"
|
||||
import { Effect, Schema } from "effect"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export * as SubagentTool from "./subagent.js"
|
||||
|
||||
import { ToolFailure } from "@opencode-ai/ai"
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/effect/plugin"
|
||||
import type { Context as PluginContext } from "@opencode-ai/core/plugin/definition"
|
||||
import { Effect, Schema, Scope } from "effect"
|
||||
import { Agent } from "../../agent.js"
|
||||
import { Config } from "../../config.js"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as WebFetchTool from "./webfetch.js"
|
||||
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/effect/plugin"
|
||||
import type { Context as PluginContext } from "@opencode-ai/core/plugin/definition"
|
||||
import { ToolFailure } from "@opencode-ai/ai"
|
||||
import { Duration, Effect, Schema } from "effect"
|
||||
import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as WebSearchTool from "./websearch.js"
|
||||
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/effect/plugin"
|
||||
import type { Context as PluginContext } from "@opencode-ai/core/plugin/definition"
|
||||
import { ToolFailure } from "@opencode-ai/ai"
|
||||
import { Effect, Schema, Semaphore } from "effect"
|
||||
import { HttpClientError } from "effect/unstable/http"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
export * as WriteTool from "./write.js"
|
||||
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/effect/plugin"
|
||||
import type { Context as PluginContext } from "@opencode-ai/core/plugin/definition"
|
||||
import { ToolFailure } from "@opencode-ai/ai"
|
||||
import { Effect, Schema } from "effect"
|
||||
import { Bom } from "@opencode-ai/util/bom"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export * as WellKnownPlugin from "./plugin.js"
|
||||
|
||||
import { define } from "@opencode-ai/plugin/effect/plugin"
|
||||
import { define } from "@opencode-ai/core/plugin/definition"
|
||||
import { Effect, Stream } from "effect"
|
||||
import { Bus } from "../bus.js"
|
||||
import { WellKnown } from "../wellknown.js"
|
||||
|
||||
@@ -2,7 +2,7 @@ import fs from "fs/promises"
|
||||
import path from "path"
|
||||
import { pathToFileURL } from "url"
|
||||
import { describe, expect } from "bun:test"
|
||||
import { Plugin as EffectPlugin } from "@opencode-ai/plugin/effect"
|
||||
import { Plugin as EffectPlugin } from "@opencode-ai/core/plugin/definition"
|
||||
import { Agent } from "@opencode-ai/core/agent"
|
||||
import { Catalog } from "@opencode-ai/core/catalog"
|
||||
import { ConfigPluginSource } from "@opencode-ai/core/config/plugin/source"
|
||||
@@ -146,6 +146,7 @@ describe("PluginSupervisor config", () => {
|
||||
"-*",
|
||||
path.join(import.meta.dir, "../plugin/fixtures/missing-plugin.ts"),
|
||||
path.join(import.meta.dir, "../plugin/fixtures/invalid-plugin.ts"),
|
||||
path.join(import.meta.dir, "../plugin/fixtures/raw-effect-plugin.ts"),
|
||||
{
|
||||
package: path.join(import.meta.dir, "../plugin/fixtures/config-promise-plugin.ts"),
|
||||
options: { description: "Loaded after invalid plugins" },
|
||||
@@ -162,12 +163,14 @@ describe("PluginSupervisor config", () => {
|
||||
expect(output).toEqual([
|
||||
path.join(import.meta.dir, "../plugin/fixtures/missing-plugin.ts"),
|
||||
path.join(import.meta.dir, "../plugin/fixtures/invalid-plugin.ts"),
|
||||
path.join(import.meta.dir, "../plugin/fixtures/raw-effect-plugin.ts"),
|
||||
])
|
||||
expect(
|
||||
(yield* plugins.list()).filter((plugin) => plugin.status === "failed").map((plugin) => plugin.source),
|
||||
).toEqual([
|
||||
{ type: "local", path: path.join(import.meta.dir, "../plugin/fixtures/missing-plugin.ts") },
|
||||
{ type: "local", path: path.join(import.meta.dir, "../plugin/fixtures/invalid-plugin.ts") },
|
||||
{ type: "local", path: path.join(import.meta.dir, "../plugin/fixtures/raw-effect-plugin.ts") },
|
||||
])
|
||||
}),
|
||||
).pipe(Effect.provide(Logger.layer([logger])))
|
||||
|
||||
@@ -4,7 +4,7 @@ import { SessionMessage } from "@opencode-ai/core/session/message"
|
||||
import { toSessionError } from "@opencode-ai/core/session/to-session-error"
|
||||
import type { SessionError } from "@opencode-ai/schema/session-error"
|
||||
import { Tool } from "@opencode-ai/core/tool"
|
||||
import type { Context as PluginContext } from "@opencode-ai/plugin/effect/plugin"
|
||||
import type { Context as PluginContext } from "@opencode-ai/core/plugin/definition"
|
||||
import { Effect, type Scope } from "effect"
|
||||
import { host } from "../plugin/host"
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
Stream,
|
||||
} from "effect"
|
||||
import { TestClock } from "effect/testing"
|
||||
import { Plugin as EffectPlugin } from "@opencode-ai/plugin/effect"
|
||||
import { Plugin as EffectPlugin } from "@opencode-ai/core/plugin/definition"
|
||||
import { Agent } from "@opencode-ai/core/agent"
|
||||
import { Catalog } from "@opencode-ai/core/catalog"
|
||||
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, expect } from "bun:test"
|
||||
import { ToolFailure } from "@opencode-ai/ai"
|
||||
import { Context, Effect, Exit, Fiber, Schema, Stream } from "effect"
|
||||
import { Plugin as EffectPlugin } from "@opencode-ai/plugin/effect"
|
||||
import { Plugin as EffectPlugin } from "@opencode-ai/core/plugin/definition"
|
||||
import { Config as ConfigSchema } from "@opencode-ai/schema/config"
|
||||
import { Agent } from "@opencode-ai/core/agent"
|
||||
import { Bus } from "@opencode-ai/core/bus"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Effect, Plugin } from "@opencode-ai/plugin/effect"
|
||||
import { Plugin } from "@opencode-ai/plugin/effect"
|
||||
import { Effect } from "effect"
|
||||
|
||||
export default Plugin.define({
|
||||
id: "config-effect-plugin",
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import { Effect } from "effect"
|
||||
|
||||
export default {
|
||||
id: "raw-effect-plugin",
|
||||
effect: () => Effect.void,
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect } from "bun:test"
|
||||
import { Message, SystemPart } from "@opencode-ai/ai"
|
||||
import { DateTime, Effect, Schema } from "effect"
|
||||
import { DateTime, Effect, Fiber, Schema } from "effect"
|
||||
import { Agent } from "@opencode-ai/core/agent"
|
||||
import { Catalog } from "@opencode-ai/core/catalog"
|
||||
import { Model } from "@opencode-ai/core/model"
|
||||
@@ -25,6 +25,7 @@ import { PluginTestLayer } from "./fixture"
|
||||
import { host as testHost } from "./host"
|
||||
|
||||
const it = testEffect(PluginTestLayer)
|
||||
const EffectPlugin = await import("@opencode-ai/plugin/effect")
|
||||
|
||||
describe("fromPromise", () => {
|
||||
it.effect("adapts plugin storage methods", () =>
|
||||
@@ -469,11 +470,11 @@ describe("fromPromise", () => {
|
||||
const events: string[] = []
|
||||
const promisePlugin = define({
|
||||
id: "promise-cleanup",
|
||||
setup: async () => {
|
||||
setup: async (context) => {
|
||||
events.push("setup")
|
||||
return async () => {
|
||||
await Promise.resolve()
|
||||
events.push("cleanup")
|
||||
events.push(context.signal.aborted ? "cleanup-aborted" : "cleanup-active")
|
||||
}
|
||||
},
|
||||
})
|
||||
@@ -485,7 +486,7 @@ describe("fromPromise", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
expect(events).toEqual(["setup", "cleanup"])
|
||||
expect(events).toEqual(["setup", "cleanup-aborted"])
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -534,6 +535,77 @@ describe("fromPromise", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("runs Effect-authored tool codecs through the Promise boundary", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugins = yield* Plugin.Service
|
||||
const registry = yield* Tool.Service
|
||||
const host = yield* PluginHost.make(plugins)
|
||||
const interrupted: string[] = []
|
||||
const effectPlugin = EffectPlugin.Plugin.define({
|
||||
id: "effect-tool",
|
||||
effect: (context) =>
|
||||
context.tool.transform((tools) =>
|
||||
tools.add({
|
||||
name: "increment",
|
||||
options: { codemode: false },
|
||||
description: "Increment",
|
||||
input: Schema.FiniteFromString,
|
||||
output: Schema.FiniteFromString,
|
||||
execute: (input) => {
|
||||
if (input === 42) {
|
||||
return Effect.fail(
|
||||
new Tool.Error({ message: "cannot increment 42", metadata: { reason: "reserved" } }),
|
||||
)
|
||||
}
|
||||
if (input === 43) {
|
||||
return Effect.sync(() => interrupted.push("started")).pipe(
|
||||
Effect.andThen(Effect.never),
|
||||
Effect.ensuring(Effect.sync(() => interrupted.push("finalized"))),
|
||||
)
|
||||
}
|
||||
return Effect.succeed({ output: input + 1 })
|
||||
},
|
||||
}),
|
||||
),
|
||||
})
|
||||
|
||||
yield* PluginPromise.fromPromise(effectPlugin).effect(host)
|
||||
|
||||
expect(
|
||||
yield* (yield* registry.snapshot()).execute({
|
||||
sessionID: Session.ID.make("ses_effect_tool"),
|
||||
agent: Agent.ID.make("build"),
|
||||
messageID: SessionMessage.ID.make("msg_effect_tool"),
|
||||
progress: () => Effect.void,
|
||||
call: { type: "tool-call", id: "call_effect_tool", name: "increment", input: "41" },
|
||||
}),
|
||||
).toMatchObject({ output: "42" })
|
||||
expect(
|
||||
yield* Effect.flip(
|
||||
(yield* registry.snapshot()).execute({
|
||||
sessionID: Session.ID.make("ses_effect_tool"),
|
||||
agent: Agent.ID.make("build"),
|
||||
messageID: SessionMessage.ID.make("msg_effect_tool_error"),
|
||||
progress: () => Effect.void,
|
||||
call: { type: "tool-call", id: "call_effect_tool_error", name: "increment", input: "42" },
|
||||
}),
|
||||
),
|
||||
).toMatchObject({ _tag: "Tool.Error", message: "cannot increment 42", metadata: { reason: "reserved" } })
|
||||
const execution = yield* (yield* registry.snapshot())
|
||||
.execute({
|
||||
sessionID: Session.ID.make("ses_effect_tool"),
|
||||
agent: Agent.ID.make("build"),
|
||||
messageID: SessionMessage.ID.make("msg_effect_tool_interrupt"),
|
||||
progress: () => Effect.void,
|
||||
call: { type: "tool-call", id: "call_effect_tool_interrupt", name: "increment", input: "43" },
|
||||
})
|
||||
.pipe(Effect.forkScoped({ startImmediately: true }))
|
||||
while (interrupted.length === 0) yield* Effect.yieldNow
|
||||
yield* Fiber.interrupt(execution)
|
||||
expect(interrupted).toEqual(["started", "finalized"])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("returns content-only plugin results through Code Mode", () =>
|
||||
Effect.gen(function* () {
|
||||
const plugins = yield* Plugin.Service
|
||||
|
||||
@@ -113,6 +113,13 @@ describe("SessionStats", () => {
|
||||
completed: DateTime.makeUnsafe(Date.UTC(2026, 0, 2, 10, 0, 2)),
|
||||
},
|
||||
}),
|
||||
SessionMessage.AssistantTool.make({
|
||||
type: "tool",
|
||||
id: "call_pending",
|
||||
name: "pending",
|
||||
state: SessionMessage.ToolStateRunning.make({ status: "running", input: {}, metadata: {} }),
|
||||
time: { created: DateTime.makeUnsafe(Date.UTC(2026, 0, 2, 10)) },
|
||||
}),
|
||||
]),
|
||||
),
|
||||
messageRow(childID, 1, assistant("msg_stats_child", Date.UTC(2026, 0, 3, 10), [], "large", 2)),
|
||||
@@ -210,7 +217,7 @@ describe("SessionStats", () => {
|
||||
expect(stats.cost).toBe(Money.USD.make(6.25))
|
||||
expect(stats.tools).toMatchObject({
|
||||
mode: "detail",
|
||||
totals: { calls: 2, succeeded: 1, failed: 1, unfinished: 0 },
|
||||
totals: { calls: 3, succeeded: 1, failed: 1, unfinished: 1 },
|
||||
})
|
||||
expect(stats.activity).toEqual([
|
||||
{ date: "2026-01-02", steps: 1 },
|
||||
@@ -224,6 +231,7 @@ describe("SessionStats", () => {
|
||||
expect(stats.tools.usage).toMatchObject([
|
||||
{ name: "read", calls: 1, succeeded: 1, failed: 0, durationP50: 250 },
|
||||
{ name: "edit", calls: 1, succeeded: 0, failed: 1, durationP50: 2_000 },
|
||||
{ name: "pending", calls: 1, succeeded: 0, failed: 0, unfinished: 1 },
|
||||
])
|
||||
|
||||
const summary = yield* SessionStats.get({
|
||||
@@ -234,7 +242,7 @@ describe("SessionStats", () => {
|
||||
expect(summary.models.map((model) => String(model.model.id))).toEqual(["large", "sonnet", "fork-new"])
|
||||
expect(summary.tools).toEqual({
|
||||
mode: "summary",
|
||||
totals: { calls: 2, succeeded: 1, failed: 1, unfinished: 0 },
|
||||
totals: { calls: 3, succeeded: 1, failed: 1, unfinished: 1 },
|
||||
})
|
||||
|
||||
const withoutTools = yield* SessionStats.get({
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user