test: make unsafe test coercion explicit
Move test coercion out of a hidden global and require each test to import the helper so review tools and runtime scripts can see the unsafe boundary. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -6,6 +6,7 @@ import { describe, expect, mock, test } from "bun:test"
|
||||
import type { BackgroundManager } from "../../features/background-agent"
|
||||
import { clearPendingStore, consumeToolMetadata } from "../../features/tool-metadata-store"
|
||||
import { createBackgroundTask } from "./create-background-task"
|
||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||
|
||||
const projectDir = "/Users/yeongyu/local-workspaces/oh-my-opencode"
|
||||
|
||||
@@ -18,7 +19,7 @@ describe("createBackgroundTask metadata", () => {
|
||||
// #given
|
||||
clearPendingStore()
|
||||
|
||||
const manager = testCoerce<BackgroundManager>({
|
||||
const manager = unsafeTestValue<BackgroundManager>({
|
||||
launch: mock(() => Promise.resolve({
|
||||
id: "task-1",
|
||||
sessionID: null,
|
||||
@@ -28,7 +29,7 @@ describe("createBackgroundTask metadata", () => {
|
||||
})),
|
||||
getTask: mock(() => undefined),
|
||||
})
|
||||
const client = testCoerce<PluginInput["client"]>({
|
||||
const client = unsafeTestValue<PluginInput["client"]>({
|
||||
session: {
|
||||
messages: mock(() => Promise.resolve({ data: [] })),
|
||||
},
|
||||
|
||||
@@ -4,6 +4,7 @@ import { describe, test, expect, mock } from "bun:test"
|
||||
import type { BackgroundManager } from "../../features/background-agent"
|
||||
import type { PluginInput } from "@opencode-ai/plugin"
|
||||
import { createBackgroundTask } from "./create-background-task"
|
||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||
|
||||
describe("createBackgroundTask", () => {
|
||||
const launchMock = mock(async (): Promise<{
|
||||
@@ -21,12 +22,12 @@ describe("createBackgroundTask", () => {
|
||||
}))
|
||||
const getTaskMock = mock()
|
||||
|
||||
const mockManager = testCoerce<BackgroundManager>({
|
||||
const mockManager = unsafeTestValue<BackgroundManager>({
|
||||
launch: launchMock,
|
||||
getTask: getTaskMock,
|
||||
})
|
||||
|
||||
const mockClient = testCoerce<PluginInput["client"]>({
|
||||
const mockClient = unsafeTestValue<PluginInput["client"]>({
|
||||
session: {
|
||||
messages: mock(() => Promise.resolve({ data: [] })),
|
||||
},
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { BackgroundManager, BackgroundTask } from "../../features/backgroun
|
||||
import type { ToolContext } from "@opencode-ai/plugin/tool"
|
||||
import type { BackgroundCancelClient, BackgroundOutputManager, BackgroundOutputClient } from "./tools"
|
||||
import { consumeToolMetadata, clearPendingStore } from "../../features/tool-metadata-store"
|
||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||
|
||||
const projectDir = "/Users/yeongyu/local-workspaces/oh-my-opencode"
|
||||
|
||||
@@ -66,7 +67,7 @@ describe("background_output full_session", () => {
|
||||
const manager = createMockManager(task)
|
||||
const client = createMockClient({})
|
||||
const tool = createBackgroundOutput(manager, client)
|
||||
const ctxWithCallId = testCoerce<ToolContext>({
|
||||
const ctxWithCallId = unsafeTestValue<ToolContext>({
|
||||
...mockContext,
|
||||
callID: "call-1",
|
||||
})
|
||||
@@ -93,7 +94,7 @@ describe("background_output full_session", () => {
|
||||
const manager = createMockManager(task)
|
||||
const client = createMockClient({})
|
||||
const tool = createBackgroundOutput(manager, client)
|
||||
const ctxWithCallId = testCoerce<ToolContext>({
|
||||
const ctxWithCallId = unsafeTestValue<ToolContext>({
|
||||
...mockContext,
|
||||
callID: "call-1",
|
||||
})
|
||||
@@ -387,7 +388,7 @@ describe("background_cancel", () => {
|
||||
// #given
|
||||
const task = createTask({ status: "running" })
|
||||
const cancelled: string[] = []
|
||||
const manager = testCoerce<BackgroundManager>({
|
||||
const manager = unsafeTestValue<BackgroundManager>({
|
||||
getTask: (id: string) => (id === task.id ? task : undefined),
|
||||
getAllDescendantTasks: () => [task],
|
||||
cancelTask: async (taskId: string) => {
|
||||
@@ -412,7 +413,7 @@ describe("background_cancel", () => {
|
||||
const taskA = createTask({ id: "task-a", status: "running" })
|
||||
const taskB = createTask({ id: "task-b", status: "pending" })
|
||||
const cancelled: string[] = []
|
||||
const manager = testCoerce<BackgroundManager>({
|
||||
const manager = unsafeTestValue<BackgroundManager>({
|
||||
getTask: () => undefined,
|
||||
getAllDescendantTasks: () => [taskA, taskB],
|
||||
cancelTask: async (taskId: string) => {
|
||||
@@ -437,7 +438,7 @@ describe("background_cancel", () => {
|
||||
// #given
|
||||
const taskA = createTask({ id: "task-a", status: "running", sessionId: "ses-a", description: "running task" })
|
||||
const taskB = createTask({ id: "task-b", status: "pending", sessionId: undefined, description: "pending task" })
|
||||
const manager = testCoerce<BackgroundManager>({
|
||||
const manager = unsafeTestValue<BackgroundManager>({
|
||||
getTask: () => undefined,
|
||||
getAllDescendantTasks: () => [taskA, taskB],
|
||||
cancelTask: async (taskId: string) => {
|
||||
@@ -461,7 +462,7 @@ describe("background_cancel", () => {
|
||||
// #given
|
||||
const task = createTask({ id: "task-1", status: "running" })
|
||||
const cancelOptions: Array<{ taskId: string; options: unknown }> = []
|
||||
const manager = testCoerce<BackgroundManager>({
|
||||
const manager = unsafeTestValue<BackgroundManager>({
|
||||
getTask: (id: string) => (id === task.id ? task : undefined),
|
||||
getAllDescendantTasks: () => [task],
|
||||
cancelTask: async (taskId: string, options?: unknown) => {
|
||||
@@ -487,7 +488,7 @@ describe("background_cancel", () => {
|
||||
// #given
|
||||
const task = createTask({ id: "task-1", status: "running" })
|
||||
const cancelOptions: Array<{ taskId: string; options: unknown }> = []
|
||||
const manager = testCoerce<BackgroundManager>({
|
||||
const manager = unsafeTestValue<BackgroundManager>({
|
||||
getTask: (id: string) => (id === task.id ? task : undefined),
|
||||
getAllDescendantTasks: () => [task],
|
||||
cancelTask: async (taskId: string, options?: unknown) => {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { describe, expect, test } from "bun:test"
|
||||
|
||||
import { createOrGetSession } from "./session-creator"
|
||||
import { _resetForTesting, subagentSessions } from "../../features/claude-code-session-state"
|
||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||
|
||||
describe("call-omo-agent createOrGetSession", () => {
|
||||
test("creates child session without overriding permission and tracks it as subagent session", async () => {
|
||||
@@ -37,12 +38,12 @@ describe("call-omo-agent createOrGetSession", () => {
|
||||
}
|
||||
|
||||
// when
|
||||
const result = await createOrGetSession(testCoerce(args), testCoerce(toolContext), testCoerce(ctx))
|
||||
const result = await createOrGetSession(unsafeTestValue(args), unsafeTestValue(toolContext), unsafeTestValue(ctx))
|
||||
|
||||
// then
|
||||
expect(result).toEqual({ sessionID: "ses_child", isNew: true })
|
||||
expect(createCalls).toHaveLength(1)
|
||||
const createBody = (testCoerce(createCalls[0]))?.body
|
||||
const createBody = (unsafeTestValue(createCalls[0]))?.body
|
||||
expect(createBody?.parentID).toBe("ses_parent")
|
||||
expect(createBody?.permission).toBeUndefined()
|
||||
expect(subagentSessions.has("ses_child")).toBe(true)
|
||||
|
||||
@@ -2,6 +2,7 @@ import { describe, expect, test } from "bun:test"
|
||||
|
||||
import { resolveOrCreateSessionId } from "./subagent-session-creator"
|
||||
import { _resetForTesting, subagentSessions } from "../../features/claude-code-session-state"
|
||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||
|
||||
describe("call-omo-agent resolveOrCreateSessionId", () => {
|
||||
const originalPlatform = process.platform
|
||||
@@ -19,7 +20,7 @@ describe("call-omo-agent resolveOrCreateSessionId", () => {
|
||||
const { parentDirectory, contextDirectory } = options
|
||||
const parentSessionData = parentDirectory ? { data: { directory: parentDirectory } } : { data: {} }
|
||||
|
||||
const ctx = testCoerce<Parameters<typeof resolveOrCreateSessionId>[0]>({
|
||||
const ctx = unsafeTestValue<Parameters<typeof resolveOrCreateSessionId>[0]>({
|
||||
directory: contextDirectory,
|
||||
client: {
|
||||
session: {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||
const { describe, test, expect, mock } = require("bun:test")
|
||||
|
||||
type ExecuteSync = typeof import("./sync-executor").executeSync
|
||||
@@ -389,7 +390,7 @@ describe("executeSync", () => {
|
||||
}
|
||||
|
||||
//#when
|
||||
await executeSync(args, toolContext, testCoerce(ctx), deps, undefined, spawnReservation)
|
||||
await executeSync(args, toolContext, unsafeTestValue(ctx), deps, undefined, spawnReservation)
|
||||
|
||||
//#then
|
||||
expect(spawnReservation.commit).toHaveBeenCalledTimes(1)
|
||||
|
||||
@@ -3,6 +3,7 @@ const { describe, test, expect, beforeEach, afterEach, spyOn, mock } = require("
|
||||
import { resolveCategoryExecution } from "./category-resolver"
|
||||
import type { ExecutorContext } from "./executor-types"
|
||||
import * as connectedProvidersCache from "../../shared/connected-providers-cache"
|
||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||
|
||||
describe("resolveCategoryExecution", () => {
|
||||
let connectedProvidersSpy: ReturnType<typeof spyOn> | undefined
|
||||
@@ -26,8 +27,8 @@ describe("resolveCategoryExecution", () => {
|
||||
})
|
||||
|
||||
const createMockExecutorContext = (): ExecutorContext => ({
|
||||
client: testCoerce({}),
|
||||
manager: testCoerce({}),
|
||||
client: unsafeTestValue({}),
|
||||
manager: unsafeTestValue({}),
|
||||
directory: "/tmp/test",
|
||||
userCategories: {},
|
||||
sisyphusJuniorModel: undefined,
|
||||
|
||||
@@ -2,6 +2,7 @@ const { describe, test, expect } = require("bun:test")
|
||||
|
||||
import { executeBackgroundTask } from "./executor"
|
||||
import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types"
|
||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||
|
||||
describe("task tool metadata awaiting", () => {
|
||||
test("executeBackgroundTask awaits ctx.metadata before returning", async () => {
|
||||
@@ -28,7 +29,7 @@ describe("task tool metadata awaiting", () => {
|
||||
subagent_type: "explore",
|
||||
}
|
||||
|
||||
const executorCtx = testCoerce({
|
||||
const executorCtx = unsafeTestValue({
|
||||
manager: {
|
||||
launch: async () => ({
|
||||
id: "task_1",
|
||||
|
||||
@@ -2,6 +2,7 @@ const { describe, test, expect } = require("bun:test")
|
||||
|
||||
import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types"
|
||||
import type { ParentContext } from "./executor-types"
|
||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||
|
||||
const MODEL = { providerID: "anthropic", modelID: "claude-sonnet-4-6" }
|
||||
const MODEL_WITH_VARIANT = { providerID: "google", modelID: "gemini-3.1-pro", variant: "high" }
|
||||
@@ -63,7 +64,7 @@ describe("metadata model unification", () => {
|
||||
load_skills: [], run_in_background: true, subagent_type: "explore",
|
||||
}
|
||||
|
||||
await executeBackgroundTask(args, ctx, testCoerce({
|
||||
await executeBackgroundTask(args, ctx, unsafeTestValue({
|
||||
manager: {
|
||||
launch: async () => ({
|
||||
id: "bg_1", description: "test", agent: "explore",
|
||||
@@ -92,7 +93,7 @@ describe("metadata model unification", () => {
|
||||
}
|
||||
await executeUnstableAgentTask(
|
||||
args, ctx,
|
||||
testCoerce({
|
||||
unsafeTestValue({
|
||||
manager: {
|
||||
launch: async () => launchedTask,
|
||||
getTask: () => launchedTask,
|
||||
@@ -126,7 +127,7 @@ describe("metadata model unification", () => {
|
||||
load_skills: [], run_in_background: true, task_id: "ses_resumed",
|
||||
}
|
||||
|
||||
await executeBackgroundContinuation(args, ctx, testCoerce({
|
||||
await executeBackgroundContinuation(args, ctx, unsafeTestValue({
|
||||
manager: {
|
||||
resume: async () => ({
|
||||
id: "bg_2", description: "continue", agent: "explore",
|
||||
@@ -153,7 +154,7 @@ describe("metadata model unification", () => {
|
||||
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
|
||||
}
|
||||
|
||||
await executeSyncContinuation(args, ctx, testCoerce({
|
||||
await executeSyncContinuation(args, ctx, unsafeTestValue({
|
||||
client: {
|
||||
session: {
|
||||
messages: async () => ({
|
||||
@@ -206,7 +207,7 @@ describe("metadata model unification", () => {
|
||||
load_skills: [], run_in_background: true, subagent_type: "explore",
|
||||
}
|
||||
|
||||
await executeBackgroundTask(args, ctx, testCoerce({
|
||||
await executeBackgroundTask(args, ctx, unsafeTestValue({
|
||||
manager: {
|
||||
launch: async () => ({
|
||||
id: "bg_1", description: "test", agent: "explore",
|
||||
@@ -236,7 +237,7 @@ describe("metadata model unification", () => {
|
||||
|
||||
await executeUnstableAgentTask(
|
||||
args, ctx,
|
||||
testCoerce({
|
||||
unsafeTestValue({
|
||||
manager: {
|
||||
launch: async () => launchedTask,
|
||||
getTask: () => launchedTask,
|
||||
@@ -270,7 +271,7 @@ describe("metadata model unification", () => {
|
||||
load_skills: [], run_in_background: true, task_id: "ses_resumed",
|
||||
}
|
||||
|
||||
await executeBackgroundContinuation(args, ctx, testCoerce({
|
||||
await executeBackgroundContinuation(args, ctx, unsafeTestValue({
|
||||
manager: {
|
||||
resume: async () => ({
|
||||
id: "bg_2", description: "continue", agent: "explore",
|
||||
@@ -297,7 +298,7 @@ describe("metadata model unification", () => {
|
||||
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
|
||||
}
|
||||
|
||||
await executeSyncContinuation(args, ctx, testCoerce({
|
||||
await executeSyncContinuation(args, ctx, unsafeTestValue({
|
||||
client: {
|
||||
session: {
|
||||
messages: async () => ({ data: [] }),
|
||||
@@ -381,7 +382,7 @@ describe("metadata model unification", () => {
|
||||
category: "visual-engineering", load_skills: [], run_in_background: true, subagent_type: "explore",
|
||||
}
|
||||
|
||||
await executeBackgroundTask(args, ctx, testCoerce({
|
||||
await executeBackgroundTask(args, ctx, unsafeTestValue({
|
||||
manager: {
|
||||
launch: async () => ({
|
||||
id: "bg_variant", description: "test", agent: "explore",
|
||||
@@ -411,7 +412,7 @@ describe("metadata model unification", () => {
|
||||
|
||||
await executeUnstableAgentTask(
|
||||
args, ctx,
|
||||
testCoerce({
|
||||
unsafeTestValue({
|
||||
manager: {
|
||||
launch: async () => launchedTask,
|
||||
getTask: () => launchedTask,
|
||||
@@ -445,7 +446,7 @@ describe("metadata model unification", () => {
|
||||
load_skills: [], run_in_background: true, task_id: "ses_resumed_variant",
|
||||
}
|
||||
|
||||
await executeBackgroundContinuation(args, ctx, testCoerce({
|
||||
await executeBackgroundContinuation(args, ctx, unsafeTestValue({
|
||||
manager: {
|
||||
resume: async () => ({
|
||||
id: "bg_resume_variant", description: "continue", agent: "explore",
|
||||
@@ -472,7 +473,7 @@ describe("metadata model unification", () => {
|
||||
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
|
||||
}
|
||||
|
||||
await executeSyncContinuation(args, ctx, testCoerce({
|
||||
await executeSyncContinuation(args, ctx, unsafeTestValue({
|
||||
client: {
|
||||
session: {
|
||||
messages: async () => ({
|
||||
|
||||
@@ -2,6 +2,7 @@ const { describe, test, expect } = require("bun:test")
|
||||
|
||||
import type { DelegateTaskArgs, ToolContextWithMetadata } from "./types"
|
||||
import type { ParentContext } from "./executor-types"
|
||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||
|
||||
const MODEL = { providerID: "anthropic", modelID: "claude-sonnet-4-6" }
|
||||
|
||||
@@ -64,7 +65,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
|
||||
load_skills: [], run_in_background: true, subagent_type: "explore",
|
||||
}
|
||||
|
||||
await executeBackgroundTask(args, ctx, testCoerce({
|
||||
await executeBackgroundTask(args, ctx, unsafeTestValue({
|
||||
manager: {
|
||||
launch: async () => ({
|
||||
id: "bg_abc123", description: "test", agent: "explore",
|
||||
@@ -98,7 +99,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
|
||||
|
||||
await executeUnstableAgentTask(
|
||||
args, ctx,
|
||||
testCoerce({
|
||||
unsafeTestValue({
|
||||
manager: {
|
||||
launch: async () => launchedTask,
|
||||
getTask: () => launchedTask,
|
||||
@@ -136,7 +137,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
|
||||
load_skills: [], run_in_background: true, task_id: "ses_resumed_x",
|
||||
}
|
||||
|
||||
await executeBackgroundContinuation(args, ctx, testCoerce({
|
||||
await executeBackgroundContinuation(args, ctx, unsafeTestValue({
|
||||
manager: {
|
||||
resume: async () => ({
|
||||
id: "bg_resumed_y", description: "continue", agent: "explore",
|
||||
@@ -160,7 +161,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
|
||||
load_skills: [], run_in_background: true, task_id: "ses_resumed_x",
|
||||
}
|
||||
|
||||
await executeBackgroundContinuation(args, ctx, testCoerce({
|
||||
await executeBackgroundContinuation(args, ctx, unsafeTestValue({
|
||||
manager: {
|
||||
resume: async () => ({
|
||||
id: "bg_resumed_y", description: "continue", agent: "explore",
|
||||
@@ -187,7 +188,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
|
||||
task_id: "ses_resumed_x",
|
||||
}
|
||||
|
||||
await executeBackgroundContinuation(args, ctx, testCoerce({
|
||||
await executeBackgroundContinuation(args, ctx, unsafeTestValue({
|
||||
manager: {
|
||||
resume: async () => ({
|
||||
id: "bg_resumed_y", description: "continue", agent: "explore",
|
||||
@@ -216,7 +217,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
|
||||
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
|
||||
}
|
||||
|
||||
await executeSyncContinuation(args, ctx, testCoerce({
|
||||
await executeSyncContinuation(args, ctx, unsafeTestValue({
|
||||
client: {
|
||||
session: {
|
||||
messages: async () => ({
|
||||
@@ -246,7 +247,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
|
||||
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
|
||||
}
|
||||
|
||||
await executeSyncContinuation(args, ctx, testCoerce({
|
||||
await executeSyncContinuation(args, ctx, unsafeTestValue({
|
||||
client: {
|
||||
session: {
|
||||
messages: async () => ({
|
||||
@@ -275,7 +276,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
|
||||
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
|
||||
}
|
||||
|
||||
await executeSyncContinuation(args, ctx, testCoerce({
|
||||
await executeSyncContinuation(args, ctx, unsafeTestValue({
|
||||
client: {
|
||||
session: {
|
||||
messages: async () => ({
|
||||
@@ -309,7 +310,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
|
||||
fetchSyncResult: async () => ({ ok: true as const, textContent: "done" }),
|
||||
}
|
||||
|
||||
await executeSyncContinuation(args, ctx, testCoerce({
|
||||
await executeSyncContinuation(args, ctx, unsafeTestValue({
|
||||
client: {
|
||||
session: {
|
||||
messages: async () => ({
|
||||
@@ -368,7 +369,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
|
||||
run_in_background: true,
|
||||
}
|
||||
|
||||
await executeBackgroundTask(args, ctx, testCoerce({
|
||||
await executeBackgroundTask(args, ctx, unsafeTestValue({
|
||||
manager: {
|
||||
launch: async () => ({
|
||||
id: "bg_abc123", description: "test", agent: "Sisyphus-Junior",
|
||||
@@ -402,7 +403,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
|
||||
|
||||
await executeUnstableAgentTask(
|
||||
args, ctx,
|
||||
testCoerce({
|
||||
unsafeTestValue({
|
||||
manager: {
|
||||
launch: async () => launchedTask,
|
||||
getTask: () => launchedTask,
|
||||
@@ -438,7 +439,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
|
||||
load_skills: [], run_in_background: true, task_id: "ses_resume_title",
|
||||
}
|
||||
|
||||
await executeBackgroundContinuation(args, ctx, testCoerce({
|
||||
await executeBackgroundContinuation(args, ctx, unsafeTestValue({
|
||||
manager: {
|
||||
resume: async () => ({
|
||||
id: "bg_resume_title", description: "continue work", agent: "explore",
|
||||
@@ -460,7 +461,7 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
|
||||
load_skills: [], run_in_background: false, task_id: "ses_sync_title",
|
||||
}
|
||||
|
||||
await executeSyncContinuation(args, ctx, testCoerce({
|
||||
await executeSyncContinuation(args, ctx, unsafeTestValue({
|
||||
client: {
|
||||
session: {
|
||||
messages: async () => ({
|
||||
@@ -500,8 +501,8 @@ describe("taskId and backgroundTaskId metadata consistency", () => {
|
||||
},
|
||||
}
|
||||
|
||||
const bgOutput = createBackgroundOutput(testCoerce(manager), testCoerce(client))
|
||||
await bgOutput.execute(testCoerce({ task_id: "bg_output_xyz" }), testCoerce(ctx))
|
||||
const bgOutput = createBackgroundOutput(unsafeTestValue(manager), unsafeTestValue(client))
|
||||
await bgOutput.execute(unsafeTestValue({ task_id: "bg_output_xyz" }), unsafeTestValue(ctx))
|
||||
|
||||
const meta = ctx.captured.find((m: any) => m.metadata?.backgroundTaskId)
|
||||
expect(meta).toBeDefined()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||
const { describe, expect, test } = require("bun:test")
|
||||
|
||||
function requireFresh<T>(modulePath: string): T {
|
||||
@@ -18,7 +19,7 @@ function createDelegateTask(...args: Parameters<typeof import("./tools").createD
|
||||
const toolDefinition = createDelegateTask({ manager: {} as never, client: {} as never, directory: "/tmp/test" })
|
||||
|
||||
//#when
|
||||
const categorySchema = testCoerce<{
|
||||
const categorySchema = unsafeTestValue<{
|
||||
def: {
|
||||
type: string
|
||||
innerType: {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
|
||||
import { executeUnstableAgentTask } from "./unstable-agent-task"
|
||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||
|
||||
describe("executeUnstableAgentTask session permission", () => {
|
||||
test("passes question-deny session permission into background launch", async () => {
|
||||
@@ -33,7 +34,7 @@ describe("executeUnstableAgentTask session permission", () => {
|
||||
metadata: () => {},
|
||||
abort: new AbortController().signal,
|
||||
} satisfies Parameters<typeof executeUnstableAgentTask>[1]
|
||||
const executorContext = testCoerce<Parameters<typeof executeUnstableAgentTask>[2]>({
|
||||
const executorContext = unsafeTestValue<Parameters<typeof executeUnstableAgentTask>[2]>({
|
||||
manager: mockManager,
|
||||
client: {
|
||||
session: {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, expect, it } from "bun:test"
|
||||
import { normalizeHashlineEdits, type RawHashlineEdit } from "./normalize-edits"
|
||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||
|
||||
describe("normalizeHashlineEdits", () => {
|
||||
it("maps replace with pos to replace", () => {
|
||||
@@ -51,7 +52,7 @@ describe("normalizeHashlineEdits", () => {
|
||||
|
||||
it("rejects legacy payload without op", () => {
|
||||
//#given
|
||||
const input = testCoerce<Parameters<
|
||||
const input = unsafeTestValue<Parameters<
|
||||
typeof normalizeHashlineEdits
|
||||
>[0]>([{ type: "set_line", line: "2#VK", text: "updated" }])
|
||||
|
||||
|
||||
@@ -6,9 +6,10 @@ import { canonicalizeFileText } from "./file-text-canonicalization"
|
||||
import * as fs from "node:fs"
|
||||
import * as os from "node:os"
|
||||
import * as path from "node:path"
|
||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||
|
||||
function createMockContext(): ToolContext {
|
||||
return testCoerce<ToolContext>({
|
||||
return unsafeTestValue<ToolContext>({
|
||||
sessionID: "test",
|
||||
messageID: "test",
|
||||
agent: "test",
|
||||
|
||||
@@ -6,6 +6,7 @@ import { resolveMultimodalLookerAgentMetadata } from "./multimodal-agent-metadat
|
||||
import { setVisionCapableModelsCache, clearVisionCapableModelsCache } from "../../shared/vision-capable-models-cache"
|
||||
import * as connectedProvidersCache from "../../shared/connected-providers-cache"
|
||||
import * as modelAvailability from "../../shared/model-availability"
|
||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||
|
||||
function createPluginInput(agentData: Array<Record<string, unknown>>): PluginInput {
|
||||
const client = {} as PluginInput["client"]
|
||||
@@ -32,8 +33,8 @@ describe("resolveMultimodalLookerAgentMetadata", () => {
|
||||
|
||||
afterEach(() => {
|
||||
clearVisionCapableModelsCache()
|
||||
;(testCoerce<{ mockRestore?: () => void }>(modelAvailability.fetchAvailableModels)).mockRestore?.()
|
||||
;(testCoerce<{ mockRestore?: () => void }>(connectedProvidersCache.readConnectedProvidersCache)).mockRestore?.()
|
||||
;(unsafeTestValue<{ mockRestore?: () => void }>(modelAvailability.fetchAvailableModels)).mockRestore?.()
|
||||
;(unsafeTestValue<{ mockRestore?: () => void }>(connectedProvidersCache.readConnectedProvidersCache)).mockRestore?.()
|
||||
})
|
||||
|
||||
test("returns configured multimodal-looker model when it already matches a vision-capable override", async () => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, expect, test, mock } from "bun:test"
|
||||
import { pollSessionUntilIdle } from "./session-poller"
|
||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||
|
||||
type SessionStatusResult = {
|
||||
data?: Record<string, { type: string; attempt?: number; message?: string; next?: number }>
|
||||
@@ -30,7 +31,7 @@ describe("pollSessionUntilIdle", () => {
|
||||
{ data: { ses_test: { type: "idle" } } },
|
||||
])
|
||||
|
||||
await pollSessionUntilIdle(testCoerce(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
|
||||
await pollSessionUntilIdle(unsafeTestValue(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
|
||||
|
||||
expect(client.session.status).toHaveBeenCalledTimes(3)
|
||||
})
|
||||
@@ -43,7 +44,7 @@ describe("pollSessionUntilIdle", () => {
|
||||
{ data: {} },
|
||||
])
|
||||
|
||||
await pollSessionUntilIdle(testCoerce(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
|
||||
await pollSessionUntilIdle(unsafeTestValue(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
|
||||
|
||||
expect(client.session.status).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
@@ -57,7 +58,7 @@ describe("pollSessionUntilIdle", () => {
|
||||
])
|
||||
|
||||
await expect(
|
||||
pollSessionUntilIdle(testCoerce(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 50 })
|
||||
pollSessionUntilIdle(unsafeTestValue(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 50 })
|
||||
).rejects.toThrow("timed out")
|
||||
})
|
||||
|
||||
@@ -69,7 +70,7 @@ describe("pollSessionUntilIdle", () => {
|
||||
{ error: new Error("API error") },
|
||||
])
|
||||
|
||||
await pollSessionUntilIdle(testCoerce(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
|
||||
await pollSessionUntilIdle(unsafeTestValue(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
|
||||
|
||||
expect(client.session.status).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
@@ -85,7 +86,7 @@ describe("pollSessionUntilIdle", () => {
|
||||
{ data: {} },
|
||||
])
|
||||
|
||||
await pollSessionUntilIdle(testCoerce(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
|
||||
await pollSessionUntilIdle(unsafeTestValue(client), "ses_test", { pollIntervalMs: 10, timeoutMs: 5000 })
|
||||
|
||||
expect(client.session.status).toHaveBeenCalledTimes(4)
|
||||
})
|
||||
@@ -98,7 +99,7 @@ describe("pollSessionUntilIdle", () => {
|
||||
{ data: {} },
|
||||
])
|
||||
|
||||
await pollSessionUntilIdle(testCoerce(client), "ses_test")
|
||||
await pollSessionUntilIdle(unsafeTestValue(client), "ses_test")
|
||||
|
||||
expect(client.session.status).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
@@ -2,6 +2,7 @@ import { afterEach, describe, expect, test, mock } from "bun:test"
|
||||
import type { ToolContext } from "@opencode-ai/plugin/tool"
|
||||
import { clearVisionCapableModelsCache, setVisionCapableModelsCache } from "../../shared/vision-capable-models-cache"
|
||||
import { normalizeArgs, validateArgs, createLookAt } from "./tools"
|
||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||
|
||||
describe("look-at tool", () => {
|
||||
afterEach(() => {
|
||||
@@ -14,7 +15,7 @@ describe("look-at tool", () => {
|
||||
// then should normalize to file_path
|
||||
test("normalizes path to file_path for LLM compatibility", () => {
|
||||
const args = { path: "/some/file.png", goal: "analyze" }
|
||||
const normalized = normalizeArgs(testCoerce(args))
|
||||
const normalized = normalizeArgs(unsafeTestValue(args))
|
||||
expect(normalized.file_path).toBe("/some/file.png")
|
||||
expect(normalized.goal).toBe("analyze")
|
||||
})
|
||||
@@ -33,7 +34,7 @@ describe("look-at tool", () => {
|
||||
// then prefer file_path
|
||||
test("prefers file_path over path when both provided", () => {
|
||||
const args = { file_path: "/preferred.png", path: "/fallback.png", goal: "test" }
|
||||
const normalized = normalizeArgs(testCoerce(args))
|
||||
const normalized = normalizeArgs(unsafeTestValue(args))
|
||||
expect(normalized.file_path).toBe("/preferred.png")
|
||||
})
|
||||
|
||||
@@ -42,7 +43,7 @@ describe("look-at tool", () => {
|
||||
// then preserve image_data in normalized args
|
||||
test("preserves image_data when provided", () => {
|
||||
const args = { image_data: "data:image/png;base64,iVBORw0KGgo=", goal: "analyze" }
|
||||
const normalized = normalizeArgs(testCoerce(args))
|
||||
const normalized = normalizeArgs(unsafeTestValue(args))
|
||||
expect(normalized.image_data).toBe("data:image/png;base64,iVBORw0KGgo=")
|
||||
expect(normalized.file_path).toBeUndefined()
|
||||
})
|
||||
@@ -69,7 +70,7 @@ describe("look-at tool", () => {
|
||||
// when validated
|
||||
// then clear error message
|
||||
test("returns error when neither file_path nor image_data provided", () => {
|
||||
const args = testCoerce({ goal: "analyze" })
|
||||
const args = unsafeTestValue({ goal: "analyze" })
|
||||
const error = validateArgs(args)
|
||||
expect(error).toContain("file_path")
|
||||
expect(error).toContain("image_data")
|
||||
@@ -88,7 +89,7 @@ describe("look-at tool", () => {
|
||||
// when validated
|
||||
// then clear error message
|
||||
test("returns error when goal is missing", () => {
|
||||
const args = testCoerce({ file_path: "/some/path.png" })
|
||||
const args = unsafeTestValue({ file_path: "/some/path.png" })
|
||||
const error = validateArgs(args)
|
||||
expect(error).toContain("goal")
|
||||
expect(error).toContain("required")
|
||||
@@ -156,7 +157,7 @@ describe("look-at tool", () => {
|
||||
},
|
||||
}
|
||||
|
||||
const tool = createLookAt(testCoerce({
|
||||
const tool = createLookAt(unsafeTestValue({
|
||||
client: mockClient,
|
||||
directory: "/project",
|
||||
}))
|
||||
@@ -193,7 +194,7 @@ describe("look-at tool", () => {
|
||||
},
|
||||
}
|
||||
|
||||
const tool = createLookAt(testCoerce({
|
||||
const tool = createLookAt(unsafeTestValue({
|
||||
client: mockClient,
|
||||
directory: "/project",
|
||||
}))
|
||||
@@ -230,7 +231,7 @@ describe("look-at tool", () => {
|
||||
},
|
||||
}
|
||||
|
||||
const tool = createLookAt(testCoerce({
|
||||
const tool = createLookAt(unsafeTestValue({
|
||||
client: mockClient,
|
||||
directory: "/project",
|
||||
}))
|
||||
@@ -291,7 +292,7 @@ describe("look-at tool", () => {
|
||||
},
|
||||
}
|
||||
|
||||
const tool = createLookAt(testCoerce({
|
||||
const tool = createLookAt(unsafeTestValue({
|
||||
client: mockClient,
|
||||
directory: "/project",
|
||||
}))
|
||||
@@ -346,7 +347,7 @@ describe("look-at tool", () => {
|
||||
},
|
||||
}
|
||||
|
||||
const tool = createLookAt(testCoerce({
|
||||
const tool = createLookAt(unsafeTestValue({
|
||||
client: mockClient,
|
||||
directory: "/project",
|
||||
}))
|
||||
@@ -395,7 +396,7 @@ describe("look-at tool", () => {
|
||||
},
|
||||
}
|
||||
|
||||
const tool = createLookAt(testCoerce({
|
||||
const tool = createLookAt(unsafeTestValue({
|
||||
client: mockClient,
|
||||
directory: "/project",
|
||||
}))
|
||||
@@ -437,7 +438,7 @@ describe("look-at tool", () => {
|
||||
},
|
||||
}
|
||||
|
||||
const tool = createLookAt(testCoerce({
|
||||
const tool = createLookAt(unsafeTestValue({
|
||||
client: mockClient,
|
||||
directory: "/project",
|
||||
}))
|
||||
@@ -486,7 +487,7 @@ describe("look-at tool", () => {
|
||||
},
|
||||
}
|
||||
|
||||
const tool = createLookAt(testCoerce({
|
||||
const tool = createLookAt(unsafeTestValue({
|
||||
client: mockClient,
|
||||
directory: "/project",
|
||||
}))
|
||||
@@ -515,7 +516,7 @@ describe("look-at tool", () => {
|
||||
},
|
||||
}
|
||||
|
||||
const tool = createLookAt(testCoerce({
|
||||
const tool = createLookAt(unsafeTestValue({
|
||||
client: mockClient,
|
||||
directory: "/project",
|
||||
}))
|
||||
@@ -539,7 +540,7 @@ describe("look-at tool", () => {
|
||||
},
|
||||
}
|
||||
|
||||
const tool = createLookAt(testCoerce({
|
||||
const tool = createLookAt(unsafeTestValue({
|
||||
client: mockClient,
|
||||
directory: "/project",
|
||||
}))
|
||||
@@ -579,7 +580,7 @@ describe("look-at tool", () => {
|
||||
},
|
||||
}
|
||||
|
||||
const tool = createLookAt(testCoerce({
|
||||
const tool = createLookAt(unsafeTestValue({
|
||||
client: mockClient,
|
||||
directory: "/project",
|
||||
}))
|
||||
@@ -632,7 +633,7 @@ describe("look-at tool", () => {
|
||||
},
|
||||
}
|
||||
|
||||
const tool = createLookAt(testCoerce({
|
||||
const tool = createLookAt(unsafeTestValue({
|
||||
client: mockClient,
|
||||
directory: "/project",
|
||||
}))
|
||||
@@ -701,7 +702,7 @@ describe("look-at tool", () => {
|
||||
test("instructs agent to analyze attached file when Read is disabled (file_path mode)", async () => {
|
||||
const { mockClient, captured } = captureLastPromptBody()
|
||||
|
||||
const tool = createLookAt(testCoerce({
|
||||
const tool = createLookAt(unsafeTestValue({
|
||||
client: mockClient,
|
||||
directory: "/project",
|
||||
}))
|
||||
@@ -726,7 +727,7 @@ describe("look-at tool", () => {
|
||||
test("instructs agent to analyze attached image when image_data is provided", async () => {
|
||||
const { mockClient, captured } = captureLastPromptBody()
|
||||
|
||||
const tool = createLookAt(testCoerce({
|
||||
const tool = createLookAt(unsafeTestValue({
|
||||
client: mockClient,
|
||||
directory: "/project",
|
||||
}))
|
||||
@@ -751,7 +752,7 @@ describe("look-at tool", () => {
|
||||
test("explicitly warns the agent not to attempt Read when Read is disabled", async () => {
|
||||
const { mockClient, captured } = captureLastPromptBody()
|
||||
|
||||
const tool = createLookAt(testCoerce({
|
||||
const tool = createLookAt(unsafeTestValue({
|
||||
client: mockClient,
|
||||
directory: "/project",
|
||||
}))
|
||||
|
||||
@@ -16,6 +16,7 @@ afterAll(() => { mock.restore() })
|
||||
|
||||
import { LSPClient, lspManager, validateCwd } from "./client"
|
||||
import type { ResolvedServer } from "./types"
|
||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||
|
||||
describe("LSPClient", () => {
|
||||
beforeEach(async () => {
|
||||
@@ -36,7 +37,7 @@ describe("LSPClient", () => {
|
||||
const originalSetTimeout = globalThis.setTimeout
|
||||
globalThis.setTimeout = ((fn: (...args: unknown[]) => void, _ms?: number) => {
|
||||
fn()
|
||||
return testCoerce<ReturnType<typeof setTimeout>>(0)
|
||||
return unsafeTestValue<ReturnType<typeof setTimeout>>(0)
|
||||
}) as typeof setTimeout
|
||||
|
||||
const server: ResolvedServer = {
|
||||
@@ -50,7 +51,7 @@ describe("LSPClient", () => {
|
||||
|
||||
// Stub protocol output: we only want to assert notifications.
|
||||
const sendNotificationSpy = spyOn(
|
||||
testCoerce<{ sendNotification: (m: string, p?: unknown) => void }>(client),
|
||||
unsafeTestValue<{ sendNotification: (m: string, p?: unknown) => void }>(client),
|
||||
"sendNotification"
|
||||
)
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { mkdirSync, writeFileSync, rmSync, existsSync, readdirSync } from "node:
|
||||
import { join } from "node:path"
|
||||
import { tmpdir } from "node:os"
|
||||
import { randomUUID } from "node:crypto"
|
||||
import { unsafeTestValue } from "../../../test-support/unsafe-test-value"
|
||||
|
||||
const TEST_DIR = join(tmpdir(), `omo-test-session-manager-${randomUUID()}`)
|
||||
const TEST_MESSAGE_STORAGE = join(TEST_DIR, "message")
|
||||
@@ -448,7 +449,7 @@ describe("session-manager storage - SDK path (beta mode)", () => {
|
||||
|
||||
// Re-import to get fresh module with mocked isSqliteBackend
|
||||
const { setStorageClient, getMainSessions } = await import("./storage")
|
||||
setStorageClient(testCoerce<Parameters<typeof setStorageClient>[0]>(mockClient))
|
||||
setStorageClient(unsafeTestValue<Parameters<typeof setStorageClient>[0]>(mockClient))
|
||||
|
||||
// when
|
||||
const sessions = await getMainSessions({ directory: "/test" })
|
||||
@@ -473,7 +474,7 @@ describe("session-manager storage - SDK path (beta mode)", () => {
|
||||
}))
|
||||
|
||||
const { setStorageClient, getAllSessions } = await import("./storage")
|
||||
setStorageClient(testCoerce<Parameters<typeof setStorageClient>[0]>(mockClient))
|
||||
setStorageClient(unsafeTestValue<Parameters<typeof setStorageClient>[0]>(mockClient))
|
||||
|
||||
// when
|
||||
const sessionIDs = await getAllSessions()
|
||||
@@ -503,7 +504,7 @@ describe("session-manager storage - SDK path (beta mode)", () => {
|
||||
}))
|
||||
|
||||
const { setStorageClient, readSessionMessages } = await import("./storage")
|
||||
setStorageClient(testCoerce<Parameters<typeof setStorageClient>[0]>(mockClient))
|
||||
setStorageClient(unsafeTestValue<Parameters<typeof setStorageClient>[0]>(mockClient))
|
||||
|
||||
// when
|
||||
const messages = await readSessionMessages("ses_test")
|
||||
@@ -531,7 +532,7 @@ describe("session-manager storage - SDK path (beta mode)", () => {
|
||||
}))
|
||||
|
||||
const { setStorageClient, readSessionTodos } = await import("./storage")
|
||||
setStorageClient(testCoerce<Parameters<typeof setStorageClient>[0]>(mockClient))
|
||||
setStorageClient(unsafeTestValue<Parameters<typeof setStorageClient>[0]>(mockClient))
|
||||
|
||||
// when
|
||||
const todos = await readSessionTodos("ses_test")
|
||||
@@ -555,7 +556,7 @@ describe("session-manager storage - SDK path (beta mode)", () => {
|
||||
}))
|
||||
|
||||
const { setStorageClient, readSessionMessages } = await import("./storage")
|
||||
setStorageClient(testCoerce<Parameters<typeof setStorageClient>[0]>(mockClient))
|
||||
setStorageClient(unsafeTestValue<Parameters<typeof setStorageClient>[0]>(mockClient))
|
||||
|
||||
await expect(readSessionMessages("ses_test")).rejects.toThrow("API error")
|
||||
})
|
||||
|
||||
@@ -12,6 +12,7 @@ import { clearSkillCache } from "../../../features/opencode-skill-loader/skill-c
|
||||
import type { LoadedSkill } from "../../../features/opencode-skill-loader/types"
|
||||
import type { CommandInfo } from "../../slashcommand/types"
|
||||
import type { Tool as McpTool } from "@modelcontextprotocol/sdk/types.js"
|
||||
import { unsafeTestValue } from "../../../../test-support/unsafe-test-value"
|
||||
|
||||
const originalReadFileSync = fs.readFileSync.bind(fs)
|
||||
|
||||
@@ -205,7 +206,7 @@ describe("skill tool - agent restriction", () => {
|
||||
// given
|
||||
const loadedSkills = [createMockSkill("sisyphus-only-skill", { agent: "sisyphus" })]
|
||||
const tool = createSkillTool({ skills: loadedSkills })
|
||||
const contextWithoutAgent = { ...mockContext, agent: testCoerce<string>(undefined) }
|
||||
const contextWithoutAgent = { ...mockContext, agent: unsafeTestValue<string>(undefined) }
|
||||
|
||||
// when / #then
|
||||
return expect(tool.execute({ name: "sisyphus-only-skill" }, contextWithoutAgent)).rejects.toThrow(
|
||||
|
||||
Reference in New Issue
Block a user