Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
36160ef
feat(core): add sqlite schema sync
thdxr May 21, 2026
eaf5697
progress
thdxr May 22, 2026
0cab11f
refactor(core): move database schema ownership
thdxr May 24, 2026
977f48a
Merge remote-tracking branch 'origin/dev' into refactor/core-database…
thdxr May 24, 2026
46422a4
core: support native node sqlite database runtime
thdxr May 24, 2026
31d8959
core: isolate native node sqlite provider
thdxr May 24, 2026
077c91b
core: avoid session schema import cycle
thdxr May 24, 2026
4695346
refactor(core): centralize project and workspace schemas
thdxr May 24, 2026
aa8ad49
refactor(core): centralize legacy session schemas
thdxr May 24, 2026
9b812d9
fix(core): migrate sync database clients
thdxr May 24, 2026
9ded717
refactor(core): unify sqlite database clients
thdxr May 24, 2026
b18ff8f
progress
thdxr May 24, 2026
dedcb9b
refactor(core): project session events in core
thdxr May 25, 2026
05dca9f
feat(core): persist sync event projections
thdxr May 25, 2026
06bd34c
feat(core): add sync event replay controls
thdxr May 25, 2026
13e9e31
chore: merge dev into core database branch
thdxr May 25, 2026
9440f7f
test(core): cover sync event replay controls
thdxr May 25, 2026
7180c3a
fix(core): add session list cursor schema
thdxr May 25, 2026
dcbe09b
refactor(core): mark session methods unimplemented
thdxr May 25, 2026
b819034
fix(opencode): align v2 session endpoint errors
thdxr May 25, 2026
dad0f57
refactor(opencode): remove storage db from domain services
thdxr May 25, 2026
08c17e8
refactor(opencode): move session reads to core database
thdxr May 25, 2026
087d356
chore(core): format event service
thdxr May 25, 2026
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
3 changes: 3 additions & 0 deletions .opencode/opencode.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
"$schema": "https://opencode.ai/config.json",
"provider": {},
"permission": {},
"reference": {
"effect": "github.com/Effect-TS/effect-smol",
},
"mcp": {},
"tools": {
"github-triage": false,
Expand Down
6 changes: 6 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ obj.b
const { a, b } = obj
```

### Imports

- Never alias imports. Do not use `import { foo as bar } from "..."` or renamed imports like `resolve as pathResolve`.
- Never use star imports. Do not use `import * as Foo from "..."` or `import type * as Foo from "..."`.
- If a namespace-style value is needed, import the module's own exported namespace by name, for example `import { Project } from "@opencode-ai/core/project"`, then reference `Project.ID`.

### Variables

Prefer `const` over `let`. Use ternaries or early returns instead of reassignment.
Expand Down
20 changes: 19 additions & 1 deletion bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

File renamed without changes.
17 changes: 15 additions & 2 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
"license": "MIT",
"private": true,
"scripts": {
"db": "bun drizzle-kit",
"migration": "bun run script/migration.ts",
"test": "bun test",
"test:ci": "mkdir -p .artifacts/unit && bun test --timeout 30000 --reporter=junit --reporter-outfile=.artifacts/unit/junit.xml",
"typecheck": "tsgo --noEmit"
Expand All @@ -16,14 +18,21 @@
"exports": {
"./*": "./src/*.ts"
},
"imports": {},
"imports": {
"#sqlite": {
"bun": "./src/database/sqlite.bun.ts",
"node": "./src/database/sqlite.node.ts",
"default": "./src/database/sqlite.bun.ts"
}
},
"devDependencies": {
"@tsconfig/bun": "catalog:",
"@types/bun": "catalog:",
"@types/cross-spawn": "catalog:",
"@types/npm-package-arg": "6.1.4",
"@types/npmcli__arborist": "6.3.3",
"@types/semver": "catalog:"
"@types/semver": "catalog:",
"drizzle-kit": "catalog:"
},
"dependencies": {
"@ai-sdk/alibaba": "1.0.17",
Expand All @@ -49,15 +58,19 @@
"@aws-sdk/credential-providers": "3.993.0",
"@effect/opentelemetry": "catalog:",
"@effect/platform-node": "catalog:",
"@effect/sql-sqlite-bun": "catalog:",
"@npmcli/arborist": "9.4.0",
"@npmcli/config": "10.8.1",
"@opencode-ai/effect-drizzle-sqlite": "workspace:*",
"@opencode-ai/effect-sqlite-node": "workspace:*",
"@opentelemetry/api": "1.9.0",
"@opentelemetry/context-async-hooks": "2.6.1",
"@opentelemetry/exporter-trace-otlp-http": "0.214.0",
"@opentelemetry/sdk-trace-base": "2.6.1",
"@openrouter/ai-sdk-provider": "2.8.1",
"ai-gateway-provider": "3.1.2",
"cross-spawn": "catalog:",
"drizzle-orm": "catalog:",
"effect": "catalog:",
"gitlab-ai-provider": "6.7.0",
"glob": "13.0.5",
Expand Down
62 changes: 62 additions & 0 deletions packages/core/script/migration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env bun

import { $ } from "bun"
import path from "path"

const root = path.resolve(import.meta.dirname, "../../..")
const sqlDir = path.join(root, "packages/core/migration")
const tsDir = path.join(root, "packages/core/src/database/migration")
const registry = path.join(root, "packages/core/src/database/migration.gen.ts")

await $`bun drizzle-kit generate`.cwd(path.join(root, "packages/core"))

const sqlMigrations = (await Array.fromAsync(new Bun.Glob("*/migration.sql").scan({ cwd: sqlDir })))
.map((file) => file.split("/")[0])
.filter((name) => name !== undefined)
.sort()

for (const name of sqlMigrations) {
if (await Bun.file(path.join(tsDir, `${name}.ts`)).exists()) continue
await Bun.write(path.join(tsDir, `${name}.ts`), renderMigration(name, await Bun.file(path.join(sqlDir, name, "migration.sql")).text()))
}

await Bun.write(registry, renderRegistry(sqlMigrations))

function renderMigration(name: string, sql: string) {
return `import { Effect } from "effect"
import type { DatabaseMigration } from "../migration"

export default {
id: ${JSON.stringify(name)},
up(tx) {
return Effect.gen(function* () {
${sql
.split("--> statement-breakpoint")
.map((statement) => statement.trim())
.filter((statement) => statement.length > 0)
.map(renderRun)
.join("\n")}
})
},
} satisfies DatabaseMigration.Migration
`
}

function renderRun(statement: string) {
const lines = statement.replaceAll("\t", " ").split("\n")
if (lines.length === 1) return ` yield* tx.run(\`${escapeTemplate(lines[0])}\`)`
return ` yield* tx.run(\`\n${lines.map((line) => ` ${escapeTemplate(line)}`).join("\n")}\n \`)`
}

function escapeTemplate(line: string) {
return line.replaceAll("\\", "\\\\").replaceAll("`", "\\`").replaceAll("${", "\\${")
}

function renderRegistry(names: string[]) {
return `import type { DatabaseMigration } from "./migration"

export const migrations = (await Promise.all([
${names.map((name) => ` import("./migration/${name}"),`).join("\n")}
])).map((module) => module.default) satisfies DatabaseMigration.Migration[]
`
}
Loading
Loading