mirror of
https://github.com/anomalyco/opencode.git
synced 2026-02-13 20:34:28 +00:00
Compare commits
1 Commits
dev
...
add-or-var
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ecebc1013 |
@@ -50,8 +50,7 @@ scoop install opencode # Windows
|
||||
choco install opencode # Windows
|
||||
brew install anomalyco/tap/opencode # macOS و Linux (موصى به، دائما محدث)
|
||||
brew install opencode # macOS و Linux (صيغة brew الرسمية، تحديث اقل)
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin # Arch Linux
|
||||
mise use -g opencode # اي نظام
|
||||
nix run nixpkgs#opencode # او github:anomalyco/opencode لاحدث فرع dev
|
||||
```
|
||||
|
||||
@@ -50,8 +50,7 @@ scoop install opencode # Windows
|
||||
choco install opencode # Windows
|
||||
brew install anomalyco/tap/opencode # macOS e Linux (recomendado, sempre atualizado)
|
||||
brew install opencode # macOS e Linux (fórmula oficial do brew, atualiza menos)
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin # Arch Linux
|
||||
mise use -g opencode # qualquer sistema
|
||||
nix run nixpkgs#opencode # ou github:anomalyco/opencode para a branch dev mais recente
|
||||
```
|
||||
|
||||
@@ -51,8 +51,7 @@ scoop install opencode # Windows
|
||||
choco install opencode # Windows
|
||||
brew install anomalyco/tap/opencode # macOS i Linux (preporučeno, uvijek ažurno)
|
||||
brew install opencode # macOS i Linux (zvanična brew formula, rjeđe se ažurira)
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin # Arch Linux
|
||||
mise use -g opencode # Bilo koji OS
|
||||
nix run nixpkgs#opencode # ili github:anomalyco/opencode za najnoviji dev branch
|
||||
```
|
||||
|
||||
@@ -50,8 +50,7 @@ scoop install opencode # Windows
|
||||
choco install opencode # Windows
|
||||
brew install anomalyco/tap/opencode # macOS og Linux (anbefalet, altid up to date)
|
||||
brew install opencode # macOS og Linux (officiel brew formula, opdateres sjældnere)
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin # Arch Linux
|
||||
mise use -g opencode # alle OS
|
||||
nix run nixpkgs#opencode # eller github:anomalyco/opencode for nyeste dev-branch
|
||||
```
|
||||
|
||||
@@ -50,8 +50,7 @@ scoop install opencode # Windows
|
||||
choco install opencode # Windows
|
||||
brew install anomalyco/tap/opencode # macOS und Linux (empfohlen, immer aktuell)
|
||||
brew install opencode # macOS und Linux (offizielle Brew-Formula, seltener aktualisiert)
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin # Arch Linux
|
||||
mise use -g opencode # jedes Betriebssystem
|
||||
nix run nixpkgs#opencode # oder github:anomalyco/opencode für den neuesten dev-Branch
|
||||
```
|
||||
|
||||
@@ -50,8 +50,7 @@ scoop install opencode # Windows
|
||||
choco install opencode # Windows
|
||||
brew install anomalyco/tap/opencode # macOS y Linux (recomendado, siempre al día)
|
||||
brew install opencode # macOS y Linux (fórmula oficial de brew, se actualiza menos)
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin # Arch Linux
|
||||
mise use -g opencode # cualquier sistema
|
||||
nix run nixpkgs#opencode # o github:anomalyco/opencode para la rama dev más reciente
|
||||
```
|
||||
|
||||
@@ -50,8 +50,7 @@ scoop install opencode # Windows
|
||||
choco install opencode # Windows
|
||||
brew install anomalyco/tap/opencode # macOS et Linux (recommandé, toujours à jour)
|
||||
brew install opencode # macOS et Linux (formule officielle brew, mise à jour moins fréquente)
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin # Arch Linux
|
||||
mise use -g opencode # n'importe quel OS
|
||||
nix run nixpkgs#opencode # ou github:anomalyco/opencode pour la branche dev la plus récente
|
||||
```
|
||||
|
||||
@@ -50,8 +50,7 @@ scoop install opencode # Windows
|
||||
choco install opencode # Windows
|
||||
brew install anomalyco/tap/opencode # macOS e Linux (consigliato, sempre aggiornato)
|
||||
brew install opencode # macOS e Linux (formula brew ufficiale, aggiornata meno spesso)
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin # Arch Linux
|
||||
mise use -g opencode # Qualsiasi OS
|
||||
nix run nixpkgs#opencode # oppure github:anomalyco/opencode per l’ultima branch di sviluppo
|
||||
```
|
||||
|
||||
@@ -50,8 +50,7 @@ scoop install opencode # Windows
|
||||
choco install opencode # Windows
|
||||
brew install anomalyco/tap/opencode # macOS と Linux(推奨。常に最新)
|
||||
brew install opencode # macOS と Linux(公式 brew formula。更新頻度は低め)
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin # Arch Linux
|
||||
mise use -g opencode # どのOSでも
|
||||
nix run nixpkgs#opencode # または github:anomalyco/opencode で最新 dev ブランチ
|
||||
```
|
||||
|
||||
@@ -50,8 +50,7 @@ scoop install opencode # Windows
|
||||
choco install opencode # Windows
|
||||
brew install anomalyco/tap/opencode # macOS 및 Linux (권장, 항상 최신)
|
||||
brew install opencode # macOS 및 Linux (공식 brew formula, 업데이트 빈도 낮음)
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin # Arch Linux
|
||||
mise use -g opencode # 어떤 OS든
|
||||
nix run nixpkgs#opencode # 또는 github:anomalyco/opencode 로 최신 dev 브랜치
|
||||
```
|
||||
|
||||
@@ -51,8 +51,7 @@ scoop install opencode # Windows
|
||||
choco install opencode # Windows
|
||||
brew install anomalyco/tap/opencode # macOS and Linux (recommended, always up to date)
|
||||
brew install opencode # macOS and Linux (official brew formula, updated less)
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin # Arch Linux
|
||||
mise use -g opencode # Any OS
|
||||
nix run nixpkgs#opencode # or github:anomalyco/opencode for latest dev branch
|
||||
```
|
||||
|
||||
@@ -50,8 +50,7 @@ scoop install opencode # Windows
|
||||
choco install opencode # Windows
|
||||
brew install anomalyco/tap/opencode # macOS og Linux (anbefalt, alltid oppdatert)
|
||||
brew install opencode # macOS og Linux (offisiell brew-formel, oppdateres sjeldnere)
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin # Arch Linux
|
||||
mise use -g opencode # alle OS
|
||||
nix run nixpkgs#opencode # eller github:anomalyco/opencode for nyeste dev-branch
|
||||
```
|
||||
|
||||
@@ -50,8 +50,7 @@ scoop install opencode # Windows
|
||||
choco install opencode # Windows
|
||||
brew install anomalyco/tap/opencode # macOS i Linux (polecane, zawsze aktualne)
|
||||
brew install opencode # macOS i Linux (oficjalna formuła brew, rzadziej aktualizowana)
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin # Arch Linux
|
||||
mise use -g opencode # dowolny system
|
||||
nix run nixpkgs#opencode # lub github:anomalyco/opencode dla najnowszej gałęzi dev
|
||||
```
|
||||
|
||||
@@ -50,8 +50,7 @@ scoop install opencode # Windows
|
||||
choco install opencode # Windows
|
||||
brew install anomalyco/tap/opencode # macOS и Linux (рекомендуем, всегда актуально)
|
||||
brew install opencode # macOS и Linux (официальная формула brew, обновляется реже)
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin # Arch Linux
|
||||
mise use -g opencode # любая ОС
|
||||
nix run nixpkgs#opencode # или github:anomalyco/opencode для самой свежей ветки dev
|
||||
```
|
||||
|
||||
@@ -50,8 +50,7 @@ scoop install opencode # Windows
|
||||
choco install opencode # Windows
|
||||
brew install anomalyco/tap/opencode # macOS และ Linux (แนะนำ อัปเดตเสมอ)
|
||||
brew install opencode # macOS และ Linux (brew formula อย่างเป็นทางการ อัปเดตน้อยกว่า)
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin # Arch Linux
|
||||
mise use -g opencode # ระบบปฏิบัติการใดก็ได้
|
||||
nix run nixpkgs#opencode # หรือ github:anomalyco/opencode สำหรับสาขาพัฒนาล่าสุด
|
||||
```
|
||||
|
||||
@@ -50,8 +50,7 @@ scoop install opencode # Windows
|
||||
choco install opencode # Windows
|
||||
brew install anomalyco/tap/opencode # macOS ve Linux (önerilir, her zaman güncel)
|
||||
brew install opencode # macOS ve Linux (resmi brew formülü, daha az güncellenir)
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin # Arch Linux
|
||||
mise use -g opencode # Tüm işletim sistemleri
|
||||
nix run nixpkgs#opencode # veya en güncel geliştirme dalı için github:anomalyco/opencode
|
||||
```
|
||||
|
||||
@@ -50,8 +50,7 @@ scoop install opencode # Windows
|
||||
choco install opencode # Windows
|
||||
brew install anomalyco/tap/opencode # macOS 和 Linux(推荐,始终保持最新)
|
||||
brew install opencode # macOS 和 Linux(官方 brew formula,更新频率较低)
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin # Arch Linux
|
||||
mise use -g opencode # 任意系统
|
||||
nix run nixpkgs#opencode # 或用 github:anomalyco/opencode 获取最新 dev 分支
|
||||
```
|
||||
|
||||
@@ -50,8 +50,7 @@ scoop install opencode # Windows
|
||||
choco install opencode # Windows
|
||||
brew install anomalyco/tap/opencode # macOS 與 Linux(推薦,始終保持最新)
|
||||
brew install opencode # macOS 與 Linux(官方 brew formula,更新頻率較低)
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin # Arch Linux
|
||||
mise use -g opencode # 任何作業系統
|
||||
nix run nixpkgs#opencode # 或使用 github:anomalyco/opencode 以取得最新開發分支
|
||||
```
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"nodeModules": {
|
||||
"x86_64-linux": "sha256-FsFTitxnN2brebZDBRGJB0NWTOVYDa/QcNRH0ip/Gk4=",
|
||||
"aarch64-linux": "sha256-knSEqEPyonBUfmGZKTq5Om4HikItWbfPdfT7p6iljzs=",
|
||||
"aarch64-darwin": "sha256-uRgWfuOlLECRCOszm8XhySiWxu9IdDhpSbosPZPAZVI=",
|
||||
"x86_64-darwin": "sha256-gHuA+Ud9L+XLvKm5Vp5jCXfZWOtunnmX/lB8vczHsG0="
|
||||
"x86_64-linux": "sha256-XIf7b6yALzH1/MkGGrsmq2DeXIC9vgD9a7D/dxhi6iU=",
|
||||
"aarch64-linux": "sha256-mKDCs6QhIelWc3E17zOufaSDTovtjO/Xyh3JtlWl01s=",
|
||||
"aarch64-darwin": "sha256-wC7bbbIyZ62uMxTr9FElTbEBMrfz0S/ndqwZZ3V9EOA=",
|
||||
"x86_64-darwin": "sha256-/7Nn65m5Zhvzz0TKsG9nWd2v5WDHQNi3UzCfuAR8SLo="
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
import { test, expect } from "../fixtures"
|
||||
import { promptSelector } from "../selectors"
|
||||
import { sessionIDFromUrl } from "../actions"
|
||||
|
||||
// Regression test for Issue #12453: the synchronous POST /message endpoint holds
|
||||
// the connection open while the agent works, causing "Failed to fetch" over
|
||||
// VPN/Tailscale. The fix switches to POST /prompt_async which returns immediately.
|
||||
test("prompt succeeds when sync message endpoint is unreachable", async ({ page, sdk, gotoSession }) => {
|
||||
test.setTimeout(120_000)
|
||||
|
||||
// Simulate Tailscale/VPN killing the long-lived sync connection
|
||||
await page.route("**/session/*/message", (route) => route.abort("connectionfailed"))
|
||||
|
||||
await gotoSession()
|
||||
|
||||
const token = `E2E_ASYNC_${Date.now()}`
|
||||
await page.locator(promptSelector).click()
|
||||
await page.keyboard.type(`Reply with exactly: ${token}`)
|
||||
await page.keyboard.press("Enter")
|
||||
|
||||
await expect(page).toHaveURL(/\/session\/[^/?#]+/, { timeout: 30_000 })
|
||||
const sessionID = sessionIDFromUrl(page.url())!
|
||||
|
||||
try {
|
||||
// Agent response arrives via SSE despite sync endpoint being dead
|
||||
await expect
|
||||
.poll(
|
||||
async () => {
|
||||
const messages = await sdk.session.messages({ sessionID, limit: 50 }).then((r) => r.data ?? [])
|
||||
return messages
|
||||
.filter((m) => m.info.role === "assistant")
|
||||
.flatMap((m) => m.parts)
|
||||
.filter((p) => p.type === "text")
|
||||
.map((p) => p.text)
|
||||
.join("\n")
|
||||
},
|
||||
{ timeout: 90_000 },
|
||||
)
|
||||
.toContain(token)
|
||||
} finally {
|
||||
await sdk.session.delete({ sessionID }).catch(() => undefined)
|
||||
}
|
||||
})
|
||||
@@ -1,5 +1,5 @@
|
||||
import "@/index.css"
|
||||
import { ErrorBoundary, Show, Suspense, lazy, type JSX, type ParentProps } from "solid-js"
|
||||
import { ErrorBoundary, Suspense, lazy, type JSX, type ParentProps } from "solid-js"
|
||||
import { Router, Route, Navigate } from "@solidjs/router"
|
||||
import { MetaProvider } from "@solidjs/meta"
|
||||
import { Font } from "@opencode-ai/ui/font"
|
||||
@@ -156,11 +156,8 @@ export function AppBaseProviders(props: ParentProps) {
|
||||
|
||||
function ServerKey(props: ParentProps) {
|
||||
const server = useServer()
|
||||
return (
|
||||
<Show when={server.url} keyed>
|
||||
{props.children}
|
||||
</Show>
|
||||
)
|
||||
if (!server.url) return null
|
||||
return props.children
|
||||
}
|
||||
|
||||
export function AppInterface(props: { defaultUrl?: string; children?: JSX.Element; isSidecar?: boolean }) {
|
||||
|
||||
@@ -385,7 +385,7 @@ export function createPromptSubmit(input: PromptSubmitInput) {
|
||||
const send = async () => {
|
||||
const ok = await waitForWorktree()
|
||||
if (!ok) return
|
||||
await client.session.promptAsync({
|
||||
await client.session.prompt({
|
||||
sessionID: session.id,
|
||||
agent,
|
||||
model,
|
||||
|
||||
@@ -552,7 +552,7 @@ export function SessionHeader() {
|
||||
</Show>
|
||||
</div>
|
||||
</Show>
|
||||
<div class="flex items-center gap-3 ml-2 shrink-0">
|
||||
<div class="hidden lg:flex items-center gap-3 ml-2 shrink-0">
|
||||
<TooltipKeybind
|
||||
title={language.t("command.terminal.toggle")}
|
||||
keybind={command.keybind("terminal.toggle")}
|
||||
|
||||
@@ -156,10 +156,6 @@ export const Terminal = (props: TerminalProps) => {
|
||||
let serializeAddon: SerializeAddon
|
||||
let fitAddon: FitAddon
|
||||
let handleResize: () => void
|
||||
let fitFrame: number | undefined
|
||||
let sizeTimer: ReturnType<typeof setTimeout> | undefined
|
||||
let pendingSize: { cols: number; rows: number } | undefined
|
||||
let lastSize: { cols: number; rows: number } | undefined
|
||||
let disposed = false
|
||||
const cleanups: VoidFunction[] = []
|
||||
const start =
|
||||
@@ -213,43 +209,6 @@ export const Terminal = (props: TerminalProps) => {
|
||||
|
||||
const [terminalColors, setTerminalColors] = createSignal<TerminalColors>(getTerminalColors())
|
||||
|
||||
const scheduleFit = () => {
|
||||
if (disposed) return
|
||||
if (!fitAddon) return
|
||||
if (fitFrame !== undefined) return
|
||||
|
||||
fitFrame = requestAnimationFrame(() => {
|
||||
fitFrame = undefined
|
||||
if (disposed) return
|
||||
fitAddon.fit()
|
||||
})
|
||||
}
|
||||
|
||||
const scheduleSize = (cols: number, rows: number) => {
|
||||
if (disposed) return
|
||||
if (lastSize?.cols === cols && lastSize?.rows === rows) return
|
||||
|
||||
pendingSize = { cols, rows }
|
||||
|
||||
if (!lastSize) {
|
||||
lastSize = pendingSize
|
||||
void pushSize(cols, rows)
|
||||
return
|
||||
}
|
||||
|
||||
if (sizeTimer !== undefined) return
|
||||
sizeTimer = setTimeout(() => {
|
||||
sizeTimer = undefined
|
||||
const next = pendingSize
|
||||
if (!next) return
|
||||
pendingSize = undefined
|
||||
if (disposed) return
|
||||
if (lastSize?.cols === next.cols && lastSize?.rows === next.rows) return
|
||||
lastSize = next
|
||||
void pushSize(next.cols, next.rows)
|
||||
}, 100)
|
||||
}
|
||||
|
||||
createEffect(() => {
|
||||
const colors = getTerminalColors()
|
||||
setTerminalColors(colors)
|
||||
@@ -261,16 +220,6 @@ export const Terminal = (props: TerminalProps) => {
|
||||
const font = monoFontFamily(settings.appearance.font())
|
||||
if (!term) return
|
||||
setOptionIfSupported(term, "fontFamily", font)
|
||||
scheduleFit()
|
||||
})
|
||||
|
||||
let zoom = platform.webviewZoom?.()
|
||||
createEffect(() => {
|
||||
const next = platform.webviewZoom?.()
|
||||
if (next === undefined) return
|
||||
if (next === zoom) return
|
||||
zoom = next
|
||||
scheduleFit()
|
||||
})
|
||||
|
||||
const focusTerminal = () => {
|
||||
@@ -314,6 +263,25 @@ export const Terminal = (props: TerminalProps) => {
|
||||
|
||||
const once = { value: false }
|
||||
|
||||
const url = new URL(sdk.url + `/pty/${local.pty.id}/connect`)
|
||||
url.searchParams.set("directory", sdk.directory)
|
||||
url.searchParams.set("cursor", String(start !== undefined ? start : local.pty.buffer ? -1 : 0))
|
||||
url.protocol = url.protocol === "https:" ? "wss:" : "ws:"
|
||||
if (window.__OPENCODE__?.serverPassword) {
|
||||
url.username = "opencode"
|
||||
url.password = window.__OPENCODE__?.serverPassword
|
||||
}
|
||||
const socket = new WebSocket(url)
|
||||
socket.binaryType = "arraybuffer"
|
||||
cleanups.push(() => {
|
||||
if (socket.readyState !== WebSocket.CLOSED && socket.readyState !== WebSocket.CLOSING) socket.close()
|
||||
})
|
||||
if (disposed) {
|
||||
cleanup()
|
||||
return
|
||||
}
|
||||
ws = socket
|
||||
|
||||
const restore = typeof local.pty.buffer === "string" ? local.pty.buffer : ""
|
||||
const restoreSize =
|
||||
restore &&
|
||||
@@ -376,28 +344,9 @@ export const Terminal = (props: TerminalProps) => {
|
||||
|
||||
focusTerminal()
|
||||
|
||||
if (typeof document !== "undefined" && document.fonts) {
|
||||
document.fonts.ready.then(scheduleFit)
|
||||
}
|
||||
|
||||
const onResize = t.onResize((size) => {
|
||||
scheduleSize(size.cols, size.rows)
|
||||
})
|
||||
cleanups.push(() => disposeIfDisposable(onResize))
|
||||
const onData = t.onData((data) => {
|
||||
if (ws?.readyState === WebSocket.OPEN) ws.send(data)
|
||||
})
|
||||
cleanups.push(() => disposeIfDisposable(onData))
|
||||
const onKey = t.onKey((key) => {
|
||||
if (key.key == "Enter") {
|
||||
props.onSubmit?.()
|
||||
}
|
||||
})
|
||||
cleanups.push(() => disposeIfDisposable(onKey))
|
||||
|
||||
const startResize = () => {
|
||||
fit.observeResize()
|
||||
handleResize = scheduleFit
|
||||
handleResize = () => fit.fit()
|
||||
window.addEventListener("resize", handleResize)
|
||||
cleanups.push(() => window.removeEventListener("resize", handleResize))
|
||||
}
|
||||
@@ -405,13 +354,11 @@ export const Terminal = (props: TerminalProps) => {
|
||||
if (restore && restoreSize) {
|
||||
t.write(restore, () => {
|
||||
fit.fit()
|
||||
scheduleSize(t.cols, t.rows)
|
||||
if (typeof local.pty.scrollY === "number") t.scrollToLine(local.pty.scrollY)
|
||||
startResize()
|
||||
})
|
||||
} else {
|
||||
fit.fit()
|
||||
scheduleSize(t.cols, t.rows)
|
||||
if (restore) {
|
||||
t.write(restore, () => {
|
||||
if (typeof local.pty.scrollY === "number") t.scrollToLine(local.pty.scrollY)
|
||||
@@ -420,38 +367,35 @@ export const Terminal = (props: TerminalProps) => {
|
||||
startResize()
|
||||
}
|
||||
|
||||
const onResize = t.onResize(async (size) => {
|
||||
if (socket.readyState === WebSocket.OPEN) {
|
||||
await pushSize(size.cols, size.rows)
|
||||
}
|
||||
})
|
||||
cleanups.push(() => disposeIfDisposable(onResize))
|
||||
const onData = t.onData((data) => {
|
||||
if (socket.readyState === WebSocket.OPEN) {
|
||||
socket.send(data)
|
||||
}
|
||||
})
|
||||
cleanups.push(() => disposeIfDisposable(onData))
|
||||
const onKey = t.onKey((key) => {
|
||||
if (key.key == "Enter") {
|
||||
props.onSubmit?.()
|
||||
}
|
||||
})
|
||||
cleanups.push(() => disposeIfDisposable(onKey))
|
||||
// t.onScroll((ydisp) => {
|
||||
// console.log("Scroll position:", ydisp)
|
||||
// })
|
||||
|
||||
const url = new URL(sdk.url + `/pty/${local.pty.id}/connect`)
|
||||
url.searchParams.set("directory", sdk.directory)
|
||||
url.searchParams.set("cursor", String(start !== undefined ? start : local.pty.buffer ? -1 : 0))
|
||||
url.protocol = url.protocol === "https:" ? "wss:" : "ws:"
|
||||
if (window.__OPENCODE__?.serverPassword) {
|
||||
url.username = "opencode"
|
||||
url.password = window.__OPENCODE__?.serverPassword
|
||||
}
|
||||
const socket = new WebSocket(url)
|
||||
socket.binaryType = "arraybuffer"
|
||||
ws = socket
|
||||
cleanups.push(() => {
|
||||
if (socket.readyState !== WebSocket.CLOSED && socket.readyState !== WebSocket.CLOSING) socket.close()
|
||||
})
|
||||
if (disposed) {
|
||||
cleanup()
|
||||
return
|
||||
}
|
||||
|
||||
const handleOpen = () => {
|
||||
local.onConnect?.()
|
||||
scheduleSize(t.cols, t.rows)
|
||||
void pushSize(t.cols, t.rows)
|
||||
}
|
||||
socket.addEventListener("open", handleOpen)
|
||||
cleanups.push(() => socket.removeEventListener("open", handleOpen))
|
||||
|
||||
if (socket.readyState === WebSocket.OPEN) handleOpen()
|
||||
|
||||
const decoder = new TextDecoder()
|
||||
|
||||
const handleMessage = (event: MessageEvent) => {
|
||||
@@ -518,8 +462,6 @@ export const Terminal = (props: TerminalProps) => {
|
||||
|
||||
onCleanup(() => {
|
||||
disposed = true
|
||||
if (fitFrame !== undefined) cancelAnimationFrame(fitFrame)
|
||||
if (sizeTimer !== undefined) clearTimeout(sizeTimer)
|
||||
output?.flush()
|
||||
persistTerminal({ term, addon: serializeAddon, cursor, pty: local.pty, onCleanup: props.onCleanup })
|
||||
cleanup()
|
||||
@@ -535,7 +477,7 @@ export const Terminal = (props: TerminalProps) => {
|
||||
classList={{
|
||||
...(local.classList ?? {}),
|
||||
"select-text": true,
|
||||
"size-full px-6 py-3 font-mono relative overflow-hidden": true,
|
||||
"size-full px-6 py-3 font-mono": true,
|
||||
[local.class ?? ""]: !!local.class,
|
||||
}}
|
||||
{...others}
|
||||
|
||||
@@ -57,10 +57,6 @@ export type Locale =
|
||||
type RawDictionary = typeof en & typeof uiEn
|
||||
type Dictionary = i18n.Flatten<RawDictionary>
|
||||
|
||||
function cookie(locale: Locale) {
|
||||
return `oc_locale=${encodeURIComponent(locale)}; Path=/; Max-Age=31536000; SameSite=Lax`
|
||||
}
|
||||
|
||||
const LOCALES: readonly Locale[] = [
|
||||
"en",
|
||||
"zh",
|
||||
@@ -203,7 +199,6 @@ export const { use: useLanguage, provider: LanguageProvider } = createSimpleCont
|
||||
createEffect(() => {
|
||||
if (typeof document !== "object") return
|
||||
document.documentElement.lang = locale()
|
||||
document.cookie = cookie(locale())
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
@@ -1758,7 +1758,7 @@ export default function Page() {
|
||||
</div>
|
||||
|
||||
<TerminalPanel
|
||||
open={view().terminal.opened()}
|
||||
open={isDesktop() && view().terminal.opened()}
|
||||
height={layout.terminal.height()}
|
||||
resize={layout.terminal.resize}
|
||||
close={view().terminal.close}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { type ValidComponent, createEffect, createMemo, For, Match, on, onCleanup, Show, Switch } from "solid-js"
|
||||
import { createStore, produce } from "solid-js/store"
|
||||
import { Dynamic } from "solid-js/web"
|
||||
import { sampledChecksum } from "@opencode-ai/util/encode"
|
||||
import { checksum } from "@opencode-ai/util/encode"
|
||||
import { decode64 } from "@/utils/base64"
|
||||
import { showToast } from "@opencode-ai/ui/toast"
|
||||
import { LineComment as LineCommentView, LineCommentEditor } from "@opencode-ai/ui/line-comment"
|
||||
@@ -49,7 +49,7 @@ export function FileTabContent(props: {
|
||||
return props.file.get(p)
|
||||
})
|
||||
const contents = createMemo(() => state()?.content?.content ?? "")
|
||||
const cacheKey = createMemo(() => sampledChecksum(contents()))
|
||||
const cacheKey = createMemo(() => checksum(contents()))
|
||||
const isImage = createMemo(() => {
|
||||
const c = state()?.content
|
||||
return c?.encoding === "base64" && c?.mimeType?.startsWith("image/") && c?.mimeType !== "image/svg+xml"
|
||||
@@ -163,20 +163,11 @@ export function FileTabContent(props: {
|
||||
return
|
||||
}
|
||||
|
||||
const estimateTop = (range: SelectedLineRange) => {
|
||||
const line = Math.max(range.start, range.end)
|
||||
const height = 24
|
||||
const offset = 2
|
||||
return Math.max(0, (line - 1) * height + offset)
|
||||
}
|
||||
|
||||
const large = contents().length > 500_000
|
||||
|
||||
const next: Record<string, number> = {}
|
||||
for (const comment of fileComments()) {
|
||||
const marker = findMarker(root, comment.selection)
|
||||
if (marker) next[comment.id] = markerTop(el, marker)
|
||||
else if (large) next[comment.id] = estimateTop(comment.selection)
|
||||
if (!marker) continue
|
||||
next[comment.id] = markerTop(el, marker)
|
||||
}
|
||||
|
||||
const removed = Object.keys(note.positions).filter((id) => next[id] === undefined)
|
||||
@@ -203,12 +194,12 @@ export function FileTabContent(props: {
|
||||
}
|
||||
|
||||
const marker = findMarker(root, range)
|
||||
if (marker) {
|
||||
setNote("draftTop", markerTop(el, marker))
|
||||
if (!marker) {
|
||||
setNote("draftTop", undefined)
|
||||
return
|
||||
}
|
||||
|
||||
setNote("draftTop", large ? estimateTop(range) : undefined)
|
||||
setNote("draftTop", markerTop(el, marker))
|
||||
}
|
||||
|
||||
const scheduleComments = () => {
|
||||
|
||||
@@ -2,6 +2,4 @@ preload = ["@opentui/solid/preload"]
|
||||
|
||||
[test]
|
||||
preload = ["./test/preload.ts"]
|
||||
# timeout is not actually parsed from bunfig.toml (see src/bunfig.zig in oven-sh/bun)
|
||||
# using --timeout in package.json scripts instead
|
||||
# https://github.com/oven-sh/bun/issues/7789
|
||||
timeout = 30000 # 30 seconds - allow time for package installation
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"typecheck": "tsgo --noEmit",
|
||||
"test": "bun test --timeout 30000",
|
||||
"test": "bun test",
|
||||
"build": "bun run script/build.ts",
|
||||
"dev": "bun run --conditions=browser ./src/index.ts",
|
||||
"random": "echo 'Random script updated at $(date)' && echo 'Change queued successfully' && echo 'Another change made' && echo 'Yet another change' && echo 'One more change' && echo 'Final change' && echo 'Another final change' && echo 'Yet another final change'",
|
||||
|
||||
@@ -360,7 +360,7 @@ export namespace ProviderTransform {
|
||||
|
||||
switch (model.api.npm) {
|
||||
case "@openrouter/ai-sdk-provider":
|
||||
if (!model.id.includes("gpt") && !model.id.includes("gemini-3")) return {}
|
||||
if (!model.id.includes("gpt") && !model.id.includes("gemini-3") && !model.id.includes("claude")) return {}
|
||||
return Object.fromEntries(OPENAI_EFFORTS.map((effort) => [effort, { reasoning: { effort } }]))
|
||||
|
||||
// TODO: YOU CANNOT SET max_tokens if this is set!!!
|
||||
@@ -720,6 +720,10 @@ export namespace ProviderTransform {
|
||||
result["promptCacheKey"] = input.sessionID
|
||||
}
|
||||
|
||||
if (input.model.providerID === "openrouter") {
|
||||
result["prompt_cache_key"] = input.sessionID
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
@@ -1,27 +1,10 @@
|
||||
import {
|
||||
DEFAULT_VIRTUAL_FILE_METRICS,
|
||||
type FileContents,
|
||||
File,
|
||||
FileOptions,
|
||||
LineAnnotation,
|
||||
type SelectedLineRange,
|
||||
type VirtualFileMetrics,
|
||||
VirtualizedFile,
|
||||
Virtualizer,
|
||||
} from "@pierre/diffs"
|
||||
import { type FileContents, File, FileOptions, LineAnnotation, type SelectedLineRange } from "@pierre/diffs"
|
||||
import { ComponentProps, createEffect, createMemo, createSignal, onCleanup, onMount, Show, splitProps } from "solid-js"
|
||||
import { Portal } from "solid-js/web"
|
||||
import { createDefaultOptions, styleVariables } from "../pierre"
|
||||
import { getWorkerPool } from "../pierre/worker"
|
||||
import { Icon } from "./icon"
|
||||
|
||||
const VIRTUALIZE_BYTES = 500_000
|
||||
const codeMetrics = {
|
||||
...DEFAULT_VIRTUAL_FILE_METRICS,
|
||||
lineHeight: 24,
|
||||
fileGap: 0,
|
||||
} satisfies Partial<VirtualFileMetrics>
|
||||
|
||||
type SelectionSide = "additions" | "deletions"
|
||||
|
||||
export type CodeProps<T = {}> = FileOptions<T> & {
|
||||
@@ -177,28 +160,16 @@ export function Code<T>(props: CodeProps<T>) {
|
||||
|
||||
const [findPos, setFindPos] = createSignal<{ top: number; right: number }>({ top: 8, right: 8 })
|
||||
|
||||
let instance: File<T> | VirtualizedFile<T> | undefined
|
||||
let virtualizer: Virtualizer | undefined
|
||||
let virtualRoot: Document | HTMLElement | undefined
|
||||
|
||||
const bytes = createMemo(() => {
|
||||
const value = local.file.contents as unknown
|
||||
if (typeof value === "string") return value.length
|
||||
if (Array.isArray(value)) {
|
||||
return value.reduce(
|
||||
(acc, part) => acc + (typeof part === "string" ? part.length + 1 : String(part).length + 1),
|
||||
0,
|
||||
)
|
||||
}
|
||||
if (value == null) return 0
|
||||
return String(value).length
|
||||
})
|
||||
const virtual = createMemo(() => bytes() > VIRTUALIZE_BYTES)
|
||||
|
||||
const options = createMemo(() => ({
|
||||
...createDefaultOptions<T>("unified"),
|
||||
...others,
|
||||
}))
|
||||
const file = createMemo(
|
||||
() =>
|
||||
new File<T>(
|
||||
{
|
||||
...createDefaultOptions<T>("unified"),
|
||||
...others,
|
||||
},
|
||||
getWorkerPool("unified"),
|
||||
),
|
||||
)
|
||||
|
||||
const getRoot = () => {
|
||||
const host = container.querySelector("diffs-container")
|
||||
@@ -606,14 +577,6 @@ export function Code<T>(props: CodeProps<T>) {
|
||||
}
|
||||
|
||||
const applySelection = (range: SelectedLineRange | null) => {
|
||||
const current = instance
|
||||
if (!current) return false
|
||||
|
||||
if (virtual()) {
|
||||
current.setSelectedLines(range)
|
||||
return true
|
||||
}
|
||||
|
||||
const root = getRoot()
|
||||
if (!root) return false
|
||||
|
||||
@@ -621,7 +584,7 @@ export function Code<T>(props: CodeProps<T>) {
|
||||
if (root.querySelectorAll("[data-line]").length < lines) return false
|
||||
|
||||
if (!range) {
|
||||
current.setSelectedLines(null)
|
||||
file().setSelectedLines(null)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -629,12 +592,12 @@ export function Code<T>(props: CodeProps<T>) {
|
||||
const end = Math.max(range.start, range.end)
|
||||
|
||||
if (start < 1 || end > lines) {
|
||||
current.setSelectedLines(null)
|
||||
file().setSelectedLines(null)
|
||||
return true
|
||||
}
|
||||
|
||||
if (!root.querySelector(`[data-line="${start}"]`) || !root.querySelector(`[data-line="${end}"]`)) {
|
||||
current.setSelectedLines(null)
|
||||
file().setSelectedLines(null)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -645,7 +608,7 @@ export function Code<T>(props: CodeProps<T>) {
|
||||
return { start: range.start, end: range.end }
|
||||
})()
|
||||
|
||||
current.setSelectedLines(normalized)
|
||||
file().setSelectedLines(normalized)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -656,12 +619,9 @@ export function Code<T>(props: CodeProps<T>) {
|
||||
|
||||
const token = renderToken
|
||||
|
||||
const lines = virtual() ? undefined : lineCount()
|
||||
const lines = lineCount()
|
||||
|
||||
const isReady = (root: ShadowRoot) =>
|
||||
virtual()
|
||||
? root.querySelector("[data-line]") != null
|
||||
: root.querySelectorAll("[data-line]").length >= (lines ?? 0)
|
||||
const isReady = (root: ShadowRoot) => root.querySelectorAll("[data-line]").length >= lines
|
||||
|
||||
const notify = () => {
|
||||
if (token !== renderToken) return
|
||||
@@ -884,41 +844,20 @@ export function Code<T>(props: CodeProps<T>) {
|
||||
}
|
||||
|
||||
createEffect(() => {
|
||||
const opts = options()
|
||||
const workerPool = getWorkerPool("unified")
|
||||
const isVirtual = virtual()
|
||||
const current = file()
|
||||
|
||||
onCleanup(() => {
|
||||
current.cleanUp()
|
||||
})
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
observer?.disconnect()
|
||||
observer = undefined
|
||||
|
||||
instance?.cleanUp()
|
||||
instance = undefined
|
||||
|
||||
if (!isVirtual && virtualizer) {
|
||||
virtualizer.cleanUp()
|
||||
virtualizer = undefined
|
||||
virtualRoot = undefined
|
||||
}
|
||||
|
||||
const v = (() => {
|
||||
if (!isVirtual) return
|
||||
if (typeof document === "undefined") return
|
||||
|
||||
const root = getScrollParent(wrapper) ?? document
|
||||
if (virtualizer && virtualRoot === root) return virtualizer
|
||||
|
||||
virtualizer?.cleanUp()
|
||||
virtualizer = new Virtualizer()
|
||||
virtualRoot = root
|
||||
virtualizer.setup(root, root instanceof Document ? undefined : wrapper)
|
||||
return virtualizer
|
||||
})()
|
||||
|
||||
instance = isVirtual && v ? new VirtualizedFile<T>(opts, v, codeMetrics, workerPool) : new File<T>(opts, workerPool)
|
||||
|
||||
container.innerHTML = ""
|
||||
const value = text()
|
||||
instance.render({
|
||||
file().render({
|
||||
file: typeof local.file.contents === "string" ? local.file : { ...local.file, contents: value },
|
||||
lineAnnotations: local.annotations,
|
||||
containerWrapper: container,
|
||||
@@ -971,13 +910,6 @@ export function Code<T>(props: CodeProps<T>) {
|
||||
onCleanup(() => {
|
||||
observer?.disconnect()
|
||||
|
||||
instance?.cleanUp()
|
||||
instance = undefined
|
||||
|
||||
virtualizer?.cleanUp()
|
||||
virtualizer = undefined
|
||||
virtualRoot = undefined
|
||||
|
||||
clearOverlayScroll()
|
||||
clearOverlay()
|
||||
if (findCurrent === host) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { sampledChecksum } from "@opencode-ai/util/encode"
|
||||
import { FileDiff, type FileDiffOptions, type SelectedLineRange, VirtualizedFileDiff } from "@pierre/diffs"
|
||||
import { checksum } from "@opencode-ai/util/encode"
|
||||
import { FileDiff, type SelectedLineRange, VirtualizedFileDiff } from "@pierre/diffs"
|
||||
import { createMediaQuery } from "@solid-primitives/media"
|
||||
import { createEffect, createMemo, createSignal, onCleanup, splitProps } from "solid-js"
|
||||
import { createDefaultOptions, type DiffProps, styleVariables } from "../pierre"
|
||||
@@ -78,29 +78,14 @@ export function Diff<T>(props: DiffProps<T>) {
|
||||
|
||||
const mobile = createMediaQuery("(max-width: 640px)")
|
||||
|
||||
const large = createMemo(() => {
|
||||
const before = typeof local.before?.contents === "string" ? local.before.contents : ""
|
||||
const after = typeof local.after?.contents === "string" ? local.after.contents : ""
|
||||
return Math.max(before.length, after.length) > 500_000
|
||||
})
|
||||
|
||||
const largeOptions = {
|
||||
lineDiffType: "none",
|
||||
maxLineDiffLength: 0,
|
||||
tokenizeMaxLineLength: 1,
|
||||
} satisfies Pick<FileDiffOptions<T>, "lineDiffType" | "maxLineDiffLength" | "tokenizeMaxLineLength">
|
||||
|
||||
const options = createMemo<FileDiffOptions<T>>(() => {
|
||||
const base = {
|
||||
const options = createMemo(() => {
|
||||
const opts = {
|
||||
...createDefaultOptions(props.diffStyle),
|
||||
...others,
|
||||
}
|
||||
|
||||
const perf = large() ? { ...base, ...largeOptions } : base
|
||||
if (!mobile()) return perf
|
||||
|
||||
if (!mobile()) return opts
|
||||
return {
|
||||
...perf,
|
||||
...opts,
|
||||
disableLineNumbers: true,
|
||||
}
|
||||
})
|
||||
@@ -543,17 +528,12 @@ export function Diff<T>(props: DiffProps<T>) {
|
||||
|
||||
createEffect(() => {
|
||||
const opts = options()
|
||||
const workerPool = large() ? getWorkerPool("unified") : getWorkerPool(props.diffStyle)
|
||||
const workerPool = getWorkerPool(props.diffStyle)
|
||||
const virtualizer = getVirtualizer()
|
||||
const annotations = local.annotations
|
||||
const beforeContents = typeof local.before?.contents === "string" ? local.before.contents : ""
|
||||
const afterContents = typeof local.after?.contents === "string" ? local.after.contents : ""
|
||||
|
||||
const cacheKey = (contents: string) => {
|
||||
if (!large()) return sampledChecksum(contents, contents.length)
|
||||
return sampledChecksum(contents)
|
||||
}
|
||||
|
||||
instance?.cleanUp()
|
||||
instance = virtualizer
|
||||
? new VirtualizedFileDiff<T>(opts, virtualizer, virtualMetrics, workerPool)
|
||||
@@ -565,12 +545,12 @@ export function Diff<T>(props: DiffProps<T>) {
|
||||
oldFile: {
|
||||
...local.before,
|
||||
contents: beforeContents,
|
||||
cacheKey: cacheKey(beforeContents),
|
||||
cacheKey: checksum(beforeContents),
|
||||
},
|
||||
newFile: {
|
||||
...local.after,
|
||||
contents: afterContents,
|
||||
cacheKey: cacheKey(afterContents),
|
||||
cacheKey: checksum(afterContents),
|
||||
},
|
||||
lineAnnotations: annotations,
|
||||
containerWrapper: container,
|
||||
|
||||
@@ -209,8 +209,3 @@
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
[data-component="markdown"] a.external-link:hover > code {
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
|
||||
@@ -49,19 +49,6 @@ type CopyLabels = {
|
||||
copied: string
|
||||
}
|
||||
|
||||
const urlPattern = /^https?:\/\/[^\s<>()`"']+$/
|
||||
|
||||
function codeUrl(text: string) {
|
||||
const href = text.trim().replace(/[),.;!?]+$/, "")
|
||||
if (!urlPattern.test(href)) return
|
||||
try {
|
||||
const url = new URL(href)
|
||||
return url.toString()
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function createIcon(path: string, slot: string) {
|
||||
const icon = document.createElement("div")
|
||||
icon.setAttribute("data-component", "icon")
|
||||
@@ -123,39 +110,9 @@ function setupCodeCopy(root: HTMLDivElement, labels: CopyLabels) {
|
||||
wrapper.appendChild(createCopyButton(labels))
|
||||
}
|
||||
|
||||
const markCodeLinks = () => {
|
||||
const codeNodes = Array.from(root.querySelectorAll(":not(pre) > code"))
|
||||
for (const code of codeNodes) {
|
||||
const href = codeUrl(code.textContent ?? "")
|
||||
const parentLink =
|
||||
code.parentElement instanceof HTMLAnchorElement && code.parentElement.classList.contains("external-link")
|
||||
? code.parentElement
|
||||
: null
|
||||
|
||||
if (!href) {
|
||||
if (parentLink) parentLink.replaceWith(code)
|
||||
continue
|
||||
}
|
||||
|
||||
if (parentLink) {
|
||||
parentLink.href = href
|
||||
continue
|
||||
}
|
||||
|
||||
const link = document.createElement("a")
|
||||
link.href = href
|
||||
link.className = "external-link"
|
||||
link.target = "_blank"
|
||||
link.rel = "noopener noreferrer"
|
||||
code.parentNode?.replaceChild(link, code)
|
||||
link.appendChild(code)
|
||||
}
|
||||
}
|
||||
|
||||
const handleClick = async (event: MouseEvent) => {
|
||||
const target = event.target
|
||||
if (!(target instanceof Element)) return
|
||||
|
||||
const button = target.closest('[data-slot="markdown-copy-button"]')
|
||||
if (!(button instanceof HTMLButtonElement)) return
|
||||
const code = button.closest('[data-component="markdown-code"]')?.querySelector("code")
|
||||
@@ -175,7 +132,6 @@ function setupCodeCopy(root: HTMLDivElement, labels: CopyLabels) {
|
||||
for (const block of blocks) {
|
||||
ensureWrapper(block)
|
||||
}
|
||||
markCodeLinks()
|
||||
|
||||
const buttons = Array.from(root.querySelectorAll('[data-slot="markdown-copy-button"]'))
|
||||
for (const button of buttons) {
|
||||
|
||||
@@ -222,30 +222,4 @@
|
||||
--line-comment-popover-z: 30;
|
||||
--line-comment-open-z: 6;
|
||||
}
|
||||
|
||||
[data-slot="session-review-large-diff"] {
|
||||
padding: 12px;
|
||||
background: var(--background-stronger);
|
||||
}
|
||||
|
||||
[data-slot="session-review-large-diff-title"] {
|
||||
font-family: var(--font-family-sans);
|
||||
font-size: var(--font-size-small);
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--text-strong);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
[data-slot="session-review-large-diff-meta"] {
|
||||
font-family: var(--font-family-sans);
|
||||
font-size: var(--font-size-small);
|
||||
color: var(--text-weak);
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
[data-slot="session-review-large-diff-actions"] {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,26 +17,6 @@ import { PreloadMultiFileDiffResult } from "@pierre/diffs/ssr"
|
||||
import { type SelectedLineRange } from "@pierre/diffs"
|
||||
import { Dynamic } from "solid-js/web"
|
||||
|
||||
const MAX_DIFF_LINES = 20_000
|
||||
const MAX_DIFF_BYTES = 2_000_000
|
||||
|
||||
function linesOver(text: string, max: number) {
|
||||
let lines = 1
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
if (text.charCodeAt(i) !== 10) continue
|
||||
lines++
|
||||
if (lines > max) return true
|
||||
}
|
||||
return lines > max
|
||||
}
|
||||
|
||||
function formatBytes(bytes: number) {
|
||||
if (!Number.isFinite(bytes) || bytes <= 0) return "0 B"
|
||||
if (bytes < 1024) return `${bytes} B`
|
||||
if (bytes < 1024 * 1024) return `${Math.round((bytes / 1024) * 10) / 10} KB`
|
||||
return `${Math.round((bytes / (1024 * 1024)) * 10) / 10} MB`
|
||||
}
|
||||
|
||||
export type SessionReviewDiffStyle = "unified" | "split"
|
||||
|
||||
export type SessionReviewComment = {
|
||||
@@ -346,28 +326,12 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
{(diff) => {
|
||||
let wrapper: HTMLDivElement | undefined
|
||||
|
||||
const expanded = createMemo(() => open().includes(diff.file))
|
||||
const [force, setForce] = createSignal(false)
|
||||
|
||||
const comments = createMemo(() => (props.comments ?? []).filter((c) => c.file === diff.file))
|
||||
const commentedLines = createMemo(() => comments().map((c) => c.selection))
|
||||
|
||||
const beforeText = () => (typeof diff.before === "string" ? diff.before : "")
|
||||
const afterText = () => (typeof diff.after === "string" ? diff.after : "")
|
||||
|
||||
const tooLarge = createMemo(() => {
|
||||
if (!expanded()) return false
|
||||
if (force()) return false
|
||||
if (isImageFile(diff.file)) return false
|
||||
|
||||
const before = beforeText()
|
||||
const after = afterText()
|
||||
|
||||
if (before.length > MAX_DIFF_BYTES || after.length > MAX_DIFF_BYTES) return true
|
||||
if (linesOver(before, MAX_DIFF_LINES) || linesOver(after, MAX_DIFF_LINES)) return true
|
||||
return false
|
||||
})
|
||||
|
||||
const isAdded = () => diff.status === "added" || (beforeText().length === 0 && afterText().length > 0)
|
||||
const isDeleted = () =>
|
||||
diff.status === "deleted" || (afterText().length === 0 && beforeText().length > 0)
|
||||
@@ -607,114 +571,94 @@ export const SessionReview = (props: SessionReviewProps) => {
|
||||
scheduleAnchors()
|
||||
}}
|
||||
>
|
||||
<Show when={expanded()}>
|
||||
<Switch>
|
||||
<Match when={isImage() && imageSrc()}>
|
||||
<div data-slot="session-review-image-container">
|
||||
<img data-slot="session-review-image" src={imageSrc()} alt={diff.file} />
|
||||
</div>
|
||||
</Match>
|
||||
<Match when={isImage() && isDeleted()}>
|
||||
<div data-slot="session-review-image-container" data-removed>
|
||||
<span data-slot="session-review-image-placeholder">
|
||||
{i18n.t("ui.sessionReview.change.removed")}
|
||||
</span>
|
||||
</div>
|
||||
</Match>
|
||||
<Match when={isImage() && !imageSrc()}>
|
||||
<div data-slot="session-review-image-container">
|
||||
<span data-slot="session-review-image-placeholder">
|
||||
{imageStatus() === "loading"
|
||||
? i18n.t("ui.sessionReview.image.loading")
|
||||
: i18n.t("ui.sessionReview.image.placeholder")}
|
||||
</span>
|
||||
</div>
|
||||
</Match>
|
||||
<Match when={!isImage() && tooLarge()}>
|
||||
<div data-slot="session-review-large-diff">
|
||||
<div data-slot="session-review-large-diff-title">
|
||||
{i18n.t("ui.sessionReview.largeDiff.title")}
|
||||
</div>
|
||||
<div data-slot="session-review-large-diff-meta">
|
||||
Limit: {MAX_DIFF_LINES.toLocaleString()} lines / {formatBytes(MAX_DIFF_BYTES)}.
|
||||
Current: {formatBytes(Math.max(beforeText().length, afterText().length))}.
|
||||
</div>
|
||||
<div data-slot="session-review-large-diff-actions">
|
||||
<Button size="normal" variant="secondary" onClick={() => setForce(true)}>
|
||||
{i18n.t("ui.sessionReview.largeDiff.renderAnyway")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Match>
|
||||
<Match when={!isImage()}>
|
||||
<Dynamic
|
||||
component={diffComponent}
|
||||
preloadedDiff={diff.preloaded}
|
||||
diffStyle={diffStyle()}
|
||||
onRendered={() => {
|
||||
props.onDiffRendered?.()
|
||||
scheduleAnchors()
|
||||
}}
|
||||
enableLineSelection={props.onLineComment != null}
|
||||
onLineSelected={handleLineSelected}
|
||||
onLineSelectionEnd={handleLineSelectionEnd}
|
||||
selectedLines={selectedLines()}
|
||||
commentedLines={commentedLines()}
|
||||
before={{
|
||||
name: diff.file!,
|
||||
contents: typeof diff.before === "string" ? diff.before : "",
|
||||
}}
|
||||
after={{
|
||||
name: diff.file!,
|
||||
contents: typeof diff.after === "string" ? diff.after : "",
|
||||
<Switch>
|
||||
<Match when={isImage() && imageSrc()}>
|
||||
<div data-slot="session-review-image-container">
|
||||
<img data-slot="session-review-image" src={imageSrc()} alt={diff.file} />
|
||||
</div>
|
||||
</Match>
|
||||
<Match when={isImage() && isDeleted()}>
|
||||
<div data-slot="session-review-image-container" data-removed>
|
||||
<span data-slot="session-review-image-placeholder">
|
||||
{i18n.t("ui.sessionReview.change.removed")}
|
||||
</span>
|
||||
</div>
|
||||
</Match>
|
||||
<Match when={isImage() && !imageSrc()}>
|
||||
<div data-slot="session-review-image-container">
|
||||
<span data-slot="session-review-image-placeholder">
|
||||
{imageStatus() === "loading" ? "Loading..." : "Image"}
|
||||
</span>
|
||||
</div>
|
||||
</Match>
|
||||
<Match when={!isImage()}>
|
||||
<Dynamic
|
||||
component={diffComponent}
|
||||
preloadedDiff={diff.preloaded}
|
||||
diffStyle={diffStyle()}
|
||||
onRendered={() => {
|
||||
props.onDiffRendered?.()
|
||||
scheduleAnchors()
|
||||
}}
|
||||
enableLineSelection={props.onLineComment != null}
|
||||
onLineSelected={handleLineSelected}
|
||||
onLineSelectionEnd={handleLineSelectionEnd}
|
||||
selectedLines={selectedLines()}
|
||||
commentedLines={commentedLines()}
|
||||
before={{
|
||||
name: diff.file!,
|
||||
contents: typeof diff.before === "string" ? diff.before : "",
|
||||
}}
|
||||
after={{
|
||||
name: diff.file!,
|
||||
contents: typeof diff.after === "string" ? diff.after : "",
|
||||
}}
|
||||
/>
|
||||
</Match>
|
||||
</Switch>
|
||||
|
||||
<For each={comments()}>
|
||||
{(comment) => (
|
||||
<LineComment
|
||||
id={comment.id}
|
||||
top={positions()[comment.id]}
|
||||
onMouseEnter={() => setSelection({ file: comment.file, range: comment.selection })}
|
||||
onClick={() => {
|
||||
if (isCommentOpen(comment)) {
|
||||
setOpened(null)
|
||||
return
|
||||
}
|
||||
|
||||
openComment(comment)
|
||||
}}
|
||||
open={isCommentOpen(comment)}
|
||||
comment={comment.comment}
|
||||
selection={selectionLabel(comment.selection)}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
|
||||
<Show when={draftRange()}>
|
||||
{(range) => (
|
||||
<Show when={draftTop() !== undefined}>
|
||||
<LineCommentEditor
|
||||
top={draftTop()}
|
||||
value={draft()}
|
||||
selection={selectionLabel(range())}
|
||||
onInput={setDraft}
|
||||
onCancel={() => setCommenting(null)}
|
||||
onSubmit={(comment) => {
|
||||
props.onLineComment?.({
|
||||
file: diff.file,
|
||||
selection: range(),
|
||||
comment,
|
||||
preview: selectionPreview(diff, range()),
|
||||
})
|
||||
setCommenting(null)
|
||||
}}
|
||||
/>
|
||||
</Match>
|
||||
</Switch>
|
||||
|
||||
<For each={comments()}>
|
||||
{(comment) => (
|
||||
<LineComment
|
||||
id={comment.id}
|
||||
top={positions()[comment.id]}
|
||||
onMouseEnter={() => setSelection({ file: comment.file, range: comment.selection })}
|
||||
onClick={() => {
|
||||
if (isCommentOpen(comment)) {
|
||||
setOpened(null)
|
||||
return
|
||||
}
|
||||
|
||||
openComment(comment)
|
||||
}}
|
||||
open={isCommentOpen(comment)}
|
||||
comment={comment.comment}
|
||||
selection={selectionLabel(comment.selection)}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
|
||||
<Show when={draftRange()}>
|
||||
{(range) => (
|
||||
<Show when={draftTop() !== undefined}>
|
||||
<LineCommentEditor
|
||||
top={draftTop()}
|
||||
value={draft()}
|
||||
selection={selectionLabel(range())}
|
||||
onInput={setDraft}
|
||||
onCancel={() => setCommenting(null)}
|
||||
onSubmit={(comment) => {
|
||||
props.onLineComment?.({
|
||||
file: diff.file,
|
||||
selection: range(),
|
||||
comment,
|
||||
preview: selectionPreview(diff, range()),
|
||||
})
|
||||
setCommenting(null)
|
||||
}}
|
||||
/>
|
||||
</Show>
|
||||
)}
|
||||
</Show>
|
||||
</Show>
|
||||
)}
|
||||
</Show>
|
||||
</div>
|
||||
</Accordion.Content>
|
||||
|
||||
@@ -8,11 +8,6 @@ export const dict = {
|
||||
"ui.sessionReview.change.added": "مضاف",
|
||||
"ui.sessionReview.change.removed": "محذوف",
|
||||
"ui.sessionReview.change.modified": "معدل",
|
||||
"ui.sessionReview.image.loading": "جار التحميل...",
|
||||
"ui.sessionReview.image.placeholder": "صورة",
|
||||
"ui.sessionReview.largeDiff.title": "Diff كبير جدا لعرضه",
|
||||
"ui.sessionReview.largeDiff.meta": "الحد: {{lines}} سطر / {{limit}}. الحالي: {{current}}.",
|
||||
"ui.sessionReview.largeDiff.renderAnyway": "اعرض على أي حال",
|
||||
|
||||
"ui.lineComment.label.prefix": "تعليق على ",
|
||||
"ui.lineComment.label.suffix": "",
|
||||
|
||||
@@ -8,11 +8,6 @@ export const dict = {
|
||||
"ui.sessionReview.change.added": "Adicionado",
|
||||
"ui.sessionReview.change.removed": "Removido",
|
||||
"ui.sessionReview.change.modified": "Modificado",
|
||||
"ui.sessionReview.image.loading": "Carregando...",
|
||||
"ui.sessionReview.image.placeholder": "Imagem",
|
||||
"ui.sessionReview.largeDiff.title": "Diff grande demais para renderizar",
|
||||
"ui.sessionReview.largeDiff.meta": "Limite: {{lines}} linhas / {{limit}}. Atual: {{current}}.",
|
||||
"ui.sessionReview.largeDiff.renderAnyway": "Renderizar mesmo assim",
|
||||
|
||||
"ui.lineComment.label.prefix": "Comentar em ",
|
||||
"ui.lineComment.label.suffix": "",
|
||||
|
||||
@@ -12,11 +12,6 @@ export const dict = {
|
||||
"ui.sessionReview.change.added": "Dodano",
|
||||
"ui.sessionReview.change.removed": "Uklonjeno",
|
||||
"ui.sessionReview.change.modified": "Izmijenjeno",
|
||||
"ui.sessionReview.image.loading": "Učitavanje...",
|
||||
"ui.sessionReview.image.placeholder": "Slika",
|
||||
"ui.sessionReview.largeDiff.title": "Diff je prevelik za prikaz",
|
||||
"ui.sessionReview.largeDiff.meta": "Limit: {{lines}} linija / {{limit}}. Trenutno: {{current}}.",
|
||||
"ui.sessionReview.largeDiff.renderAnyway": "Prikaži svejedno",
|
||||
|
||||
"ui.lineComment.label.prefix": "Komentar na ",
|
||||
"ui.lineComment.label.suffix": "",
|
||||
|
||||
@@ -9,11 +9,6 @@ export const dict = {
|
||||
"ui.sessionReview.change.added": "Tilføjet",
|
||||
"ui.sessionReview.change.removed": "Fjernet",
|
||||
"ui.sessionReview.change.modified": "Ændret",
|
||||
"ui.sessionReview.image.loading": "Indlæser...",
|
||||
"ui.sessionReview.image.placeholder": "Billede",
|
||||
"ui.sessionReview.largeDiff.title": "Diff er for stor til at blive vist",
|
||||
"ui.sessionReview.largeDiff.meta": "Grænse: {{lines}} linjer / {{limit}}. Nuværende: {{current}}.",
|
||||
"ui.sessionReview.largeDiff.renderAnyway": "Vis alligevel",
|
||||
"ui.lineComment.label.prefix": "Kommenter på ",
|
||||
"ui.lineComment.label.suffix": "",
|
||||
"ui.lineComment.editorLabel.prefix": "Kommenterer på ",
|
||||
|
||||
@@ -13,11 +13,6 @@ export const dict = {
|
||||
"ui.sessionReview.change.added": "Hinzugefügt",
|
||||
"ui.sessionReview.change.removed": "Entfernt",
|
||||
"ui.sessionReview.change.modified": "Geändert",
|
||||
"ui.sessionReview.image.loading": "Wird geladen...",
|
||||
"ui.sessionReview.image.placeholder": "Bild",
|
||||
"ui.sessionReview.largeDiff.title": "Diff zu groß zum Rendern",
|
||||
"ui.sessionReview.largeDiff.meta": "Limit: {{lines}} Zeilen / {{limit}}. Aktuell: {{current}}.",
|
||||
"ui.sessionReview.largeDiff.renderAnyway": "Trotzdem rendern",
|
||||
"ui.lineComment.label.prefix": "Kommentar zu ",
|
||||
"ui.lineComment.label.suffix": "",
|
||||
"ui.lineComment.editorLabel.prefix": "Kommentiere ",
|
||||
|
||||
@@ -8,11 +8,6 @@ export const dict = {
|
||||
"ui.sessionReview.change.added": "Added",
|
||||
"ui.sessionReview.change.removed": "Removed",
|
||||
"ui.sessionReview.change.modified": "Modified",
|
||||
"ui.sessionReview.image.loading": "Loading...",
|
||||
"ui.sessionReview.image.placeholder": "Image",
|
||||
"ui.sessionReview.largeDiff.title": "Diff too large to render",
|
||||
"ui.sessionReview.largeDiff.meta": "Limit: {{lines}} lines / {{limit}}. Current: {{current}}.",
|
||||
"ui.sessionReview.largeDiff.renderAnyway": "Render anyway",
|
||||
|
||||
"ui.lineComment.label.prefix": "Comment on ",
|
||||
"ui.lineComment.label.suffix": "",
|
||||
|
||||
@@ -8,11 +8,6 @@ export const dict = {
|
||||
"ui.sessionReview.change.added": "Añadido",
|
||||
"ui.sessionReview.change.removed": "Eliminado",
|
||||
"ui.sessionReview.change.modified": "Modificado",
|
||||
"ui.sessionReview.image.loading": "Cargando...",
|
||||
"ui.sessionReview.image.placeholder": "Imagen",
|
||||
"ui.sessionReview.largeDiff.title": "Diff demasiado grande para renderizar",
|
||||
"ui.sessionReview.largeDiff.meta": "Límite: {{lines}} líneas / {{limit}}. Actual: {{current}}.",
|
||||
"ui.sessionReview.largeDiff.renderAnyway": "Renderizar de todos modos",
|
||||
|
||||
"ui.lineComment.label.prefix": "Comentar en ",
|
||||
"ui.lineComment.label.suffix": "",
|
||||
|
||||
@@ -8,11 +8,6 @@ export const dict = {
|
||||
"ui.sessionReview.change.added": "Ajouté",
|
||||
"ui.sessionReview.change.removed": "Supprimé",
|
||||
"ui.sessionReview.change.modified": "Modifié",
|
||||
"ui.sessionReview.image.loading": "Chargement...",
|
||||
"ui.sessionReview.image.placeholder": "Image",
|
||||
"ui.sessionReview.largeDiff.title": "Diff trop volumineux pour être affiché",
|
||||
"ui.sessionReview.largeDiff.meta": "Limite : {{lines}} lignes / {{limit}}. Actuel : {{current}}.",
|
||||
"ui.sessionReview.largeDiff.renderAnyway": "Afficher quand même",
|
||||
|
||||
"ui.lineComment.label.prefix": "Commenter sur ",
|
||||
"ui.lineComment.label.suffix": "",
|
||||
|
||||
@@ -9,11 +9,6 @@ export const dict = {
|
||||
"ui.sessionReview.change.added": "追加",
|
||||
"ui.sessionReview.change.removed": "削除",
|
||||
"ui.sessionReview.change.modified": "変更",
|
||||
"ui.sessionReview.image.loading": "読み込み中...",
|
||||
"ui.sessionReview.image.placeholder": "画像",
|
||||
"ui.sessionReview.largeDiff.title": "差分が大きすぎて表示できません",
|
||||
"ui.sessionReview.largeDiff.meta": "上限: {{lines}} 行 / {{limit}}。現在: {{current}}。",
|
||||
"ui.sessionReview.largeDiff.renderAnyway": "それでも表示する",
|
||||
"ui.lineComment.label.prefix": "",
|
||||
"ui.lineComment.label.suffix": "へのコメント",
|
||||
"ui.lineComment.editorLabel.prefix": "",
|
||||
|
||||
@@ -8,11 +8,6 @@ export const dict = {
|
||||
"ui.sessionReview.change.added": "추가됨",
|
||||
"ui.sessionReview.change.removed": "삭제됨",
|
||||
"ui.sessionReview.change.modified": "수정됨",
|
||||
"ui.sessionReview.image.loading": "로딩 중...",
|
||||
"ui.sessionReview.image.placeholder": "이미지",
|
||||
"ui.sessionReview.largeDiff.title": "차이가 너무 커서 렌더링할 수 없습니다",
|
||||
"ui.sessionReview.largeDiff.meta": "제한: {{lines}}줄 / {{limit}}. 현재: {{current}}.",
|
||||
"ui.sessionReview.largeDiff.renderAnyway": "그래도 렌더링",
|
||||
|
||||
"ui.lineComment.label.prefix": "",
|
||||
"ui.lineComment.label.suffix": "에 댓글 달기",
|
||||
|
||||
@@ -11,11 +11,6 @@ export const dict: Record<Keys, string> = {
|
||||
"ui.sessionReview.change.added": "Lagt til",
|
||||
"ui.sessionReview.change.removed": "Fjernet",
|
||||
"ui.sessionReview.change.modified": "Endret",
|
||||
"ui.sessionReview.image.loading": "Laster...",
|
||||
"ui.sessionReview.image.placeholder": "Bilde",
|
||||
"ui.sessionReview.largeDiff.title": "Diff er for stor til å gjengi",
|
||||
"ui.sessionReview.largeDiff.meta": "Grense: {{lines}} linjer / {{limit}}. Nåværende: {{current}}.",
|
||||
"ui.sessionReview.largeDiff.renderAnyway": "Gjengi likevel",
|
||||
|
||||
"ui.lineComment.label.prefix": "Kommenter på ",
|
||||
"ui.lineComment.label.suffix": "",
|
||||
|
||||
@@ -9,11 +9,6 @@ export const dict = {
|
||||
"ui.sessionReview.change.added": "Dodano",
|
||||
"ui.sessionReview.change.removed": "Usunięto",
|
||||
"ui.sessionReview.change.modified": "Zmodyfikowano",
|
||||
"ui.sessionReview.image.loading": "Ładowanie...",
|
||||
"ui.sessionReview.image.placeholder": "Obraz",
|
||||
"ui.sessionReview.largeDiff.title": "Diff jest zbyt duży, aby go wyrenderować",
|
||||
"ui.sessionReview.largeDiff.meta": "Limit: {{lines}} linii / {{limit}}. Obecnie: {{current}}.",
|
||||
"ui.sessionReview.largeDiff.renderAnyway": "Renderuj mimo to",
|
||||
"ui.lineComment.label.prefix": "Komentarz do ",
|
||||
"ui.lineComment.label.suffix": "",
|
||||
"ui.lineComment.editorLabel.prefix": "Komentowanie: ",
|
||||
|
||||
@@ -9,11 +9,6 @@ export const dict = {
|
||||
"ui.sessionReview.change.added": "Добавлено",
|
||||
"ui.sessionReview.change.removed": "Удалено",
|
||||
"ui.sessionReview.change.modified": "Изменено",
|
||||
"ui.sessionReview.image.loading": "Загрузка...",
|
||||
"ui.sessionReview.image.placeholder": "Изображение",
|
||||
"ui.sessionReview.largeDiff.title": "Diff слишком большой для отображения",
|
||||
"ui.sessionReview.largeDiff.meta": "Лимит: {{lines}} строк / {{limit}}. Текущий: {{current}}.",
|
||||
"ui.sessionReview.largeDiff.renderAnyway": "Отобразить всё равно",
|
||||
"ui.lineComment.label.prefix": "Комментарий к ",
|
||||
"ui.lineComment.label.suffix": "",
|
||||
"ui.lineComment.editorLabel.prefix": "Комментирование: ",
|
||||
|
||||
@@ -8,11 +8,6 @@ export const dict = {
|
||||
"ui.sessionReview.change.added": "เพิ่ม",
|
||||
"ui.sessionReview.change.removed": "ลบ",
|
||||
"ui.sessionReview.change.modified": "แก้ไข",
|
||||
"ui.sessionReview.image.loading": "กำลังโหลด...",
|
||||
"ui.sessionReview.image.placeholder": "รูปภาพ",
|
||||
"ui.sessionReview.largeDiff.title": "Diff มีขนาดใหญ่เกินไปจนไม่สามารถแสดงผลได้",
|
||||
"ui.sessionReview.largeDiff.meta": "ขีดจำกัด: {{lines}} บรรทัด / {{limit}}. ปัจจุบัน: {{current}}.",
|
||||
"ui.sessionReview.largeDiff.renderAnyway": "แสดงผลต่อไป",
|
||||
|
||||
"ui.lineComment.label.prefix": "แสดงความคิดเห็นบน ",
|
||||
"ui.lineComment.label.suffix": "",
|
||||
|
||||
@@ -12,11 +12,6 @@ export const dict = {
|
||||
"ui.sessionReview.change.added": "已添加",
|
||||
"ui.sessionReview.change.removed": "已移除",
|
||||
"ui.sessionReview.change.modified": "已修改",
|
||||
"ui.sessionReview.image.loading": "加载中...",
|
||||
"ui.sessionReview.image.placeholder": "图片",
|
||||
"ui.sessionReview.largeDiff.title": "差异过大,无法渲染",
|
||||
"ui.sessionReview.largeDiff.meta": "限制:{{lines}} 行 / {{limit}}。当前:{{current}}。",
|
||||
"ui.sessionReview.largeDiff.renderAnyway": "仍然渲染",
|
||||
|
||||
"ui.lineComment.label.prefix": "评论 ",
|
||||
"ui.lineComment.label.suffix": "",
|
||||
|
||||
@@ -12,11 +12,6 @@ export const dict = {
|
||||
"ui.sessionReview.change.added": "已新增",
|
||||
"ui.sessionReview.change.removed": "已移除",
|
||||
"ui.sessionReview.change.modified": "已修改",
|
||||
"ui.sessionReview.image.loading": "載入中...",
|
||||
"ui.sessionReview.image.placeholder": "圖片",
|
||||
"ui.sessionReview.largeDiff.title": "差異過大,無法渲染",
|
||||
"ui.sessionReview.largeDiff.meta": "限制:{{lines}} 行 / {{limit}}。目前:{{current}}。",
|
||||
"ui.sessionReview.largeDiff.renderAnyway": "仍然渲染",
|
||||
|
||||
"ui.lineComment.label.prefix": "評論 ",
|
||||
"ui.lineComment.label.suffix": "",
|
||||
|
||||
@@ -28,24 +28,3 @@ export function checksum(content: string): string | undefined {
|
||||
}
|
||||
return (hash >>> 0).toString(36)
|
||||
}
|
||||
|
||||
export function sampledChecksum(content: string, limit = 500_000): string | undefined {
|
||||
if (!content) return undefined
|
||||
if (content.length <= limit) return checksum(content)
|
||||
|
||||
const size = 4096
|
||||
const points = [
|
||||
0,
|
||||
Math.floor(content.length * 0.25),
|
||||
Math.floor(content.length * 0.5),
|
||||
Math.floor(content.length * 0.75),
|
||||
content.length - size,
|
||||
]
|
||||
const hashes = points
|
||||
.map((point) => {
|
||||
const start = Math.max(0, Math.min(content.length - size, point - Math.floor(size / 2)))
|
||||
return checksum(content.slice(start, start + size)) ?? ""
|
||||
})
|
||||
.join(":")
|
||||
return `${content.length}:${hashes}`
|
||||
}
|
||||
|
||||
@@ -84,8 +84,7 @@ curl -fsSL https://opencode.ai/install | bash
|
||||
- **باستخدام Paru على Arch Linux**
|
||||
|
||||
```bash
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
@@ -84,8 +84,7 @@ Du kan også installere det med følgende kommandoer:
|
||||
- **Brug af Paru på Arch Linux**
|
||||
|
||||
```bash
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
@@ -84,8 +84,7 @@ Sie können es auch mit den folgenden Befehlen installieren:
|
||||
- **Verwendung von Paru unter Arch Linux**
|
||||
|
||||
```bash
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
@@ -84,8 +84,7 @@ También puedes instalarlo con los siguientes comandos:
|
||||
- **Usando Paru en Arch Linux**
|
||||
|
||||
```bash
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
@@ -84,8 +84,7 @@ Vous pouvez également l'installer avec les commandes suivantes :
|
||||
- **Via Paru sur Arch Linux**
|
||||
|
||||
```bash
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
@@ -81,11 +81,10 @@ You can also install it with the following commands:
|
||||
|
||||
> We recommend using the OpenCode tap for the most up to date releases. The official `brew install opencode` formula is maintained by the Homebrew team and is updated less frequently.
|
||||
|
||||
- **Installing on Arch Linux**
|
||||
- **Using Paru on Arch Linux**
|
||||
|
||||
```bash
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
@@ -84,8 +84,7 @@ Puoi anche installarlo con i seguenti comandi:
|
||||
- **Con Paru su Arch Linux**
|
||||
|
||||
```bash
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
@@ -84,8 +84,7 @@ curl -fsSL https://opencode.ai/install | bash
|
||||
- **Arch Linux での Paru の使用**
|
||||
|
||||
```bash
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: ACP Support
|
||||
description: Use OpenCode in any ACP-compatible editor.
|
||||
title: ACP 지원
|
||||
description: ACP 호환 편집기에서 opencode를 사용하세요.
|
||||
---
|
||||
|
||||
OpenCode는 [Agent Client Protocol](https://agentclientprotocol.com)(ACP)을 지원하므로, ACP 호환 편집기와 IDE에서 OpenCode를 직접 사용할 수 있습니다.
|
||||
opencode는 [Agent Client Protocol](https://agentclientprotocol.com) 또는 (ACP)을 지원하며, 호환 편집기 및 IDE에서 직접 사용할 수 있습니다.
|
||||
|
||||
:::tip
|
||||
ACP를 지원하는 편집기와 tool 목록은 [ACP progress report](https://zed.dev/blog/acp-progress-report#available-now)에서 확인하세요.
|
||||
ACP를 지원하는 편집기 및 도구 목록의 경우 [ACP 진행 보고서](https://zed.dev/blog/acp-progress-report#available-now)를 확인하십시오.
|
||||
:::
|
||||
|
||||
ACP는 코드 편집기와 AI 코딩 에이전트 간의 통신을 표준화하는 개방형 프로토콜입니다.
|
||||
@@ -15,17 +15,17 @@ ACP는 코드 편집기와 AI 코딩 에이전트 간의 통신을 표준화하
|
||||
|
||||
## 구성
|
||||
|
||||
ACP로 OpenCode를 사용하려면, 편집기에서 `opencode acp` 명령을 실행하도록 config를 설정하세요.
|
||||
ACP를 통해 opencode를 사용하려면 `opencode acp` 명령을 실행하려면 편집기를 구성하십시오.
|
||||
|
||||
이 명령은 OpenCode를 ACP 호환 subprocess로 시작하며, stdio 기반 JSON-RPC를 통해 편집기와 통신합니다.
|
||||
명령은 opencode를 실행하여 JSON-RPC를 통해 편집기와 통신하는 ACP 호환 하위 프로세스로 시작합니다.
|
||||
|
||||
아래는 ACP를 지원하는 주요 편집기 예시입니다.
|
||||
아래는 ACP를 지원하는 인기있는 편집기의 예입니다.
|
||||
|
||||
---
|
||||
|
||||
### Zed
|
||||
##### Zed
|
||||
|
||||
[Zed](https://zed.dev) config(`~/.config/zed/settings.json`)에 다음을 추가하세요.
|
||||
[Zed](https://zed.dev) 구성 (`~/.config/zed/settings.json`)에 추가 :
|
||||
|
||||
```json title="~/.config/zed/settings.json"
|
||||
{
|
||||
@@ -38,9 +38,9 @@ ACP로 OpenCode를 사용하려면, 편집기에서 `opencode acp` 명령을 실
|
||||
}
|
||||
```
|
||||
|
||||
열려면 **Command Palette**에서 `agent: new thread` action을 사용하세요.
|
||||
그것을 열려면 **Command Palette **에서 `agent: new thread` 동작을 사용하십시오.
|
||||
|
||||
`keymap.json`을 수정해 키보드 단축키를 바인딩할 수도 있습니다.
|
||||
`keymap.json`를 편집하여 키보드 단축키도 결합할 수 있습니다.
|
||||
|
||||
```json title="keymap.json"
|
||||
[
|
||||
@@ -67,9 +67,9 @@ ACP로 OpenCode를 사용하려면, 편집기에서 `opencode acp` 명령을 실
|
||||
|
||||
---
|
||||
|
||||
### JetBrains IDEs
|
||||
#### JetBrains IDEs
|
||||
|
||||
[JetBrains IDE](https://www.jetbrains.com/)에서는 [documentation](https://www.jetbrains.com/help/ai-assistant/acp.html)에 따라 `acp.json`에 다음을 추가하세요.
|
||||
[JetBrains IDE]에 추가하십시오 (https://www.jetbrains.com/) [documentation]에 따라 acp.json (https://www.jetbrains.com/help/ai-assistant/acp.html):
|
||||
|
||||
```json title="acp.json"
|
||||
{
|
||||
@@ -82,13 +82,13 @@ ACP로 OpenCode를 사용하려면, 편집기에서 `opencode acp` 명령을 실
|
||||
}
|
||||
```
|
||||
|
||||
열려면 AI Chat agent selector에서 새 `OpenCode` agent를 선택하세요.
|
||||
그것을 열려면 AI Chat Agent selector의 새로운 'opencode' 에이전트를 사용하십시오.
|
||||
|
||||
---
|
||||
|
||||
### Avante.nvim
|
||||
#### Avante.nvim
|
||||
|
||||
[Avante.nvim](https://github.com/yetone/avante.nvim) config에 다음을 추가하세요.
|
||||
[Avante.nvim](https://github.com/yetone/avante.nvim) 구성에 추가하십시오:
|
||||
|
||||
```lua
|
||||
{
|
||||
@@ -101,7 +101,7 @@ ACP로 OpenCode를 사용하려면, 편집기에서 `opencode acp` 명령을 실
|
||||
}
|
||||
```
|
||||
|
||||
환경 변수를 전달해야 한다면 다음과 같이 설정하세요.
|
||||
환경 변수를 전달해야 하는 경우:
|
||||
|
||||
```lua {6-8}
|
||||
{
|
||||
@@ -119,9 +119,9 @@ ACP로 OpenCode를 사용하려면, 편집기에서 `opencode acp` 명령을 실
|
||||
|
||||
---
|
||||
|
||||
### CodeCompanion.nvim
|
||||
#### CodeCompanion.nvim
|
||||
|
||||
[CodeCompanion.nvim](https://github.com/olimorris/codecompanion.nvim)에서 OpenCode를 ACP agent로 사용하려면 Neovim config에 다음을 추가하세요.
|
||||
opencode를 [CodeCompanion.nvim](https://github.com/olimorris/codecompanion.nvim)에서 ACP 에이전트로 사용하려면 Neovim config에 다음을 추가하십시오.
|
||||
|
||||
```lua
|
||||
require("codecompanion").setup({
|
||||
@@ -136,21 +136,21 @@ require("codecompanion").setup({
|
||||
})
|
||||
```
|
||||
|
||||
이 config는 chat에서 OpenCode를 ACP agent로 사용하도록 CodeCompanion을 설정합니다.
|
||||
이 구성은 CodeCompanion을 설정하여 채팅을 위한 ACP 에이전트로 opencode를 사용합니다.
|
||||
|
||||
환경 변수(`OPENCODE_API_KEY` 등)를 전달해야 한다면 CodeCompanion.nvim documentation의 [Configuring Adapters: Environment Variables](https://codecompanion.olimorris.dev/getting-started#setting-an-api-key)를 참고하세요.
|
||||
환경 변수 (`OPENCODE_API_KEY`와 같은)를 전달해야하는 경우, CodeCompanion.nvim 문서에서 [Configuring Adapters: Environment variables](https://codecompanion.olimorris.dev/getting-started#setting-an-api-key)를 참조하십시오.
|
||||
|
||||
## 지원
|
||||
## 지원 기능
|
||||
|
||||
OpenCode는 ACP를 통해서도 터미널과 동일하게 동작합니다. 다음 기능을 모두 지원합니다.
|
||||
opencode는 터미널과 동일하게 ACP를 통해 작동합니다. 모든 기능은 지원됩니다:
|
||||
|
||||
:::note
|
||||
`/undo` 및 `/redo`와 같은 일부 내장 슬래시 명령은 현재 지원되지 않습니다.
|
||||
:::
|
||||
|
||||
- 내장 tool(파일 작업, terminal 명령 등)
|
||||
- 사용자 정의 tool과 slash command
|
||||
- OpenCode config에 설정한 MCP 서버
|
||||
- `AGENTS.md`의 프로젝트별 규칙
|
||||
- 사용자 정의 formatter와 linter
|
||||
- agent 및 권한 시스템
|
||||
- 내장 도구 (파일 작업, terminal 명령 등)
|
||||
- 사용자 정의 도구 및 슬래시 명령
|
||||
- opencode config에서 설정된 MCP 서버
|
||||
- `AGENTS.md`의 프로젝트 별 규칙
|
||||
- 사용자 정의 포맷 및 라이터
|
||||
- 에이전트 및 권한 시스템
|
||||
|
||||
@@ -1,141 +1,141 @@
|
||||
---
|
||||
title: Agents
|
||||
description: Configure and use specialized agents.
|
||||
title: 에이전트
|
||||
description: 전문 에이전트를 구성하고 사용하세요.
|
||||
---
|
||||
|
||||
agent는 특정 작업과 워크플로에 맞게 설정할 수 있는 전문 AI assistant입니다. custom prompt, model, tool 접근 권한을 조합해 목적에 맞는 agent를 만들 수 있습니다.
|
||||
에이전트는 특정 작업과 워크플로우를 전문으로 하는 구성 가능한 AI 보조자입니다. 사용자 정의 프롬프트, 모델, 도구 액세스로 집중된 도구를 만들 수 있습니다.
|
||||
|
||||
:::tip
|
||||
코드를 수정하지 않고 분석과 제안 검토만 하고 싶다면 plan agent를 사용하세요.
|
||||
코드 변경 없이 제안을 검토할 때는 Plan 에이전트를 사용하세요.
|
||||
:::
|
||||
|
||||
세션 중에 agent를 전환하거나 `@` mention으로 호출할 수 있습니다.
|
||||
세션 중에 에이전트를 전환하거나 `@` 멘션으로 호출할 수 있습니다.
|
||||
|
||||
---
|
||||
|
||||
## 유형
|
||||
|
||||
OpenCode의 agent는 primary agent와 subagent, 두 가지 유형으로 나뉩니다.
|
||||
OpenCode에는 두 가지 유형의 에이전트가 있습니다: 기본 에이전트(Primary Agent)와 서브 에이전트(Subagent).
|
||||
|
||||
---
|
||||
|
||||
### Primary agents
|
||||
### 기본 에이전트
|
||||
|
||||
primary agent는 사용자가 직접 상호작용하는 메인 assistant입니다. **Tab** 키 또는 설정한 `switch_agent` keybind로 순환 전환할 수 있습니다. primary agent는 메인 대화를 처리하며, tool 접근은 permission으로 제어합니다. 예를 들어 Build는 모든 tool이 활성화되어 있고 Plan은 제한되어 있습니다.
|
||||
기본 에이전트는 사용자가 직접 상호 작용하는 주요 보조자입니다. **Tab** 키 또는 설정된 `switch_agent` 키바인드를 사용하여 순환할 수 있습니다. 이 에이전트는 주요 대화를 처리합니다. 도구 액세스는 권한을 통해 구성됩니다 — 예를 들어, Build는 모든 도구를 사용할 수 있지만 Plan은 제한됩니다.
|
||||
|
||||
:::tip
|
||||
세션 중 **Tab** 키로 primary agent를 빠르게 전환할 수 있습니다.
|
||||
세션 중에 **Tab** 키를 사용하여 기본 에이전트를 전환할 수 있습니다.
|
||||
:::
|
||||
|
||||
OpenCode에는 기본 제공 primary agent인 **Build**와 **Plan**이 포함되어 있습니다. 아래에서 각각 살펴보겠습니다.
|
||||
OpenCode는 두 가지 내장 기본 에이전트, **Build** 및 **Plan**을 제공합니다. 아래에서 자세히 살펴봅니다.
|
||||
|
||||
---
|
||||
|
||||
### Subagents
|
||||
### 서브 에이전트
|
||||
|
||||
subagent는 primary agent가 특정 작업을 위해 호출하는 전문 assistant입니다. 메시지에서 **@ mention**으로 직접 호출할 수도 있습니다.
|
||||
서브 에이전트는 기본 에이전트가 특정 작업을 위해 호출할 수 있는 전문 보조자입니다. 또한 메시지에서 **@멘션**을 통해 수동으로 호출할 수도 있습니다.
|
||||
|
||||
OpenCode에는 기본 제공 subagent인 **General**과 **Explore**가 포함되어 있습니다. 아래에서 살펴보겠습니다.
|
||||
OpenCode는 두 가지 내장 서브 에이전트, **General** 및 **Explore**를 제공합니다. 아래에서 자세히 살펴봅니다.
|
||||
|
||||
---
|
||||
|
||||
## 기본 제공
|
||||
|
||||
OpenCode는 기본적으로 primary agent 2개와 subagent 2개를 제공합니다.
|
||||
OpenCode는 기본 에이전트와 두 개의 내장 서브 에이전트를 제공합니다.
|
||||
|
||||
---
|
||||
|
||||
### Use build
|
||||
### Build
|
||||
|
||||
_Mode_: `primary`
|
||||
_모드_: `primary`
|
||||
|
||||
Build는 모든 tool이 활성화된 **default** primary agent입니다. 파일 작업과 시스템 명령에 대한 전체 접근이 필요한 일반적인 개발 작업에 사용하는 표준 agent입니다.
|
||||
Build는 모든 도구가 활성화된 **기본** 에이전트입니다. 파일 조작 및 시스템 명령에 대한 전체 액세스가 필요한 개발 작업을 위한 표준 에이전트입니다.
|
||||
|
||||
---
|
||||
|
||||
### Use plan
|
||||
### Plan
|
||||
|
||||
_Mode_: `primary`
|
||||
_모드_: `primary`
|
||||
|
||||
Plan은 계획과 분석에 특화된 제한형 agent입니다. 더 높은 제어력과 의도치 않은 변경 방지를 위해 permission 시스템을 사용합니다.
|
||||
기본값으로 아래 항목은 모두 `ask`로 설정됩니다.
|
||||
계획 및 분석을 위해 설계된 제한된 에이전트입니다. 더 많은 제어권을 부여하고 의도하지 않은 변경을 방지하기 위해 권한 시스템을 사용합니다.
|
||||
기본적으로 다음은 모두 `ask`로 설정됩니다:
|
||||
|
||||
- `file edits`: 모든 write, patch, edit
|
||||
- `file edits`: 모든 쓰기, 패치 및 편집
|
||||
- `bash`: 모든 bash 명령
|
||||
|
||||
코드베이스를 실제로 수정하지 않고 LLM 분석, 변경 제안, 계획 수립만 진행하고 싶을 때 유용합니다.
|
||||
이 에이전트는 코드를 분석하거나 변경을 제안받고 싶지만, 코드베이스에 실제 수정 없이 계획만 만들고 싶을 때 유용합니다.
|
||||
|
||||
---
|
||||
|
||||
### Use general
|
||||
### General
|
||||
|
||||
_Mode_: `subagent`
|
||||
_모드_: `subagent`
|
||||
|
||||
복잡한 질문을 조사하고 다단계 작업을 수행하기 위한 범용 agent입니다. todo를 제외한 모든 tool 접근이 가능하므로 필요하면 파일 수정도 할 수 있습니다. 여러 작업 단위를 병렬로 처리할 때 사용하세요.
|
||||
복잡한 질문을 연구하고 다단계 작업을 실행하기 위한 범용 에이전트입니다. 전체 도구 액세스(todo 제외)를 가지므로 필요할 때 파일 변경을 수행할 수 있습니다. 여러 단위의 작업을 병렬로 실행할 때 사용하세요.
|
||||
|
||||
---
|
||||
|
||||
### Use explore
|
||||
### Explore
|
||||
|
||||
_Mode_: `subagent`
|
||||
_모드_: `subagent`
|
||||
|
||||
코드베이스 탐색에 최적화된 빠른 읽기 전용 agent입니다. 파일을 수정할 수 없습니다. 패턴 기반 파일 탐색, 키워드 검색, 코드베이스 관련 질의 응답을 빠르게 처리할 때 사용하세요.
|
||||
코드베이스를 탐색하는 빠르고 읽기 전용인 에이전트입니다. 파일을 수정할 수 없습니다. 패턴, 키워드로 코드를 검색하거나 코드베이스에 대한 질문에 답하기 위해 파일을 빠르게 찾아야 할 때 사용하세요.
|
||||
|
||||
---
|
||||
|
||||
### Use compaction
|
||||
### Compaction
|
||||
|
||||
_Mode_: `primary`
|
||||
_모드_: `primary`
|
||||
|
||||
긴 context를 더 짧은 요약으로 압축하는 숨겨진 시스템 agent입니다. 필요할 때 자동으로 실행되며 UI에서 직접 선택할 수 없습니다.
|
||||
긴 컨텍스트를 작은 요약으로 압축하는 숨겨진 시스템 에이전트입니다. 필요한 경우 자동으로 실행되며 UI에서 선택할 수 없습니다.
|
||||
|
||||
---
|
||||
|
||||
### Use title
|
||||
### Title
|
||||
|
||||
_Mode_: `primary`
|
||||
_모드_: `primary`
|
||||
|
||||
짧은 세션 제목을 생성하는 숨겨진 시스템 agent입니다. 자동으로 실행되며 UI에서 직접 선택할 수 없습니다.
|
||||
짧은 세션 제목을 생성하는 숨겨진 시스템 에이전트입니다. 자동으로 실행되며 UI에서 선택할 수 없습니다.
|
||||
|
||||
---
|
||||
|
||||
### Use summary
|
||||
### Summary
|
||||
|
||||
_Mode_: `primary`
|
||||
_모드_: `primary`
|
||||
|
||||
세션 요약을 생성하는 숨겨진 시스템 agent입니다. 자동으로 실행되며 UI에서 직접 선택할 수 없습니다.
|
||||
세션 요약을 만드는 숨겨진 시스템 에이전트입니다. 자동으로 실행되며 UI에서 선택할 수 없습니다.
|
||||
|
||||
---
|
||||
|
||||
## 사용법
|
||||
|
||||
1. primary agent는 세션 중 **Tab** 키로 순환 전환할 수 있습니다. 설정한 `switch_agent` keybind를 사용할 수도 있습니다.
|
||||
1. 기본 에이전트의 경우, 세션 중에 **Tab** 키를 사용하여 순환합니다. 구성된 `switch_agent` 키바인드도 사용할 수 있습니다.
|
||||
|
||||
2. subagent 호출 방법:
|
||||
- **Automatically**: primary agent가 설명(description)을 바탕으로 특화 작업에 자동 호출합니다.
|
||||
- 수동 호출: 메시지에서 subagent를 **@ mention**하여 호출합니다. 예:
|
||||
2. 서브 에이전트는 다음과 같이 호출할 수 있습니다:
|
||||
- 설명에 근거하여 전문적인 작업을 위해 기본 에이전트에 의해 **자동으로** 호출됨.
|
||||
- 메시지에서 서브 에이전트를 **@멘션**. 예를 들어:
|
||||
|
||||
```txt frame="none"
|
||||
@general help me search for this function
|
||||
```
|
||||
|
||||
3. **세션 간 이동**: subagent가 child session을 만들면 아래 키로 parent session과 child session 사이를 이동할 수 있습니다.
|
||||
- **\<Leader>+Right** (또는 설정한 `session_child_cycle` keybind): parent → child1 → child2 → ... → parent 순방향 순환
|
||||
- **\<Leader>+Left** (또는 설정한 `session_child_cycle_reverse` keybind): parent ← child1 ← child2 ← ... ← parent 역방향 순환
|
||||
3. **세션 간 이동**: 서브 에이전트가 자체 자식 세션을 만들 때, 부모 세션과 자식 세션 간을 탐색할 수 있습니다.
|
||||
- **\<Leader>+Right** (또는 부모 → 자식1 → 자식2 순으로 이동하기 위해 설정된 `session_child_cycle` 키바인드)
|
||||
- **\<Leader>+Left** (또는 `session_child_cycle_reverse` 키바인드) 부모 방향으로 되돌아가기: 자식2 → 자식1 → 부모
|
||||
|
||||
이를 통해 메인 대화와 특화 subagent 작업 사이를 자연스럽게 오갈 수 있습니다.
|
||||
이를 통해 주요 대화와 전문적인 서브 에이전트 작업 간을 원활하게 전환할 수 있습니다.
|
||||
|
||||
---
|
||||
|
||||
## 구성
|
||||
|
||||
기본 제공 agent를 커스터마이즈하거나 config를 통해 직접 agent를 만들 수 있습니다. agent는 두 가지 방식으로 설정합니다.
|
||||
내장 에이전트를 사용자 정의하거나 구성을 통해 자신만의 에이전트를 만들 수 있습니다. 에이전트는 두 가지 방법으로 구성될 수 있습니다:
|
||||
|
||||
---
|
||||
|
||||
### JSON
|
||||
|
||||
`opencode.json` config 파일에서 agent를 설정합니다.
|
||||
`opencode.json` config 파일에 에이전트 구성:
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -178,10 +178,10 @@ _Mode_: `primary`
|
||||
|
||||
### Markdown
|
||||
|
||||
Markdown 파일로도 agent를 정의할 수 있습니다. 다음 위치에 두세요.
|
||||
Markdown 파일을 사용하여 에이전트를 정의 할 수 있습니다. 그들에 게:
|
||||
|
||||
- Global: `~/.config/opencode/agents/`
|
||||
- Per-project: `.opencode/agents/`
|
||||
- 글로벌: `~/.config/opencode/agents/`
|
||||
- 프로젝트: `.opencode/agents/`
|
||||
|
||||
```markdown title="~/.config/opencode/agents/review.md"
|
||||
---
|
||||
@@ -205,19 +205,19 @@ You are in code review mode. Focus on:
|
||||
Provide constructive feedback without making direct changes.
|
||||
```
|
||||
|
||||
Markdown 파일명은 agent 이름이 됩니다. 예를 들어 `review.md`는 `review` agent를 만듭니다.
|
||||
markdown 파일 이름은 에이전트 이름입니다. 예를 들어, `review.md`는 `review` 에이전트을 만듭니다.
|
||||
|
||||
---
|
||||
|
||||
## 옵션
|
||||
|
||||
각 config 옵션을 자세히 살펴보겠습니다.
|
||||
이 구성 옵션들을 자세히 살펴봅시다.
|
||||
|
||||
---
|
||||
|
||||
### Description
|
||||
### 설명
|
||||
|
||||
`description` 옵션으로 agent의 역할과 사용 시점을 간단히 설명하세요.
|
||||
`description` 옵션을 사용하여 에이전트가 무엇을 하고 언제 사용해야 하는지에 대한 간단한 설명을 제공합니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -229,15 +229,15 @@ Markdown 파일명은 agent 이름이 됩니다. 예를 들어 `review.md`는 `r
|
||||
}
|
||||
```
|
||||
|
||||
이 옵션은 **필수** config 항목입니다.
|
||||
\*\* 필수 구성 옵션입니다.
|
||||
|
||||
---
|
||||
|
||||
### Temperature
|
||||
### 온도
|
||||
|
||||
`temperature` config로 LLM 응답의 무작위성과 창의성을 제어합니다.
|
||||
`temperature` 구성으로 LLM 응답의 무작위성과 창의성을 제어합니다.
|
||||
|
||||
값이 낮을수록 응답이 더 집중되고 결정적이며, 값이 높을수록 창의성과 다양성이 커집니다.
|
||||
값이 낮을수록 더 집중되고 결정적인 응답을 생성하며, 값이 높을수록 창의성과 가변성이 증가합니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -252,11 +252,11 @@ Markdown 파일명은 agent 이름이 됩니다. 예를 들어 `review.md`는 `r
|
||||
}
|
||||
```
|
||||
|
||||
Temperature 값은 일반적으로 0.0~1.0 범위를 사용합니다.
|
||||
온도 값은 일반적으로 0.0에서 1.0 사이입니다:
|
||||
|
||||
- **0.0-0.2**: 매우 집중되고 결정적인 응답, 코드 분석/계획에 적합
|
||||
- **0.3-0.5**: 적당한 창의성이 섞인 균형형 응답, 일반 개발 작업에 적합
|
||||
- **0.6-1.0**: 더 창의적이고 다양한 응답, 브레인스토밍/탐색에 유용
|
||||
- **0.0-0.2**: 매우 집중되고 신중한 응답, 코드 분석 및 계획에 이상적
|
||||
- **0.3-0.5**: 창의성과 정확성의 균형, 일반 개발 작업에 좋음
|
||||
- **0.6-1.0**: 더 창의적이고 다양한 응답, 브레인스토밍 및 탐색에 유용함
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -276,15 +276,15 @@ Temperature 값은 일반적으로 0.0~1.0 범위를 사용합니다.
|
||||
}
|
||||
```
|
||||
|
||||
temperature를 지정하지 않으면 OpenCode는 model별 기본값을 사용합니다. 일반적으로 대부분의 model은 0, Qwen model은 0.55를 사용합니다.
|
||||
온도가 지정되지 않은 경우, OpenCode는 모델별 기본값을 사용합니다. 일반적으로 대부분의 모델은 0, Qwen 모델의 경우 0.55입니다.
|
||||
|
||||
---
|
||||
|
||||
### Max steps
|
||||
## 최대 단계
|
||||
|
||||
agent가 텍스트 응답만 하도록 강제되기 전까지 수행할 수 있는 agentic iteration의 최대 횟수를 제어합니다. 비용을 관리하려는 사용자에게 agentic action 제한을 제공하기 위한 옵션입니다.
|
||||
에이전트가 중지하고 사용자와 다시 상호 작용하기 전에 실행할 수 있는 최대 단계 수를 제어합니다. 이를 통해 에이전트의 행동과 비용을 제어할 수 있습니다.
|
||||
|
||||
이 값을 설정하지 않으면 model이 중단을 선택하거나 사용자가 세션을 중단할 때까지 agent는 계속 반복합니다.
|
||||
설정되지 않은 경우, 에이전트는 모델이 중지하거나 사용자가 세션을 중단할 때까지 계속됩니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -298,17 +298,17 @@ agent가 텍스트 응답만 하도록 강제되기 전까지 수행할 수 있
|
||||
}
|
||||
```
|
||||
|
||||
제한에 도달하면 agent는 작업 요약과 남은 권장 작업을 응답하도록 지시하는 특수 시스템 prompt를 받습니다.
|
||||
제한에 도달하면, 에이전트는 작업 요약과 권장되는 남은 작업을 신속하게 응답하도록 지시받습니다.
|
||||
|
||||
:::caution
|
||||
레거시 `maxSteps` 필드는 deprecated입니다. 대신 `steps`를 사용하세요.
|
||||
레거시 `maxSteps` 필드는 더 이상 사용되지 않습니다. 대신 `steps`를 사용하십시오.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
### Disable
|
||||
#### 비활성화
|
||||
|
||||
`true`로 설정하면 agent를 비활성화합니다.
|
||||
`true`로 설정하여 에이전트를 비활성화합니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -322,9 +322,9 @@ agent가 텍스트 응답만 하도록 강제되기 전까지 수행할 수 있
|
||||
|
||||
---
|
||||
|
||||
### Prompt
|
||||
#### 프롬프트
|
||||
|
||||
`prompt` config로 해당 agent의 custom 시스템 prompt 파일을 지정합니다. prompt 파일에는 agent 목적에 맞는 지시사항을 작성하세요.
|
||||
`prompt` 구성으로 이 에이전트를 위한 사용자 정의 시스템 프롬프트 파일을 지정하십시오. 프롬프트 파일은 에이전트의 목적에 따른 지시를 포함해야 합니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -336,16 +336,16 @@ agent가 텍스트 응답만 하도록 강제되기 전까지 수행할 수 있
|
||||
}
|
||||
```
|
||||
|
||||
이 경로는 config 파일 위치 기준의 상대 경로입니다. 따라서 전역 OpenCode config와 프로젝트별 config 모두에서 동일하게 동작합니다.
|
||||
이 경로는 구성 파일이 있는 위치를 기준으로 합니다. 따라서 글로벌 OpenCode 구성과 프로젝트별 구성 모두에서 작동합니다.
|
||||
|
||||
---
|
||||
|
||||
### Model
|
||||
### 모델
|
||||
|
||||
`model` config로 해당 agent의 model을 override할 수 있습니다. 작업 특성에 맞춰 model을 달리 쓸 때 유용합니다. 예를 들어 계획에는 더 빠른 model, 구현에는 더 강력한 model을 사용할 수 있습니다.
|
||||
`model` 구성을 사용하여 이 에이전트에 대한 모델을 재정의합니다. 다른 작업에 최적화된 다른 모델을 사용하는 데 유용합니다. 예를 들어, 계획을 위한 빠른 모델, 구현을 위한 더 강력한 모델 등입니다.
|
||||
|
||||
:::tip
|
||||
model을 지정하지 않으면 primary agent는 [전역으로 설정한 model](/docs/config#models)을 사용하고, subagent는 해당 subagent를 호출한 primary agent의 model을 사용합니다.
|
||||
모델을 지정하지 않는 경우, 기본 에이전트는 [전역 구성 모델](/docs/config#models)을 사용하며, 서브 에이전트는 자신을 호출한 기본 에이전트의 모델을 사용합니다.
|
||||
:::
|
||||
|
||||
```json title="opencode.json"
|
||||
@@ -358,13 +358,13 @@ model을 지정하지 않으면 primary agent는 [전역으로 설정한 model](
|
||||
}
|
||||
```
|
||||
|
||||
OpenCode config의 model ID는 `provider/model-id` 형식을 사용합니다. 예를 들어 [OpenCode Zen](/docs/zen)을 사용한다면 GPT 5.1 Codex에 `opencode/gpt-5.1-codex`를 사용합니다.
|
||||
OpenCode 구성의 모델 ID는 `provider/model-id` 형식을 사용합니다. 예를 들어, [OpenCode Zen](/docs/zen)을 사용한다면, GPT 5.1 Codex에 `opencode/gpt-5.1-codex`를 사용할 수 있습니다.
|
||||
|
||||
---
|
||||
|
||||
### Tools
|
||||
## 도구
|
||||
|
||||
`tools` config로 agent에서 사용할 tool을 제어합니다. 각 tool을 `true` 또는 `false`로 설정해 활성화/비활성화할 수 있습니다.
|
||||
`tools` 구성으로 이 에이전트가 사용할 수 있는 도구를 제어합니다. `true` 또는 `false`로 설정하여 특정 도구를 활성화하거나 비활성화할 수 있습니다.
|
||||
|
||||
```json title="opencode.json" {3-6,9-12}
|
||||
{
|
||||
@@ -385,10 +385,10 @@ OpenCode config의 model ID는 `provider/model-id` 형식을 사용합니다.
|
||||
```
|
||||
|
||||
:::note
|
||||
agent별 config는 전역 config를 override합니다.
|
||||
에이전트별 구성은 글로벌 구성을 덮어씁니다.
|
||||
:::
|
||||
|
||||
와일드카드를 사용하면 여러 tool을 한 번에 제어할 수 있습니다. 예를 들어 MCP 서버의 모든 tool을 비활성화하려면 다음과 같이 설정합니다.
|
||||
한 번에 여러 도구를 제어하기 위해 와일드카드를 사용할 수 있습니다. 예를 들어, MCP 서버에서 모든 도구를 비활성화하려면:
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -405,17 +405,17 @@ agent별 config는 전역 config를 override합니다.
|
||||
}
|
||||
```
|
||||
|
||||
[tool에 대해 더 알아보기](/docs/tools).
|
||||
[도구에 대해 더 알아보기](/docs/tools).
|
||||
|
||||
---
|
||||
|
||||
### Permissions
|
||||
## 권한
|
||||
|
||||
permission을 설정해 agent가 수행할 수 있는 action을 제어할 수 있습니다. 현재 `edit`, `bash`, `webfetch` tool의 permission은 다음 값으로 설정할 수 있습니다.
|
||||
에이전트가 수행할 수 있는 작업을 관리할 수 있는 권한을 구성할 수 있습니다. 현재 `edit`, `bash` 및 `webfetch` 도구에 대한 권한은 다음과 같습니다.
|
||||
|
||||
- `"ask"` — tool 실행 전에 승인 요청
|
||||
- `"allow"` — 승인 없이 모든 작업 허용
|
||||
- `"deny"` — tool 비활성화
|
||||
- `"ask"` - 도구를 실행하기 전에 승인 요청
|
||||
- `"allow"` - 승인 없이 모든 작업 허용
|
||||
- `"deny"` - 도구 비활성화
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -426,7 +426,7 @@ permission을 설정해 agent가 수행할 수 있는 action을 제어할 수
|
||||
}
|
||||
```
|
||||
|
||||
이 permission은 agent별로 override할 수 있습니다.
|
||||
에이전트별로 이 권한을 재정의(override)할 수 있습니다.
|
||||
|
||||
```json title="opencode.json" {3-5,8-10}
|
||||
{
|
||||
@@ -444,7 +444,7 @@ permission을 설정해 agent가 수행할 수 있는 action을 제어할 수
|
||||
}
|
||||
```
|
||||
|
||||
Markdown agent에서도 permission을 설정할 수 있습니다.
|
||||
Markdown 에이전트에서도 권한을 설정할 수 있습니다.
|
||||
|
||||
```markdown title="~/.config/opencode/agents/review.md"
|
||||
---
|
||||
@@ -463,7 +463,7 @@ permission:
|
||||
Only analyze code and suggest changes.
|
||||
```
|
||||
|
||||
특정 bash 명령에 대해서도 permission을 설정할 수 있습니다.
|
||||
특정 bash 명령에 대한 권한을 설정할 수 있습니다.
|
||||
|
||||
```json title="opencode.json" {7}
|
||||
{
|
||||
@@ -481,7 +481,7 @@ Only analyze code and suggest changes.
|
||||
}
|
||||
```
|
||||
|
||||
여기에는 glob 패턴을 사용할 수 있습니다.
|
||||
이것은 glob 패턴을 사용할 수 있습니다.
|
||||
|
||||
```json title="opencode.json" {7}
|
||||
{
|
||||
@@ -498,8 +498,8 @@ Only analyze code and suggest changes.
|
||||
}
|
||||
```
|
||||
|
||||
또한 `*` 와일드카드로 모든 명령의 permission을 제어할 수 있습니다.
|
||||
마지막으로 일치한 규칙이 우선하므로 `*` 와일드카드를 먼저 두고, 구체적인 규칙을 뒤에 두세요.
|
||||
또한 `*` 와일드카드를 사용하여 모든 명령에 대한 권한을 관리할 수 있습니다.
|
||||
마지막 일치 규칙이 우선하므로, `*` 와일드카드를 먼저 두고 특정 규칙을 나중에 두십시오.
|
||||
|
||||
```json title="opencode.json" {8}
|
||||
{
|
||||
@@ -517,13 +517,13 @@ Only analyze code and suggest changes.
|
||||
}
|
||||
```
|
||||
|
||||
[permission에 대해 더 알아보기](/docs/permissions).
|
||||
[권한에 대해 더 알아보기](/docs/permissions).
|
||||
|
||||
---
|
||||
|
||||
### Mode
|
||||
### 모드
|
||||
|
||||
`mode` config로 agent 모드를 제어합니다. `mode` 옵션은 agent를 어떤 방식으로 사용할지 결정합니다.
|
||||
`mode` 구성으로 에이전트 모드를 제어합니다. `mode` 옵션은 에이전트가 어떻게 사용될 수 있는지 결정하는 데 사용됩니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -535,13 +535,13 @@ Only analyze code and suggest changes.
|
||||
}
|
||||
```
|
||||
|
||||
`mode`는 `primary`, `subagent`, `all` 중 하나로 설정할 수 있습니다. 설정하지 않으면 기본값은 `all`입니다.
|
||||
`mode` 옵션은 `primary`, `subagent`, 또는 `all`로 설정할 수 있습니다. `mode`가 지정되지 않은 경우 `all`이 기본값입니다.
|
||||
|
||||
---
|
||||
|
||||
### Hidden
|
||||
## 숨김
|
||||
|
||||
`hidden: true`를 설정하면 `@` 자동완성 메뉴에서 subagent를 숨길 수 있습니다. 다른 agent가 Task tool을 통해 programmatic으로만 호출해야 하는 내부 subagent에 유용합니다.
|
||||
`hidden: true`를 사용하여 `@` 자동 완성 메뉴에서 에이전트를 숨깁니다. 작업 도구를 통해 다른 에이전트에 의해 프로그래밍 방식으로 호출되어야 하는 내부 에이전트에 유용합니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -554,17 +554,17 @@ Only analyze code and suggest changes.
|
||||
}
|
||||
```
|
||||
|
||||
이 설정은 자동완성 메뉴에서의 사용자 가시성에만 영향을 줍니다. permission이 허용되면 hidden agent도 모델이 Task tool을 통해 호출할 수 있습니다.
|
||||
자동 완성 메뉴의 사용자 가시성에만 영향을 미칩니다. 숨겨진 에이전트는 권한이 허용된다면 여전히 작업 도구를 통해 모델에 의해 호출될 수 있습니다.
|
||||
|
||||
:::note
|
||||
`mode: subagent` agent에만 적용됩니다.
|
||||
`mode: subagent` 에이전트에만 적용됩니다.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
### Task permissions
|
||||
## 작업 권한
|
||||
|
||||
`permission.task`로 Task tool을 통해 해당 agent가 호출할 수 있는 subagent 범위를 제어합니다. 유연한 매칭을 위해 glob 패턴을 사용합니다.
|
||||
`permission.task`와 작업 도구를 통해 에이전트가 호출할 수 있는 서브 에이전트를 제어합니다. 유연한 일치를 위한 glob 패턴을 사용합니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -583,23 +583,23 @@ Only analyze code and suggest changes.
|
||||
}
|
||||
```
|
||||
|
||||
`deny`로 설정되면 해당 subagent는 Task tool 설명에서 완전히 제거되므로 모델이 호출을 시도하지 않습니다.
|
||||
`deny`로 설정할 때, 서브 에이전트는 작업 도구 설명에서 완전히 제거됩니다. 따라서 모델은 그것을 호출하려고 시도하지 않습니다.
|
||||
|
||||
:::tip
|
||||
규칙은 선언 순서대로 평가되며, **마지막으로 일치한 규칙이 승리합니다**. 위 예시에서 `orchestrator-planner`는 `*`(deny)와 `orchestrator-*`(allow) 모두에 일치하지만, `orchestrator-*`가 뒤에 있으므로 결과는 `allow`입니다.
|
||||
규칙은 순서대로 평가되며, **마지막 일치 규칙**이 우선합니다. 위의 예에서 `orchestrator-planner`는 `*` (deny)와 `orchestrator-*` (allow) 모두 일치하지만 `orchestrator-*`가 `*` 뒤에 오므로 결과는 `allow`입니다.
|
||||
:::
|
||||
|
||||
:::tip
|
||||
사용자는 agent의 task permission이 deny여도 `@` 자동완성 메뉴를 통해 어떤 subagent든 직접 호출할 수 있습니다.
|
||||
사용자는 에이전트의 작업 권한이 거부되더라도 `@` 자동 완성 메뉴를 통해 직접 어떤 서브 에이전트든 호출할 수 있습니다.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
### Color
|
||||
### 색상
|
||||
|
||||
`color` 옵션으로 UI에서 agent의 시각 스타일을 지정할 수 있습니다. 인터페이스에서 agent가 표시되는 방식에 영향을 줍니다.
|
||||
`color` 옵션으로 UI에서 에이전트의 시각적 모양을 사용자 정의합니다.
|
||||
|
||||
유효한 hex 색상(예: `#FF5733`) 또는 theme 색상(`primary`, `secondary`, `accent`, `success`, `warning`, `error`, `info`)을 사용하세요.
|
||||
유효한 hex 색상(예: `#FF5733`) 또는 테마 색상을 사용하십시오: `primary`, `secondary`, `accent`, `success`, `warning`, `error`, `info`.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -618,7 +618,7 @@ Only analyze code and suggest changes.
|
||||
|
||||
### Top P
|
||||
|
||||
`top_p` 옵션으로 응답 다양성을 제어합니다. 무작위성을 제어하는 Temperature의 대안입니다.
|
||||
`top_p` 옵션으로 응답의 다양성을 제어합니다. 무작위성 제어를 위한 온도의 대안입니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -630,15 +630,15 @@ Only analyze code and suggest changes.
|
||||
}
|
||||
```
|
||||
|
||||
값 범위는 0.0~1.0입니다. 값이 낮을수록 집중되고, 높을수록 다양해집니다.
|
||||
값은 0.0에서 1.0 사이입니다. 낮은 값은 더 집중되고, 높은 값은 더 다양합니다.
|
||||
|
||||
---
|
||||
|
||||
### Additional
|
||||
### 추가 옵션
|
||||
|
||||
agent config에 지정한 나머지 옵션은 모델 옵션으로 provider에 **그대로 전달(pass through)** 됩니다. 이를 통해 provider별 기능과 파라미터를 활용할 수 있습니다.
|
||||
에이전트 구성에 지정하는 다른 옵션은 모델 옵션으로 공급자에게 **직접 전달**됩니다. 이를 통해 공급자별 기능 및 매개변수를 사용할 수 있습니다.
|
||||
|
||||
예를 들어 OpenAI reasoning model에서는 reasoning effort를 제어할 수 있습니다.
|
||||
예를 들어, OpenAI의 추론 모델과 함께, 추론 노력을 제어할 수 있습니다:
|
||||
|
||||
```json title="opencode.json" {6,7}
|
||||
{
|
||||
@@ -653,55 +653,55 @@ agent config에 지정한 나머지 옵션은 모델 옵션으로 provider에 **
|
||||
}
|
||||
```
|
||||
|
||||
이 추가 옵션은 model 및 provider마다 다릅니다. 사용 가능한 파라미터는 provider 문서를 확인하세요.
|
||||
이 추가 옵션은 모델과 공급자별로 다릅니다. 사용 가능한 매개변수는 공급자의 문서를 확인하십시오.
|
||||
|
||||
:::tip
|
||||
사용 가능한 model 목록은 `opencode models` 명령으로 확인할 수 있습니다.
|
||||
`opencode models`를 실행하여 사용 가능한 모델 목록을 볼 수 있습니다.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 에이전트 생성
|
||||
## 에이전트 만들기
|
||||
|
||||
아래 명령으로 새 agent를 만들 수 있습니다.
|
||||
다음 명령을 사용하여 새로운 에이전트를 만들 수 있습니다:
|
||||
|
||||
```bash
|
||||
opencode agent create
|
||||
```
|
||||
|
||||
이 인터랙티브 명령은 다음을 수행합니다.
|
||||
이 대화형 명령은:
|
||||
|
||||
1. agent 저장 위치를 묻습니다(전역/프로젝트).
|
||||
2. agent가 수행할 작업의 설명을 받습니다.
|
||||
3. 적절한 시스템 prompt와 식별자를 생성합니다.
|
||||
4. agent가 접근할 tool을 선택하게 합니다.
|
||||
5. 마지막으로 agent config가 담긴 Markdown 파일을 생성합니다.
|
||||
1. 에이전트를 저장할 위치를 묻습니다 (전역 또는 프로젝트별).
|
||||
2. 에이전트가 해야 할 일에 대한 설명을 묻습니다.
|
||||
3. 적절한 시스템 프롬프트 및 식별자를 생성합니다.
|
||||
4. 에이전트가 접근할 수 있는 도구를 선택하게 합니다.
|
||||
5. 마지막으로, 에이전트 구성을 가진 markdown 파일을 생성합니다.
|
||||
|
||||
---
|
||||
|
||||
## 사용 사례
|
||||
|
||||
서로 다른 agent의 대표적인 사용 사례는 다음과 같습니다.
|
||||
다른 에이전트를 위한 몇 가지 일반적인 사용 사례는 다음과 같습니다.
|
||||
|
||||
- **Build agent**: 모든 tool을 활성화한 전체 개발 작업
|
||||
- **Plan agent**: 코드 변경 없이 분석과 계획 수행
|
||||
- **Review agent**: 읽기 전용 접근 + 문서화 tool 기반 코드 리뷰
|
||||
- **Debug agent**: bash/read tool 중심의 조사 작업
|
||||
- **Docs agent**: 파일 작업은 가능하지만 시스템 명령은 없는 문서 작성 작업
|
||||
- **Build Agent**: 모든 도구와 함께 전체 개발 작업
|
||||
- **Plan Agent**: 변경 없이 분석 및 계획
|
||||
- **Review Agent**: 읽기 전용 액세스 및 문서 도구와 함께 코드 리뷰
|
||||
- **Debug Agent**: bash 및 읽기 도구와 함께 조사에 집중
|
||||
- **Docs Agent**: 파일 작업과 문서 작성을 하지만 시스템 명령 없음
|
||||
|
||||
---
|
||||
|
||||
## 예시
|
||||
## 예제
|
||||
|
||||
실제로 유용하게 쓸 수 있는 예시 agent를 소개합니다.
|
||||
여기에 유용 할 수있는 몇 가지 예 에이전트가 있습니다.
|
||||
|
||||
:::tip
|
||||
공유하고 싶은 agent가 있나요? [PR 제출하기](https://github.com/anomalyco/opencode).
|
||||
공유하고 싶은 에이전트가 있습니까? [PR](https://github.com/anomalyco/opencode).
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
### Documentation agent
|
||||
### 문서 에이전트
|
||||
|
||||
```markdown title="~/.config/opencode/agents/docs-writer.md"
|
||||
---
|
||||
@@ -723,7 +723,7 @@ Focus on:
|
||||
|
||||
---
|
||||
|
||||
### Security auditor
|
||||
## 보안 감사
|
||||
|
||||
```markdown title="~/.config/opencode/agents/security-auditor.md"
|
||||
---
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
---
|
||||
title: Config
|
||||
description: Using the OpenCode JSON config.
|
||||
title: 구성
|
||||
description: OpenCode JSON 구성을 사용합니다.
|
||||
---
|
||||
|
||||
JSON config 파일로 OpenCode를 설정할 수 있습니다.
|
||||
JSON 구성 파일을 사용하여 OpenCode를 구성할 수 있습니다.
|
||||
|
||||
---
|
||||
|
||||
## 형식
|
||||
|
||||
OpenCode는 **JSON**과 **JSONC**(주석이 포함된 JSON) 형식을 모두 지원합니다.
|
||||
OpenCode는 **JSON** 및 **JSONC** (주석이 있는 JSON) 형식을 지원합니다.
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
@@ -25,44 +25,44 @@ OpenCode는 **JSON**과 **JSONC**(주석이 포함된 JSON) 형식을 모두 지
|
||||
|
||||
## 위치
|
||||
|
||||
config 파일은 여러 위치에 둘 수 있으며, 각 위치에는 우선순위가 있습니다.
|
||||
구성을 여러 위치에 배치할 수 있으며, 이들은 서로 다른 우선 순위(precedence)를 가집니다.
|
||||
|
||||
:::note
|
||||
config 파일은 **교체되지 않고 병합**됩니다.
|
||||
구성 파일은 **병합**되며, 대체되지 않습니다.
|
||||
:::
|
||||
|
||||
config 파일은 서로 대체되는 방식이 아니라 병합됩니다. 아래 config 위치의 설정이 결합되며, 충돌하는 key에 대해서만 나중에 로드된 config가 앞선 값을 override합니다. 충돌하지 않는 설정은 모두 유지됩니다.
|
||||
구성 파일은 함께 병합되며 대체되지 않습니다. 다음 구성 위치의 설정이 결합됩니다. 나중의 구성은 충돌하는 키에 대해 이전 구성을 덮어씁니다. 모든 구성의 설정이 보존됩니다.
|
||||
|
||||
예를 들어, 전역 config에 `theme: "opencode"`와 `autoupdate: true`가 있고 프로젝트 config에 `model: "anthropic/claude-sonnet-4-5"`가 있으면 최종 config에는 이 세 설정이 모두 포함됩니다.
|
||||
예를 들어, 전역 구성이 `theme: "opencode"` 및 `autoupdate: true`를 설정하고 프로젝트 구성이 `model: "anthropic/claude-sonnet-4-5"`를 설정하면 최종 구성에는 세 가지 설정이 모두 포함됩니다.
|
||||
|
||||
---
|
||||
|
||||
### 우선순위
|
||||
### 우선 순위
|
||||
|
||||
config source는 다음 순서로 로드됩니다(나중 source가 앞선 source를 override).
|
||||
구성 소스는 다음 순서로 로드됩니다 (나중 소스가 이전 소스를 덮어씀):
|
||||
|
||||
1. **Remote config**(`.well-known/opencode`) - 조직 기본값
|
||||
2. **Global config**(`~/.config/opencode/opencode.json`) - 사용자 기본 설정
|
||||
3. **Custom config**(`OPENCODE_CONFIG` env var) - custom override
|
||||
4. **Project config**(프로젝트의 `opencode.json`) - 프로젝트별 설정
|
||||
5. **`.opencode` directories** - agents, commands, plugins
|
||||
6. **Inline config**(`OPENCODE_CONFIG_CONTENT` env var) - 런타임 override
|
||||
1. **원격 구성** (`.well-known/opencode`에서) - 조직 기본값
|
||||
2. **전역 구성** (`~/.config/opencode/opencode.json`) - 사용자 환경설정
|
||||
3. **사용자 정의 구성** (`OPENCODE_CONFIG` 환경 변수) - 사용자 정의 재정의
|
||||
4. **프로젝트별 구성** (`opencode.json`) - 프로젝트별 설정
|
||||
5. **`.opencode` 디렉토리** - 에이전트, 명령, 플러그인
|
||||
6. **인라인 구성** (`OPENCODE_CONFIG_CONTENT` 환경 변수) - 런타임 재정의
|
||||
|
||||
즉, 프로젝트 config는 전역 기본값을 override할 수 있고, 전역 config는 조직의 Remote 기본값을 override할 수 있습니다.
|
||||
이것은 프로젝트 구성이 전역 기본값을 덮어쓸 수 있고, 전역 구성이 원격 조직 기본값을 덮어쓸 수 있음을 의미합니다.
|
||||
|
||||
:::note
|
||||
`.opencode` 및 `~/.config/opencode` 디렉토리는 하위 디렉토리에 **복수형 이름**을 사용합니다: `agents/`, `commands/`, `modes/`, `plugins/`, `skills/`, `tools/`, `themes/`. 단수형 이름(예: `agent/`)도 하위 호환성을 위해 지원합니다.
|
||||
`.opencode`와 `~/.config/opencode` 디렉토리는 하위 디렉토리에 대해 **복수형 이름**을 사용합니다: `agents/`, `commands/`, `modes/`, `plugins/`, `skills/`, `tools/`, 그리고 `themes/`. 단수형 이름(예: `agent/`)도 하위 호환성을 위해 지원됩니다.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
### Remote
|
||||
### 원격
|
||||
|
||||
조직은 `.well-known/opencode` endpoint로 기본 config를 제공할 수 있습니다. 이를 지원하는 provider로 인증하면 자동으로 가져옵니다.
|
||||
조직은 `.well-known/opencode` 엔드포인트를 통해 기본 구성을 제공할 수 있습니다. 이를 지원하는 공급자로 인증할 때 자동으로 가져옵니다.
|
||||
|
||||
Remote config는 가장 먼저 로드되어 기본 레이어 역할을 합니다. 이후의 모든 config source(전역, 프로젝트)는 이 기본값을 override할 수 있습니다.
|
||||
원격 구성은 기본 레이어로 가장 먼저 로드됩니다. 다른 구성 소스(전역, 프로젝트)는 이러한 기본값을 무시(override)할 수 있습니다.
|
||||
|
||||
예를 들어, 조직에서 기본 비활성화된 MCP 서버를 제공하는 경우:
|
||||
예를 들어, 조직이 기본적으로 비활성화된 MCP 서버를 제공하는 경우:
|
||||
|
||||
```json title="Remote config from .well-known/opencode"
|
||||
{
|
||||
@@ -76,7 +76,7 @@ Remote config는 가장 먼저 로드되어 기본 레이어 역할을 합니다
|
||||
}
|
||||
```
|
||||
|
||||
로컬 config에서 특정 서버를 활성화할 수 있습니다.
|
||||
로컬 설정에서 특정 서버를 활성화할 수 있습니다:
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -92,65 +92,65 @@ Remote config는 가장 먼저 로드되어 기본 레이어 역할을 합니다
|
||||
|
||||
---
|
||||
|
||||
### Global
|
||||
## 전역
|
||||
|
||||
전역 OpenCode config는 `~/.config/opencode/opencode.json`에 두세요. theme, provider, keybind 같은 사용자 전체 기본 설정은 전역 config로 관리하세요.
|
||||
`~/.config/opencode/opencode.json`에 전역 OpenCode 구성을 배치합니다. 테마, 공급자, 키바인드와 같은 사용자 전체 기본 설정에 전역 구성을 사용하십시오.
|
||||
|
||||
전역 config는 조직의 Remote 기본값을 override합니다.
|
||||
전역 구성은 원격 조직 기본값을 덮어씁니다.
|
||||
|
||||
---
|
||||
|
||||
### Per project
|
||||
## 프로젝트별
|
||||
|
||||
프로젝트 루트에 `opencode.json`을 추가하세요. 프로젝트 config는 표준 config 파일 중 우선순위가 가장 높아 전역 및 Remote config를 모두 override합니다.
|
||||
프로젝트 루트에 `opencode.json`을 추가합니다. 프로젝트 구성은 표준 구성 파일 중 가장 높은 우선순위를 가집니다. 이는 전역 및 원격 구성을 모두 덮어씁니다.
|
||||
|
||||
:::tip
|
||||
프로젝트별 config는 프로젝트 루트에 두세요.
|
||||
프로젝트의 루트에 특정 설정을 둡니다.
|
||||
:::
|
||||
|
||||
OpenCode 시작 시 현재 디렉토리에서 config 파일을 찾고, 없으면 가장 가까운 Git 디렉토리까지 상위로 탐색합니다.
|
||||
OpenCode가 시작될 때, 현재 디렉토리의 설정 파일이나 가장 가까운 Git 디렉토리를 찾습니다.
|
||||
|
||||
이 파일은 Git에 커밋해도 안전하며 전역 config와 동일한 schema를 사용합니다.
|
||||
이것은 Git으로 관리되며 전역 구성과 동일한 스키마를 사용합니다.
|
||||
|
||||
---
|
||||
|
||||
### Custom path
|
||||
### 사용자 정의 경로
|
||||
|
||||
`OPENCODE_CONFIG` 환경 변수로 custom config 파일 경로를 지정하세요.
|
||||
`OPENCODE_CONFIG` 환경 변수를 사용하여 사용자 정의 구성 파일 경로를 지정합니다.
|
||||
|
||||
```bash
|
||||
export OPENCODE_CONFIG=/path/to/my/custom-config.json
|
||||
opencode run "Hello world"
|
||||
```
|
||||
|
||||
Custom config는 우선순위상 전역 config와 프로젝트 config 사이에서 로드됩니다.
|
||||
사용자 정의 구성은 우선 순위에서 전역 구성과 프로젝트 구성 사이에 로드됩니다.
|
||||
|
||||
---
|
||||
|
||||
### Custom directory
|
||||
## 사용자 정의 디렉토리
|
||||
|
||||
`OPENCODE_CONFIG_DIR` 환경 변수로 custom config 디렉토리를 지정할 수 있습니다. 이 디렉토리는 표준 `.opencode` 디렉토리와 동일하게 agents, commands, modes, plugins를 검색하며, 동일한 구조를 따라야 합니다.
|
||||
`OPENCODE_CONFIG_DIR` 환경 변수를 사용하여 사용자 정의 구성 디렉토리를 지정할 수 있습니다. 이 디렉토리는 표준 `.opencode` 디렉토리와 마찬가지로 에이전트, 명령, 모드 및 플러그인을 검색하며 동일한 구조를 따라야 합니다.
|
||||
|
||||
```bash
|
||||
export OPENCODE_CONFIG_DIR=/path/to/my/config-directory
|
||||
opencode run "Hello world"
|
||||
```
|
||||
|
||||
custom 디렉토리는 전역 config와 `.opencode` 디렉토리 뒤에 로드되므로 해당 설정을 **override할 수 있습니다**.
|
||||
사용자 정의 디렉토리는 전역 구성 이후 및 `.opencode` 디렉토리 이전에 로드됩니다.
|
||||
|
||||
---
|
||||
|
||||
## Schema
|
||||
## 스키마
|
||||
|
||||
config 파일의 schema는 [**`opencode.ai/config.json`**](https://opencode.ai/config.json)에 정의되어 있습니다.
|
||||
구성 파일에는 [**`opencode.ai/config.json`**](https://opencode.ai/config.json)에 정의된 스키마가 있습니다.
|
||||
|
||||
편집기에서 이 schema를 기반으로 validation과 autocomplete를 사용할 수 있습니다.
|
||||
편집기는 스키마에 따라 유효성 검사 및 자동 완성을 제공해야 합니다.
|
||||
|
||||
---
|
||||
|
||||
### TUI
|
||||
#### TUI
|
||||
|
||||
`tui` 옵션으로 TUI 관련 설정을 구성할 수 있습니다.
|
||||
`tui` 옵션을 통해 TUI 관련 설정을 구성할 수 있습니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -165,19 +165,19 @@ config 파일의 schema는 [**`opencode.ai/config.json`**](https://opencode.ai/c
|
||||
}
|
||||
```
|
||||
|
||||
사용 가능한 옵션:
|
||||
유효한 옵션:
|
||||
|
||||
- `scroll_acceleration.enabled` - macOS 스타일 스크롤 가속을 활성화합니다. **`scroll_speed`보다 우선합니다.**
|
||||
- `scroll_speed` - 사용자 정의 스크롤 속도 배수(기본: `3`, 최소: `1`). `scroll_acceleration.enabled`가 `true`이면 무시됩니다.
|
||||
- `diff_style` - diff 렌더링 방식을 제어합니다. `"auto"`는 터미널 너비에 맞춰 조정되고, `"stacked"`는 항상 단일 컬럼으로 표시합니다.
|
||||
- `scroll_speed` - 사용자 정의 스크롤 속도 배수 (기본값: `3`, 최소값: `1`). `scroll_acceleration.enabled`가 `true`이면 무시됩니다.
|
||||
- `diff_style` - diff 렌더링을 제어합니다. `"auto"`는 터미널 너비에 맞추고, `"stacked"`는 항상 단일 열을 보여줍니다.
|
||||
|
||||
[TUI에 대해 더 알아보기](/docs/tui).
|
||||
[TUI 사용법에 대해 더 알아보기](/docs/tui).
|
||||
|
||||
---
|
||||
|
||||
### Server
|
||||
## 서버
|
||||
|
||||
`server` 옵션으로 `opencode serve`와 `opencode web` 명령의 server 설정을 구성할 수 있습니다.
|
||||
`opencode serve` 및 `opencode web` 명령에 대한 서버 설정을 구성할 수 있습니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -192,21 +192,21 @@ config 파일의 schema는 [**`opencode.ai/config.json`**](https://opencode.ai/c
|
||||
}
|
||||
```
|
||||
|
||||
사용 가능한 옵션:
|
||||
유효한 옵션:
|
||||
|
||||
- `port` - 수신할 포트입니다.
|
||||
- `hostname` - 수신할 호스트명입니다. `mdns`가 활성화되어 있고 hostname이 없으면 기본값은 `0.0.0.0`입니다.
|
||||
- `mdns` - mDNS service discovery를 활성화합니다. 네트워크 내 다른 기기에서 OpenCode server를 찾을 수 있습니다.
|
||||
- `mdnsDomain` - mDNS service의 custom 도메인 이름입니다. 기본값은 `opencode.local`입니다. 같은 네트워크에서 여러 인스턴스를 실행할 때 유용합니다.
|
||||
- `cors` - 브라우저 기반 client에서 HTTP server를 사용할 때 허용할 추가 CORS origin입니다. 값은 전체 origin(scheme + host + optional port) 형식이어야 하며, 예: `https://app.example.com`.
|
||||
- `port` - 리스닝 포트.
|
||||
- `hostname` - 리스닝 호스트 이름. `mdns`가 활성화되고 hostname이 설정되지 않으면 `0.0.0.0`이 기본값이 됩니다.
|
||||
- `mdns` - mDNS 서비스 발견 활성화. 로컬 네트워크의 다른 장치가 OpenCode 서버를 찾을 수 있습니다.
|
||||
- `mdnsDomain` - mDNS 서비스를 위한 사용자 정의 도메인 이름. 기본값은 `opencode.local`입니다. 동일한 네트워크에서 여러 인스턴스를 실행할 때 유용합니다.
|
||||
- `cors` - 브라우저 기반 클라이언트에서 HTTP 서버를 사용할 때 CORS를 허용할 추가 출처(Origin). 값은 전체 출처(스킴 + 호스트 + 선택적 포트)여야 합니다. 예: `https://app.example.com`.
|
||||
|
||||
[server에 대해 더 알아보기](/docs/server).
|
||||
[서버에 대해 더 알아보기](/docs/server).
|
||||
|
||||
---
|
||||
|
||||
### Tools
|
||||
## 도구
|
||||
|
||||
`tools` 옵션으로 LLM이 사용할 수 있는 tool을 관리할 수 있습니다.
|
||||
`tools` 옵션을 통해 LLM이 사용할 수 있는 도구를 구성할 수 있습니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -218,13 +218,13 @@ config 파일의 schema는 [**`opencode.ai/config.json`**](https://opencode.ai/c
|
||||
}
|
||||
```
|
||||
|
||||
[tool에 대해 더 알아보기](/docs/tools).
|
||||
[도구에 대해 더 알아보기](/docs/tools).
|
||||
|
||||
---
|
||||
|
||||
### Models
|
||||
## 모델
|
||||
|
||||
OpenCode config의 `provider`, `model`, `small_model` 옵션으로 사용할 provider와 model을 설정할 수 있습니다.
|
||||
`provider`, `model`, `small_model` 옵션을 통해 OpenCode 구성에서 사용할 공급자와 모델을 구성할 수 있습니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -235,9 +235,9 @@ OpenCode config의 `provider`, `model`, `small_model` 옵션으로 사용할 pro
|
||||
}
|
||||
```
|
||||
|
||||
`small_model`은 제목 생성 같은 경량 작업에 사용할 별도 model을 설정합니다. 기본적으로 OpenCode는 provider에서 더 저렴한 model을 사용할 수 있으면 우선 사용하고, 없으면 메인 model로 fallback합니다.
|
||||
`small_model` 옵션은 제목 생성과 같은 가벼운 작업을 위한 별도의 모델을 구성합니다. 기본적으로, OpenCode는 공급자에게서 사용 가능한 더 저렴한 모델이 있다면 그것을 사용하고, 그렇지 않으면 주 모델로 돌아갑니다.
|
||||
|
||||
provider 옵션에는 `timeout`, `setCacheKey`를 포함할 수 있습니다.
|
||||
공급자 옵션은 `timeout`과 `setCacheKey`를 포함할 수 있습니다:
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -253,20 +253,20 @@ provider 옵션에는 `timeout`, `setCacheKey`를 포함할 수 있습니다.
|
||||
}
|
||||
```
|
||||
|
||||
- `timeout` - 요청 timeout(밀리초, 기본값: 300000). `false`로 비활성화할 수 있습니다.
|
||||
- `setCacheKey` - 지정된 provider에 대해 cache key가 항상 설정되도록 보장합니다.
|
||||
- `timeout` - 요청 타임아웃(밀리초) (기본값: 300000). `false`로 설정하여 비활성화할 수 있습니다.
|
||||
- `setCacheKey` - 지정된 공급자에 대해 캐시 키가 항상 설정되도록 강제합니다.
|
||||
|
||||
[local model](/docs/models#local)도 설정할 수 있습니다. [더 알아보기](/docs/models).
|
||||
[로컬 모델](/docs/models#local)을 구성할 수도 있습니다. [더 알아보기](/docs/models).
|
||||
|
||||
---
|
||||
|
||||
#### Provider-Specific Options
|
||||
### 공급자별 옵션
|
||||
|
||||
일부 provider는 공통 옵션인 `timeout`, `apiKey` 외에 추가 config 옵션을 지원합니다.
|
||||
일반적인 `timeout` 및 `apiKey` 외에도 일부 공급자는 추가 구성 옵션을 지원합니다.
|
||||
|
||||
##### Amazon Bedrock
|
||||
|
||||
Amazon Bedrock은 AWS 전용 config를 지원합니다.
|
||||
Amazon Bedrock는 AWS 관련 구성을 지원합니다:
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -283,21 +283,21 @@ Amazon Bedrock은 AWS 전용 config를 지원합니다.
|
||||
}
|
||||
```
|
||||
|
||||
- `region` - Bedrock용 AWS 리전(`AWS_REGION` env var 또는 기본값 `us-east-1`)
|
||||
- `profile` - `~/.aws/credentials`의 AWS named profile(기본값: `AWS_PROFILE` env var)
|
||||
- `endpoint` - VPC endpoint용 custom endpoint URL입니다. AWS 용어를 사용한 일반 `baseURL` 옵션의 별칭(alias)입니다. 둘 다 지정하면 `endpoint`가 우선합니다.
|
||||
- `region` - Bedrock를 위한 AWS 리전 (`AWS_REGION` 환경 변수 또는 `us-east-1`이 기본값)
|
||||
- `profile` - `~/.aws/credentials`의 AWS 프로필 이름 (`AWS_PROFILE` 환경 변수가 기본값)
|
||||
- `endpoint` - VPC 엔드포인트 등을 위한 사용자 정의 엔드포인트 URL. 이는 AWS 관련 용어를 사용한 일반적인 `baseURL` 옵션의 별칭입니다. 둘 다 지정된 경우 `endpoint`가 우선합니다.
|
||||
|
||||
:::note
|
||||
Bearer token(`AWS_BEARER_TOKEN_BEDROCK` 또는 `/connect`)은 profile 기반 인증보다 우선합니다. 자세한 내용은 [authentication precedence](/docs/providers#authentication-precedence)를 참고하세요.
|
||||
Bearer 토큰(`AWS_BEARER_TOKEN_BEDROCK` 또는 `/connect`)은 프로필 기반 인증보다 우선합니다. 자세한 내용은 [인증 우선 순위](/docs/providers#authentication-precedence)를 참조하십시오.
|
||||
:::
|
||||
|
||||
[Amazon Bedrock config 더 알아보기](/docs/providers#amazon-bedrock).
|
||||
[Amazon Bedrock에 대해 더 알아보기](/docs/providers#amazon-bedrock).
|
||||
|
||||
---
|
||||
|
||||
### Themes
|
||||
## 테마
|
||||
|
||||
`theme` 옵션으로 OpenCode config에서 사용할 theme를 설정할 수 있습니다.
|
||||
`theme` 옵션을 통해 OpenCode 구성에서 사용할 테마를 설정할 수 있습니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -310,9 +310,9 @@ Bearer token(`AWS_BEARER_TOKEN_BEDROCK` 또는 `/connect`)은 profile 기반 인
|
||||
|
||||
---
|
||||
|
||||
### Agents
|
||||
## 에이전트
|
||||
|
||||
`agent` 옵션으로 특정 작업용 전문 agent를 구성할 수 있습니다.
|
||||
`agent` 옵션을 통해 특정 작업을 전문으로 하는 에이전트를 구성할 수 있습니다.
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
@@ -332,13 +332,13 @@ Bearer token(`AWS_BEARER_TOKEN_BEDROCK` 또는 `/connect`)은 profile 기반 인
|
||||
}
|
||||
```
|
||||
|
||||
`~/.config/opencode/agents/` 또는 `.opencode/agents/`의 Markdown 파일로 agent를 정의할 수도 있습니다. [더 알아보기](/docs/agents).
|
||||
`~/.config/opencode/agents/` 또는 `.opencode/agents/`에서 Markdown 파일을 사용하여 에이전트를 정의할 수도 있습니다. [더 알아보기](/docs/agents).
|
||||
|
||||
---
|
||||
|
||||
### Default agent
|
||||
### 기본 에이전트
|
||||
|
||||
`default_agent` 옵션으로 기본 agent를 설정할 수 있습니다. 별도 지정이 없을 때 어떤 agent를 사용할지 결정합니다.
|
||||
`default_agent` 옵션을 사용하여 기본 에이전트를 설정할 수 있습니다. 명시적으로 지정되지 않았을 때 어떤 에이전트가 사용될지 결정합니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -347,15 +347,15 @@ Bearer token(`AWS_BEARER_TOKEN_BEDROCK` 또는 `/connect`)은 profile 기반 인
|
||||
}
|
||||
```
|
||||
|
||||
기본 agent는 primary agent여야 합니다(subagent 불가). `"build"`, `"plan"` 같은 내장 agent나 직접 정의한 [custom agent](/docs/agents)를 지정할 수 있습니다. 지정한 agent가 없거나 subagent이면 OpenCode는 경고와 함께 `"build"`로 fallback합니다.
|
||||
기본 에이전트는 기본(primary) 에이전트여야 합니다(서브 에이전트 불가). `"build"` 또는 `"plan"`과 같은 내장 에이전트이거나 정의된 [사용자 정의 에이전트](./agents)일 수 있습니다. 지정된 에이전트가 존재하지 않는 경우, OpenCode는 경고와 함께 `"build"`로 돌아갑니다.
|
||||
|
||||
이 설정은 TUI, CLI(`opencode run`), 데스크톱 앱, GitHub Action 등 모든 인터페이스에 적용됩니다.
|
||||
이 설정은 모든 인터페이스에 적용됩니다: TUI, CLI (`opencode run`), 데스크톱 앱 및 GitHub Action.
|
||||
|
||||
---
|
||||
|
||||
### Sharing
|
||||
## 공유
|
||||
|
||||
`share` 옵션으로 [share](/docs/share) 기능을 설정할 수 있습니다.
|
||||
`share` 옵션을 통해 [공유](/docs/share) 기능을 구성할 수 있습니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -364,19 +364,19 @@ Bearer token(`AWS_BEARER_TOKEN_BEDROCK` 또는 `/connect`)은 profile 기반 인
|
||||
}
|
||||
```
|
||||
|
||||
허용 값:
|
||||
값은 다음과 같습니다:
|
||||
|
||||
- `"manual"` - 명령으로 수동 공유 허용(기본값)
|
||||
- `"auto"` - 새 대화를 자동 공유
|
||||
- `"disabled"` - 공유 기능 완전 비활성화
|
||||
- `"manual"` - 명령을 통한 수동 공유 허용 (기본값)
|
||||
- `"auto"` - 새로운 대화를 자동으로 공유
|
||||
- `"disabled"` - 공유 기능 완전히 비활성화
|
||||
|
||||
기본값은 manual 모드이며, `/share` 명령으로 명시적으로 공유해야 합니다.
|
||||
기본적으로 `/share` 명령을 사용하여 대화를 명시적으로 공유해야 하는 수동 모드로 설정됩니다.
|
||||
|
||||
---
|
||||
|
||||
### Commands
|
||||
## 명령
|
||||
|
||||
`command` 옵션으로 반복 작업용 custom command를 구성할 수 있습니다.
|
||||
`command` 옵션을 통해 반복 작업을 위한 사용자 정의 명령을 구성할 수 있습니다.
|
||||
|
||||
```jsonc title="opencode.jsonc"
|
||||
{
|
||||
@@ -387,6 +387,8 @@ Bearer token(`AWS_BEARER_TOKEN_BEDROCK` 또는 `/connect`)은 profile 기반 인
|
||||
"description": "Run tests with coverage",
|
||||
"agent": "build",
|
||||
"model": "anthropic/claude-haiku-4-5",
|
||||
"agent": "build",
|
||||
"model": "anthropic/claude-haiku-4-5",
|
||||
},
|
||||
"component": {
|
||||
"template": "Create a new React component named $ARGUMENTS with TypeScript support.\nInclude proper typing and basic structure.",
|
||||
@@ -396,13 +398,13 @@ Bearer token(`AWS_BEARER_TOKEN_BEDROCK` 또는 `/connect`)은 profile 기반 인
|
||||
}
|
||||
```
|
||||
|
||||
`~/.config/opencode/commands/` 또는 `.opencode/commands/`의 Markdown 파일로 command를 정의할 수도 있습니다. [더 알아보기](/docs/commands).
|
||||
`~/.config/opencode/commands/` 또는 `.opencode/commands/`에서 Markdown 파일을 사용하여 명령을 정의할 수도 있습니다. [더 알아보기](/docs/commands).
|
||||
|
||||
---
|
||||
|
||||
### Keybinds
|
||||
## 키바인드
|
||||
|
||||
`keybinds` 옵션으로 keybind를 커스터마이즈할 수 있습니다.
|
||||
`keybinds` 옵션을 통해 키바인드를 사용자 정의할 수 있습니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -415,9 +417,9 @@ Bearer token(`AWS_BEARER_TOKEN_BEDROCK` 또는 `/connect`)은 profile 기반 인
|
||||
|
||||
---
|
||||
|
||||
### Autoupdate
|
||||
## 자동 업데이트
|
||||
|
||||
OpenCode는 시작 시 새 업데이트를 자동으로 다운로드합니다. `autoupdate` 옵션으로 비활성화할 수 있습니다.
|
||||
OpenCode는 시작될 때 자동으로 새로운 업데이트를 다운로드합니다. `autoupdate` 옵션으로 이를 비활성화할 수 있습니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -426,14 +428,14 @@ OpenCode는 시작 시 새 업데이트를 자동으로 다운로드합니다. `
|
||||
}
|
||||
```
|
||||
|
||||
업데이트를 자동 적용하지 않고 새 버전 알림만 받고 싶다면 `autoupdate`를 `"notify"`로 설정하세요.
|
||||
이 옵션은 Homebrew 같은 패키지 매니저로 설치하지 않은 경우에만 동작합니다.
|
||||
업데이트를 원하지 않지만 새 버전을 알림받고 싶다면 `autoupdate`를 `"notify"`로 설정하십시오.
|
||||
Homebrew와 같은 패키지 관리자를 사용하여 설치되지 않은 경우에만 작동합니다.
|
||||
|
||||
---
|
||||
|
||||
### Formatters
|
||||
## 포매터
|
||||
|
||||
`formatter` 옵션으로 코드 formatter를 설정할 수 있습니다.
|
||||
`formatter` 옵션을 통해 코드 포매터를 구성할 수 있습니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -453,15 +455,15 @@ OpenCode는 시작 시 새 업데이트를 자동으로 다운로드합니다. `
|
||||
}
|
||||
```
|
||||
|
||||
[formatter에 대해 더 알아보기](/docs/formatters).
|
||||
[포매터에 대해 더 알아보기](/docs/formatters).
|
||||
|
||||
---
|
||||
|
||||
### Permissions
|
||||
## 권한
|
||||
|
||||
기본적으로 OpenCode는 **명시적 승인 없이 모든 작업을 허용**합니다. `permission` 옵션으로 이 동작을 바꿀 수 있습니다.
|
||||
기본적으로, OpenCode는 **명시적 승인 없이 모든 작업을 허용**합니다. `permission` 옵션을 사용하여 이를 변경할 수 있습니다.
|
||||
|
||||
예를 들어 `edit`, `bash` tool이 사용자 승인을 요구하게 하려면:
|
||||
예를 들어, `edit` 및 `bash` 도구가 사용자 승인을 요구하도록 설정하려면:
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -473,34 +475,32 @@ OpenCode는 시작 시 새 업데이트를 자동으로 다운로드합니다. `
|
||||
}
|
||||
```
|
||||
|
||||
[permission에 대해 더 알아보기](/docs/permissions).
|
||||
[권한에 대해 더 알아보기](/docs/permissions).
|
||||
|
||||
---
|
||||
|
||||
### Compaction
|
||||
### 압축
|
||||
|
||||
`compaction` 옵션으로 context compaction 동작을 제어할 수 있습니다.
|
||||
`compaction` 옵션을 통해 컨텍스트 압축 동작을 제어할 수 있습니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"compaction": {
|
||||
"auto": true,
|
||||
"prune": true,
|
||||
"reserved": 10000
|
||||
"prune": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `auto` - context가 가득 찼을 때 세션을 자동 compact합니다(기본값: `true`).
|
||||
- `prune` - token 절약을 위해 오래된 tool 출력을 제거합니다(기본값: `true`).
|
||||
- `reserved` - compaction용 token buffer입니다. compaction 중 overflow가 나지 않도록 충분한 window를 남깁니다.
|
||||
- `auto` - 컨텍스트가 꽉 차면 자동으로 세션을 압축합니다 (기본값: `true`).
|
||||
- `prune` - 토큰을 절약하기 위해 오래된 도구 출력을 제거합니다 (기본값: `true`).
|
||||
|
||||
---
|
||||
|
||||
### Watcher
|
||||
### 파일 감시자
|
||||
|
||||
`watcher` 옵션으로 파일 watcher ignore 패턴을 설정할 수 있습니다.
|
||||
`watcher` 옵션을 통해 파일 감시자가 무시할 패턴을 설정할 수 있습니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -511,13 +511,13 @@ OpenCode는 시작 시 새 업데이트를 자동으로 다운로드합니다. `
|
||||
}
|
||||
```
|
||||
|
||||
패턴은 glob 문법을 따릅니다. 파일 감시에서 노이즈가 많은 디렉토리를 제외할 때 유용합니다.
|
||||
패턴은 glob 구문을 따릅니다. 잡음이 많은 디렉토리를 제외하는 데 사용하십시오.
|
||||
|
||||
---
|
||||
|
||||
### MCP servers
|
||||
### MCP 서버
|
||||
|
||||
`mcp` 옵션으로 사용할 MCP server를 설정할 수 있습니다.
|
||||
`mcp` 옵션을 통해 사용하려는 MCP 서버를 구성할 수 있습니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -530,11 +530,11 @@ OpenCode는 시작 시 새 업데이트를 자동으로 다운로드합니다. `
|
||||
|
||||
---
|
||||
|
||||
### Plugins
|
||||
### 플러그인
|
||||
|
||||
[Plugins](/docs/plugins)는 custom tool, hook, integration으로 OpenCode를 확장합니다.
|
||||
[플러그인](/docs/plugins)은 사용자 정의 도구, 훅(hook), 통합으로 OpenCode를 확장합니다.
|
||||
|
||||
plugin 파일은 `.opencode/plugins/` 또는 `~/.config/opencode/plugins/`에 두세요. `plugin` 옵션으로 npm plugin을 로드할 수도 있습니다.
|
||||
`.opencode/plugins/` 또는 `~/.config/opencode/plugins/`에 플러그인 파일을 배치하십시오. `plugin` 옵션을 통해 npm에서 플러그인을 로드할 수 있습니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -547,9 +547,9 @@ plugin 파일은 `.opencode/plugins/` 또는 `~/.config/opencode/plugins/`에
|
||||
|
||||
---
|
||||
|
||||
### Instructions
|
||||
### 지침
|
||||
|
||||
`instructions` 옵션으로 사용 중인 model에 제공할 지침 파일을 설정할 수 있습니다.
|
||||
`instructions` 옵션을 통해 모델에 대한 지침(Rules)을 구성할 수 있습니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -558,13 +558,13 @@ plugin 파일은 `.opencode/plugins/` 또는 `~/.config/opencode/plugins/`에
|
||||
}
|
||||
```
|
||||
|
||||
이 옵션은 지침 파일 경로 및 glob 패턴 배열을 받습니다. [rules에 대해 더 알아보기](/docs/rules).
|
||||
지침 파일에 대한 경로와 glob 패턴의 배열을 사용합니다. [규칙에 대해 더 알아보기](/docs/rules).
|
||||
|
||||
---
|
||||
|
||||
### Disabled providers
|
||||
## 비활성화된 공급자
|
||||
|
||||
`disabled_providers` 옵션으로 자동 로드되는 provider를 비활성화할 수 있습니다. credential이 있어도 특정 provider를 로드하지 않게 하고 싶을 때 유용합니다.
|
||||
`disabled_providers` 옵션을 통해 자동으로 로드되는 공급자를 비활성화할 수 있습니다. 자격 증명이 유효하더라도 특정 공급자가 로드되는 것을 방지할 때 유용합니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -577,17 +577,17 @@ plugin 파일은 `.opencode/plugins/` 또는 `~/.config/opencode/plugins/`에
|
||||
`disabled_providers`는 `enabled_providers`보다 우선합니다.
|
||||
:::
|
||||
|
||||
`disabled_providers`는 provider ID 배열을 받습니다. provider가 비활성화되면:
|
||||
`disabled_providers` 옵션은 공급자 ID의 배열을 허용합니다. 공급자가 비활성화되면:
|
||||
|
||||
- 환경 변수가 설정되어 있어도 로드되지 않습니다.
|
||||
- `/connect` 명령으로 API key를 설정해도 로드되지 않습니다.
|
||||
- 해당 provider의 model은 model 선택 목록에 표시되지 않습니다.
|
||||
- 환경 변수가 설정된 경우에도 로드되지 않습니다.
|
||||
- API 키가 `/connect` 명령을 통해 구성되는 경우에도 로드되지 않습니다.
|
||||
- 공급자의 모델은 모델 선택 목록에 표시되지 않습니다.
|
||||
|
||||
---
|
||||
|
||||
### Enabled providers
|
||||
### 활성화된 공급자
|
||||
|
||||
`enabled_providers` 옵션으로 provider allowlist를 지정할 수 있습니다. 이 값을 설정하면 지정한 provider만 활성화되고 나머지는 무시됩니다.
|
||||
`enabled_providers` 옵션을 통해 허용할 공급자를 지정할 수 있습니다. 설정하면 지정된 공급자만 활성화되고 다른 모든 공급자는 무시됩니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -596,19 +596,19 @@ plugin 파일은 `.opencode/plugins/` 또는 `~/.config/opencode/plugins/`에
|
||||
}
|
||||
```
|
||||
|
||||
provider를 하나씩 비활성화하는 대신, OpenCode가 특정 provider만 사용하도록 제한하고 싶을 때 유용합니다.
|
||||
OpenCode를 제한하여 특정 공급자만 사용하도록 할 때 유용합니다.
|
||||
|
||||
:::note
|
||||
`disabled_providers`는 `enabled_providers`보다 우선합니다.
|
||||
:::
|
||||
|
||||
동일 provider가 `enabled_providers`와 `disabled_providers`에 모두 있으면 하위 호환성을 위해 `disabled_providers`가 우선합니다.
|
||||
공급자가 `enabled_providers`와 `disabled_providers` 둘 다에 나타나면, 하위 호환성을 위해 `disabled_providers`가 우선합니다.
|
||||
|
||||
---
|
||||
|
||||
### Experimental
|
||||
### 실험적 기능
|
||||
|
||||
`experimental` key에는 현재 활발히 개발 중인 옵션이 포함됩니다.
|
||||
`experimental` 키는 활발히 개발 중인 옵션을 포함합니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -618,20 +618,20 @@ provider를 하나씩 비활성화하는 대신, OpenCode가 특정 provider만
|
||||
```
|
||||
|
||||
:::caution
|
||||
experimental 옵션은 안정적이지 않습니다. 예고 없이 변경되거나 제거될 수 있습니다.
|
||||
실험적 옵션은 안정적이지 않습니다. 예고 없이 변경되거나 제거될 수 있습니다.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Variables
|
||||
## 변수
|
||||
|
||||
config 파일에서 환경 변수와 파일 내용을 참조할 수 있도록 변수 치환을 사용할 수 있습니다.
|
||||
구성 파일에서 환경 변수를 참조하고 파일 내용에 대한 변수 대체를 사용할 수 있습니다.
|
||||
|
||||
---
|
||||
|
||||
### Env vars
|
||||
##### 환경 변수
|
||||
|
||||
`{env:VARIABLE_NAME}` 형식으로 환경 변수를 치환할 수 있습니다.
|
||||
`{env:VARIABLE_NAME}`을 사용하여 환경 변수를 대체합니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -648,13 +648,13 @@ config 파일에서 환경 변수와 파일 내용을 참조할 수 있도록
|
||||
}
|
||||
```
|
||||
|
||||
환경 변수가 설정되지 않았으면 빈 문자열로 치환됩니다.
|
||||
환경 변수가 설정되지 않으면 빈 문자열로 대체됩니다.
|
||||
|
||||
---
|
||||
|
||||
### Files
|
||||
## 파일
|
||||
|
||||
`{file:path/to/file}` 형식으로 파일 내용을 치환할 수 있습니다.
|
||||
`{file:path/to/file}`를 사용하여 파일의 내용을 대체합니다.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -670,13 +670,13 @@ config 파일에서 환경 변수와 파일 내용을 참조할 수 있도록
|
||||
}
|
||||
```
|
||||
|
||||
파일 경로는 다음을 지원합니다.
|
||||
파일 경로는:
|
||||
|
||||
- config 파일 디렉토리 기준 상대 경로
|
||||
- `/` 또는 `~`로 시작하는 절대 경로
|
||||
- 구성 파일 디렉토리에 상대적이거나
|
||||
- `/` 또는 `~`로 시작하는 절대 경로여야 합니다.
|
||||
|
||||
이 기능은 다음 상황에 유용합니다.
|
||||
이것은 다음에 유용합니다:
|
||||
|
||||
- API key 같은 민감 정보를 별도 파일로 분리
|
||||
- 큰 지침 파일을 config를 복잡하게 만들지 않고 포함
|
||||
- 여러 config 파일에서 공통 설정 스니펫 재사용
|
||||
- API 키와 같은 민감한 데이터를 별도의 파일에 유지할 때.
|
||||
- 구성을 어지럽히지 않고 큰 지침 파일을 포함할 때.
|
||||
- 여러 구성 파일에서 공통 구성 스니펫을 공유할 때.
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
---
|
||||
title: Custom Tools
|
||||
description: Create tools the LLM can call in OpenCode.
|
||||
title: 사용자 정의 도구
|
||||
description: OpenCode에서 LLM이 호출할 수 있는 도구를 만듭니다.
|
||||
---
|
||||
|
||||
custom tool은 대화 중 LLM이 호출할 수 있도록 사용자가 직접 만든 함수입니다. `read`, `write`, `bash` 같은 OpenCode의 [built-in tools](/docs/tools)와 함께 동작합니다.
|
||||
사용자 정의 도구는 LLM이 대화 중에 호출 할 수있는 기능을 만듭니다. 그들은 `read`, `write` 및 `bash`와 같은 opencode의 [붙박이 도구](./tools)와 함께 작동합니다.
|
||||
|
||||
---
|
||||
|
||||
## 도구 만들기
|
||||
|
||||
tool은 **TypeScript** 또는 **JavaScript** 파일로 정의합니다. 다만 tool 정의에서 호출하는 스크립트는 **어떤 언어든** 사용할 수 있습니다. 즉, TypeScript/JavaScript는 tool 정의 자체에만 필요합니다.
|
||||
도구는 **TypeScript** 또는 **JavaScript** 파일로 정의됩니다. 그러나 도구 정의는 ** 어떤 언어로 작성된 스크립트를 호출 할 수 있습니다 ** - TypeScript 또는 JavaScript는 도구 정의 자체에서만 사용됩니다.
|
||||
|
||||
---
|
||||
|
||||
### 위치
|
||||
## 위치
|
||||
|
||||
tool은 다음 위치에 둘 수 있습니다.
|
||||
그들은 정의 할 수 있습니다:
|
||||
|
||||
- 프로젝트의 `.opencode/tools/` 디렉토리(로컬)
|
||||
- `~/.config/opencode/tools/` 디렉토리(전역)
|
||||
- 프로젝트의 `.opencode/tools/` 디렉토리에 배치하여 로컬.
|
||||
- 또는 전 세계적으로 `~/.config/opencode/tools/`에 배치하여.
|
||||
|
||||
---
|
||||
|
||||
### 구조
|
||||
## 구조
|
||||
|
||||
tool을 가장 쉽게 만드는 방법은 타입 안정성과 validation을 제공하는 `tool()` helper를 사용하는 것입니다.
|
||||
도구를 만드는 가장 쉬운 방법은 `tool()` helper를 사용하여 유형 안전 및 검증을 제공합니다.
|
||||
|
||||
```ts title=".opencode/tools/database.ts" {1}
|
||||
import { tool } from "@opencode-ai/plugin"
|
||||
@@ -41,13 +41,13 @@ export default tool({
|
||||
})
|
||||
```
|
||||
|
||||
**파일 이름**이 **tool 이름**이 됩니다. 위 예시는 `database` tool을 생성합니다.
|
||||
**파일 이름**는 **tool name**가 됩니다. 위는 `database` 공구를 만듭니다.
|
||||
|
||||
---
|
||||
|
||||
#### 파일 하나에 여러 tool 정의
|
||||
### 파일당 여러 도구
|
||||
|
||||
하나의 파일에서 여러 tool을 export할 수도 있습니다. 각 export는 **별도의 tool**이 되며 이름은 **`<filename>_<exportname>`** 형식을 사용합니다.
|
||||
단일 파일에서 여러 도구를 수출할 수 있습니다. 각 수출은 ** 별도의 도구 ** 이름 ** `<filename>_<exportname>`**:
|
||||
|
||||
```ts title=".opencode/tools/math.ts"
|
||||
import { tool } from "@opencode-ai/plugin"
|
||||
@@ -75,13 +75,13 @@ export const multiply = tool({
|
||||
})
|
||||
```
|
||||
|
||||
이 경우 `math_add`, `math_multiply` 두 tool이 생성됩니다.
|
||||
이것은 2개의 공구를 만듭니다: `math_add`와 `math_multiply`.
|
||||
|
||||
---
|
||||
|
||||
### 인자
|
||||
#### 스키마
|
||||
|
||||
인자 타입은 `tool.schema`로 정의할 수 있습니다. `tool.schema`는 [Zod](https://zod.dev) 기반입니다.
|
||||
`tool.schema`를 사용할 수 있습니다, 그냥 [Zod](https://zod.dev), 인수 유형을 정의합니다.
|
||||
|
||||
```ts "tool.schema"
|
||||
args: {
|
||||
@@ -89,7 +89,7 @@ args: {
|
||||
}
|
||||
```
|
||||
|
||||
[Zod](https://zod.dev)를 직접 import해서 일반 객체를 반환하는 방식도 사용할 수 있습니다.
|
||||
[Zod](https://zod.dev)를 직접 가져오고 일반 객체를 반환할 수 있습니다.
|
||||
|
||||
```ts {6}
|
||||
import { z } from "zod"
|
||||
@@ -108,9 +108,9 @@ export default {
|
||||
|
||||
---
|
||||
|
||||
### Context
|
||||
### 컨텍스트
|
||||
|
||||
tool은 현재 세션의 context 정보를 전달받습니다.
|
||||
도구는 현재 세션에 대한 컨텍스트를받습니다.
|
||||
|
||||
```ts title=".opencode/tools/project.ts" {8}
|
||||
import { tool } from "@opencode-ai/plugin"
|
||||
@@ -126,18 +126,18 @@ export default tool({
|
||||
})
|
||||
```
|
||||
|
||||
세션 작업 디렉토리는 `context.directory`를 사용하세요.
|
||||
git worktree 루트는 `context.worktree`를 사용하세요.
|
||||
세션 작업 디렉토리에 `context.directory`를 사용합니다.
|
||||
git worktree 루트에 `context.worktree`를 사용합니다.
|
||||
|
||||
---
|
||||
|
||||
## 예시
|
||||
## 예제
|
||||
|
||||
### Python으로 tool 작성
|
||||
### Python 도구 작성
|
||||
|
||||
tool은 원하는 언어로 작성할 수 있습니다. 아래는 Python으로 두 숫자를 더하는 예시입니다.
|
||||
원하는 모든 언어로 도구를 쓸 수 있습니다. 여기에 Python을 사용하여 두 개의 숫자를 추가하는 예입니다.
|
||||
|
||||
먼저 Python 스크립트로 tool을 만듭니다.
|
||||
먼저 Python 스크립트로 도구를 만듭니다.
|
||||
|
||||
```python title=".opencode/tools/add.py"
|
||||
import sys
|
||||
@@ -147,7 +147,7 @@ b = int(sys.argv[2])
|
||||
print(a + b)
|
||||
```
|
||||
|
||||
그다음 이 스크립트를 호출하는 tool 정의를 만듭니다.
|
||||
그런 다음 도구 정의를 만듭니다.
|
||||
|
||||
```ts title=".opencode/tools/python-add.ts" {10}
|
||||
import { tool } from "@opencode-ai/plugin"
|
||||
@@ -167,4 +167,4 @@ export default tool({
|
||||
})
|
||||
```
|
||||
|
||||
여기서는 Python 스크립트를 실행하기 위해 [`Bun.$`](https://bun.com/docs/runtime/shell) 유틸리티를 사용합니다.
|
||||
여기에 우리는 [`Bun.$`](https://bun.com/docs/runtime/shell) 유틸리티를 사용하여 Python 스크립트를 실행합니다.
|
||||
|
||||
@@ -84,8 +84,7 @@ curl -fsSL https://opencode.ai/install | bash
|
||||
- **Arch Linux에서 Paru 사용**
|
||||
|
||||
```bash
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
@@ -84,8 +84,7 @@ Du kan også installere den med følgende kommandoer:
|
||||
- **Bruke Paru på Arch Linux**
|
||||
|
||||
```bash
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
@@ -84,8 +84,7 @@ Możesz też użyć poniższych metod instalacji:
|
||||
- **Korzystanie z Paru na Arch Linux**
|
||||
|
||||
```bash
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
@@ -84,8 +84,7 @@ Você também pode instalá-lo com os seguintes comandos:
|
||||
- **Usando Paru no Arch Linux**
|
||||
|
||||
```bash
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
@@ -84,8 +84,7 @@ curl -fsSL https://opencode.ai/install | bash
|
||||
- **Использование Paru в Arch Linux**
|
||||
|
||||
```bash
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
@@ -84,8 +84,7 @@ curl -fsSL https://opencode.ai/install | bash
|
||||
- **ใช้ Paru บน Arch Linux**
|
||||
|
||||
```bash
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
@@ -84,8 +84,7 @@ Ayrıca aşağıdaki komutlarla da yükleyebilirsiniz:
|
||||
- **Paru'yu Arch Linux'ta kullanma**
|
||||
|
||||
```bash
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
@@ -84,8 +84,7 @@ curl -fsSL https://opencode.ai/install | bash
|
||||
- **在 Arch Linux 上使用 Paru**
|
||||
|
||||
```bash
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
@@ -169,7 +169,7 @@ opencode自动处理远程MCP服务器的OAuth身份验证。当服务器需要
|
||||
|
||||
1. 检测 401 响应并启动 OAuth 流程
|
||||
2. 如果服务器支持,请使用**动态客户端注册 (RFC 7591)**
|
||||
3. 安全地存储Tokens以供将来的请求
|
||||
3. 安全地存儲Tokens以供将來的请求
|
||||
|
||||
---
|
||||
|
||||
@@ -189,7 +189,7 @@ opencode自动处理远程MCP服务器的OAuth身份验证。当服务器需要
|
||||
}
|
||||
```
|
||||
|
||||
如果服务器需要身份验证,opencode 将在您第一次尝试使用它时提示您进行身份验证。如果没有,您可以使用 `timeout`[手动触发流量](#authenticating)。
|
||||
如果服務器需要身份验证,opencode 将在您第一次嘗試使用它時提示您进行身份验证。如果沒有,您可以使用 `timeout`[手动觸發流量](#authenticating)。
|
||||
|
||||
---
|
||||
|
||||
@@ -218,7 +218,7 @@ opencode自动处理远程MCP服务器的OAuth身份验证。当服务器需要
|
||||
|
||||
### 身份验证
|
||||
|
||||
您可以手动触发身份验证或管理凭据。
|
||||
您可以手动觸發身份验证或管理憑據。
|
||||
|
||||
使用特定MCP服务器进行身份验证:
|
||||
|
||||
@@ -232,7 +232,7 @@ opencode mcp auth my-oauth-server
|
||||
opencode mcp list
|
||||
```
|
||||
|
||||
删除存储的凭据:
|
||||
删除存儲的憑據:
|
||||
|
||||
```bash
|
||||
opencode mcp logout my-oauth-server
|
||||
@@ -297,7 +297,7 @@ opencode mcp debug my-oauth-server
|
||||
|
||||
### 全局
|
||||
|
||||
这意味著您可以全局启用或禁用它们。
|
||||
这意味著您可以全局启用或禁用它們。
|
||||
|
||||
```json title="opencode.json" {14}
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ opencode 使用 [AI SDK](https://ai-sdk.dev/) 和 [Models.dev](https://models.de
|
||||
|
||||
## 选择模型
|
||||
|
||||
配置完提供商后,您可以通过输入以下内容来选择您想要的模型:
|
||||
配置完提供商後,您可以通过輸入以下內容來选择您想要的模型:
|
||||
|
||||
```bash frame="none"
|
||||
/models
|
||||
@@ -27,29 +27,29 @@ opencode 使用 [AI SDK](https://ai-sdk.dev/) 和 [Models.dev](https://models.de
|
||||
|
||||
## 推荐模型
|
||||
|
||||
那里有很多模型,每周都会有新模型问世。
|
||||
那裡有很多模型,每週都会有新模型問世。
|
||||
|
||||
:::tip
|
||||
考虑使用我们推荐的模型之一。
|
||||
考慮使用我们推薦的模型之一。
|
||||
:::
|
||||
|
||||
然而,既擅长生成代码又擅长工具调用的只有少数。
|
||||
然而,既擅長生成代碼又擅長工具调用的只有少數。
|
||||
|
||||
以下是与 opencode 配合良好的几个模型,排名不分前面。(这不是好看的列表,也不一定是最新的):
|
||||
|
||||
- GPT 5.2
|
||||
- GPT 5.1 Codex
|
||||
- Claude Opus 4.5
|
||||
- Claude Sonnet 4.5
|
||||
- Minimax M2.1
|
||||
- Gemini 3 Pro
|
||||
- GPT 5.1 法典
|
||||
- 近距離工作4.5
|
||||
- 克勞德十四行詩 4.5
|
||||
- 极小极M2.1
|
||||
- 雙子座 3 专業版
|
||||
|
||||
---
|
||||
|
||||
## 设置默认值
|
||||
|
||||
要将其中之一设置为默认模型,您可以在您的
|
||||
打开代码配置。
|
||||
要将其中之一设置为默認模型,您可以在您的
|
||||
打開代碼配置。
|
||||
|
||||
```json title="opencode.json" {3}
|
||||
{
|
||||
@@ -143,14 +143,14 @@ opencode 使用 [AI SDK](https://ai-sdk.dev/) 和 [Models.dev](https://models.de
|
||||
|
||||
opencode 附带了许多重大的默认变体:
|
||||
|
||||
**Anthropic**:
|
||||
**人擇**:
|
||||
|
||||
- `high` - 高思维预算(默认)
|
||||
- `max` - 最大预算规划
|
||||
|
||||
**OpenAI**:
|
||||
|
||||
因模型而异,但大致如下:
|
||||
因模型而異,但大致如下:
|
||||
|
||||
- `none` - 没有推理
|
||||
- `minimal` - 最少的推理工作
|
||||
@@ -159,18 +159,18 @@ opencode 附带了许多重大的默认变体:
|
||||
- `high` - 高推理能力
|
||||
- `xhigh` - 极高的推理能力
|
||||
|
||||
**Google**:
|
||||
**谷歌**:
|
||||
|
||||
- `low` - 降低工作量/Tokens预算
|
||||
- `high` - 更高的努力/Tokens预算
|
||||
- `low` - 降低工作量/Tokens預算
|
||||
- `high` - 更高的努力/Tokens預算
|
||||
|
||||
:::tip
|
||||
该列表并不全面。许多其他提供商也有内置的默认值。
|
||||
该列表并不全面。許多其他提供商也有内置的默認值。
|
||||
:::
|
||||
|
||||
### 自定义变体
|
||||
|
||||
您可以覆盖现有变体或添加您自己的变体:
|
||||
您可以覆盖現有變體或添加您自己的變體:
|
||||
|
||||
```jsonc title="opencode.jsonc" {7-18}
|
||||
{
|
||||
@@ -195,7 +195,7 @@ opencode 附带了许多重大的默认变体:
|
||||
}
|
||||
```
|
||||
|
||||
### 切换变体
|
||||
### 循环变体
|
||||
|
||||
使用按键绑定`variant_cycle`在变体之间快速切换。 [了解更多](/docs/keybinds)。
|
||||
|
||||
@@ -220,4 +220,4 @@ opencode 附带了许多重大的默认变体:
|
||||
|
||||
3. 最后使用的模型。
|
||||
|
||||
4. 第一个模型使用内部优先级。
|
||||
4. 第一个模型使用内部优先級。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: 模式
|
||||
description: 不同的模式适用于不同的用例。
|
||||
description: 不同的模式適用于不同的用例。
|
||||
---
|
||||
|
||||
:::caution
|
||||
@@ -13,7 +13,7 @@ opencode 中的模式允许自定义不同的示例行为、工具和提示。
|
||||
它具有两种内置模式:**构建**和**计划**。您可以定制
|
||||
这些或通过 opencode 配置配置您自己的。
|
||||
|
||||
您可以在会话期间在模式之间切换或在配置文件中配置它们。
|
||||
您可以在会话期間在模式之間切換或在配置文件中配置它們。
|
||||
|
||||
---
|
||||
|
||||
@@ -25,13 +25,13 @@ opencode 有两种内置模式。
|
||||
|
||||
### 构建
|
||||
|
||||
构建是启用所有工具的**默认**模式。这是开发工作的标准模式,您需要完全访问文件操作和系统命令。
|
||||
構建是启用所有工具的**默認**模式。这是開發工作的標準模式,您需要完全访问文件操作和系統命令。
|
||||
|
||||
---
|
||||
|
||||
### 计划
|
||||
|
||||
专为规划和分析而设计的受限模式。在计划模式下,默认情况下禁用以下工具:
|
||||
专为規劃和分析而設計的受限模式。在計劃模式下,默認情况下禁用以下工具:
|
||||
|
||||
- `write` - 无法创建新文件
|
||||
- `edit` - 无法修改现有文件,位于 `.opencode/plans/*.md` 的用于详细说明计划本身的文件另外
|
||||
@@ -52,7 +52,7 @@ opencode 有两种内置模式。
|
||||
|
||||
## 配置
|
||||
|
||||
您可以自定义内置模式或通过配置创建自己的模式。可以通过两种方式配置模式:
|
||||
您可以自定義内置模式或通过配置创建自己的模式。可以通过两种方式配置模式:
|
||||
|
||||
### JSON 配置
|
||||
|
||||
@@ -112,7 +112,7 @@ Provide constructive feedback without making direct changes.
|
||||
|
||||
Markdown 文件名成为模式名称(例如,`review.md` 创建`review` 模式)。
|
||||
|
||||
让我们详细看看这些配置选项。
|
||||
讓我们詳細看看这些配置選項。
|
||||
|
||||
---
|
||||
|
||||
@@ -191,7 +191,7 @@ Markdown 文件名成为模式名称(例如,`review.md` 创建`review` 模
|
||||
}
|
||||
```
|
||||
|
||||
该路径是相对于配置文件所在位置的。所以这适用于
|
||||
该路徑是相对于配置文件所在位置的。所以这適用于
|
||||
全局opencode配置和项目特定配置。
|
||||
|
||||
---
|
||||
@@ -217,13 +217,13 @@ Markdown 文件名成为模式名称(例如,`review.md` 创建`review` 模
|
||||
}
|
||||
```
|
||||
|
||||
如果未指定任何工具,则默认启用所有工具。
|
||||
如果未指定任何工具,则默認启用所有工具。
|
||||
|
||||
---
|
||||
|
||||
#### 可用工具
|
||||
|
||||
这里是所有可以通过模式配置控制的工具。
|
||||
这裡是所有可以通过模式配置控制的工具。
|
||||
|
||||
| 工具 | 描述 |
|
||||
| ----------- | ---------------- |
|
||||
@@ -243,7 +243,7 @@ Markdown 文件名成为模式名称(例如,`review.md` 创建`review` 模
|
||||
|
||||
## 自定义模式
|
||||
|
||||
您可以通过将自定义模式添加到配置来创建自己的自定义模式。以下是使用这两种方法的示例:
|
||||
您可以通过将自定義模式添加到配置來创建自己的自定義模式。以下是使用这两种方法的示例:
|
||||
|
||||
### 使用 JSON 配置
|
||||
|
||||
@@ -320,12 +320,12 @@ Priorities:
|
||||
|
||||
### 使用案例
|
||||
|
||||
以下是不同模式的一些常见用例。
|
||||
以下是不同模式的一些常見用例。
|
||||
|
||||
- **构建模式**:启用所有工具的完整开发工作
|
||||
- **计划模式**:分析和计划,无需更改
|
||||
- **审阅模式**:使用只读访问权限和文档工具进行代码审阅
|
||||
- **构建模式**:启用所有工具的完整開發工作
|
||||
- **计划模式**:分析和計劃,無需更改
|
||||
- **审阅模式**:使用只讀访问权限和文档工具進行代碼审阅
|
||||
- **调试模式**:专注于启用bash和读取工具的调查
|
||||
- **文档模式**:使用文件操作但不使用系统命令的文档编写
|
||||
- **文档模式**:使用文件操作但不使用系統命令的文档編寫
|
||||
|
||||
您可能还会发现不同的模型适用于不同的用例。
|
||||
您可能还会發現不同的模型適用于不同的用例。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: 网络
|
||||
description: 配置代理和自定义证书。
|
||||
description: 配置代理和自定義證書。
|
||||
---
|
||||
|
||||
opencode支持企业网络环境的标准代理环境变量和自定义证书。
|
||||
@@ -9,7 +9,7 @@ opencode支持企业网络环境的标准代理环境变量和自定义证书。
|
||||
|
||||
## 代理
|
||||
|
||||
opencode 遵循标准代理环境变量。
|
||||
opencode 尊重标准代理环境变量。
|
||||
|
||||
```bash
|
||||
# HTTPS proxy (recommended)
|
||||
@@ -39,7 +39,7 @@ export HTTPS_PROXY=http://username:password@proxy.example.com:8080
|
||||
```
|
||||
|
||||
:::caution
|
||||
避免对密码进行硬编码。使用环境变量或安全凭证存储。
|
||||
避免对密碼進行硬編碼。使用環境變量或安全憑證存儲。
|
||||
:::
|
||||
|
||||
对于需要高级身份验证(例如 NTLM 或 Kerberos)的代理,请考虑使用支持您的身份验证方法的 LLM 网关。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: 权限
|
||||
description: 控制哪些操作需要批准才能运行。
|
||||
description: 控制哪些操作需要批准才能運行。
|
||||
---
|
||||
|
||||
opencode 使用`permission` 配置来决定给定的操作是否应自动运行、提示您或被阻止。
|
||||
@@ -47,7 +47,7 @@ opencode 使用`permission` 配置来决定给定的操作是否应自动运行
|
||||
|
||||
## 粒度规则(对象语法)
|
||||
|
||||
对于大多数权限,您可以使用对象根据工具输入应用不同的操作。
|
||||
对于大多數权限,您可以使用对像根據工具輸入应用不同的操作。
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -68,11 +68,11 @@ opencode 使用`permission` 配置来决定给定的操作是否应自动运行
|
||||
}
|
||||
```
|
||||
|
||||
规则通过模式匹配进行评估,**最后匹配的规则获胜**。常见的模式是将包罗万象的 `"*"` 规则放在前面,然后再放置更具体的规则。
|
||||
规则通过模式匹配進行評估,**最后匹配的规则獲勝**。常見的模式是将包羅万象的 `"*"` 规则放在前面,然後再放置更具體的规则。
|
||||
|
||||
### 通配符
|
||||
|
||||
权限模式使用简单的通配符匹配:
|
||||
权限模式使用簡單的通配符匹配:
|
||||
|
||||
- `*` 匹配零个或多个任意字符
|
||||
- `?` 恰好匹配一个字符
|
||||
@@ -80,7 +80,7 @@ opencode 使用`permission` 配置来决定给定的操作是否应自动运行
|
||||
|
||||
### 主目录扩展
|
||||
|
||||
您可以在模式目录中使用 `~` 或 `$HOME` 来引用您的主目录。这对于 [`外部目录`](#external_directory) 规则特别有用。
|
||||
您可以在模式目录中使用 `~` 或 `$HOME` 来引用您的主目录。这对于 [`external_directory`](#external-directories) 规则特别有用。
|
||||
|
||||
- `~/projects/*` -> `/Users/username/projects/*`
|
||||
- `$HOME/projects/*` -> `/Users/username/projects/*`
|
||||
@@ -133,14 +133,14 @@ opencode权限由工具名称和一些安全防护措施决定:
|
||||
- `edit` — 所有文件修改(头部`edit`、`write`、`patch`、`multiedit`)
|
||||
- `glob` — 文件通配符(匹配通配符模式)
|
||||
- `grep` — 内容搜索(匹配正则表达式模式)
|
||||
- `list` — 列出目录中的文件(与目录路径匹配)
|
||||
- `list` — 上市目录中的文件(与目录路径匹配)
|
||||
- `bash` — 运行 shell 命令(匹配 `git status --porcelain` 等解析命令)
|
||||
- `task` — 启动子代理(与子代理类型匹配)
|
||||
- `skill` — 加载技能(与技能名称匹配)
|
||||
- `lsp` — 运行 LSP 查询(当前非粒度)
|
||||
- `todoread`、`todowrite` — 读取/更新待办事项列表
|
||||
- `todoread`、`todowrite` — 讀取/更新待辦事項列表
|
||||
- `webfetch` — 获取 URL(与 URL 匹配)
|
||||
- `websearch`、`codesearch` — 网页/代码搜索(与查询匹配)
|
||||
- `websearch`、`codesearch` — 網頁/代碼搜索(与查询匹配)
|
||||
- `external_directory` — 当工具访问项目工作目录外部的路径时触发
|
||||
- `doom_loop` — 当相同的工具调用相同的输入重复 3 次时触发
|
||||
|
||||
@@ -148,7 +148,7 @@ opencode权限由工具名称和一些安全防护措施决定:
|
||||
|
||||
## 默认值
|
||||
|
||||
如果您未指定任何内容,opencode将从宽松的默认值开始:
|
||||
如果您未指定任何内容,opencode分散许可的默认值开始:
|
||||
|
||||
- 大部分权限默认为`"allow"`。
|
||||
- `doom_loop`和`external_directory`默认为`"ask"`。
|
||||
@@ -171,7 +171,7 @@ opencode权限由工具名称和一些安全防护措施决定:
|
||||
|
||||
## “询问”的作用是什么
|
||||
|
||||
当 opencode 提示批准时,UI 会提供三种结果:
|
||||
当 opencode 提示批准时,UI 会提供清晰的结果:
|
||||
|
||||
- `once` — 仅批准此请求
|
||||
- `always` — 批准与建议模式匹配的未来请求(对于当前 opencode 会话的其余部分)
|
||||
|
||||
@@ -11,7 +11,7 @@ description: 编写您自己的插件来扩展 opencode。
|
||||
|
||||
## 使用插件
|
||||
|
||||
有两种加载插件的方法。
|
||||
有两种加載插件的方法。
|
||||
|
||||
---
|
||||
|
||||
@@ -22,7 +22,7 @@ description: 编写您自己的插件来扩展 opencode。
|
||||
- `.opencode/plugins/` - 项目级插件
|
||||
- `~/.config/opencode/plugins/` - 全局插件
|
||||
|
||||
这些目录中的文件会在启动时自动加载。
|
||||
这些目录中的文件会在启动時自动加載。
|
||||
|
||||
---
|
||||
|
||||
@@ -53,7 +53,7 @@ description: 编写您自己的插件来扩展 opencode。
|
||||
|
||||
### 加载顺序
|
||||
|
||||
插件从所有源加载,所有挂钩按顺序运行。加载顺序为:
|
||||
插件從所有源加載,所有掛鉤按顺序運行。加載顺序为:
|
||||
|
||||
1. 全局配置 (`~/.config/opencode/opencode.json`)
|
||||
2. 项目配置(`opencode.json`)
|
||||
@@ -67,7 +67,7 @@ description: 编写您自己的插件来扩展 opencode。
|
||||
## 创建一个插件
|
||||
|
||||
插件是一个 **JavaScript/TypeScript 模块多个**,它导出一个或插件
|
||||
功能。每个函数接收一个上下文对象并返回一个钩子对象。
|
||||
功能。每个函數接收一个上下文对象并返回一个鉤子对象。
|
||||
|
||||
---
|
||||
|
||||
@@ -113,7 +113,7 @@ export const MyPlugin = async ({ project, client, $, directory, worktree }) => {
|
||||
}
|
||||
```
|
||||
|
||||
插件函数接收:
|
||||
插件函數接收:
|
||||
|
||||
- `project`:当前项目信息。
|
||||
- `directory`:当前工作目录。
|
||||
@@ -141,7 +141,7 @@ export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree
|
||||
|
||||
### 事件
|
||||
|
||||
插件可以订阅事件,如下面的示例部分所示。以下是可用的不同事件的列表。
|
||||
插件可以訂閱事件,如下面的示例部分所示。以下是可用的不同事件的列表。
|
||||
|
||||
#### 命令事件
|
||||
|
||||
@@ -217,7 +217,7 @@ export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree
|
||||
|
||||
### 发送通知
|
||||
|
||||
当某些事件发生时发送通知:
|
||||
当某些事件發生時發送通知:
|
||||
|
||||
```js title=".opencode/plugins/notification.js"
|
||||
export const NotificationPlugin = async ({ project, client, $, directory, worktree }) => {
|
||||
@@ -306,7 +306,7 @@ export const CustomToolsPlugin: Plugin = async (ctx) => {
|
||||
- `args`:Zod 模式的工具参数
|
||||
- `execute`:调用工具时运行的函数
|
||||
|
||||
您的自定义工具将可与内置工具一起用于opencode。
|
||||
您的自定義工具将可与内置工具一起用于opencode。
|
||||
|
||||
---
|
||||
|
||||
@@ -333,7 +333,7 @@ export const MyPlugin = async ({ client }) => {
|
||||
|
||||
### 压缩钩子
|
||||
|
||||
自定义压缩会话时包含的上下文:
|
||||
自定義壓縮会话時包含的上下文:
|
||||
|
||||
```ts title=".opencode/plugins/compaction.ts"
|
||||
import type { Plugin } from "@opencode-ai/plugin"
|
||||
|
||||
@@ -85,7 +85,7 @@ OpenCode Zen 是opencode团队提供的模型列表,这些模型已被
|
||||
|
||||
## 目录
|
||||
|
||||
让我们详细了解一些提供商。如果您想将提供商添加到
|
||||
讓我们詳細瞭解一些提供商。如果您想将提供商添加到
|
||||
列表,请随时开启PR。
|
||||
|
||||
:::note
|
||||
@@ -156,7 +156,7 @@ OpenCode Zen 是opencode团队提供的模型列表,这些模型已被
|
||||
export AWS_REGION=us-east-1
|
||||
```
|
||||
|
||||
#### 配置文件(推荐)
|
||||
#### 配置文件(推薦)
|
||||
|
||||
For project-specific or persistent configuration, use `opencode.json`:
|
||||
|
||||
@@ -174,13 +174,13 @@ OpenCode Zen 是opencode团队提供的模型列表,这些模型已被
|
||||
}
|
||||
```
|
||||
|
||||
**可用选项:**
|
||||
**可用選項:**
|
||||
- `region` - AWS 区域(例如 `us-east-1`、`eu-west-1`)
|
||||
- `profile` - 来自 `~/.aws/credentials` 的 AWS 命名配置档案
|
||||
- `endpoint` - VPC 节点节点的自定义节点 URL(通用 `baseURL` 选项的别名)
|
||||
|
||||
:::提示
|
||||
配置文件选项优先于环境变量。
|
||||
配置文件選項优先于环境变量。
|
||||
:::
|
||||
|
||||
#### 高阶:VPC 端点
|
||||
@@ -206,13 +206,13 @@ OpenCode Zen 是opencode团队提供的模型列表,这些模型已被
|
||||
`endpoint` 选项是通用 `baseURL` 选项的别名,使用 AWS 术语特定。如果同时指定了 `endpoint` 和 `baseURL`,则 `endpoint` 优先。
|
||||
:::
|
||||
|
||||
#### 认证方式
|
||||
#### 認證方式
|
||||
- **`AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`**:创建IAM用户并在AWS控制台中生成访问金币。
|
||||
- **`AWS_PROFILE`**:使用 `~/.aws/credentials` 中的命名配置文件。首先配置 `aws configure --profile my-profile` 或 `aws sso login`
|
||||
- **`AWS_BEARER_TOKEN_BEDROCK`**:从 Amazon Bedrock 控制台生成长期 API 密钥
|
||||
- **`AWS_WEB_IDENTITY_TOKEN_FILE` / `AWS_ROLE_ARN`**:适用于 EKS IRSA(服务账户的 IAM 角色)或具有 OIDC 联合的其他 Kubernetes 环境。使用服务账户注释时,这些环境变量由 Kubernetes 自动注入。
|
||||
|
||||
#### 认证优先顺序
|
||||
#### 認證优先顺序
|
||||
|
||||
Amazon Bedrock 使用以下身份验证优先顺序:
|
||||
1. **不记名Tokens** - `AWS_BEARER_TOKEN_BEDROCK`环境变化数据或来自`/connect`Tokens的Tokens
|
||||
@@ -663,7 +663,7 @@ GitLab Duo 通过 GitLab 的人工代理提供具有本机工具呼叫功能的
|
||||
2. 单击**添加新Tokens**
|
||||
3. Name: `OpenCode`, Scopes: `api`
|
||||
4. 复制Tokens(以 `glpat-` 发起人)
|
||||
5. 在终端中输入
|
||||
5. 在终端中輸入
|
||||
|
||||
3. 执行 `/models` 命令查看可用模型。
|
||||
|
||||
@@ -834,7 +834,7 @@ Google Vertex AI 与 opencode 结合使用:
|
||||
2. 设置所需的环境变量:
|
||||
- `GOOGLE_CLOUD_PROJECT`:您的Google云专案ID
|
||||
- `VERTEX_LOCATION`(可选):Vertex AI的区域(默认为`global`)
|
||||
- 身份验证(选择一项):
|
||||
- 身份验证(选择一項):
|
||||
- `GOOGLE_APPLICATION_CREDENTIALS`:服务帐户 JSON 密钥文件的路径
|
||||
- 使用 gcloud CLI 进行身份验证:`gcloud auth application-default login`
|
||||
|
||||
@@ -903,7 +903,7 @@ The `global` region improves availability and reduces errors at no extra cost. U
|
||||
/connect
|
||||
```
|
||||
|
||||
3. 输入您的 Hugging Face API 密钥。
|
||||
3. 輸入您的擁抱臉標記。
|
||||
|
||||
```txt
|
||||
┌ API key
|
||||
@@ -949,7 +949,7 @@ The `global` region improves availability and reduces errors at no extra cost. U
|
||||
|
||||
For more providers and advanced features like caching and rate limiting, check the [Helicone documentation](https://docs.helicone.ai).
|
||||
|
||||
#### 可选配置
|
||||
#### 可選配置
|
||||
|
||||
如果您发现Helicone的某些功能或模型未通过opencode自动配置,您始终可以自行配置。
|
||||
|
||||
@@ -979,7 +979,7 @@ Here's [Helicone's Model Directory](https://helicone.ai/models), you'll need thi
|
||||
}
|
||||
```
|
||||
|
||||
#### 自定义标头
|
||||
#### 自定義標頭
|
||||
|
||||
Helicone 支持快速获取、用户跟踪和会话管理等功能的自定义标头。使用 `options.headers` 将它们添加到您提供的方案配置中:
|
||||
|
||||
@@ -1002,7 +1002,7 @@ Helicone 支持快速获取、用户跟踪和会话管理等功能的自定义
|
||||
}
|
||||
```
|
||||
|
||||
##### 会话跟踪
|
||||
##### 会话跟蹤
|
||||
|
||||
Helicone's [Sessions](https://docs.helicone.ai/features/sessions) feature lets you group related LLM requests together. Use the [opencode-helicone-session](https://github.com/H2Shami/opencode-helicone-session) plugin to automatically log each opencode conversation as a session in Helicone.
|
||||
|
||||
@@ -1022,7 +1022,7 @@ npm install -g opencode-helicone-session
|
||||
|
||||
##### 常见螺旋接头
|
||||
|
||||
| 标题 | 描述 |
|
||||
| 標題 | 描述 |
|
||||
| -------------------------- | ----------------------------------------------------- |
|
||||
| `Helicone-Cache-Enabled` | Enable response caching (`true`/`false`) |
|
||||
| `Helicone-User-Id` | 点击用户跟踪指标 |
|
||||
@@ -1635,9 +1635,9 @@ Vercel AI Gateway 可以让您跨统一端点访问来自 OpenAI、Anthropic、G
|
||||
}
|
||||
```
|
||||
|
||||
一些有用的路由选项:
|
||||
一些有用的路由選項:
|
||||
|
||||
| 选项 | 描述 |
|
||||
| 選項 | 描述 |
|
||||
| ------------------- | ---------------------- |
|
||||
| `order` | 提供商尝试顺序 |
|
||||
| `only` | 限制特定提供商 |
|
||||
@@ -1816,7 +1816,7 @@ Vercel AI Gateway 可以让您跨统一端点访问来自 OpenAI、Anthropic、G
|
||||
}
|
||||
```
|
||||
|
||||
以下是配置选项:
|
||||
以下是配置選項:
|
||||
- **npm**:要使用AI的SDK包,`@ai-sdk/openai-compatible`用于OpenAI兼容的事业
|
||||
- **名称**:UI中的显示名称。
|
||||
- **模型**:可用模型。
|
||||
@@ -1824,7 +1824,7 @@ Vercel AI Gateway 可以让您跨统一端点访问来自 OpenAI、Anthropic、G
|
||||
- **options.apiKey**:如果不使用身份验证,可以选择设置API 密钥。
|
||||
- **options.headers**:可选择设置自定义标头。
|
||||
|
||||
有关高阶选项的更多资讯,请参见下面的示例。
|
||||
有關高階選項的更多資訊,请參見下面的示例。
|
||||
|
||||
5. 执行 `/models` 命令,您提供的自定义程序和模型将出现在选择列表中。
|
||||
|
||||
@@ -1875,7 +1875,7 @@ Vercel AI Gateway 可以让您跨统一端点访问来自 OpenAI、Anthropic、G
|
||||
|
||||
## 故障排除
|
||||
|
||||
如果您在配置提供商时遇到问题,请检查以下内容:
|
||||
如果您在配置提供商時遇到問題,请检查以下內容:
|
||||
|
||||
1. **Check the auth setup**: Run `opencode auth list` to see if the credentials
|
||||
提供商的配置已添加到您的配置中。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: 规则
|
||||
description: 设置opencode的自定义指令。
|
||||
description: 设置opencode的自定義指令。
|
||||
---
|
||||
|
||||
您可以通过 `AGENTS.md` 文件创建 opencode 的自定义指令。这和 Cursor 的规则类似。它包含将包含在 LLM 上下文中的说明,方便您的特定项目自定义其行为。
|
||||
@@ -48,7 +48,7 @@ This is an SST v3 monorepo with TypeScript. The project uses bun workspaces for
|
||||
- Import shared modules using workspace names: `@my-app/core/example`
|
||||
```
|
||||
|
||||
我们在此处添加特定于项目的说明,这将在您的团队中共享。
|
||||
我们在此處添加特定于項目的說明,这将在您的團隊中共享。
|
||||
|
||||
---
|
||||
|
||||
@@ -66,7 +66,7 @@ opencode 还支持从多个位置读取 `AGENTS.md` 文件。这有不同的目
|
||||
|
||||
由于此未提交给 Git 或与您的团队共享,因此我们建议使用它来指定 LLM 应遵循的任何个人规则。
|
||||
|
||||
### 克劳德代码兼容性
|
||||
### 克勞德代碼兼容性
|
||||
|
||||
Error 500 (Server Error)!!1500.That’s an error.There was an error. Please try again later.That’s all we know.
|
||||
|
||||
@@ -118,7 +118,7 @@ export OPENCODE_DISABLE_CLAUDE_CODE_SKILLS=1 # Disable only .claude/skills
|
||||
}
|
||||
```
|
||||
|
||||
远程指令的获取有 5 秒的超时时间。
|
||||
遠程指令的获取有 5 秒的超時時間。
|
||||
|
||||
所有说明文件均与您的`AGENTS.md`文件合并。
|
||||
|
||||
@@ -168,9 +168,9 @@ For testing strategies and coverage requirements: @test/testing-guidelines.md
|
||||
Read the following file immediately as it's relevant to all workflows: @rules/general-guidelines.md.
|
||||
```
|
||||
|
||||
这种方法允许您:
|
||||
这種方法允许您:
|
||||
|
||||
- 创建模块化、可重用的规则文件
|
||||
- 创建模塊化、可重用的规则文件
|
||||
- 通过符号链接或git子模块在项目之间共享规则
|
||||
- 保持 AGENTS.md 简洁,同时参考详细指南
|
||||
- 确保opencode仅在特定任务需要时加载文件
|
||||
|
||||
@@ -33,7 +33,7 @@ import { createOpencode } from "@opencode-ai/sdk"
|
||||
const { client } = await createOpencode()
|
||||
```
|
||||
|
||||
这会同时启动服务器和客户端
|
||||
这会同時启动服务器和客戶端
|
||||
|
||||
#### 选项
|
||||
|
||||
@@ -99,7 +99,7 @@ SDK 包括所有 API 型以外的 TypeScript 定义。直接汇入其中:
|
||||
import type { Session, Message, Part } from "@opencode-ai/sdk"
|
||||
```
|
||||
|
||||
所有型别均根据服务器的 OpenAPI 规范生成,并可在 <a href={typesUrl}> 型别文件 </a> 中找到。
|
||||
所有型別均根據服务器的 OpenAPI 規範生成,并可在 <a href={typesUrl}> 型別文件 </a> 中找到。
|
||||
|
||||
---
|
||||
|
||||
@@ -192,7 +192,7 @@ const currentProject = await client.project.current()
|
||||
|
||||
| 方法 | 描述 | 回应 |
|
||||
| ------------ | ------------ | ---------------------------------------- |
|
||||
| `path.get()` | 获取当前路径 | <a href={typesUrl}><code>路径</code></a> |
|
||||
| `path.get()` | 获取当前路徑 | <a href={typesUrl}><code>路徑</code></a> |
|
||||
|
||||
---
|
||||
|
||||
@@ -209,7 +209,7 @@ const pathInfo = await client.path.get()
|
||||
|
||||
| 方法 | 描述 | 回应 |
|
||||
| -------------------- | -------------------- | --------------------------------------------------------------------------------------------------- |
|
||||
| `config.get()` | 获取配置资讯 | <a href={typesUrl}><code>配置</code></a> |
|
||||
| `config.get()` | 获取配置資訊 | <a href={typesUrl}><code>配置</code></a> |
|
||||
| `config.providers()` | 列出提供商和默认模型 | `{ providers: `<a href={typesUrl}><code>提供商[]</code></a>`, default: { [key: string]: string } }` |
|
||||
|
||||
---
|
||||
@@ -226,14 +226,14 @@ const { providers, default: defaults } = await client.config.providers()
|
||||
|
||||
### 会话
|
||||
|
||||
| 方法 | 描述 | 备注 |
|
||||
| 方法 | 描述 | 筆記 |
|
||||
| ---------------------------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `session.list()` | 列出会话 | 返回 <a href={typesUrl}><code>Session[]</code></a> |
|
||||
| `session.get({ path })` | 获取会话 | 返回 <a href={typesUrl}><code>会话</code></a> |
|
||||
| `session.children({ path })` | 列出子会话 | 返回 <a href={typesUrl}><code>Session[]</code></a> |
|
||||
| `session.create({ body })` | 建立会话 | 返回 <a href={typesUrl}><code>会话</code></a> |
|
||||
| `session.delete({ path })` | 离开会话 | 返回`boolean` |
|
||||
| `session.update({ path, body })` | 更新会话属性 | 返回 <a href={typesUrl}><code>会话</code></a> |
|
||||
| `session.update({ path, body })` | 更新会话屬性 | 返回 <a href={typesUrl}><code>会话</code></a> |
|
||||
| `session.init({ path, body })` | Analyze app and create `AGENTS.md` | Returns `boolean` |
|
||||
| `session.abort({ path })` | 中止正在执行的会话 | 返回`boolean` |
|
||||
| `session.share({ path })` | 分享会 | 返回 <a href={typesUrl}><code>会话</code></a> |
|
||||
@@ -241,7 +241,7 @@ const { providers, default: defaults } = await client.config.providers()
|
||||
| `session.summarize({ path, body })` | 会议总结 | 返回`boolean` |
|
||||
| `session.messages({ path })` | 列出会话中的消息 | 返回 `{ info: `<a href={typesUrl}><code>消息</code></a>`, parts: `<a href={typesUrl}><code>部分[]</code></a>`}[]` |
|
||||
| `session.message({ path })` | 获取消息详情 | 返回 `{ info: `<a href={typesUrl}><code>消息</code></a>`, parts: `<a href={typesUrl}><code>部分[]</code></a>`}` |
|
||||
| `session.prompt({ path, body })` | 发送提示资讯 | `body.noReply: true` 返回 UserMessage(仅限上下文)。默认返回 <a href={typesUrl}><code>AssistantMessage</code></a> 以及 AI 响应 |
|
||||
| `session.prompt({ path, body })` | 发送提示資訊 | `body.noReply: true` 返回 UserMessage(仅限上下文)。默认返回 <a href={typesUrl}><code>AssistantMessage</code></a> 以及 AI 響应 |
|
||||
| `session.command({ path, body })` | 向会话发送命令 | 返回 `{ info: `<a href={typesUrl}><code>AssistantMessage</code></a>`, parts: `<a href={typesUrl}><code>部分[]</code></a>`}` |
|
||||
| `session.shell({ path, body })` | 执行 shell 命令 | 返回 <a href={typesUrl}><code>AssistantMessage</code></a> |
|
||||
| `session.revert({ path, body })` | 回复消息 | 返回 <a href={typesUrl}><code>会话</code></a> |
|
||||
@@ -287,9 +287,9 @@ await client.session.prompt({
|
||||
| ------------------------- | -------------------- | ----------------------------------------------------------------------------------- |
|
||||
| `find.text({ query })` | 搜索档案中文字 | 具有 `path`、`lines`、`line_number`、`absolute_offset`、`submatches` 的匹配对象数组 |
|
||||
| `find.files({ query })` | 按名称查询档案和目录 | `string[]`(路径) |
|
||||
| `find.symbols({ query })` | 查询工作区符号 | <a href={typesUrl}><code>符号[]</code></a> |
|
||||
| `find.symbols({ query })` | 查询工作区符號 | <a href={typesUrl}><code>符號[]</code></a> |
|
||||
| `file.read({ query })` | 读取档案 | `{ type: "raw" \| "patch", content: string }` |
|
||||
| `file.status({ query? })` | 获取跟踪文件的状态 | <a href={typesUrl}><code>文件[]</code></a> |
|
||||
| `file.status({ query? })` | 获取跟蹤文件的狀態 | <a href={typesUrl}><code>文件[]</code></a> |
|
||||
|
||||
`find.files` 支持一些可选的查询栏位:
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ OPENCODE_SERVER_PASSWORD=your-password opencode serve
|
||||
|
||||
---
|
||||
|
||||
### 它是如何运作的
|
||||
### 它是如何運作的
|
||||
|
||||
When you run `opencode` it starts a TUI and a server. Where the TUI is the
|
||||
与服务器器对话的客户端。服务器器公开 OpenAPI 3.1 规范
|
||||
@@ -61,7 +61,7 @@ opencode TUI running, `opencode serve` will start a new server.
|
||||
|
||||
---
|
||||
|
||||
#### 连接到现有服务器
|
||||
#### 连接到現有服务器
|
||||
|
||||
当您启动 TUI 时,它会随机分配端口和主机名。您可以重新设置 `--hostname` 和 `--port` [flags](/docs/cli)。使用它连线到其服务器然后器。
|
||||
|
||||
@@ -69,7 +69,7 @@ opencode TUI running, `opencode serve` will start a new server.
|
||||
|
||||
---
|
||||
|
||||
## 规格
|
||||
## 規格
|
||||
|
||||
服务器发布了OpenAPI 3.1规范,可以在以下位置查看:
|
||||
|
||||
@@ -89,7 +89,7 @@ opencode服务器公开以下API。
|
||||
|
||||
### 全局
|
||||
|
||||
| 方法 | 路径 | 描述 | 回应 |
|
||||
| 方法 | 路徑 | 描述 | 回应 |
|
||||
| ----- | ---------------- | ------------------------ | ------------------------------------ |
|
||||
| `GET` | `/global/health` | 获取服务器运行状况和版本 | `{ healthy: true, version: string }` |
|
||||
| `GET` | `/global/event` | 获取全域性事件(SSE 流) | 事件流 |
|
||||
@@ -98,7 +98,7 @@ opencode服务器公开以下API。
|
||||
|
||||
### 项目
|
||||
|
||||
| 方法 | 路径 | 描述 | 回应 |
|
||||
| 方法 | 路徑 | 描述 | 回应 |
|
||||
| ----- | ------------------ | ------------ | ------------------------------------------ |
|
||||
| `GET` | `/project` | 列出所有专案 | <a href={typesUrl}><code>专案[]</code></a> |
|
||||
| `GET` | `/project/current` | 获取当前专案 | <a href={typesUrl}><code>专案</code></a> |
|
||||
@@ -107,16 +107,16 @@ opencode服务器公开以下API。
|
||||
|
||||
### 路径和VCS
|
||||
|
||||
| 方法 | 路径 | 描述 | 回应 |
|
||||
| 方法 | 路徑 | 描述 | 回应 |
|
||||
| ----- | ------- | ----------------------- | ------------------------------------------- |
|
||||
| `GET` | `/path` | 获取当前路径 | <a href={typesUrl}><code>路径</code></a> |
|
||||
| `GET` | `/vcs` | 获取当前专案的 VCS 资讯 | <a href={typesUrl}><code>VcsInfo</code></a> |
|
||||
| `GET` | `/path` | 获取当前路徑 | <a href={typesUrl}><code>路徑</code></a> |
|
||||
| `GET` | `/vcs` | 获取当前专案的 VCS 資訊 | <a href={typesUrl}><code>VcsInfo</code></a> |
|
||||
|
||||
---
|
||||
|
||||
### 例项
|
||||
### 例項
|
||||
|
||||
| 方法 | 路径 | 描述 | 回应 |
|
||||
| 方法 | 路徑 | 描述 | 回应 |
|
||||
| ------ | ------------------- | -------------- | --------- |
|
||||
| `POST` | `/instance/dispose` | 执行当前实例项 | `boolean` |
|
||||
|
||||
@@ -124,9 +124,9 @@ opencode服务器公开以下API。
|
||||
|
||||
### 配置
|
||||
|
||||
| 方法 | 路径 | 描述 | 回应 |
|
||||
| 方法 | 路徑 | 描述 | 回应 |
|
||||
| ------- | ------------------- | -------------------- | -------------------------------------------------------------------------------------- |
|
||||
| `GET` | `/config` | 获取配置资讯 | <a href={typesUrl}><code>配置</code></a> |
|
||||
| `GET` | `/config` | 获取配置資訊 | <a href={typesUrl}><code>配置</code></a> |
|
||||
| `PATCH` | `/config` | 更新配置 | <a href={typesUrl}><code>配置</code></a> |
|
||||
| `GET` | `/config/providers` | 列出提供商和默认模型 | `{ providers: `<a href={typesUrl}>提供商[]</a>`, default: { [key: string]: string } }` |
|
||||
|
||||
@@ -134,33 +134,33 @@ opencode服务器公开以下API。
|
||||
|
||||
### 提供商
|
||||
|
||||
| 方法 | 路径 | 描述 | 回应 |
|
||||
| 方法 | 路徑 | 描述 | 回应 |
|
||||
| ------ | -------------------------------- | ----------------------- | --------------------------------------------------------------------------------- |
|
||||
| `GET` | `/provider` | 列出所有提供商 | `{ all: `<a href={typesUrl}>提供商[]</a>`, default: {...}, connected: string[] }` |
|
||||
| `GET` | `/provider/auth` | 获取提供商身份验证方法 | `{ [providerID: string]: `<a href={typesUrl}>ProviderAuthMethod[]</a>` }` |
|
||||
| `POST` | `/provider/{id}/oauth/authorize` | 使用 OAuth 授权提供商 | <a href={typesUrl}><code>ProviderAuthAuthorization</code></a> |
|
||||
| `POST` | `/provider/{id}/oauth/authorize` | 使用 OAuth 授權提供商 | <a href={typesUrl}><code>ProviderAuthAuthorization</code></a> |
|
||||
| `POST` | `/provider/{id}/oauth/callback` | 处理提供商的 OAuth 回调 | `boolean` |
|
||||
|
||||
---
|
||||
|
||||
### 会话
|
||||
|
||||
| 方法 | 路径 | 描述 | 笔记 |
|
||||
| 方法 | 路徑 | 描述 | 筆記 |
|
||||
| -------- | ---------------------------------------- | ---------------------------------- | -------------------------------------------------------------------------------- |
|
||||
| `GET` | `/session` | 列出所有会话 | 返回 <a href={typesUrl}><code>Session[]</code></a> |
|
||||
| `POST` | `/session` | 建立新会话 | 正文: `{ parentID?, title? }`,返回 <a href={typesUrl}><code>Session</code></a> |
|
||||
| `GET` | `/session/status` | 获取所有会话的会话状态 | 返回 `{ [sessionID: string]: `<a href={typesUrl}>SessionStatus</a>` }` |
|
||||
| `GET` | `/session/status` | 获取所有会话的会话狀態 | 返回 `{ [sessionID: string]: `<a href={typesUrl}>SessionStatus</a>` }` |
|
||||
| `GET` | `/session/:id` | 获取会话详细信息 | 返回<a href={typesUrl}><code>会话</code></a> |
|
||||
| `DELETE` | `/session/:id` | 删除会话及所有资料 | 返回`boolean` |
|
||||
| `PATCH` | `/session/:id` | 更新会话属性 | 正文: `{ title? }`,返回 <a href={typesUrl}><code>Session</code></a> |
|
||||
| `PATCH` | `/session/:id` | 更新会话屬性 | 正文: `{ title? }`,返回 <a href={typesUrl}><code>Session</code></a> |
|
||||
| `GET` | `/session/:id/children` | 获取会话的子会话 | 返回 <a href={typesUrl}><code>Session[]</code></a> |
|
||||
| `GET` | `/session/:id/todo` | 获取会话的待办事项列表 | 返回 <a href={typesUrl}><code>Todo[]</code></a> |
|
||||
| `GET` | `/session/:id/todo` | 获取会话的待辦事項列表 | 返回 <a href={typesUrl}><code>Todo[]</code></a> |
|
||||
| `POST` | `/session/:id/init` | Analyze app and create `AGENTS.md` | body: `{ messageID, providerID, modelID }`, returns `boolean` |
|
||||
| `POST` | `/session/:id/fork` | 在消息中分叉现有会话 | 正文: `{ messageID? }`,返回 <a href={typesUrl}><code>Session</code></a> |
|
||||
| `POST` | `/session/:id/fork` | 在消息中分叉現有会话 | 正文: `{ messageID? }`,返回 <a href={typesUrl}><code>Session</code></a> |
|
||||
| `POST` | `/session/:id/abort` | 中止正在执行的会话 | 返回`boolean` |
|
||||
| `POST` | `/session/:id/share` | 分享会话 | 返回<a href={typesUrl}><code>会话</code></a> |
|
||||
| `DELETE` | `/session/:id/share` | 取消共享会话 | 返回<a href={typesUrl}><code>会话</code></a> |
|
||||
| `GET` | `/session/:id/diff` | 获取本次会话的差异 | 查询:`messageID?`,返回 <a href={typesUrl}><code>FileDiff[]</code></a> |
|
||||
| `GET` | `/session/:id/diff` | 获取本次会话的差異 | 查询:`messageID?`,返回 <a href={typesUrl}><code>FileDiff[]</code></a> |
|
||||
| `POST` | `/session/:id/summarize` | 会议总结 | 正文:`{ providerID, modelID }`,返回 `boolean` |
|
||||
| `POST` | `/session/:id/revert` | 回复讯息 | 正文:`{ messageID, partID? }`,返回 `boolean` |
|
||||
| `POST` | `/session/:id/unrevert` | 恢复所有已恢复的消息 | 返回`boolean` |
|
||||
@@ -170,20 +170,20 @@ opencode服务器公开以下API。
|
||||
|
||||
### 留言
|
||||
|
||||
| 方法 | 路径 | 描述 | 笔记 |
|
||||
| 方法 | 路徑 | 描述 | 筆記 |
|
||||
| ------ | --------------------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `GET` | `/session/:id/message` | 列出会话中的消息 | 查询: `limit?`,返回 `{ info: `<a href={typesUrl}>消息</a>`, parts: `<a href={typesUrl}>Part[]</a>`}[]` |
|
||||
| `POST` | `/session/:id/message` | 发送消息并等待回复 | 正文: `{ messageID?, model?, agent?, noReply?, system?, tools?, parts }`,返回 `{ info: `<a href={typesUrl}>消息</a>`, parts: `<a href={typesUrl}>部分[]</a>`}` |
|
||||
| `GET` | `/session/:id/message/:messageID` | 获取消息详情 | 返回 `{ info: `<a href={typesUrl}>消息</a>`, parts: `<a href={typesUrl}>部分[]</a>`}` |
|
||||
| `POST` | `/session/:id/prompt_async` | 非同步传送消息(休眠等待) | 主体:与 `/session/:id/message` 相同,返回 `204 No Content` |
|
||||
| `POST` | `/session/:id/command` | 执行斜杠命令 | 正文: `{ messageID?, agent?, model?, command, arguments }`,返回 `{ info: `<a href={typesUrl}>消息</a>`, parts: `<a href={typesUrl}>部分[]</a>`}` |
|
||||
| `POST` | `/session/:id/command` | 执行斜槓命令 | 正文: `{ messageID?, agent?, model?, command, arguments }`,返回 `{ info: `<a href={typesUrl}>消息</a>`, parts: `<a href={typesUrl}>部分[]</a>`}` |
|
||||
| `POST` | `/session/:id/shell` | 执行 shell 命令 | 正文: `{ agent, model?, command }`,返回 `{ info: `<a href={typesUrl}>消息</a>`, parts: `<a href={typesUrl}>部分[]</a>`}` |
|
||||
|
||||
---
|
||||
|
||||
### 命令
|
||||
|
||||
| 方法 | 路径 | 描述 | 回应 |
|
||||
| 方法 | 路徑 | 描述 | 回应 |
|
||||
| ----- | ---------- | ------------ | ------------------------------------------ |
|
||||
| `GET` | `/command` | 列出所有命令 | <a href={typesUrl}><code>命令[]</code></a> |
|
||||
|
||||
@@ -191,14 +191,14 @@ opencode服务器公开以下API。
|
||||
|
||||
### 文件
|
||||
|
||||
| 方法 | 路径 | 描述 | 回应 |
|
||||
| 方法 | 路徑 | 描述 | 回应 |
|
||||
| ----- | ------------------------ | -------------------- | ----------------------------------------------------------------------------------- |
|
||||
| `GET` | `/find?pattern=<pat>` | 搜索文件中的文字 | 具有 `path`、`lines`、`line_number`、`absolute_offset`、`submatches` 的匹配对像数组 |
|
||||
| `GET` | `/find/file?query=<q>` | 按名称查询文件和目录 | `string[]`(路径) |
|
||||
| `GET` | `/find/symbol?query=<q>` | 查询工作区符号 | <a href={typesUrl}><code>符号[]</code></a> |
|
||||
| `GET` | `/find/file?query=<q>` | 按名称查询文件和目录 | `string[]`(路徑) |
|
||||
| `GET` | `/find/symbol?query=<q>` | 查询工作区符號 | <a href={typesUrl}><code>符號[]</code></a> |
|
||||
| `GET` | `/file?path=<path>` | 列出文件和目录 | <a href={typesUrl}><code>FileNode[]</code></a> |
|
||||
| `GET` | `/file/content?path=<p>` | 读取文件 | <a href={typesUrl}><code>文件内容</code></a> |
|
||||
| `GET` | `/file/status` | 获取跟踪文件的状态 | <a href={typesUrl}><code>文件[]</code></a> |
|
||||
| `GET` | `/file/content?path=<p>` | 讀取文件 | <a href={typesUrl}><code>文件內容</code></a> |
|
||||
| `GET` | `/file/status` | 获取跟蹤文件的狀態 | <a href={typesUrl}><code>文件[]</code></a> |
|
||||
|
||||
#### `/find/file` 查询参数
|
||||
|
||||
@@ -210,9 +210,9 @@ opencode服务器公开以下API。
|
||||
|
||||
---
|
||||
|
||||
### 工具(实验)
|
||||
### 工具(實驗)
|
||||
|
||||
| 方法 | 路径 | 描述 | 回应 |
|
||||
| 方法 | 路徑 | 描述 | 回应 |
|
||||
| ----- | ------------------------------------------- | ---------------------------- | -------------------------------------------- |
|
||||
| `GET` | `/experimental/tool/ids` | 列出所有工具 ID | <a href={typesUrl}><code>工具ID</code></a> |
|
||||
| `GET` | `/experimental/tool?provider=<p>&model=<m>` | 列出具有模型 JSON 模式的工具 | <a href={typesUrl}><code>工具列表</code></a> |
|
||||
@@ -221,18 +221,18 @@ opencode服务器公开以下API。
|
||||
|
||||
### LSP、格式化程式和 MCP
|
||||
|
||||
| 方法 | 路径 | 描述 | 回应 |
|
||||
| 方法 | 路徑 | 描述 | 回应 |
|
||||
| ------ | ------------ | ------------------- | ------------------------------------------------------ |
|
||||
| `GET` | `/lsp` | 获取 LSP 服务器状态 | <a href={typesUrl}><code>LSPStatus[]</code></a> |
|
||||
| `GET` | `/formatter` | 获取格式化程式状态 | <a href={typesUrl}><code>FormatterStatus[]</code></a> |
|
||||
| `GET` | `/mcp` | 获取 MCP 服务器状态 | `{ [name: string]: `<a href={typesUrl}>MCP状态</a>` }` |
|
||||
| `GET` | `/lsp` | 获取 LSP 服务器狀態 | <a href={typesUrl}><code>LSPStatus[]</code></a> |
|
||||
| `GET` | `/formatter` | 获取格式化程式狀態 | <a href={typesUrl}><code>FormatterStatus[]</code></a> |
|
||||
| `GET` | `/mcp` | 获取 MCP 服务器狀態 | `{ [name: string]: `<a href={typesUrl}>MCP狀態</a>` }` |
|
||||
| `POST` | `/mcp` | 动态添加 MCP 服务器 | 主体:`{ name, config }`,返回 MCP 状态对象 |
|
||||
|
||||
---
|
||||
|
||||
### 代理商
|
||||
|
||||
| 方法 | 路径 | 描述 | 回应 |
|
||||
| 方法 | 路徑 | 描述 | 回应 |
|
||||
| ----- | -------- | ------------------ | ------------------------------------------ |
|
||||
| `GET` | `/agent` | 列出所有可用的代理 | <a href={typesUrl}><code>代理[]</code></a> |
|
||||
|
||||
@@ -240,7 +240,7 @@ opencode服务器公开以下API。
|
||||
|
||||
### 日志
|
||||
|
||||
| 方法 | 路径 | 描述 | 回应 |
|
||||
| 方法 | 路徑 | 描述 | 回应 |
|
||||
| ------ | ------------------------------------------- | ------ | -------------------- |
|
||||
| `POST` | 身体:`{ service, level, message, extra? }` | `/log` | 写入日志。 `boolean` |
|
||||
|
||||
@@ -248,7 +248,7 @@ opencode服务器公开以下API。
|
||||
|
||||
### TUI
|
||||
|
||||
| 方法 | 路径 | 描述 | 回应 |
|
||||
| 方法 | 路徑 | 描述 | 回应 |
|
||||
| ------ | ----------------------- | ----------------------------------------- | ------------ |
|
||||
| `POST` | `/tui/append-prompt` | 将文字附加到提示 | `boolean` |
|
||||
| `POST` | `/tui/open-help` | 开启帮助对话方块 | `boolean` |
|
||||
@@ -266,7 +266,7 @@ opencode服务器公开以下API。
|
||||
|
||||
### 授权
|
||||
|
||||
| 方法 | 路径 | 描述 | 回应 |
|
||||
| 方法 | 路徑 | 描述 | 回应 |
|
||||
| ----- | ----------- | ------------------------------------------ | --------- |
|
||||
| `PUT` | `/auth/:id` | 设置身份验证凭据。正文必须与提供商架构匹配 | `boolean` |
|
||||
|
||||
@@ -274,7 +274,7 @@ opencode服务器公开以下API。
|
||||
|
||||
### 活动
|
||||
|
||||
| 方法 | 路径 | 描述 | 回应 |
|
||||
| 方法 | 路徑 | 描述 | 回应 |
|
||||
| ----- | -------- | ------------------------------------------------------------------- | ------------------ |
|
||||
| `GET` | `/event` | 服务器发送事件流。第一个事件是 `server.connected`,之后是总线事件。 | 服务器发送事件流。 |
|
||||
|
||||
@@ -282,6 +282,6 @@ opencode服务器公开以下API。
|
||||
|
||||
### 文档
|
||||
|
||||
| 方法 | 路径 | 描述 | 回应 |
|
||||
| 方法 | 路徑 | 描述 | 回应 |
|
||||
| ----- | ------ | --------------- | ------------------------- |
|
||||
| `GET` | `/doc` | 开启API 3.1规范 | 具有OpenAPI规范的HTML页面 |
|
||||
|
||||
@@ -6,24 +6,24 @@ description: 分享您的 opencode 对话。
|
||||
opencode 的共享功能允许您建立指向 opencode 对话的公共链接,以便您可以与蓝牙进行战斗或从其他人那里获得帮助。
|
||||
|
||||
:::note
|
||||
任何知道链接的人都可以公开访问共享对话。
|
||||
任何知道链接的人都可以公開访问共享对话。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## 它是如何运作的
|
||||
## 它是如何運作的
|
||||
|
||||
当您分享对话时,opencode:
|
||||
|
||||
1. 为您的会话建立唯一的公共 URL
|
||||
2. 将您的对话历史记录同步到我们的服务器
|
||||
2. 将您的对话歷史記錄同步到我们的服务器
|
||||
3. 通过可共享链接访问对话 — `opncd.ai/s/<share-id>`
|
||||
|
||||
---
|
||||
|
||||
## 分享
|
||||
|
||||
opencode 支持三种控制对话共享方式的共享模式:
|
||||
opencode 支持清晰控制对话共享方式的共享模式:
|
||||
|
||||
---
|
||||
|
||||
@@ -35,7 +35,7 @@ opencode 支持三种控制对话共享方式的共享模式:
|
||||
/share
|
||||
```
|
||||
|
||||
这将生成一个唯一的 URL,将其复制到您的剪贴板中。
|
||||
这将生成一个唯一的 URL,将其复制到您的剪贴簿中。
|
||||
|
||||
要在[配置文件](/docs/config) 中显式设置手动模式:
|
||||
|
||||
@@ -50,7 +50,7 @@ opencode 支持三种控制对话共享方式的共享模式:
|
||||
|
||||
### 自动分享
|
||||
|
||||
您可以通过将 [配置文件](/docs/config) 中的 `share` 选项设置为 `"auto"` 来为所有新对话启用自动共享:
|
||||
您可以通过将 [config file](/docs/config) 中的 `share` 选项设置为 `"auto"` 来为所有新对话启用自动共享:
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -59,13 +59,13 @@ opencode 支持三种控制对话共享方式的共享模式:
|
||||
}
|
||||
```
|
||||
|
||||
启用自动共享后,每个新对话都会自动共享并生成链接。
|
||||
启用自动共享後,每个新对话都会自动共享并生成链接。
|
||||
|
||||
---
|
||||
|
||||
### 已禁用
|
||||
|
||||
您可以通过将 [配置文件](/docs/config) 中的 `share` 选项设置为 `"disabled"` 来完全禁用共享:
|
||||
您可以通过将 [config file](/docs/config) 中的 `share` 选项设置为 `"disabled"` 来完全禁用共享:
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -74,13 +74,13 @@ opencode 支持三种控制对话共享方式的共享模式:
|
||||
}
|
||||
```
|
||||
|
||||
为了在您的团队中针对特定项目强制执行此操作,请将其添加到您项目的 `opencode.json` 文件中,并将其提交到Git。
|
||||
To enforce this across your team for a given project, add it to the `opencode.json` in your project and check into Git.
|
||||
|
||||
---
|
||||
|
||||
## 取消共享
|
||||
|
||||
要停止共享对话并将其从公共访问中删除:
|
||||
要停止共享对话并将其從公共访问中删除:
|
||||
|
||||
```
|
||||
/unshare
|
||||
@@ -90,39 +90,39 @@ opencode 支持三种控制对话共享方式的共享模式:
|
||||
|
||||
---
|
||||
|
||||
## 隐私
|
||||
## 隱私
|
||||
|
||||
分享对话时需要记住一些事项。
|
||||
分享对话時需要記住一些事項。
|
||||
|
||||
---
|
||||
|
||||
### 数据保留
|
||||
|
||||
共享对话仍然可以访问,直到您明确取消共享。这
|
||||
共享对话仍然可以访问,直到您明確取消共享。这
|
||||
包括:
|
||||
|
||||
- 完整的对话历史记录
|
||||
- 完整的对话歷史記錄
|
||||
- 所有消息和回复
|
||||
- 会话元数据
|
||||
|
||||
---
|
||||
|
||||
### 建议
|
||||
### 建議
|
||||
|
||||
- 仅共享不包含敏感资讯的对话。
|
||||
- 分享之前查看对话内容。
|
||||
- 协作完成后取消共享对话。
|
||||
- 避免共享包括专有代码或机密数据的对话。
|
||||
- 对于敏感项目,完全禁用共享。
|
||||
- 仅共享不包含敏感資訊的对话。
|
||||
- 分享之前查看对话內容。
|
||||
- 協作完成後取消共享对话。
|
||||
- 避免与专有程式碼或機密数据共享对话。
|
||||
- 对于敏感专案,完全禁用共享。
|
||||
|
||||
---
|
||||
|
||||
## 对于企业
|
||||
## 对于企業
|
||||
|
||||
对于企业部署,共享功能可以是:
|
||||
对于企業部署,共享功能可以是:
|
||||
|
||||
- **出于安全合规性完全禁用**
|
||||
- **出于安全合規性完全禁用**
|
||||
- **仅限** 仅通过 SSO 进行身份验证的用户
|
||||
- **在您自己的基础设施上自行托管**
|
||||
- **在您自己的基礎設施上自行託管**
|
||||
|
||||
[了解更多关于在您的组织中使用opencode的](/docs/enterprise)。
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
title: 代理技能
|
||||
description: “通过 SKILL.md 定义可复用的行为”
|
||||
title: 《代理技巧》
|
||||
description: “贯穿 SKILL.md 定义可重用行为”
|
||||
---
|
||||
|
||||
代理技能使 OpenCode 能够从您的仓库或主目录中发现可重用的指令。
|
||||
技能通过原生 `skill` 工具输入导入 - 代理可以查看可用技能并可以在需要时加载完整内容。
|
||||
代理让 opencode 技能从您的存储库或主目录中找到可重用的指令。
|
||||
技能贯穿本机 `skill` 工具输入导入 - 代理可以查看可用技能并可以在需要时加载完整内容。
|
||||
|
||||
---
|
||||
|
||||
@@ -34,7 +34,7 @@ Global definitions are also loaded from `~/.config/opencode/skills/*/SKILL.md`,
|
||||
## 编写 Frontmatter
|
||||
|
||||
每个 `SKILL.md` 必须以 YAML frontmatter 。
|
||||
仅识别这些栏位:
|
||||
仅識別这些欄位:
|
||||
|
||||
- `name`(必填)
|
||||
- `description`(必填)
|
||||
@@ -50,13 +50,13 @@ Global definitions are also loaded from `~/.config/opencode/skills/*/SKILL.md`,
|
||||
|
||||
`name` 必须:
|
||||
|
||||
- 长度为 1–64 个字元
|
||||
- 为小写字母数字并带有单个连字元分隔符
|
||||
- 不以 `-` 开始或结束
|
||||
- 不包含连续的 `--`
|
||||
- 長度为 1–64 个字元
|
||||
- 为小寫字母數字并带有單个連字元分隔符
|
||||
- 不以 `-` 開始或結束
|
||||
- 不包含連續的 `--`
|
||||
- 匹配包含 `SKILL.md` 的目录名
|
||||
|
||||
等效的正规表示式:
|
||||
等效的正規表示式:
|
||||
|
||||
```text
|
||||
^[a-z0-9]+(-[a-z0-9]+)*$
|
||||
@@ -67,7 +67,7 @@ Global definitions are also loaded from `~/.config/opencode/skills/*/SKILL.md`,
|
||||
## 遵循长度规则
|
||||
|
||||
`description` 必须是 1-1024 个字元。
|
||||
保持足够具体,以便代理能够正确选择。
|
||||
保持足夠具體,以便代理能夠正确选择。
|
||||
|
||||
---
|
||||
|
||||
@@ -114,7 +114,7 @@ opencode 列出了 `skill` 工具描述中的可用技能。
|
||||
</available_skills>
|
||||
```
|
||||
|
||||
代理通过呼叫工具来载入技能:
|
||||
代理通过呼叫工具來載入技能:
|
||||
|
||||
```
|
||||
skill({ name: "git-release" })
|
||||
@@ -139,7 +139,7 @@ Control which skills agents can access using pattern-based permissions in `openc
|
||||
}
|
||||
```
|
||||
|
||||
| 许可 | 行为 |
|
||||
| 許可 | 行为 |
|
||||
| ------- | -------------------------- |
|
||||
| `allow` | 技能立即加载 |
|
||||
| `deny` | 对特工隐藏技能,访问被拒绝 |
|
||||
@@ -153,7 +153,7 @@ Control which skills agents can access using pattern-based permissions in `openc
|
||||
|
||||
为特定代理授予与全域性默认权限不同的权限。
|
||||
|
||||
**对于自定义代理**(在代理前言中):
|
||||
**对于自定義代理**(在代理前言中):
|
||||
|
||||
```yaml
|
||||
---
|
||||
@@ -185,7 +185,7 @@ permission:
|
||||
|
||||
完全禁用不应该使用技能的特工:
|
||||
|
||||
**对于定制代理**:
|
||||
**对于定製代理**:
|
||||
|
||||
```yaml
|
||||
---
|
||||
@@ -194,7 +194,7 @@ tools:
|
||||
---
|
||||
```
|
||||
|
||||
**对于内建代理**:
|
||||
**对于內建代理**:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -208,15 +208,15 @@ tools:
|
||||
}
|
||||
```
|
||||
|
||||
禁用后,`<available_skills>` 部分将被完全省略。
|
||||
禁用後,`<available_skills>` 部分将被完全省略。
|
||||
|
||||
---
|
||||
|
||||
## 解决加载问题
|
||||
|
||||
如果某项技能没有显示:
|
||||
如果某項技能沒有显示:
|
||||
|
||||
1. 验证 `SKILL.md` 拼写为全部大写
|
||||
2. 检查 frontmatter 是否包括 `name` 和 `description`
|
||||
3. 确保技能名称在所有位置都是唯一的
|
||||
3. 確保技能名称在所有位置都是唯一的
|
||||
4. 查询权限——具有`deny`的代理隐藏技能
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: 主题
|
||||
description: 选择内建主题或定义您自己的主题。
|
||||
description: 选择內建主题或定義您自己的主题。
|
||||
---
|
||||
|
||||
使用 opencode,您可以从多个内建主题中进行选择,使用适合您的终端主题的主题,或定义您自己的自定义主题。
|
||||
@@ -11,13 +11,13 @@ By default, opencode uses our own `opencode` theme.
|
||||
|
||||
## 终端要求
|
||||
|
||||
为了使主题能够正确显示完整的调色板,您的终端必须支持**真彩色**(24 位颜色)。大多数现代终端默认支持此功能,但您可能需要启用它:
|
||||
为了使主题能夠正确显示完整的调色板,您的终端必須支持**真彩色**(24 位顏色)。大多數现代终端默认支持此功能,但您可能需要启用它:
|
||||
|
||||
- **检查支持**:执行 `echo $COLORTERM` - 它应该输出 `truecolor` 或 `24bit`
|
||||
- **启用真彩色**:在shell配置文件中设置环境变量`COLORTERM=truecolor`
|
||||
- **您的终端兼容性**:确保终端模拟器支持24位颜色(大多数现代终端,如iTerm2、Alacritty、Kitty、Windows终端和最新版本的GNOME终端都支持)
|
||||
|
||||
如果没有真彩色支持,主题的颜色精度可能会降低或回落到最接近的 256 色近似值。
|
||||
如果沒有真彩色支持,主题的顏色精度可能会降低或回落到最接近的 256 色近似值。
|
||||
|
||||
---
|
||||
|
||||
@@ -39,7 +39,7 @@ opencode 带有几个内建主题。
|
||||
| `matrix` | 骇客风格黑底绿主题 |
|
||||
| `one-dark` | Based on the [Atom One](https://github.com/Th3Whit3Wolf/one-nvim) Dark theme |
|
||||
|
||||
此外,我们还在不断添加新主题。
|
||||
此外,我们还在不斷添加新主题。
|
||||
|
||||
---
|
||||
|
||||
@@ -47,15 +47,15 @@ opencode 带有几个内建主题。
|
||||
|
||||
`system` 主题旨在自动适应您的最终方案。与使用固定颜色的传统主题不同,_system_ 主题:
|
||||
|
||||
- **生成灰度**:根据终端的背景颜色建立自定义灰度,确保最佳对比度。
|
||||
- **生成灰度**:根據终端的背景顏色建立自定義灰度,確保最佳对比度。
|
||||
- **使用 ANSI 颜色**:使用标准 ANSI 颜色 (0-15) 进行语法突出显示和 UI 元素,尊重 Windows 的调色盘。
|
||||
- **保留默认设置**:使用 `none` 作为文字和背景颜色以保持本机的外观。
|
||||
|
||||
系统主题适合以下用户:
|
||||
系統主题適合以下用户:
|
||||
|
||||
- 希望 opencode 与终端的外观相匹配
|
||||
- 使用自定义终端配色方案
|
||||
- 希望所有终端应用程序具有一致的外观
|
||||
- 使用自定義终端配色方案
|
||||
- 希望所有终端应用程序具有一致的外觀
|
||||
|
||||
---
|
||||
|
||||
@@ -80,14 +80,14 @@ opencode 支持灵活的基于 JSON 的主题系统,允许用户轻松创建
|
||||
|
||||
### 优先级
|
||||
|
||||
主题按以下顺序从多个目录载入,其中后面的目录覆盖前面的目录:
|
||||
主题按以下顺序從多个目录載入,其中后面的目录覆盖前面的目录:
|
||||
|
||||
1. **内建主题** - 这些主题嵌入在二进制文件中
|
||||
1. **內建主题** - 这些主题嵌入在二進製文件中
|
||||
2. **User config directory** - Defined in `~/.config/opencode/themes/*.json` or `$XDG_CONFIG_HOME/opencode/themes/*.json`
|
||||
3. **Project root directory** - Defined in the `<project-root>/.opencode/themes/*.json`
|
||||
4. **Current working directory** - Defined in `./.opencode/themes/*.json`
|
||||
|
||||
如果多个目录包含同名主题,则将使用优先顺序较高的目录中的主题。
|
||||
如果多个目录包含同名主题,则将使用优先顺序較高的目录中的主题。
|
||||
|
||||
---
|
||||
|
||||
@@ -102,7 +102,7 @@ mkdir -p ~/.config/opencode/themes
|
||||
vim ~/.config/opencode/themes/my-theme.json
|
||||
```
|
||||
|
||||
以及针对特定项目的主题。
|
||||
以及針对特定专案的主题。
|
||||
|
||||
```bash no-frame
|
||||
mkdir -p .opencode/themes
|
||||
@@ -140,7 +140,7 @@ vim .opencode/themes/my-theme.json
|
||||
|
||||
### 例子
|
||||
|
||||
以下是自定义主题的示例:
|
||||
以下是自定義主题的示例:
|
||||
|
||||
```json title="my-theme.json"
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ Tools allow the LLM to perform actions in your codebase. opencode comes with a s
|
||||
}
|
||||
```
|
||||
|
||||
您还可以使用通配符同时控制多个工具。例如,要求 MCP 服务器批准所有工具:
|
||||
您还可以使用万用字元同时控制多个工具。例如,要求 MCP 服务器批准所有工具:
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
@@ -39,15 +39,15 @@ Tools allow the LLM to perform actions in your codebase. opencode comes with a s
|
||||
|
||||
---
|
||||
|
||||
## 內建工具
|
||||
## 內建
|
||||
|
||||
以下是 opencode 中可用的所有内置工具。
|
||||
|
||||
---
|
||||
|
||||
### bash
|
||||
### 巴什
|
||||
|
||||
在项目环境中执行shell命令。
|
||||
在专案环境中执行shell命令。
|
||||
|
||||
```json title="opencode.json" {4}
|
||||
{
|
||||
@@ -58,13 +58,13 @@ Tools allow the LLM to perform actions in your codebase. opencode comes with a s
|
||||
}
|
||||
```
|
||||
|
||||
这个工具允许 LLM 运行终端命令,例如:`npm install`, `git status`,或者其他任何终端命令。
|
||||
This tool allows the LLM to run terminal commands like `npm install`, `git status`, or any other shell command.
|
||||
|
||||
---
|
||||
|
||||
### edit
|
||||
### 編輯
|
||||
|
||||
使用精确的字符串替换来修改现有文件。
|
||||
使用精確的字符串替換修改現有文件。
|
||||
|
||||
```json title="opencode.json" {4}
|
||||
{
|
||||
@@ -75,13 +75,13 @@ Tools allow the LLM to perform actions in your codebase. opencode comes with a s
|
||||
}
|
||||
```
|
||||
|
||||
该工具通过替换完全匹配的文本来对文件进行精确编辑。这是 LLM 修改代码的主要方式。
|
||||
该工具取消替换精确的文字来匹配对文件执行精确编辑。这是 LLM 修改代码的主要方式。
|
||||
|
||||
---
|
||||
|
||||
### write
|
||||
### 寫
|
||||
|
||||
建立新文件或覆盖现有文件。
|
||||
建立新文件或覆盖現有文件。
|
||||
|
||||
```json title="opencode.json" {4}
|
||||
{
|
||||
@@ -92,17 +92,17 @@ Tools allow the LLM to perform actions in your codebase. opencode comes with a s
|
||||
}
|
||||
```
|
||||
|
||||
使用此功能可允许 LLM 创建新文件。如果文件已存在,则会覆盖现有文件。
|
||||
使用它允许 LLM 创建新文件。如果现有文件已经存在,将会覆盖它们。
|
||||
|
||||
:::note
|
||||
`写入`工具由`编辑`权限控制,涵盖所有文件修改(`编辑`、`写入`、`修补`、`多重编辑`)。
|
||||
`write`工具由`edit`许可权控制,该许可权主题所有文件修改(`edit`、`write`、`patch`、`multiedit`)。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
### read
|
||||
### 讀
|
||||
|
||||
读取代码库中的文件内容。
|
||||
從程式碼庫中讀取文件內容。
|
||||
|
||||
```json title="opencode.json" {4}
|
||||
{
|
||||
@@ -113,13 +113,13 @@ Tools allow the LLM to perform actions in your codebase. opencode comes with a s
|
||||
}
|
||||
```
|
||||
|
||||
该工具读取文件并返回其内容。它支持读取大型文件中的特定行范围。
|
||||
该工具讀取文件并返回其內容。它支持讀取大文件的特定行范围。
|
||||
|
||||
---
|
||||
|
||||
### grep
|
||||
|
||||
使用正则表达式搜索文件内容。
|
||||
使用正規表示式搜索文件內容。
|
||||
|
||||
```json title="opencode.json" {4}
|
||||
{
|
||||
@@ -130,13 +130,13 @@ Tools allow the LLM to perform actions in your codebase. opencode comes with a s
|
||||
}
|
||||
```
|
||||
|
||||
快速搜索代码库中的内容。支持完整的正则表达式语法和文件模式过滤。
|
||||
在您的程式碼庫中快速進行內容搜索。支持完整的正規表示式語法和文件模式过濾。
|
||||
|
||||
---
|
||||
|
||||
### glob
|
||||
### 全域性
|
||||
|
||||
通过模式匹配查找文件。
|
||||
通过模式匹配查询文件。
|
||||
|
||||
```json title="opencode.json" {4}
|
||||
{
|
||||
@@ -147,13 +147,13 @@ Tools allow the LLM to perform actions in your codebase. opencode comes with a s
|
||||
}
|
||||
```
|
||||
|
||||
使用类似 **/\*.js 或 src/**/\*.ts 的通配符模式搜索文件。返回按修改时间排序的匹配文件路径。
|
||||
使用 `**/*.js` 或 `src/**/*.ts` 等全域性模式搜索档案。返回按时间排序的匹配档案路径修改。
|
||||
|
||||
---
|
||||
|
||||
### list
|
||||
### 列表
|
||||
|
||||
列出给定路径中的文件和目录。
|
||||
列出給定路徑中的文件和目录。
|
||||
|
||||
```json title="opencode.json" {4}
|
||||
{
|
||||
@@ -164,16 +164,16 @@ Tools allow the LLM to perform actions in your codebase. opencode comes with a s
|
||||
}
|
||||
```
|
||||
|
||||
此工具用于列出目录内容。它接受通配符模式来筛选结果。
|
||||
该工具列出目录內容。它接受全域性模式來过濾結果。
|
||||
|
||||
---
|
||||
|
||||
### lsp(实验性)
|
||||
|
||||
与已配置的 LSP 服务器交互,以获取代码智能功能,例如定义、引用、悬停信息和调用层次结构。
|
||||
与您配置的LSP服务器交互,通知计划码智慧功能,例如定义、引用、悬停资讯和呼叫层次结构。
|
||||
|
||||
:::note
|
||||
只有当 OPENCODE_EXPERIMENTAL_LSP_TOOL=true(或 OPENCODE_EXPERIMENTAL=true)时,此工具才可用。
|
||||
This tool is only available when `OPENCODE_EXPERIMENTAL_LSP_TOOL=true` (or `OPENCODE_EXPERIMENTAL=true`).
|
||||
:::
|
||||
|
||||
```json title="opencode.json" {4}
|
||||
@@ -187,13 +187,13 @@ Tools allow the LLM to perform actions in your codebase. opencode comes with a s
|
||||
|
||||
支持的操作包括 `goToDefinition`、`findReferences`、`hover`、`documentSymbol`、`workspaceSymbol`、`goToImplementation`、`prepareCallHierarchy`、`incomingCalls` 和 `outgoingCalls`。
|
||||
|
||||
要配置哪些 LSP 服务器可用于您的项目,请参阅 [LSP Servers](/docs/lsp).
|
||||
To configure which LSP servers are available for your project, see [LSP Servers](/docs/lsp).
|
||||
|
||||
---
|
||||
|
||||
### patch
|
||||
### 修補
|
||||
|
||||
对文件应用补丁。
|
||||
对文件应用補丁。
|
||||
|
||||
```json title="opencode.json" {4}
|
||||
{
|
||||
@@ -204,17 +204,17 @@ Tools allow the LLM to perform actions in your codebase. opencode comes with a s
|
||||
}
|
||||
```
|
||||
|
||||
此工具可将补丁文件应用到您的代码库。它可用于应用来自各种来源的差异和补丁。
|
||||
该工具将補丁文件应用到您的程式碼庫。对于应用來自各種來源的差異和補丁很有帮助。
|
||||
|
||||
:::note
|
||||
`修补`工具由`编辑`权限控制,涵盖所有文件修改(`编辑`、`写入`、`修补`、`多重编辑`)。
|
||||
`patch`工具由`edit`许可权控制,该许可权主题所有文件修改(`edit`、`write`、`patch`、`multiedit`)。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
### skill
|
||||
### 技能
|
||||
|
||||
加载[技能](/docs/skills)(`SKILL.md` 文件)并在对话中返回其内容。
|
||||
加载[skill](/docs/skills)(`SKILL.md` 档案)并在对话中返回其内容。
|
||||
|
||||
```json title="opencode.json" {4}
|
||||
{
|
||||
@@ -227,9 +227,9 @@ Tools allow the LLM to perform actions in your codebase. opencode comes with a s
|
||||
|
||||
---
|
||||
|
||||
### todowrite
|
||||
### 待辦寫入
|
||||
|
||||
在编码会话过程中管理待办事项列表。
|
||||
在編碼会话期間管理待辦事項列表。
|
||||
|
||||
```json title="opencode.json" {4}
|
||||
{
|
||||
@@ -240,17 +240,17 @@ Tools allow the LLM to perform actions in your codebase. opencode comes with a s
|
||||
}
|
||||
```
|
||||
|
||||
创建和更新任务列表,以跟踪复杂操作的进度。LLM 利用此功能来组织多步骤任务。
|
||||
建立和更新任务列表以跟踪复杂操作期间的详细信息。LLM 使用它来组织多步骤任务。
|
||||
|
||||
:::note
|
||||
此工具默认情况下对子代理禁用,但您可以手动启用它。 [了解更多](/docs/agents/#permissions)
|
||||
默认情况下,子代理取消此工具,但您可以手动启用它。 [了解更多](/docs/agents/#permissions)
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
### todoread
|
||||
### 託多雷德
|
||||
|
||||
阅读现有的待办事项清单。
|
||||
閱讀現有的待辦事項列表。
|
||||
|
||||
```json title="opencode.json" {4}
|
||||
{
|
||||
@@ -261,17 +261,17 @@ Tools allow the LLM to perform actions in your codebase. opencode comes with a s
|
||||
}
|
||||
```
|
||||
|
||||
读取当前待办事项列表状态。LLM 使用此信息来跟踪哪些任务处于待处理状态或已完成状态。
|
||||
读取当前完成待办事项列表状态。由 LLM 用于跟踪哪些任务待处理或已已。
|
||||
|
||||
:::note
|
||||
此工具默认情况下对子代理禁用,但您可以手动启用它。 [了解更多](/docs/agents/#permissions)
|
||||
默认情况下,子代理取消此工具,但您可以手动启用它。 [了解更多](/docs/agents/#permissions)
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
### webfetch
|
||||
### 網頁抓取
|
||||
|
||||
获取网页内容。
|
||||
获取網頁內容。
|
||||
|
||||
```json title="opencode.json" {4}
|
||||
{
|
||||
@@ -282,18 +282,18 @@ Tools allow the LLM to perform actions in your codebase. opencode comes with a s
|
||||
}
|
||||
```
|
||||
|
||||
允许LLM获取并读取网页。可用于查找文档或研究在线资源。
|
||||
允许 LLM 获取和读取网页。对于查询文件或研究线上资源很有帮助。
|
||||
|
||||
---
|
||||
|
||||
### websearch
|
||||
### 網路搜索
|
||||
|
||||
在网络上搜索资料。
|
||||
在網路上搜索資訊。
|
||||
|
||||
:::note
|
||||
只有在使用 OpenCode 提供程序时,或者当 OPENCODE_ENABLE_EXA 环境变量被设置为任何真值(例如 true 或 1)时,此工具才可用。
|
||||
仅当使用 opencode 提供或 `OPENCODE_ENABLE_EXA` 程序环境变量设置为任何真值(例如 `true` 或 `1`)时,此工具才可用。
|
||||
|
||||
在启动 OpenCode 时启用:
|
||||
要在启动 opencode 时启用:
|
||||
|
||||
```bash
|
||||
OPENCODE_ENABLE_EXA=1 opencode
|
||||
@@ -310,19 +310,19 @@ OPENCODE_ENABLE_EXA=1 opencode
|
||||
}
|
||||
```
|
||||
|
||||
利用 Exa AI 进行网络搜索,查找相关信息。可用于研究特定主题、了解时事新闻或收集超出训练数据范围的信息。
|
||||
使用 Exa AI 执行网路搜索以线上查询相关资讯。对于研究主题、查询时事或收集训练超出数据范围的资讯很有帮助。
|
||||
|
||||
无需 API 密钥——该工具无需身份验证即可直接连接到 Exa AI 托管的 MCP 服务。
|
||||
不需要 API 密钥 — 该工具消耗身份验证即可直接连线到 Exa AI 的托管 MCP 服务。
|
||||
|
||||
:::tip
|
||||
当您需要查找信息时,请使用`网页搜索`;当您需要从特定 URL 检索内容时,请使用`网页获取`。
|
||||
当您需要查询资讯(发现)时,请使用 `websearch`;当您需要从特定 URL 检索内容(搜索)时,请使用 `webfetch`。
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
### question
|
||||
### 問題
|
||||
|
||||
在执行过程中向用户提问。
|
||||
在执行过程中詢問用户問題。
|
||||
|
||||
```json title="opencode.json" {4}
|
||||
{
|
||||
@@ -333,20 +333,20 @@ OPENCODE_ENABLE_EXA=1 opencode
|
||||
}
|
||||
```
|
||||
|
||||
该工具允许 LLM 在执行任务期间向用户提问。它在以下方面很有用:
|
||||
该工具允许 LLM 在任务期间询问用户问题。它适用于:
|
||||
|
||||
- 收集用户偏好或需求
|
||||
- 澄清含糊不清的指示
|
||||
- 就实施方案做出决定
|
||||
- 提供关于选择下一步方向的选项
|
||||
- 收集用户偏好或要求
|
||||
- 澄清不明確的指令
|
||||
- 就實施选择做出決策
|
||||
- 提供选择方向
|
||||
|
||||
每个问题都包含标题、问题正文和选项列表。用户可以从提供的选项中选择答案,也可以输入自定义答案。如果有多个问题,用户可以在提交所有答案之前在不同问题之间切换。
|
||||
每个問題都包含標題、問題文字和選項列表。用户可以從提供的選項中進行选择或輸入自定義答案。当存在多个問題時,用户可以在提交所有答案之前在这些問題之间导航。
|
||||
|
||||
---
|
||||
|
||||
## 自定义工具
|
||||
## 定製工具
|
||||
|
||||
自定义工具允许您定义LLM可以调用的自定义函数。这些函数在您的配置文件中定义,并且可以执行任意代码。
|
||||
自定义工具可以让您定义LLM可以调用自己的函式。这些是在您的配置文件中定义的并且可以执行任何代码。
|
||||
|
||||
[了解更多](/docs/custom-tools)关于创建自定义工具。
|
||||
|
||||
@@ -360,15 +360,15 @@ MCP(模型上下文协议)服务器允许您集成外部工具和服务。
|
||||
|
||||
---
|
||||
|
||||
## 内部规则
|
||||
## 内部結構
|
||||
|
||||
在内部,`grep`、 `通配符` 和 `罗列` 等工具底层都使用了 ripgrep。默认情况下,ripgrep 会遵循 .gitignore 文件中的规则,这意味着 .gitignore 文件中列出的文件和目录将被排除在搜索和列表之外。
|
||||
Internally, tools like `grep`, `glob`, and `list` use [ripgrep](https://github.com/BurntSushi/ripgrep) under the hood. By default, ripgrep respects `.gitignore` patterns, which means files and directories listed in your `.gitignore` will be excluded from searches and listings.
|
||||
|
||||
---
|
||||
|
||||
### 忽略模式
|
||||
|
||||
为了使工具不跳过那些通常会被忽略的文件,请在项目根目录下创建一个 `.ignore` 文件。该文件内定义的目录可以不会被跳过。
|
||||
要包含通常会被忽略的文件,请在专案根目录中建立 `.ignore` 文件。该文件可以明确允许某些路径。
|
||||
|
||||
```text title=".ignore"
|
||||
!node_modules/
|
||||
@@ -376,4 +376,4 @@ MCP(模型上下文协议)服务器允许您集成外部工具和服务。
|
||||
!build/
|
||||
```
|
||||
|
||||
例如,这个 `.ignore` 文件允许 ripgrep 在 `node_modules/`、`dist/` 和 `build/` 目录中搜索,即使它们已在 `.gitignore` 中列出。
|
||||
例如,此 `.ignore` 档案允许 ripgrep 在 `node_modules/`、`dist/` 和 `build/` 目录中搜索,即使它们列在 `.gitignore` 中。
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
---
|
||||
title: 故障排除
|
||||
description: 常见问题以及如何解决它们。
|
||||
description: 常見問題以及如何解決它們。
|
||||
---
|
||||
|
||||
要排除 opencode 的问题,请首先检查其存储在磁盘上的日志和本地数据。
|
||||
要排除 opencode 的问题,请首先检查其存储在磁碟上的日志和本地数据。
|
||||
|
||||
---
|
||||
|
||||
## 日志
|
||||
|
||||
日志文件写入:
|
||||
日誌文件寫入:
|
||||
|
||||
- **macOS/Linux**: `~/.local/share/opencode/log/`
|
||||
- **Windows**: Press `WIN+R` and paste `%USERPROFILE%\.local\share\opencode\log`
|
||||
@@ -51,7 +51,7 @@ opencode Desktop runs a local opencode server (the `opencode-cli` sidecar) in th
|
||||
|
||||
### 禁用插件
|
||||
|
||||
如果桌面应用程序在启动时崩溃、挂起或行为异常,请首先禁用插件。
|
||||
如果桌面应用程序在启动時崩潰、掛起或行为異常,请首先禁用插件。
|
||||
|
||||
#### 检查全域性配置
|
||||
|
||||
@@ -61,7 +61,7 @@ opencode Desktop runs a local opencode server (the `opencode-cli` sidecar) in th
|
||||
- **macOS/Linux** (older installs): `~/.local/share/opencode/opencode.jsonc`
|
||||
- **Windows**: Press `WIN+R` and paste `%USERPROFILE%\.config\opencode\opencode.jsonc`
|
||||
|
||||
如果您配置了插件,请通过删除密钥或将其设置为空数组来暂时禁用它们:
|
||||
如果您配置了插件,请通过删除密钥或将其设置为空数组來暂时禁用它們:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
@@ -77,10 +77,10 @@ opencode 还可以从磁碟加载本地外挂。暂时将它们移开(或重
|
||||
- **全域性插件**
|
||||
- **macOS/Linux**: `~/.config/opencode/plugins/`
|
||||
- **Windows**: Press `WIN+R` and paste `%USERPROFILE%\.config\opencode\plugins`
|
||||
- **项目插件**(仅当您使用每个项目配置时)
|
||||
- **专案插件**(仅当您使用每个专案配置時)
|
||||
- `<your-project>/.opencode/plugins/`
|
||||
|
||||
如果应用程序再次开始工作,请一次重新启用一个插件,以找出导致问题的插件。
|
||||
如果应用程序再次開始工作,请一次重新启用一个插件,以找出導致問題的插件。
|
||||
|
||||
---
|
||||
|
||||
@@ -99,7 +99,7 @@ opencode 还可以从磁碟加载本地外挂。暂时将它们移开(或重
|
||||
|
||||
---
|
||||
|
||||
### 修复服务器连接问题
|
||||
### 修復服务器连接問題
|
||||
|
||||
opencode Desktop 可以启动自己的本地服务器(默认配置)或连线到您的服务器 URL。
|
||||
|
||||
@@ -147,11 +147,11 @@ If you're experiencing slow performance, file access issues, or terminal problem
|
||||
opencode 桌面仅在以下情况下显示系统通知:
|
||||
|
||||
- 在您的作业系统中设置为 opencode 启用了通知,并且
|
||||
- 应用程序视窗未聚焦。
|
||||
- 应用程序視窗未聚焦。
|
||||
|
||||
---
|
||||
|
||||
### 重置桌面应用程序储存(最后的手段)
|
||||
### 重置桌面应用程序儲存(最后的手段)
|
||||
|
||||
如果应用程序无法并且启动您无法从 UI 内部清除设置,请重置桌面应用程序的存储状态。
|
||||
|
||||
@@ -179,9 +179,9 @@ opencode 桌面仅在以下情况下显示系统通知:
|
||||
|
||||
[**github.com/anomalyco/opencode/issues**](https://github.com/anomalyco/opencode/issues)
|
||||
|
||||
在建立新问题之前,请搜索现有问题以查看您的问题是否已被报告。
|
||||
在建立新問題之前,请搜索現有問題以查看您的問題是否已被報告。
|
||||
|
||||
2. **加入我们的不和谐**
|
||||
2. **加入我们的不和諧**
|
||||
|
||||
获得实时帮助和社群讨论,请加入我们的Discord服务器:
|
||||
|
||||
@@ -191,19 +191,19 @@ opencode 桌面仅在以下情况下显示系统通知:
|
||||
|
||||
## 常见问题
|
||||
|
||||
以下是一些常见问题以及解决方法。
|
||||
以下是一些常見問題以及解決方法。
|
||||
|
||||
---
|
||||
|
||||
### opencode 无法启动
|
||||
|
||||
1. 检查日志中是否有错误消息
|
||||
1. 检查日誌中是否有错误消息
|
||||
2. 尝试使用 `--print-logs` 执行以查看终端中的输出
|
||||
3. Ensure you have the latest version with `opencode upgrade`
|
||||
|
||||
---
|
||||
|
||||
### 身份验证问题
|
||||
### 身份验证問題
|
||||
|
||||
1. 尝试使用 TUI 中的 `/connect` 命令重新进行身份验证
|
||||
2. 检查您的API 密钥是否有效
|
||||
@@ -214,12 +214,12 @@ opencode 桌面仅在以下情况下显示系统通知:
|
||||
### 模型不可用
|
||||
|
||||
1. 检查您是否已通过提供商的身份验证
|
||||
2. 验证配置中的模型名称是否正确
|
||||
3. 某些模型可能需要特定的访问权限或订阅
|
||||
2. 驗證配置中的模型名称是否正确
|
||||
3. 某些模型可能需要特定的访问权限或訂閱
|
||||
|
||||
如果您遇到 `ProviderModelNotFoundError` 您很可能是错误的
|
||||
在某处引用模型。
|
||||
模型应该像这样引用:`<providerId>/<modelId>`
|
||||
在某處引用模型。
|
||||
模型应该像这樣引用:`<providerId>/<modelId>`
|
||||
|
||||
示例:
|
||||
|
||||
@@ -235,10 +235,10 @@ To figure out what models you have access to, run `opencode models`
|
||||
|
||||
如果遇到 ProviderInitError,您的配置可能无效或损坏。
|
||||
|
||||
要解决这个问题:
|
||||
要解決这个問題:
|
||||
|
||||
1. 首先,按照[提供商指南](/docs/providers) 验证您的事业是否已正确设置
|
||||
2. 如果问题仍然存在,请尝试清除储存的配置:
|
||||
2. 如果問題仍然存在,请嘗試清除儲存的配置:
|
||||
|
||||
```bash
|
||||
rm -rf ~/.local/share/opencode
|
||||
@@ -254,7 +254,7 @@ To figure out what models you have access to, run `opencode models`
|
||||
|
||||
如果您遇到 API 呼叫错误,这可能是由于过去提供包造成的。 opencode 根据需要动态安装提供包(OpenAI、Anthropic、Google 等)将其缓存放在本地。
|
||||
|
||||
要解决provider 包问题:
|
||||
要解決provider 包問題:
|
||||
|
||||
1. 清除provider 包缓存:
|
||||
|
||||
@@ -288,7 +288,7 @@ apt install -y xsel
|
||||
apt install -y wl-clipboard
|
||||
```
|
||||
|
||||
**对于无头环境:**
|
||||
**对于無頭環境:**
|
||||
|
||||
```bash
|
||||
apt install -y xvfb
|
||||
|
||||
@@ -29,17 +29,17 @@ Give me a quick summary of the codebase.
|
||||
|
||||
## 文件引用
|
||||
|
||||
您可以使用 `@` 在消息中引用文件。这会在当前工作目录中进行模糊文件搜索。
|
||||
您可以使用 `@` 在消息中引用文件。这会在当前工作目录中進行模糊文件搜索。
|
||||
|
||||
:::tip
|
||||
您还可以使用 `@` 来引用消息中的文件。
|
||||
您还可以使用 `@` 來引用消息中的文件。
|
||||
:::
|
||||
|
||||
```text "@packages/functions/src/api/index.ts"
|
||||
How is auth handled in @packages/functions/src/api/index.ts?
|
||||
```
|
||||
|
||||
文件的内容会自动添加到对话中。
|
||||
文件的內容会自动添加到对话中。
|
||||
|
||||
---
|
||||
|
||||
@@ -51,7 +51,7 @@ How is auth handled in @packages/functions/src/api/index.ts?
|
||||
!ls -la
|
||||
```
|
||||
|
||||
命令的输出将作为工具结果添加到对话中。
|
||||
命令的輸出将作为工具結果添加到对话中。
|
||||
|
||||
---
|
||||
|
||||
@@ -65,11 +65,11 @@ How is auth handled in @packages/functions/src/api/index.ts?
|
||||
|
||||
大多数命令还是以使用 `ctrl+x` 作为主键的键系结,其中 `ctrl+x` 是默认主键。 [了解更多](/docs/keybinds)。
|
||||
|
||||
以下是所有可用的斜杠命令:
|
||||
以下是所有可用的斜槓命令:
|
||||
|
||||
---
|
||||
|
||||
### connect
|
||||
### 连接
|
||||
|
||||
将提供商添加到 opencode。你可以从可用提供商中选择,并添加它们的 API 密钥。
|
||||
|
||||
@@ -79,7 +79,7 @@ How is auth handled in @packages/functions/src/api/index.ts?
|
||||
|
||||
---
|
||||
|
||||
### compact
|
||||
### 紧凑
|
||||
|
||||
压缩当前会话。_别名_: `/summarize`
|
||||
|
||||
@@ -91,9 +91,9 @@ How is auth handled in @packages/functions/src/api/index.ts?
|
||||
|
||||
---
|
||||
|
||||
### details
|
||||
### 細節
|
||||
|
||||
切换工具执行详细信息。
|
||||
切換工具执行详细信息。
|
||||
|
||||
```bash frame="none"
|
||||
/details
|
||||
@@ -103,7 +103,7 @@ How is auth handled in @packages/functions/src/api/index.ts?
|
||||
|
||||
---
|
||||
|
||||
### editor
|
||||
### 編輯
|
||||
|
||||
开启外部编辑器来编写消息。使用`EDITOR`环境变量中设定的编辑器。 [了解更多](#editor-setup)。
|
||||
|
||||
@@ -115,7 +115,7 @@ How is auth handled in @packages/functions/src/api/index.ts?
|
||||
|
||||
---
|
||||
|
||||
### exit
|
||||
### 退出
|
||||
|
||||
退出opencode。 _别名_:`/quit`、`/q`
|
||||
|
||||
@@ -127,7 +127,7 @@ How is auth handled in @packages/functions/src/api/index.ts?
|
||||
|
||||
---
|
||||
|
||||
### export
|
||||
### 导出
|
||||
|
||||
将当前对话汇出到 Markdown 并在默认编辑器中开启。使用 `EDITOR` 环境变数中设定的编辑器。 [了解更多](#editor-setup)。
|
||||
|
||||
@@ -139,9 +139,9 @@ How is auth handled in @packages/functions/src/api/index.ts?
|
||||
|
||||
---
|
||||
|
||||
### help
|
||||
### 幫助
|
||||
|
||||
显示帮助对话方块。
|
||||
显示幫助对话方塊。
|
||||
|
||||
```bash frame="none"
|
||||
/help
|
||||
@@ -151,7 +151,7 @@ How is auth handled in @packages/functions/src/api/index.ts?
|
||||
|
||||
---
|
||||
|
||||
### init
|
||||
### 初始化
|
||||
|
||||
Create or update `AGENTS.md` file. [Learn more](/docs/rules).
|
||||
|
||||
@@ -163,7 +163,7 @@ Create or update `AGENTS.md` file. [Learn more](/docs/rules).
|
||||
|
||||
---
|
||||
|
||||
### models
|
||||
### 模型
|
||||
|
||||
列出可用模型。
|
||||
|
||||
@@ -175,7 +175,7 @@ Create or update `AGENTS.md` file. [Learn more](/docs/rules).
|
||||
|
||||
---
|
||||
|
||||
### new
|
||||
### 新的
|
||||
|
||||
开始新的会话。 _别名_: `/clear`
|
||||
|
||||
@@ -187,7 +187,7 @@ Create or update `AGENTS.md` file. [Learn more](/docs/rules).
|
||||
|
||||
---
|
||||
|
||||
### redo
|
||||
### 重做
|
||||
|
||||
删除之前重做消除的讯息。仅在使用`/undo`后可用。
|
||||
|
||||
@@ -206,7 +206,7 @@ Create or update `AGENTS.md` file. [Learn more](/docs/rules).
|
||||
|
||||
---
|
||||
|
||||
### sessions
|
||||
### 会话
|
||||
|
||||
上市会话并在会话之间切换。 _别名_:`/resume`、`/continue`
|
||||
|
||||
@@ -218,7 +218,7 @@ Create or update `AGENTS.md` file. [Learn more](/docs/rules).
|
||||
|
||||
---
|
||||
|
||||
### share
|
||||
### 分享
|
||||
|
||||
共享当前会话。 [了解更多](/docs/share)。
|
||||
|
||||
@@ -230,7 +230,7 @@ Create or update `AGENTS.md` file. [Learn more](/docs/rules).
|
||||
|
||||
---
|
||||
|
||||
### themes
|
||||
### 主题
|
||||
|
||||
列出可用的主题。
|
||||
|
||||
@@ -242,9 +242,9 @@ Create or update `AGENTS.md` file. [Learn more](/docs/rules).
|
||||
|
||||
---
|
||||
|
||||
### thinking
|
||||
### 思維
|
||||
|
||||
切换对话中 thinking/reasoning 块的可视性。启用后,您可以看到支持扩展思考的模型的推理过程。
|
||||
切换对话中 thinking/reasoning 块的可视性。启用后,您可以看到支持增强套件思维的模型的推理过程。
|
||||
|
||||
:::note
|
||||
该命令仅控制是否**显示** - 不启用或取消模型的推理功能。要切换实际推理功能,请使用 `ctrl+t` 回圈切换模型变体。
|
||||
@@ -256,9 +256,9 @@ Create or update `AGENTS.md` file. [Learn more](/docs/rules).
|
||||
|
||||
---
|
||||
|
||||
### undo
|
||||
### 撤消
|
||||
|
||||
撤消对话中的最后一条消息。删除最近的用户消息、所有后续响应以及任何文件更改。
|
||||
撤消对话中的最后一条消息。删除最近的用户消息、所有后续響应以及任何文件更改。
|
||||
|
||||
:::tip
|
||||
所做的任何文件更改也将被恢复。
|
||||
@@ -275,7 +275,7 @@ Create or update `AGENTS.md` file. [Learn more](/docs/rules).
|
||||
|
||||
---
|
||||
|
||||
### unshare
|
||||
### 取消共享
|
||||
|
||||
取消共享当前会话。 [了解更多](/docs/share#un-sharing)。
|
||||
|
||||
@@ -334,7 +334,7 @@ Create or update `AGENTS.md` file. [Learn more](/docs/rules).
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
流行的编辑器选项包括:
|
||||
流行的编辑器選項包括:
|
||||
|
||||
- `code` - Visual Studio Code
|
||||
- `cursor` - 游标
|
||||
@@ -369,7 +369,7 @@ Create or update `AGENTS.md` file. [Learn more](/docs/rules).
|
||||
}
|
||||
```
|
||||
|
||||
### 选项
|
||||
### 選項
|
||||
|
||||
- `scroll_acceleration` - 启用 macOS 式滚动加速以实现平滑、自然的滚动。启用后,滚动速度会随着快速滚动滚动而增加,并在较慢的移动时保持精确。 **此设定优先于 `scroll_speed` 并在启用时覆盖它。 **
|
||||
- `scroll_speed` - 控制使用滚动控制器时 TUI 滚动的速度(简单:`1`)。默认为 `3`。 **注意:如果 `scroll_acceleration.enabled` 设置为 `true`,则忽略此设置。 **
|
||||
@@ -384,7 +384,7 @@ Create or update `AGENTS.md` file. [Learn more](/docs/rules).
|
||||
|
||||
#### 用户名称显示
|
||||
|
||||
切换您的用户名称是否出现在聊天消息中。通过以下方式访问:
|
||||
切換您的用户名称是否出現在聊天消息中。通过以下方式访问:
|
||||
|
||||
- 命令面板:搜索“用户名称”或“隐藏用户名称”
|
||||
- 该设置会自动保留,放在 TUI 会话中被记住
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Web
|
||||
title: 網路
|
||||
description: 在浏览器中使用opencode。
|
||||
---
|
||||
|
||||
@@ -7,7 +7,7 @@ opencode 可以在浏览器中作为 Web 应用程序执行,消耗终端可以
|
||||
|
||||

|
||||
|
||||
## 入门
|
||||
## 入門
|
||||
|
||||
绕过执行以下命令启动 Web 简介:
|
||||
|
||||
@@ -29,7 +29,7 @@ For the best experience, run `opencode web` from [WSL](/docs/windows-wsl) rather
|
||||
|
||||
## 配置
|
||||
|
||||
您可以使用命令行标志或在[config file](/docs/config).conf 中配置Web服务器。
|
||||
您可以使用命令列标志或在[config file](/docs/config).conf 中配置Web服务器。
|
||||
|
||||
### 端口
|
||||
|
||||
@@ -39,9 +39,9 @@ For the best experience, run `opencode web` from [WSL](/docs/windows-wsl) rather
|
||||
opencode web --port 4096
|
||||
```
|
||||
|
||||
### 主机名
|
||||
### 主機名
|
||||
|
||||
默认情况下,服务器绑定到`127.0.0.1`(仅限本地主机)。要使opencode在您的网路上可访问:
|
||||
情况默认下,服务器系结到`127.0.0.1`(仅限本地主机)。要使opencode在您的网路上可访问:
|
||||
|
||||
```bash
|
||||
opencode web --hostname 0.0.0.0
|
||||
@@ -78,9 +78,9 @@ opencode web --mdns --mdns-domain myproject.local
|
||||
opencode web --cors https://example.com
|
||||
```
|
||||
|
||||
### 验证
|
||||
### 驗證
|
||||
|
||||
要保护访问,请使用 `OPENCODE_SERVER_PASSWORD` 环境变量设置密码:
|
||||
要保护访问,请使用 `OPENCODE_SERVER_PASSWORD` 环境变数设置密码:
|
||||
|
||||
```bash
|
||||
OPENCODE_SERVER_PASSWORD=secret opencode web
|
||||
@@ -90,19 +90,19 @@ The username defaults to `opencode` but can be changed with `OPENCODE_SERVER_USE
|
||||
|
||||
---
|
||||
|
||||
## 使用web界面
|
||||
## 使用网络界面
|
||||
|
||||
启动后,web界面将提供对您的 opencode 会话的访问。
|
||||
启动后,网路界面将提供对您的 opencode 会话的访问。
|
||||
|
||||
### 会话
|
||||
|
||||
从主页查看和管理您的会话。您可以查看活动会话并开始新会话。
|
||||
從主頁查看和管理您的会话。您可以查看活动会话并開始新会话。
|
||||
|
||||

|
||||
|
||||
### 服务器状态
|
||||
### 服务器狀態
|
||||
|
||||
单击“查看服务器”可查看连接的服务器及其状态。
|
||||
单击“查看服务器”可查看连接的服务器及其狀態。
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Zen
|
||||
title: 禪
|
||||
description: 由 opencode 提供的精选模型列表。
|
||||
---
|
||||
|
||||
@@ -7,10 +7,10 @@ import config from "../../../../config.mjs"
|
||||
export const console = config.console
|
||||
export const email = `mailto:${config.email}`
|
||||
|
||||
OpenCode Zen 是由 OpenCode 团队提供的一组经过测试和验证的模型列表。
|
||||
Error 500 (Server Error)!!1500.That’s an error.There was an error. Please try again later.That’s all we know.
|
||||
|
||||
:::note
|
||||
OpenCode Zen 目前处于测试阶段。
|
||||
OpenCode Zen 目前处于一个测试阶段。
|
||||
:::
|
||||
|
||||
Zen 的工作方式与 opencode 中的任何其他提供商相同。您登录 OpenCode Zen 并获得
|
||||
@@ -21,31 +21,31 @@ opencode。
|
||||
|
||||
## 背景
|
||||
|
||||
市面上有很多模型,但其中只有少数几个
|
||||
这些模型可以很好地用作编码代理。此外,大多数提供商都
|
||||
配置非常不同;所以你会得到截然不同的效率和质量。
|
||||
市面上有很多模型,但其中只有少數幾个
|
||||
这些模型可以很好地用作編碼代理。此外,大多數提供商都
|
||||
配置非常不同;所以你会得到截然不同的效能和質量。
|
||||
|
||||
:::tip
|
||||
我们测试了一组与 opencode 配合良好的模型并提供商。
|
||||
:::
|
||||
|
||||
因此,如果您通过 OpenRouter 之类的东西使用模型,您永远无法
|
||||
确定您是否获得了您想要的模型的最佳版本。
|
||||
因此,如果您使用 OpenRouter 之类的东西使用模型,您永远无法
|
||||
確定您是否獲得了您想要的模型的最佳版本。
|
||||
|
||||
为了解决这个问题,我们做了几件事:
|
||||
为瞭解決这个問題,我们做了幾件事:
|
||||
|
||||
1. 我们测试了一组选定的模型,并与他们的团队讨论了如何
|
||||
最好执行它们。
|
||||
2. 然后我们与一些提供商合作以确保这些服务得到服务
|
||||
1. 我们測試了一組選定的模型,并与他們的團隊討論瞭如何
|
||||
最好执行它們。
|
||||
2. 然後我们与一些提供商合作以確保这些服務得到服務
|
||||
正确。
|
||||
3. 最后,我们对 model/provider 的组合进行了基准测试,总结了
|
||||
并附上一份我们觉得不错的推荐清单。
|
||||
并附上一份我们覺得不錯的推薦清單。
|
||||
|
||||
OpenCode Zen 是一个AI网关,让您可以访问这些模型。
|
||||
OpenCode Zen 是一个AI闸道器,可以让您访问这些模型。
|
||||
|
||||
---
|
||||
|
||||
## 它是如何运作的
|
||||
## 它是如何運作的
|
||||
|
||||
OpenCode Zen 的工作方式与 opencode 中的任何其他功能相同。
|
||||
|
||||
@@ -54,7 +54,7 @@ OpenCode Zen 的工作方式与 opencode 中的任何其他功能相同。
|
||||
2. 您在 TUI 中执行 `/connect` 命令,选择 OpenCode Zen,然后贴上 API 密钥。
|
||||
3. 在 TUI 中执行 `/models` 以查看我们推荐的模型列表。
|
||||
|
||||
您需要按请求付费,并且您可以将积分添加到您的账户中。
|
||||
您需要按请求付費,并且您可以将積分添加到您的账户中。
|
||||
|
||||
---
|
||||
|
||||
@@ -62,7 +62,7 @@ OpenCode Zen 的工作方式与 opencode 中的任何其他功能相同。
|
||||
|
||||
您还可以通过以下 API 端点访问我们的模型。
|
||||
|
||||
| 模型 | 模型ID | 端点 | AI SDK 套件 |
|
||||
| 模型 | 模型ID | 端点 | 人工智慧SDK包 |
|
||||
| ------------------ | ------------------ | -------------------------------------------------- | --------------------------- |
|
||||
| GPT 5.2 | gpt-5.2 | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||
| GPT 5.2 Codex | gpt-5.2-codex | `https://opencode.ai/zen/v1/responses` | `@ai-sdk/openai` |
|
||||
@@ -102,7 +102,7 @@ use `opencode/gpt-5.2-codex` in your config.
|
||||
|
||||
### 模型
|
||||
|
||||
您可以从以下位置获取可用模型及其元数据的完整列表:
|
||||
您可以從以下位置获取可用模型及其元数据的完整列表:
|
||||
|
||||
```
|
||||
https://opencode.ai/zen/v1/models
|
||||
@@ -114,9 +114,9 @@ https://opencode.ai/zen/v1/models
|
||||
|
||||
我们支持即用即付模式。以下是**每 100 万Tokens的价格**。
|
||||
|
||||
| 模型 | 输入 | 输出 | 缓存读取 | 缓存写入 |
|
||||
| 模型 | 輸入 | 輸出 | 缓存讀取 | 缓存寫入 |
|
||||
| ---------------------------------- | ---------- | ---------- | ---------- | ---------- |
|
||||
| 大泡菜 | 免费 | 免费 | 免费 | - |
|
||||
| 大泡菜 | 免費 | 免費 | 免費 | - |
|
||||
| MiniMax M2.1 免费 | 免费 | 免费 | 免费 | - |
|
||||
| 迷你最大M2.1 | 0.30 美元 | 1.20 美元 | 0.10 美元 | - |
|
||||
| GLM 4.7 免费 | 免费 | 免费 | 免费 | - |
|
||||
@@ -153,32 +153,32 @@ https://opencode.ai/zen/v1/models
|
||||
您可能会在您的使用历史记录中注意到*Claude Haiku 3.5*。这是一个[低成本模型](/docs/config/#models),用于生成会话标题。
|
||||
|
||||
:::note
|
||||
信用卡费用按成本转嫁(4.4% + 每笔交易 0.30 美元);除此之外我们不收取任何费用。
|
||||
信用卡费用按成本轉嫁(4.4% + 每筆交易 0.30 美元);除此之外我们不收取任何费用。
|
||||
:::
|
||||
|
||||
免费模型:
|
||||
免費模型:
|
||||
|
||||
- GLM 4.7 免费版本在 opencode 上限时提供。团队正在利用这段时间收集反馈并改进模型。
|
||||
- Kimi K2.5 在 opencode 限时免费发布。团队正在利用这段时间收集反馈并改进模型。
|
||||
- MiniMax M2.1 在 opencode 限时免费供应。团队正在利用这段时间收集反馈并改进模型。
|
||||
- Big Pickle 是一个隐形模型,在 opencode 上限时免费。团队正在利用这个临时收集反馈并改进模型。
|
||||
|
||||
<a href={email}>如果您有任何疑问,请联络我们</a>。
|
||||
<a href={email}>如果您有任何疑問,请聯絡我们</a>。
|
||||
|
||||
---
|
||||
|
||||
### 自动重新载入
|
||||
### 自动重新載入
|
||||
|
||||
如果您的余额低于 5 美元,Zen 将自动充值 20 美元。
|
||||
|
||||
您可以更改自动充值金额。您还可以完全禁用自动重新载入。
|
||||
您可以更改自动充值金額。您还可以完全禁用自动重新載入。
|
||||
|
||||
---
|
||||
|
||||
### 每月限额
|
||||
|
||||
您还可以为整个工作区和每个工作区设置每月使用限制
|
||||
你的团队成员。
|
||||
你的團隊成员。
|
||||
|
||||
例如,假设您将每月使用中断设置为 20 美元,Zen 将不会使用
|
||||
一个月超过 20 美元。但如果你启用了自动重新加载,Zen 可能会结束
|
||||
@@ -188,7 +188,7 @@ https://opencode.ai/zen/v1/models
|
||||
|
||||
## 隐私
|
||||
|
||||
我们所有的模型都在美国托管。我们的提供商遵循零保留政策,不会将您的数据用于模型训练,但以下情况除外:
|
||||
我们所有的模型都在美国託管。我们的提供商遵循零保留政策,不会将您的数据用于模型训练,但以下情况除外:
|
||||
|
||||
- Big Pickle:在免费期间,收集可用于改进模型的数据。
|
||||
- GLM 4.7 免费:在免费期间,收集可用于改进模型的数据。
|
||||
@@ -201,20 +201,21 @@ https://opencode.ai/zen/v1/models
|
||||
|
||||
## 对于团队
|
||||
|
||||
Zen 也非常适合团队使用。您可以邀请您可以邀请队友,分配角色,管理团队使用的模型等。
|
||||
Zen 对团队也很有效。您可以参与第三方、角色、策划
|
||||
您的團隊使用的模型等等。
|
||||
|
||||
:::note
|
||||
作为测试版的一部分,工作空间目前对团队免费。
|
||||
作为測試版的一部分,工作空間目前对團隊免費。
|
||||
:::
|
||||
|
||||
作为测试版的一部分,管理工作空间目前对团队免费。我们将会
|
||||
很快就会分享更多有关定价的细节。
|
||||
作为測試版的一部分,管理工作空間目前对團隊免費。我们将会
|
||||
很快就会分享更多有關定價的細節。
|
||||
|
||||
---
|
||||
|
||||
### 角色
|
||||
|
||||
您可以邀请团队成员到您的工作区并分配角色:
|
||||
您可以邀请團隊成员到您的工作区并分配角色:
|
||||
|
||||
- **管理员**:管理模型、成员、API 密钥和设备
|
||||
- **成员**:仅管理自己的API 金?
|
||||
|
||||
@@ -84,8 +84,7 @@ curl -fsSL https://opencode.ai/install | bash
|
||||
- **在 Arch Linux 上使用 Paru**
|
||||
|
||||
```bash
|
||||
sudo pacman -S opencode # Arch Linux (Stable)
|
||||
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
||||
paru -S opencode-bin
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
@@ -12,28 +12,7 @@ function docsAlias(pathname: string) {
|
||||
|
||||
const next = locale === "root" ? `/docs${tail}` : `/docs/${locale}${tail}`
|
||||
if (next === pathname) return null
|
||||
return {
|
||||
path: next,
|
||||
locale,
|
||||
}
|
||||
}
|
||||
|
||||
function cookie(locale: string) {
|
||||
const value = locale === "root" ? "en" : locale
|
||||
return `oc_locale=${encodeURIComponent(value)}; Path=/; Max-Age=31536000; SameSite=Lax`
|
||||
}
|
||||
|
||||
function redirect(url: URL, path: string, locale?: string) {
|
||||
const next = new URL(url.toString())
|
||||
next.pathname = path
|
||||
const headers = new Headers({
|
||||
Location: next.toString(),
|
||||
})
|
||||
if (locale) headers.set("Set-Cookie", cookie(locale))
|
||||
return new Response(null, {
|
||||
status: 302,
|
||||
headers,
|
||||
})
|
||||
return next
|
||||
}
|
||||
|
||||
function localeFromCookie(header: string | null) {
|
||||
@@ -80,7 +59,9 @@ function localeFromAcceptLanguage(header: string | null) {
|
||||
export const onRequest = defineMiddleware((ctx, next) => {
|
||||
const alias = docsAlias(ctx.url.pathname)
|
||||
if (alias) {
|
||||
return redirect(ctx.url, alias.path, alias.locale)
|
||||
const url = new URL(ctx.request.url)
|
||||
url.pathname = alias
|
||||
return ctx.redirect(url.toString(), 302)
|
||||
}
|
||||
|
||||
if (ctx.url.pathname !== "/docs" && ctx.url.pathname !== "/docs/") return next()
|
||||
@@ -90,5 +71,7 @@ export const onRequest = defineMiddleware((ctx, next) => {
|
||||
localeFromAcceptLanguage(ctx.request.headers.get("accept-language"))
|
||||
if (!locale || locale === "root") return next()
|
||||
|
||||
return redirect(ctx.url, `/docs/${locale}/`)
|
||||
const url = new URL(ctx.request.url)
|
||||
url.pathname = `/docs/${locale}/`
|
||||
return ctx.redirect(url.toString(), 302)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user