Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,7 @@ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json

# Agent runtime data (contexts, logs)
.mini-agent/
opensrc/
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unexplained gitignore entry for opensrc/ directory

Low Severity

The opensrc/ directory is added to .gitignore without any explanatory comment and doesn't appear anywhere else in the codebase. Unlike .iterate/ which has a descriptive comment and is documented in src/durable-streams/README.md, there's no documentation or code referencing opensrc/. This appears to be an accidentally committed personal or local directory ignore entry that isn't related to the PR's stated purpose of implementing durable-streams.

Fix in Cursor Fix in Web


# durable-streams runtime data
.iterate/
57 changes: 47 additions & 10 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ See README.md for context

# Typescript

- Use bun as runtime and package manager
- Run CLI using `bun run mini-agent` (includes doppler for env vars)
- Use Node.js as runtime, pnpm as package manager
- Run CLI using `pnpm mini-agent` (includes doppler for env vars)
- kebab-case filenames
- tests using vitest; colocate test files with .test.ts
- import using .ts extension; no .js
Expand All @@ -27,18 +27,18 @@ See README.md for context

## Scripts

- `bun run typecheck` — tsc only
- `bun run lint` / `bun run lint:fix` — eslint only
- `bun run check` — typecheck + lint
- `bun run check:fix` — typecheck + lint:fix
- `doppler run -- bun run test` — vitest (requires Doppler for API keys)
- `doppler run -- bun run test:watch` — vitest watch mode
- `pnpm typecheck` — tsc only
- `pnpm lint` / `pnpm lint:fix` — eslint only
- `pnpm check` — typecheck + lint
- `pnpm check:fix` — typecheck + lint:fix
- `pnpm test` — vitest (requires Doppler for API keys)
- `pnpm test:watch` — vitest watch mode

## Pull Requests

Before committing and pushing code, you must run:
```bash
bun run check:fix
pnpm check:fix
```

This runs typecheck + linter with auto-fix. Commit any resulting changes before pushing.
Expand Down Expand Up @@ -333,14 +333,51 @@ describe("MyService", () => {
static readonly testLayer = Layer.sync(MyService, () => {
// Mutable state is fine in tests - JS is single-threaded
const store = new Map<string, Data>()

return MyService.of({
get: (key) => Effect.succeed(store.get(key)),
set: (key, value) => Effect.sync(() => void store.set(key, value))
})
})
```

## TestClock in vitest

`@effect/vitest` uses `TestClock` by default—time doesn't advance automatically. Use `TestClock.adjust` to advance time in tests with `Effect.sleep`:

```typescript
import { Effect, Fiber, TestClock } from "effect"
import { it } from "@effect/vitest"

it.effect("handles sleep with TestClock", () =>
Effect.gen(function*() {
const fiber = yield* Effect.fork(
Effect.gen(function*() {
yield* Effect.sleep("1 second")
return "done"
})
)

yield* TestClock.adjust("1 second") // Advance virtual time

const result = yield* Fiber.join(fiber)
expect(result).toBe("done")
})
)
```

For real time instead of test clock, use `it.live`:

```typescript
it.live("uses real clock", () =>
Effect.gen(function*() {
yield* Effect.sleep("10 millis") // Actually waits
})
)
```

**Alternative:** For PubSub subscription tests, `PubSub.subscribe` guarantees subscription is established when effect completes—often you can publish immediately without sleep.

## Layer Memoization

Layers are memoized by reference. Functions returning layers defeat memoization—each call creates a new object, causing duplicate construction, resource leaks, and inconsistent state.
Expand Down
1,015 changes: 656 additions & 359 deletions bun.lock

Large diffs are not rendered by default.

18 changes: 11 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
"private": true,
"scripts": {
"prepare": "effect-language-service patch",
"mini-agent": "doppler run -- bun src/cli/main.ts",
"start": "bun src/cli/main.ts",
"dev": "bun --watch src/cli/main.ts",
"mini-agent": "doppler run -- npx tsx src/cli/main.ts",
"agent-wrapper": "doppler run -- npx tsx src/agent-wrapper/main.ts",
"start": "npx tsx src/cli/main.ts",
"dev": "npx tsx --watch src/cli/main.ts",
"typecheck": "tsc --noEmit",
"lint": "eslint \"src/**/*.ts\" \"src/**/*.tsx\" \"test/**/*.ts\"",
"lint:fix": "eslint \"src/**/*.ts\" \"src/**/*.tsx\" \"test/**/*.ts\" --fix",
"check": "bun run typecheck && bun run lint",
"check:fix": "bun run typecheck && bun run lint:fix",
"check": "pnpm typecheck && pnpm lint",
"check:fix": "pnpm typecheck && pnpm lint:fix",
"test": "doppler run -- vitest run",
"test:watch": "doppler run -- vitest"
},
Expand All @@ -23,8 +24,9 @@
"@eslint/compat": "^1.1.1",
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.10.0",
"@types/bun": "latest",
"@types/node": "^22",
"@types/react": "19",
"tsx": "^4.19.0",
"@typescript-eslint/eslint-plugin": "^8.4.0",
"@typescript-eslint/parser": "^8.4.0",
"eslint": "^9.10.0",
Expand All @@ -47,16 +49,18 @@
"@effect/cli": "^0.72.1",
"@effect/opentelemetry": "^0.59.1",
"@effect/platform": "^0.93.5",
"@effect/platform-bun": "^0.85.0",
"@effect/platform-node": "^0.104.0",
"@effect/rpc": "^0.72.2",
"@effect/rpc-http": "^0.52.4",
"@mariozechner/pi-coding-agent": "^0.38.0",
"@opentelemetry/otlp-transformer": "^0.208.0",
"@opentelemetry/sdk-trace-base": "^2.2.0",
"@opentui/core": "^0.1.55",
"@opentui/react": "^0.1.55",
"effect": "^3.19.8",
"react": "19",
"react-dom": "19",
"uuid": "^11.1.0",
"yaml": "^2.7.0"
}
}
Loading