perf: make OpenCode config defaults non-blocking
Removes startup blocking on OpenCode config defaults Preserves manual and directory-specific model selections Adds regression coverage for config races
This commit is contained in:
@@ -2,6 +2,7 @@ import type { OpencodeClient, PermissionRequest, Project, QuestionRequest } from
|
||||
import { retry } from "./retry"
|
||||
import type { GlobalState, State } from "./types"
|
||||
import { runtimeFetch } from "../lib/runtime-fetch"
|
||||
import { emitSyncConfigChanged } from "./sync-refs"
|
||||
|
||||
const cmp = (a: string, b: string) => (a < b ? -1 : a > b ? 1 : 0)
|
||||
|
||||
@@ -135,7 +136,9 @@ export async function bootstrapDirectory(input: {
|
||||
const seededProject = projectID(directory, g.projects)
|
||||
if (seededProject) set({ project: seededProject })
|
||||
if (Object.keys(state.config ?? {}).length === 0 && Object.keys(g.config ?? {}).length > 0) {
|
||||
set({ config: g.config as State["config"] })
|
||||
const seededConfig = g.config as State["config"]
|
||||
set({ config: seededConfig })
|
||||
emitSyncConfigChanged(directory, seededConfig)
|
||||
}
|
||||
if (loading) set({ status: "partial" })
|
||||
|
||||
@@ -147,7 +150,11 @@ export async function bootstrapDirectory(input: {
|
||||
seededProject
|
||||
? Promise.resolve()
|
||||
: retry(() => sdk.project.current().then((x) => set({ project: unwrap(x, "project.current").id }))),
|
||||
retry(() => sdk.config.get().then((x) => set({ config: unwrap(x, "config.get") }))),
|
||||
retry(() => sdk.config.get().then((x) => {
|
||||
const config = unwrap(x, "config.get")
|
||||
set({ config })
|
||||
emitSyncConfigChanged(directory, config)
|
||||
})),
|
||||
retry(() =>
|
||||
sdk.path.get().then((x) => {
|
||||
const data = unwrap(x, "path.get")
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* session-actions) use them to read child-store domain data without hooks.
|
||||
*/
|
||||
|
||||
import type { OpencodeClient } from "@opencode-ai/sdk/v2/client"
|
||||
import type { Config, OpencodeClient } from "@opencode-ai/sdk/v2/client"
|
||||
import type { ChildStoreManager } from "./child-store"
|
||||
import { getSessionMaterializationStatus } from "./materialization"
|
||||
import type { State } from "./types"
|
||||
@@ -14,6 +14,7 @@ let _sdk: OpencodeClient | null = null
|
||||
let _childStores: ChildStoreManager | null = null
|
||||
let _directory: string = ""
|
||||
let _registerSessionDirectory: ((sessionID: string, directory: string) => void) | null = null
|
||||
const configListeners = new Set<(directory: string, config: Config) => void>()
|
||||
|
||||
export function setSyncRefs(
|
||||
sdk: OpencodeClient,
|
||||
@@ -59,6 +60,26 @@ export function getDirectoryState(directory?: string): State | undefined {
|
||||
return stores.getState(dir)
|
||||
}
|
||||
|
||||
/** Read resolved OpenCode config from a directory child store, if bootstrapped. */
|
||||
export function getSyncConfig(directory?: string): Config | undefined {
|
||||
const config = getDirectoryState(directory)?.config
|
||||
return config && Object.keys(config).length > 0 ? config : undefined
|
||||
}
|
||||
|
||||
export function subscribeToSyncConfigChanges(listener: (directory: string, config: Config) => void): () => void {
|
||||
configListeners.add(listener)
|
||||
return () => {
|
||||
configListeners.delete(listener)
|
||||
}
|
||||
}
|
||||
|
||||
export function emitSyncConfigChanged(directory: string, config: Config): void {
|
||||
if (!directory) return
|
||||
for (const listener of configListeners) {
|
||||
listener(directory, config)
|
||||
}
|
||||
}
|
||||
|
||||
/** Read sessions from current directory's child store */
|
||||
export function getSyncSessions(directory?: string) {
|
||||
return getDirectoryState(directory)?.session ?? []
|
||||
|
||||
Reference in New Issue
Block a user