feat: unwrap Config namespace to flat exports + barrel (#22689)

This commit is contained in:
Kit Langton
2026-04-15 21:26:24 -04:00
committed by GitHub
parent 0fb0135e51
commit bbdbc107ae
54 changed files with 1105 additions and 1125 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env bun #!/usr/bin/env bun
import { z } from "zod" import { z } from "zod"
import { Config } from "../src/config/config" import { Config } from "../src/config"
import { TuiConfig } from "../src/config/tui" import { TuiConfig } from "../src/config/tui"
function generate(schema: z.ZodType) { function generate(schema: z.ZodType) {
+1 -1
View File
@@ -43,7 +43,7 @@ import { Agent as AgentModule } from "../agent/agent"
import { AppRuntime } from "@/effect/app-runtime" import { AppRuntime } from "@/effect/app-runtime"
import { Installation } from "@/installation" import { Installation } from "@/installation"
import { MessageV2 } from "@/session/message-v2" import { MessageV2 } from "@/session/message-v2"
import { Config } from "@/config/config" import { Config } from "@/config"
import { Todo } from "@/session/todo" import { Todo } from "@/session/todo"
import { z } from "zod" import { z } from "zod"
import { LoadAPIKeyError } from "ai" import { LoadAPIKeyError } from "ai"
+1 -1
View File
@@ -1,4 +1,4 @@
import { Config } from "../config/config" import { Config } from "../config"
import z from "zod" import z from "zod"
import { Provider } from "../provider/provider" import { Provider } from "../provider/provider"
import { ModelID, ProviderID } from "../provider/schema" import { ModelID, ProviderID } from "../provider/schema"
@@ -1,5 +1,5 @@
import { EOL } from "os" import { EOL } from "os"
import { Config } from "../../../config/config" import { Config } from "../../../config"
import { AppRuntime } from "@/effect/app-runtime" import { AppRuntime } from "@/effect/app-runtime"
import { bootstrap } from "../../bootstrap" import { bootstrap } from "../../bootstrap"
import { cmd } from "../cmd" import { cmd } from "../cmd"
+1 -1
View File
@@ -7,7 +7,7 @@ import { UI } from "../ui"
import { MCP } from "../../mcp" import { MCP } from "../../mcp"
import { McpAuth } from "../../mcp/auth" import { McpAuth } from "../../mcp/auth"
import { McpOAuthProvider } from "../../mcp/oauth-provider" import { McpOAuthProvider } from "../../mcp/oauth-provider"
import { Config } from "../../config/config" import { Config } from "../../config"
import { Instance } from "../../project/instance" import { Instance } from "../../project/instance"
import { Installation } from "../../installation" import { Installation } from "../../installation"
import path from "path" import path from "path"
+1 -1
View File
@@ -7,7 +7,7 @@ import { ModelsDev } from "../../provider/models"
import { map, pipe, sortBy, values } from "remeda" import { map, pipe, sortBy, values } from "remeda"
import path from "path" import path from "path"
import os from "os" import os from "os"
import { Config } from "../../config/config" import { Config } from "../../config"
import { Global } from "../../global" import { Global } from "../../global"
import { Plugin } from "../../plugin" import { Plugin } from "../../plugin"
import { Instance } from "../../project/instance" import { Instance } from "../../project/instance"
@@ -13,7 +13,7 @@ import {
import path from "path" import path from "path"
import { fileURLToPath } from "url" import { fileURLToPath } from "url"
import { Config } from "@/config/config" import { Config } from "@/config"
import { TuiConfig } from "@/config/tui" import { TuiConfig } from "@/config/tui"
import { Log } from "@/util/log" import { Log } from "@/util/log"
import { errorData, errorMessage } from "@/util/error" import { errorData, errorMessage } from "@/util/error"
+1 -1
View File
@@ -5,7 +5,7 @@ import { Instance } from "@/project/instance"
import { InstanceBootstrap } from "@/project/bootstrap" import { InstanceBootstrap } from "@/project/bootstrap"
import { Rpc } from "@/util/rpc" import { Rpc } from "@/util/rpc"
import { upgrade } from "@/cli/upgrade" import { upgrade } from "@/cli/upgrade"
import { Config } from "@/config/config" import { Config } from "@/config"
import { GlobalBus } from "@/bus/global" import { GlobalBus } from "@/bus/global"
import { Flag } from "@/flag/flag" import { Flag } from "@/flag/flag"
import { writeHeapSnapshot } from "node:v8" import { writeHeapSnapshot } from "node:v8"
+1 -1
View File
@@ -1,7 +1,7 @@
import { AccountServiceError, AccountTransportError } from "@/account" import { AccountServiceError, AccountTransportError } from "@/account"
import { ConfigMarkdown } from "@/config/markdown" import { ConfigMarkdown } from "@/config/markdown"
import { errorFormat } from "@/util/error" import { errorFormat } from "@/util/error"
import { Config } from "../config/config" import { Config } from "../config"
import { MCP } from "../mcp" import { MCP } from "../mcp"
import { Provider } from "../provider/provider" import { Provider } from "../provider/provider"
import { UI } from "./ui" import { UI } from "./ui"
+1 -1
View File
@@ -1,5 +1,5 @@
import type { Argv, InferredOptionTypes } from "yargs" import type { Argv, InferredOptionTypes } from "yargs"
import { Config } from "../config/config" import { Config } from "../config"
import { AppRuntime } from "@/effect/app-runtime" import { AppRuntime } from "@/effect/app-runtime"
const options = { const options = {
+1 -1
View File
@@ -1,5 +1,5 @@
import { Bus } from "@/bus" import { Bus } from "@/bus"
import { Config } from "@/config/config" import { Config } from "@/config"
import { AppRuntime } from "@/effect/app-runtime" import { AppRuntime } from "@/effect/app-runtime"
import { Flag } from "@/flag/flag" import { Flag } from "@/flag/flag"
import { Installation } from "@/installation" import { Installation } from "@/installation"
+1 -1
View File
@@ -5,7 +5,7 @@ import type { InstanceContext } from "@/project/instance"
import { SessionID, MessageID } from "@/session/schema" import { SessionID, MessageID } from "@/session/schema"
import { Effect, Layer, Context } from "effect" import { Effect, Layer, Context } from "effect"
import z from "zod" import z from "zod"
import { Config } from "../config/config" import { Config } from "../config"
import { MCP } from "../mcp" import { MCP } from "../mcp"
import { Skill } from "../skill" import { Skill } from "../skill"
import { Log } from "../util/log" import { Log } from "../util/log"
+121 -142
View File
@@ -39,25 +39,24 @@ import { isPathPluginSpec, parsePluginSpecifier, resolvePathPluginTarget } from
import { Npm } from "../npm" import { Npm } from "../npm"
import { InstanceRef } from "@/effect/instance-ref" import { InstanceRef } from "@/effect/instance-ref"
export namespace Config { const ModelId = z.string().meta({ $ref: "https://models.dev/model-schema.json#/$defs/Model" })
const ModelId = z.string().meta({ $ref: "https://models.dev/model-schema.json#/$defs/Model" }) const PluginOptions = z.record(z.string(), z.unknown())
const PluginOptions = z.record(z.string(), z.unknown()) export const PluginSpec = z.union([z.string(), z.tuple([z.string(), PluginOptions])])
export const PluginSpec = z.union([z.string(), z.tuple([z.string(), PluginOptions])])
export type PluginOptions = z.infer<typeof PluginOptions> export type PluginOptions = z.infer<typeof PluginOptions>
export type PluginSpec = z.infer<typeof PluginSpec> export type PluginSpec = z.infer<typeof PluginSpec>
export type PluginScope = "global" | "local" export type PluginScope = "global" | "local"
export type PluginOrigin = { export type PluginOrigin = {
spec: PluginSpec spec: PluginSpec
source: string source: string
scope: PluginScope scope: PluginScope
} }
const log = Log.create({ service: "config" }) const log = Log.create({ service: "config" })
// Managed settings directory for enterprise deployments (highest priority, admin-controlled) // Managed settings directory for enterprise deployments (highest priority, admin-controlled)
// These settings override all user and project settings // These settings override all user and project settings
function systemManagedConfigDir(): string { function systemManagedConfigDir(): string {
switch (process.platform) { switch (process.platform) {
case "darwin": case "darwin":
return "/Library/Application Support/opencode" return "/Library/Application Support/opencode"
@@ -66,45 +65,45 @@ export namespace Config {
default: default:
return "/etc/opencode" return "/etc/opencode"
} }
} }
export function managedConfigDir() { export function managedConfigDir() {
return process.env.OPENCODE_TEST_MANAGED_CONFIG_DIR || systemManagedConfigDir() return process.env.OPENCODE_TEST_MANAGED_CONFIG_DIR || systemManagedConfigDir()
} }
const managedDir = managedConfigDir() const managedDir = managedConfigDir()
const MANAGED_PLIST_DOMAIN = "ai.opencode.managed" const MANAGED_PLIST_DOMAIN = "ai.opencode.managed"
// Keys injected by macOS/MDM into the managed plist that are not OpenCode config // Keys injected by macOS/MDM into the managed plist that are not OpenCode config
const PLIST_META = new Set([ const PLIST_META = new Set([
"PayloadDisplayName", "PayloadDisplayName",
"PayloadIdentifier", "PayloadIdentifier",
"PayloadType", "PayloadType",
"PayloadUUID", "PayloadUUID",
"PayloadVersion", "PayloadVersion",
"_manualProfile", "_manualProfile",
]) ])
/** /**
* Parse raw JSON (from plutil conversion of a managed plist) into OpenCode config. * Parse raw JSON (from plutil conversion of a managed plist) into OpenCode config.
* Strips MDM metadata keys before parsing through the config schema. * Strips MDM metadata keys before parsing through the config schema.
* Pure function — no OS interaction, safe to unit test directly. * Pure function — no OS interaction, safe to unit test directly.
*/ */
export function parseManagedPlist(json: string, source: string): Info { export function parseManagedPlist(json: string, source: string): Info {
const raw = JSON.parse(json) const raw = JSON.parse(json)
for (const key of Object.keys(raw)) { for (const key of Object.keys(raw)) {
if (PLIST_META.has(key)) delete raw[key] if (PLIST_META.has(key)) delete raw[key]
} }
return parseConfig(JSON.stringify(raw), source) return parseConfig(JSON.stringify(raw), source)
} }
/** /**
* Read macOS managed preferences deployed via .mobileconfig / MDM (Jamf, Kandji, etc). * Read macOS managed preferences deployed via .mobileconfig / MDM (Jamf, Kandji, etc).
* MDM-installed profiles write to /Library/Managed Preferences/ which is only writable by root. * MDM-installed profiles write to /Library/Managed Preferences/ which is only writable by root.
* User-scoped plists are checked first, then machine-scoped. * User-scoped plists are checked first, then machine-scoped.
*/ */
async function readManagedPreferences(): Promise<Info> { async function readManagedPreferences(): Promise<Info> {
if (process.platform !== "darwin") return {} if (process.platform !== "darwin") return {}
const domain = MANAGED_PLIST_DOMAIN const domain = MANAGED_PLIST_DOMAIN
@@ -125,40 +124,40 @@ export namespace Config {
return parseManagedPlist(result.stdout.toString(), `mobileconfig:${plist}`) return parseManagedPlist(result.stdout.toString(), `mobileconfig:${plist}`)
} }
return {} return {}
} }
// Custom merge function that concatenates array fields instead of replacing them // Custom merge function that concatenates array fields instead of replacing them
function mergeConfigConcatArrays(target: Info, source: Info): Info { function mergeConfigConcatArrays(target: Info, source: Info): Info {
const merged = mergeDeep(target, source) const merged = mergeDeep(target, source)
if (target.instructions && source.instructions) { if (target.instructions && source.instructions) {
merged.instructions = Array.from(new Set([...target.instructions, ...source.instructions])) merged.instructions = Array.from(new Set([...target.instructions, ...source.instructions]))
} }
return merged return merged
} }
export type InstallInput = { export type InstallInput = {
waitTick?: (input: { dir: string; attempt: number; delay: number; waited: number }) => void | Promise<void> waitTick?: (input: { dir: string; attempt: number; delay: number; waited: number }) => void | Promise<void>
} }
type Package = { type Package = {
dependencies?: Record<string, string> dependencies?: Record<string, string>
} }
function rel(item: string, patterns: string[]) { function rel(item: string, patterns: string[]) {
const normalizedItem = item.replaceAll("\\", "/") const normalizedItem = item.replaceAll("\\", "/")
for (const pattern of patterns) { for (const pattern of patterns) {
const index = normalizedItem.indexOf(pattern) const index = normalizedItem.indexOf(pattern)
if (index === -1) continue if (index === -1) continue
return normalizedItem.slice(index + pattern.length) return normalizedItem.slice(index + pattern.length)
} }
} }
function trim(file: string) { function trim(file: string) {
const ext = path.extname(file) const ext = path.extname(file)
return ext.length ? file.slice(0, -ext.length) : file return ext.length ? file.slice(0, -ext.length) : file
} }
async function loadCommand(dir: string) { async function loadCommand(dir: string) {
const result: Record<string, Command> = {} const result: Record<string, Command> = {}
for (const item of await Glob.scan("{command,commands}/**/*.md", { for (const item of await Glob.scan("{command,commands}/**/*.md", {
cwd: dir, cwd: dir,
@@ -194,9 +193,9 @@ export namespace Config {
throw new InvalidError({ path: item, issues: parsed.error.issues }, { cause: parsed.error }) throw new InvalidError({ path: item, issues: parsed.error.issues }, { cause: parsed.error })
} }
return result return result
} }
async function loadAgent(dir: string) { async function loadAgent(dir: string) {
const result: Record<string, Agent> = {} const result: Record<string, Agent> = {}
for (const item of await Glob.scan("{agent,agents}/**/*.md", { for (const item of await Glob.scan("{agent,agents}/**/*.md", {
@@ -233,9 +232,9 @@ export namespace Config {
throw new InvalidError({ path: item, issues: parsed.error.issues }, { cause: parsed.error }) throw new InvalidError({ path: item, issues: parsed.error.issues }, { cause: parsed.error })
} }
return result return result
} }
async function loadMode(dir: string) { async function loadMode(dir: string) {
const result: Record<string, Agent> = {} const result: Record<string, Agent> = {}
for (const item of await Glob.scan("{mode,modes}/*.md", { for (const item of await Glob.scan("{mode,modes}/*.md", {
cwd: dir, cwd: dir,
@@ -269,9 +268,9 @@ export namespace Config {
} }
} }
return result return result
} }
async function loadPlugin(dir: string) { async function loadPlugin(dir: string) {
const plugins: PluginSpec[] = [] const plugins: PluginSpec[] = []
for (const item of await Glob.scan("{plugin,plugins}/*.{ts,js}", { for (const item of await Glob.scan("{plugin,plugins}/*.{ts,js}", {
@@ -283,17 +282,17 @@ export namespace Config {
plugins.push(pathToFileURL(item).href) plugins.push(pathToFileURL(item).href)
} }
return plugins return plugins
} }
export function pluginSpecifier(plugin: PluginSpec): string { export function pluginSpecifier(plugin: PluginSpec): string {
return Array.isArray(plugin) ? plugin[0] : plugin return Array.isArray(plugin) ? plugin[0] : plugin
} }
export function pluginOptions(plugin: PluginSpec): PluginOptions | undefined { export function pluginOptions(plugin: PluginSpec): PluginOptions | undefined {
return Array.isArray(plugin) ? plugin[1] : undefined return Array.isArray(plugin) ? plugin[1] : undefined
} }
export async function resolvePluginSpec(plugin: PluginSpec, configFilepath: string): Promise<PluginSpec> { export async function resolvePluginSpec(plugin: PluginSpec, configFilepath: string): Promise<PluginSpec> {
const spec = pluginSpecifier(plugin) const spec = pluginSpecifier(plugin)
if (!isPathPluginSpec(spec)) return plugin if (!isPathPluginSpec(spec)) return plugin
@@ -308,9 +307,9 @@ export namespace Config {
if (Array.isArray(plugin)) return [resolved, plugin[1]] if (Array.isArray(plugin)) return [resolved, plugin[1]]
return resolved return resolved
} }
export function deduplicatePluginOrigins(plugins: PluginOrigin[]): PluginOrigin[] { export function deduplicatePluginOrigins(plugins: PluginOrigin[]): PluginOrigin[] {
const seen = new Set<string>() const seen = new Set<string>()
const list: PluginOrigin[] = [] const list: PluginOrigin[] = []
@@ -323,9 +322,9 @@ export namespace Config {
} }
return list.toReversed() return list.toReversed()
} }
export const McpLocal = z export const McpLocal = z
.object({ .object({
type: z.literal("local").describe("Type of MCP server connection"), type: z.literal("local").describe("Type of MCP server connection"),
command: z.string().array().describe("Command and arguments to run the MCP server"), command: z.string().array().describe("Command and arguments to run the MCP server"),
@@ -346,7 +345,7 @@ export namespace Config {
ref: "McpLocalConfig", ref: "McpLocalConfig",
}) })
export const McpOAuth = z export const McpOAuth = z
.object({ .object({
clientId: z clientId: z
.string() .string()
@@ -363,9 +362,9 @@ export namespace Config {
.meta({ .meta({
ref: "McpOAuthConfig", ref: "McpOAuthConfig",
}) })
export type McpOAuth = z.infer<typeof McpOAuth> export type McpOAuth = z.infer<typeof McpOAuth>
export const McpRemote = z export const McpRemote = z
.object({ .object({
type: z.literal("remote").describe("Type of MCP server connection"), type: z.literal("remote").describe("Type of MCP server connection"),
url: z.string().describe("URL of the remote MCP server"), url: z.string().describe("URL of the remote MCP server"),
@@ -374,9 +373,7 @@ export namespace Config {
oauth: z oauth: z
.union([McpOAuth, z.literal(false)]) .union([McpOAuth, z.literal(false)])
.optional() .optional()
.describe( .describe("OAuth authentication configuration for the MCP server. Set to false to disable OAuth auto-detection."),
"OAuth authentication configuration for the MCP server. Set to false to disable OAuth auto-detection.",
),
timeout: z timeout: z
.number() .number()
.int() .int()
@@ -389,33 +386,33 @@ export namespace Config {
ref: "McpRemoteConfig", ref: "McpRemoteConfig",
}) })
export const Mcp = z.discriminatedUnion("type", [McpLocal, McpRemote]) export const Mcp = z.discriminatedUnion("type", [McpLocal, McpRemote])
export type Mcp = z.infer<typeof Mcp> export type Mcp = z.infer<typeof Mcp>
export const PermissionAction = z.enum(["ask", "allow", "deny"]).meta({ export const PermissionAction = z.enum(["ask", "allow", "deny"]).meta({
ref: "PermissionActionConfig", ref: "PermissionActionConfig",
}) })
export type PermissionAction = z.infer<typeof PermissionAction> export type PermissionAction = z.infer<typeof PermissionAction>
export const PermissionObject = z.record(z.string(), PermissionAction).meta({ export const PermissionObject = z.record(z.string(), PermissionAction).meta({
ref: "PermissionObjectConfig", ref: "PermissionObjectConfig",
}) })
export type PermissionObject = z.infer<typeof PermissionObject> export type PermissionObject = z.infer<typeof PermissionObject>
export const PermissionRule = z.union([PermissionAction, PermissionObject]).meta({ export const PermissionRule = z.union([PermissionAction, PermissionObject]).meta({
ref: "PermissionRuleConfig", ref: "PermissionRuleConfig",
}) })
export type PermissionRule = z.infer<typeof PermissionRule> export type PermissionRule = z.infer<typeof PermissionRule>
// Capture original key order before zod reorders, then rebuild in original order // Capture original key order before zod reorders, then rebuild in original order
const permissionPreprocess = (val: unknown) => { const permissionPreprocess = (val: unknown) => {
if (typeof val === "object" && val !== null && !Array.isArray(val)) { if (typeof val === "object" && val !== null && !Array.isArray(val)) {
return { __originalKeys: Object.keys(val), ...val } return { __originalKeys: Object.keys(val), ...val }
} }
return val return val
} }
const permissionTransform = (x: unknown): Record<string, PermissionRule> => { const permissionTransform = (x: unknown): Record<string, PermissionRule> => {
if (typeof x === "string") return { "*": x as PermissionAction } if (typeof x === "string") return { "*": x as PermissionAction }
const obj = x as { __originalKeys?: string[] } & Record<string, unknown> const obj = x as { __originalKeys?: string[] } & Record<string, unknown>
const { __originalKeys, ...rest } = obj const { __originalKeys, ...rest } = obj
@@ -425,9 +422,9 @@ export namespace Config {
if (key in rest) result[key] = rest[key] as PermissionRule if (key in rest) result[key] = rest[key] as PermissionRule
} }
return result return result
} }
export const Permission = z export const Permission = z
.preprocess( .preprocess(
permissionPreprocess, permissionPreprocess,
z z
@@ -457,27 +454,27 @@ export namespace Config {
.meta({ .meta({
ref: "PermissionConfig", ref: "PermissionConfig",
}) })
export type Permission = z.infer<typeof Permission> export type Permission = z.infer<typeof Permission>
export const Command = z.object({ export const Command = z.object({
template: z.string(), template: z.string(),
description: z.string().optional(), description: z.string().optional(),
agent: z.string().optional(), agent: z.string().optional(),
model: ModelId.optional(), model: ModelId.optional(),
subtask: z.boolean().optional(), subtask: z.boolean().optional(),
}) })
export type Command = z.infer<typeof Command> export type Command = z.infer<typeof Command>
export const Skills = z.object({ export const Skills = z.object({
paths: z.array(z.string()).optional().describe("Additional paths to skill folders"), paths: z.array(z.string()).optional().describe("Additional paths to skill folders"),
urls: z urls: z
.array(z.string()) .array(z.string())
.optional() .optional()
.describe("URLs to fetch skills from (e.g., https://example.com/.well-known/skills/)"), .describe("URLs to fetch skills from (e.g., https://example.com/.well-known/skills/)"),
}) })
export type Skills = z.infer<typeof Skills> export type Skills = z.infer<typeof Skills>
export const Agent = z export const Agent = z
.object({ .object({
model: ModelId.optional(), model: ModelId.optional(),
variant: z variant: z
@@ -564,9 +561,9 @@ export namespace Config {
.meta({ .meta({
ref: "AgentConfig", ref: "AgentConfig",
}) })
export type Agent = z.infer<typeof Agent> export type Agent = z.infer<typeof Agent>
export const Keybinds = z export const Keybinds = z
.object({ .object({
leader: z.string().optional().default("ctrl+x").describe("Leader key for keybind combinations"), leader: z.string().optional().default("ctrl+x").describe("Leader key for keybind combinations"),
app_exit: z.string().optional().default("ctrl+c,ctrl+d,<leader>q").describe("Exit the application"), app_exit: z.string().optional().default("ctrl+c,ctrl+d,<leader>q").describe("Exit the application"),
@@ -599,11 +596,7 @@ export namespace Config {
messages_line_up: z.string().optional().default("ctrl+alt+y").describe("Scroll messages up by one line"), messages_line_up: z.string().optional().default("ctrl+alt+y").describe("Scroll messages up by one line"),
messages_line_down: z.string().optional().default("ctrl+alt+e").describe("Scroll messages down by one line"), messages_line_down: z.string().optional().default("ctrl+alt+e").describe("Scroll messages down by one line"),
messages_half_page_up: z.string().optional().default("ctrl+alt+u").describe("Scroll messages up by half page"), messages_half_page_up: z.string().optional().default("ctrl+alt+u").describe("Scroll messages up by half page"),
messages_half_page_down: z messages_half_page_down: z.string().optional().default("ctrl+alt+d").describe("Scroll messages down by half page"),
.string()
.optional()
.default("ctrl+alt+d")
.describe("Scroll messages down by half page"),
messages_first: z.string().optional().default("ctrl+g,home").describe("Navigate to first message"), messages_first: z.string().optional().default("ctrl+g,home").describe("Navigate to first message"),
messages_last: z.string().optional().default("ctrl+alt+g,end").describe("Navigate to last message"), messages_last: z.string().optional().default("ctrl+alt+g,end").describe("Navigate to last message"),
messages_next: z.string().optional().default("none").describe("Navigate to next message"), messages_next: z.string().optional().default("none").describe("Navigate to next message"),
@@ -647,11 +640,7 @@ export namespace Config {
input_select_down: z.string().optional().default("shift+down").describe("Select down in input"), input_select_down: z.string().optional().default("shift+down").describe("Select down in input"),
input_line_home: z.string().optional().default("ctrl+a").describe("Move to start of line in input"), input_line_home: z.string().optional().default("ctrl+a").describe("Move to start of line in input"),
input_line_end: z.string().optional().default("ctrl+e").describe("Move to end of line in input"), input_line_end: z.string().optional().default("ctrl+e").describe("Move to end of line in input"),
input_select_line_home: z input_select_line_home: z.string().optional().default("ctrl+shift+a").describe("Select to start of line in input"),
.string()
.optional()
.default("ctrl+shift+a")
.describe("Select to start of line in input"),
input_select_line_end: z.string().optional().default("ctrl+shift+e").describe("Select to end of line in input"), input_select_line_end: z.string().optional().default("ctrl+shift+e").describe("Select to end of line in input"),
input_visual_line_home: z.string().optional().default("alt+a").describe("Move to start of visual line in input"), input_visual_line_home: z.string().optional().default("alt+a").describe("Move to start of visual line in input"),
input_visual_line_end: z.string().optional().default("alt+e").describe("Move to end of visual line in input"), input_visual_line_end: z.string().optional().default("alt+e").describe("Move to end of visual line in input"),
@@ -727,7 +716,7 @@ export namespace Config {
ref: "KeybindsConfig", ref: "KeybindsConfig",
}) })
export const Server = z export const Server = z
.object({ .object({
port: z.number().int().positive().optional().describe("Port to listen on"), port: z.number().int().positive().optional().describe("Port to listen on"),
hostname: z.string().optional().describe("Hostname to listen on"), hostname: z.string().optional().describe("Hostname to listen on"),
@@ -740,12 +729,12 @@ export namespace Config {
ref: "ServerConfig", ref: "ServerConfig",
}) })
export const Layout = z.enum(["auto", "stretch"]).meta({ export const Layout = z.enum(["auto", "stretch"]).meta({
ref: "LayoutConfig", ref: "LayoutConfig",
}) })
export type Layout = z.infer<typeof Layout> export type Layout = z.infer<typeof Layout>
export const Model = z export const Model = z
.object({ .object({
id: z.string(), id: z.string(),
name: z.string(), name: z.string(),
@@ -811,7 +800,7 @@ export namespace Config {
}) })
.partial() .partial()
export const Provider = z export const Provider = z
.object({ .object({
api: z.string().optional(), api: z.string().optional(),
name: z.string(), name: z.string(),
@@ -860,9 +849,9 @@ export namespace Config {
ref: "ProviderConfig", ref: "ProviderConfig",
}) })
export type Provider = z.infer<typeof Provider> export type Provider = z.infer<typeof Provider>
export const Info = z export const Info = z
.object({ .object({
$schema: z.string().optional().describe("JSON schema reference for configuration validation"), $schema: z.string().optional().describe("JSON schema reference for configuration validation"),
logLevel: Log.Level.optional().describe("Log level"), logLevel: Log.Level.optional().describe("Log level"),
@@ -915,10 +904,7 @@ export namespace Config {
.describe( .describe(
"Default agent to use when none is specified. Must be a primary agent. Falls back to 'build' if not set or if the specified agent is invalid.", "Default agent to use when none is specified. Must be a primary agent. Falls back to 'build' if not set or if the specified agent is invalid.",
), ),
username: z username: z.string().optional().describe("Custom username to display in conversations instead of system username"),
.string()
.optional()
.describe("Custom username to display in conversations instead of system username"),
mode: z mode: z
.object({ .object({
build: Agent.optional(), build: Agent.optional(),
@@ -943,10 +929,7 @@ export namespace Config {
.catchall(Agent) .catchall(Agent)
.optional() .optional()
.describe("Agent configuration, see https://opencode.ai/docs/agents"), .describe("Agent configuration, see https://opencode.ai/docs/agents"),
provider: z provider: z.record(z.string(), Provider).optional().describe("Custom provider configurations and model overrides"),
.record(z.string(), Provider)
.optional()
.describe("Custom provider configurations and model overrides"),
mcp: z mcp: z
.record( .record(
z.string(), z.string(),
@@ -1059,18 +1042,18 @@ export namespace Config {
ref: "Config", ref: "Config",
}) })
export type Info = z.output<typeof Info> & { export type Info = z.output<typeof Info> & {
plugin_origins?: PluginOrigin[] plugin_origins?: PluginOrigin[]
} }
type State = { type State = {
config: Info config: Info
directories: string[] directories: string[]
deps: Fiber.Fiber<void, never>[] deps: Fiber.Fiber<void, never>[]
consoleState: ConsoleState consoleState: ConsoleState
} }
export interface Interface { export interface Interface {
readonly get: () => Effect.Effect<Info> readonly get: () => Effect.Effect<Info>
readonly getGlobal: () => Effect.Effect<Info> readonly getGlobal: () => Effect.Effect<Info>
readonly getConsoleState: () => Effect.Effect<ConsoleState> readonly getConsoleState: () => Effect.Effect<ConsoleState>
@@ -1080,11 +1063,11 @@ export namespace Config {
readonly invalidate: (wait?: boolean) => Effect.Effect<void> readonly invalidate: (wait?: boolean) => Effect.Effect<void>
readonly directories: () => Effect.Effect<string[]> readonly directories: () => Effect.Effect<string[]>
readonly waitForDependencies: () => Effect.Effect<void> readonly waitForDependencies: () => Effect.Effect<void>
} }
export class Service extends Context.Service<Service, Interface>()("@opencode/Config") {} export class Service extends Context.Service<Service, Interface>()("@opencode/Config") {}
function globalConfigFile() { function globalConfigFile() {
const candidates = ["opencode.jsonc", "opencode.json", "config.json"].map((file) => const candidates = ["opencode.jsonc", "opencode.json", "config.json"].map((file) =>
path.join(Global.Path.config, file), path.join(Global.Path.config, file),
) )
@@ -1092,9 +1075,9 @@ export namespace Config {
if (existsSync(file)) return file if (existsSync(file)) return file
} }
return candidates[0] return candidates[0]
} }
function patchJsonc(input: string, patch: unknown, path: string[] = []): string { function patchJsonc(input: string, patch: unknown, path: string[] = []): string {
if (!isRecord(patch)) { if (!isRecord(patch)) {
const edits = modify(input, path, patch, { const edits = modify(input, path, patch, {
formattingOptions: { formattingOptions: {
@@ -1109,14 +1092,14 @@ export namespace Config {
if (value === undefined) return result if (value === undefined) return result
return patchJsonc(result, value, [...path, key]) return patchJsonc(result, value, [...path, key])
}, input) }, input)
} }
function writable(info: Info) { function writable(info: Info) {
const { plugin_origins, ...next } = info const { plugin_origins, ...next } = info
return next return next
} }
function parseConfig(text: string, filepath: string): Info { function parseConfig(text: string, filepath: string): Info {
const errors: JsoncParseError[] = [] const errors: JsoncParseError[] = []
const data = parseJsonc(text, errors, { allowTrailingComma: true }) const data = parseJsonc(text, errors, { allowTrailingComma: true })
if (errors.length) { if (errors.length) {
@@ -1148,24 +1131,21 @@ export namespace Config {
path: filepath, path: filepath,
issues: parsed.error.issues, issues: parsed.error.issues,
}) })
} }
export const { JsonError, InvalidError } = ConfigPaths export const { JsonError, InvalidError } = ConfigPaths
export const ConfigDirectoryTypoError = NamedError.create( export const ConfigDirectoryTypoError = NamedError.create(
"ConfigDirectoryTypoError", "ConfigDirectoryTypoError",
z.object({ z.object({
path: z.string(), path: z.string(),
dir: z.string(), dir: z.string(),
suggestion: z.string(), suggestion: z.string(),
}), }),
) )
export const layer: Layer.Layer< export const layer: Layer.Layer<Service, never, AppFileSystem.Service | Auth.Service | Account.Service | Env.Service> =
Service, Layer.effect(
never,
AppFileSystem.Service | Auth.Service | Account.Service | Env.Service
> = Layer.effect(
Service, Service,
Effect.gen(function* () { Effect.gen(function* () {
const fs = yield* AppFileSystem.Service const fs = yield* AppFileSystem.Service
@@ -1531,9 +1511,9 @@ export namespace Config {
} }
if (result.tools) { if (result.tools) {
const perms: Record<string, Config.PermissionAction> = {} const perms: Record<string, PermissionAction> = {}
for (const [tool, enabled] of Object.entries(result.tools)) { for (const [tool, enabled] of Object.entries(result.tools)) {
const action: Config.PermissionAction = enabled ? "allow" : "deny" const action: PermissionAction = enabled ? "allow" : "deny"
if (tool === "write" || tool === "edit" || tool === "patch" || tool === "multiedit") { if (tool === "write" || tool === "edit" || tool === "patch" || tool === "multiedit") {
perms.edit = action perms.edit = action
continue continue
@@ -1654,10 +1634,9 @@ export namespace Config {
}), }),
) )
export const defaultLayer = layer.pipe( export const defaultLayer = layer.pipe(
Layer.provide(AppFileSystem.defaultLayer), Layer.provide(AppFileSystem.defaultLayer),
Layer.provide(Env.defaultLayer), Layer.provide(Env.defaultLayer),
Layer.provide(Auth.defaultLayer), Layer.provide(Auth.defaultLayer),
Layer.provide(Account.defaultLayer), Layer.provide(Account.defaultLayer),
) )
}
+1
View File
@@ -0,0 +1 @@
export * as Config from "./config"
+1 -1
View File
@@ -1,5 +1,5 @@
import z from "zod" import z from "zod"
import { Config } from "./config" import { Config } from "."
const KeybindOverride = z const KeybindOverride = z
.object( .object(
+1 -1
View File
@@ -2,7 +2,7 @@ import { existsSync } from "fs"
import z from "zod" import z from "zod"
import { mergeDeep, unique } from "remeda" import { mergeDeep, unique } from "remeda"
import { Context, Effect, Fiber, Layer } from "effect" import { Context, Effect, Fiber, Layer } from "effect"
import { Config } from "./config" import { Config } from "."
import { ConfigPaths } from "./paths" import { ConfigPaths } from "./paths"
import { migrateTuiConfig } from "./tui-migrate" import { migrateTuiConfig } from "./tui-migrate"
import { TuiInfo } from "./tui-schema" import { TuiInfo } from "./tui-schema"
+1 -1
View File
@@ -6,7 +6,7 @@ import { AppFileSystem } from "@opencode-ai/shared/filesystem"
import { Bus } from "@/bus" import { Bus } from "@/bus"
import { Auth } from "@/auth" import { Auth } from "@/auth"
import { Account } from "@/account" import { Account } from "@/account"
import { Config } from "@/config/config" import { Config } from "@/config"
import { Git } from "@/git" import { Git } from "@/git"
import { Ripgrep } from "@/file/ripgrep" import { Ripgrep } from "@/file/ripgrep"
import { FileTime } from "@/file/time" import { FileTime } from "@/file/time"
+1 -1
View File
@@ -12,7 +12,7 @@ import { Flag } from "@/flag/flag"
import { Git } from "@/git" import { Git } from "@/git"
import { Instance } from "@/project/instance" import { Instance } from "@/project/instance"
import { lazy } from "@/util/lazy" import { lazy } from "@/util/lazy"
import { Config } from "../config/config" import { Config } from "../config"
import { FileIgnore } from "./ignore" import { FileIgnore } from "./ignore"
import { Protected } from "./protected" import { Protected } from "./protected"
import { Log } from "../util/log" import { Log } from "../util/log"
+1 -1
View File
@@ -5,7 +5,7 @@ import { InstanceState } from "@/effect/instance-state"
import path from "path" import path from "path"
import { mergeDeep } from "remeda" import { mergeDeep } from "remeda"
import z from "zod" import z from "zod"
import { Config } from "../config/config" import { Config } from "../config"
import { Instance } from "../project/instance" import { Instance } from "../project/instance"
import { Log } from "../util/log" import { Log } from "../util/log"
import * as Formatter from "./formatter" import * as Formatter from "./formatter"
+1 -1
View File
@@ -6,7 +6,7 @@ import path from "path"
import { pathToFileURL, fileURLToPath } from "url" import { pathToFileURL, fileURLToPath } from "url"
import { LSPServer } from "./server" import { LSPServer } from "./server"
import z from "zod" import z from "zod"
import { Config } from "../config/config" import { Config } from "../config"
import { Instance } from "../project/instance" import { Instance } from "../project/instance"
import { Flag } from "@/flag/flag" import { Flag } from "@/flag/flag"
import { Process } from "../util/process" import { Process } from "../util/process"
+1 -1
View File
@@ -9,7 +9,7 @@ import {
type Tool as MCPToolDef, type Tool as MCPToolDef,
ToolListChangedNotificationSchema, ToolListChangedNotificationSchema,
} from "@modelcontextprotocol/sdk/types.js" } from "@modelcontextprotocol/sdk/types.js"
import { Config } from "../config/config" import { Config } from "../config"
import { Log } from "../util/log" import { Log } from "../util/log"
import { NamedError } from "@opencode-ai/shared/util/error" import { NamedError } from "@opencode-ai/shared/util/error"
import z from "zod/v4" import z from "zod/v4"
+1 -1
View File
@@ -1,4 +1,4 @@
export { Config } from "./config/config" export { Config } from "./config"
export { Server } from "./server/server" export { Server } from "./server/server"
export { bootstrap } from "./cli/bootstrap" export { bootstrap } from "./cli/bootstrap"
export { Log } from "./util/log" export { Log } from "./util/log"
+1 -1
View File
@@ -1,6 +1,6 @@
import { Bus } from "@/bus" import { Bus } from "@/bus"
import { BusEvent } from "@/bus/bus-event" import { BusEvent } from "@/bus/bus-event"
import { Config } from "@/config/config" import { Config } from "@/config"
import { InstanceState } from "@/effect/instance-state" import { InstanceState } from "@/effect/instance-state"
import { ProjectID } from "@/project/schema" import { ProjectID } from "@/project/schema"
import { Instance } from "@/project/instance" import { Instance } from "@/project/instance"
+1 -1
View File
@@ -5,7 +5,7 @@ import type {
PluginModule, PluginModule,
WorkspaceAdaptor as PluginWorkspaceAdaptor, WorkspaceAdaptor as PluginWorkspaceAdaptor,
} from "@opencode-ai/plugin" } from "@opencode-ai/plugin"
import { Config } from "../config/config" import { Config } from "../config"
import { Bus } from "../bus" import { Bus } from "../bus"
import { Log } from "../util/log" import { Log } from "../util/log"
import { createOpencodeClient } from "@opencode-ai/sdk" import { createOpencodeClient } from "@opencode-ai/sdk"
+1 -1
View File
@@ -1,4 +1,4 @@
import { Config } from "@/config/config" import { Config } from "@/config"
import { Installation } from "@/installation" import { Installation } from "@/installation"
import { import {
checkPluginCompatibility, checkPluginCompatibility,
+1 -1
View File
@@ -1,7 +1,7 @@
import z from "zod" import z from "zod"
import os from "os" import os from "os"
import fuzzysort from "fuzzysort" import fuzzysort from "fuzzysort"
import { Config } from "../config/config" import { Config } from "../config"
import { mapValues, mergeDeep, omit, pickBy, sortBy } from "remeda" import { mapValues, mergeDeep, omit, pickBy, sortBy } from "remeda"
import { NoSuchModelError, type Provider as SDK } from "ai" import { NoSuchModelError, type Provider as SDK } from "ai"
import { Log } from "../util/log" import { Log } from "../util/log"
@@ -1,7 +1,7 @@
import { Hono } from "hono" import { Hono } from "hono"
import { describeRoute, validator, resolver } from "hono-openapi" import { describeRoute, validator, resolver } from "hono-openapi"
import z from "zod" import z from "zod"
import { Config } from "../../config/config" import { Config } from "../../config"
import { Provider } from "../../provider/provider" import { Provider } from "../../provider/provider"
import { mapValues } from "remeda" import { mapValues } from "remeda"
import { errors } from "../error" import { errors } from "../error"
@@ -8,7 +8,7 @@ import { Instance } from "../../project/instance"
import { Project } from "../../project/project" import { Project } from "../../project/project"
import { MCP } from "../../mcp" import { MCP } from "../../mcp"
import { Session } from "../../session" import { Session } from "../../session"
import { Config } from "../../config/config" import { Config } from "../../config"
import { ConsoleState } from "../../config/console-state" import { ConsoleState } from "../../config/console-state"
import { Account, AccountID, OrgID } from "../../account" import { Account, AccountID, OrgID } from "../../account"
import { AppRuntime } from "../../effect/app-runtime" import { AppRuntime } from "../../effect/app-runtime"
@@ -12,7 +12,7 @@ import { Instance } from "../../project/instance"
import { Installation } from "@/installation" import { Installation } from "@/installation"
import { Log } from "../../util/log" import { Log } from "../../util/log"
import { lazy } from "../../util/lazy" import { lazy } from "../../util/lazy"
import { Config } from "../../config/config" import { Config } from "../../config"
import { errors } from "../error" import { errors } from "../error"
const log = Log.create({ service: "server" }) const log = Log.create({ service: "server" })
+1 -1
View File
@@ -2,7 +2,7 @@ import { Hono } from "hono"
import { describeRoute, validator, resolver } from "hono-openapi" import { describeRoute, validator, resolver } from "hono-openapi"
import z from "zod" import z from "zod"
import { MCP } from "../../mcp" import { MCP } from "../../mcp"
import { Config } from "../../config/config" import { Config } from "../../config"
import { AppRuntime } from "../../effect/app-runtime" import { AppRuntime } from "../../effect/app-runtime"
import { errors } from "../error" import { errors } from "../error"
import { lazy } from "../../util/lazy" import { lazy } from "../../util/lazy"
@@ -1,7 +1,7 @@
import { Hono } from "hono" import { Hono } from "hono"
import { describeRoute, validator, resolver } from "hono-openapi" import { describeRoute, validator, resolver } from "hono-openapi"
import z from "zod" import z from "zod"
import { Config } from "../../config/config" import { Config } from "../../config"
import { Provider } from "../../provider/provider" import { Provider } from "../../provider/provider"
import { ModelsDev } from "../../provider/models" import { ModelsDev } from "../../provider/models"
import { ProviderAuth } from "../../provider/auth" import { ProviderAuth } from "../../provider/auth"
+1 -1
View File
@@ -11,7 +11,7 @@ import { Log } from "../util/log"
import { SessionProcessor } from "./processor" import { SessionProcessor } from "./processor"
import { Agent } from "@/agent/agent" import { Agent } from "@/agent/agent"
import { Plugin } from "@/plugin" import { Plugin } from "@/plugin"
import { Config } from "@/config/config" import { Config } from "@/config"
import { NotFoundError } from "@/storage/db" import { NotFoundError } from "@/storage/db"
import { ModelID, ProviderID } from "@/provider/schema" import { ModelID, ProviderID } from "@/provider/schema"
import { Effect, Layer, Context } from "effect" import { Effect, Layer, Context } from "effect"
+1 -1
View File
@@ -2,7 +2,7 @@ import os from "os"
import path from "path" import path from "path"
import { Effect, Layer, Context } from "effect" import { Effect, Layer, Context } from "effect"
import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/unstable/http" import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/unstable/http"
import { Config } from "@/config/config" import { Config } from "@/config"
import { InstanceState } from "@/effect/instance-state" import { InstanceState } from "@/effect/instance-state"
import { Flag } from "@/flag/flag" import { Flag } from "@/flag/flag"
import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { AppFileSystem } from "@opencode-ai/shared/filesystem"
+1 -1
View File
@@ -6,7 +6,7 @@ import { streamText, wrapLanguageModel, type ModelMessage, type Tool, tool, json
import { mergeDeep, pipe } from "remeda" import { mergeDeep, pipe } from "remeda"
import { GitLabWorkflowLanguageModel } from "gitlab-ai-provider" import { GitLabWorkflowLanguageModel } from "gitlab-ai-provider"
import { ProviderTransform } from "@/provider/transform" import { ProviderTransform } from "@/provider/transform"
import { Config } from "@/config/config" import { Config } from "@/config"
import { Instance } from "@/project/instance" import { Instance } from "@/project/instance"
import type { Agent } from "@/agent/agent" import type { Agent } from "@/agent/agent"
import type { MessageV2 } from "./message-v2" import type { MessageV2 } from "./message-v2"
+1 -1
View File
@@ -1,4 +1,4 @@
import type { Config } from "@/config/config" import type { Config } from "@/config"
import type { Provider } from "@/provider/provider" import type { Provider } from "@/provider/provider"
import { ProviderTransform } from "@/provider/transform" import { ProviderTransform } from "@/provider/transform"
import type { MessageV2 } from "./message-v2" import type { MessageV2 } from "./message-v2"
+1 -1
View File
@@ -2,7 +2,7 @@ import { Cause, Deferred, Effect, Layer, Context, Scope } from "effect"
import * as Stream from "effect/Stream" import * as Stream from "effect/Stream"
import { Agent } from "@/agent/agent" import { Agent } from "@/agent/agent"
import { Bus } from "@/bus" import { Bus } from "@/bus"
import { Config } from "@/config/config" import { Config } from "@/config"
import { Permission } from "@/permission" import { Permission } from "@/permission"
import { Plugin } from "@/plugin" import { Plugin } from "@/plugin"
import { Snapshot } from "@/snapshot" import { Snapshot } from "@/snapshot"
+1 -1
View File
@@ -2,7 +2,7 @@ import { Session } from "@/session"
import { SessionID } from "@/session/schema" import { SessionID } from "@/session/schema"
import { SyncEvent } from "@/sync" import { SyncEvent } from "@/sync"
import { Effect, Layer, Scope, Context } from "effect" import { Effect, Layer, Scope, Context } from "effect"
import { Config } from "../config/config" import { Config } from "../config"
import { Flag } from "../flag/flag" import { Flag } from "../flag/flag"
import { ShareNext } from "./share-next" import { ShareNext } from "./share-next"
+1 -1
View File
@@ -10,7 +10,7 @@ import { Session } from "@/session"
import { MessageV2 } from "@/session/message-v2" import { MessageV2 } from "@/session/message-v2"
import type { SessionID } from "@/session/schema" import type { SessionID } from "@/session/schema"
import { Database, eq } from "@/storage/db" import { Database, eq } from "@/storage/db"
import { Config } from "@/config/config" import { Config } from "@/config"
import { Log } from "@/util/log" import { Log } from "@/util/log"
import { SessionShareTable } from "./share.sql" import { SessionShareTable } from "./share.sql"
+1 -1
View File
@@ -11,7 +11,7 @@ import { Flag } from "@/flag/flag"
import { Global } from "@/global" import { Global } from "@/global"
import { Permission } from "@/permission" import { Permission } from "@/permission"
import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { AppFileSystem } from "@opencode-ai/shared/filesystem"
import { Config } from "../config/config" import { Config } from "../config"
import { ConfigMarkdown } from "../config/markdown" import { ConfigMarkdown } from "../config/markdown"
import { Glob } from "@opencode-ai/shared/util/glob" import { Glob } from "@opencode-ai/shared/util/glob"
import { Log } from "../util/log" import { Log } from "../util/log"
+1 -1
View File
@@ -7,7 +7,7 @@ import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
import { InstanceState } from "@/effect/instance-state" import { InstanceState } from "@/effect/instance-state"
import { AppFileSystem } from "@opencode-ai/shared/filesystem" import { AppFileSystem } from "@opencode-ai/shared/filesystem"
import { Hash } from "@opencode-ai/shared/util/hash" import { Hash } from "@opencode-ai/shared/util/hash"
import { Config } from "../config/config" import { Config } from "../config"
import { Global } from "../global" import { Global } from "../global"
import { Log } from "../util/log" import { Log } from "../util/log"
+1 -1
View File
@@ -13,7 +13,7 @@ import { WriteTool } from "./write"
import { InvalidTool } from "./invalid" import { InvalidTool } from "./invalid"
import { SkillTool } from "./skill" import { SkillTool } from "./skill"
import { Tool } from "./tool" import { Tool } from "./tool"
import { Config } from "../config/config" import { Config } from "../config"
import { type ToolContext as PluginToolContext, type ToolDefinition } from "@opencode-ai/plugin" import { type ToolContext as PluginToolContext, type ToolDefinition } from "@opencode-ai/plugin"
import z from "zod" import z from "zod"
import { Plugin } from "../plugin" import { Plugin } from "../plugin"
+1 -1
View File
@@ -6,7 +6,7 @@ import { SessionID, MessageID } from "../session/schema"
import { MessageV2 } from "../session/message-v2" import { MessageV2 } from "../session/message-v2"
import { Agent } from "../agent/agent" import { Agent } from "../agent/agent"
import type { SessionPrompt } from "../session/prompt" import type { SessionPrompt } from "../session/prompt"
import { Config } from "../config/config" import { Config } from "../config"
import { Effect } from "effect" import { Effect } from "effect"
import { Log } from "@/util/log" import { Log } from "@/util/log"
@@ -3,7 +3,7 @@ import { Effect } from "effect"
import path from "path" import path from "path"
import { provideInstance, tmpdir } from "../fixture/fixture" import { provideInstance, tmpdir } from "../fixture/fixture"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { Config } from "../../src/config/config" import { Config } from "../../src/config"
import { Agent as AgentSvc } from "../../src/agent/agent" import { Agent as AgentSvc } from "../../src/agent/agent"
import { Color } from "../../src/util/color" import { Color } from "../../src/util/color"
import { AppRuntime } from "../../src/effect/app-runtime" import { AppRuntime } from "../../src/effect/app-runtime"
+1 -1
View File
@@ -1,7 +1,7 @@
import { test, expect, describe, mock, afterEach, beforeEach, spyOn } from "bun:test" import { test, expect, describe, mock, afterEach, beforeEach, spyOn } from "bun:test"
import { Deferred, Effect, Fiber, Layer, Option } from "effect" import { Deferred, Effect, Fiber, Layer, Option } from "effect"
import { NodeFileSystem, NodePath } from "@effect/platform-node" import { NodeFileSystem, NodePath } from "@effect/platform-node"
import { Config } from "../../src/config/config" import { Config } from "../../src/config"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { Auth } from "../../src/auth" import { Auth } from "../../src/auth"
import { AccessToken, Account, AccountID, OrgID } from "../../src/account" import { AccessToken, Account, AccountID, OrgID } from "../../src/account"
+1 -1
View File
@@ -3,7 +3,7 @@ import path from "path"
import fs from "fs/promises" import fs from "fs/promises"
import { tmpdir } from "../fixture/fixture" import { tmpdir } from "../fixture/fixture"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { Config } from "../../src/config/config" import { Config } from "../../src/config"
import { TuiConfig } from "../../src/config/tui" import { TuiConfig } from "../../src/config/tui"
import { Global } from "../../src/global" import { Global } from "../../src/global"
import { Filesystem } from "../../src/util/filesystem" import { Filesystem } from "../../src/util/filesystem"
+1 -1
View File
@@ -5,7 +5,7 @@ import path from "path"
import { ConfigProvider, Deferred, Effect, Layer, ManagedRuntime, Option } from "effect" import { ConfigProvider, Deferred, Effect, Layer, ManagedRuntime, Option } from "effect"
import { tmpdir } from "../fixture/fixture" import { tmpdir } from "../fixture/fixture"
import { Bus } from "../../src/bus" import { Bus } from "../../src/bus"
import { Config } from "../../src/config/config" import { Config } from "../../src/config"
import { FileWatcher } from "../../src/file/watcher" import { FileWatcher } from "../../src/file/watcher"
import { Git } from "../../src/git" import { Git } from "../../src/git"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
+1 -1
View File
@@ -6,7 +6,7 @@ import { Effect, Context } from "effect"
import type * as PlatformError from "effect/PlatformError" import type * as PlatformError from "effect/PlatformError"
import type * as Scope from "effect/Scope" import type * as Scope from "effect/Scope"
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process" import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
import type { Config } from "../../src/config/config" import type { Config } from "../../src/config"
import { InstanceRef } from "../../src/effect/instance-ref" import { InstanceRef } from "../../src/effect/instance-ref"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { TestLLMServer } from "../lib/llm-server" import { TestLLMServer } from "../lib/llm-server"
@@ -1,6 +1,6 @@
import { afterEach, describe, test, expect } from "bun:test" import { afterEach, describe, test, expect } from "bun:test"
import { Permission } from "../src/permission" import { Permission } from "../src/permission"
import { Config } from "../src/config/config" import { Config } from "../src/config"
import { Instance } from "../src/project/instance" import { Instance } from "../src/project/instance"
import { tmpdir } from "./fixture/fixture" import { tmpdir } from "./fixture/fixture"
import { AppRuntime } from "../src/effect/app-runtime" import { AppRuntime } from "../src/effect/app-runtime"
@@ -5,7 +5,7 @@ import * as Stream from "effect/Stream"
import path from "path" import path from "path"
import z from "zod" import z from "zod"
import { Bus } from "../../src/bus" import { Bus } from "../../src/bus"
import { Config } from "../../src/config/config" import { Config } from "../../src/config"
import { Agent } from "../../src/agent/agent" import { Agent } from "../../src/agent/agent"
import { LLM } from "../../src/session/llm" import { LLM } from "../../src/session/llm"
import { SessionCompaction } from "../../src/session/compaction" import { SessionCompaction } from "../../src/session/compaction"
@@ -5,7 +5,7 @@ import path from "path"
import type { Agent } from "../../src/agent/agent" import type { Agent } from "../../src/agent/agent"
import { Agent as AgentSvc } from "../../src/agent/agent" import { Agent as AgentSvc } from "../../src/agent/agent"
import { Bus } from "../../src/bus" import { Bus } from "../../src/bus"
import { Config } from "../../src/config/config" import { Config } from "../../src/config"
import { Permission } from "../../src/permission" import { Permission } from "../../src/permission"
import { Plugin } from "../../src/plugin" import { Plugin } from "../../src/plugin"
import { Provider } from "../../src/provider/provider" import { Provider } from "../../src/provider/provider"
@@ -7,7 +7,7 @@ import z from "zod"
import { Agent as AgentSvc } from "../../src/agent/agent" import { Agent as AgentSvc } from "../../src/agent/agent"
import { Bus } from "../../src/bus" import { Bus } from "../../src/bus"
import { Command } from "../../src/command" import { Command } from "../../src/command"
import { Config } from "../../src/config/config" import { Config } from "../../src/config"
import { FileTime } from "../../src/file/time" import { FileTime } from "../../src/file/time"
import { LSP } from "../../src/lsp" import { LSP } from "../../src/lsp"
import { MCP } from "../../src/mcp" import { MCP } from "../../src/mcp"
@@ -32,7 +32,7 @@ import { NodeFileSystem } from "@effect/platform-node"
import { Agent as AgentSvc } from "../../src/agent/agent" import { Agent as AgentSvc } from "../../src/agent/agent"
import { Bus } from "../../src/bus" import { Bus } from "../../src/bus"
import { Command } from "../../src/command" import { Command } from "../../src/command"
import { Config } from "../../src/config/config" import { Config } from "../../src/config"
import { FileTime } from "../../src/file/time" import { FileTime } from "../../src/file/time"
import { LSP } from "../../src/lsp" import { LSP } from "../../src/lsp"
import { MCP } from "../../src/mcp" import { MCP } from "../../src/mcp"
@@ -8,7 +8,7 @@ import { Account } from "../../src/account"
import { AccountRepo } from "../../src/account/repo" import { AccountRepo } from "../../src/account/repo"
import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner" import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
import { Bus } from "../../src/bus" import { Bus } from "../../src/bus"
import { Config } from "../../src/config/config" import { Config } from "../../src/config"
import { Provider } from "../../src/provider/provider" import { Provider } from "../../src/provider/provider"
import { Session } from "../../src/session" import { Session } from "../../src/session"
import type { SessionID } from "../../src/session/schema" import type { SessionID } from "../../src/session/schema"
+1 -1
View File
@@ -1,7 +1,7 @@
import { afterEach, describe, expect } from "bun:test" import { afterEach, describe, expect } from "bun:test"
import { Effect, Layer } from "effect" import { Effect, Layer } from "effect"
import { Agent } from "../../src/agent/agent" import { Agent } from "../../src/agent/agent"
import { Config } from "../../src/config/config" import { Config } from "../../src/config"
import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner" import * as CrossSpawnSpawner from "../../src/effect/cross-spawn-spawner"
import { Instance } from "../../src/project/instance" import { Instance } from "../../src/project/instance"
import { Session } from "../../src/session" import { Session } from "../../src/session"