@@ -196,15 +196,59 @@ import regressions at runtime — the typechecker does not catch these.
196196## Rules for new code
197197
198198- No new ` export namespace ` .
199- - Every module file that wants a namespace gets a self-reexport at the
199+ - Every module directory has a single canonical file — typically
200+ ` dir/index.ts ` — with flat top-level exports and a self-reexport at the
200201 bottom:
201- ` export * as Foo from "./foo" `
202- - Consumers import from the file itself:
203- ` import { Foo } from "../path/to/foo" `
204- - No new barrel ` index.ts ` files for internal code.
202+ ` export * as Foo from "." `
203+ - Consumers import from the directory:
204+ ` import { Foo } from "@/dir" ` or ` import { Foo } from "../dir" ` .
205+ - No sibling barrel files. If a directory has multiple independent
206+ namespaces, they each get their own file (e.g. ` config/config.ts ` ,
207+ ` config/plugin.ts ` ) and their own self-reexport; the ` index.ts ` in that
208+ directory stays minimal or does not exist.
205209- If a file needs a sibling, import the sibling file directly:
206210 ` import * as Sibling from "./sibling" ` , not ` from "." ` .
207211
212+ ### Why ` dir/index.ts ` + ` "." ` is fine for us
213+
214+ A single-file module (e.g. ` pty/ ` ) can live entirely in ` dir/index.ts `
215+ with ` export * as Foo from "." ` at the bottom. Consumers write the
216+ short form:
217+
218+ ``` ts
219+ import { Pty } from " @/pty"
220+ ```
221+
222+ This works in Bun runtime, Bun build, esbuild, and Rollup. It does NOT
223+ work under Node's ` --experimental-strip-types ` runner:
224+
225+ ```
226+ node --experimental-strip-types entry.ts
227+ ERR_UNSUPPORTED_DIR_IMPORT: Directory import '/.../pty' is not supported
228+ ```
229+
230+ Node requires an explicit file or a ` package.json#exports ` map for ESM.
231+ We don't care about that target right now because the opencode CLI is
232+ built with Bun and the web apps are built with Vite/Rollup. If we ever
233+ want to run raw ` .ts ` through Node, we'll need to either use explicit
234+ ` .ts ` extensions everywhere or add per-directory ` package.json ` exports
235+ maps.
236+
237+ ### When NOT to collapse to ` index.ts `
238+
239+ Some directories contain multiple independent namespaces where
240+ ` dir/index.ts ` would be misleading. Examples:
241+
242+ - ` config/ ` has ` Config ` , ` ConfigPaths ` , ` ConfigMarkdown ` , ` ConfigPlugin ` ,
243+ ` ConfigKeybinds ` . Each lives in its own file with its own self-reexport
244+ (` config/config.ts ` , ` config/plugin.ts ` , etc.). Consumers import the
245+ specific one: ` import { ConfigPlugin } from "@/config/plugin" ` .
246+ - Same shape for ` session/ ` , ` server/ ` , etc.
247+
248+ Collapsing one of those into ` index.ts ` would mean picking a single
249+ "canonical" namespace for the directory, which breaks the symmetry and
250+ hides the other files.
251+
208252## Scope
209253
210254There are still dozens of ` export namespace ` files left across the codebase.
0 commit comments