Skip to content

Commit 2d803af

Browse files
committed
Use turso db
1 parent 0b17cc0 commit 2d803af

File tree

34 files changed

+350
-208
lines changed

34 files changed

+350
-208
lines changed

bun.lock

Lines changed: 43 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/opencode/Dockerfile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1+
FROM node:20-slim AS libsql-native
2+
WORKDIR /libsql
3+
RUN npm install @libsql/linux-x64-gnu@0.5.22
4+
15
FROM debian:12-slim AS base
26

37
# Disable the runtime transpiler cache by default inside Docker containers.
48
# On ephemeral containers, the cache is not useful
59
ARG BUN_RUNTIME_TRANSPILER_CACHE_PATH=0
610
ENV BUN_RUNTIME_TRANSPILER_CACHE_PATH=${BUN_RUNTIME_TRANSPILER_CACHE_PATH}
7-
RUN apt-get update && apt-get install -y ripgrep libgcc-s1 && rm -rf /var/lib/apt/lists/*
11+
RUN apt-get update && apt-get install -y ripgrep libgcc-s1 ca-certificates && rm -rf /var/lib/apt/lists/*
812

913
COPY dist/opencode-linux-x64/bin/opencode /usr/local/bin/opencode
14+
COPY --from=libsql-native /libsql/node_modules/@libsql/linux-x64-gnu /node_modules/@libsql/linux-x64-gnu
15+
ENV NODE_PATH=/node_modules
1016
RUN opencode --version
1117
ENTRYPOINT ["opencode"]
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { defineConfig } from "drizzle-kit"
22

33
export default defineConfig({
4-
dialect: "sqlite",
4+
dialect: "turso",
55
schema: "./src/**/*.sql.ts",
66
out: "./migration",
77
dbCredentials: {
8-
url: "/home/thdxr/.local/share/opencode/opencode.db",
8+
url: process.env["OPENCODE_DB_URL"] ?? `file:${process.env["HOME"]}/.local/share/opencode/opencode.db`,
9+
authToken: process.env["OPENCODE_DB_TOKEN"],
910
},
1011
})

