| 82 | dispose?: (dir: string) => Promise<T> |
| 83 | } |
| 84 | export async function tmpdir<T>(options?: TmpDirOptions<T>) { |
| 85 | const dirpath = sanitizePath(path.join(os.tmpdir(), "opencode-test-" + Math.random().toString(36).slice(2))) |
| 86 | await fs.mkdir(dirpath, { recursive: true }) |
| 87 | if (options?.git) { |
| 88 | await $`git init`.cwd(dirpath).quiet() |
| 89 | await $`git config core.fsmonitor false`.cwd(dirpath).quiet() |
| 90 | await $`git config commit.gpgsign false`.cwd(dirpath).quiet() |
| 91 | await $`git config user.email "test@opencode.test"`.cwd(dirpath).quiet() |
| 92 | await $`git config user.name "Test"`.cwd(dirpath).quiet() |
| 93 | await $`git commit --allow-empty -m "root commit ${dirpath}"`.cwd(dirpath).quiet() |
| 94 | } |
| 95 | if (options?.config) { |
| 96 | await Bun.write( |
| 97 | path.join(dirpath, "opencode.json"), |
| 98 | JSON.stringify({ |
| 99 | $schema: "https://opencode.ai/config.json", |
| 100 | ...options.config, |
| 101 | }), |
| 102 | ) |
| 103 | } |
| 104 | const realpath = sanitizePath(await fs.realpath(dirpath)) |
| 105 | const extra = await options?.init?.(realpath) |
| 106 | const result = { |
| 107 | [Symbol.asyncDispose]: async () => { |
| 108 | try { |
| 109 | await options?.dispose?.(realpath) |
| 110 | } finally { |
| 111 | if (options?.git) await stop(realpath).catch(() => undefined) |
| 112 | await clean(realpath).catch(() => undefined) |
| 113 | } |
| 114 | }, |
| 115 | path: realpath, |
| 116 | extra: extra as T, |
| 117 | } |
| 118 | return result |
| 119 | } |
| 120 | |
| 121 | /** Effectful scoped tmpdir. Cleaned up when the scope closes. Make sure these stay in sync */ |
| 122 | export function tmpdirScoped<E = never, R = never>(options?: { |