mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-13 11:39:41 +03:00
feat(app): add /reload to reload configuration (#59887)
Co-authored-by: vimtor <36263538+vimtor@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
b6c43a5242
commit
35a4a6876d
@@ -915,10 +915,32 @@ test("lists slash commands in their built-in order", async ({ page }) => {
|
||||
"/mcp",
|
||||
"/model",
|
||||
"/connect",
|
||||
"/reload",
|
||||
"/btw",
|
||||
])
|
||||
})
|
||||
|
||||
test("/reload reloads the server's configuration once and reports it", async ({ page }) => {
|
||||
const { editor } = await openSession(page, { name: "ComposerReload", provider: NO_PROVIDER })
|
||||
const reloaded = Promise.withResolvers<void>()
|
||||
let reloads = 0
|
||||
await page.route(/\/api\/location\/reload$/, async (route) => {
|
||||
reloads++
|
||||
await reloaded.promise
|
||||
await route.fulfill({ status: 204 })
|
||||
})
|
||||
|
||||
await editor.fill("/reload")
|
||||
await expect(page.locator('[data-suggestion-id="config.reload"]')).toHaveAttribute("data-active", "")
|
||||
await editor.press("Enter")
|
||||
await expect(page.getByText("Reloading configuration…", { exact: true })).toBeVisible()
|
||||
reloaded.resolve()
|
||||
await expect(page.getByText("Configuration reloaded", { exact: true })).toBeVisible()
|
||||
await expect(page.getByText("Reloading configuration…", { exact: true })).toBeHidden()
|
||||
await expect(editor).toBeEmpty()
|
||||
expect(reloads).toBe(1)
|
||||
})
|
||||
|
||||
const followUp = "Add follow-up, / for commands, @ for context…"
|
||||
|
||||
for (const row of [
|
||||
|
||||
@@ -9,6 +9,10 @@ import { useSessionLayout } from "@/session/session-layout"
|
||||
import { createSessionOwnership } from "@/session/session-ownership"
|
||||
import { useWorkspaceLocation } from "@/workspaces/location"
|
||||
import { useData } from "@/runtime/server/current"
|
||||
import { useServerSDK } from "@/runtime/server/client"
|
||||
import { formatServerError } from "@/runtime/server/errors"
|
||||
import { showToast } from "@/shell/notifications/toast"
|
||||
import { toaster } from "@opencode/ui/toast"
|
||||
|
||||
const withCategory = (category: string) => {
|
||||
return (option: Omit<CommandOption, "category">): CommandOption => ({
|
||||
@@ -26,12 +30,14 @@ export const useComposerCommands = (input: { model?: ModelSelection } = {}) => {
|
||||
const workspace = useWorkspaceLocation()
|
||||
const { sessionKey, params } = useSessionLayout()
|
||||
const data = useData()
|
||||
const sdk = useServerSDK()
|
||||
const sessionOwnership = createSessionOwnership(sessionKey)
|
||||
const model = input.model ?? local.model
|
||||
const modelCommand = withCategory(language.t("command.category.model"))
|
||||
const agentCommand = withCategory(language.t("command.category.agent"))
|
||||
const providerCommand = withCategory(language.t("command.category.provider"))
|
||||
const viewCommand = withCategory(language.t("command.category.view"))
|
||||
const serverCommand = withCategory(language.t("command.category.server"))
|
||||
|
||||
// Mirrors the TUI's `/connect`, which the Console's setup steps tell people to run.
|
||||
const connectProvider = async () => {
|
||||
@@ -40,6 +46,28 @@ export const useComposerCommands = (input: { model?: ModelSelection } = {}) => {
|
||||
void dialog.show(() => <DialogConnectProvider directory={workspace().directory} selection={model} />)
|
||||
}
|
||||
|
||||
// Mirrors the TUI's `/reload`. The server rebuilds every loaded location and announces the changed agents,
|
||||
// commands, models and skills, so the data layer refreshes them without restarting the app.
|
||||
const reloadConfig = () => {
|
||||
const pending = showToast({
|
||||
variant: "loading",
|
||||
title: language.t("command.config.reload.pending"),
|
||||
persistent: true,
|
||||
})
|
||||
|
||||
void sdk.api.location
|
||||
.reload()
|
||||
.then(() => showToast({ variant: "success", title: language.t("command.config.reload.done") }))
|
||||
.catch((error) =>
|
||||
showToast({
|
||||
variant: "error",
|
||||
title: language.t("command.config.reload.failed"),
|
||||
description: formatServerError(error, language.t),
|
||||
}),
|
||||
)
|
||||
.finally(() => toaster.dismiss(pending))
|
||||
}
|
||||
|
||||
const chooseModel = () => {
|
||||
const Picker = settings.general.newModelPicker() ? DialogSelectModelNext : DialogSelectModel
|
||||
sessionOwnership.capture().run(() => {
|
||||
@@ -50,10 +78,12 @@ export const useComposerCommands = (input: { model?: ModelSelection } = {}) => {
|
||||
const viewUsage = async () => {
|
||||
const { DialogUsage } = await import("@/usage/dialog")
|
||||
const current = model.current()
|
||||
|
||||
// Console refuses with 402 only when the workspace can't pay, which the dialog explains.
|
||||
const last = params.id
|
||||
? data.session.message.list(params.id)?.findLast((message) => message.type === "assistant")
|
||||
: undefined
|
||||
|
||||
void dialog.show(() => (
|
||||
<DialogUsage
|
||||
location={workspace().ref}
|
||||
@@ -93,6 +123,13 @@ export const useComposerCommands = (input: { model?: ModelSelection } = {}) => {
|
||||
slash: "connect",
|
||||
onSelect: connectProvider,
|
||||
}),
|
||||
serverCommand({
|
||||
id: "config.reload",
|
||||
title: language.t("command.config.reload"),
|
||||
description: language.t("command.config.reload.description"),
|
||||
slash: "reload",
|
||||
onSelect: reloadConfig,
|
||||
}),
|
||||
agentCommand({
|
||||
id: "agent.cycle",
|
||||
title: language.t("command.agent.cycle"),
|
||||
|
||||
@@ -57,6 +57,11 @@ export const dict = {
|
||||
"command.provider.connect": "Connect an integration",
|
||||
"command.provider.connect.description": "Sign in to OpenCode Go, OpenCode Console, or another model provider",
|
||||
"command.settings.open": "Open settings",
|
||||
"command.config.reload": "Reload configuration",
|
||||
"command.config.reload.description": "Reload agents, commands, skills, MCP servers and plugins from your config",
|
||||
"command.config.reload.pending": "Reloading configuration…",
|
||||
"command.config.reload.done": "Configuration reloaded",
|
||||
"command.config.reload.failed": "Couldn't reload configuration",
|
||||
"command.usage.view": "View usage",
|
||||
"command.usage.view.description": "See your OpenCode Go allowance and Console budgets",
|
||||
"command.session.location.cycle": "Cycle session location",
|
||||
|
||||
Reference in New Issue
Block a user