Skip to content

Commit 4880db4

Browse files
kitlangtonmrsimpson
authored andcommitted
refactor(file): destroy FileTime facade (anomalyco#22090)
1 parent 51950ee commit 4880db4

3 files changed

Lines changed: 423 additions & 413 deletions

File tree

packages/opencode/src/file/time.ts

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { DateTime, Effect, Layer, Option, Semaphore, Context } from "effect"
22
import { InstanceState } from "@/effect/instance-state"
3-
import { makeRuntime } from "@/effect/run-service"
43
import { AppFileSystem } from "@/filesystem"
54
import { Flag } from "@/flag/flag"
65
import type { SessionID } from "@/session/schema"
@@ -112,22 +111,4 @@ export namespace FileTime {
112111
).pipe(Layer.orDie)
113112

114113
export const defaultLayer = layer.pipe(Layer.provide(AppFileSystem.defaultLayer))
115-
116-
const { runPromise } = makeRuntime(Service, defaultLayer)
117-
118-
export function read(sessionID: SessionID, file: string) {
119-
return runPromise((s) => s.read(sessionID, file))
120-
}
121-
122-
export function get(sessionID: SessionID, file: string) {
123-
return runPromise((s) => s.get(sessionID, file))
124-
}
125-
126-
export async function assert(sessionID: SessionID, filepath: string) {
127-
return runPromise((s) => s.assert(sessionID, filepath))
128-
}
129-
130-
export async function withLock<T>(filepath: string, fn: () => Promise<T>): Promise<T> {
131-
return runPromise((s) => s.withLock(filepath, () => Effect.promise(fn)))
132-
}
133114
}

packages/opencode/test/AGENTS.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,55 @@ await using tmp = await tmpdir({
7979
- Directories are created in the system temp folder with prefix `opencode-test-`
8080
- Use `await using` for automatic cleanup when the variable goes out of scope
8181
- Paths are sanitized to strip null bytes (defensive fix for CI environments)
82+
83+
## Testing With Effects
84+
85+
Use `testEffect(...)` from `test/lib/effect.ts` for tests that exercise Effect services or Effect-based workflows.
86+
87+
### Core Pattern
88+
89+
```typescript
90+
import { describe, expect } from "bun:test"
91+
import { Effect, Layer } from "effect"
92+
import { provideTmpdirInstance } from "../fixture/fixture"
93+
import { testEffect } from "../lib/effect"
94+
95+
const it = testEffect(Layer.mergeAll(MyService.defaultLayer))
96+
97+
describe("my service", () => {
98+
it.live("does the thing", () =>
99+
provideTmpdirInstance(() =>
100+
Effect.gen(function* () {
101+
const svc = yield* MyService.Service
102+
const out = yield* svc.run()
103+
expect(out).toEqual("ok")
104+
}),
105+
),
106+
)
107+
})
108+
```
109+
110+
### `it.effect` vs `it.live`
111+
112+
- Use `it.effect(...)` when the test should run with `TestClock` and `TestConsole`.
113+
- Use `it.live(...)` when the test depends on real time, filesystem mtimes, child processes, git, locks, or other live OS behavior.
114+
- Most integration-style tests in this package use `it.live(...)`.
115+
116+
### Effect Fixtures
117+
118+
Prefer the Effect-aware helpers from `fixture/fixture.ts` instead of building a manual runtime in each test.
119+
120+
- `tmpdirScoped(options?)` creates a scoped temp directory and cleans it up when the Effect scope closes.
121+
- `provideInstance(dir)(effect)` is the low-level helper. It does not create a directory; it just runs an Effect with `Instance.current` bound to `dir`.
122+
- `provideTmpdirInstance((dir) => effect, options?)` is the convenience helper. It creates a temp directory, binds it as the active instance, and disposes the instance on cleanup.
123+
- `provideTmpdirServer((input) => effect, options?)` does the same, but also provides the test LLM server.
124+
125+
Use `provideTmpdirInstance(...)` by default when a test only needs one temp instance. Use `tmpdirScoped()` plus `provideInstance(...)` when a test needs multiple directories, custom setup before binding, or needs to switch instance context within one test.
126+
127+
### Style
128+
129+
- Define `const it = testEffect(...)` near the top of the file.
130+
- Keep the test body inside `Effect.gen(function* () { ... })`.
131+
- Yield services directly with `yield* MyService.Service` or `yield* MyTool`.
132+
- Avoid custom `ManagedRuntime`, `attach(...)`, or ad hoc `run(...)` wrappers when `testEffect(...)` already provides the runtime.
133+
- When a test needs instance-local state, prefer `provideTmpdirInstance(...)` or `provideInstance(...)` over manual `Instance.provide(...)` inside Promise-style tests.

0 commit comments

Comments
 (0)