Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 7 additions & 8 deletions packages/core/src/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export * as PluginV2 from "./plugin"

import { Context, Deferred, Effect, Exit, Layer, Scope } from "effect"
import type { Plugin } from "@opencode-ai/plugin/v2/effect"
import { PluginEvent, PluginID } from "@opencode-ai/schema/plugin"
import type { Plugin as PluginRuntime } from "@opencode-ai/plugin/v2/effect"
import { Plugin } from "@opencode-ai/schema/plugin"
import { AgentV2 } from "./agent"
import { AISDK } from "./aisdk"
import { Catalog } from "./catalog"
Expand All @@ -15,13 +15,12 @@ import { Reference } from "./reference"
import { SkillV2 } from "./skill"
import { State } from "./state"

export const ID = PluginID
export const ID = Plugin.ID
export type ID = typeof ID.Type

export const Event = PluginEvent
export const Event = Plugin.Event

export interface Interface {
readonly add: (id: ID, effect: Plugin["effect"]) => Effect.Effect<void>
readonly add: (id: ID, effect: PluginRuntime["effect"]) => Effect.Effect<void>
readonly remove: (id: ID) => Effect.Effect<void>
readonly wait: (id: ID) => Effect.Effect<void>
}
Expand All @@ -38,9 +37,9 @@ export const layer = Layer.effect(
const loading = new Set<ID>()
const waiters = new Map<ID, Set<Deferred.Deferred<void>>>()
const failures = new Map<ID, Exit.Exit<void, never>>()
let host: Parameters<Plugin["effect"]>[0]
let host: Parameters<PluginRuntime["effect"]>[0]

const add = Effect.fn("Plugin.add")(function* (id: ID, effect: Plugin["effect"]) {
const add = Effect.fn("Plugin.add")(function* (id: ID, effect: PluginRuntime["effect"]) {
if (loading.has(id)) return yield* Effect.die(`Plugin load cycle detected for ${id}`)

yield* locks.withLock(id)(
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/project/copy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Slug } from "../util/slug"
import { EventV2 } from "../event"
import { Database } from "../database/database"
import { Location } from "../location"
import { ProjectDirectoriesEvent } from "@opencode-ai/schema/project-directories"
import { Event } from "@opencode-ai/schema/project-directories"
import { ProjectCopy } from "@opencode-ai/schema/project-copy"

export const StrategyID = ProjectCopy.StrategyID
Expand Down Expand Up @@ -96,7 +96,7 @@ export interface Strategy {
readonly list: (directory: AbsolutePath) => Effect.Effect<ListEntry[], Git.WorktreeError | DirectoryUnavailableError>
}

export const Event = ProjectDirectoriesEvent
export { Event }

export interface Interface {
readonly register: (strategy: Strategy) => Effect.Effect<void, DuplicateStrategyError>
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/project/directories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { and, asc, desc, eq, isNotNull, isNull, ne, or } from "drizzle-orm"
import { Context, Effect, Layer, Schema } from "effect"
import { Database } from "../database/database"
import { LayerNode } from "../effect/layer-node"
import { AbsolutePath, optionalOmitUndefined } from "../schema"
import { AbsolutePath, optional } from "../schema"
import { ProjectSchema } from "./schema"
import { ProjectDirectoryTable } from "./sql"
import type { EffectDrizzleSqlite } from "@opencode-ai/effect-drizzle-sqlite"
Expand Down Expand Up @@ -39,7 +39,7 @@ export type ListInput = typeof ListInput.Type
export const ListOutput = Schema.Array(
Schema.Struct({
directory: AbsolutePath,
strategy: optionalOmitUndefined(Schema.String),
strategy: optional(Schema.String),
}),
).annotate({ identifier: "Project.Directories" })
export type ListOutput = typeof ListOutput.Type
Expand Down
9 changes: 4 additions & 5 deletions packages/core/src/pty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export * as Pty from "./pty"

import type { Disp, Proc } from "#pty"
import { Context, Effect, Layer, Schema, Types } from "effect"
import { PtyEvent, PtyInfo, Pty } from "@opencode-ai/schema/pty"
import { Pty } from "@opencode-ai/schema/pty"
import { Config } from "./config"
import { EventV2 } from "./event"
import { Location } from "./location"
Expand Down Expand Up @@ -35,8 +35,7 @@ type Active = {
listeners: Disp[]
}

export const Info = PtyInfo

export const Info = Pty.Info
export type Info = Types.DeepMutable<typeof Info.Type>

export const CreateInput = Pty.CreateInput
Expand All @@ -47,6 +46,8 @@ export const UpdateInput = Pty.UpdateInput

export type UpdateInput = Types.DeepMutable<typeof UpdateInput.Type>

export const Event = Pty.Event

export type AttachInput = {
// Absolute output cursor to replay from. -1 tails from the current end; omitted replays the full retained buffer.
readonly cursor?: number
Expand Down Expand Up @@ -75,8 +76,6 @@ export class ExitedError extends Schema.TaggedErrorClass<ExitedError>()("Pty.Exi
ptyID: PtyID,
}) {}

export const Event = PtyEvent

export interface Interface {
readonly list: () => Effect.Effect<Info[]>
readonly get: (id: PtyID) => Effect.Effect<Info, NotFoundError>
Expand Down
8 changes: 4 additions & 4 deletions packages/core/src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@ import {
AbsolutePath,
DateTimeUtcFromMillis,
NonNegativeInt,
optionalOmitUndefined,
optional,
PositiveInt,
RelativePath,
withStatics,
statics,
} from "@opencode-ai/schema/schema"

export {
AbsolutePath,
DateTimeUtcFromMillis,
NonNegativeInt,
optionalOmitUndefined,
optional,
PositiveInt,
RelativePath,
withStatics,
statics,
}

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/session/context-epoch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ContextSnapshotDecodeError } from "./error"
import { SessionEvent } from "./event"
import { SessionHistory } from "./history"
import { SessionInput } from "./input"
import { SessionMessageID } from "./message-id"
import { SessionMessage } from "./message"
import { SessionSchema } from "./schema"
import { SessionContextEpochTable } from "./sql"

Expand Down Expand Up @@ -71,7 +71,7 @@ const prepareOnce = Effect.fnUntraced(function* (

yield* events.publish(
SessionEvent.ContextUpdated,
{ sessionID, messageID: SessionMessageID.ID.create(), timestamp: yield* DateTime.now, text: result.text },
{ sessionID, messageID: SessionMessage.ID.create(), timestamp: yield* DateTime.now, text: result.text },
{ commit: () => advance(db, sessionID, result.snapshot).pipe(Effect.orDie) },
)
return { baseline: stored.baseline, baselineSeq: stored.baseline_seq }
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/session/info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { AbsolutePath, RelativePath } from "../schema"
import { WorkspaceV2 } from "../workspace"
import { SessionSchema } from "./schema"
import { SessionTable } from "./sql"
import { SessionMessageID } from "./message-id"
import { SessionMessage } from "./message"
import { Snapshot } from "../snapshot"

export function fromRow(row: typeof SessionTable.$inferSelect): SessionSchema.Info {
Expand Down Expand Up @@ -40,7 +40,7 @@ export function fromRow(row: typeof SessionTable.$inferSelect): SessionSchema.In
workspaceID: row.workspace_id ? WorkspaceV2.ID.make(row.workspace_id) : undefined,
}),
subpath: row.path ? RelativePath.make(row.path) : undefined,
revert: row.revert ? { ...row.revert, messageID: SessionMessageID.ID.make(row.revert.messageID) } : undefined,
revert: row.revert ? { ...row.revert, messageID: SessionMessage.ID.make(row.revert.messageID) } : undefined,
time: {
created: DateTime.makeUnsafe(row.time_created),
updated: DateTime.makeUnsafe(row.time_updated),
Expand Down
2 changes: 0 additions & 2 deletions packages/core/src/session/message-id.ts

This file was deleted.

3 changes: 1 addition & 2 deletions packages/core/src/session/projector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import { WorkspaceV2 } from "../workspace"
import { SessionContextEpoch } from "./context-epoch"
import { MessageTable, PartTable, SessionInputTable, SessionMessageTable, SessionTable } from "./sql"
import type { DeepMutable } from "../schema"
import { SessionMessageID } from "./message-id"

type DatabaseService = Database.Interface["db"]

Expand Down Expand Up @@ -67,7 +66,7 @@ function sessionRow(info: SessionV1.SessionInfo): typeof SessionTable.$inferInse
tokens_reasoning: (info.tokens ?? { reasoning: 0 }).reasoning,
tokens_cache_read: (info.tokens ?? { cache: { read: 0 } }).cache.read,
tokens_cache_write: (info.tokens ?? { cache: { write: 0 } }).cache.write,
revert: info.revert ? { ...info.revert, messageID: SessionMessageID.ID.make(info.revert.messageID) } : null,
revert: info.revert ? { ...info.revert, messageID: SessionMessage.ID.make(info.revert.messageID) } : null,
permission: info.permission ? [...info.permission] : undefined,
time_created: info.time.created,
time_updated: info.time.updated,
Expand Down
5 changes: 2 additions & 3 deletions packages/core/src/session/todo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ export * as SessionTodo from "./todo"

import { asc, eq } from "drizzle-orm"
import { Context, Effect, Layer } from "effect"
import { SessionTodo, SessionTodoInfo } from "@opencode-ai/schema/session-todo"
import { SessionTodo } from "@opencode-ai/schema/session-todo"
import { Database } from "../database/database"
import { EventV2 } from "../event"
import { SessionSchema } from "./schema"
import { TodoTable } from "./sql"

export const Info = SessionTodoInfo
export const Info = SessionTodo.Info
export type Info = typeof Info.Type

export const Event = SessionTodo.Event

export interface Interface {
Expand Down
28 changes: 27 additions & 1 deletion packages/core/test/shared-schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { Model } from "@opencode-ai/schema/model"
import { AgentAttachment, FileAttachment, Prompt, Source } from "@opencode-ai/schema/prompt"
import { Provider } from "@opencode-ai/schema/provider"
import { Project } from "@opencode-ai/schema/project"
import { ProjectDirectories } from "@opencode-ai/schema/project-directories"
import { PermissionV1 } from "@opencode-ai/schema/permission-v1"
import { Session } from "@opencode-ai/schema/session"
import { SessionInput } from "@opencode-ai/schema/session-input"
import { SessionMessage } from "@opencode-ai/schema/session-message"
Expand All @@ -20,10 +22,14 @@ import { FileSystem } from "@opencode-ai/schema/filesystem"
import { Integration } from "@opencode-ai/schema/integration"
import { LLM } from "@opencode-ai/schema/llm"
import { Permission } from "@opencode-ai/schema/permission"
import { Plugin } from "@opencode-ai/schema/plugin"
import { Pty } from "@opencode-ai/schema/pty"
import { Reference } from "@opencode-ai/schema/reference"
import { SessionTodo } from "@opencode-ai/schema/session-todo"
import { Skill } from "@opencode-ai/schema/skill"
import { AbsolutePath, DateTimeUtcFromMillis } from "@opencode-ai/schema/schema"
import { AbsolutePath, DateTimeUtcFromMillis, optional, statics } from "@opencode-ai/schema/schema"
import { ProviderV2 } from "@opencode-ai/core/provider"
import { PluginV2 } from "@opencode-ai/core/plugin"

test("Core reuses the canonical shared schemas", async () => {
const [
Expand All @@ -35,13 +41,18 @@ test("Core reuses the canonical shared schemas", async () => {
coreLocation,
coreLLM,
corePermission,
corePermissionV1,
coreProjectCopy,
corePty,
coreProject,
coreReference,
coreSessionInput,
coreSessionMessage,
coreSessionTodo,
corePrompt,
coreSkill,
coreV2Schema,
coreSchema,
coreWorkspace,
] = await Promise.all([
import("@opencode-ai/core/command"),
Expand All @@ -52,13 +63,18 @@ test("Core reuses the canonical shared schemas", async () => {
import("@opencode-ai/core/location"),
import("@opencode-ai/llm"),
import("@opencode-ai/core/permission"),
import("@opencode-ai/core/v1/permission"),
import("@opencode-ai/core/project/copy"),
import("@opencode-ai/core/pty"),
import("@opencode-ai/core/project/schema"),
import("@opencode-ai/core/reference"),
import("@opencode-ai/core/session/input"),
import("@opencode-ai/core/session/message"),
import("@opencode-ai/core/session/todo"),
import("@opencode-ai/core/session/prompt"),
import("@opencode-ai/core/skill"),
import("@opencode-ai/core/v2-schema"),
import("@opencode-ai/core/schema"),
import("@opencode-ai/core/workspace"),
])

Expand Down Expand Up @@ -111,6 +127,12 @@ test("Core reuses the canonical shared schemas", async () => {
[corePermission.Effect, Permission.Effect],
[corePermission.Rule, Permission.Rule],
[corePermission.Ruleset, Permission.Ruleset],
[corePermissionV1.Event, PermissionV1.Event],
[coreProjectCopy.Event, ProjectDirectories.Event],
[PluginV2.ID, Plugin.ID],
[PluginV2.Event, Plugin.Event],
[corePty.Info, Pty.Info],
[corePty.Event, Pty.Event],
[coreProject.ID, Project.ID],
[coreReference.LocalSource, Reference.LocalSource],
[coreReference.GitSource, Reference.GitSource],
Expand Down Expand Up @@ -140,6 +162,8 @@ test("Core reuses the canonical shared schemas", async () => {
[coreSessionMessage.Assistant, SessionMessage.Assistant],
[coreSessionMessage.Compaction, SessionMessage.Compaction],
[coreSessionMessage.Message, SessionMessage.Message],
[coreSessionTodo.Info, SessionTodo.Info],
[coreSessionTodo.Event, SessionTodo.Event],
[corePrompt.Source, Source],
[corePrompt.FileAttachment, FileAttachment],
[corePrompt.AgentAttachment, AgentAttachment],
Expand All @@ -150,6 +174,8 @@ test("Core reuses the canonical shared schemas", async () => {
[coreSkill.Source, Skill.Source],
[coreSkill.Info, Skill.Info],
[coreV2Schema.DateTimeUtcFromMillis, DateTimeUtcFromMillis],
[coreSchema.optional, optional],
[coreSchema.statics, statics],
[coreWorkspace.ID, Workspace.ID],
]
for (const [core, shared] of schemas) expect(core).toBe(shared)
Expand Down
3 changes: 1 addition & 2 deletions packages/opencode/src/permission/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ import { Deferred, Effect, Layer, Context } from "effect"
import os from "os"
import { PermissionV1 } from "@opencode-ai/core/v1/permission"
import { EventV2Bridge } from "@/event-v2-bridge"
import { PermissionV1Event } from "@opencode-ai/schema/permission-v1"

export const Event = PermissionV1Event
export const Event = PermissionV1.Event

export interface Interface {
readonly ask: (input: PermissionV1.AskInput) => Effect.Effect<void, PermissionV1.Error>
Expand Down
12 changes: 6 additions & 6 deletions packages/opencode/src/provider/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { AuthOAuthResult, Hooks } from "@opencode-ai/plugin"
import { serviceUse } from "@opencode-ai/core/effect/service-use"
import { Auth } from "@/auth"
import { InstanceState } from "@/effect/instance-state"
import { optionalOmitUndefined } from "@opencode-ai/core/schema"
import { optional } from "@opencode-ai/core/schema"
import { Plugin } from "../plugin"
import { ProviderV2 } from "@opencode-ai/core/provider"
import { Array as Arr, Effect, Layer, Record, Result, Context, Schema } from "effect"
Expand All @@ -18,30 +18,30 @@ const TextPrompt = Schema.Struct({
type: Schema.Literal("text"),
key: Schema.String,
message: Schema.String,
placeholder: optionalOmitUndefined(Schema.String),
when: optionalOmitUndefined(When),
placeholder: optional(Schema.String),
when: optional(When),
})

const SelectOption = Schema.Struct({
label: Schema.String,
value: Schema.String,
hint: optionalOmitUndefined(Schema.String),
hint: optional(Schema.String),
})

const SelectPrompt = Schema.Struct({
type: Schema.Literal("select"),
key: Schema.String,
message: Schema.String,
options: Schema.Array(SelectOption),
when: optionalOmitUndefined(When),
when: optional(When),
})

const Prompt = Schema.Union([TextPrompt, SelectPrompt])

export class Method extends Schema.Class<Method>("ProviderAuthMethod")({
type: Schema.Literals(["oauth", "api"]),
label: Schema.String,
prompts: optionalOmitUndefined(Schema.Array(Prompt)),
prompts: optional(Schema.Array(Prompt)),
}) {}

export const Methods = Schema.Record(Schema.String, Schema.Array(Method))
Expand Down
Loading
Loading