fix(ci): simplify test runner to plain bun test by fixing mock.module() leakage
- Add afterAll(() => { mock.restore() }) to 52 test files missing cleanup
- Rewrite create-tool-guard-hooks.test.ts to use spyOn instead of barrel mock
- Fix skill-mcp-manager OAuth tests with missing mockTokens/mockLogin definitions
- Fix start-work hook: show worktree active block on resume with existing worktree_path
- Extract createWorktreeActiveBlock to worktree-block.ts to avoid circular import
- Replace 80-line isolated test runner CI config with single `bun test` command
This commit is contained in:
+5
-1
@@ -1,4 +1,4 @@
|
||||
import { describe, it, expect, mock, beforeEach } from "bun:test"
|
||||
import { afterAll, describe, it, expect, mock, beforeEach } from "bun:test"
|
||||
import { fixEmptyMessagesWithSDK } from "./empty-content-recovery-sdk"
|
||||
|
||||
const mockReplaceEmptyTextParts = mock(() => Promise.resolve(false))
|
||||
@@ -11,6 +11,10 @@ mock.module("../session-recovery/storage/text-part-injector", () => ({
|
||||
injectTextPartAsync: mockInjectTextPart,
|
||||
}))
|
||||
|
||||
afterAll(() => {
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
function createMockClient(messages: Array<{ info?: { id?: string }; parts?: Array<{ type?: string; text?: string }> }>) {
|
||||
return {
|
||||
session: {
|
||||
|
||||
@@ -11,6 +11,7 @@ mock.module("./deduplication-recovery", () => ({
|
||||
|
||||
afterAll(() => {
|
||||
mock.module("./deduplication-recovery", () => originalDeduplicationRecovery)
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
function createImmediateTimeouts(): () => void {
|
||||
|
||||
@@ -13,6 +13,7 @@ mock.module("./storage", () => {
|
||||
|
||||
afterAll(() => {
|
||||
mock.module("./storage", () => storage)
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
describe("truncateUntilTargetTokens", () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
declare const require: (name: string) => any
|
||||
const { afterEach, beforeEach, describe, expect, mock, test } = require("bun:test")
|
||||
const { afterEach, beforeEach, describe, expect, mock, test, afterAll } = require("bun:test")
|
||||
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs"
|
||||
import { tmpdir } from "node:os"
|
||||
import { join } from "node:path"
|
||||
@@ -30,6 +30,8 @@ mock.module("../../shared/opencode-storage-detection", () => ({
|
||||
isSqliteBackend: () => false,
|
||||
}))
|
||||
|
||||
afterAll(() => { mock.restore() })
|
||||
|
||||
const { createAtlasHook } = await import("./index")
|
||||
|
||||
describe("atlas hook compaction agent filtering", () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test"
|
||||
import { afterEach, beforeEach, describe, expect, mock, test, afterAll } from "bun:test"
|
||||
import { randomUUID } from "node:crypto"
|
||||
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs"
|
||||
import { tmpdir } from "node:os"
|
||||
@@ -29,6 +29,8 @@ mock.module("../../shared/opencode-storage-detection", () => ({
|
||||
isSqliteBackend: () => false,
|
||||
}))
|
||||
|
||||
afterAll(() => { mock.restore() })
|
||||
|
||||
const { createAtlasHook } = await import("./index")
|
||||
const { MESSAGE_STORAGE } = await import("../../features/hook-message-injector")
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test"
|
||||
import { afterEach, beforeEach, describe, expect, mock, test, afterAll } from "bun:test"
|
||||
import { randomUUID } from "node:crypto"
|
||||
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs"
|
||||
import { tmpdir } from "node:os"
|
||||
@@ -29,6 +29,8 @@ mock.module("../../shared/opencode-storage-detection", () => ({
|
||||
isSqliteBackend: () => false,
|
||||
}))
|
||||
|
||||
afterAll(() => { mock.restore() })
|
||||
|
||||
const { createAtlasHook } = await import("./index")
|
||||
const { MESSAGE_STORAGE } = await import("../../features/hook-message-injector")
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, test, beforeEach, afterEach, mock } from "bun:test"
|
||||
import { describe, expect, test, beforeEach, afterEach, mock, afterAll } from "bun:test"
|
||||
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs"
|
||||
import { join } from "node:path"
|
||||
import { tmpdir } from "node:os"
|
||||
@@ -33,6 +33,8 @@ mock.module("../../shared/opencode-storage-detection", () => ({
|
||||
isSqliteBackend: () => false,
|
||||
}))
|
||||
|
||||
afterAll(() => { mock.restore() })
|
||||
|
||||
const { createAtlasHook } = await import("./index")
|
||||
const { createToolExecuteAfterHandler } = await import("./tool-execute-after")
|
||||
const { createToolExecuteBeforeHandler } = await import("./tool-execute-before")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { describe, expect, mock, test } = require("bun:test")
|
||||
const { describe, expect, mock, test, afterAll } = require("bun:test")
|
||||
|
||||
mock.module("../../shared/opencode-message-dir", () => ({
|
||||
getMessageDir: () => null,
|
||||
@@ -12,6 +12,8 @@ mock.module("../../shared/normalize-sdk-response", () => ({
|
||||
normalizeSDKResponse: <TData>(response: { data?: TData }, fallback: TData): TData => response.data ?? fallback,
|
||||
}))
|
||||
|
||||
afterAll(() => { mock.restore() })
|
||||
|
||||
const { getLastAgentFromSession } = await import("./session-last-agent")
|
||||
|
||||
function createMockClient(messages: Array<{ info?: { agent?: string } }>) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/// <reference types="bun-types" />
|
||||
|
||||
import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test"
|
||||
import { afterEach, beforeEach, describe, expect, it, mock, afterAll } from "bun:test"
|
||||
import { existsSync, mkdirSync, rmSync } from "node:fs"
|
||||
import { tmpdir } from "node:os"
|
||||
import { join } from "node:path"
|
||||
@@ -23,6 +23,8 @@ mock.module("../../shared/git-worktree", () => ({
|
||||
formatFileChanges: mock(() => "No file changes"),
|
||||
}))
|
||||
|
||||
afterAll(() => { mock.restore() })
|
||||
|
||||
const { createToolExecuteAfterHandler } = await import("./tool-execute-after")
|
||||
|
||||
describe("createToolExecuteAfterHandler background launch detection", () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { beforeEach, describe, expect, it, mock, spyOn } from "bun:test"
|
||||
import { afterAll, beforeEach, describe, expect, it, mock, spyOn } from "bun:test"
|
||||
import { AUTO_SLASH_COMMAND_TAG_OPEN } from "./constants"
|
||||
import type {
|
||||
AutoSlashCommandHookInput,
|
||||
@@ -19,6 +19,10 @@ mock.module("./executor", () => ({
|
||||
executeSlashCommand: executeSlashCommandMock,
|
||||
}))
|
||||
|
||||
afterAll(() => {
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
const logMock = spyOn(shared, "log").mockImplementation(() => {})
|
||||
|
||||
const { createAutoSlashCommandHook } = await import("./hook")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, it, mock } from "bun:test"
|
||||
import { afterAll, describe, expect, it, mock } from "bun:test"
|
||||
import type { LoadedSkill } from "../../features/opencode-skill-loader"
|
||||
|
||||
mock.module("../../shared", () => ({
|
||||
@@ -27,6 +27,10 @@ mock.module("../../features/opencode-skill-loader", () => ({
|
||||
discoverAllSkills: async (): Promise<LoadedSkill[]> => [],
|
||||
}))
|
||||
|
||||
afterAll(() => {
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
const { executeSlashCommand } = await import("./executor")
|
||||
|
||||
function createRestrictedSkill(): LoadedSkill {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test"
|
||||
import { afterAll, afterEach, beforeEach, describe, expect, it, mock } from "bun:test"
|
||||
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"
|
||||
import { join } from "node:path"
|
||||
|
||||
@@ -16,6 +16,10 @@ mock.module("../../shared/logger", () => ({
|
||||
log: () => {},
|
||||
}))
|
||||
|
||||
afterAll(() => {
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
function resetTestCache(): void {
|
||||
if (existsSync(TEST_CACHE_DIR)) {
|
||||
rmSync(TEST_CACHE_DIR, { recursive: true, force: true })
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test"
|
||||
import { afterAll, afterEach, beforeEach, describe, expect, it, mock } from "bun:test"
|
||||
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"
|
||||
import { join } from "node:path"
|
||||
import type { PluginEntryInfo } from "./plugin-entry"
|
||||
@@ -22,6 +22,10 @@ mock.module("../../../shared/logger", () => ({
|
||||
log: () => {},
|
||||
}))
|
||||
|
||||
afterAll(() => {
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
function resetTestCache(currentVersion = "3.10.0"): void {
|
||||
if (existsSync(TEST_CACHE_DIR)) {
|
||||
rmSync(TEST_CACHE_DIR, { recursive: true, force: true })
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test"
|
||||
import { afterAll, afterEach, beforeEach, describe, expect, it, mock } from "bun:test"
|
||||
|
||||
const mockShowConfigErrorsIfAny = mock(async () => {})
|
||||
const mockShowModelCacheWarningIfNeeded = mock(async () => {})
|
||||
@@ -45,6 +45,10 @@ mock.module("../../shared/logger", () => ({
|
||||
log: () => {},
|
||||
}))
|
||||
|
||||
afterAll(() => {
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
type HookFactory = typeof import("./hook").createAutoUpdateCheckerHook
|
||||
|
||||
async function importFreshHookFactory(): Promise<HookFactory> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { PluginInput } from "@opencode-ai/plugin"
|
||||
import { beforeEach, describe, expect, it, mock } from "bun:test"
|
||||
import { afterAll, beforeEach, describe, expect, it, mock } from "bun:test"
|
||||
|
||||
type PluginEntry = {
|
||||
entry: string
|
||||
@@ -51,6 +51,10 @@ mock.module("./update-toasts", () => ({
|
||||
}))
|
||||
mock.module("../../../shared/logger", () => ({ log: () => {} }))
|
||||
|
||||
afterAll(() => {
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
const modulePath = "./background-update-check?test"
|
||||
const { runBackgroundUpdateCheck } = await import(modulePath)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { PluginInput } from "@opencode-ai/plugin"
|
||||
import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test"
|
||||
import { afterAll, afterEach, beforeEach, describe, expect, it, mock } from "bun:test"
|
||||
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs"
|
||||
import { join } from "node:path"
|
||||
|
||||
@@ -101,6 +101,10 @@ mock.module("../../../shared/opencode-config-dir", () => ({
|
||||
}),
|
||||
}))
|
||||
|
||||
afterAll(() => {
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
const modulePath = "./background-update-check?test"
|
||||
const { runBackgroundUpdateCheck } = await import(modulePath)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { beforeEach, describe, expect, mock, test } = require("bun:test")
|
||||
const { beforeEach, describe, expect, mock, test, afterAll } = require("bun:test")
|
||||
|
||||
const executeStopHooks = mock(async (context: { parentSessionId?: string }) => ({
|
||||
block: false,
|
||||
@@ -19,6 +19,8 @@ mock.module("../stop", () => ({
|
||||
executeStopHooks,
|
||||
}))
|
||||
|
||||
afterAll(() => { mock.restore() })
|
||||
|
||||
const { createSessionEventHandler } = await import("./session-event-handler")
|
||||
|
||||
describe("createSessionEventHandler retry behavior", () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { beforeEach, describe, expect, it, mock } from "bun:test"
|
||||
import { beforeEach, describe, expect, it, mock, afterAll } from "bun:test"
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value)
|
||||
@@ -26,6 +26,8 @@ mock.module("../transcript", () => ({
|
||||
getTranscriptPath: () => "/tmp/transcript.jsonl",
|
||||
}))
|
||||
|
||||
afterAll(() => { mock.restore() })
|
||||
|
||||
const { createToolExecuteAfterHandler } = await import("./tool-execute-after-handler")
|
||||
|
||||
describe("createToolExecuteAfterHandler", () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, it, expect, mock, beforeEach } from "bun:test"
|
||||
import { describe, it, expect, mock, beforeEach, afterAll } from "bun:test"
|
||||
import type { ClaudeHooksConfig } from "./types"
|
||||
import type { StopContext } from "./stop"
|
||||
|
||||
@@ -17,6 +17,8 @@ mock.module("../../shared/logger", () => ({
|
||||
getLogFilePath: () => "/tmp/test.log",
|
||||
}))
|
||||
|
||||
afterAll(() => { mock.restore() })
|
||||
|
||||
const { executeStopHooks } = await import("./stop")
|
||||
|
||||
function createStopContext(overrides?: Partial<StopContext>): StopContext {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, test, expect, mock } from "bun:test"
|
||||
import { describe, test, expect, mock, afterAll } from "bun:test"
|
||||
import { chmodSync, mkdtempSync, writeFileSync } from "node:fs"
|
||||
import { join } from "node:path"
|
||||
import { tmpdir } from "node:os"
|
||||
@@ -24,6 +24,8 @@ function createScriptBinary(scriptContent: string): string {
|
||||
return binaryPath
|
||||
}
|
||||
|
||||
afterAll(() => { mock.restore() })
|
||||
|
||||
describe("comment-checker CLI", () => {
|
||||
describe("lazy initialization", () => {
|
||||
test("getCommentCheckerPathSync should be lazy and callable", async () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, it, expect, mock, beforeEach } from "bun:test"
|
||||
import { describe, it, expect, mock, beforeEach, afterAll } from "bun:test"
|
||||
|
||||
const processApplyPatchEditsWithCli = mock(async () => {})
|
||||
|
||||
@@ -10,6 +10,8 @@ mock.module("./cli-runner", () => ({
|
||||
processApplyPatchEditsWithCli,
|
||||
}))
|
||||
|
||||
afterAll(() => { mock.restore() })
|
||||
|
||||
const { createCommentCheckerHooks } = await import("./hook")
|
||||
|
||||
describe("comment-checker apply_patch integration", () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, it, mock } from "bun:test"
|
||||
import { afterAll, describe, expect, it, mock } from "bun:test"
|
||||
|
||||
mock.module("../../shared/system-directive", () => ({
|
||||
createSystemDirective: (type: string) => `[DIRECTIVE:${type}]`,
|
||||
@@ -14,6 +14,10 @@ mock.module("../../shared/system-directive", () => ({
|
||||
},
|
||||
}))
|
||||
|
||||
afterAll(() => {
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
import { createCompactionContextInjector } from "./index"
|
||||
import { TaskHistory } from "../../features/background-agent/task-history"
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ afterAll(() => {
|
||||
update: async () => {},
|
||||
},
|
||||
}))
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
function createMockContext(todoResponses: Array<Todo>[]): PluginInput {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { mkdirSync, rmSync, writeFileSync } from "node:fs"
|
||||
import { tmpdir } from "node:os"
|
||||
import { join } from "node:path"
|
||||
import type { PluginInput } from "@opencode-ai/plugin"
|
||||
import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test"
|
||||
import { afterAll, afterEach, beforeEach, describe, expect, it, mock } from "bun:test"
|
||||
|
||||
const storageMaps = new Map<string, Set<string>>()
|
||||
|
||||
@@ -22,6 +22,10 @@ mock.module("./storage", () => ({
|
||||
},
|
||||
}))
|
||||
|
||||
afterAll(() => {
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
const truncator = {
|
||||
truncate: async (_sessionID: string, content: string) => ({ result: content, truncated: false }),
|
||||
getUsage: async (_sessionID: string) => null,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test"
|
||||
import { afterAll, afterEach, beforeEach, describe, expect, it, mock } from "bun:test"
|
||||
import { randomUUID } from "node:crypto"
|
||||
import { mkdirSync, rmSync, writeFileSync } from "node:fs"
|
||||
import { tmpdir } from "node:os"
|
||||
@@ -15,6 +15,10 @@ mock.module("./storage", () => ({
|
||||
},
|
||||
}))
|
||||
|
||||
afterAll(() => {
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
function createPluginContext(directory: string): PluginInput {
|
||||
return { directory } as PluginInput
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
declare const require: (name: string) => any
|
||||
const { beforeEach, describe, expect, mock, test } = require("bun:test")
|
||||
const { beforeEach, describe, expect, mock, test, afterAll } = require("bun:test")
|
||||
|
||||
const readConnectedProvidersCacheMock = mock(() => null)
|
||||
const readProviderModelsCacheMock = mock(() => null)
|
||||
@@ -53,6 +53,10 @@ mock.module("../../shared/model-error-classifier", () => ({
|
||||
selectFallbackProvider: selectFallbackProviderMock,
|
||||
}))
|
||||
|
||||
afterAll(() => {
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
import {
|
||||
clearPendingModelFallback,
|
||||
createModelFallbackHook,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { beforeEach, describe, expect, mock, test } from "bun:test"
|
||||
import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test"
|
||||
|
||||
const wakeOpenClawMock = mock(async () => null)
|
||||
|
||||
@@ -6,6 +6,10 @@ mock.module("../openclaw", () => ({
|
||||
wakeOpenClaw: wakeOpenClawMock,
|
||||
}))
|
||||
|
||||
afterAll(() => {
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
describe("createOpenClawHook", () => {
|
||||
beforeEach(() => {
|
||||
wakeOpenClawMock.mockClear()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, it, mock } from "bun:test"
|
||||
import { describe, expect, it, mock, afterAll } from "bun:test"
|
||||
|
||||
import { applyProviderConfig } from "../plugin-handlers/provider-config-handler"
|
||||
import { createModelCacheState } from "../plugin-state"
|
||||
@@ -9,6 +9,8 @@ mock.module("../shared/logger", () => ({
|
||||
log: logMock,
|
||||
}))
|
||||
|
||||
afterAll(() => { mock.restore() })
|
||||
|
||||
const { createPreemptiveCompactionHook } = await import("./preemptive-compaction")
|
||||
|
||||
function createMockCtx() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/// <reference types="bun-types" />
|
||||
|
||||
import { beforeEach, describe, expect, it, mock } from "bun:test"
|
||||
import { beforeEach, describe, expect, it, mock, afterAll } from "bun:test"
|
||||
|
||||
const logMock = mock(() => {})
|
||||
|
||||
@@ -8,6 +8,8 @@ mock.module("../shared/logger", () => ({
|
||||
log: logMock,
|
||||
}))
|
||||
|
||||
afterAll(() => { mock.restore() })
|
||||
|
||||
const { createPreemptiveCompactionHook } = await import("./preemptive-compaction")
|
||||
|
||||
type AssistantHistoryMessage = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/// <reference types="bun-types" />
|
||||
|
||||
import { describe, it, expect, mock, beforeEach, afterEach } from "bun:test"
|
||||
import { afterAll, describe, it, expect, mock, beforeEach, afterEach } from "bun:test"
|
||||
|
||||
const ANTHROPIC_CONTEXT_ENV_KEY = "ANTHROPIC_1M_CONTEXT"
|
||||
const VERTEX_CONTEXT_ENV_KEY = "VERTEX_ANTHROPIC_1M_CONTEXT"
|
||||
@@ -28,6 +28,10 @@ mock.module("../shared/logger", () => ({
|
||||
log: logMock,
|
||||
}))
|
||||
|
||||
afterAll(() => {
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
const { createPreemptiveCompactionHook } = await import("./preemptive-compaction")
|
||||
|
||||
function createMockCtx() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, test, beforeEach, afterEach, mock } from "bun:test"
|
||||
import { afterAll, describe, expect, test, beforeEach, afterEach, mock } from "bun:test"
|
||||
import { mkdirSync, rmSync, writeFileSync } from "node:fs"
|
||||
import { join } from "node:path"
|
||||
import { tmpdir } from "node:os"
|
||||
@@ -11,6 +11,10 @@ mock.module("../../shared/opencode-storage-detection", () => ({
|
||||
resetSqliteBackendCache: () => {},
|
||||
}))
|
||||
|
||||
afterAll(() => {
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
const { createPrometheusMdOnlyHook } = await import("./index")
|
||||
const { MESSAGE_STORAGE } = await import("../../features/hook-message-injector")
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test"
|
||||
import { afterAll, afterEach, beforeEach, describe, expect, mock, test } from "bun:test"
|
||||
import type { HookDeps, RuntimeFallbackPluginInput } from "./types"
|
||||
|
||||
let capturedDeps: HookDeps | undefined
|
||||
@@ -36,6 +36,10 @@ mock.module("./chat-message-handler", () => ({
|
||||
createChatMessageHandler: mockCreateChatMessageHandler,
|
||||
}))
|
||||
|
||||
afterAll(() => {
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
const { createRuntimeFallbackHook } = await import("./hook")
|
||||
|
||||
function createMockContext(): RuntimeFallbackPluginInput {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { describe, it, expect, mock, beforeEach } = require("bun:test")
|
||||
const { describe, it, expect, mock, beforeEach, afterAll } = require("bun:test")
|
||||
|
||||
import type { MessageData } from "./types"
|
||||
|
||||
@@ -17,6 +17,10 @@ mock.module("./storage", () => ({
|
||||
readParts: () => storedParts,
|
||||
}))
|
||||
|
||||
afterAll(() => {
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
const { recoverToolResultMissing } = await import("./recover-tool-result-missing")
|
||||
|
||||
function createMockClient(messages: MessageData[] = []) {
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
writeBoulderState,
|
||||
} from "../../features/boulder-state"
|
||||
import { log } from "../../shared/logger"
|
||||
import { createWorktreeActiveBlock } from "./worktree-block"
|
||||
import type { PluginInput } from "@opencode-ai/plugin"
|
||||
import { HOOK_NAME } from "./start-work-hook"
|
||||
|
||||
@@ -158,7 +159,9 @@ Looking for new plans...`
|
||||
appendSessionId(directory, sessionId)
|
||||
}
|
||||
|
||||
const worktreeDisplay = effectiveWorktree ? worktreeBlock.replace(worktreePath ?? "", effectiveWorktree) : worktreeBlock
|
||||
const worktreeDisplay = effectiveWorktree
|
||||
? (worktreeBlock || createWorktreeActiveBlock(effectiveWorktree))
|
||||
: worktreeBlock
|
||||
|
||||
return `
|
||||
## Active Work Session Found
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
import { detectWorktreePath } from "./worktree-detector"
|
||||
import { parseUserRequest } from "./parse-user-request"
|
||||
import { buildStartWorkContextInfo } from "./context-info-builder"
|
||||
import { createWorktreeActiveBlock } from "./worktree-block"
|
||||
|
||||
export const HOOK_NAME = "start-work" as const
|
||||
const START_WORK_TEMPLATE_MARKER = "You are starting a Sisyphus work session."
|
||||
@@ -44,18 +45,6 @@ interface StartWorkHookOutput {
|
||||
parts: Array<{ type: string; text?: string }>
|
||||
}
|
||||
|
||||
function createWorktreeActiveBlock(worktreePath: string): string {
|
||||
return `
|
||||
## Worktree Active
|
||||
|
||||
**Worktree**: \`${worktreePath}\`
|
||||
|
||||
**CRITICAL - DO NOT FORGET**: You are working inside a git worktree. ALL operations MUST be performed exclusively within this worktree directory.
|
||||
- Every file read, write, edit, and git operation MUST target paths under: \`${worktreePath}\`
|
||||
- When delegating tasks to subagents, you MUST include the worktree path in your delegation prompt so they also operate exclusively within the worktree
|
||||
- NEVER operate on the main repository directory - always use the worktree path above`
|
||||
}
|
||||
|
||||
function resolveWorktreeContext(
|
||||
explicitWorktreePath: string | null,
|
||||
): { worktreePath: string | undefined; block: string } {
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
export function createWorktreeActiveBlock(worktreePath: string): string {
|
||||
return `
|
||||
## Worktree Active
|
||||
|
||||
**Worktree**: \`${worktreePath}\`
|
||||
|
||||
**CRITICAL - DO NOT FORGET**: You are working inside a git worktree. ALL operations MUST be performed exclusively within this worktree directory.
|
||||
- Every file read, write, edit, and git operation MUST target paths under: \`${worktreePath}\`
|
||||
- When delegating tasks to subagents, you MUST include the worktree path in your delegation prompt so they also operate exclusively within the worktree
|
||||
- NEVER operate on the main repository directory - always use the worktree path above`
|
||||
}
|
||||
Reference in New Issue
Block a user