feat(api): publish v2 reference

This commit is contained in:
Dax Raad 2026-07-06 01:29:08 -04:00
commit eed23d8ee9
40 changed files with 26473 additions and 147 deletions

View file

@ -3,8 +3,10 @@ export * as Project from "./project"
import { Context, Effect, Layer, Schema } from "effect"
import { ChildProcess } from "effect/unstable/process"
import { asc, desc } from "drizzle-orm"
import path from "path"
import { AbsolutePath } from "./schema"
import { Database } from "./database/database"
import { FSUtil } from "./fs-util"
import { Git } from "./git"
import { AppProcess } from "./process"
@ -12,6 +14,7 @@ import { makeGlobalNode } from "./effect/app-node"
import { Hash } from "./util/hash"
import { ProjectDirectories } from "./project/directories"
import { ProjectSchema } from "./project/schema"
import { ProjectTable } from "./project/sql"
export const ID = ProjectSchema.ID
export type ID = ProjectSchema.ID
@ -25,9 +28,8 @@ export type Current = ProjectSchema.Current
export const Directory = ProjectSchema.Directory
export type Directory = ProjectSchema.Directory
export class Info extends Schema.Class<Info>("Project.Info")({
id: ID,
}) {}
export const Info = ProjectSchema.Info
export interface Info extends Schema.Schema.Type<typeof Info> {}
export const DirectoriesInput = ProjectSchema.DirectoriesInput
export type DirectoriesInput = typeof DirectoriesInput.Type
@ -54,6 +56,7 @@ export const root = Effect.fn("Project.root")(function* (
})
export interface Interface {
readonly list: () => Effect.Effect<ReadonlyArray<Info>>
readonly directories: (input: DirectoriesInput) => Effect.Effect<Directories>
readonly resolve: (input: AbsolutePath) => Effect.Effect<Resolved>
/**
@ -70,14 +73,50 @@ export interface Interface {
export class Service extends Context.Service<Service, Interface>()("@opencode/ProjectV2") {}
function fromRow(row: typeof ProjectTable.$inferSelect): Info {
const icon =
row.icon_url || row.icon_url_override || row.icon_color
? {
url: row.icon_url ?? undefined,
override: row.icon_url_override ?? undefined,
color: row.icon_color ?? undefined,
}
: undefined
return {
id: row.id,
worktree: row.worktree,
vcs: row.vcs ?? undefined,
name: row.name ?? undefined,
icon,
commands: row.commands ?? undefined,
time: {
created: row.time_created,
updated: row.time_updated,
initialized: row.time_initialized ?? undefined,
},
sandboxes: row.sandboxes,
}
}
const layer = Layer.effect(
Service,
Effect.gen(function* () {
const fs = yield* FSUtil.Service
const git = yield* Git.Service
const proc = yield* AppProcess.Service
const db = (yield* Database.Service).db
const projectDirectories = yield* ProjectDirectories.Service
const list = Effect.fn("Project.list")(function* () {
const rows = yield* db
.select()
.from(ProjectTable)
.orderBy(desc(ProjectTable.time_updated), asc(ProjectTable.id))
.all()
.pipe(Effect.orDie)
return rows.map(fromRow)
})
const directories = Effect.fn("Project.directories")(function* (input: DirectoriesInput) {
return yield* projectDirectories.list(input.projectID)
})
@ -190,12 +229,12 @@ const layer = Layer.effect(
yield* fs.writeFileString(path.join(input.store, "opencode"), input.id).pipe(Effect.ignore)
})
return Service.of({ directories, resolve, commit })
return Service.of({ list, directories, resolve, commit })
}),
)
export const node = makeGlobalNode({
service: Service,
layer: layer,
deps: [FSUtil.node, Git.node, AppProcess.node, ProjectDirectories.node],
deps: [Database.node, FSUtil.node, Git.node, AppProcess.node, ProjectDirectories.node],
})

View file

@ -13,6 +13,9 @@ export type Current = typeof Current.Type
export const Directory = Project.Directory
export type Directory = typeof Directory.Type
export const Info = Project.Info
export interface Info extends Schema.Schema.Type<typeof Info> {}
export const DirectoriesInput = Project.DirectoriesInput
export type DirectoriesInput = typeof DirectoriesInput.Type

View file

@ -6,7 +6,7 @@ import { ProjectSchema } from "./schema"
export const ProjectTable = sqliteTable("project", {
id: text().$type<ProjectSchema.ID>().primaryKey(),
worktree: absoluteColumn().notNull(),
vcs: text(),
vcs: text().$type<"git" | "hg">(),
name: text(),
icon_url: text(),
icon_url_override: text(),