refactor(core): remove util log initialization

This commit is contained in:
opencode-agent[bot] 2026-06-05 14:30:25 +00:00
commit 8123247d7a
127 changed files with 356 additions and 714 deletions

View file

@ -1,36 +1,94 @@
import { Cause, Effect, Logger, References } from "effect"
import * as Log from "../util/log"
import { appendFileSync } from "fs"
import fs from "fs/promises"
import path from "path"
import { Cause, Effect, Layer, Logger, References, Schema } from "effect"
import * as Global from "../global"
import { ensureProcessMetadata } from "../util/opencode-process"
type Fields = Record<string, unknown>
type FieldInput = object
export const Level = Schema.Literals(["DEBUG", "INFO", "WARN", "ERROR"]).annotate({
identifier: "LogLevel",
description: "Log level",
})
export type Level = Schema.Schema.Type<typeof Level>
const levelPriority: Record<Level, number> = {
DEBUG: 0,
INFO: 1,
WARN: 2,
ERROR: 3,
}
const normalizeKey = (key: string) => (key === "sessionID" ? "session.id" : key)
export interface Handle {
readonly debug: (msg?: unknown, extra?: Fields) => Effect.Effect<void>
readonly info: (msg?: unknown, extra?: Fields) => Effect.Effect<void>
readonly warn: (msg?: unknown, extra?: Fields) => Effect.Effect<void>
readonly error: (msg?: unknown, extra?: Fields) => Effect.Effect<void>
readonly with: (extra: Fields) => Handle
readonly debug: (msg?: unknown, extra?: FieldInput) => Effect.Effect<void>
readonly info: (msg?: unknown, extra?: FieldInput) => Effect.Effect<void>
readonly warn: (msg?: unknown, extra?: FieldInput) => Effect.Effect<void>
readonly error: (msg?: unknown, extra?: FieldInput) => Effect.Effect<void>
readonly tag: (key: string, value: string) => Handle
readonly with: (extra: FieldInput) => Handle
readonly clone: () => Handle
readonly time: (message: string, extra?: Fields) => { stop(): void; [Symbol.dispose](): void }
}
const clean = (input?: Fields): Fields =>
const clean = (input?: FieldInput): Fields =>
Object.fromEntries(
Object.entries(input ?? {})
.filter((entry) => entry[1] !== undefined && entry[1] !== null)
.map(([key, value]) => [normalizeKey(key), value]),
)
const text = (input: unknown): string => {
// oxlint-disable-next-line no-base-to-string
if (Array.isArray(input)) return input.map((item) => String(item)).join(" ")
// oxlint-disable-next-line no-base-to-string
return input === undefined ? "" : String(input)
const call = (run: (msg: string) => Effect.Effect<void>, base: FieldInput, msg?: unknown, extra?: FieldInput) => {
const ann = clean({ ...base, ...extra })
const fx = run(stringifyMessage(msg))
return Object.keys(ann).length ? Effect.annotateLogs(fx, ann) : fx
}
const call = (run: (msg?: unknown) => Effect.Effect<void>, base: Fields, msg?: unknown, extra?: Fields) => {
const ann = clean({ ...base, ...extra })
const fx = run(msg)
return Object.keys(ann).length ? Effect.annotateLogs(fx, ann) : fx
export function file() {
if (disabled(process.env.OPENCODE_LOG_FILE)) return ""
return process.env.OPENCODE_LOG_FILE || path.join(Global.Path.log, "log.jsonl")
}
function shouldLog(input: Level): boolean {
return levelPriority[input] >= levelPriority[parseLevel(process.env.OPENCODE_LOG_LEVEL) ?? "INFO"]
}
function write(input: { json: string; pretty: string }) {
const target = file()
if (target) {
try {
appendFileSync(target, input.json)
} catch {}
}
if (truthy(process.env.OPENCODE_PRINT_LOGS)) process.stderr.write(input.pretty)
}
function build(inputLevel: Level, ts: Date, message: unknown, fields: Fields): { json: string; pretty: string } {
const metadata = ensureProcessMetadata("main")
const service = typeof fields.service === "string" ? fields.service : undefined
if (service) delete fields.service
const text = stringifyMessage(message)
const record = {
ts: ts.toISOString(),
level: inputLevel,
message: text,
run_id: metadata.runID,
process_role: metadata.processRole,
pid: process.pid,
service,
fields: Object.fromEntries(Object.entries(fields).map(([key, value]) => [key, normalize(value)])),
}
const prefix = Object.entries({ service, ...record.fields })
.filter((entry) => entry[1] !== undefined && entry[1] !== null)
.map(([key, value]) => `${key}=${typeof value === "object" ? safeStringify(value) : value}`)
.join(" ")
return {
json: safeStringify(record) + "\n",
pretty: [inputLevel.padEnd(5), ts.toISOString().split(".")[0], prefix, text].filter(Boolean).join(" ") + "\n",
}
}
export const logger = Logger.make((opts) => {
@ -43,31 +101,97 @@ export const logger = Logger.make((opts) => {
extra.cause = Cause.pretty(opts.cause)
}
const svc = typeof extra.service === "string" ? extra.service : undefined
if (svc) delete extra.service
const log = svc ? Log.create({ service: svc }) : Log.Default
const msg = text(opts.message)
switch (opts.logLevel) {
case "Trace":
case "Debug":
return log.debug(msg, extra)
if (shouldLog("DEBUG")) write(build("DEBUG", opts.date, opts.message, extra))
return
case "Warn":
return log.warn(msg, extra)
if (shouldLog("WARN")) write(build("WARN", opts.date, opts.message, extra))
return
case "Error":
case "Fatal":
return log.error(msg, extra)
if (shouldLog("ERROR")) write(build("ERROR", opts.date, opts.message, extra))
return
default:
return log.info(msg, extra)
if (shouldLog("INFO")) write(build("INFO", opts.date, opts.message, extra))
}
})
export const layer = Logger.layer([logger], { mergeWithExisting: false })
export const layer = Logger.layer([logger], { mergeWithExisting: false }).pipe(
Layer.tap(() =>
Effect.promise(async () => {
const target = file()
if (target) await fs.mkdir(path.dirname(target), { recursive: true })
}),
),
)
export const create = (base: Fields = {}): Handle => ({
export const create = (base: FieldInput = {}): Handle => ({
debug: (msg, extra) => call((item) => Effect.logDebug(item), base, msg, extra),
info: (msg, extra) => call((item) => Effect.logInfo(item), base, msg, extra),
warn: (msg, extra) => call((item) => Effect.logWarning(item), base, msg, extra),
error: (msg, extra) => call((item) => Effect.logError(item), base, msg, extra),
tag: (key, value) => create({ ...base, [key]: value }),
with: (extra) => create({ ...base, ...extra }),
clone: () => create({ ...base }),
time: () => ({
stop() {},
[Symbol.dispose]() {},
}),
})
function truthy(value: string | undefined) {
return value?.toLowerCase() === "1" || value?.toLowerCase() === "true"
}
function disabled(value: string | undefined) {
const lower = value?.toLowerCase()
return lower === "0" || lower === "false" || lower === "off"
}
function parseLevel(value: string | undefined): Level | undefined {
if (value === "DEBUG" || value === "INFO" || value === "WARN" || value === "ERROR") return value
return undefined
}
function formatError(error: Error, depth = 0): string {
const result = error.message
return error.cause instanceof Error && depth < 10
? result + " Caused by: " + formatError(error.cause, depth + 1)
: result
}
function stringifyMessage(message: unknown): string {
if (message instanceof Error) return formatError(message)
if (message === undefined) return ""
if (typeof message === "string") return message
if (Array.isArray(message)) return message.map((item) => stringifyMessage(item)).join(" ")
if (typeof message === "object") return safeStringify(message)
return String(message)
}
function normalize(value: unknown): unknown {
if (value instanceof Error) {
return {
name: value.name,
message: formatError(value),
stack: value.stack,
}
}
if (typeof value === "bigint") return value.toString()
return value
}
function safeStringify(value: unknown) {
const seen = new WeakSet<object>()
return JSON.stringify(value, (_, item) => {
if (typeof item === "bigint") return item.toString()
if (item instanceof Error) return normalize(item)
if (typeof item === "object" && item !== null) {
if (seen.has(item)) return "[Circular]"
seen.add(item)
}
return item
})
}

View file

@ -1,241 +0,0 @@
export * as Log from "./log"
import path from "path"
import fs from "fs/promises"
import { appendFileSync } from "fs"
import * as Global from "../global"
import { Schema } from "effect"
import { ensureProcessMetadata } from "./opencode-process"
export const Level = Schema.Literals(["DEBUG", "INFO", "WARN", "ERROR"]).annotate({
identifier: "LogLevel",
description: "Log level",
})
export type Level = Schema.Schema.Type<typeof Level>
const levelPriority: Record<Level, number> = {
DEBUG: 0,
INFO: 1,
WARN: 2,
ERROR: 3,
}
let level: Level = "INFO"
function shouldLog(input: Level): boolean {
return levelPriority[input] >= levelPriority[level]
}
export type Logger = {
debug(message?: any, extra?: Record<string, any>): void
info(message?: any, extra?: Record<string, any>): void
error(message?: any, extra?: Record<string, any>): void
warn(message?: any, extra?: Record<string, any>): void
tag(key: string, value: string): Logger
clone(): Logger
time(
message: string,
extra?: Record<string, any>,
): {
stop(): void
[Symbol.dispose](): void
}
}
const loggers = new Map<string, Logger>()
export const Default = create({ service: "default" })
export interface Options {
print?: boolean
dev?: boolean
level?: Level
file?: string | false
}
let logpath = ""
export function file() {
return logpath
}
type LogEntry = {
json: string
pretty: string
}
let write = (entry: LogEntry) => {
process.stderr.write(entry.pretty)
}
export async function init(options: Options) {
level = options.level ?? parseLevel(process.env.OPENCODE_LOG_LEVEL) ?? level
const print = options.print ?? truthy(process.env.OPENCODE_PRINT_LOGS)
const configured = options.file ?? process.env.OPENCODE_LOG_FILE
logpath = configured === false || disabled(configured) ? "" : configured || path.join(Global.Path.log, "log.jsonl")
if (logpath) await fs.mkdir(path.dirname(logpath), { recursive: true })
write = (entry) => {
if (logpath) {
try {
appendFileSync(logpath, entry.json)
} catch {}
}
if (print) process.stderr.write(entry.pretty)
}
}
function formatError(error: Error, depth = 0): string {
const result = error.message
return error.cause instanceof Error && depth < 10
? result + " Caused by: " + formatError(error.cause, depth + 1)
: result
}
let last = Date.now()
export function create(tags?: Record<string, any>) {
tags = tags || {}
const service = tags["service"]
if (service && typeof service === "string") {
const cached = loggers.get(service)
if (cached) {
return cached
}
}
function build(inputLevel: Level, message: any, extra?: Record<string, any>): LogEntry {
const ts = new Date()
const metadata = ensureProcessMetadata("main")
const fields = Object.fromEntries(
Object.entries({
...tags,
...extra,
})
.filter((entry) => entry[1] !== undefined && entry[1] !== null)
.map(([key, value]) => [key, normalize(value)]),
)
const service = typeof fields.service === "string" ? fields.service : undefined
if (service) delete fields.service
const text = stringifyMessage(message)
const record = {
ts: ts.toISOString(),
level: inputLevel,
message: text,
run_id: metadata.runID,
process_role: metadata.processRole,
pid: process.pid,
service,
fields,
}
const diff = ts.getTime() - last
last = ts.getTime()
const prefix = Object.entries({ service, ...fields })
.filter((entry) => entry[1] !== undefined && entry[1] !== null)
.map(([key, value]) => `${key}=${typeof value === "object" ? safeStringify(value) : value}`)
.join(" ")
return {
json: safeStringify(record) + "\n",
pretty:
[inputLevel.padEnd(5), ts.toISOString().split(".")[0], "+" + diff + "ms", prefix, text]
.filter(Boolean)
.join(" ") + "\n",
}
}
const result: Logger = {
debug(message?: any, extra?: Record<string, any>) {
if (shouldLog("DEBUG")) {
write(build("DEBUG", message, extra))
}
},
info(message?: any, extra?: Record<string, any>) {
if (shouldLog("INFO")) {
write(build("INFO", message, extra))
}
},
error(message?: any, extra?: Record<string, any>) {
if (shouldLog("ERROR")) {
write(build("ERROR", message, extra))
}
},
warn(message?: any, extra?: Record<string, any>) {
if (shouldLog("WARN")) {
write(build("WARN", message, extra))
}
},
tag(key: string, value: string) {
if (tags) tags[key] = value
return result
},
clone() {
return create({ ...tags })
},
time(message: string, extra?: Record<string, any>) {
const now = Date.now()
result.info(message, { status: "started", ...extra })
function stop() {
result.info(message, {
status: "completed",
duration: Date.now() - now,
...extra,
})
}
return {
stop,
[Symbol.dispose]() {
stop()
},
}
},
}
if (service && typeof service === "string") {
loggers.set(service, result)
}
return result
}
function truthy(value: string | undefined) {
return value?.toLowerCase() === "1" || value?.toLowerCase() === "true"
}
function disabled(value: string | undefined) {
const lower = value?.toLowerCase()
return lower === "0" || lower === "false" || lower === "off"
}
function parseLevel(value: string | undefined): Level | undefined {
if (value === "DEBUG" || value === "INFO" || value === "WARN" || value === "ERROR") return value
return undefined
}
function stringifyMessage(message: any): string {
if (message instanceof Error) return formatError(message)
if (message === undefined) return ""
if (typeof message === "string") return message
if (typeof message === "object") return safeStringify(message)
return String(message)
}
function normalize(value: any): any {
if (value instanceof Error) {
return {
name: value.name,
message: formatError(value),
stack: value.stack,
}
}
if (typeof value === "bigint") return value.toString()
return value
}
function safeStringify(value: any) {
const seen = new WeakSet<object>()
return JSON.stringify(value, (_, item) => {
if (typeof item === "bigint") return item.toString()
if (item instanceof Error) return normalize(item)
if (typeof item === "object" && item !== null) {
if (seen.has(item)) return "[Circular]"
seen.add(item)
}
return item
})
}

View file

@ -15,9 +15,6 @@ declare module "virtual:opencode-server" {
export const get: typeof import("../../../opencode/dist/types/src/node").Config.get
export type Info = import("../../../opencode/dist/types/src/node").Config.Info
}
export namespace Log {
export const init: typeof import("../../../opencode/dist/types/src/node").Log.init
}
export namespace Database {
export const getPath: typeof import("../../../opencode/dist/types/src/node").Database.getPath
export const Client: typeof import("../../../opencode/dist/types/src/node").Database.Client

View file

@ -57,8 +57,8 @@ async function start(command: StartCommand) {
ensureLoopbackNoProxy()
useSystemCertificates()
useEnvProxy()
const { Database, JsonMigration, Log, Server } = await import("virtual:opencode-server")
await Log.init({ level: "WARN" })
process.env.OPENCODE_LOG_LEVEL = "WARN"
const { Database, JsonMigration, Server } = await import("virtual:opencode-server")
if (command.needsMigration) {
await JsonMigration.run(drizzle({ client: Database.Client().$client }), {

View file

@ -1,5 +1,5 @@
import type { AgentSideConnection } from "@agentclientprotocol/sdk"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import type {
Event,
EventMessagePartDelta,
@ -20,7 +20,7 @@ import {
completedToolUpdate,
} from "./tool"
const log = Log.create({ service: "acp-next-event" })
const log = EffectLogger.create({ service: "acp-next-event" })
type Connection = Pick<AgentSideConnection, "sessionUpdate">
type GlobalEventEnvelope = {

View file

@ -30,7 +30,7 @@ import {
type SetSessionModeResponse,
} from "@agentclientprotocol/sdk"
import { InstallationVersion } from "@opencode-ai/core/installation/version"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import type { Message, OpencodeClient, SessionMessageResponse } from "@opencode-ai/sdk/v2"
import { Context, Effect, Layer, ManagedRuntime } from "effect"
import * as ACPNextError from "./error"
@ -43,7 +43,7 @@ import { Provider } from "@/provider/provider"
import type { Command } from "@/command"
export const AuthMethodID = "opencode-login"
const log = Log.create({ service: "acp-next-service" })
const log = EffectLogger.create({ service: "acp-next-service" })
export type Error = ACPNextError.Error

View file

@ -1,5 +1,5 @@
import type { AgentSideConnection, Usage } from "@agentclientprotocol/sdk"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import type { AssistantMessage as OpenCodeAssistantMessage, Message } from "@opencode-ai/sdk/v2"
import { InstanceRef } from "@/effect/instance-ref"
import { InstanceStore } from "@/project/instance-store"
@ -7,7 +7,7 @@ import { ModelID, ProviderID } from "@/provider/schema"
import { Provider } from "@/provider/provider"
import { Context, Effect, Layer, SynchronizedRef } from "effect"
const log = Log.create({ service: "acp-next-usage" })
const log = EffectLogger.create({ service: "acp-next-usage" })
export type AssistantTokenCost = Pick<OpenCodeAssistantMessage, "cost" | "tokens">

View file

@ -33,7 +33,7 @@ import {
type Usage,
} from "@agentclientprotocol/sdk"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { pathToFileURL } from "url"
import { Filesystem } from "@/util/filesystem"
import { Hash } from "@opencode-ai/core/util/hash"
@ -58,7 +58,7 @@ const decodeTodos = Schema.decodeUnknownResult(Schema.fromJsonString(Schema.Arra
const DEFAULT_VARIANT_VALUE = "default"
const log = Log.create({ service: "acp-agent" })
const log = EffectLogger.create({ service: "acp-agent" })
async function getContextLimit(
sdk: OpencodeClient,

View file

@ -1,9 +1,9 @@
import { RequestError, type McpServer } from "@agentclientprotocol/sdk"
import type { ACPSessionState } from "./types"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import type { OpencodeClient } from "@opencode-ai/sdk/v2"
const log = Log.create({ service: "acp-session-manager" })
const log = EffectLogger.create({ service: "acp-session-manager" })
export class ACPSessionManager {
private sessions = new Map<string, ACPSessionState>()

View file

@ -1,6 +1,6 @@
import { Effect, Exit, Layer, PubSub, Scope, Context, Stream, Schema } from "effect"
import { EffectBridge } from "@/effect/bridge"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { BusEvent } from "./bus-event"
import { GlobalBus } from "./global"
import { InstanceState } from "@/effect/instance-state"
@ -10,7 +10,7 @@ import { Identifier } from "@/id/id"
import type { InstanceContext } from "@/project/instance-context"
import { InstanceRef } from "@/effect/instance-ref"
const log = Log.create({ service: "bus" })
const log = EffectLogger.create({ service: "bus" })
type BusProperties<D extends BusEvent.Definition<string, Schema.Top>> = Schema.Schema.Type<D["properties"]>

View file

@ -1,4 +1,4 @@
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Effect } from "effect"
import { effectCmd } from "../effect-cmd"
import { AgentSideConnection, ndJsonStream } from "@agentclientprotocol/sdk"
@ -10,7 +10,7 @@ import { createOpencodeClient } from "@opencode-ai/sdk/v2"
import { withNetworkOptions, resolveNetworkOptions } from "../network"
import { RuntimeFlags } from "@/effect/runtime-flags"
const log = Log.create({ service: "acp-command" })
const log = EffectLogger.create({ service: "acp-command" })
export const AcpCommand = effectCmd({
command: "acp",

View file

@ -2,7 +2,6 @@ import { LSP } from "@/lsp/lsp"
import { Effect } from "effect"
import { effectCmd } from "../../effect-cmd"
import { cmd } from "../cmd"
import * as Log from "@opencode-ai/core/util/log"
import { EOL } from "os"
export const LSPCommand = cmd({
@ -33,7 +32,6 @@ export const SymbolsCommand = effectCmd({
describe: "search workspace symbols",
builder: (yargs) => yargs.positional("query", { type: "string", demandOption: true }),
handler: Effect.fn("Cli.debug.lsp.symbols")(function* (args) {
using _ = Log.Default.time("symbols")
const results = yield* LSP.Service.use((lsp) => lsp.workspaceSymbol(args.query))
process.stdout.write(JSON.stringify(results, null, 2) + EOL)
}),
@ -44,7 +42,6 @@ export const DocumentSymbolsCommand = effectCmd({
describe: "get symbols from a document",
builder: (yargs) => yargs.positional("uri", { type: "string", demandOption: true }),
handler: Effect.fn("Cli.debug.lsp.documentSymbols")(function* (args) {
using _ = Log.Default.time("document-symbols")
const results = yield* LSP.Service.use((lsp) => lsp.documentSymbol(args.uri))
process.stdout.write(JSON.stringify(results, null, 2) + EOL)
}),

View file

@ -1,6 +1,5 @@
import { EOL } from "os"
import { Project } from "@/project/project"
import * as Log from "@opencode-ai/core/util/log"
import { cmd } from "../cmd"
export const ScrapCommand = cmd({
@ -8,9 +7,7 @@ export const ScrapCommand = cmd({
describe: "list all known projects",
builder: (yargs) => yargs,
async handler() {
const timer = Log.Default.time("scrap")
const list = await Project.list()
process.stdout.write(JSON.stringify(list, null, 2) + EOL)
timer.stop()
},
})

View file

@ -19,7 +19,7 @@ import permissionSoundPath from "@opencode-ai/ui/audio/staplebops-06.mp3" with {
import errorSoundPath from "@opencode-ai/ui/audio/nope-03.mp3" with { type: "file" }
import doneSoundPath from "@opencode-ai/ui/audio/bip-bop-01.mp3" with { type: "file" }
import subagentDoneSoundPath from "@opencode-ai/ui/audio/yup-01.mp3" with { type: "file" }
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
type FocusState = "unknown" | "focused" | "blurred"
@ -38,7 +38,7 @@ type TuiAttentionHost = TuiAttention & {
dispose(): void
}
const log = Log.create({ service: "tui.attention" })
const log = EffectLogger.create({ service: "tui.attention" })
const DEFAULT_TITLE = "opencode"
const DEFAULT_PACK_ID = "opencode.default"

View file

@ -6,10 +6,10 @@ import { DiffStyle, ScrollAcceleration, ScrollSpeed } from "./tui-schema"
import { Flag } from "@opencode-ai/core/flag/flag"
import { Global } from "@opencode-ai/core/global"
import { Filesystem } from "@/util/filesystem"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import * as ConfigPaths from "@/config/paths"
const log = Log.create({ service: "tui.migrate" })
const log = EffectLogger.create({ service: "tui.migrate" })
const TUI_SCHEMA_URL = "https://opencode.ai/tui.json"

View file

@ -18,14 +18,14 @@ import { TuiKeybind } from "./keybind"
import { InstallationLocal, InstallationVersion } from "@opencode-ai/core/installation/version"
import { makeRuntime } from "@opencode-ai/core/effect/runtime"
import { Filesystem } from "@/util/filesystem"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { ConfigVariable } from "@/config/variable"
import { Npm } from "@opencode-ai/core/npm"
import type { DeepMutable } from "@opencode-ai/core/schema"
import type { TuiAttentionSoundName } from "@opencode-ai/plugin/tui"
import { FormatError, FormatUnknownError } from "@/cli/error"
const log = Log.create({ service: "tui.config" })
const log = EffectLogger.create({ service: "tui.config" })
export const Info = TuiInfo
export type Info = DeepMutable<Schema.Schema.Type<typeof Info>>

View file

@ -28,7 +28,6 @@ import type { Snapshot } from "@/snapshot"
import { useExit } from "./exit"
import { useArgs } from "./args"
import { batch, onMount } from "solid-js"
import * as Log from "@opencode-ai/core/util/log"
import { emptyConsoleState, type ConsoleState } from "@/config/console-state"
import path from "path"
import { useKV } from "./kv"
@ -465,11 +464,6 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
})
})
.catch(async (e) => {
Log.Default.error("tui bootstrap failed", {
error: e instanceof Error ? e.message : String(e),
name: e instanceof Error ? e.name : undefined,
stack: e instanceof Error ? e.stack : undefined,
})
if (fatal) {
await exit(e)
} else {

View file

@ -14,7 +14,7 @@ import {
import path from "path"
import { fileURLToPath } from "url"
import { TuiConfig } from "@/cli/cmd/tui/config/tui"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { errorData, errorMessage } from "@/util/error"
import { isRecord } from "@/util/record"
import { resolveAttentionSoundPaths } from "../config/tui-schema"
@ -117,7 +117,7 @@ type RuntimeState = {
dispose_timeout_ms: number
}
const log = Log.create({ service: "tui.plugin" })
const log = EffectLogger.create({ service: "tui.plugin" })
const DISPOSE_TIMEOUT_MS = 5000
const KV_KEY = "plugin_enabled"
const EMPTY_TUI: TuiPluginModule = {

View file

@ -4,7 +4,6 @@ import { type rpc } from "./worker"
import path from "path"
import { fileURLToPath } from "url"
import { UI } from "@/cli/ui"
import * as Log from "@opencode-ai/core/util/log"
import { errorMessage } from "@/util/error"
import { withTimeout } from "@/util/timeout"
import { withNetworkOptions, resolveNetworkOptionsNoConfig } from "@/cli/network"
@ -146,26 +145,12 @@ export const TuiThreadCommand = cmd({
const worker = new Worker(file, {
env,
})
worker.onerror = (e) => {
Log.Default.error("thread error", {
message: e.message,
filename: e.filename,
lineno: e.lineno,
colno: e.colno,
error: e.error,
})
}
worker.onerror = () => {}
const client = Rpc.client<typeof rpc>(worker)
const error = (e: unknown) => {
Log.Default.error("process error", { error: errorMessage(e) })
}
const error = () => {}
const reload = () => {
client.call("reload", undefined).catch((err) => {
Log.Default.warn("worker reload failed", {
error: errorMessage(err),
})
})
client.call("reload", undefined).catch(() => {})
}
process.on("uncaughtException", error)
process.on("unhandledRejection", error)
@ -178,11 +163,7 @@ export const TuiThreadCommand = cmd({
process.off("uncaughtException", error)
process.off("unhandledRejection", error)
process.off("SIGUSR2", reload)
await withTimeout(client.call("shutdown", undefined), 5000).catch((error) => {
Log.Default.warn("worker shutdown failed", {
error: errorMessage(error),
})
})
await withTimeout(client.call("shutdown", undefined), 5000).catch(() => {})
worker.terminate()
}

View file

@ -1,7 +1,7 @@
import { Audio, type AudioErrorContext, type AudioPlayOptions, type AudioSound, type AudioVoice } from "@opentui/core"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
const log = Log.create({ service: "tui.audio" })
const log = EffectLogger.create({ service: "tui.audio" })
let audio: Audio | null | undefined
const sounds = new Map<string, Promise<AudioSound | null>>()

View file

@ -1,6 +1,5 @@
import { Installation } from "@/installation"
import { Server } from "@/server/server"
import * as Log from "@opencode-ai/core/util/log"
import { InstanceRuntime } from "@/project/instance-runtime"
import { Rpc } from "@/util/rpc"
import { upgrade } from "@/cli/upgrade"
@ -15,30 +14,10 @@ import { Effect } from "effect"
import { disposeAllInstancesAndEmitGlobalDisposed } from "@/server/global-lifecycle"
ensureProcessMetadata("worker")
await Log.init({
print: process.argv.includes("--print-logs"),
dev: Installation.isLocal(),
level: (() => {
if (Installation.isLocal()) return "DEBUG"
return "INFO"
})(),
})
if (!process.env.OPENCODE_LOG_LEVEL) process.env.OPENCODE_LOG_LEVEL = Installation.isLocal() ? "DEBUG" : "INFO"
Heap.start()
process.on("unhandledRejection", (e) => {
Log.Default.error("rejection", {
e: e instanceof Error ? e.message : e,
})
})
process.on("uncaughtException", (e) => {
Log.Default.error("exception", {
e: e instanceof Error ? e.message : e,
})
})
// Subscribe to global events and forward them via RPC
GlobalBus.on("event", (event) => {
Rpc.emit("global.event", event)
@ -89,8 +68,6 @@ export const rpc = {
)
},
async shutdown() {
Log.Default.info("worker shutting down")
await InstanceRuntime.disposeAllInstances()
if (server) await server.stop(true)
},

View file

@ -2,9 +2,9 @@ import path from "path"
import { writeHeapSnapshot } from "node:v8"
import { Flag } from "@opencode-ai/core/flag/flag"
import { Global } from "@opencode-ai/core/global"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
const log = Log.create({ service: "heap" })
const log = EffectLogger.create({ service: "heap" })
const MINUTE = 60_000
const LIMIT = 2 * 1024 * 1024 * 1024

View file

@ -3,7 +3,7 @@ export * as ConfigAgent from "./agent"
import path from "path"
import { Exit, Schema, SchemaGetter } from "effect"
import { PositiveInt } from "@opencode-ai/core/schema"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Glob } from "@opencode-ai/core/util/glob"
import { configEntryNameFromPath } from "./entry-name"
import * as ConfigMarkdown from "./markdown"
@ -11,7 +11,7 @@ import { ConfigModelID } from "./model-id"
import { ConfigParse } from "./parse"
import { ConfigPermission } from "./permission"
const log = Log.create({ service: "config" })
const log = EffectLogger.create({ service: "config" })
const Color = Schema.Union([
Schema.String.check(Schema.isPattern(/^#[0-9a-fA-F]{6}$/)),

View file

@ -1,7 +1,7 @@
export * as ConfigCommand from "./command"
import path from "path"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Cause, Exit, Schema } from "effect"
import { Glob } from "@opencode-ai/core/util/glob"
import { configEntryNameFromPath } from "./entry-name"
@ -9,7 +9,7 @@ import { InvalidError } from "./error"
import * as ConfigMarkdown from "./markdown"
import { ConfigModelID } from "./model-id"
const log = Log.create({ service: "config" })
const log = EffectLogger.create({ service: "config" })
export const Info = Schema.Struct({
template: Schema.String,

View file

@ -1,4 +1,4 @@
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { serviceUse } from "@opencode-ai/core/effect/service-use"
import path from "path"
import { pathToFileURL } from "url"
@ -44,7 +44,7 @@ import { ConfigVariable } from "./variable"
import { Npm } from "@opencode-ai/core/npm"
import { withTransientReadRetry } from "@/util/effect-http-client"
const log = Log.create({ service: "config" })
const log = EffectLogger.create({ service: "config" })
// Custom merge function that concatenates array fields instead of replacing them
// Keep remeda's deep conditional merge type out of hot config-loading paths; TS profiling showed it dominates here.

View file

@ -3,10 +3,10 @@ export * as ConfigManaged from "./managed"
import { existsSync } from "fs"
import os from "os"
import path from "path"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Process } from "@/util/process"
const log = Log.create({ service: "config" })
const log = EffectLogger.create({ service: "config" })
const MANAGED_PLIST_DOMAIN = "ai.opencode.managed"

View file

@ -12,7 +12,7 @@ import { Auth } from "@/auth"
import { SyncEvent } from "@/sync"
import { EventSequenceTable, EventTable } from "@/sync/event.sql"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { RuntimeFlags } from "@/effect/runtime-flags"
import { ProjectID } from "@/project/schema"
import { Slug } from "@opencode-ai/core/util/slug"
@ -77,7 +77,7 @@ function fromRow(row: typeof WorkspaceTable.$inferSelect): Info {
const db = <T>(fn: (d: Parameters<typeof Database.use>[0] extends (trx: infer D) => any ? D : never) => T) =>
Effect.sync(() => Database.use(fn))
const log = Log.create({ service: "workspace-sync" })
const log = EffectLogger.create({ service: "workspace-sync" })
export const CreateInput = Schema.Struct({
id: Schema.optional(WorkspaceID),

View file

@ -1,7 +1,7 @@
import { Context, Effect, Layer } from "effect"
import { Database } from "./storage/db"
import { DataMigrationTable } from "./data-migration.sql"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { and, asc, eq, gt, inArray, sql } from "drizzle-orm"
import { MessageTable, SessionTable } from "./session/session.sql"
import type { SessionID } from "./session/schema"
@ -11,7 +11,7 @@ export type Migration<R = never> = {
run: Effect.Effect<void, unknown, R>
}
const log = Log.create({ service: "data-migration" })
const log = EffectLogger.create({ service: "data-migration" })
export interface Interface {}

View file

@ -12,7 +12,7 @@ import ignore from "ignore"
import path from "path"
import { Global } from "@opencode-ai/core/global"
import { containsPath } from "../project/instance-context"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Protected } from "./protected"
import { Ripgrep } from "./ripgrep"
import { NonNegativeInt, type DeepMutable } from "@opencode-ai/core/schema"
@ -70,7 +70,7 @@ export const Event = {
),
}
const log = Log.create({ service: "file" })
const log = EffectLogger.create({ service: "file" })
const binary = new Set([
"exe",

View file

@ -9,12 +9,12 @@ import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import { Global } from "@opencode-ai/core/global"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { sanitizedProcessEnv } from "@opencode-ai/core/util/opencode-process"
import { which } from "@/util/which"
import { NonNegativeInt } from "@opencode-ai/core/schema"
const log = Log.create({ service: "ripgrep" })
const log = EffectLogger.create({ service: "ripgrep" })
const VERSION = "15.1.0"
const PLATFORM = {
"arm64-darwin": { platform: "aarch64-apple-darwin", extension: "tar.gz" },

View file

@ -14,11 +14,11 @@ import { lazy } from "@/util/lazy"
import { Config } from "@/config/config"
import { FileIgnore } from "./ignore"
import { Protected } from "./protected"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
declare const OPENCODE_LIBC: string | undefined
const log = Log.create({ service: "file.watcher" })
const log = EffectLogger.create({ service: "file.watcher" })
const SUBSCRIBE_TIMEOUT_MS = 10_000
export const Event = {

View file

@ -8,10 +8,10 @@ import { mergeDeep } from "remeda"
import { Config } from "@/config/config"
import { RuntimeFlags } from "@/effect/runtime-flags"
import { errorMessage } from "@/util/error"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import * as Formatter from "./formatter"
const log = Log.create({ service: "format" })
const log = EffectLogger.create({ service: "format" })
export const Status = Schema.Struct({
name: Schema.String,

View file

@ -1,7 +1,7 @@
import { BusEvent } from "@/bus/bus-event"
import { Schema } from "effect"
import { NamedError } from "@opencode-ai/core/util/error"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Process } from "@/util/process"
const SUPPORTED_IDES = [
@ -12,7 +12,7 @@ const SUPPORTED_IDES = [
{ name: "VSCodium" as const, cmd: "codium" },
]
const log = Log.create({ service: "ide" })
const log = EffectLogger.create({ service: "ide" })
export const Event = {
Installed: BusEvent.define(

View file

@ -1,6 +1,6 @@
import { Config } from "@/config/config"
import type { MessageV2 } from "@/session/message-v2"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import photonWasm from "@silvia-odwyer/photon-node/photon_rs_bg.wasm" with { type: "file" }
import { Context, Effect, Layer, Schema } from "effect"
import path from "node:path"
@ -11,7 +11,7 @@ const MAX_WIDTH = 2000
const MAX_HEIGHT = 2000
const AUTO_RESIZE = true
const JPEG_QUALITIES = [80, 85, 70, 55, 40]
const log = Log.create({ service: "image" })
const log = EffectLogger.create({ service: "image" })
export class ResizerUnavailableError extends Schema.TaggedErrorClass<ResizerUnavailableError>()(
"ImageResizerUnavailableError",

View file

@ -2,7 +2,6 @@ import yargs from "yargs"
import { hideBin } from "yargs/helpers"
import { RunCommand } from "./cli/cmd/run"
import { GenerateCommand } from "./cli/cmd/generate"
import * as Log from "@opencode-ai/core/util/log"
import { ConsoleCommand } from "./cli/cmd/account"
import { ProvidersCommand } from "./cli/cmd/providers"
import { AgentCommand } from "./cli/cmd/agent"
@ -12,7 +11,6 @@ import { ModelsCommand } from "./cli/cmd/models"
import { UI } from "./cli/ui"
import { Installation } from "./installation"
import { InstallationVersion } from "@opencode-ai/core/installation/version"
import { NamedError } from "@opencode-ai/core/util/error"
import { FormatError } from "./cli/error"
import { ServeCommand } from "./cli/cmd/serve"
import { Filesystem } from "@/util/filesystem"
@ -38,24 +36,9 @@ import { errorMessage } from "./util/error"
import { PluginCommand } from "./cli/cmd/plug"
import { Heap } from "./cli/heap"
import { drizzle } from "drizzle-orm/bun-sqlite"
import { ensureProcessMetadata } from "@opencode-ai/core/util/opencode-process"
import { isRecord } from "@/util/record"
const processMetadata = ensureProcessMetadata("main")
process.on("unhandledRejection", (e) => {
Log.Default.error("rejection", {
e: errorMessage(e),
})
})
process.on("uncaughtException", (e) => {
Log.Default.error("exception", {
e: errorMessage(e),
})
})
const args = hideBin(process.argv)
type LogLevel = "DEBUG" | "INFO" | "WARN" | "ERROR"
function show(out: string) {
const text = out.trimStart()
@ -67,7 +50,7 @@ function show(out: string) {
process.stderr.write(out)
}
function parseLogLevel(value: string | undefined): Log.Level | undefined {
function parseLogLevel(value: string | undefined): LogLevel | undefined {
if (value === "DEBUG" || value === "INFO" || value === "WARN" || value === "ERROR") return value
return undefined
}
@ -102,18 +85,12 @@ const cli = yargs(args)
process.env.OPENCODE_PURE = "1"
}
await Log.init({
print: opts.printLogs,
file: opts.logFile,
dev: Installation.isLocal(),
level: (() => {
if (opts.logLevel) return opts.logLevel as Log.Level
const envLevel = parseLogLevel(process.env.OPENCODE_LOG_LEVEL)
if (envLevel) return envLevel
if (Installation.isLocal()) return "DEBUG"
return "INFO"
})(),
})
if (opts.printLogs !== undefined) process.env.OPENCODE_PRINT_LOGS = opts.printLogs ? "1" : "0"
if (opts.logFile) process.env.OPENCODE_LOG_FILE = opts.logFile
const envLevel = parseLogLevel(process.env.OPENCODE_LOG_LEVEL)
process.env.OPENCODE_LOG_LEVEL = opts.logLevel
? (opts.logLevel as LogLevel)
: (envLevel ?? (Installation.isLocal() ? "DEBUG" : "INFO"))
Heap.start()
@ -121,13 +98,6 @@ const cli = yargs(args)
process.env.OPENCODE = "1"
process.env.OPENCODE_PID = String(process.pid)
Log.Default.info("opencode", {
version: InstallationVersion,
args: process.argv.slice(2),
process_role: processMetadata.processRole,
run_id: processMetadata.runID,
})
const marker = path.join(Global.Path.data, "opencode.db")
if (!(await Filesystem.exists(marker))) {
const tty = process.stderr.isTTY
@ -215,42 +185,10 @@ try {
await cli.parse()
}
} catch (e) {
let data: Record<string, any> = {}
if (e instanceof Error) {
Object.assign(data, {
name: e.name,
message: e.message,
cause: e.cause?.toString(),
stack: e.stack,
})
}
if (e instanceof NamedError) {
const obj = e.toObject()
if (isRecord(obj.data)) {
for (const [key, value] of Object.entries(obj.data)) {
if (key === "name" || key === "stack" || key === "cause") continue
data[key] = value
}
}
}
if (e instanceof ResolveMessage) {
Object.assign(data, {
name: e.name,
message: e.message,
code: e.code,
specifier: e.specifier,
referrer: e.referrer,
position: e.position,
importKind: e.importKind,
})
}
Log.Default.error("fatal", data)
const formatted = FormatError(e)
if (formatted) UI.error(formatted)
if (formatted === undefined) {
UI.error("Unexpected error, check log file at " + Log.file() + " for more details" + EOL)
UI.error("Unexpected error" + EOL)
process.stderr.write(errorMessage(e) + EOL)
}
process.exitCode = 1

View file

@ -7,13 +7,13 @@ import { ChildProcess } from "effect/unstable/process"
import { AppProcess } from "@opencode-ai/core/process"
import path from "path"
import { BusEvent } from "@/bus/bus-event"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { makeRuntime } from "@opencode-ai/core/effect/runtime"
import semver from "semver"
import { InstallationChannel, InstallationVersion } from "@opencode-ai/core/installation/version"
import { NpmConfig } from "@opencode-ai/core/npm-config"
const log = Log.create({ service: "installation" })
const log = EffectLogger.create({ service: "installation" })
export type Method = "curl" | "npm" | "yarn" | "pnpm" | "bun" | "brew" | "scoop" | "choco" | "unknown"

View file

@ -4,7 +4,7 @@ import path from "path"
import { pathToFileURL, fileURLToPath } from "url"
import { createMessageConnection, StreamMessageReader, StreamMessageWriter } from "vscode-jsonrpc/node"
import type { Diagnostic as VSCodeDiagnostic } from "vscode-languageserver-types"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Process } from "@/util/process"
import { LANGUAGE_EXTENSIONS } from "./language"
import { Effect, Schema } from "effect"
@ -27,7 +27,7 @@ const FILE_CHANGE_CREATED = 1
const FILE_CHANGE_CHANGED = 2
const TEXT_DOCUMENT_SYNC_INCREMENTAL = 2
const log = Log.create({ service: "lsp.client" })
const log = EffectLogger.create({ service: "lsp.client" })
const busRuntime = makeRuntime(Bus.Service, Bus.layer)
export type Info = NonNullable<Awaited<ReturnType<typeof create>>>

View file

@ -1,6 +1,6 @@
import { BusEvent } from "@/bus/bus-event"
import { Bus } from "@/bus"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import * as LSPClient from "./client"
import path from "path"
import { pathToFileURL, fileURLToPath } from "url"
@ -14,7 +14,7 @@ import { containsPath } from "@/project/instance-context"
import { NonNegativeInt } from "@opencode-ai/core/schema"
import { RuntimeFlags } from "@/effect/runtime-flags"
const log = Log.create({ service: "lsp" })
const log = EffectLogger.create({ service: "lsp" })
export const Event = {
Updated: BusEvent.define("lsp.updated", Schema.Struct({})),

View file

@ -2,7 +2,7 @@ import type { ChildProcessWithoutNullStreams } from "child_process"
import path from "path"
import os from "os"
import { Global } from "@opencode-ai/core/global"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { text } from "node:stream/consumers"
import fs from "fs/promises"
import { Filesystem } from "@/util/filesystem"
@ -15,7 +15,7 @@ import { spawn } from "./launch"
import { Npm } from "@opencode-ai/core/npm"
import type { RuntimeFlags } from "@/effect/runtime-flags"
const log = Log.create({ service: "lsp.server" })
const log = EffectLogger.create({ service: "lsp.server" })
const pathExists = async (p: string) =>
fs
.stat(p)

View file

@ -14,7 +14,7 @@ import {
} from "@modelcontextprotocol/sdk/types.js"
import { Config } from "@/config/config"
import { ConfigMCP } from "../config/mcp"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { NamedError } from "@opencode-ai/core/util/error"
import { InstallationVersion } from "@opencode-ai/core/installation/version"
import { withTimeout } from "@/util/timeout"
@ -32,7 +32,7 @@ import { InstanceState } from "@/effect/instance-state"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
const log = Log.create({ service: "mcp" })
const log = EffectLogger.create({ service: "mcp" })
const DEFAULT_TIMEOUT = 30_000
const TolerantListToolsResultSchema = ListToolsResultSchema.extend({

View file

@ -1,9 +1,9 @@
import { createConnection } from "net"
import { createServer } from "http"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { OAUTH_CALLBACK_PORT, OAUTH_CALLBACK_PATH, parseRedirectUri } from "./oauth-provider"
const log = Log.create({ service: "mcp.oauth-callback" })
const log = EffectLogger.create({ service: "mcp.oauth-callback" })
// Current callback server configuration (may differ from defaults if custom redirectUri is used)
let currentPort = OAUTH_CALLBACK_PORT

View file

@ -7,9 +7,9 @@ import type {
} from "@modelcontextprotocol/sdk/shared/auth.js"
import { Effect } from "effect"
import { McpAuth } from "./auth"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
const log = Log.create({ service: "mcp.oauth" })
const log = EffectLogger.create({ service: "mcp.oauth" })
const OAUTH_CALLBACK_PORT = 19876
const OAUTH_CALLBACK_PATH = "/mcp/oauth/callback"

View file

@ -1,6 +1,5 @@
export { Config } from "@/config/config"
export { Server } from "./server/server"
export { bootstrap } from "./cli/bootstrap"
export * as Log from "@opencode-ai/core/util/log"
export { Database } from "@/storage/db"
export { JsonMigration } from "@/storage/json-migration"

View file

@ -1,10 +1,10 @@
import { Effect, Schema } from "effect"
import * as path from "path"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import * as Bom from "../util/bom"
const log = Log.create({ service: "patch" })
const log = EffectLogger.create({ service: "patch" })
export const PatchSchema = Schema.Struct({
patchText: Schema.String.annotate({ description: "The full patch text that describes all changes to be made" }),

View file

@ -7,14 +7,14 @@ import { MessageID, SessionID } from "@/session/schema"
import { PermissionTable } from "@/session/session.sql"
import { Database } from "@/storage/db"
import { eq } from "drizzle-orm"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Wildcard } from "@opencode-ai/core/util/wildcard"
import { Deferred, Effect, Layer, Schema, Context } from "effect"
import os from "os"
import { PermissionV2 } from "@opencode-ai/core/permission"
import { PermissionID } from "./schema"
const log = Log.create({ service: "permission" })
const log = EffectLogger.create({ service: "permission" })
export const Action = PermissionV2.Action.annotate({ identifier: "PermissionAction" })
export type Action = Schema.Schema.Type<typeof Action>

View file

@ -1,12 +1,12 @@
import type { Hooks, PluginInput } from "@opencode-ai/plugin"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { InstallationVersion } from "@opencode-ai/core/installation/version"
import { OAUTH_DUMMY_KEY } from "../auth"
import os from "os"
import { setTimeout as sleep } from "node:timers/promises"
import { createServer } from "http"
const log = Log.create({ service: "plugin.codex" })
const log = EffectLogger.create({ service: "plugin.codex" })
const CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann"
const ISSUER = "https://auth.openai.com"

View file

@ -1,11 +1,11 @@
import type { Hooks, PluginInput } from "@opencode-ai/plugin"
import type { Model } from "@opencode-ai/sdk/v2"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { InstallationVersion } from "@opencode-ai/core/installation/version"
import { createServer } from "http"
import open from "open"
const log = Log.create({ service: "plugin.digitalocean" })
const log = EffectLogger.create({ service: "plugin.digitalocean" })
const DO_OAUTH_CLIENT_ID = "b1a6c5158156caac821fd1b30253ca8acb52454a48fa744420e41889cb589f82"
const DO_AUTHORIZE_URL = "https://cloud.digitalocean.com/v1/oauth/authorize"

View file

@ -2,12 +2,12 @@ import type { Hooks, PluginInput } from "@opencode-ai/plugin"
import type { Model } from "@opencode-ai/sdk/v2"
import { InstallationVersion } from "@opencode-ai/core/installation/version"
import { iife } from "@/util/iife"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { setTimeout as sleep } from "node:timers/promises"
import { CopilotModels } from "./models"
import { MessageV2 } from "@/session/message-v2"
const log = Log.create({ service: "plugin.copilot" })
const log = EffectLogger.create({ service: "plugin.copilot" })
const CLIENT_ID = "Ov23li8tweQw6odWQebz"
// Add a small safety buffer when polling to avoid hitting the server

View file

@ -7,7 +7,7 @@ import type {
} from "@opencode-ai/plugin"
import { Config } from "@/config/config"
import { Bus } from "../bus"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { createOpencodeClient } from "@opencode-ai/sdk"
import { ServerAuth } from "@/server/auth"
import { CodexAuthPlugin } from "./codex"
@ -30,7 +30,7 @@ import { registerAdapter } from "@/control-plane/adapters"
import type { WorkspaceAdapter } from "@/control-plane/types"
import { RuntimeFlags } from "@/effect/runtime-flags"
const log = Log.create({ service: "plugin" })
const log = EffectLogger.create({ service: "plugin" })
type State = {
hooks: Hooks[]

View file

@ -1,10 +1,10 @@
import type { Hooks, PluginInput } from "@opencode-ai/plugin"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { OAUTH_DUMMY_KEY } from "../auth"
import { createServer } from "http"
import { InstallationVersion } from "@opencode-ai/core/installation/version"
const log = Log.create({ service: "plugin.xai" })
const log = EffectLogger.create({ service: "plugin.xai" })
// Public Grok-CLI OAuth client. xAI's auth server rejects loopback OAuth from
// non-allowlisted clients, so we reuse the Grok-CLI client_id that xAI ships

View file

@ -3,7 +3,7 @@ import { Database } from "@/storage/db"
import { ProjectTable } from "./project.sql"
import { PermissionTable, SessionTable } from "../session/session.sql"
import { WorkspaceTable } from "../control-plane/workspace.sql"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Flag } from "@opencode-ai/core/flag/flag"
import { BusEvent } from "@/bus/bus-event"
import { GlobalBus } from "@/bus/global"
@ -22,7 +22,7 @@ import { AbsolutePath, NonNegativeInt, optionalOmitUndefined } from "@opencode-a
import { serviceUse } from "@opencode-ai/core/effect/service-use"
import { RuntimeFlags } from "@/effect/runtime-flags"
const log = Log.create({ service: "project" })
const log = EffectLogger.create({ service: "project" })
const ProjectVcs = Schema.Literal("git")

View file

@ -5,9 +5,9 @@ import { BusEvent } from "@/bus/bus-event"
import { InstanceState } from "@/effect/instance-state"
import { FileWatcher } from "@/file/watcher"
import { Git } from "@/git"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
const log = Log.create({ service: "vcs" })
const log = EffectLogger.create({ service: "vcs" })
const PATCH_CONTEXT_LINES = 2_147_483_647
const MAX_PATCH_BYTES = 10_000_000
const MAX_TOTAL_PATCH_BYTES = 10_000_000

View file

@ -3,7 +3,7 @@ import fuzzysort from "fuzzysort"
import { Config } from "@/config/config"
import { mapValues, mergeDeep, omit, pickBy, sortBy } from "remeda"
import { NoSuchModelError, type Provider as SDK } from "ai"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Npm } from "@opencode-ai/core/npm"
import { Hash } from "@opencode-ai/core/util/hash"
import { Plugin } from "../plugin"
@ -29,7 +29,7 @@ import { ModelID, ProviderID } from "./schema"
import { ModelStatus } from "./model-status"
import { RuntimeFlags } from "@/effect/runtime-flags"
const log = Log.create({ service: "provider" })
const log = EffectLogger.create({ service: "provider" })
function shouldUseCopilotResponsesApi(modelID: string): boolean {
const match = /^gpt-(\d+)/.exec(modelID)

View file

@ -7,12 +7,12 @@ import { lazy } from "@opencode-ai/core/util/lazy"
import { Plugin } from "@/plugin"
import { Shell } from "@/shell/shell"
import type { Proc } from "#pty"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { PtyID } from "./schema"
import { Effect, Layer, Context, Schema, Types } from "effect"
import { NonNegativeInt, PositiveInt } from "@opencode-ai/core/schema"
const log = Log.create({ service: "pty" })
const log = EffectLogger.create({ service: "pty" })
const BUFFER_LIMIT = 1024 * 1024 * 2
const BUFFER_CHUNK = 64 * 1024

View file

@ -3,10 +3,10 @@ import { Bus } from "@/bus"
import { BusEvent } from "@/bus/bus-event"
import { InstanceState } from "@/effect/instance-state"
import { SessionID, MessageID } from "@/session/schema"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { QuestionID } from "./schema"
const log = Log.create({ service: "question" })
const log = EffectLogger.create({ service: "question" })
// Schemas — these are pure data; nothing checks class identity (see PR
// description) so they're plain `Schema.Struct` + type alias. That lets

View file

@ -1,10 +1,10 @@
import { GlobalBus } from "@/bus/global"
import { InstanceStore } from "@/project/instance-store"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Effect } from "effect"
import { Event } from "./event"
const log = Log.create({ service: "server" })
const log = EffectLogger.create({ service: "server" })
export const emitGlobalDisposed = Effect.sync(() =>
GlobalBus.emit("event", {

View file

@ -1,7 +1,7 @@
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Bonjour } from "bonjour-service"
const log = Log.create({ service: "mdns" })
const log = EffectLogger.create({ service: "mdns" })
let bonjour: Bonjour | undefined
let currentPort: number | undefined

View file

@ -1,6 +1,6 @@
import { Auth } from "@/auth"
import { ProviderID } from "@/provider/schema"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Effect } from "effect"
import { HttpApiBuilder } from "effect/unstable/httpapi"
import { RootHttpApi } from "../api"
@ -24,7 +24,7 @@ export const controlHandlers = HttpApiBuilder.group(RootHttpApi, "control", (han
})
const log = Effect.fn("ControlHttpApi.log")(function* (ctx: { payload: typeof LogInput.Type }) {
const logger = Log.create({ service: ctx.payload.service })
const logger = EffectLogger.create({ service: ctx.payload.service })
logger[ctx.payload.level](ctx.payload.message, ctx.payload.extra)
return true
})

View file

@ -1,5 +1,5 @@
import { Bus } from "@/bus"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Effect } from "effect"
import * as Stream from "effect/Stream"
import { HttpServerResponse } from "effect/unstable/http"
@ -7,7 +7,7 @@ import { HttpApiBuilder } from "effect/unstable/httpapi"
import * as Sse from "effect/unstable/encoding/Sse"
import { EventApi } from "../groups/event"
const log = Log.create({ service: "server" })
const log = EffectLogger.create({ service: "server" })
function eventData(data: unknown): Sse.Event {
return {

View file

@ -5,7 +5,7 @@ import { Bus } from "@/bus"
import { Installation } from "@/installation"
import { disposeAllInstancesAndEmitGlobalDisposed } from "@/server/global-lifecycle"
import { InstallationVersion } from "@opencode-ai/core/installation/version"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Effect, Queue, Schema } from "effect"
import * as Stream from "effect/Stream"
import { HttpServerRequest, HttpServerResponse } from "effect/unstable/http"
@ -14,7 +14,7 @@ import * as Sse from "effect/unstable/encoding/Sse"
import { RootHttpApi } from "../api"
import { GlobalUpgradeInput } from "../groups/global"
const log = Log.create({ service: "server" })
const log = EffectLogger.create({ service: "server" })
function eventData(data: unknown): Sse.Event {
return {

View file

@ -14,9 +14,9 @@ import { Effect, Scope } from "effect"
import { HttpApiBuilder, HttpApiError } from "effect/unstable/httpapi"
import { InstanceHttpApi } from "../api"
import { HistoryPayload, ReplayPayload, SessionPayload } from "../groups/sync"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
const log = Log.create({ service: "server.sync" })
const log = EffectLogger.create({ service: "server.sync" })
export const syncHandlers = HttpApiBuilder.group(InstanceHttpApi, "sync", (handlers) =>
Effect.gen(function* () {

View file

@ -1,11 +1,11 @@
import { EffectBridge } from "@/effect/bridge"
import type { InstanceContext } from "@/project/instance-context"
import { InstanceStore } from "@/project/instance-store"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Effect } from "effect"
import { HttpEffect, HttpMiddleware, HttpServerRequest } from "effect/unstable/http"
const log = Log.create({ service: "server" })
const log = EffectLogger.create({ service: "server" })
type MarkedInstance = {
ctx: InstanceContext

View file

@ -1,9 +1,9 @@
import { NamedError } from "@opencode-ai/core/util/error"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Cause, Effect } from "effect"
import { HttpRouter, HttpServerError, HttpServerRespondable, HttpServerResponse } from "effect/unstable/http"
const log = Log.create({ service: "server" })
const log = EffectLogger.create({ service: "server" })
// Keep typed HttpApi failures on their declared error path; this boundary only replaces defect-only empty 500s.
export const errorLayer = HttpRouter.middleware<{ handles: unknown }>()((effect) =>

View file

@ -1,10 +1,10 @@
import { Effect } from "effect"
import { HttpServerResponse } from "effect/unstable/http"
import { HttpApiMiddleware } from "effect/unstable/httpapi"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { InvalidRequestError } from "../errors"
const log = Log.create({ service: "server" })
const log = EffectLogger.create({ service: "server" })
// Effect's Issue formatter recursively dumps the rejected `actual` value with
// no truncation, so a 5KB invalid array produces a ~360KB string. Cap to keep

View file

@ -1,7 +1,7 @@
import "./init-projectors"
import { NodeHttpServer } from "@effect/platform-node"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { ConfigProvider, Context, Effect, Exit, Layer, Scope } from "effect"
import { HttpRouter, HttpServer } from "effect/unstable/http"
import { OpenApi } from "effect/unstable/httpapi"
@ -17,7 +17,7 @@ import { lazy } from "@/util/lazy"
// @ts-ignore This global is needed to prevent ai-sdk from logging warnings to stdout https://github.com/vercel/ai/blob/2dc67e0ef538307f21368db32d5a12345d98831b/packages/ai/src/logger/log-warnings.ts#L85
globalThis.AI_SDK_LOG_WARNINGS = false
const log = Log.create({ service: "server" })
const log = EffectLogger.create({ service: "server" })
export type Listener = {
hostname: string

View file

@ -3,12 +3,12 @@ import { inArray } from "drizzle-orm"
import { EventSequenceTable } from "@/sync/event.sql"
import { Workspace } from "@/control-plane/workspace"
import type { WorkspaceID } from "@/control-plane/schema"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Effect } from "effect"
export const HEADER = "x-opencode-sync"
export type State = Record<string, number>
const log = Log.create({ service: "fence" })
const log = EffectLogger.create({ service: "fence" })
export function load(ids?: string[]) {
const rows = Database.use((db) => {

View file

@ -5,7 +5,7 @@ import { SessionID, MessageID, PartID } from "./schema"
import { Provider } from "@/provider/provider"
import { MessageV2 } from "./message-v2"
import { Token } from "@/util/token"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { SessionProcessor } from "./processor"
import { Agent } from "@/agent/agent"
import { Plugin } from "@/plugin"
@ -21,7 +21,7 @@ import { RuntimeFlags } from "@/effect/runtime-flags"
import { EventV2Bridge } from "@/event-v2-bridge"
import { SessionEvent } from "@opencode-ai/core/session-event"
const log = Log.create({ service: "session.compaction" })
const log = EffectLogger.create({ service: "session.compaction" })
export const Event = {
Compacted: BusEvent.define(

View file

@ -1,6 +1,6 @@
import { Provider } from "@/provider/provider"
import { serviceUse } from "@opencode-ai/core/effect/service-use"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Context, Effect, Layer } from "effect"
import * as Stream from "effect/Stream"
import { streamText, wrapLanguageModel, type ModelMessage, type Tool } from "ai"
@ -27,7 +27,7 @@ import { LLMAISDK } from "./llm/ai-sdk"
import { LLMNativeRuntime } from "./llm/native-runtime"
import { LLMRequestPrep } from "./llm/request"
const log = Log.create({ service: "llm" })
const log = EffectLogger.create({ service: "llm" })
export const OUTPUT_TOKEN_MAX = ProviderTransform.OUTPUT_TOKEN_MAX
export type StreamInput = {

View file

@ -19,7 +19,7 @@ import { SessionSummary } from "./summary"
import type { Provider } from "@/provider/provider"
import { Question } from "@/question"
import { errorMessage } from "@/util/error"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { isRecord } from "@/util/record"
import { EventV2Bridge } from "@/event-v2-bridge"
import { SessionEvent } from "@opencode-ai/core/session-event"
@ -30,7 +30,7 @@ import { RuntimeFlags } from "@/effect/runtime-flags"
import { Usage, type LLMEvent } from "@opencode-ai/llm"
const DOOM_LOOP_THRESHOLD = 3
const log = Log.create({ service: "session.processor" })
const log = EffectLogger.create({ service: "session.processor" })
export type Result = "compact" | "stop" | "continue"

View file

@ -8,10 +8,10 @@ import * as Session from "./session"
import { MessageV2 } from "./message-v2"
import { SessionTable, MessageTable, PartTable } from "./session.sql"
import { WorkspaceTable } from "@/control-plane/workspace.sql"
import { Log } from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import nextProjectors from "./projectors-next"
const log = Log.create({ service: "session.projector" })
const log = EffectLogger.create({ service: "session.projector" })
function foreign(err: unknown) {
if (typeof err !== "object" || err === null) return false

View file

@ -2,7 +2,7 @@ import path from "path"
import os from "os"
import { SessionID, MessageID, PartID } from "./schema"
import { MessageV2 } from "./message-v2"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { SessionRevert } from "./revert"
import * as Session from "./session"
import { Agent } from "../agent/agent"
@ -42,7 +42,6 @@ import { Image } from "@/image/image"
import { decodeDataUrl } from "@/util/data-url"
import { Process } from "@/util/process"
import { Cause, Effect, Exit, Latch, Layer, Option, Scope, Context, Schema, Types } from "effect"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { InstanceState } from "@/effect/instance-state"
import { TaskTool, type TaskPromptOps } from "@/tool/task"
import { SessionRunState } from "./run-state"
@ -78,7 +77,7 @@ IMPORTANT:
const STRUCTURED_OUTPUT_SYSTEM_PROMPT = `IMPORTANT: The user has requested structured output. You MUST use the StructuredOutput tool to provide your final response. Do NOT respond with plain text - you MUST call the StructuredOutput tool with your answer formatted according to the schema.`
const log = Log.create({ service: "session.prompt" })
const log = EffectLogger.create({ service: "session.prompt" })
const elog = EffectLogger.create({ service: "session.prompt" })
function isOrphanedInterruptedTool(part: MessageV2.ToolPart) {

View file

@ -3,14 +3,14 @@ import { Bus } from "../bus"
import { Snapshot } from "../snapshot"
import { Storage } from "@/storage/storage"
import { SyncEvent } from "../sync"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import * as Session from "./session"
import { MessageV2 } from "./message-v2"
import { SessionID, MessageID, PartID } from "./schema"
import { SessionRunState } from "./run-state"
import { SessionSummary } from "./summary"
const log = Log.create({ service: "session.revert" })
const log = EffectLogger.create({ service: "session.revert" })
export const RevertInput = Schema.Struct({
sessionID: SessionID,

View file

@ -24,7 +24,7 @@ import type { SQL } from "drizzle-orm"
import { PartTable, SessionTable } from "./session.sql"
import { ProjectTable } from "../project/project.sql"
import { Storage } from "@/storage/storage"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { MessageV2 } from "./message-v2"
import type { InstanceContext } from "../project/instance-context"
import { InstanceState } from "@/effect/instance-state"
@ -41,7 +41,7 @@ import { Effect, Layer, Option, Context, Schema, Types } from "effect"
import { NonNegativeInt, optionalOmitUndefined } from "@opencode-ai/core/schema"
import { RuntimeFlags } from "@/effect/runtime-flags"
const log = Log.create({ service: "session" })
const log = EffectLogger.create({ service: "session" })
const parentTitlePrefix = "New session - "
const childTitlePrefix = "Child session - "

View file

@ -16,10 +16,10 @@ import { MessageV2 } from "./message-v2"
import * as Session from "./session"
import { SessionProcessor } from "./processor"
import { PartID } from "./schema"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { EffectBridge } from "@/effect/bridge"
const log = Log.create({ service: "session.tools" })
const log = EffectLogger.create({ service: "session.tools" })
export const resolve = Effect.fn("SessionTools.resolve")(function* (input: {
agent: Agent.Info

View file

@ -13,10 +13,10 @@ import type { SessionID } from "@/session/schema"
import { Database } from "@/storage/db"
import { eq } from "drizzle-orm"
import { Config } from "@/config/config"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { SessionShareTable } from "./share.sql"
const log = Log.create({ service: "share-next" })
const log = EffectLogger.create({ service: "share-next" })
const disabled = process.env["OPENCODE_DISABLE_SHARE"] === "true" || process.env["OPENCODE_DISABLE_SHARE"] === "1"
export type Api = {

View file

@ -4,7 +4,7 @@ import { FetchHttpClient, HttpClient, HttpClientRequest, HttpClientResponse } fr
import { withTransientReadRetry } from "@/util/effect-http-client"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { Global } from "@opencode-ai/core/global"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
const skillConcurrency = 4
const fileConcurrency = 8
@ -28,7 +28,7 @@ export const layer: Layer.Layer<Service, never, AppFileSystem.Service | Path.Pat
Layer.effect(
Service,
Effect.gen(function* () {
const log = Log.create({ service: "skill-discovery" })
const log = EffectLogger.create({ service: "skill-discovery" })
const fs = yield* AppFileSystem.Service
const path = yield* Path.Path
const http = HttpClient.filterStatusOk(withTransientReadRetry(yield* HttpClient.HttpClient))

View file

@ -12,12 +12,12 @@ import { Config } from "@/config/config"
import { ConfigMarkdown } from "@/config/markdown"
import { RuntimeFlags } from "@/effect/runtime-flags"
import { Glob } from "@opencode-ai/core/util/glob"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Discovery } from "./discovery"
import CUSTOMIZE_OPENCODE_SKILL_BODY from "./prompt/customize-opencode.md" with { type: "text" }
import { isRecord } from "@/util/record"
const log = Log.create({ service: "skill" })
const log = EffectLogger.create({ service: "skill" })
const CLAUDE_EXTERNAL_DIR = ".claude"
const AGENTS_EXTERNAL_DIR = ".agents"
const EXTERNAL_SKILL_PATTERN = "skills/**/SKILL.md"

View file

@ -8,7 +8,7 @@ import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { Hash } from "@opencode-ai/core/util/hash"
import { Config } from "@/config/config"
import { Global } from "@opencode-ai/core/global"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
export const Patch = Schema.Struct({
hash: Schema.String,
@ -28,7 +28,7 @@ export const FileDiff = Schema.Struct({
}).annotate({ identifier: "SnapshotFileDiff" })
export type FileDiff = typeof FileDiff.Type
const log = Log.create({ service: "snapshot" })
const log = EffectLogger.create({ service: "snapshot" })
const prune = "7.days"
const limit = 2 * 1024 * 1024
const core = ["-c", "core.longpaths=true", "-c", "core.symlinks=true"]

View file

@ -5,7 +5,7 @@ export * from "drizzle-orm"
import { RuntimeFlags } from "@/effect/runtime-flags"
import { LocalContext } from "@/util/local-context"
import { Global } from "@opencode-ai/core/global"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { NamedError } from "@opencode-ai/core/util/error"
import path from "path"
import { readFileSync, readdirSync, existsSync } from "fs"
@ -21,7 +21,7 @@ export const NotFoundError = NamedError.create("NotFoundError", {
message: Schema.String,
})
const log = Log.create({ service: "db" })
const log = EffectLogger.create({ service: "db" })
type DatabaseFlags = Pick<RuntimeFlags.Info, "disableChannelDb" | "skipMigrations">

View file

@ -1,7 +1,7 @@
import type { SQLiteBunDatabase } from "drizzle-orm/bun-sqlite"
import type { NodeSQLiteDatabase } from "drizzle-orm/node-sqlite"
import { Global } from "@opencode-ai/core/global"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { ProjectTable } from "../project/project.sql"
import { SessionTable, MessageTable, PartTable, TodoTable, PermissionTable } from "../session/session.sql"
import { SessionShareTable } from "../share/share.sql"
@ -10,7 +10,7 @@ import { existsSync } from "fs"
import { Filesystem } from "@/util/filesystem"
import { Glob } from "@opencode-ai/core/util/glob"
const log = Log.create({ service: "json-migration" })
const log = EffectLogger.create({ service: "json-migration" })
export type Progress = {
current: number

View file

@ -1,4 +1,4 @@
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import path from "path"
import { Global } from "@opencode-ai/core/global"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
@ -6,7 +6,7 @@ import { Effect, Exit, Layer, Option, RcMap, Schema, Context, TxReentrantLock }
import { NonNegativeInt } from "@opencode-ai/core/schema"
import { Git } from "@/git"
const log = Log.create({ service: "storage" })
const log = EffectLogger.create({ service: "storage" })
type Migration = (
dir: string,

View file

@ -2,9 +2,9 @@ import yargs from "yargs"
import { TuiThreadCommand } from "./cli/cmd/tui/thread"
import { InstallationVersion } from "@opencode-ai/core/installation/version"
import { hideBin } from "yargs/helpers"
import { Log } from "./node"
const args = hideBin(process.argv)
type LogLevel = "DEBUG" | "INFO" | "WARN" | "ERROR"
function flag(name: string) {
const index = args.indexOf(name)
@ -13,16 +13,16 @@ function flag(name: string) {
return value?.slice(name.length + 1)
}
function parseLogLevel(value: string | undefined): Log.Level | undefined {
function parseLogLevel(value: string | undefined): LogLevel | undefined {
if (value === "DEBUG" || value === "INFO" || value === "WARN" || value === "ERROR") return value
return undefined
}
Log.init({
print: args.includes("--print-logs"),
file: flag("--log-file"),
level: parseLogLevel(flag("--log-level")),
})
if (args.includes("--print-logs")) process.env.OPENCODE_PRINT_LOGS = "1"
const logFile = flag("--log-file")
if (logFile) process.env.OPENCODE_LOG_FILE = logFile
const logLevel = parseLogLevel(flag("--log-level"))
if (logLevel) process.env.OPENCODE_LOG_LEVEL = logLevel
const cli = yargs(args)
.parserConfiguration({ "populate--": true })

View file

@ -25,7 +25,7 @@ import { WebSearchTool } from "./websearch"
import { RepoCloneTool } from "./repo_clone"
import { RepoOverviewTool } from "./repo_overview"
import { RepositoryCache } from "@/reference/repository-cache"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { LspTool } from "./lsp"
import * as Truncate from "./truncate"
import { ApplyPatchTool } from "./apply_patch"
@ -54,7 +54,7 @@ import { Reference } from "@/reference/reference"
import { BackgroundJob } from "@/background/job"
import { RuntimeFlags } from "@/effect/runtime-flags"
const log = Log.create({ service: "tool.registry" })
const log = EffectLogger.create({ service: "tool.registry" })
export function webSearchEnabled(providerID: ProviderID, flags = { exa: false, parallel: false }) {
return providerID === ProviderID.opencode || flags.exa || flags.parallel

View file

@ -3,7 +3,7 @@ import os from "os"
import { createWriteStream } from "node:fs"
import * as Tool from "./tool"
import path from "path"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { containsPath, type InstanceContext } from "../project/instance-context"
import { InstanceState } from "@/effect/instance-state"
import { lazy } from "@/util/lazy"
@ -82,7 +82,7 @@ type Chunk = {
size: number
}
export const log = Log.create({ service: "shell-tool" })
export const log = EffectLogger.create({ service: "shell-tool" })
const resolveWasm = (asset: string) => {
if (asset.startsWith("file://")) return fileURLToPath(asset)

View file

@ -6,11 +6,11 @@ import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { evaluate } from "@/permission/evaluate"
import { Config } from "@/config/config"
import { Identifier } from "../id/id"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { ToolID } from "./schema"
import { TRUNCATION_DIR } from "./truncation-dir"
const log = Log.create({ service: "truncation" })
const log = EffectLogger.create({ service: "truncation" })
const RETENTION = Duration.days(7)
export const MAX_LINES = 2000

View file

@ -6,7 +6,7 @@ import { Database } from "@/storage/db"
import { eq } from "drizzle-orm"
import { ProjectTable } from "../project/project.sql"
import type { ProjectID } from "../project/schema"
import * as Log from "@opencode-ai/core/util/log"
import * as EffectLogger from "@opencode-ai/core/effect/logger"
import { Slug } from "@opencode-ai/core/util/slug"
import { errorMessage } from "../util/error"
import { BusEvent } from "@/bus/bus-event"
@ -19,7 +19,7 @@ import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { AppProcess } from "@opencode-ai/core/process"
import { InstanceState } from "@/effect/instance-state"
const log = Log.create({ service: "worktree" })
const log = EffectLogger.create({ service: "worktree" })
export const Event = {
Ready: BusEvent.define(

View file

@ -8,7 +8,6 @@ import { Effect, Exit, Fiber, Layer, Schema } from "effect"
import { FetchHttpClient, HttpServer, HttpServerRequest, HttpServerResponse } from "effect/unstable/http"
import { eq } from "drizzle-orm"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import * as Log from "@opencode-ai/core/util/log"
import { GlobalBus, type GlobalEvent } from "@/bus/global"
import { Database } from "@/storage/db"
import { ProjectID } from "@/project/schema"
@ -34,8 +33,6 @@ import { Project } from "@/project/project"
import { Vcs } from "@/project/vcs"
import { RuntimeFlags } from "@/effect/runtime-flags"
void Log.init({ print: false })
const originalEnv = {
OPENCODE_AUTH_CONTENT: process.env.OPENCODE_AUTH_CONTENT,
OPENCODE_EXPERIMENTAL_WORKSPACES: process.env.OPENCODE_EXPERIMENTAL_WORKSPACES,

View file

@ -1,10 +1,9 @@
import { beforeEach, describe, expect, test } from "bun:test"
import { describe, expect, test } from "bun:test"
import path from "path"
import { pathToFileURL } from "url"
import { tmpdir, withTestInstance } from "../fixture/fixture"
import { LSPClient } from "@/lsp/client"
import * as LSPServer from "@/lsp/server"
import * as Log from "@opencode-ai/core/util/log"
function spawnFakeServer() {
const { spawn } = require("child_process")
@ -17,10 +16,6 @@ function spawnFakeServer() {
}
describe("LSPClient interop", () => {
beforeEach(async () => {
await Log.init({ print: true })
})
test("handles workspace/workspaceFolders request", async () => {
const handle = spawnFakeServer() as any

View file

@ -80,13 +80,8 @@ delete process.env["OPENCODE_SERVER_USERNAME"]
process.env["OPENCODE_DB"] = ":memory:"
// Now safe to import from src/
const { Log } = await import("@opencode-ai/core/util/log")
const { initProjectors } = await import("../src/server/projectors")
void Log.init({
print: false,
dev: true,
level: "DEBUG",
})
process.env.OPENCODE_LOG_LEVEL = "DEBUG"
process.env.OPENCODE_LOG_FILE = "0"
initProjectors()

View file

@ -6,15 +6,12 @@ import { SessionTable } from "../../src/session/session.sql"
import { ProjectTable } from "../../src/project/project.sql"
import { ProjectID } from "../../src/project/schema"
import { SessionID } from "../../src/session/schema"
import * as Log from "@opencode-ai/core/util/log"
import { $ } from "bun"
import { tmpdirScoped } from "../fixture/fixture"
import { Effect, Layer } from "effect"
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import { testEffect } from "../lib/effect"
void Log.init({ print: false })
const it = testEffect(Layer.mergeAll(Project.defaultLayer, CrossSpawnSpawner.defaultLayer))
function legacySessionID() {

View file

@ -1,7 +1,6 @@
import { describe, expect, test } from "bun:test"
import { Bus } from "@/bus"
import { Project } from "@/project/project"
import * as Log from "@opencode-ai/core/util/log"
import { $ } from "bun"
import path from "path"
import { tmpdirScoped } from "../fixture/fixture"
@ -17,8 +16,6 @@ import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import { testEffect } from "../lib/effect"
import { RuntimeFlags } from "@/effect/runtime-flags"
void Log.init({ print: false })
const encoder = new TextEncoder()
const layer = Layer.mergeAll(Project.defaultLayer, CrossSpawnSpawner.defaultLayer)

View file

@ -3,12 +3,9 @@ import { Deferred, Effect, Layer } from "effect"
import { Project } from "@/project/project"
import { Session as SessionNs } from "@/session/session"
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import * as Log from "@opencode-ai/core/util/log"
import { provideInstance, TestInstance, tmpdirScoped } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
void Log.init({ print: false })
const it = testEffect(Layer.mergeAll(SessionNs.defaultLayer, Project.defaultLayer, CrossSpawnSpawner.defaultLayer))
const withSession = (input?: Parameters<SessionNs.Interface["create"]>[0]) =>

View file

@ -1,12 +1,9 @@
import { afterEach, describe, expect, test } from "bun:test"
import { gunzipSync, inflateSync } from "node:zlib"
import * as Log from "@opencode-ai/core/util/log"
import { Server } from "../../src/server/server"
import { resetDatabase } from "../fixture/db"
import { disposeAllInstances, tmpdir } from "../fixture/fixture"
void Log.init({ print: false })
afterEach(async () => {
await disposeAllInstances()
await resetDatabase()

View file

@ -1,15 +1,12 @@
import { afterEach, describe, expect } from "bun:test"
import path from "path"
import { Server } from "../../src/server/server"
import * as Log from "@opencode-ai/core/util/log"
import { Effect, Fiber } from "effect"
import { resetDatabase } from "../fixture/db"
import { disposeAllInstances, tmpdir } from "../fixture/fixture"
import { it } from "../lib/effect"
import { waitGlobalBusEvent } from "./global-bus"
void Log.init({ print: false })
function app() {
return Server.Default().app
}

View file

@ -1,11 +1,8 @@
import { afterEach, describe, expect, test } from "bun:test"
import * as Log from "@opencode-ai/core/util/log"
import { Server } from "../../src/server/server"
import { resetDatabase } from "../fixture/db"
import { disposeAllInstances } from "../fixture/fixture"
void Log.init({ print: false })
afterEach(async () => {
await disposeAllInstances()
await resetDatabase()

View file

@ -26,7 +26,6 @@
// subscription is established. Order-of-setup variable.
import { afterEach, describe, expect } from "bun:test"
import { Deferred, Effect, Layer, Schema } from "effect"
import * as Log from "@opencode-ai/core/util/log"
import { Bus } from "../../src/bus"
import { Event as ServerEvent } from "../../src/server/event"
import { Server } from "../../src/server/server"
@ -38,8 +37,6 @@ import { resetDatabase } from "../fixture/db"
import { disposeAllInstances, TestInstance } from "../fixture/fixture"
import { testEffectShared } from "../lib/effect"
void Log.init({ print: false })
const SseEvent = Schema.Struct({
id: Schema.optional(Schema.String),
type: Schema.String,

View file

@ -1,6 +1,5 @@
import { afterEach, describe, expect } from "bun:test"
import { Effect, Schema } from "effect"
import * as Log from "@opencode-ai/core/util/log"
import { Bus } from "../../src/bus"
import { Event as ServerEvent } from "../../src/server/event"
import { Server } from "../../src/server/server"
@ -9,8 +8,6 @@ import { resetDatabase } from "../fixture/db"
import { disposeAllInstances, TestInstance } from "../fixture/fixture"
import { testEffectShared } from "../lib/effect"
void Log.init({ print: false })
const EventData = Schema.Struct({
id: Schema.optional(Schema.String),
type: Schema.String,

View file

@ -36,8 +36,6 @@ import { runScenario } from "./runner"
import { runtime } from "./runtime"
import { type Scenario } from "./types"
void (await import("@opencode-ai/core/util/log")).init({ print: false })
function cursor(input: Record<string, unknown>) {
return Buffer.from(JSON.stringify(input)).toString("base64url")
}

View file

@ -7,14 +7,11 @@ import { ExperimentalPaths } from "../../src/server/routes/instance/httpapi/grou
import { Session } from "@/session/session"
import { SessionTable } from "@/session/session.sql"
import { Database } from "@/storage/db"
import * as Log from "@opencode-ai/core/util/log"
import { Worktree } from "../../src/worktree"
import { resetDatabase } from "../fixture/db"
import { disposeAllInstances, TestInstance } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
void Log.init({ print: false })
const it = testEffect(Layer.mergeAll(Session.defaultLayer))
const testWorktreeMutations = process.platform === "win32" ? it.instance.skip : it.instance

View file

@ -3,12 +3,9 @@ import { Context } from "effect"
import path from "path"
import { HttpApiApp } from "../../src/server/routes/instance/httpapi/server"
import { FilePaths } from "../../src/server/routes/instance/httpapi/groups/file"
import * as Log from "@opencode-ai/core/util/log"
import { resetDatabase } from "../fixture/db"
import { disposeAllInstances, tmpdir } from "../fixture/fixture"
void Log.init({ print: false })
const context = Context.empty() as Context.Context<unknown>
function request(route: string, directory: string, query?: Record<string, string>) {

Some files were not shown because too many files have changed in this diff Show more