feat(tui): reload command restarts the service
This commit is contained in:
@@ -63,6 +63,24 @@ export default Runtime.handler(Commands, (input) =>
|
|||||||
}).pipe(Effect.provide(NodeFileSystem.layer)),
|
}).pipe(Effect.provide(NodeFileSystem.layer)),
|
||||||
)
|
)
|
||||||
: () => Promise.resolve(transport)
|
: () => Promise.resolve(transport)
|
||||||
yield* runTui(transport, { continue: input.continue, sessionID: Option.getOrUndefined(input.session) }, discover)
|
// Restart the managed service in place; start() resolves once the
|
||||||
|
// replacement is healthy and the reconnect loop reattaches on its own.
|
||||||
|
// Only meaningful in service mode: --server is not ours to restart and a
|
||||||
|
// standalone child cannot be respawned.
|
||||||
|
const reload = serviceOptions
|
||||||
|
? () =>
|
||||||
|
Effect.runPromise(
|
||||||
|
Effect.gen(function* () {
|
||||||
|
yield* Service.stop(serviceOptions)
|
||||||
|
yield* Service.start(serviceOptions)
|
||||||
|
}).pipe(Effect.provide(NodeFileSystem.layer)),
|
||||||
|
)
|
||||||
|
: undefined
|
||||||
|
yield* runTui(
|
||||||
|
transport,
|
||||||
|
{ continue: input.continue, sessionID: Option.getOrUndefined(input.session) },
|
||||||
|
discover,
|
||||||
|
reload,
|
||||||
|
)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,7 +9,12 @@ import type { Service } from "@opencode-ai/client/effect"
|
|||||||
import { createOpencodeClient } from "@opencode-ai/sdk/v2/client"
|
import { createOpencodeClient } from "@opencode-ai/sdk/v2/client"
|
||||||
import type { Args } from "@opencode-ai/tui/context/args"
|
import type { Args } from "@opencode-ai/tui/context/args"
|
||||||
|
|
||||||
export function runTui(transport: Service.Transport, args: Args, discover?: () => Promise<Service.Transport>) {
|
export function runTui(
|
||||||
|
transport: Service.Transport,
|
||||||
|
args: Args,
|
||||||
|
discover?: () => Promise<Service.Transport>,
|
||||||
|
reload?: () => Promise<void>,
|
||||||
|
) {
|
||||||
const config = TuiConfig.resolve({}, { terminalSuspend: false })
|
const config = TuiConfig.resolve({}, { terminalSuspend: false })
|
||||||
let disposeSlots: (() => void) | undefined
|
let disposeSlots: (() => void) | undefined
|
||||||
return Effect.gen(function* () {
|
return Effect.gen(function* () {
|
||||||
@@ -33,6 +38,7 @@ export function runTui(transport: Service.Transport, args: Args, discover?: () =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
|
reload,
|
||||||
args,
|
args,
|
||||||
config,
|
config,
|
||||||
pluginHost: {
|
pluginHost: {
|
||||||
|
|||||||
@@ -139,6 +139,7 @@ export type TuiInput = {
|
|||||||
client: OpencodeClient
|
client: OpencodeClient
|
||||||
api: OpenCodeClient
|
api: OpenCodeClient
|
||||||
discover?: () => Promise<{ client: OpencodeClient; api: OpenCodeClient }>
|
discover?: () => Promise<{ client: OpencodeClient; api: OpenCodeClient }>
|
||||||
|
reload?: () => Promise<void>
|
||||||
args: Args
|
args: Args
|
||||||
config: TuiConfig.Resolved
|
config: TuiConfig.Resolved
|
||||||
onSnapshot?: () => Promise<string[]>
|
onSnapshot?: () => Promise<string[]>
|
||||||
@@ -301,7 +302,7 @@ export const run = Effect.fn("Tui.run")(function* (input: TuiInput) {
|
|||||||
>
|
>
|
||||||
<TuiConfigProvider config={input.config}>
|
<TuiConfigProvider config={input.config}>
|
||||||
<PluginRuntimeProvider value={pluginRuntime}>
|
<PluginRuntimeProvider value={pluginRuntime}>
|
||||||
<SDKProvider client={input.client} api={input.api} discover={input.discover}>
|
<SDKProvider client={input.client} api={input.api} discover={input.discover} reload={input.reload}>
|
||||||
<PermissionProvider>
|
<PermissionProvider>
|
||||||
<ProjectProvider>
|
<ProjectProvider>
|
||||||
<SyncProvider>
|
<SyncProvider>
|
||||||
@@ -800,6 +801,26 @@ function App(props: { onSnapshot?: () => Promise<string[]>; pluginHost: TuiPlugi
|
|||||||
},
|
},
|
||||||
category: "System",
|
category: "System",
|
||||||
},
|
},
|
||||||
|
...(sdk.reload
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
name: "server.reload",
|
||||||
|
title: "Reload server",
|
||||||
|
slashName: "reload",
|
||||||
|
run: async () => {
|
||||||
|
dialog.clear()
|
||||||
|
toast.show({ variant: "info", message: "Reloading server...", duration: 30000 })
|
||||||
|
// reload resolves once the replacement service is healthy; the
|
||||||
|
// event stream reattaches through the reconnect loop.
|
||||||
|
await sdk
|
||||||
|
.reload!()
|
||||||
|
.then(() => toast.show({ variant: "success", message: "Server reloaded" }))
|
||||||
|
.catch(toast.error)
|
||||||
|
},
|
||||||
|
category: "System",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
{
|
{
|
||||||
name: "theme.switch",
|
name: "theme.switch",
|
||||||
title: "Switch theme",
|
title: "Switch theme",
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({
|
|||||||
client: OpencodeClient
|
client: OpencodeClient
|
||||||
api: OpenCodeClient
|
api: OpenCodeClient
|
||||||
discover?: () => Promise<{ client: OpencodeClient; api: OpenCodeClient }>
|
discover?: () => Promise<{ client: OpencodeClient; api: OpenCodeClient }>
|
||||||
|
// Stops and starts the managed service; present only in service mode.
|
||||||
|
reload?: () => Promise<void>
|
||||||
}) => {
|
}) => {
|
||||||
const abort = new AbortController()
|
const abort = new AbortController()
|
||||||
let client = props.client
|
let client = props.client
|
||||||
@@ -138,6 +140,7 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({
|
|||||||
return connection.connectedOnce
|
return connection.connectedOnce
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
reload: props.reload,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user