mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-05 09:19:53 +00:00
test(opencode): use filesystem service accessors
This commit is contained in:
parent
22f79f05cf
commit
2fc0793f1f
2 changed files with 88 additions and 64 deletions
|
|
@ -7,6 +7,43 @@ import { Effect, FileSystem, Layer, Schema, Context } from "effect"
|
|||
import type { PlatformError } from "effect/PlatformError"
|
||||
import { Glob } from "./util/glob"
|
||||
|
||||
type EffectMethod = (...args: ReadonlyArray<never>) => Effect.Effect<unknown, unknown, unknown>
|
||||
|
||||
type ServiceUse<Identifier, Shape> = {
|
||||
readonly [Key in keyof Shape as Shape[Key] extends EffectMethod ? Key : never]: Shape[Key] extends (
|
||||
...args: infer Args
|
||||
) => infer Return
|
||||
? Args extends ReadonlyArray<unknown>
|
||||
? Return extends Effect.Effect<infer A, infer E, infer R>
|
||||
? (...args: Args) => Effect.Effect<A, E, R | Identifier>
|
||||
: never
|
||||
: never
|
||||
: never
|
||||
}
|
||||
|
||||
const serviceUse = <Identifier, Shape>(tag: Context.Service<Identifier, Shape>) => {
|
||||
// This is the only dynamic boundary: TypeScript knows the accessor shape,
|
||||
// but Proxy property names are runtime values.
|
||||
const access = new Proxy(
|
||||
{},
|
||||
{
|
||||
get: (_, key) => {
|
||||
if (typeof key !== "string") return undefined
|
||||
return (...args: unknown[]) =>
|
||||
tag.use((service) => {
|
||||
// oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- Proxy keys are checked at runtime.
|
||||
const method = service[key as keyof Shape]
|
||||
if (typeof method !== "function") return Effect.die(new Error(`Service method not found: ${key}`))
|
||||
// oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- ServiceUse exposes only Effect-returning methods.
|
||||
return (method as (...args: unknown[]) => Effect.Effect<unknown, unknown, unknown>)(...args)
|
||||
})
|
||||
},
|
||||
},
|
||||
)
|
||||
// oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion -- Proxy implements the mapped accessor surface lazily.
|
||||
return access as ServiceUse<Identifier, Shape>
|
||||
}
|
||||
|
||||
export namespace AppFileSystem {
|
||||
export class FileSystemError extends Schema.TaggedErrorClass<FileSystemError>()("FileSystemError", {
|
||||
method: Schema.String,
|
||||
|
|
@ -39,6 +76,8 @@ export namespace AppFileSystem {
|
|||
|
||||
export class Service extends Context.Service<Service, Interface>()("@opencode/FileSystem") {}
|
||||
|
||||
export const use = serviceUse(Service)
|
||||
|
||||
export const layer = Layer.effect(
|
||||
Service,
|
||||
Effect.gen(function* () {
|
||||
|
|
|
|||
|
|
@ -140,32 +140,21 @@ afterEach(async () => {
|
|||
await clear(true)
|
||||
})
|
||||
|
||||
async function writeManagedSettings(settings: object, filename = "opencode.json") {
|
||||
await fs.mkdir(managedConfigDir, { recursive: true })
|
||||
await Filesystem.write(path.join(managedConfigDir, filename), JSON.stringify(settings))
|
||||
}
|
||||
|
||||
const writeManagedSettingsEffect = (settings: object, filename?: string) =>
|
||||
Effect.promise(() => writeManagedSettings(settings, filename))
|
||||
AppFileSystem.use.writeWithDirs(path.join(managedConfigDir, filename ?? "opencode.json"), JSON.stringify(settings))
|
||||
|
||||
async function writeConfig(dir: string, config: object, name = "opencode.json") {
|
||||
await Filesystem.write(path.join(dir, name), JSON.stringify(config))
|
||||
}
|
||||
|
||||
const writeConfigEffect = (dir: string, config: object, name = "opencode.json") =>
|
||||
AppFileSystem.Service.use((fs) => fs.writeFileString(path.join(dir, name), JSON.stringify(config)))
|
||||
const mkdirEffect = (dir: string) => AppFileSystem.Service.use((fs) => fs.ensureDir(dir))
|
||||
const writeTextEffect = (file: string, content: string) =>
|
||||
AppFileSystem.Service.use((fs) => fs.writeWithDirs(file, content))
|
||||
const readTextEffect = (file: string) => AppFileSystem.Service.use((fs) => fs.readFileString(file))
|
||||
const readJsonEffect = (file: string) => AppFileSystem.Service.use((fs) => fs.readJson(file))
|
||||
const existsEffect = (file: string) => AppFileSystem.Service.use((fs) => fs.existsSafe(file))
|
||||
const chmodEffect = (file: string, mode: number) => AppFileSystem.Service.use((fs) => fs.chmod(file, mode))
|
||||
AppFileSystem.use.writeFileString(path.join(dir, name), JSON.stringify(config))
|
||||
|
||||
const project = {
|
||||
dir: (relative: string) => TestInstance.use((test) => mkdirEffect(path.join(test.directory, relative))),
|
||||
dir: (relative: string) =>
|
||||
TestInstance.use((test) => AppFileSystem.use.ensureDir(path.join(test.directory, relative))),
|
||||
file: (relative: string, content: string) =>
|
||||
TestInstance.use((test) => writeTextEffect(path.join(test.directory, relative), content)),
|
||||
TestInstance.use((test) => AppFileSystem.use.writeWithDirs(path.join(test.directory, relative), content)),
|
||||
}
|
||||
|
||||
const withGlobalConfigDir = <A, E, R>(dir: string, effect: Effect.Effect<A, E, R>) =>
|
||||
|
|
@ -202,7 +191,7 @@ const withConfigTree = <A, E, R>(
|
|||
const root = yield* tmpdirScoped()
|
||||
const directory = path.join(root, "project")
|
||||
const local = path.join(directory, ".opencode")
|
||||
yield* mkdirEffect(local)
|
||||
yield* AppFileSystem.use.ensureDir(local)
|
||||
if (input.global) yield* writeConfigEffect(root, schemaConfig(input.global))
|
||||
if (input.project) yield* writeConfigEffect(directory, schemaConfig(input.project))
|
||||
if (input.local) yield* writeConfigEffect(local, schemaConfig(input.local))
|
||||
|
|
@ -302,7 +291,7 @@ it.effect("creates global jsonc config with schema when no global configs exist"
|
|||
Effect.gen(function* () {
|
||||
yield* Config.use.get().pipe(provideInstanceEffect(dir))
|
||||
|
||||
const content = yield* readTextEffect(path.join(dir, "opencode.jsonc"))
|
||||
const content = yield* AppFileSystem.use.readFileString(path.join(dir, "opencode.jsonc"))
|
||||
expect(content).toContain('"$schema": "https://opencode.ai/config.json"')
|
||||
}).pipe(Effect.provide(testInstanceStoreLayer), Effect.provide(CrossSpawnSpawner.defaultLayer)),
|
||||
),
|
||||
|
|
@ -318,7 +307,7 @@ it.effect("does not create global config when OPENCODE_CONFIG_DIR is set", () =>
|
|||
Effect.gen(function* () {
|
||||
yield* Config.use.get().pipe(provideInstanceEffect(dir))
|
||||
|
||||
expect(yield* existsEffect(path.join(dir, "opencode.jsonc"))).toBe(false)
|
||||
expect(yield* AppFileSystem.use.existsSafe(path.join(dir, "opencode.jsonc"))).toBe(false)
|
||||
}).pipe(Effect.provide(testInstanceStoreLayer), Effect.provide(CrossSpawnSpawner.defaultLayer)),
|
||||
),
|
||||
)
|
||||
|
|
@ -355,10 +344,8 @@ it.instance("updates config and preserves empty shell sentinel", () =>
|
|||
|
||||
yield* Config.Service.use((svc) => svc.update(ConfigParse.schema(Config.Info, { shell: "" }, "test:config")))
|
||||
|
||||
const writtenConfig = yield* Effect.promise(() =>
|
||||
Filesystem.readJson<{ shell?: string }>(path.join(test.directory, "config.json")),
|
||||
)
|
||||
expect(writtenConfig.shell).toBe("")
|
||||
const writtenConfig = yield* AppFileSystem.use.readJson(path.join(test.directory, "config.json"))
|
||||
expect(writtenConfig).toMatchObject({ shell: "" })
|
||||
}),
|
||||
)
|
||||
|
||||
|
|
@ -367,7 +354,7 @@ it.effect("updates global config and omits empty shell key in json", () =>
|
|||
Effect.gen(function* () {
|
||||
yield* Config.use.updateGlobal({ shell: "" })
|
||||
|
||||
const writtenConfig = yield* readJsonEffect(path.join(dir, "opencode.json"))
|
||||
const writtenConfig = yield* AppFileSystem.use.readJson(path.join(dir, "opencode.json"))
|
||||
expect(writtenConfig).not.toHaveProperty("shell")
|
||||
}),
|
||||
),
|
||||
|
|
@ -379,7 +366,7 @@ it.effect("updates global config and omits empty shell key in jsonc", () =>
|
|||
yield* Config.use.updateGlobal({ shell: "" })
|
||||
|
||||
const file = path.join(dir, "opencode.jsonc")
|
||||
const writtenConfig = yield* readTextEffect(file)
|
||||
const writtenConfig = yield* AppFileSystem.use.readFileString(file)
|
||||
const parsed = ConfigParse.schema(Config.Info, ConfigParse.jsonc(writtenConfig, file), file)
|
||||
expect(writtenConfig).not.toContain('"shell"')
|
||||
expect(parsed.shell).toBeUndefined()
|
||||
|
|
@ -443,7 +430,7 @@ it.instance("ignores legacy tui keys in opencode config", () =>
|
|||
it.instance("loads JSONC config file", () =>
|
||||
Effect.gen(function* () {
|
||||
const test = yield* TestInstance
|
||||
yield* writeTextEffect(
|
||||
yield* AppFileSystem.use.writeWithDirs(
|
||||
path.join(test.directory, "opencode.jsonc"),
|
||||
`{
|
||||
// This is a comment
|
||||
|
|
@ -503,7 +490,7 @@ it.instance("preserves env variables when adding $schema to config", () =>
|
|||
Effect.gen(function* () {
|
||||
const test = yield* TestInstance
|
||||
// Config without $schema - should trigger auto-add
|
||||
yield* writeTextEffect(
|
||||
yield* AppFileSystem.use.writeWithDirs(
|
||||
path.join(test.directory, "opencode.json"),
|
||||
JSON.stringify({ username: "{env:PRESERVE_VAR}" }),
|
||||
)
|
||||
|
|
@ -511,7 +498,7 @@ it.instance("preserves env variables when adding $schema to config", () =>
|
|||
expect(config.username).toBe("secret_value")
|
||||
|
||||
// Read the file to verify the env variable was preserved
|
||||
const content = yield* readTextEffect(path.join(test.directory, "opencode.json"))
|
||||
const content = yield* AppFileSystem.use.readFileString(path.join(test.directory, "opencode.json"))
|
||||
expect(content).toContain("{env:PRESERVE_VAR}")
|
||||
expect(content).not.toContain("secret_value")
|
||||
expect(content).toContain("$schema")
|
||||
|
|
@ -522,7 +509,7 @@ it.instance("preserves env variables when adding $schema to config", () =>
|
|||
it.instance("handles file inclusion substitution", () =>
|
||||
Effect.gen(function* () {
|
||||
const test = yield* TestInstance
|
||||
yield* writeTextEffect(path.join(test.directory, "included.txt"), "test-user")
|
||||
yield* AppFileSystem.use.writeWithDirs(path.join(test.directory, "included.txt"), "test-user")
|
||||
yield* writeConfigEffect(test.directory, {
|
||||
$schema: "https://opencode.ai/config.json",
|
||||
username: "{file:included.txt}",
|
||||
|
|
@ -535,7 +522,7 @@ it.instance("handles file inclusion substitution", () =>
|
|||
it.instance("handles file inclusion with replacement tokens", () =>
|
||||
Effect.gen(function* () {
|
||||
const test = yield* TestInstance
|
||||
yield* writeTextEffect(path.join(test.directory, "included.md"), "const out = await Bun.$`echo hi`")
|
||||
yield* AppFileSystem.use.writeWithDirs(path.join(test.directory, "included.md"), "const out = await Bun.$`echo hi`")
|
||||
yield* writeConfigEffect(test.directory, {
|
||||
$schema: "https://opencode.ai/config.json",
|
||||
username: "{file:included.md}",
|
||||
|
|
@ -603,7 +590,7 @@ it.instance("validates config schema and throws on invalid fields", () =>
|
|||
it.instance("throws error for invalid JSON", () =>
|
||||
Effect.gen(function* () {
|
||||
const test = yield* TestInstance
|
||||
yield* writeTextEffect(path.join(test.directory, "opencode.json"), "{ invalid json }")
|
||||
yield* AppFileSystem.use.writeWithDirs(path.join(test.directory, "opencode.json"), "{ invalid json }")
|
||||
const exit = yield* Config.use.get().pipe(Effect.exit)
|
||||
expect(Exit.isFailure(exit)).toBe(true)
|
||||
}),
|
||||
|
|
@ -718,8 +705,8 @@ it.instance("migrates mode field to agent field", () =>
|
|||
it.instance("loads config from .opencode directory", () =>
|
||||
Effect.gen(function* () {
|
||||
const test = yield* TestInstance
|
||||
yield* mkdirEffect(path.join(test.directory, ".opencode", "agent"))
|
||||
yield* writeTextEffect(
|
||||
yield* AppFileSystem.use.ensureDir(path.join(test.directory, ".opencode", "agent"))
|
||||
yield* AppFileSystem.use.writeWithDirs(
|
||||
path.join(test.directory, ".opencode", "agent", "test.md"),
|
||||
`---
|
||||
model: test/model
|
||||
|
|
@ -741,8 +728,8 @@ Test agent prompt`,
|
|||
it.instance("agent markdown permission config preserves user key order", () =>
|
||||
Effect.gen(function* () {
|
||||
const test = yield* TestInstance
|
||||
yield* mkdirEffect(path.join(test.directory, ".opencode", "agent"))
|
||||
yield* writeTextEffect(
|
||||
yield* AppFileSystem.use.ensureDir(path.join(test.directory, ".opencode", "agent"))
|
||||
yield* AppFileSystem.use.writeWithDirs(
|
||||
path.join(test.directory, ".opencode", "agent", "ordered.md"),
|
||||
`---
|
||||
permission:
|
||||
|
|
@ -761,8 +748,8 @@ Ordered permissions`,
|
|||
it.instance("loads agents from .opencode/agents (plural)", () =>
|
||||
Effect.gen(function* () {
|
||||
const test = yield* TestInstance
|
||||
yield* mkdirEffect(path.join(test.directory, ".opencode", "agents", "nested"))
|
||||
yield* writeTextEffect(
|
||||
yield* AppFileSystem.use.ensureDir(path.join(test.directory, ".opencode", "agents", "nested"))
|
||||
yield* AppFileSystem.use.writeWithDirs(
|
||||
path.join(test.directory, ".opencode", "agents", "helper.md"),
|
||||
`---
|
||||
model: test/model
|
||||
|
|
@ -771,7 +758,7 @@ mode: subagent
|
|||
Helper agent prompt`,
|
||||
)
|
||||
|
||||
yield* writeTextEffect(
|
||||
yield* AppFileSystem.use.writeWithDirs(
|
||||
path.join(test.directory, ".opencode", "agents", "nested", "child.md"),
|
||||
`---
|
||||
model: test/model
|
||||
|
|
@ -801,8 +788,8 @@ Nested agent prompt`,
|
|||
it.instance("loads commands from .opencode/command (singular)", () =>
|
||||
Effect.gen(function* () {
|
||||
const test = yield* TestInstance
|
||||
yield* mkdirEffect(path.join(test.directory, ".opencode", "command", "nested"))
|
||||
yield* writeTextEffect(
|
||||
yield* AppFileSystem.use.ensureDir(path.join(test.directory, ".opencode", "command", "nested"))
|
||||
yield* AppFileSystem.use.writeWithDirs(
|
||||
path.join(test.directory, ".opencode", "command", "hello.md"),
|
||||
`---
|
||||
description: Test command
|
||||
|
|
@ -810,7 +797,7 @@ description: Test command
|
|||
Hello from singular command`,
|
||||
)
|
||||
|
||||
yield* writeTextEffect(
|
||||
yield* AppFileSystem.use.writeWithDirs(
|
||||
path.join(test.directory, ".opencode", "command", "nested", "child.md"),
|
||||
`---
|
||||
description: Nested command
|
||||
|
|
@ -835,8 +822,8 @@ Nested command template`,
|
|||
it.instance("loads commands from .opencode/commands (plural)", () =>
|
||||
Effect.gen(function* () {
|
||||
const test = yield* TestInstance
|
||||
yield* mkdirEffect(path.join(test.directory, ".opencode", "commands", "nested"))
|
||||
yield* writeTextEffect(
|
||||
yield* AppFileSystem.use.ensureDir(path.join(test.directory, ".opencode", "commands", "nested"))
|
||||
yield* AppFileSystem.use.writeWithDirs(
|
||||
path.join(test.directory, ".opencode", "commands", "hello.md"),
|
||||
`---
|
||||
description: Test command
|
||||
|
|
@ -844,7 +831,7 @@ description: Test command
|
|||
Hello from plural commands`,
|
||||
)
|
||||
|
||||
yield* writeTextEffect(
|
||||
yield* AppFileSystem.use.writeWithDirs(
|
||||
path.join(test.directory, ".opencode", "commands", "nested", "child.md"),
|
||||
`---
|
||||
description: Nested command
|
||||
|
|
@ -873,10 +860,8 @@ it.instance("updates config and writes to file", () =>
|
|||
svc.update(ConfigParse.schema(Config.Info, { model: "updated/model" }, "test:config")),
|
||||
)
|
||||
|
||||
const writtenConfig = yield* Effect.promise(() =>
|
||||
Filesystem.readJson<{ model: string }>(path.join(test.directory, "config.json")),
|
||||
)
|
||||
expect(writtenConfig.model).toBe("updated/model")
|
||||
const writtenConfig = yield* AppFileSystem.use.readJson(path.join(test.directory, "config.json"))
|
||||
expect(writtenConfig).toMatchObject({ model: "updated/model" })
|
||||
}),
|
||||
)
|
||||
|
||||
|
|
@ -893,9 +878,9 @@ it.effect("does not try to install dependencies in read-only OPENCODE_CONFIG_DIR
|
|||
|
||||
const dir = yield* tmpdirScoped()
|
||||
const readonly = path.join(dir, "readonly")
|
||||
yield* mkdirEffect(readonly)
|
||||
yield* chmodEffect(readonly, 0o555)
|
||||
yield* Effect.addFinalizer(() => chmodEffect(readonly, 0o755).pipe(Effect.ignore))
|
||||
yield* AppFileSystem.use.ensureDir(readonly)
|
||||
yield* AppFileSystem.use.chmod(readonly, 0o555)
|
||||
yield* Effect.addFinalizer(() => AppFileSystem.use.chmod(readonly, 0o755).pipe(Effect.ignore))
|
||||
|
||||
yield* withProcessEnv("OPENCODE_CONFIG_DIR", readonly, Config.use.get().pipe(provideInstanceEffect(dir)))
|
||||
}).pipe(Effect.provide(testInstanceStoreLayer), Effect.provide(CrossSpawnSpawner.defaultLayer)),
|
||||
|
|
@ -905,7 +890,7 @@ it.effect("installs dependencies in writable OPENCODE_CONFIG_DIR", () =>
|
|||
Effect.gen(function* () {
|
||||
const dir = yield* tmpdirScoped()
|
||||
const configDir = path.join(dir, "configdir")
|
||||
yield* mkdirEffect(configDir)
|
||||
yield* AppFileSystem.use.ensureDir(configDir)
|
||||
|
||||
yield* withProcessEnv(
|
||||
"OPENCODE_CONFIG_DIR",
|
||||
|
|
@ -915,7 +900,7 @@ it.effect("installs dependencies in writable OPENCODE_CONFIG_DIR", () =>
|
|||
),
|
||||
)
|
||||
|
||||
expect(yield* readTextEffect(path.join(configDir, ".gitignore"))).toContain("package-lock.json")
|
||||
expect(yield* AppFileSystem.use.readFileString(path.join(configDir, ".gitignore"))).toContain("package-lock.json")
|
||||
}).pipe(Effect.provide(testInstanceStoreLayer), Effect.provide(CrossSpawnSpawner.defaultLayer)),
|
||||
)
|
||||
|
||||
|
|
@ -927,12 +912,12 @@ it.instance("resolves scoped npm plugins in config", () =>
|
|||
Effect.gen(function* () {
|
||||
const test = yield* TestInstance
|
||||
const pluginDir = path.join(test.directory, "node_modules", "@scope", "plugin")
|
||||
yield* mkdirEffect(pluginDir)
|
||||
yield* writeTextEffect(
|
||||
yield* AppFileSystem.use.ensureDir(pluginDir)
|
||||
yield* AppFileSystem.use.writeWithDirs(
|
||||
path.join(test.directory, "package.json"),
|
||||
JSON.stringify({ name: "config-fixture", version: "1.0.0", type: "module" }, null, 2),
|
||||
)
|
||||
yield* writeTextEffect(
|
||||
yield* AppFileSystem.use.writeWithDirs(
|
||||
path.join(pluginDir, "package.json"),
|
||||
JSON.stringify(
|
||||
{
|
||||
|
|
@ -945,7 +930,7 @@ it.instance("resolves scoped npm plugins in config", () =>
|
|||
2,
|
||||
),
|
||||
)
|
||||
yield* writeTextEffect(path.join(pluginDir, "index.js"), "export default {}\n")
|
||||
yield* AppFileSystem.use.writeWithDirs(path.join(pluginDir, "index.js"), "export default {}\n")
|
||||
yield* writeConfigEffect(test.directory, { plugin: ["@scope/plugin"] })
|
||||
|
||||
const config = yield* Config.use.get()
|
||||
|
|
@ -975,8 +960,8 @@ it.effect("merges plugin arrays from global and local configs", () =>
|
|||
it.instance("does not error when only custom agent is a subagent", () =>
|
||||
Effect.gen(function* () {
|
||||
const test = yield* TestInstance
|
||||
yield* mkdirEffect(path.join(test.directory, ".opencode", "agent"))
|
||||
yield* writeTextEffect(
|
||||
yield* AppFileSystem.use.ensureDir(path.join(test.directory, ".opencode", "agent"))
|
||||
yield* AppFileSystem.use.writeWithDirs(
|
||||
path.join(test.directory, ".opencode", "agent", "helper.md"),
|
||||
`---
|
||||
model: test/model
|
||||
|
|
@ -1387,7 +1372,7 @@ it.instance("local .opencode config can override MCP from project config", () =>
|
|||
},
|
||||
},
|
||||
})
|
||||
yield* mkdirEffect(path.join(test.directory, ".opencode"))
|
||||
yield* AppFileSystem.use.ensureDir(path.join(test.directory, ".opencode"))
|
||||
yield* writeConfigEffect(
|
||||
path.join(test.directory, ".opencode"),
|
||||
{
|
||||
|
|
@ -1719,8 +1704,8 @@ describe("OPENCODE_DISABLE_PROJECT_CONFIG", () => {
|
|||
"true",
|
||||
Effect.gen(function* () {
|
||||
const test = yield* TestInstance
|
||||
yield* mkdirEffect(path.join(test.directory, ".opencode", "command"))
|
||||
yield* writeTextEffect(
|
||||
yield* AppFileSystem.use.ensureDir(path.join(test.directory, ".opencode", "command"))
|
||||
yield* AppFileSystem.use.writeWithDirs(
|
||||
path.join(test.directory, ".opencode", "command", "test-cmd.md"),
|
||||
"# Test Command\nThis is a test command.",
|
||||
)
|
||||
|
|
@ -1749,7 +1734,7 @@ describe("OPENCODE_DISABLE_PROJECT_CONFIG", () => {
|
|||
{ OPENCODE_CONFIG_DIR: undefined, OPENCODE_DISABLE_PROJECT_CONFIG: "true" },
|
||||
Effect.gen(function* () {
|
||||
const test = yield* TestInstance
|
||||
yield* writeTextEffect(path.join(test.directory, "CUSTOM.md"), "# Custom Instructions")
|
||||
yield* AppFileSystem.use.writeWithDirs(path.join(test.directory, "CUSTOM.md"), "# Custom Instructions")
|
||||
// The relative instruction should be skipped without error
|
||||
const config = yield* Config.use.get()
|
||||
expect(config).toBeDefined()
|
||||
|
|
@ -1814,7 +1799,7 @@ describe("OPENCODE_CONFIG_CONTENT token substitution", () => {
|
|||
it.instance("substitutes {file:} tokens in OPENCODE_CONFIG_CONTENT", () =>
|
||||
Effect.gen(function* () {
|
||||
const test = yield* TestInstance
|
||||
yield* writeTextEffect(path.join(test.directory, "api_key.txt"), "secret_key_from_file")
|
||||
yield* AppFileSystem.use.writeWithDirs(path.join(test.directory, "api_key.txt"), "secret_key_from_file")
|
||||
yield* withProcessEnv(
|
||||
"OPENCODE_CONFIG_CONTENT",
|
||||
JSON.stringify({
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue