mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-03-30 05:43:55 +00:00
- Rename packages/opencode → packages/tfcode (directory only) - Rename bin/opencode → bin/tfcode (CLI binary) - Rename .opencode → .tfcode (config directory) - Update package.json name and bin field - Update config directory path references (.tfcode) - Keep internal code references as 'opencode' for easy upstream sync - Keep @opencode-ai/* workspace package names This minimal branding approach allows clean merges from upstream opencode repository while providing tfcode branding for users.
3.2 KiB
3.2 KiB
opencode database guide
Database
- Schema: Drizzle schema lives in
src/**/*.sql.ts. - Naming: tables and columns use snake*case; join columns are
<entity>_id; indexes are<table>*<column>\_idx. - Migrations: generated by Drizzle Kit using
drizzle.config.ts(schema:./src/**/*.sql.ts, output:./migration). - Command:
bun run db generate --name <slug>. - Output: creates
migration/<timestamp>_<slug>/migration.sqlandsnapshot.json. - Tests: migration tests should read the per-folder layout (no
_journal.json).
opencode Effect rules
Use these rules when writing or migrating Effect code.
See specs/effect-migration.md for the compact pattern reference and examples.
Core
- Use
Effect.gen(function* () { ... })for composition. - Use
Effect.fn("Domain.method")for named/traced effects andEffect.fnUntracedfor internal helpers. Effect.fn/Effect.fnUntracedaccept pipeable operators as extra arguments, so avoid unnecessary outer.pipe()wrappers.- Use
Effect.callbackfor callback-based APIs. - Prefer
DateTime.nowAsDateovernew Date(yield* Clock.currentTimeMillis)when you need aDate.
Schemas and errors
- Use
Schema.Classfor multi-field data. - Use branded schemas (
Schema.brand) for single-value types. - Use
Schema.TaggedErrorClassfor typed errors. - Use
Schema.Defectinstead ofunknownfor defect-like causes. - In
Effect.gen/Effect.fn, preferyield* new MyError(...)overyield* Effect.fail(new MyError(...))for direct early-failure branches.
Runtime vs Instances
- Use the shared runtime for process-wide services with one lifecycle for the whole app.
- Use
src/effect/instances.tsfor per-directory or per-project services that needInstanceContext, per-instance state, or per-instance cleanup. - If two open directories should not share one copy of the service, it belongs in
Instances. - Instance-scoped services should read context from
InstanceContext, notInstance.*globals.
Preferred Effect services
- In effectified services, prefer yielding existing Effect services over dropping down to ad hoc platform APIs.
- Prefer
FileSystem.FileSysteminstead of rawfs/promisesfor effectful file I/O. - Prefer
ChildProcessSpawner.ChildProcessSpawnerwithChildProcess.make(...)instead of custom process wrappers. - Prefer
HttpClient.HttpClientinstead of rawfetch. - Prefer
Path.Path,Config,Clock, andDateTimewhen those concerns are already inside Effect code. - For background loops or scheduled tasks, use
Effect.repeatorEffect.schedulewithEffect.forkScopedin the layer definition.
Instance.bind — ALS for native callbacks
Instance.bind(fn) captures the current Instance AsyncLocalStorage context and restores it synchronously when called.
Use it for native addon callbacks (@parcel/watcher, node-pty, native fs.watch, etc.) that need to call Bus.publish, Instance.state(), or anything that reads Instance.directory.
You do not need it for setTimeout, Promise.then, EventEmitter.on, or Effect fibers.
const cb = Instance.bind((err, evts) => {
Bus.publish(MyEvent, { ... })
})
nativeAddon.subscribe(dir, cb)