chore(app): global config changes
This commit is contained in:
@@ -188,7 +188,74 @@ function createGlobalSync() {
|
|||||||
config: {},
|
config: {},
|
||||||
reload: undefined,
|
reload: undefined,
|
||||||
})
|
})
|
||||||
let bootstrapQueue: string[] = []
|
|
||||||
|
const queued = new Set<string>()
|
||||||
|
let root = false
|
||||||
|
let running = false
|
||||||
|
let timer: ReturnType<typeof setTimeout> | undefined
|
||||||
|
|
||||||
|
const paused = () => untrack(() => globalStore.reload) !== undefined
|
||||||
|
|
||||||
|
const tick = () => new Promise<void>((resolve) => setTimeout(resolve, 0))
|
||||||
|
|
||||||
|
const take = (count: number) => {
|
||||||
|
if (queued.size === 0) return [] as string[]
|
||||||
|
const items: string[] = []
|
||||||
|
for (const item of queued) {
|
||||||
|
queued.delete(item)
|
||||||
|
items.push(item)
|
||||||
|
if (items.length >= count) break
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
const schedule = () => {
|
||||||
|
if (timer) return
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
timer = undefined
|
||||||
|
void drain()
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
const push = (directory: string) => {
|
||||||
|
if (!directory) return
|
||||||
|
queued.add(directory)
|
||||||
|
if (paused()) return
|
||||||
|
schedule()
|
||||||
|
}
|
||||||
|
|
||||||
|
const refresh = () => {
|
||||||
|
root = true
|
||||||
|
if (paused()) return
|
||||||
|
schedule()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function drain() {
|
||||||
|
if (running) return
|
||||||
|
running = true
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
if (paused()) return
|
||||||
|
|
||||||
|
if (root) {
|
||||||
|
root = false
|
||||||
|
await bootstrap()
|
||||||
|
await tick()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const dirs = take(2)
|
||||||
|
if (dirs.length === 0) return
|
||||||
|
|
||||||
|
await Promise.all(dirs.map((dir) => bootstrapInstance(dir)))
|
||||||
|
await tick()
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
running = false
|
||||||
|
if (paused()) return
|
||||||
|
if (root || queued.size) schedule()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (!projectCacheReady()) return
|
if (!projectCacheReady()) return
|
||||||
@@ -210,14 +277,8 @@ function createGlobalSync() {
|
|||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
if (globalStore.reload !== "complete") return
|
if (globalStore.reload !== "complete") return
|
||||||
if (bootstrapQueue.length) {
|
|
||||||
for (const directory of bootstrapQueue) {
|
|
||||||
bootstrapInstance(directory)
|
|
||||||
}
|
|
||||||
bootstrap()
|
|
||||||
}
|
|
||||||
bootstrapQueue = []
|
|
||||||
setGlobalStore("reload", undefined)
|
setGlobalStore("reload", undefined)
|
||||||
|
refresh()
|
||||||
})
|
})
|
||||||
|
|
||||||
const children: Record<string, [Store<State>, SetStoreFunction<State>]> = {}
|
const children: Record<string, [Store<State>, SetStoreFunction<State>]> = {}
|
||||||
@@ -584,9 +645,8 @@ function createGlobalSync() {
|
|||||||
if (directory === "global") {
|
if (directory === "global") {
|
||||||
switch (event?.type) {
|
switch (event?.type) {
|
||||||
case "global.disposed": {
|
case "global.disposed": {
|
||||||
if (globalStore.reload) return
|
refresh()
|
||||||
bootstrap()
|
return
|
||||||
break
|
|
||||||
}
|
}
|
||||||
case "project.updated": {
|
case "project.updated": {
|
||||||
const result = Binary.search(globalStore.project, event.properties.id, (s) => s.id)
|
const result = Binary.search(globalStore.project, event.properties.id, (s) => s.id)
|
||||||
@@ -647,12 +707,8 @@ function createGlobalSync() {
|
|||||||
|
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case "server.instance.disposed": {
|
case "server.instance.disposed": {
|
||||||
if (globalStore.reload) {
|
push(directory)
|
||||||
bootstrapQueue.push(directory)
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
bootstrapInstance(directory)
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
case "session.created": {
|
case "session.created": {
|
||||||
const info = event.properties.info
|
const info = event.properties.info
|
||||||
@@ -893,6 +949,10 @@ function createGlobalSync() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
onCleanup(unsub)
|
onCleanup(unsub)
|
||||||
|
onCleanup(() => {
|
||||||
|
if (!timer) return
|
||||||
|
clearTimeout(timer)
|
||||||
|
})
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const health = await globalSDK.client.global
|
const health = await globalSDK.client.global
|
||||||
@@ -916,7 +976,7 @@ function createGlobalSync() {
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
retry(() =>
|
retry(() =>
|
||||||
globalSDK.client.config.get().then((x) => {
|
globalSDK.client.global.config.get().then((x) => {
|
||||||
setGlobalStore("config", x.data!)
|
setGlobalStore("config", x.data!)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
@@ -999,13 +1059,13 @@ function createGlobalSync() {
|
|||||||
},
|
},
|
||||||
child,
|
child,
|
||||||
bootstrap,
|
bootstrap,
|
||||||
updateConfig: async (config: Config) => {
|
updateConfig: (config: Config) => {
|
||||||
setGlobalStore("reload", "pending")
|
setGlobalStore("reload", "pending")
|
||||||
const response = await globalSDK.client.config.update({ config })
|
return globalSDK.client.global.config.update({ config }).finally(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setGlobalStore("reload", "complete")
|
setGlobalStore("reload", "complete")
|
||||||
}, 1000)
|
}, 1000)
|
||||||
return response
|
})
|
||||||
},
|
},
|
||||||
project: {
|
project: {
|
||||||
loadSessions,
|
loadSessions,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Hono } from "hono"
|
import { Hono } from "hono"
|
||||||
import { describeRoute, resolver } from "hono-openapi"
|
import { describeRoute, resolver, validator } from "hono-openapi"
|
||||||
import { streamSSE } from "hono/streaming"
|
import { streamSSE } from "hono/streaming"
|
||||||
import z from "zod"
|
import z from "zod"
|
||||||
import { BusEvent } from "@/bus/bus-event"
|
import { BusEvent } from "@/bus/bus-event"
|
||||||
@@ -8,6 +8,8 @@ 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 { errors } from "../error"
|
||||||
|
|
||||||
const log = Log.create({ service: "server" })
|
const log = Log.create({ service: "server" })
|
||||||
|
|
||||||
@@ -103,6 +105,52 @@ export const GlobalRoutes = lazy(() =>
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
.get(
|
||||||
|
"/config",
|
||||||
|
describeRoute({
|
||||||
|
summary: "Get global configuration",
|
||||||
|
description: "Retrieve the current global OpenCode configuration settings and preferences.",
|
||||||
|
operationId: "global.config.get",
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
description: "Get global config info",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: resolver(Config.Info),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
async (c) => {
|
||||||
|
return c.json(await Config.getGlobal())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.patch(
|
||||||
|
"/config",
|
||||||
|
describeRoute({
|
||||||
|
summary: "Update global configuration",
|
||||||
|
description: "Update global OpenCode configuration settings and preferences.",
|
||||||
|
operationId: "global.config.update",
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
description: "Successfully updated global config",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: resolver(Config.Info),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
...errors(400),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
validator("json", Config.Info),
|
||||||
|
async (c) => {
|
||||||
|
const config = c.req.valid("json")
|
||||||
|
await Config.updateGlobal(config)
|
||||||
|
return c.json(await Config.getGlobal())
|
||||||
|
},
|
||||||
|
)
|
||||||
.post(
|
.post(
|
||||||
"/dispose",
|
"/dispose",
|
||||||
describeRoute({
|
describeRoute({
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import type {
|
|||||||
AuthSetErrors,
|
AuthSetErrors,
|
||||||
AuthSetResponses,
|
AuthSetResponses,
|
||||||
CommandListResponses,
|
CommandListResponses,
|
||||||
Config as Config2,
|
Config as Config3,
|
||||||
ConfigGetResponses,
|
ConfigGetResponses,
|
||||||
ConfigProvidersResponses,
|
ConfigProvidersResponses,
|
||||||
ConfigUpdateErrors,
|
ConfigUpdateErrors,
|
||||||
@@ -34,6 +34,9 @@ import type {
|
|||||||
FindSymbolsResponses,
|
FindSymbolsResponses,
|
||||||
FindTextResponses,
|
FindTextResponses,
|
||||||
FormatterStatusResponses,
|
FormatterStatusResponses,
|
||||||
|
GlobalConfigGetResponses,
|
||||||
|
GlobalConfigUpdateErrors,
|
||||||
|
GlobalConfigUpdateResponses,
|
||||||
GlobalDisposeResponses,
|
GlobalDisposeResponses,
|
||||||
GlobalEventResponses,
|
GlobalEventResponses,
|
||||||
GlobalHealthResponses,
|
GlobalHealthResponses,
|
||||||
@@ -215,6 +218,44 @@ class HeyApiRegistry<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class Config extends HeyApiClient {
|
||||||
|
/**
|
||||||
|
* Get global configuration
|
||||||
|
*
|
||||||
|
* Retrieve the current global OpenCode configuration settings and preferences.
|
||||||
|
*/
|
||||||
|
public get<ThrowOnError extends boolean = false>(options?: Options<never, ThrowOnError>) {
|
||||||
|
return (options?.client ?? this.client).get<GlobalConfigGetResponses, unknown, ThrowOnError>({
|
||||||
|
url: "/global/config",
|
||||||
|
...options,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update global configuration
|
||||||
|
*
|
||||||
|
* Update global OpenCode configuration settings and preferences.
|
||||||
|
*/
|
||||||
|
public update<ThrowOnError extends boolean = false>(
|
||||||
|
parameters?: {
|
||||||
|
config?: Config3
|
||||||
|
},
|
||||||
|
options?: Options<never, ThrowOnError>,
|
||||||
|
) {
|
||||||
|
const params = buildClientParams([parameters], [{ args: [{ key: "config", map: "body" }] }])
|
||||||
|
return (options?.client ?? this.client).patch<GlobalConfigUpdateResponses, GlobalConfigUpdateErrors, ThrowOnError>({
|
||||||
|
url: "/global/config",
|
||||||
|
...options,
|
||||||
|
...params,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
...options?.headers,
|
||||||
|
...params.headers,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class Global extends HeyApiClient {
|
export class Global extends HeyApiClient {
|
||||||
/**
|
/**
|
||||||
* Get health
|
* Get health
|
||||||
@@ -251,6 +292,11 @@ export class Global extends HeyApiClient {
|
|||||||
...options,
|
...options,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _config?: Config
|
||||||
|
get config(): Config {
|
||||||
|
return (this._config ??= new Config({ client: this.client }))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Project extends HeyApiClient {
|
export class Project extends HeyApiClient {
|
||||||
@@ -541,7 +587,7 @@ export class Pty extends HeyApiClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Config extends HeyApiClient {
|
export class Config2 extends HeyApiClient {
|
||||||
/**
|
/**
|
||||||
* Get configuration
|
* Get configuration
|
||||||
*
|
*
|
||||||
@@ -569,7 +615,7 @@ export class Config extends HeyApiClient {
|
|||||||
public update<ThrowOnError extends boolean = false>(
|
public update<ThrowOnError extends boolean = false>(
|
||||||
parameters?: {
|
parameters?: {
|
||||||
directory?: string
|
directory?: string
|
||||||
config?: Config2
|
config?: Config3
|
||||||
},
|
},
|
||||||
options?: Options<never, ThrowOnError>,
|
options?: Options<never, ThrowOnError>,
|
||||||
) {
|
) {
|
||||||
@@ -3168,9 +3214,9 @@ export class OpencodeClient extends HeyApiClient {
|
|||||||
return (this._pty ??= new Pty({ client: this.client }))
|
return (this._pty ??= new Pty({ client: this.client }))
|
||||||
}
|
}
|
||||||
|
|
||||||
private _config?: Config
|
private _config?: Config2
|
||||||
get config(): Config {
|
get config(): Config2 {
|
||||||
return (this._config ??= new Config({ client: this.client }))
|
return (this._config ??= new Config2({ client: this.client }))
|
||||||
}
|
}
|
||||||
|
|
||||||
private _tool?: Tool
|
private _tool?: Tool
|
||||||
|
|||||||
@@ -930,21 +930,6 @@ export type GlobalEvent = {
|
|||||||
payload: Event
|
payload: Event
|
||||||
}
|
}
|
||||||
|
|
||||||
export type BadRequestError = {
|
|
||||||
data: unknown
|
|
||||||
errors: Array<{
|
|
||||||
[key: string]: unknown
|
|
||||||
}>
|
|
||||||
success: false
|
|
||||||
}
|
|
||||||
|
|
||||||
export type NotFoundError = {
|
|
||||||
name: "NotFoundError"
|
|
||||||
data: {
|
|
||||||
message: string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom keybind configurations
|
* Custom keybind configurations
|
||||||
*/
|
*/
|
||||||
@@ -1826,6 +1811,21 @@ export type Config = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type BadRequestError = {
|
||||||
|
data: unknown
|
||||||
|
errors: Array<{
|
||||||
|
[key: string]: unknown
|
||||||
|
}>
|
||||||
|
success: false
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NotFoundError = {
|
||||||
|
name: "NotFoundError"
|
||||||
|
data: {
|
||||||
|
message: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export type Model = {
|
export type Model = {
|
||||||
id: string
|
id: string
|
||||||
providerID: string
|
providerID: string
|
||||||
@@ -2199,6 +2199,47 @@ export type GlobalEventResponses = {
|
|||||||
|
|
||||||
export type GlobalEventResponse = GlobalEventResponses[keyof GlobalEventResponses]
|
export type GlobalEventResponse = GlobalEventResponses[keyof GlobalEventResponses]
|
||||||
|
|
||||||
|
export type GlobalConfigGetData = {
|
||||||
|
body?: never
|
||||||
|
path?: never
|
||||||
|
query?: never
|
||||||
|
url: "/global/config"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GlobalConfigGetResponses = {
|
||||||
|
/**
|
||||||
|
* Get global config info
|
||||||
|
*/
|
||||||
|
200: Config
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GlobalConfigGetResponse = GlobalConfigGetResponses[keyof GlobalConfigGetResponses]
|
||||||
|
|
||||||
|
export type GlobalConfigUpdateData = {
|
||||||
|
body?: Config
|
||||||
|
path?: never
|
||||||
|
query?: never
|
||||||
|
url: "/global/config"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GlobalConfigUpdateErrors = {
|
||||||
|
/**
|
||||||
|
* Bad request
|
||||||
|
*/
|
||||||
|
400: BadRequestError
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GlobalConfigUpdateError = GlobalConfigUpdateErrors[keyof GlobalConfigUpdateErrors]
|
||||||
|
|
||||||
|
export type GlobalConfigUpdateResponses = {
|
||||||
|
/**
|
||||||
|
* Successfully updated global config
|
||||||
|
*/
|
||||||
|
200: Config
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GlobalConfigUpdateResponse = GlobalConfigUpdateResponses[keyof GlobalConfigUpdateResponses]
|
||||||
|
|
||||||
export type GlobalDisposeData = {
|
export type GlobalDisposeData = {
|
||||||
body?: never
|
body?: never
|
||||||
path?: never
|
path?: never
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user