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
32 changes: 26 additions & 6 deletions packages/opencode/src/account/effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { AccountRepo, type AccountRow } from "./repo"
import {
type AccountError,
AccessToken,
Account,
AccountID,
DeviceCode,
Info,
RefreshToken,
AccountServiceError,
Login,
Expand All @@ -24,10 +24,30 @@ import {
UserCode,
} from "./schema"

export * from "./schema"
export {
AccountID,
type AccountError,
AccountRepoError,
AccountServiceError,
AccessToken,
RefreshToken,
DeviceCode,
UserCode,
Info,
Org,
OrgID,
Login,
PollSuccess,
PollPending,
PollSlow,
PollExpired,
PollDenied,
PollError,
PollResult,
} from "./schema"

export type AccountOrgs = {
account: Account
account: Info
orgs: readonly Org[]
}

Expand Down Expand Up @@ -108,10 +128,10 @@ const mapAccountServiceError =
),
)

export namespace AccountEffect {
export namespace Account {
export interface Interface {
readonly active: () => Effect.Effect<Option.Option<Account>, AccountError>
readonly list: () => Effect.Effect<Account[], AccountError>
readonly active: () => Effect.Effect<Option.Option<Info>, AccountError>
readonly list: () => Effect.Effect<Info[], AccountError>
readonly orgsByAccount: () => Effect.Effect<readonly AccountOrgs[], AccountError>
readonly remove: (accountID: AccountID) => Effect.Effect<void, AccountError>
readonly use: (accountID: AccountID, orgID: Option.Option<OrgID>) => Effect.Effect<void, AccountError>
Expand Down
23 changes: 8 additions & 15 deletions packages/opencode/src/account/index.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,24 @@
import { Effect, Option } from "effect"

import {
Account as AccountSchema,
type AccountError,
type AccessToken,
AccountID,
AccountEffect,
OrgID,
} from "./effect"
import { Account as S, type AccountError, type AccessToken, AccountID, Info as Model, OrgID } from "./effect"

export { AccessToken, AccountID, OrgID } from "./effect"

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

function runSync<A>(f: (service: AccountEffect.Interface) => Effect.Effect<A, AccountError>) {
return runtime.runSync(AccountEffect.Service.use(f))
function runSync<A>(f: (service: S.Interface) => Effect.Effect<A, AccountError>) {
return runtime.runSync(S.Service.use(f))
}

function runPromise<A>(f: (service: AccountEffect.Interface) => Effect.Effect<A, AccountError>) {
return runtime.runPromise(AccountEffect.Service.use(f))
function runPromise<A>(f: (service: S.Interface) => Effect.Effect<A, AccountError>) {
return runtime.runPromise(S.Service.use(f))
}

export namespace Account {
export const Account = AccountSchema
export type Account = AccountSchema
export const Info = Model
export type Info = Model

export function active(): Account | undefined {
export function active(): Info | undefined {
return Option.getOrUndefined(runSync((service) => service.active()))
}

Expand Down
8 changes: 4 additions & 4 deletions packages/opencode/src/account/repo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Effect, Layer, Option, Schema, ServiceMap } from "effect"

import { Database } from "@/storage/db"
import { AccountStateTable, AccountTable } from "./account.sql"
import { AccessToken, Account, AccountID, AccountRepoError, OrgID, RefreshToken } from "./schema"
import { AccessToken, AccountID, AccountRepoError, Info, OrgID, RefreshToken } from "./schema"

export type AccountRow = (typeof AccountTable)["$inferSelect"]

Expand All @@ -13,8 +13,8 @@ const ACCOUNT_STATE_ID = 1

export namespace AccountRepo {
export interface Service {
readonly active: () => Effect.Effect<Option.Option<Account>, AccountRepoError>
readonly list: () => Effect.Effect<Account[], AccountRepoError>
readonly active: () => Effect.Effect<Option.Option<Info>, AccountRepoError>
readonly list: () => Effect.Effect<Info[], AccountRepoError>
readonly remove: (accountID: AccountID) => Effect.Effect<void, AccountRepoError>
readonly use: (accountID: AccountID, orgID: Option.Option<OrgID>) => Effect.Effect<void, AccountRepoError>
readonly getRow: (accountID: AccountID) => Effect.Effect<Option.Option<AccountRow>, AccountRepoError>
Expand All @@ -40,7 +40,7 @@ export class AccountRepo extends ServiceMap.Service<AccountRepo, AccountRepo.Ser
static readonly layer: Layer.Layer<AccountRepo> = Layer.effect(
AccountRepo,
Effect.gen(function* () {
const decode = Schema.decodeUnknownSync(Account)
const decode = Schema.decodeUnknownSync(Info)

const query = <A>(f: (db: DbClient) => A) =>
Effect.try({
Expand Down
2 changes: 1 addition & 1 deletion packages/opencode/src/account/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const UserCode = Schema.String.pipe(
)
export type UserCode = Schema.Schema.Type<typeof UserCode>

export class Account extends Schema.Class<Account>("Account")({
export class Info extends Schema.Class<Info>("Account")({
id: AccountID,
email: Schema.String,
url: Schema.String,
Expand Down
2 changes: 1 addition & 1 deletion packages/opencode/src/auth/effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const file = path.join(Global.Path.data, "auth.json")

const fail = (message: string) => (cause: unknown) => new AuthError({ message, cause })

export namespace AuthEffect {
export namespace Auth {
export interface Interface {
readonly get: (providerID: string) => Effect.Effect<Info | undefined, AuthError>
readonly all: () => Effect.Effect<Record<string, Info>, AuthError>
Expand Down
4 changes: 2 additions & 2 deletions packages/opencode/src/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import * as S from "./effect"

export { OAUTH_DUMMY_KEY } from "./effect"

function runPromise<A>(f: (service: S.AuthEffect.Interface) => Effect.Effect<A, S.AuthError>) {
return runtime.runPromise(S.AuthEffect.Service.use(f))
function runPromise<A>(f: (service: S.Auth.Interface) => Effect.Effect<A, S.AuthError>) {
return runtime.runPromise(S.Auth.Service.use(f))
}

export namespace Auth {
Expand Down
10 changes: 5 additions & 5 deletions packages/opencode/src/cli/cmd/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { cmd } from "./cmd"
import { Duration, Effect, Match, Option } from "effect"
import { UI } from "../ui"
import { runtime } from "@/effect/runtime"
import { AccountID, AccountEffect, OrgID, PollExpired, type PollResult } from "@/account/effect"
import { AccountID, Account, OrgID, PollExpired, type PollResult } from "@/account/effect"
import { type AccountError } from "@/account/schema"
import * as Prompt from "../effect/prompt"
import open from "open"
Expand All @@ -17,7 +17,7 @@ const isActiveOrgChoice = (
) => Option.isSome(active) && active.value.id === choice.accountID && active.value.active_org_id === choice.orgID

const loginEffect = Effect.fn("login")(function* (url: string) {
const service = yield* AccountEffect.Service
const service = yield* Account.Service

yield* Prompt.intro("Log in")
const login = yield* service.login(url)
Expand Down Expand Up @@ -58,7 +58,7 @@ const loginEffect = Effect.fn("login")(function* (url: string) {
})

const logoutEffect = Effect.fn("logout")(function* (email?: string) {
const service = yield* AccountEffect.Service
const service = yield* Account.Service
const accounts = yield* service.list()
if (accounts.length === 0) return yield* println("Not logged in")

Expand Down Expand Up @@ -98,7 +98,7 @@ interface OrgChoice {
}

const switchEffect = Effect.fn("switch")(function* () {
const service = yield* AccountEffect.Service
const service = yield* Account.Service

const groups = yield* service.orgsByAccount()
if (groups.length === 0) return yield* println("Not logged in")
Expand Down Expand Up @@ -129,7 +129,7 @@ const switchEffect = Effect.fn("switch")(function* () {
})

const orgsEffect = Effect.fn("orgs")(function* () {
const service = yield* AccountEffect.Service
const service = yield* Account.Service

const groups = yield* service.orgsByAccount()
if (groups.length === 0) return yield* println("No accounts found")
Expand Down
4 changes: 2 additions & 2 deletions packages/opencode/src/cli/cmd/upgrade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ export const UpgradeCommand = {
spinner.stop("Upgrade failed", 1)
if (err instanceof Installation.UpgradeFailedError) {
// necessary because choco only allows install/upgrade in elevated terminals
if (method === "choco" && err.data.stderr.includes("not running from an elevated command shell")) {
if (method === "choco" && err.stderr.includes("not running from an elevated command shell")) {
prompts.log.error("Please run the terminal as Administrator and try again")
} else {
prompts.log.error(err.data.stderr)
prompts.log.error(err.stderr)
}
} else if (err instanceof Error) prompts.log.error(err.message)
prompts.outro("Done")
Expand Down
14 changes: 8 additions & 6 deletions packages/opencode/src/effect/runtime.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { Effect, Layer, ManagedRuntime } from "effect"
import { AccountEffect } from "@/account/effect"
import { AuthEffect } from "@/auth/effect"
import { Account } from "@/account/effect"
import { Auth } from "@/auth/effect"
import { Instances } from "@/effect/instances"
import type { InstanceServices } from "@/effect/instances"
import { TruncateEffect } from "@/tool/truncate-effect"
import { Installation } from "@/installation"
import { Truncate } from "@/tool/truncate-effect"
import { Instance } from "@/project/instance"

export const runtime = ManagedRuntime.make(
Layer.mergeAll(
AccountEffect.defaultLayer, //
TruncateEffect.defaultLayer,
Account.defaultLayer, //
Installation.defaultLayer,
Truncate.defaultLayer,
Instances.layer,
).pipe(Layer.provideMerge(AuthEffect.layer)),
).pipe(Layer.provideMerge(Auth.layer)),
)

export function runPromiseInstance<A, E>(effect: Effect.Effect<A, E, InstanceServices>) {
Expand Down
Loading
Loading