packages/opencode/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"zod-to-json-schema": "3.24.5"
5757
},
5858
"dependencies": {
59+
"@libsql/client": "^0.17.0",
5960
"@actions/core": "1.11.1",
6061
"@actions/github": "6.0.1",
6162
"@agentclientprotocol/sdk": "0.14.1",

packages/opencode/src/account/index.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@ export { AccessToken, AccountID, OrgID } from "./service"
1313

1414
import { runtime } from "@/effect/runtime"
1515

16-
function runSync<A>(f: (service: AccountService.Service) => Effect.Effect<A, AccountError>) {
17-
return runtime.runSync(AccountService.use(f))
18-
}
19-
2016
function runPromise<A>(f: (service: AccountService.Service) => Effect.Effect<A, AccountError>) {
2117
return runtime.runPromise(AccountService.use(f))
2218
}
@@ -25,8 +21,8 @@ export namespace Account {
2521
export const Account = AccountSchema
2622
export type Account = AccountSchema
2723

28-
export function active(): Account | undefined {
29-
return Option.getOrUndefined(runSync((service) => service.active()))
24+
export async function active(): Promise<Account | undefined> {
25+
return Option.getOrUndefined(await runPromise((service) => service.active()))
3026
}
3127

3228
export async function config(accountID: AccountID, orgID: OrgID): Promise<Record<string, unknown> | undefined> {

packages/opencode/src/account/repo.ts

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -42,27 +42,27 @@ export class AccountRepo extends ServiceMap.Service<AccountRepo, AccountRepo.Ser
4242
Effect.gen(function* () {
4343
const decode = Schema.decodeUnknownSync(Account)
4444

45-
const query = <A>(f: (db: DbClient) => A) =>
46-
Effect.try({
45+
const query = <A>(f: (db: DbClient) => Promise<A>) =>
46+
Effect.tryPromise({
4747
try: () => Database.use(f),
4848
catch: (cause) => new AccountRepoError({ message: "Database operation failed", cause }),
4949
})
5050

51-
const tx = <A>(f: (db: DbClient) => A) =>
52-
Effect.try({
51+
const tx = <A>(f: (db: DbClient) => Promise<A>) =>
52+
Effect.tryPromise({
5353
try: () => Database.transaction(f),
5454
catch: (cause) => new AccountRepoError({ message: "Database operation failed", cause }),
5555
})
5656

57-
const current = (db: DbClient) => {
58-
const state = db.select().from(AccountStateTable).where(eq(AccountStateTable.id, ACCOUNT_STATE_ID)).get()
57+
const current = async (db: DbClient) => {
58+
const state = await db.select().from(AccountStateTable).where(eq(AccountStateTable.id, ACCOUNT_STATE_ID)).get()
5959
if (!state?.active_account_id) return
60-
const account = db.select().from(AccountTable).where(eq(AccountTable.id, state.active_account_id)).get()
60+
const account = await db.select().from(AccountTable).where(eq(AccountTable.id, state.active_account_id)).get()
6161
if (!account) return
6262
return { ...account, active_org_id: state.active_org_id ?? null }
6363
}
6464

65-
const state = (db: DbClient, accountID: AccountID, orgID: Option.Option<OrgID>) => {
65+
const state = async (db: DbClient, accountID: AccountID, orgID: Option.Option<OrgID>) => {
6666
const id = Option.getOrNull(orgID)
6767
return db
6868
.insert(AccountStateTable)
@@ -75,41 +75,39 @@ export class AccountRepo extends ServiceMap.Service<AccountRepo, AccountRepo.Ser
7575
}
7676

7777
const active = Effect.fn("AccountRepo.active")(() =>
78-
query((db) => current(db)).pipe(Effect.map((row) => (row ? Option.some(decode(row)) : Option.none()))),
78+
query(async (db) => current(db)).pipe(Effect.map((row) => (row ? Option.some(decode(row)) : Option.none()))),
7979
)
8080

8181
const list = Effect.fn("AccountRepo.list")(() =>
82-
query((db) =>
83-
db
84-
.select()
85-
.from(AccountTable)
86-
.all()
87-
.map((row: AccountRow) => decode({ ...row, active_org_id: null })),
88-
),
82+
query(async (db) => {
83+
const rows = await db.select().from(AccountTable).all()
84+
return rows.map((row: AccountRow) => decode({ ...row, active_org_id: null }))
85+
}),
8986
)
9087

9188
const remove = Effect.fn("AccountRepo.remove")((accountID: AccountID) =>
92-
tx((db) => {
93-
db.update(AccountStateTable)
89+
tx(async (db) => {
90+
await db
91+
.update(AccountStateTable)
9492
.set({ active_account_id: null, active_org_id: null })
9593
.where(eq(AccountStateTable.active_account_id, accountID))
9694
.run()
97-
db.delete(AccountTable).where(eq(AccountTable.id, accountID)).run()
95+
await db.delete(AccountTable).where(eq(AccountTable.id, accountID)).run()
9896
}).pipe(Effect.asVoid),
9997
)
10098

10199
const use = Effect.fn("AccountRepo.use")((accountID: AccountID, orgID: Option.Option<OrgID>) =>
102-
query((db) => state(db, accountID, orgID)).pipe(Effect.asVoid),
100+
query(async (db) => state(db, accountID, orgID)).pipe(Effect.asVoid),
103101
)
104102

105103
const getRow = Effect.fn("AccountRepo.getRow")((accountID: AccountID) =>
106-
query((db) => db.select().from(AccountTable).where(eq(AccountTable.id, accountID)).get()).pipe(
104+
query(async (db) => db.select().from(AccountTable).where(eq(AccountTable.id, accountID)).get()).pipe(
107105
Effect.map(Option.fromNullishOr),
108106
),
109107
)
110108

111109
const persistToken = Effect.fn("AccountRepo.persistToken")((input) =>
112-
query((db) =>
110+
query(async (db) =>
113111
db
114112
.update(AccountTable)
115113
.set({
@@ -123,8 +121,9 @@ export class AccountRepo extends ServiceMap.Service<AccountRepo, AccountRepo.Ser
123121
)
124122

125123
const persistAccount = Effect.fn("AccountRepo.persistAccount")((input) =>
126-
tx((db) => {
127-
db.insert(AccountTable)
124+
tx(async (db) => {
125+
await db
126+
.insert(AccountTable)
128127
.values({
129128
id: input.id,
130129
email: input.email,
@@ -142,7 +141,7 @@ export class AccountRepo extends ServiceMap.Service<AccountRepo, AccountRepo.Ser
142141
},
143142
})
144143
.run()
145-
void state(db, input.id, input.orgID)
144+
await state(db, input.id, input.orgID)
146145
}).pipe(Effect.asVoid),
147146
)
148147

packages/opencode/src/cli/cmd/db.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,20 @@ const MigrateCommand = cmd({
108108
},
109109
})
110110

111+
const SyncCommand = cmd({
112+
command: "sync",
113+
describe: "sync local database replica with remote Turso database",
114+
handler: async () => {
115+
await Database.sync()
116+
process.stdout.write("Database sync complete." + EOL)
117+
},
118+
})
119+
111120
export const DbCommand = cmd({
112121
command: "db",
113122
describe: "database tools",
114123
builder: (yargs: Argv) => {
115-
return yargs.command(QueryCommand).command(PathCommand).command(MigrateCommand).demandCommand()
124+
return yargs.command(QueryCommand).command(PathCommand).command(MigrateCommand).command(SyncCommand).demandCommand()
116125
},
117126
handler: () => {},
118127
})

packages/opencode/src/cli/cmd/import.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ export const ImportCommand = cmd({
158158
projectID: Instance.project.id,
159159
})
160160
const row = Session.toRow(info)
161-
Database.use((db) =>
161+
await Database.use(async (db) =>
162162
db
163163
.insert(SessionTable)
164164
.values(row)
@@ -169,7 +169,7 @@ export const ImportCommand = cmd({
169169
for (const msg of exportData.messages) {
170170
const msgInfo = MessageV2.Info.parse(msg.info)
171171
const { id, sessionID: _, ...msgData } = msgInfo
172-
Database.use((db) =>
172+
await Database.use(async (db) =>
173173
db
174174
.insert(MessageTable)
175175
.values({
@@ -185,7 +185,7 @@ export const ImportCommand = cmd({
185185
for (const part of msg.parts) {
186186
const partInfo = MessageV2.Part.parse(part)
187187
const { id: partId, sessionID: _s, messageID, ...partData } = partInfo
188-
Database.use((db) =>
188+
await Database.use(async (db) =>
189189
db
190190
.insert(PartTable)
191191
.values({

packages/opencode/src/cli/cmd/session.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ export const SessionListCommand = cmd({
9090
},
9191
handler: async (args) => {
9292
await bootstrap(process.cwd(), async () => {
93-
const sessions = [...Session.list({ roots: true, limit: args.maxCount })]
93+
const sessions = await Array.fromAsync(Session.list({ roots: true, limit: args.maxCount }))
9494

9595
if (sessions.length === 0) {
9696
return

0 commit comments

Comments
 (0)