diff --git a/packages/opencode-plugin/package.json b/packages/opencode-plugin/package.json index e131953f..f0f99431 100644 --- a/packages/opencode-plugin/package.json +++ b/packages/opencode-plugin/package.json @@ -29,16 +29,21 @@ "devDependencies": { "@codemcp/workflows-core": "workspace:*", "@codemcp/workflows-server": "workspace:*", + "effect": "3.21.1", "rimraf": "^6.0.1", "tsup": "^8.0.0", "vitest": "4.0.18" }, "peerDependencies": { - "@anthropic-ai/sdk": "*" + "@anthropic-ai/sdk": "*", + "effect": ">=3.0.0" }, "peerDependenciesMeta": { "@anthropic-ai/sdk": { "optional": true + }, + "effect": { + "optional": true } }, "keywords": [ diff --git a/packages/opencode-plugin/src/plugin.ts b/packages/opencode-plugin/src/plugin.ts index ec416484..900e325d 100644 --- a/packages/opencode-plugin/src/plugin.ts +++ b/packages/opencode-plugin/src/plugin.ts @@ -13,6 +13,7 @@ */ import type { Plugin, PluginInput, Hooks, ToolDefinition } from './types.js'; +import { Effect } from 'effect'; import { createProceedToPhaseTool } from './tool-handlers/proceed-to-phase.js'; import { createConductReviewTool } from './tool-handlers/conduct-review.js'; import { createResetDevelopmentTool } from './tool-handlers/reset-development.js'; @@ -652,12 +653,14 @@ ACTION REQUIRED: Use transition_phase tool to move to a phase that allows editin ); } - await ctx.ask({ - permission: toolName, - patterns: ['*'], - always: ['*'], - metadata: {}, - }); + await Effect.runPromise( + ctx.ask({ + permission: toolName, + patterns: ['*'], + always: ['*'], + metadata: {}, + }) + ); return def.execute(args, ctx); }, diff --git a/packages/opencode-plugin/src/types.ts b/packages/opencode-plugin/src/types.ts index b6ea0036..99d00367 100644 --- a/packages/opencode-plugin/src/types.ts +++ b/packages/opencode-plugin/src/types.ts @@ -51,6 +51,8 @@ export type PluginInput = { }; // Tool context for custom tools +import type { Effect } from 'effect'; + export type ToolContext = { sessionID: string; messageID: string; @@ -64,7 +66,7 @@ export type ToolContext = { patterns: string[]; always: string[]; metadata: Record; - }): Promise; + }): Effect.Effect; }; // Tool definition diff --git a/packages/opencode-plugin/test/e2e/plugin.test.ts b/packages/opencode-plugin/test/e2e/plugin.test.ts index 999be9cf..d0864cb2 100644 --- a/packages/opencode-plugin/test/e2e/plugin.test.ts +++ b/packages/opencode-plugin/test/e2e/plugin.test.ts @@ -6,6 +6,7 @@ */ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; +import { Effect } from 'effect'; import * as fs from 'node:fs'; import * as path from 'node:path'; import { tmpdir } from 'node:os'; @@ -63,7 +64,7 @@ function createMockToolContext(overrides: Record = {}) { worktree: '', abort: new AbortController().signal, metadata: vi.fn(), - ask: vi.fn().mockResolvedValue(undefined), + ask: vi.fn().mockReturnValue(Effect.void), ...overrides, }; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 99a86fac..af6221e0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -190,6 +190,9 @@ importers: '@codemcp/workflows-server': specifier: workspace:* version: link:../mcp-server + effect: + specifier: 3.21.1 + version: 3.21.1 rimraf: specifier: ^6.0.1 version: 6.1.2 @@ -2735,6 +2738,9 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + effect@3.21.1: + resolution: {integrity: sha512-bA3TsBd0mByThuCnE6FQqS+L3DLazk4UbE9jp0CqVfIjQl5DKi8sAe93O/ZKeF7clL65fJxcsVGiAKYXdnHByA==} + electron-to-chromium@1.5.329: resolution: {integrity: sha512-/4t+AS1l4S3ZC0Ja7PHFIWeBIxGA3QGqV8/yKsP36v7NcyUCl+bIcmw6s5zVuMIECWwBrAK/6QLzTmbJChBboQ==} @@ -2857,6 +2863,10 @@ packages: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} + fast-check@3.23.2: + resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} + engines: {node: '>=8.0.0'} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -3606,6 +3616,9 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + qs@6.14.0: resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} @@ -6175,11 +6188,6 @@ snapshots: '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-vue@5.2.4(vite@5.4.21(@types/node@20.19.31))(vue@3.5.22(typescript@5.9.3))': - dependencies: - vite: 5.4.21(@types/node@20.19.31) - vue: 3.5.22(typescript@5.9.3) - '@vitejs/plugin-vue@5.2.4(vite@5.4.21(@types/node@22.19.8))(vue@3.5.22(typescript@5.9.3))': dependencies: vite: 5.4.21(@types/node@22.19.8) @@ -6202,6 +6210,14 @@ snapshots: optionalDependencies: vite: 7.1.12(@types/node@22.19.8)(tsx@4.21.0)(yaml@2.8.1) + '@vitest/mocker@4.0.18(vite@7.1.12(@types/node@24.7.0)(tsx@4.21.0)(yaml@2.8.1))': + dependencies: + '@vitest/spy': 4.0.18 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.1.12(@types/node@24.7.0)(tsx@4.21.0)(yaml@2.8.1) + '@vitest/pretty-format@4.0.18': dependencies: tinyrainbow: 3.0.3 @@ -6976,6 +6992,11 @@ snapshots: ee-first@1.1.1: {} + effect@3.21.1: + dependencies: + '@standard-schema/spec': 1.0.0 + fast-check: 3.23.2 + electron-to-chromium@1.5.329: {} emoji-regex-xs@1.0.0: {} @@ -7187,6 +7208,10 @@ snapshots: transitivePeerDependencies: - supports-color + fast-check@3.23.2: + dependencies: + pure-rand: 6.1.0 + fast-deep-equal@3.1.3: {} fast-json-stable-stringify@2.1.0: {} @@ -7916,6 +7941,8 @@ snapshots: punycode@2.3.1: {} + pure-rand@6.1.0: {} + qs@6.14.0: dependencies: side-channel: 1.1.0 @@ -8600,7 +8627,7 @@ snapshots: '@shikijs/transformers': 2.5.0 '@shikijs/types': 2.5.0 '@types/markdown-it': 14.1.2 - '@vitejs/plugin-vue': 5.2.4(vite@5.4.21(@types/node@20.19.31))(vue@3.5.22(typescript@5.9.3)) + '@vitejs/plugin-vue': 5.2.4(vite@5.4.21(@types/node@22.19.8))(vue@3.5.22(typescript@5.9.3)) '@vue/devtools-api': 7.7.7 '@vue/shared': 3.5.22 '@vueuse/core': 12.8.2(typescript@5.9.3) @@ -8730,7 +8757,7 @@ snapshots: vitest@4.0.18(@types/node@24.7.0)(jsdom@27.4.0)(tsx@4.21.0)(yaml@2.8.1): dependencies: '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.1.12(@types/node@22.19.8)(tsx@4.21.0)(yaml@2.8.1)) + '@vitest/mocker': 4.0.18(vite@7.1.12(@types/node@24.7.0)(tsx@4.21.0)(yaml@2.8.1)) '@vitest/pretty-format': 4.0.18 '@vitest/runner': 4.0.18 '@vitest/snapshot': 4.0.18