diff --git a/packages/opencode/src/permission/evaluate.ts b/packages/opencode/src/permission/evaluate.ts new file mode 100644 index 00000000000..2b0604f4bac --- /dev/null +++ b/packages/opencode/src/permission/evaluate.ts @@ -0,0 +1,15 @@ +import { Wildcard } from "@/util/wildcard" + +type Rule = { + permission: string + pattern: string + action: "allow" | "deny" | "ask" +} + +export function evaluate(permission: string, pattern: string, ...rulesets: Rule[][]): Rule { + const rules = rulesets.flat() + const match = rules.findLast( + (rule) => Wildcard.match(permission, rule.permission) && Wildcard.match(pattern, rule.pattern), + ) + return match ?? { action: "ask", permission, pattern: "*" } +} diff --git a/packages/opencode/src/permission/index.ts b/packages/opencode/src/permission/index.ts index 93a8c49b655..321c5c374e3 100644 --- a/packages/opencode/src/permission/index.ts +++ b/packages/opencode/src/permission/index.ts @@ -13,6 +13,7 @@ import { Wildcard } from "@/util/wildcard" import { Deferred, Effect, Layer, Schema, ServiceMap } from "effect" import os from "os" import z from "zod" +import { evaluate as evalRule } from "./evaluate" import { PermissionID } from "./schema" export namespace PermissionNext { @@ -125,12 +126,8 @@ export namespace PermissionNext { } export function evaluate(permission: string, pattern: string, ...rulesets: Ruleset[]): Rule { - const rules = rulesets.flat() - log.info("evaluate", { permission, pattern, ruleset: rules }) - const match = rules.findLast( - (rule) => Wildcard.match(permission, rule.permission) && Wildcard.match(pattern, rule.pattern), - ) - return match ?? { action: "ask", permission, pattern: "*" } + log.info("evaluate", { permission, pattern, ruleset: rulesets.flat() }) + return evalRule(permission, pattern, ...rulesets) } export class Service extends ServiceMap.Service()("@opencode/PermissionNext") {} diff --git a/packages/opencode/src/tool/truncate-effect.ts b/packages/opencode/src/tool/truncate-effect.ts index 4431c18f839..a263cd29437 100644 --- a/packages/opencode/src/tool/truncate-effect.ts +++ b/packages/opencode/src/tool/truncate-effect.ts @@ -3,7 +3,7 @@ import { Cause, Duration, Effect, Layer, Schedule, ServiceMap } from "effect" import path from "path" import type { Agent } from "../agent/agent" import { AppFileSystem } from "@/filesystem" -import { PermissionNext } from "../permission" +import { evaluate } from "@/permission/evaluate" import { Identifier } from "../id/id" import { Log } from "../util/log" import { ToolID } from "./schema" @@ -28,7 +28,7 @@ export namespace TruncateEffect { function hasTaskTool(agent?: Agent.Info) { if (!agent?.permission) return false - return PermissionNext.evaluate("task", "*", agent.permission).action !== "deny" + return evaluate("task", "*", agent.permission).action !== "deny" } export interface Interface { diff --git a/packages/opencode/test/tool/truncation.test.ts b/packages/opencode/test/tool/truncation.test.ts index 71439f76049..a00e07e6924 100644 --- a/packages/opencode/test/tool/truncation.test.ts +++ b/packages/opencode/test/tool/truncation.test.ts @@ -4,12 +4,14 @@ import { Effect, FileSystem, Layer } from "effect" import { Truncate } from "../../src/tool/truncate" import { TruncateEffect } from "../../src/tool/truncate-effect" import { Identifier } from "../../src/id/id" +import { Process } from "../../src/util/process" import { Filesystem } from "../../src/util/filesystem" import path from "path" import { testEffect } from "../lib/effect" import { writeFileStringScoped } from "../lib/filesystem" const FIXTURES_DIR = path.join(import.meta.dir, "fixtures") +const ROOT = path.resolve(import.meta.dir, "..", "..") describe("Truncate", () => { describe("output", () => { @@ -125,6 +127,14 @@ describe("Truncate", () => { if (result.truncated) throw new Error("expected not truncated") expect("outputPath" in result).toBe(false) }) + + test("loads truncate effect in a fresh process", async () => { + const out = await Process.run([process.execPath, "run", path.join(ROOT, "src", "tool", "truncate-effect.ts")], { + cwd: ROOT, + }) + + expect(out.code).toBe(0) + }, 20000) }) describe("cleanup", () => {