Compare commits

..

1 Commits

Author SHA1 Message Date
Adam
b3991603e2 fix(desktop): server spawn resilience 2026-02-10 15:58:17 -06:00
395 changed files with 5988 additions and 6061 deletions

1
.github/VOUCHED.td vendored
View File

@@ -15,5 +15,4 @@ kitlangton
kommander
r44vc0rp
rekram1-node
-spider-yamet clawdbot/llm psychosis, spam pinging the team
thdxr

View File

@@ -23,7 +23,7 @@
},
"packages/app": {
"name": "@opencode-ai/app",
"version": "1.1.56",
"version": "1.1.54",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/sdk": "workspace:*",
@@ -73,7 +73,7 @@
},
"packages/console/app": {
"name": "@opencode-ai/console-app",
"version": "1.1.56",
"version": "1.1.54",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@ibm/plex": "6.4.1",
@@ -107,7 +107,7 @@
},
"packages/console/core": {
"name": "@opencode-ai/console-core",
"version": "1.1.56",
"version": "1.1.54",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"@jsx-email/render": "1.1.1",
@@ -134,7 +134,7 @@
},
"packages/console/function": {
"name": "@opencode-ai/console-function",
"version": "1.1.56",
"version": "1.1.54",
"dependencies": {
"@ai-sdk/anthropic": "2.0.0",
"@ai-sdk/openai": "2.0.2",
@@ -158,7 +158,7 @@
},
"packages/console/mail": {
"name": "@opencode-ai/console-mail",
"version": "1.1.56",
"version": "1.1.54",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
@@ -182,7 +182,7 @@
},
"packages/desktop": {
"name": "@opencode-ai/desktop",
"version": "1.1.56",
"version": "1.1.54",
"dependencies": {
"@opencode-ai/app": "workspace:*",
"@opencode-ai/ui": "workspace:*",
@@ -215,7 +215,7 @@
},
"packages/enterprise": {
"name": "@opencode-ai/enterprise",
"version": "1.1.56",
"version": "1.1.54",
"dependencies": {
"@opencode-ai/ui": "workspace:*",
"@opencode-ai/util": "workspace:*",
@@ -244,7 +244,7 @@
},
"packages/function": {
"name": "@opencode-ai/function",
"version": "1.1.56",
"version": "1.1.54",
"dependencies": {
"@octokit/auth-app": "8.0.1",
"@octokit/rest": "catalog:",
@@ -260,7 +260,7 @@
},
"packages/opencode": {
"name": "opencode",
"version": "1.1.56",
"version": "1.1.54",
"bin": {
"opencode": "./bin/opencode",
},
@@ -366,7 +366,7 @@
},
"packages/plugin": {
"name": "@opencode-ai/plugin",
"version": "1.1.56",
"version": "1.1.54",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"zod": "catalog:",
@@ -386,7 +386,7 @@
},
"packages/sdk/js": {
"name": "@opencode-ai/sdk",
"version": "1.1.56",
"version": "1.1.54",
"devDependencies": {
"@hey-api/openapi-ts": "0.90.10",
"@tsconfig/node22": "catalog:",
@@ -397,7 +397,7 @@
},
"packages/slack": {
"name": "@opencode-ai/slack",
"version": "1.1.56",
"version": "1.1.54",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"@slack/bolt": "^3.17.1",
@@ -410,7 +410,7 @@
},
"packages/ui": {
"name": "@opencode-ai/ui",
"version": "1.1.56",
"version": "1.1.54",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/sdk": "workspace:*",
@@ -452,7 +452,7 @@
},
"packages/util": {
"name": "@opencode-ai/util",
"version": "1.1.56",
"version": "1.1.54",
"dependencies": {
"zod": "catalog:",
},
@@ -463,7 +463,7 @@
},
"packages/web": {
"name": "@opencode-ai/web",
"version": "1.1.56",
"version": "1.1.54",
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1",

View File

@@ -166,10 +166,14 @@ const bucketNew = new sst.cloudflare.Bucket("ZenDataNew")
const AWS_SES_ACCESS_KEY_ID = new sst.Secret("AWS_SES_ACCESS_KEY_ID")
const AWS_SES_SECRET_ACCESS_KEY = new sst.Secret("AWS_SES_SECRET_ACCESS_KEY")
const logProcessor = new sst.cloudflare.Worker("LogProcessor", {
handler: "packages/console/function/src/log-processor.ts",
link: [new sst.Secret("HONEYCOMB_API_KEY")],
})
let logProcessor
if ($app.stage === "production" || $app.stage === "frank") {
const HONEYCOMB_API_KEY = new sst.Secret("HONEYCOMB_API_KEY")
logProcessor = new sst.cloudflare.Worker("LogProcessor", {
handler: "packages/console/function/src/log-processor.ts",
link: [HONEYCOMB_API_KEY],
})
}
new sst.cloudflare.x.SolidStart("Console", {
domain,
@@ -207,7 +211,7 @@ new sst.cloudflare.x.SolidStart("Console", {
transform: {
worker: {
placement: { mode: "smart" },
tailConsumers: [{ service: logProcessor.nodes.worker.scriptName }],
tailConsumers: logProcessor ? [{ service: logProcessor.nodes.worker.scriptName }] : [],
},
},
},

View File

@@ -1,36 +0,0 @@
import { test, expect } from "../fixtures"
import { closeSidebar, hoverSessionItem } from "../actions"
import { projectSwitchSelector, sessionItemSelector } from "../selectors"
test("collapsed sidebar popover stays open when archiving a session", async ({ page, slug, sdk, gotoSession }) => {
const stamp = Date.now()
const one = await sdk.session.create({ title: `e2e sidebar popover archive 1 ${stamp}` }).then((r) => r.data)
const two = await sdk.session.create({ title: `e2e sidebar popover archive 2 ${stamp}` }).then((r) => r.data)
if (!one?.id) throw new Error("Session create did not return an id")
if (!two?.id) throw new Error("Session create did not return an id")
try {
await gotoSession(one.id)
await closeSidebar(page)
const project = page.locator(projectSwitchSelector(slug)).first()
await expect(project).toBeVisible()
await project.hover()
await expect(page.locator(sessionItemSelector(one.id)).first()).toBeVisible()
await expect(page.locator(sessionItemSelector(two.id)).first()).toBeVisible()
const item = await hoverSessionItem(page, one.id)
await item
.getByRole("button", { name: /archive/i })
.first()
.click()
await expect(page.locator(sessionItemSelector(two.id)).first()).toBeVisible()
} finally {
await sdk.session.delete({ sessionID: one.id }).catch(() => undefined)
await sdk.session.delete({ sessionID: two.id }).catch(() => undefined)
}
})

View File

@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/app",
"version": "1.1.56",
"version": "1.1.54",
"description": "",
"type": "module",
"exports": {

View File

@@ -166,7 +166,6 @@ export function SessionHeader() {
})
const [prefs, setPrefs] = persisted(Persist.global("open.app"), createStore({ app: "finder" as OpenApp }))
const [menu, setMenu] = createStore({ open: false })
const canOpen = createMemo(() => platform.platform === "desktop" && !!platform.openPath && server.isLocal())
const current = createMemo(() => options().find((o) => o.id === prefs.app) ?? options()[0])
@@ -356,12 +355,7 @@ export function SessionHeader() {
<span class="text-12-regular text-text-strong">Open</span>
</Button>
<div class="self-stretch w-px bg-border-base/70" />
<DropdownMenu
gutter={6}
placement="bottom-end"
open={menu.open}
onOpenChange={(open) => setMenu("open", open)}
>
<DropdownMenu gutter={6} placement="bottom-end">
<DropdownMenu.Trigger
as={IconButton}
icon="chevron-down"
@@ -381,13 +375,7 @@ export function SessionHeader() {
}}
>
{options().map((o) => (
<DropdownMenu.RadioItem
value={o.id}
onSelect={() => {
setMenu("open", false)
openDir(o.id)
}}
>
<DropdownMenu.RadioItem value={o.id} onSelect={() => openDir(o.id)}>
<div class="flex size-5 shrink-0 items-center justify-center">
<AppIcon id={o.icon} class={size(o.icon)} />
</div>
@@ -400,12 +388,7 @@ export function SessionHeader() {
</DropdownMenu.RadioGroup>
</DropdownMenu.Group>
<DropdownMenu.Separator />
<DropdownMenu.Item
onSelect={() => {
setMenu("open", false)
copyPath()
}}
>
<DropdownMenu.Item onSelect={copyPath}>
<div class="flex size-5 shrink-0 items-center justify-center">
<Icon name="copy" size="small" class="text-icon-weak" />
</div>

View File

@@ -190,7 +190,7 @@ export const Terminal = (props: TerminalProps) => {
cursorStyle: "bar",
fontSize: 14,
fontFamily: monoFontFamily(settings.appearance.font()),
allowTransparency: false,
allowTransparency: true,
convertEol: true,
theme: terminalColors(),
scrollback: 10_000,

View File

@@ -12,19 +12,10 @@ export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleCo
const platform = usePlatform()
const abort = new AbortController()
const auth = (() => {
if (typeof window === "undefined") return
const password = window.__OPENCODE__?.serverPassword
if (!password) return
return {
Authorization: `Basic ${btoa(`opencode:${password}`)}`,
}
})()
const eventSdk = createOpencodeClient({
baseUrl: server.url,
signal: abort.signal,
headers: auth,
fetch: platform.fetch,
})
const emitter = createGlobalEmitter<{
[key: string]: Event

View File

@@ -54,13 +54,6 @@ export default function Layout(props: ParentProps) {
navigate(`/${params.dir}/session/${sessionID}`)
}
const sessionHref = (sessionID: string) => {
if (params.dir) return `/${params.dir}/session/${sessionID}`
return `/session/${sessionID}`
}
const syncSession = (sessionID: string) => sync.session.sync(sessionID)
return (
<DataProvider
data={sync.data}
@@ -69,8 +62,6 @@ export default function Layout(props: ParentProps) {
onQuestionReply={replyToQuestion}
onQuestionReject={rejectQuestion}
onNavigateToSession={navigateToSession}
onSessionHref={sessionHref}
onSyncSession={syncSession}
>
<LocalProvider>{props.children}</LocalProvider>
</DataProvider>

View File

@@ -181,6 +181,20 @@ export default function Layout(props: ParentProps) {
aim.reset()
})
createEffect(
on(
() => ({ dir: params.dir, id: params.id }),
() => {
if (layout.sidebar.opened()) return
if (!state.hoverProject) return
aim.reset()
setState("hoverSession", undefined)
setState("hoverProject", undefined)
},
{ defer: true },
),
)
const autoselecting = createMemo(() => {
if (params.dir) return false
if (!state.autoselect) return false

View File

@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-app",
"version": "1.1.56",
"version": "1.1.54",
"type": "module",
"license": "MIT",
"scripts": {

View File

@@ -9,8 +9,8 @@ export const config = {
github: {
repoUrl: "https://github.com/anomalyco/opencode",
starsFormatted: {
compact: "100K",
full: "100,000",
compact: "95K",
full: "95,000",
},
},
@@ -22,8 +22,8 @@ export const config = {
// Static stats (used on landing page)
stats: {
contributors: "700",
commits: "9,000",
contributors: "650",
commits: "8,500",
monthlyUsers: "2.5M",
},
} as const

View File

@@ -3,13 +3,11 @@ export class CreditsError extends Error {}
export class MonthlyLimitError extends Error {}
export class UserLimitError extends Error {}
export class ModelError extends Error {}
class LimitError extends Error {
export class FreeUsageLimitError extends Error {}
export class SubscriptionUsageLimitError extends Error {
retryAfter?: number
constructor(message: string, retryAfter?: number) {
super(message)
this.retryAfter = retryAfter
}
}
export class FreeUsageLimitError extends LimitError {}
export class SubscriptionUsageLimitError extends LimitError {}

View File

@@ -134,26 +134,20 @@ export async function handler(
body: reqBody,
})
if (res.status !== 200) {
logger.metric({
"llm.error.code": res.status,
"llm.error.message": res.statusText,
// Try another provider => stop retrying if using fallback provider
if (
res.status !== 200 &&
// ie. openai 404 error: Item with id 'msg_0ead8b004a3b165d0069436a6b6834819896da85b63b196a3f' not found.
res.status !== 404 &&
// ie. cannot change codex model providers mid-session
modelInfo.stickyProvider !== "strict" &&
modelInfo.fallbackProvider &&
providerInfo.id !== modelInfo.fallbackProvider
) {
return retriableRequest({
excludeProviders: [...retry.excludeProviders, providerInfo.id],
retryCount: retry.retryCount + 1,
})
// Try another provider => stop retrying if using fallback provider
if (
// ie. openai 404 error: Item with id 'msg_0ead8b004a3b165d0069436a6b6834819896da85b63b196a3f' not found.
res.status !== 404 &&
// ie. cannot change codex model providers mid-session
modelInfo.stickyProvider !== "strict" &&
modelInfo.fallbackProvider &&
providerInfo.id !== modelInfo.fallbackProvider
) {
return retriableRequest({
excludeProviders: [...retry.excludeProviders, providerInfo.id],
retryCount: retry.retryCount + 1,
})
}
}
return { providerInfo, reqBody, res, startTimestamp }
@@ -313,7 +307,7 @@ export async function handler(
if (error instanceof FreeUsageLimitError || error instanceof SubscriptionUsageLimitError) {
const headers = new Headers()
if (error.retryAfter) {
if (error instanceof SubscriptionUsageLimitError && error.retryAfter) {
headers.set("retry-after", String(error.retryAfter))
}
return new Response(

View File

@@ -28,46 +28,17 @@ export function createRateLimiter(limit: ZenData.RateLimit | undefined, rawIp: s
check: async () => {
const rows = await Database.use((tx) =>
tx
.select({ interval: IpRateLimitTable.interval, count: IpRateLimitTable.count })
.select({ count: IpRateLimitTable.count })
.from(IpRateLimitTable)
.where(and(eq(IpRateLimitTable.ip, ip), inArray(IpRateLimitTable.interval, intervals))),
)
const total = rows.reduce((sum, r) => sum + r.count, 0)
logger.debug(`rate limit total: ${total}`)
if (total >= limitValue)
throw new FreeUsageLimitError(
`Rate limit exceeded. Please try again later.`,
limit.period === "day" ? getRetryAfterDay(now) : getRetryAfterHour(rows, intervals, limitValue, now),
)
if (total >= limitValue) throw new FreeUsageLimitError(`Rate limit exceeded. Please try again later.`)
},
}
}
export function getRetryAfterDay(now: number) {
return Math.ceil((86_400_000 - (now % 86_400_000)) / 1000)
}
export function getRetryAfterHour(
rows: { interval: string; count: number }[],
intervals: string[],
limit: number,
now: number,
) {
const counts = new Map(rows.map((r) => [r.interval, r.count]))
// intervals are ordered newest to oldest: [current, -1h, -2h]
// simulate dropping oldest intervals one at a time
let running = intervals.reduce((sum, i) => sum + (counts.get(i) ?? 0), 0)
for (let i = intervals.length - 1; i >= 0; i--) {
running -= counts.get(intervals[i]) ?? 0
if (running < limit) {
// interval at index i rolls out of the window (intervals.length - i) hours from the current hour start
const hours = intervals.length - i
return Math.ceil((hours * 3_600_000 - (now % 3_600_000)) / 1000)
}
}
return Math.ceil((3_600_000 - (now % 3_600_000)) / 1000)
}
function buildYYYYMMDD(timestamp: number) {
return new Date(timestamp)
.toISOString()

View File

@@ -1,92 +0,0 @@
import { describe, expect, test } from "bun:test"
import { getRetryAfterDay, getRetryAfterHour } from "../src/routes/zen/util/rateLimiter"
describe("getRetryAfterDay", () => {
test("returns full day at midnight UTC", () => {
const midnight = Date.UTC(2026, 0, 15, 0, 0, 0, 0)
expect(getRetryAfterDay(midnight)).toBe(86_400)
})
test("returns remaining seconds until next UTC day", () => {
const noon = Date.UTC(2026, 0, 15, 12, 0, 0, 0)
expect(getRetryAfterDay(noon)).toBe(43_200)
})
test("rounds up to nearest second", () => {
const almost = Date.UTC(2026, 0, 15, 23, 59, 59, 500)
expect(getRetryAfterDay(almost)).toBe(1)
})
})
describe("getRetryAfterHour", () => {
// 14:30:00 UTC — 30 minutes into the current hour
const now = Date.UTC(2026, 0, 15, 14, 30, 0, 0)
const intervals = ["2026011514", "2026011513", "2026011512"]
test("waits 3 hours when all usage is in current hour", () => {
const rows = [{ interval: "2026011514", count: 10 }]
// only current hour has usage — it won't leave the window for 3 hours from hour start
// 3 * 3600 - 1800 = 9000s
expect(getRetryAfterHour(rows, intervals, 10, now)).toBe(9000)
})
test("waits 1 hour when dropping oldest interval is sufficient", () => {
const rows = [
{ interval: "2026011514", count: 2 },
{ interval: "2026011512", count: 10 },
]
// total=12, drop oldest (-2h, count=10) -> 2 < 10
// hours = 3 - 2 = 1 -> 1 * 3600 - 1800 = 1800s
expect(getRetryAfterHour(rows, intervals, 10, now)).toBe(1800)
})
test("waits 2 hours when usage spans oldest two intervals", () => {
const rows = [
{ interval: "2026011513", count: 8 },
{ interval: "2026011512", count: 5 },
]
// total=13, drop -2h (5) -> 8, 8 >= 8, drop -1h (8) -> 0 < 8
// hours = 3 - 1 = 2 -> 2 * 3600 - 1800 = 5400s
expect(getRetryAfterHour(rows, intervals, 8, now)).toBe(5400)
})
test("waits 1 hour when oldest interval alone pushes over limit", () => {
const rows = [
{ interval: "2026011514", count: 1 },
{ interval: "2026011513", count: 1 },
{ interval: "2026011512", count: 10 },
]
// total=12, drop -2h (10) -> 2 < 10
// hours = 3 - 2 = 1 -> 1800s
expect(getRetryAfterHour(rows, intervals, 10, now)).toBe(1800)
})
test("waits 2 hours when middle interval keeps total over limit", () => {
const rows = [
{ interval: "2026011514", count: 4 },
{ interval: "2026011513", count: 4 },
{ interval: "2026011512", count: 4 },
]
// total=12, drop -2h (4) -> 8, 8 >= 5, drop -1h (4) -> 4 < 5
// hours = 3 - 1 = 2 -> 5400s
expect(getRetryAfterHour(rows, intervals, 5, now)).toBe(5400)
})
test("rounds up to nearest second", () => {
const offset = Date.UTC(2026, 0, 15, 14, 30, 0, 500)
const rows = [
{ interval: "2026011514", count: 2 },
{ interval: "2026011512", count: 10 },
]
// hours=1 -> 3_600_000 - 1_800_500 = 1_799_500ms -> ceil(1799.5) = 1800
expect(getRetryAfterHour(rows, intervals, 10, offset)).toBe(1800)
})
test("fallback returns time until next hour when rows are empty", () => {
// edge case: rows empty but function called (shouldn't happen in practice)
// loop drops all zeros, running stays 0 which is < any positive limit on first iteration
const rows: { interval: string; count: number }[] = []
// drop -2h (0) -> 0 < 1 -> hours = 3 - 2 = 1 -> 1800s
expect(getRetryAfterHour(rows, intervals, 1, now)).toBe(1800)
})
})

View File

@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/console-core",
"version": "1.1.56",
"version": "1.1.54",
"private": true,
"type": "module",
"license": "MIT",
@@ -19,7 +19,6 @@
"zod": "catalog:"
},
"exports": {
"./*.js": "./src/*.ts",
"./*": "./src/*"
},
"scripts": {

View File

@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-function",
"version": "1.1.56",
"version": "1.1.54",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",

View File

@@ -17,7 +17,8 @@ export default {
)
return
let data = {
let metrics = {
event_type: "completions",
"cf.continent": event.event.request.cf?.continent,
"cf.country": event.event.request.cf?.country,
"cf.city": event.event.request.cf?.city,
@@ -30,28 +31,22 @@ export default {
status: event.event.response?.status ?? 0,
ip: event.event.request.headers["x-real-ip"],
}
const time = new Date(event.eventTimestamp ?? Date.now()).toISOString()
const events = []
for (const log of event.logs) {
for (const message of log.message) {
if (!message.startsWith("_metric:")) continue
const json = JSON.parse(message.slice(8))
data = { ...data, ...json }
if ("llm.error.code" in json) {
events.push({ time, data: { ...data, event_type: "llm.error" } })
}
metrics = { ...metrics, ...JSON.parse(message.slice(8)) }
}
}
events.push({ time, data: { ...data, event_type: "completions" } })
console.log(JSON.stringify(data, null, 2))
console.log(JSON.stringify(metrics, null, 2))
const ret = await fetch("https://api.honeycomb.io/1/batch/zen", {
const ret = await fetch("https://api.honeycomb.io/1/events/zen", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Honeycomb-Event-Time": (event.eventTimestamp ?? Date.now()).toString(),
"X-Honeycomb-Team": Resource.HONEYCOMB_API_KEY.value,
},
body: JSON.stringify(events),
body: JSON.stringify(metrics),
})
console.log(ret.status)
console.log(await ret.text())

View File

@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-mail",
"version": "1.1.56",
"version": "1.1.54",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",

View File

@@ -1,7 +1,7 @@
{
"name": "@opencode-ai/desktop",
"private": true,
"version": "1.1.56",
"version": "1.1.54",
"type": "module",
"license": "MIT",
"scripts": {

View File

@@ -1,8 +1,9 @@
use tauri::{AppHandle, Manager, path::BaseDirectory};
use tauri_plugin_shell::{
ShellExt,
process::{Command, CommandChild, CommandEvent},
process::{Command, CommandChild, CommandEvent, TerminatedPayload},
};
use tokio::sync::oneshot;
use crate::{LogState, constants::MAX_LOG_ENTRIES};
@@ -188,22 +189,58 @@ pub fn create_command(app: &tauri::AppHandle, args: &str) -> Command {
};
}
pub fn serve(app: &AppHandle, hostname: &str, port: u32, password: &str) -> CommandChild {
pub fn serve(
app: &AppHandle,
hostname: &str,
port: u32,
password: &str,
) -> (CommandChild, oneshot::Receiver<TerminatedPayload>) {
let log_state = app.state::<LogState>();
let log_state_clone = log_state.inner().clone();
let (exit_tx, exit_rx) = oneshot::channel::<TerminatedPayload>();
println!("spawning sidecar on port {port}");
let (mut rx, child) = create_command(
app,
format!("serve --hostname {hostname} --port {port}").as_str(),
)
if let Ok(mut logs) = log_state_clone.0.lock() {
let args = format!(
"--print-logs --log-level WARN serve --hostname {hostname} --port {port}"
);
#[cfg(target_os = "windows")]
{
logs.push_back(format!("[SPAWN] sidecar=opencode-cli args=\"{args}\"\n"));
}
#[cfg(not(target_os = "windows"))]
{
let sidecar = get_sidecar_path(app);
let shell = get_user_shell();
let cmd = if shell.ends_with("/nu") {
format!("^\"{}\" {}", sidecar.display(), args)
} else {
format!("\"{}\" {}", sidecar.display(), args)
};
logs.push_back(format!(
"[SPAWN] shell=\"{shell}\" argv=\"-il -c {cmd}\"\n"
));
}
while logs.len() > MAX_LOG_ENTRIES {
logs.pop_front();
}
}
let args = format!("--print-logs --log-level WARN serve --hostname {hostname} --port {port}");
let (mut rx, child) = create_command(app, &args)
.env("OPENCODE_SERVER_USERNAME", "opencode")
.env("OPENCODE_SERVER_PASSWORD", password)
.spawn()
.expect("Failed to spawn opencode");
tokio::spawn(async move {
let mut exit_tx = Some(exit_tx);
while let Some(event) = rx.recv().await {
match event {
CommandEvent::Stdout(line_bytes) => {
@@ -232,10 +269,35 @@ pub fn serve(app: &AppHandle, hostname: &str, port: u32, password: &str) -> Comm
}
}
}
CommandEvent::Error(err) => {
eprintln!("{err}");
if let Ok(mut logs) = log_state_clone.0.lock() {
logs.push_back(format!("[ERROR] {err}\n"));
while logs.len() > MAX_LOG_ENTRIES {
logs.pop_front();
}
}
}
CommandEvent::Terminated(payload) => {
if let Ok(mut logs) = log_state_clone.0.lock() {
logs.push_back(format!(
"[EXIT] code={:?} signal={:?}\n",
payload.code, payload.signal
));
while logs.len() > MAX_LOG_ENTRIES {
logs.pop_front();
}
}
if let Some(tx) = exit_tx.take() {
let _ = tx.send(payload);
}
}
_ => {}
}
}
});
child
(child, exit_rx)
}

View File

@@ -20,9 +20,9 @@ use std::{
env,
net::TcpListener,
path::PathBuf,
process::Command,
sync::{Arc, Mutex},
time::Duration,
process::Command,
};
use tauri::{AppHandle, Manager, RunEvent, State, ipc::Channel};
#[cfg(any(target_os = "linux", all(debug_assertions, windows)))]
@@ -152,12 +152,12 @@ fn check_app_exists(app_name: &str) -> bool {
{
check_windows_app(app_name)
}
#[cfg(target_os = "macos")]
{
check_macos_app(app_name)
}
#[cfg(target_os = "linux")]
{
check_linux_app(app_name)
@@ -165,165 +165,11 @@ fn check_app_exists(app_name: &str) -> bool {
}
#[cfg(target_os = "windows")]
fn check_windows_app(_app_name: &str) -> bool {
fn check_windows_app(app_name: &str) -> bool {
// Check if command exists in PATH, including .exe
return true;
}
#[cfg(target_os = "windows")]
fn resolve_windows_app_path(app_name: &str) -> Option<String> {
use std::path::{Path, PathBuf};
// Try to find the command using 'where'
let output = Command::new("where").arg(app_name).output().ok()?;
if !output.status.success() {
return None;
}
let paths = String::from_utf8_lossy(&output.stdout)
.lines()
.map(str::trim)
.filter(|line| !line.is_empty())
.map(PathBuf::from)
.collect::<Vec<_>>();
let has_ext = |path: &Path, ext: &str| {
path.extension()
.and_then(|v| v.to_str())
.map(|v| v.eq_ignore_ascii_case(ext))
.unwrap_or(false)
};
if let Some(path) = paths.iter().find(|path| has_ext(path, "exe")) {
return Some(path.to_string_lossy().to_string());
}
let resolve_cmd = |path: &Path| -> Option<String> {
let content = std::fs::read_to_string(path).ok()?;
for token in content.split('"') {
let lower = token.to_ascii_lowercase();
if !lower.contains(".exe") {
continue;
}
if let Some(index) = lower.find("%~dp0") {
let base = path.parent()?;
let suffix = &token[index + 5..];
let mut resolved = PathBuf::from(base);
for part in suffix.replace('/', "\\").split('\\') {
if part.is_empty() || part == "." {
continue;
}
if part == ".." {
let _ = resolved.pop();
continue;
}
resolved.push(part);
}
if resolved.exists() {
return Some(resolved.to_string_lossy().to_string());
}
}
let resolved = PathBuf::from(token);
if resolved.exists() {
return Some(resolved.to_string_lossy().to_string());
}
}
None
};
for path in &paths {
if has_ext(path, "cmd") || has_ext(path, "bat") {
if let Some(resolved) = resolve_cmd(path) {
return Some(resolved);
}
}
if path.extension().is_none() {
let cmd = path.with_extension("cmd");
if cmd.exists() {
if let Some(resolved) = resolve_cmd(&cmd) {
return Some(resolved);
}
}
let bat = path.with_extension("bat");
if bat.exists() {
if let Some(resolved) = resolve_cmd(&bat) {
return Some(resolved);
}
}
}
}
let key = app_name
.chars()
.filter(|v| v.is_ascii_alphanumeric())
.flat_map(|v| v.to_lowercase())
.collect::<String>();
if !key.is_empty() {
for path in &paths {
let dirs = [
path.parent(),
path.parent().and_then(|dir| dir.parent()),
path.parent()
.and_then(|dir| dir.parent())
.and_then(|dir| dir.parent()),
];
for dir in dirs.into_iter().flatten() {
if let Ok(entries) = std::fs::read_dir(dir) {
for entry in entries.flatten() {
let candidate = entry.path();
if !has_ext(&candidate, "exe") {
continue;
}
let Some(stem) = candidate.file_stem().and_then(|v| v.to_str()) else {
continue;
};
let name = stem
.chars()
.filter(|v| v.is_ascii_alphanumeric())
.flat_map(|v| v.to_lowercase())
.collect::<String>();
if name.contains(&key) || key.contains(&name) {
return Some(candidate.to_string_lossy().to_string());
}
}
}
}
}
}
paths.first().map(|path| path.to_string_lossy().to_string())
}
#[tauri::command]
#[specta::specta]
fn resolve_app_path(app_name: &str) -> Option<String> {
#[cfg(target_os = "windows")]
{
resolve_windows_app_path(app_name)
}
#[cfg(not(target_os = "windows"))]
{
// On macOS/Linux, just return the app_name as-is since
// the opener plugin handles them correctly
Some(app_name.to_string())
}
}
#[cfg(target_os = "macos")]
fn check_macos_app(app_name: &str) -> bool {
// Check common installation locations
@@ -335,13 +181,13 @@ fn check_macos_app(app_name: &str) -> bool {
if let Ok(home) = std::env::var("HOME") {
app_locations.push(format!("{}/Applications/{}.app", home, app_name));
}
for location in app_locations {
if std::path::Path::new(&location).exists() {
return true;
}
}
// Also check if command exists in PATH
Command::new("which")
.arg(app_name)
@@ -405,8 +251,7 @@ pub fn run() {
get_display_backend,
set_display_backend,
markdown::parse_markdown_command,
check_app_exists,
resolve_app_path
check_app_exists
])
.events(tauri_specta::collect_events![LoadingWindowComplete])
.error_handling(tauri_specta::ErrorHandlingMode::Throw);
@@ -519,15 +364,26 @@ async fn initialize(app: AppHandle) {
let app = app.clone();
Some(
async move {
let Ok(Ok(_)) = timeout(Duration::from_secs(30), health_check.0).await
else {
let _ = child.kill();
return Err(format!(
"Failed to spawn OpenCode Server. Logs:\n{}",
get_logs(app.clone()).await.unwrap()
));
let res = timeout(Duration::from_secs(30), health_check.0).await;
let err = match res {
Ok(Ok(Ok(()))) => None,
Ok(Ok(Err(e))) => Some(e),
Ok(Err(e)) => Some(format!("Health check task failed: {e}")),
Err(_) => Some("Health check timed out".to_string()),
};
if let Some(err) = err {
let _ = child.kill();
let logs = get_logs(app.clone())
.await
.unwrap_or_else(|e| format!("[DESKTOP] Failed to read sidecar logs: {e}\n"));
return Err(format!(
"Failed to spawn OpenCode Server ({err}). Logs:\n{logs}"
));
}
println!("CLI health check OK");
#[cfg(windows)]

View File

@@ -70,26 +70,43 @@ pub fn spawn_local_server(
port: u32,
password: String,
) -> (CommandChild, HealthCheck) {
let child = cli::serve(&app, &hostname, port, &password);
let (child, exit) = cli::serve(&app, &hostname, port, &password);
let health_check = HealthCheck(tokio::spawn(async move {
let url = format!("http://{hostname}:{port}");
let timestamp = Instant::now();
loop {
tokio::time::sleep(Duration::from_millis(100)).await;
if check_health(&url, Some(&password)).await {
println!("Server ready after {:?}", timestamp.elapsed());
break;
let ready = async {
loop {
tokio::time::sleep(Duration::from_millis(100)).await;
if check_health(&url, Some(&password)).await {
println!("Server ready after {:?}", timestamp.elapsed());
return Ok(());
}
}
};
let terminated = async {
match exit.await {
Ok(payload) => Err(format!(
"Sidecar terminated before becoming healthy (code={:?} signal={:?})",
payload.code, payload.signal
)),
Err(_) => Err("Sidecar terminated before becoming healthy".to_string()),
}
};
tokio::select! {
res = ready => res,
res = terminated => res,
}
}));
(child, health_check)
}
pub struct HealthCheck(pub JoinHandle<()>);
pub struct HealthCheck(pub JoinHandle<Result<(), String>>);
pub async fn check_health(url: &str, password: Option<&str>) -> bool {
let Ok(url) = reqwest::Url::parse(url) else {

View File

@@ -14,7 +14,6 @@ export const commands = {
setDisplayBackend: (backend: LinuxDisplayBackend) => __TAURI_INVOKE<null>("set_display_backend", { backend }),
parseMarkdownCommand: (markdown: string) => __TAURI_INVOKE<string>("parse_markdown_command", { markdown }),
checkAppExists: (appName: string) => __TAURI_INVOKE<boolean>("check_app_exists", { appName }),
resolveAppPath: (appName: string) => __TAURI_INVOKE<string | null>("resolve_app_path", { appName }),
};
/** Events */

View File

@@ -98,12 +98,7 @@ const createPlatform = (password: Accessor<string | null>): Platform => ({
void shellOpen(url).catch(() => undefined)
},
async openPath(path: string, app?: string) {
const os = ostype()
if (os === "windows" && app) {
const resolvedApp = await commands.resolveAppPath(app)
return openerOpenPath(path, resolvedApp || app)
}
openPath(path: string, app?: string) {
return openerOpenPath(path, app)
},

View File

@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/enterprise",
"version": "1.1.56",
"version": "1.1.54",
"private": true,
"type": "module",
"license": "MIT",

View File

@@ -1,7 +1,7 @@
id = "opencode"
name = "OpenCode"
description = "The open source coding agent."
version = "1.1.56"
version = "1.1.54"
schema_version = 1
authors = ["Anomaly"]
repository = "https://github.com/anomalyco/opencode"
@@ -11,26 +11,26 @@ name = "OpenCode"
icon = "./icons/opencode.svg"
[agent_servers.opencode.targets.darwin-aarch64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.56/opencode-darwin-arm64.zip"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.54/opencode-darwin-arm64.zip"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.darwin-x86_64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.56/opencode-darwin-x64.zip"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.54/opencode-darwin-x64.zip"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.linux-aarch64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.56/opencode-linux-arm64.tar.gz"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.54/opencode-linux-arm64.tar.gz"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.linux-x86_64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.56/opencode-linux-x64.tar.gz"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.54/opencode-linux-x64.tar.gz"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.windows-x86_64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.56/opencode-windows-x64.zip"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.54/opencode-windows-x64.zip"
cmd = "./opencode.exe"
args = ["acp"]

View File

@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/function",
"version": "1.1.56",
"version": "1.1.54",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",

View File

@@ -2,4 +2,4 @@ preload = ["@opentui/solid/preload"]
[test]
preload = ["./test/preload.ts"]
timeout = 30000 # 30 seconds - allow time for package installation
timeout = 10000 # 10 seconds (default is 5000ms)

View File

@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.1.56",
"version": "1.1.54",
"name": "opencode",
"type": "module",
"license": "MIT",

View File

@@ -1,6 +1,6 @@
You are a helpful AI assistant tasked with summarizing conversations.
When asked to summarize, provide a detailed but concise summary of the conversation.
When asked to summarize, provide a detailed but concise summary of the conversation.
Focus on information that would be helpful for continuing the conversation, including:
- What was done
- What is currently being worked on
@@ -10,5 +10,3 @@ Focus on information that would be helpful for continuing the conversation, incl
- Important technical decisions and why they were made
Your summary should be comprehensive enough to provide context but concise enough to be quickly understood.
Do not respond to any questions in the conversation, only output the summary.

View File

@@ -141,7 +141,7 @@ export function Session() {
})
const dimensions = useTerminalDimensions()
const [sidebar, setSidebar] = kv.signal<"auto" | "hide">("sidebar", "auto")
const [sidebar, setSidebar] = kv.signal<"auto" | "hide">("sidebar", "hide")
const [sidebarOpen, setSidebarOpen] = createSignal(false)
const [conceal, setConceal] = createSignal(true)
const [showThinking, setShowThinking] = kv.signal("thinking_visibility", true)

View File

@@ -57,8 +57,6 @@ Use best judgement when processing input.
**Performance** - Only flag if obviously problematic.
- O(n²) on unbounded data, N+1 queries, blocking I/O on hot paths
**Behavior Changes** - If a behavioral change is introduced, raise it (especially if it's possibly unintentional).
---
## Before You Flag Something

View File

@@ -1161,12 +1161,6 @@ export namespace Config {
.object({
auto: z.boolean().optional().describe("Enable automatic compaction when context is full (default: true)"),
prune: z.boolean().optional().describe("Enable pruning of old tool outputs (default: true)"),
reserved: z
.number()
.int()
.min(0)
.optional()
.describe("Token buffer for compaction. Leaves enough window to avoid overflow during compaction."),
})
.optional(),
experimental: z

View File

@@ -211,12 +211,7 @@ export namespace Provider {
const awsWebIdentityTokenFile = Env.get("AWS_WEB_IDENTITY_TOKEN_FILE")
const containerCreds = Boolean(
process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI || process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI,
)
if (!profile && !awsAccessKeyId && !awsBearerToken && !awsWebIdentityTokenFile && !containerCreds)
return { autoload: false }
if (!profile && !awsAccessKeyId && !awsBearerToken && !awsWebIdentityTokenFile) return { autoload: false }
const providerOptions: AmazonBedrockProviderSettings = {
region: defaultRegion,

View File

@@ -5,7 +5,6 @@ import type { JSONSchema } from "zod/v4/core"
import type { Provider } from "./provider"
import type { ModelsDev } from "./models"
import { iife } from "@/util/iife"
import { Flag } from "@/flag/flag"
type Modality = NonNullable<ModelsDev.Model["modalities"]>["input"][number]
@@ -18,8 +17,6 @@ function mimeToModality(mime: string): Modality | undefined {
}
export namespace ProviderTransform {
export const OUTPUT_TOKEN_MAX = Flag.OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX || 32_000
// Maps npm package to the key the AI SDK expects for providerOptions
function sdkKey(npm: string): string | undefined {
switch (npm) {
@@ -726,8 +723,29 @@ export namespace ProviderTransform {
return { [key]: options }
}
export function maxOutputTokens(model: Provider.Model): number {
return Math.min(model.limit.output, OUTPUT_TOKEN_MAX) || OUTPUT_TOKEN_MAX
export function maxOutputTokens(
npm: string,
options: Record<string, any>,
modelLimit: number,
globalLimit: number,
): number {
const modelCap = modelLimit || globalLimit
const standardLimit = Math.min(modelCap, globalLimit)
if (npm === "@ai-sdk/anthropic" || npm === "@ai-sdk/google-vertex/anthropic") {
const thinking = options?.["thinking"]
const budgetTokens = typeof thinking?.["budgetTokens"] === "number" ? thinking["budgetTokens"] : 0
const enabled = thinking?.["type"] === "enabled"
if (enabled && budgetTokens > 0) {
// Return text tokens so that text + thinking <= model cap, preferring 32k text when possible.
if (budgetTokens + standardLimit <= modelCap) {
return standardLimit
}
return modelCap - budgetTokens
}
}
return standardLimit
}
export function schema(model: Provider.Model, schema: JSONSchema.BaseSchema | JSONSchema7): JSONSchema7 {

View File

@@ -78,9 +78,6 @@ export namespace Server {
})
})
.use((c, next) => {
// Allow CORS preflight requests to succeed without auth.
// Browser clients sending Authorization headers will preflight with OPTIONS.
if (c.req.method === "OPTIONS") return next()
const password = Flag.OPENCODE_SERVER_PASSWORD
if (!password) return next()
const username = Flag.OPENCODE_SERVER_USERNAME ?? "opencode"
@@ -110,12 +107,7 @@ export namespace Server {
if (input.startsWith("http://localhost:")) return input
if (input.startsWith("http://127.0.0.1:")) return input
if (
input === "tauri://localhost" ||
input === "http://tauri.localhost" ||
input === "https://tauri.localhost"
)
return input
if (input === "tauri://localhost" || input === "http://tauri.localhost") return input
// *.opencode.ai (https only, adjust if needed)
if (/^https:\/\/([a-z0-9-]+\.)*opencode\.ai$/.test(input)) {

View File

@@ -6,6 +6,7 @@ import { Instance } from "../project/instance"
import { Provider } from "../provider/provider"
import { MessageV2 } from "./message-v2"
import z from "zod"
import { SessionPrompt } from "./prompt"
import { Token } from "../util/token"
import { Log } from "../util/log"
import { SessionProcessor } from "./processor"
@@ -13,7 +14,6 @@ import { fn } from "@/util/fn"
import { Agent } from "@/agent/agent"
import { Plugin } from "@/plugin"
import { Config } from "@/config/config"
import { ProviderTransform } from "@/provider/transform"
export namespace SessionCompaction {
const log = Log.create({ service: "session.compaction" })
@@ -27,22 +27,15 @@ export namespace SessionCompaction {
),
}
const COMPACTION_BUFFER = 20_000
export async function isOverflow(input: { tokens: MessageV2.Assistant["tokens"]; model: Provider.Model }) {
const config = await Config.get()
if (config.compaction?.auto === false) return false
const context = input.model.limit.context
if (context === 0) return false
const count =
input.tokens.total ||
input.tokens.input + input.tokens.output + input.tokens.cache.read + input.tokens.cache.write
const reserved =
config.compaction?.reserved ?? Math.min(COMPACTION_BUFFER, ProviderTransform.maxOutputTokens(input.model))
const usable = input.model.limit.input ? input.model.limit.input - reserved : context - reserved
return count >= usable
const count = input.tokens.input + input.tokens.cache.read + input.tokens.output
const output = Math.min(input.model.limit.output, SessionPrompt.OUTPUT_TOKEN_MAX) || SessionPrompt.OUTPUT_TOKEN_MAX
const usable = input.model.limit.input || context - output
return count > usable
}
export const PRUNE_MINIMUM = 20_000
@@ -146,34 +139,8 @@ export namespace SessionCompaction {
{ sessionID: input.sessionID },
{ context: [], prompt: undefined },
)
const defaultPrompt = `Provide a detailed prompt for continuing our conversation above.
Focus on information that would be helpful for continuing the conversation, including what we did, what we're doing, which files we're working on, and what we're going to do next.
The summary that you construct will be used so that another agent can read it and continue the work.
When constructing the summary, try to stick to this template:
---
## Goal
[What goal(s) is the user trying to accomplish?]
## Instructions
- [What important instructions did the user give you that are relevant]
- [If there is a plan or spec, include information about it so next agent can continue using it]
## Discoveries
[What notable things were learned during this conversation that would be useful for the next agent to know when continuing the work]
## Accomplished
[What work has been completed, what work is still in progress, and what work is left?]
## Relevant files / directories
[Construct a structured list of relevant files that have been read, edited, or created that pertain to the task at hand. If all the files in a directory are relevant, include the path to the directory.]
---`
const defaultPrompt =
"Provide a detailed prompt for continuing our conversation above. Focus on information that would be helpful for continuing the conversation, including what we did, what we're doing, which files we're working on, and what we're going to do next considering new session will not have access to our conversation."
const promptText = compacting.prompt ?? [defaultPrompt, ...compacting.context].join("\n\n")
const result = await processor.process({
user: userMessage,
@@ -214,7 +181,7 @@ When constructing the summary, try to stick to this template:
sessionID: input.sessionID,
type: "text",
synthetic: true,
text: "Continue if you have next steps, or stop and ask for clarification if you are unsure how to proceed.",
text: "Continue if you have next steps",
time: {
start: Date.now(),
end: Date.now(),

View File

@@ -4,7 +4,7 @@ import { BusEvent } from "@/bus/bus-event"
import { Bus } from "@/bus"
import { Decimal } from "decimal.js"
import z from "zod"
import { type ProviderMetadata } from "ai"
import { type LanguageModelUsage, type ProviderMetadata } from "ai"
import { Config } from "../config/config"
import { Flag } from "../flag/flag"
import { Identifier } from "../id/id"
@@ -22,8 +22,6 @@ import { Snapshot } from "@/snapshot"
import type { Provider } from "@/provider/provider"
import { PermissionNext } from "@/permission/next"
import { Global } from "@/global"
import type { LanguageModelV2Usage } from "@ai-sdk/provider"
import { iife } from "@/util/iife"
export namespace Session {
const log = Log.create({ service: "session" })
@@ -441,58 +439,34 @@ export namespace Session {
export const getUsage = fn(
z.object({
model: z.custom<Provider.Model>(),
usage: z.custom<LanguageModelV2Usage>(),
usage: z.custom<LanguageModelUsage>(),
metadata: z.custom<ProviderMetadata>().optional(),
}),
(input) => {
const cacheReadInputTokens = input.usage.cachedInputTokens ?? 0
const cacheWriteInputTokens = (input.metadata?.["anthropic"]?.["cacheCreationInputTokens"] ??
// @ts-expect-error
input.metadata?.["bedrock"]?.["usage"]?.["cacheWriteInputTokens"] ??
// @ts-expect-error
input.metadata?.["venice"]?.["usage"]?.["cacheCreationInputTokens"] ??
0) as number
const excludesCachedTokens = !!(input.metadata?.["anthropic"] || input.metadata?.["bedrock"])
const adjustedInputTokens = excludesCachedTokens
? (input.usage.inputTokens ?? 0)
: (input.usage.inputTokens ?? 0) - cacheReadInputTokens - cacheWriteInputTokens
const safe = (value: number) => {
if (!Number.isFinite(value)) return 0
return value
}
const inputTokens = safe(input.usage.inputTokens ?? 0)
const outputTokens = safe(input.usage.outputTokens ?? 0)
const reasoningTokens = safe(input.usage.reasoningTokens ?? 0)
const cacheReadInputTokens = safe(input.usage.cachedInputTokens ?? 0)
const cacheWriteInputTokens = safe(
(input.metadata?.["anthropic"]?.["cacheCreationInputTokens"] ??
// @ts-expect-error
input.metadata?.["bedrock"]?.["usage"]?.["cacheWriteInputTokens"] ??
// @ts-expect-error
input.metadata?.["venice"]?.["usage"]?.["cacheCreationInputTokens"] ??
0) as number,
)
// OpenRouter provides inputTokens as the total count of input tokens (including cached).
// AFAIK other providers (OpenRouter/OpenAI/Gemini etc.) do it the same way e.g. vercel/ai#8794 (comment)
// Anthropic does it differently though - inputTokens doesn't include cached tokens.
// It looks like OpenCode's cost calculation assumes all providers return inputTokens the same way Anthropic does (I'm guessing getUsage logic was originally implemented with anthropic), so it's causing incorrect cost calculation for OpenRouter and others.
const excludesCachedTokens = !!(input.metadata?.["anthropic"] || input.metadata?.["bedrock"])
const adjustedInputTokens = safe(
excludesCachedTokens ? inputTokens : inputTokens - cacheReadInputTokens - cacheWriteInputTokens,
)
const total = iife(() => {
// Anthropic doesn't provide total_tokens, also ai sdk will vastly undercount if we
// don't compute from components
if (
input.model.api.npm === "@ai-sdk/anthropic" ||
input.model.api.npm === "@ai-sdk/amazon-bedrock" ||
input.model.api.npm === "@ai-sdk/google-vertex/anthropic"
) {
return adjustedInputTokens + outputTokens + cacheReadInputTokens + cacheWriteInputTokens
}
return input.usage.totalTokens
})
const tokens = {
total,
input: adjustedInputTokens,
output: outputTokens,
reasoning: reasoningTokens,
input: safe(adjustedInputTokens),
output: safe(input.usage.outputTokens ?? 0),
reasoning: safe(input.usage?.reasoningTokens ?? 0),
cache: {
write: cacheWriteInputTokens,
read: cacheReadInputTokens,
write: safe(cacheWriteInputTokens),
read: safe(cacheReadInputTokens),
},
}

View File

@@ -25,7 +25,8 @@ import { Auth } from "@/auth"
export namespace LLM {
const log = Log.create({ service: "llm" })
export const OUTPUT_TOKEN_MAX = ProviderTransform.OUTPUT_TOKEN_MAX
export const OUTPUT_TOKEN_MAX = Flag.OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX || 32_000
export type StreamInput = {
user: MessageV2.User
@@ -148,7 +149,14 @@ export namespace LLM {
)
const maxOutputTokens =
isCodex || provider.id.includes("github-copilot") ? undefined : ProviderTransform.maxOutputTokens(input.model)
isCodex || provider.id.includes("github-copilot")
? undefined
: ProviderTransform.maxOutputTokens(
input.model.api.npm,
params.options,
input.model.limit.output,
OUTPUT_TOKEN_MAX,
)
const tools = await resolveTools(input)

View File

@@ -210,7 +210,6 @@ export namespace MessageV2 {
snapshot: z.string().optional(),
cost: z.number(),
tokens: z.object({
total: z.number().optional(),
input: z.number(),
output: z.number(),
reasoning: z.number(),
@@ -384,7 +383,6 @@ export namespace MessageV2 {
summary: z.boolean().optional(),
cost: z.number(),
tokens: z.object({
total: z.number().optional(),
input: z.number(),
output: z.number(),
reasoning: z.number(),

View File

@@ -342,9 +342,6 @@ export namespace SessionProcessor {
stack: JSON.stringify(e.stack),
})
const error = MessageV2.fromError(e, { providerID: input.model.providerID })
if (MessageV2.ContextOverflowError.isInstance(error)) {
// TODO: Handle context overflow error
}
const retry = SessionRetry.retryable(error)
if (retry !== undefined) {
attempt++

View File

@@ -52,6 +52,7 @@ globalThis.AI_SDK_LOG_WARNINGS = false
export namespace SessionPrompt {
const log = Log.create({ service: "session.prompt" })
export const OUTPUT_TOKEN_MAX = Flag.OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX || 32_000
const state = Instance.state(
() => {

View File

@@ -59,8 +59,9 @@ export namespace SessionRetry {
}
export function retryable(error: ReturnType<NamedError["toObject"]>) {
// context overflow errors should not be retried
// DO NOT retry context overflow errors
if (MessageV2.ContextOverflowError.isInstance(error)) return undefined
if (MessageV2.APIError.isInstance(error)) {
if (!error.data.isRetryable) return undefined
if (error.data.responseBody?.includes("FreeUsageLimitError"))

View File

@@ -175,6 +175,100 @@ describe("ProviderTransform.options - gpt-5 textVerbosity", () => {
})
})
describe("ProviderTransform.maxOutputTokens", () => {
test("returns 32k when modelLimit > 32k", () => {
const modelLimit = 100000
const result = ProviderTransform.maxOutputTokens("@ai-sdk/openai", {}, modelLimit, OUTPUT_TOKEN_MAX)
expect(result).toBe(OUTPUT_TOKEN_MAX)
})
test("returns modelLimit when modelLimit < 32k", () => {
const modelLimit = 16000
const result = ProviderTransform.maxOutputTokens("@ai-sdk/openai", {}, modelLimit, OUTPUT_TOKEN_MAX)
expect(result).toBe(16000)
})
describe("azure", () => {
test("returns 32k when modelLimit > 32k", () => {
const modelLimit = 100000
const result = ProviderTransform.maxOutputTokens("@ai-sdk/azure", {}, modelLimit, OUTPUT_TOKEN_MAX)
expect(result).toBe(OUTPUT_TOKEN_MAX)
})
test("returns modelLimit when modelLimit < 32k", () => {
const modelLimit = 16000
const result = ProviderTransform.maxOutputTokens("@ai-sdk/azure", {}, modelLimit, OUTPUT_TOKEN_MAX)
expect(result).toBe(16000)
})
})
describe("bedrock", () => {
test("returns 32k when modelLimit > 32k", () => {
const modelLimit = 100000
const result = ProviderTransform.maxOutputTokens("@ai-sdk/amazon-bedrock", {}, modelLimit, OUTPUT_TOKEN_MAX)
expect(result).toBe(OUTPUT_TOKEN_MAX)
})
test("returns modelLimit when modelLimit < 32k", () => {
const modelLimit = 16000
const result = ProviderTransform.maxOutputTokens("@ai-sdk/amazon-bedrock", {}, modelLimit, OUTPUT_TOKEN_MAX)
expect(result).toBe(16000)
})
})
describe("anthropic without thinking options", () => {
test("returns 32k when modelLimit > 32k", () => {
const modelLimit = 100000
const result = ProviderTransform.maxOutputTokens("@ai-sdk/anthropic", {}, modelLimit, OUTPUT_TOKEN_MAX)
expect(result).toBe(OUTPUT_TOKEN_MAX)
})
test("returns modelLimit when modelLimit < 32k", () => {
const modelLimit = 16000
const result = ProviderTransform.maxOutputTokens("@ai-sdk/anthropic", {}, modelLimit, OUTPUT_TOKEN_MAX)
expect(result).toBe(16000)
})
})
describe("anthropic with thinking options", () => {
test("returns 32k when budgetTokens + 32k <= modelLimit", () => {
const modelLimit = 100000
const options = {
thinking: {
type: "enabled",
budgetTokens: 10000,
},
}
const result = ProviderTransform.maxOutputTokens("@ai-sdk/anthropic", options, modelLimit, OUTPUT_TOKEN_MAX)
expect(result).toBe(OUTPUT_TOKEN_MAX)
})
test("returns modelLimit - budgetTokens when budgetTokens + 32k > modelLimit", () => {
const modelLimit = 50000
const options = {
thinking: {
type: "enabled",
budgetTokens: 30000,
},
}
const result = ProviderTransform.maxOutputTokens("@ai-sdk/anthropic", options, modelLimit, OUTPUT_TOKEN_MAX)
expect(result).toBe(20000)
})
test("returns 32k when thinking type is not enabled", () => {
const modelLimit = 100000
const options = {
thinking: {
type: "disabled",
budgetTokens: 10000,
},
}
const result = ProviderTransform.maxOutputTokens("@ai-sdk/anthropic", options, modelLimit, OUTPUT_TOKEN_MAX)
expect(result).toBe(OUTPUT_TOKEN_MAX)
})
})
})
describe("ProviderTransform.schema - gemini array items", () => {
test("adds missing items for array properties", () => {
const geminiModel = {

View File

@@ -15,7 +15,6 @@ function createModel(opts: {
output: number
input?: number
cost?: Provider.Model["cost"]
npm?: string
}): Provider.Model {
return {
id: "test-model",
@@ -35,7 +34,7 @@ function createModel(opts: {
input: { text: true, image: false, audio: false, video: false },
output: { text: true, image: false, audio: false, video: false },
},
api: { npm: opts.npm ?? "@ai-sdk/anthropic" },
api: { npm: "@ai-sdk/anthropic" },
options: {},
} as Provider.Model
}
@@ -71,7 +70,7 @@ describe("session.compaction.isOverflow", () => {
directory: tmp.path,
fn: async () => {
const model = createModel({ context: 100_000, output: 32_000 })
const tokens = { input: 60_000, output: 10_000, reasoning: 0, cache: { read: 10_000, write: 0 } }
const tokens = { input: 50_000, output: 10_000, reasoning: 0, cache: { read: 10_000, write: 0 } }
expect(await SessionCompaction.isOverflow({ tokens, model })).toBe(true)
},
})
@@ -113,86 +112,6 @@ describe("session.compaction.isOverflow", () => {
})
})
// ─── Bug reproduction tests ───────────────────────────────────────────
// These tests demonstrate that when limit.input is set, isOverflow()
// does not subtract any headroom for the next model response. This means
// compaction only triggers AFTER we've already consumed the full input
// budget, leaving zero room for the next API call's output tokens.
//
// Compare: without limit.input, usable = context - output (reserves space).
// With limit.input, usable = limit.input (reserves nothing).
//
// Related issues: #10634, #8089, #11086, #12621
// Open PRs: #6875, #12924
test("BUG: no headroom when limit.input is set — compaction should trigger near boundary but does not", async () => {
await using tmp = await tmpdir()
await Instance.provide({
directory: tmp.path,
fn: async () => {
// Simulate Claude with prompt caching: input limit = 200K, output limit = 32K
const model = createModel({ context: 200_000, input: 200_000, output: 32_000 })
// We've used 198K tokens total. Only 2K under the input limit.
// On the next turn, the full conversation (198K) becomes input,
// plus the model needs room to generate output — this WILL overflow.
const tokens = { input: 180_000, output: 15_000, reasoning: 0, cache: { read: 3_000, write: 0 } }
// count = 180K + 3K + 15K = 198K
// usable = limit.input = 200K (no output subtracted!)
// 198K > 200K = false → no compaction triggered
// WITHOUT limit.input: usable = 200K - 32K = 168K, and 198K > 168K = true ✓
// WITH limit.input: usable = 200K, and 198K > 200K = false ✗
// With 198K used and only 2K headroom, the next turn will overflow.
// Compaction MUST trigger here.
expect(await SessionCompaction.isOverflow({ tokens, model })).toBe(true)
},
})
})
test("BUG: without limit.input, same token count correctly triggers compaction", async () => {
await using tmp = await tmpdir()
await Instance.provide({
directory: tmp.path,
fn: async () => {
// Same model but without limit.input — uses context - output instead
const model = createModel({ context: 200_000, output: 32_000 })
// Same token usage as above
const tokens = { input: 180_000, output: 15_000, reasoning: 0, cache: { read: 3_000, write: 0 } }
// count = 198K
// usable = context - output = 200K - 32K = 168K
// 198K > 168K = true → compaction correctly triggered
const result = await SessionCompaction.isOverflow({ tokens, model })
expect(result).toBe(true) // ← Correct: headroom is reserved
},
})
})
test("BUG: asymmetry — limit.input model allows 30K more usage before compaction than equivalent model without it", async () => {
await using tmp = await tmpdir()
await Instance.provide({
directory: tmp.path,
fn: async () => {
// Two models with identical context/output limits, differing only in limit.input
const withInputLimit = createModel({ context: 200_000, input: 200_000, output: 32_000 })
const withoutInputLimit = createModel({ context: 200_000, output: 32_000 })
// 170K total tokens — well above context-output (168K) but below input limit (200K)
const tokens = { input: 166_000, output: 10_000, reasoning: 0, cache: { read: 5_000, write: 0 } }
const withLimit = await SessionCompaction.isOverflow({ tokens, model: withInputLimit })
const withoutLimit = await SessionCompaction.isOverflow({ tokens, model: withoutInputLimit })
// Both models have identical real capacity — they should agree:
expect(withLimit).toBe(true) // should compact (170K leaves no room for 32K output)
expect(withoutLimit).toBe(true) // correctly compacts (170K > 168K)
},
})
})
test("returns false when model context limit is 0", async () => {
await using tmp = await tmpdir()
await Instance.provide({
@@ -371,53 +290,4 @@ describe("session.getUsage", () => {
expect(result.cost).toBe(3 + 1.5)
})
test.each(["@ai-sdk/anthropic", "@ai-sdk/amazon-bedrock", "@ai-sdk/google-vertex/anthropic"])(
"computes total from components for %s models",
(npm) => {
const model = createModel({ context: 100_000, output: 32_000, npm })
const usage = {
inputTokens: 1000,
outputTokens: 500,
// These providers typically report total as input + output only,
// excluding cache read/write.
totalTokens: 1500,
cachedInputTokens: 200,
}
if (npm === "@ai-sdk/amazon-bedrock") {
const result = Session.getUsage({
model,
usage,
metadata: {
bedrock: {
usage: {
cacheWriteInputTokens: 300,
},
},
},
})
expect(result.tokens.input).toBe(1000)
expect(result.tokens.cache.read).toBe(200)
expect(result.tokens.cache.write).toBe(300)
expect(result.tokens.total).toBe(2000)
return
}
const result = Session.getUsage({
model,
usage,
metadata: {
anthropic: {
cacheCreationInputTokens: 300,
},
},
})
expect(result.tokens.input).toBe(1000)
expect(result.tokens.cache.read).toBe(200)
expect(result.tokens.cache.write).toBe(300)
expect(result.tokens.total).toBe(2000)
},
)
})

View File

@@ -314,7 +314,12 @@ describe("session.llm.stream", () => {
expect(body.stream).toBe(true)
const maxTokens = (body.max_tokens as number | undefined) ?? (body.max_output_tokens as number | undefined)
const expectedMaxTokens = ProviderTransform.maxOutputTokens(resolved)
const expectedMaxTokens = ProviderTransform.maxOutputTokens(
resolved.api.npm,
ProviderTransform.options({ model: resolved, sessionID }),
resolved.limit.output,
LLM.OUTPUT_TOKEN_MAX,
)
expect(maxTokens).toBe(expectedMaxTokens)
const reasoning = (body.reasoningEffort as string | undefined) ?? (body.reasoning_effort as string | undefined)
@@ -437,7 +442,12 @@ describe("session.llm.stream", () => {
expect((body.reasoning as { effort?: string } | undefined)?.effort).toBe("high")
const maxTokens = body.max_output_tokens as number | undefined
const expectedMaxTokens = ProviderTransform.maxOutputTokens(resolved)
const expectedMaxTokens = ProviderTransform.maxOutputTokens(
resolved.api.npm,
ProviderTransform.options({ model: resolved, sessionID }),
resolved.limit.output,
LLM.OUTPUT_TOKEN_MAX,
)
expect(maxTokens).toBe(expectedMaxTokens)
},
})
@@ -555,7 +565,14 @@ describe("session.llm.stream", () => {
expect(capture.url.pathname.endsWith("/messages")).toBe(true)
expect(body.model).toBe(resolved.api.id)
expect(body.max_tokens).toBe(ProviderTransform.maxOutputTokens(resolved))
expect(body.max_tokens).toBe(
ProviderTransform.maxOutputTokens(
resolved.api.npm,
ProviderTransform.options({ model: resolved, sessionID }),
resolved.limit.output,
LLM.OUTPUT_TOKEN_MAX,
),
)
expect(body.temperature).toBe(0.4)
expect(body.top_p).toBe(0.9)
},
@@ -660,7 +677,14 @@ describe("session.llm.stream", () => {
expect(capture.url.pathname).toBe(pathSuffix)
expect(config?.temperature).toBe(0.3)
expect(config?.topP).toBe(0.8)
expect(config?.maxOutputTokens).toBe(ProviderTransform.maxOutputTokens(resolved))
expect(config?.maxOutputTokens).toBe(
ProviderTransform.maxOutputTokens(
resolved.api.npm,
ProviderTransform.options({ model: resolved, sessionID }),
resolved.limit.output,
LLM.OUTPUT_TOKEN_MAX,
),
)
},
})
})

View File

@@ -112,15 +112,6 @@ describe("session.retry.retryable", () => {
const error = wrap("not-json")
expect(SessionRetry.retryable(error)).toBeUndefined()
})
test("does not retry context overflow errors", () => {
const error = new MessageV2.ContextOverflowError({
message: "Input exceeds context window of this model",
responseBody: '{"error":{"code":"context_length_exceeded"}}',
}).toObject() as ReturnType<NamedError["toObject"]>
expect(SessionRetry.retryable(error)).toBeUndefined()
})
})
describe("session.message-v2.fromError", () => {

View File

@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/plugin",
"version": "1.1.56",
"version": "1.1.54",
"type": "module",
"license": "MIT",
"scripts": {

View File

@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/sdk",
"version": "1.1.56",
"version": "1.1.54",
"type": "module",
"license": "MIT",
"scripts": {

View File

@@ -203,7 +203,6 @@ export type AssistantMessage = {
summary?: boolean
cost: number
tokens: {
total?: number
input: number
output: number
reasoning: number
@@ -419,7 +418,6 @@ export type StepFinishPart = {
snapshot?: string
cost: number
tokens: {
total?: number
input: number
output: number
reasoning: number
@@ -1824,10 +1822,6 @@ export type Config = {
* Enable pruning of old tool outputs (default: true)
*/
prune?: boolean
/**
* Token buffer for compaction. Leaves enough window to avoid overflow during compaction.
*/
reserved?: number
}
experimental?: {
disable_paste_summary?: boolean

View File

@@ -6393,9 +6393,6 @@
"tokens": {
"type": "object",
"properties": {
"total": {
"type": "number"
},
"input": {
"type": "number"
},
@@ -7026,9 +7023,6 @@
"tokens": {
"type": "object",
"properties": {
"total": {
"type": "number"
},
"input": {
"type": "number"
},
@@ -9900,12 +9894,6 @@
"prune": {
"description": "Enable pruning of old tool outputs (default: true)",
"type": "boolean"
},
"reserved": {
"description": "Token buffer for compaction. Leaves enough window to avoid overflow during compaction.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
}
},

View File

@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/slack",
"version": "1.1.56",
"version": "1.1.54",
"type": "module",
"license": "MIT",
"scripts": {

View File

@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/ui",
"version": "1.1.56",
"version": "1.1.54",
"type": "module",
"license": "MIT",
"exports": {

View File

@@ -1,6 +1,5 @@
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"
@@ -126,9 +125,11 @@ export function Code<T>(props: CodeProps<T>) {
let wrapper!: HTMLDivElement
let container!: HTMLDivElement
let findInput: HTMLInputElement | undefined
let findBar: HTMLDivElement | undefined
let findOverlay!: HTMLDivElement
let findOverlayFrame: number | undefined
let findOverlayScroll: HTMLElement[] = []
let findScroll: HTMLElement | undefined
let observer: MutationObserver | undefined
let renderToken = 0
let selectionFrame: number | undefined
@@ -158,8 +159,6 @@ export function Code<T>(props: CodeProps<T>) {
let findMode: "highlights" | "overlay" = "overlay"
let findHits: Range[] = []
const [findPos, setFindPos] = createSignal<{ top: number; right: number }>({ top: 8, right: 8 })
const file = createMemo(
() =>
new File<T>(
@@ -292,26 +291,23 @@ export function Code<T>(props: CodeProps<T>) {
setFindIndex(0)
}
const getScrollParent = (el: HTMLElement): HTMLElement | undefined => {
const getScrollParent = (el: HTMLElement): HTMLElement | null => {
let parent = el.parentElement
while (parent) {
const style = getComputedStyle(parent)
if (style.overflowY === "auto" || style.overflowY === "scroll") return parent
parent = parent.parentElement
}
return null
}
const positionFindBar = () => {
if (typeof window === "undefined") return
const root = getScrollParent(wrapper) ?? wrapper
const rect = root.getBoundingClientRect()
const title = parseFloat(getComputedStyle(root).getPropertyValue("--session-title-height"))
const header = Number.isNaN(title) ? 0 : title
setFindPos({
top: Math.round(rect.top) + header - 4,
right: Math.round(window.innerWidth - rect.right) + 8,
})
if (!findBar || !wrapper) return
const scrollTop = findScroll ? findScroll.scrollTop : window.scrollY
findBar.style.position = "absolute"
findBar.style.top = `${scrollTop + 8}px`
findBar.style.right = "8px"
findBar.style.left = ""
}
const scanFind = (root: ShadowRoot, query: string) => {
@@ -430,6 +426,7 @@ export function Code<T>(props: CodeProps<T>) {
}
if (opts?.scroll && active) {
scrollToRange(active)
positionFindBar()
}
return
}
@@ -438,6 +435,7 @@ export function Code<T>(props: CodeProps<T>) {
syncOverlayScroll()
if (opts?.scroll && active) {
scrollToRange(active)
positionFindBar()
}
scheduleOverlay()
}
@@ -466,12 +464,14 @@ export function Code<T>(props: CodeProps<T>) {
return
}
scrollToRange(active)
positionFindBar()
return
}
clearHighlightFind()
syncOverlayScroll()
scrollToRange(active)
positionFindBar()
scheduleOverlay()
}
@@ -484,9 +484,11 @@ export function Code<T>(props: CodeProps<T>) {
findCurrent = host
findTarget = host
findScroll = getScrollParent(wrapper) ?? undefined
if (!findOpen()) setFindOpen(true)
requestAnimationFrame(() => {
applyFind({ scroll: true })
positionFindBar()
findInput?.focus()
findInput?.select()
})
@@ -512,18 +514,18 @@ export function Code<T>(props: CodeProps<T>) {
createEffect(() => {
if (!findOpen()) return
findScroll = getScrollParent(wrapper) ?? undefined
const target = findScroll ?? window
const update = () => positionFindBar()
requestAnimationFrame(update)
window.addEventListener("resize", update, { passive: true })
const root = getScrollParent(wrapper) ?? wrapper
const observer = typeof ResizeObserver === "undefined" ? undefined : new ResizeObserver(() => update())
observer?.observe(root)
const handler = () => positionFindBar()
target.addEventListener("scroll", handler, { passive: true })
window.addEventListener("resize", handler, { passive: true })
handler()
onCleanup(() => {
window.removeEventListener("resize", update)
observer?.disconnect()
target.removeEventListener("scroll", handler)
window.removeEventListener("resize", handler)
findScroll = undefined
})
})
@@ -914,64 +916,6 @@ export function Code<T>(props: CodeProps<T>) {
pendingSelectionEnd = false
})
const FindBar = (barProps: { class: string; style?: ComponentProps<"div">["style"] }) => (
<div class={barProps.class} style={barProps.style} onPointerDown={(e) => e.stopPropagation()}>
<Icon name="magnifying-glass" size="small" class="text-text-weak shrink-0" />
<input
ref={findInput}
placeholder="Find"
value={findQuery()}
class="w-40 bg-transparent outline-none text-14-regular text-text-strong placeholder:text-text-weak"
onInput={(e) => {
setFindQuery(e.currentTarget.value)
setFindIndex(0)
applyFind({ reset: true, scroll: true })
}}
onKeyDown={(e) => {
if (e.key === "Escape") {
e.preventDefault()
closeFind()
return
}
if (e.key !== "Enter") return
e.preventDefault()
stepFind(e.shiftKey ? -1 : 1)
}}
/>
<div class="shrink-0 text-12-regular text-text-weak tabular-nums text-right" style={{ width: "10ch" }}>
{findCount() ? `${findIndex() + 1}/${findCount()}` : "0/0"}
</div>
<div class="flex items-center">
<button
type="button"
class="size-6 grid place-items-center rounded text-text-weak hover:bg-surface-base-hover hover:text-text-strong disabled:opacity-40 disabled:pointer-events-none"
disabled={findCount() === 0}
aria-label="Previous match"
onClick={() => stepFind(-1)}
>
<Icon name="chevron-down" size="small" class="rotate-180" />
</button>
<button
type="button"
class="size-6 grid place-items-center rounded text-text-weak hover:bg-surface-base-hover hover:text-text-strong disabled:opacity-40 disabled:pointer-events-none"
disabled={findCount() === 0}
aria-label="Next match"
onClick={() => stepFind(1)}
>
<Icon name="chevron-down" size="small" />
</button>
</div>
<button
type="button"
class="size-6 grid place-items-center rounded text-text-weak hover:bg-surface-base-hover hover:text-text-strong"
aria-label="Close search"
onClick={closeFind}
>
<Icon name="close-small" size="small" />
</button>
</div>
)
return (
<div
data-component="code"
@@ -992,15 +936,65 @@ export function Code<T>(props: CodeProps<T>) {
}}
>
<Show when={findOpen()}>
<Portal>
<FindBar
class="fixed z-50 flex h-8 items-center gap-2 rounded-md border border-border-base bg-background-base px-3 shadow-md"
style={{
top: `${findPos().top}px`,
right: `${findPos().right}px`,
<div
ref={findBar}
class="z-50 flex h-8 items-center gap-2 rounded-md border border-border-base bg-background-base px-3 shadow-md"
onPointerDown={(e) => e.stopPropagation()}
>
<Icon name="magnifying-glass" size="small" class="text-text-weak shrink-0" />
<input
ref={findInput}
placeholder="Find"
value={findQuery()}
class="w-40 bg-transparent outline-none text-14-regular text-text-strong placeholder:text-text-weak"
onInput={(e) => {
setFindQuery(e.currentTarget.value)
setFindIndex(0)
applyFind({ reset: true, scroll: true })
}}
onKeyDown={(e) => {
if (e.key === "Escape") {
e.preventDefault()
closeFind()
return
}
if (e.key !== "Enter") return
e.preventDefault()
stepFind(e.shiftKey ? -1 : 1)
}}
/>
</Portal>
<div class="shrink-0 text-12-regular text-text-weak tabular-nums text-right" style={{ width: "10ch" }}>
{findCount() ? `${findIndex() + 1}/${findCount()}` : "0/0"}
</div>
<div class="flex items-center">
<button
type="button"
class="size-6 grid place-items-center rounded text-text-weak hover:bg-surface-base-hover hover:text-text-strong disabled:opacity-40 disabled:pointer-events-none"
disabled={findCount() === 0}
aria-label="Previous match"
onClick={() => stepFind(-1)}
>
<Icon name="chevron-down" size="small" class="rotate-180" />
</button>
<button
type="button"
class="size-6 grid place-items-center rounded text-text-weak hover:bg-surface-base-hover hover:text-text-strong disabled:opacity-40 disabled:pointer-events-none"
disabled={findCount() === 0}
aria-label="Next match"
onClick={() => stepFind(1)}
>
<Icon name="chevron-down" size="small" />
</button>
</div>
<button
type="button"
class="size-6 grid place-items-center rounded text-text-weak hover:bg-surface-base-hover hover:text-text-strong"
aria-label="Close search"
onClick={closeFind}
>
<Icon name="close-small" size="small" />
</button>
</div>
</Show>
<div ref={container} />
<div ref={findOverlay} class="pointer-events-none absolute inset-0 z-0" />

View File

@@ -877,74 +877,6 @@ ToolRegistry.register({
const data = useData()
const i18n = useI18n()
const childSessionId = () => props.metadata.sessionId as string | undefined
const href = createMemo(() => {
const sessionId = childSessionId()
if (!sessionId) return
const direct = data.sessionHref?.(sessionId)
if (direct) return direct
if (typeof window === "undefined") return
const path = window.location.pathname
const idx = path.indexOf("/session")
if (idx === -1) return
return `${path.slice(0, idx)}/session/${sessionId}`
})
createEffect(() => {
const sessionId = childSessionId()
if (!sessionId) return
const sync = data.syncSession
if (!sync) return
Promise.resolve(sync(sessionId)).catch(() => undefined)
})
const handleLinkClick = (e: MouseEvent) => {
const sessionId = childSessionId()
const url = href()
if (!sessionId || !url) return
e.stopPropagation()
if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return
const nav = data.navigateToSession
if (!nav || typeof window === "undefined") return
e.preventDefault()
const before = window.location.pathname + window.location.search + window.location.hash
nav(sessionId)
setTimeout(() => {
const after = window.location.pathname + window.location.search + window.location.hash
if (after === before) window.location.assign(url)
}, 50)
}
const trigger = () => (
<div data-slot="basic-tool-tool-info-structured">
<div data-slot="basic-tool-tool-info-main">
<span data-slot="basic-tool-tool-title" class="capitalize">
{i18n.t("ui.tool.agent", { type: props.input.subagent_type || props.tool })}
</span>
<Show when={props.input.description}>
<Switch>
<Match when={href()}>
{(url) => (
<a data-slot="basic-tool-tool-subtitle" class="clickable" href={url()} onClick={handleLinkClick}>
{props.input.description}
</a>
)}
</Match>
<Match when={true}>
<span data-slot="basic-tool-tool-subtitle">{props.input.description}</span>
</Match>
</Switch>
</Show>
</div>
</div>
)
const childToolParts = createMemo(() => {
const sessionId = childSessionId()
if (!sessionId) return []
@@ -992,6 +924,13 @@ ToolRegistry.register({
})
}
const handleSubtitleClick = () => {
const sessionId = childSessionId()
if (sessionId && data.navigateToSession) {
data.navigateToSession(sessionId)
}
}
const renderChildToolPart = () => {
const toolData = childToolPart()
if (!toolData) return null
@@ -1019,7 +958,21 @@ ToolRegistry.register({
<Switch>
<Match when={childPermission()}>
<>
<Show when={childToolPart()} fallback={<BasicTool icon="task" defaultOpen={true} trigger={trigger()} />}>
<Show
when={childToolPart()}
fallback={
<BasicTool
icon="task"
defaultOpen={true}
trigger={{
title: i18n.t("ui.tool.agent", { type: props.input.subagent_type || props.tool }),
titleClass: "capitalize",
subtitle: props.input.description,
}}
onSubtitleClick={handleSubtitleClick}
/>
}
>
{renderChildToolPart()}
</Show>
<div data-component="permission-prompt">
@@ -1038,7 +991,16 @@ ToolRegistry.register({
</>
</Match>
<Match when={true}>
<BasicTool icon="task" defaultOpen={true} trigger={trigger()}>
<BasicTool
icon="task"
defaultOpen={true}
trigger={{
title: i18n.t("ui.tool.agent", { type: props.input.subagent_type || props.tool }),
titleClass: "capitalize",
subtitle: props.input.description,
}}
onSubtitleClick={handleSubtitleClick}
>
<div
ref={autoScroll.scrollRef}
onScroll={autoScroll.handleScroll}

View File

@@ -48,10 +48,6 @@ export type QuestionRejectFn = (input: { requestID: string }) => void
export type NavigateToSessionFn = (sessionID: string) => void
export type SessionHrefFn = (sessionID: string) => string
export type SyncSessionFn = (sessionID: string) => void | Promise<void>
export const { use: useData, provider: DataProvider } = createSimpleContext({
name: "Data",
init: (props: {
@@ -61,8 +57,6 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
onQuestionReply?: QuestionReplyFn
onQuestionReject?: QuestionRejectFn
onNavigateToSession?: NavigateToSessionFn
onSessionHref?: SessionHrefFn
onSyncSession?: SyncSessionFn
}) => {
return {
get store() {
@@ -75,8 +69,6 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
replyToQuestion: props.onQuestionReply,
rejectQuestion: props.onQuestionReject,
navigateToSession: props.onNavigateToSession,
sessionHref: props.onSessionHref,
syncSession: props.onSyncSession,
}
},
})

View File

@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/util",
"version": "1.1.56",
"version": "1.1.54",
"private": true,
"type": "module",
"license": "MIT",

View File

@@ -2,7 +2,7 @@
"name": "@opencode-ai/web",
"type": "module",
"license": "MIT",
"version": "1.1.56",
"version": "1.1.54",
"scripts": {
"dev": "astro dev",
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",

View File

@@ -460,7 +460,7 @@ permission:
webfetch: deny
---
Only analyze code and suggest changes.
حلل الشفرة فقط واقترح التغييرات.
```
يمكنك ضبط الأذونات لأوامر bash محددة.

View File

@@ -17,6 +17,7 @@ Za ručnu nadogradnju, pokrenite
```bash
$ opencode upgrade 1.0.0
```
Za vraćanje na 0.x, pokrenite

View File

@@ -149,7 +149,7 @@ Neke ugrađene komande kao što su `/undo` i `/redo` trenutno nisu podržane.
:::
- Ugrađeni alati (operacije sa datotekama, naredbe terminala, itd.)
- Prilagođeni alati i slash komande
- Prilagođeni alati i komande kosih crta
- MCP serveri konfigurisani u vašoj OpenCode konfiguraciji
- Pravila specifična za projekat `AGENTS.md`
- Prilagođeni formateri i linteri

View File

@@ -4,42 +4,38 @@ description: Konfigurirajte i koristite specijalizirane agente.
---
Agenti su specijalizirani AI asistenti koji se mogu konfigurirati za specifične zadatke i tokove posla. Oni vam omogućavaju da kreirate fokusirane alate sa prilagođenim upitima, modelima i pristupom alatima.
:::tip
Koristite agenta plana za analizu koda i pregled prijedloga bez ikakvih promjena koda.
:::
Možete se prebacivati između agenata tokom sesije ili ih pozvati spominjanjem `@`.
---
## Vrste
## Vrsta
Postoje dvije vrste agenata u OpenCode; primarni agenti i podagenti.
Postoje dvije vrste agenata u OpenCode; primarni agensi i subagensi.
---
### Primarni agenti
Primarni agenti su glavni pomoćnici s kojima direktno komunicirate. Možete se kretati kroz njih pomoću tipke **Tab** ili vašeg konfigurisanog povezivanja tipki `switch_agent`. Ovi agenti vode vaš glavni razgovor. Pristup alatima se konfiguriše putem dozvola — na primjer, Build ima omogućene sve alate dok je Plan ograničen.
:::tip
Možete koristiti tipku **Tab** za prebacivanje između primarnih agenata tokom sesije.
:::
OpenCode dolazi sa dva ugrađena primarna agenta, **Build** i **Plan**. Pogledat ćemo ih u nastavku.
OpenCode dolazi sa dva ugrađena primarna agenta, **Build** i **Plan**. Hoćemo
pogledajte ove u nastavku.
---
### Subagenti
### Subagent
Subagenti su specijalizovani pomoćnici koje primarni agenti mogu pozvati za određene zadatke. Možete ih i ručno pozvati **@ spominjanjem** u svojim porukama.
OpenCode dolazi sa dva ugrađena subagenta, **General** i **Explore**. Ovo ćemo pogledati u nastavku.
---
## Ugrađeni
## Embedded
OpenCode dolazi sa dva ugrađena primarna agenta i dva ugrađena subagenta.
@@ -47,62 +43,54 @@ OpenCode dolazi sa dva ugrađena primarna agenta i dva ugrađena subagenta.
### Koristi build
_Mode_: `primary`
_Način_: `primary`
Build je **podrazumevani** primarni agent sa svim omogućenim alatima. Ovo je standardni agent za razvojni rad gdje vam je potreban pun pristup operacijama datoteka i sistemskim komandama.
---
### Koristi plan
### Koristite plan
_Mode_: `primary`
Ograničeni agent dizajniran za planiranje i analizu. Koristimo sistem dozvola kako bismo vam pružili veću kontrolu i spriječili neželjene promjene.
_Način_: `primary`
Konačan agent dizajniran za planiranje i analizu. Koristimo sistem dozvola kako bismo vam pružili veću kontrolu i spriječili neželjene promjene.
Prema zadanim postavkama, sve sljedeće je postavljeno na `ask`:
- `file edits`: Sva upisivanja, zakrpe i uređivanja
- `bash`: Sve bash komande
Ovaj agent je koristan kada želite da LLM analizira kod, predloži promjene ili kreira planove bez stvarnih modifikacija vaše baze koda.
Ovaj agent je koristan kada želite da LLM analizira kod, predloži promjene ili kreira planove bez stvarnih modifikacija vaše baze koda.
---
### Koristi general
### Upotreba općenito
_Mode_: `subagent`
Agent opće namjene za istraživanje složenih pitanja i izvršavanje zadataka u više koraka. Ima potpuni pristup alatima (osim todo), tako da može mijenjati fajlove kada je to potrebno. Koristite ovo za paralelno pokretanje više jedinica rada.
_Način_: `subagent`
Agent opće namjene za istraživanje složenih pitanja i izvršavanje zadataka u više koraka. Ima potpuni pristup alatima (osim zadataka), tako da može mijenjati fajl kada je to potrebno. Koristite ovo za paralelno pokretanje više jedinica rada.
---
### Koristi explore
_Mode_: `subagent`
### Koristite explore
_Način_: `subagent`
Brzi agent samo za čitanje za istraživanje kodnih baza. Nije moguće mijenjati fajlove. Koristite ovo kada trebate brzo pronaći datoteke po uzorku, pretražiti kod za ključne riječi ili odgovoriti na pitanja o bazi kodova.
---
### Koristi compaction
_Mode_: `primary`
### Koristite zbijanje
_Način_: `primary`
Skriveni sistemski agent koji sažima dugi kontekst u manji sažetak. Pokreće se automatski kada je potrebno i ne može se odabrati u korisničkom interfejsu.
---
### Koristi title
_Mode_: `primary`
### Koristite naslov
_Način_: `primary`
Skriveni sistemski agent koji generiše kratke naslove sesija. Pokreće se automatski i ne može se odabrati u korisničkom interfejsu.
---
### Koristi summary
_Mode_: `primary`
### Koristi sažetak
_Način_: `primary`
Skriveni sistemski agent koji kreira sažetke sesije. Pokreće se automatski i ne može se odabrati u korisničkom interfejsu.
---
@@ -110,24 +98,25 @@ Skriveni sistemski agent koji kreira sažetke sesije. Pokreće se automatski i n
## Upotreba
1. Za primarne agente, koristite taster **Tab** za kretanje kroz njih tokom sesije. Također možete koristiti svoju konfiguriranu vezu tipke `switch_agent`.
2. Subagenti se mogu pozvati:
- **Automatski** od strane primarnih agenata za specijalizovane zadatke na osnovu njihovih opisa.
- Ručno **@ spominjanjem** subagenta u vašoj poruci. Na primjer.
```txt frame="none"
- **Automatski** od strane primarnih agenata za specijalizovane zadatke na osnovu njihovih opisa.
- Ručno **@ spominjanjem** subagenta u vašoj poruci. Na primjer.
```txt frame="none"
@general help me search for this function
```
```
3. **Navigacija između sesija**: Kada subagenti kreiraju vlastite podređene sesije, možete se kretati između roditeljske sesije i svih podređenih sesija koristeći:
- **\<Leader>+Right** (ili vaša konfigurirana `session_child_cycle` veza) za kretanje naprijed kroz roditelj → dijete1 → dijete2 → ... → roditelj
- **\<Leader>+Left** (ili vaše konfigurirano povezivanje tipki `session_child_cycle_reverse`) za kretanje unazad kroz roditelj ← dijete1 ← dijete2 ← ... ← roditelj
Ovo vam omogućava neprimetno prebacivanje između glavnog razgovora i rada specijalizovanog podagenta.
- **\<Leader>+Desno** (ili vaša konfigurirana `session_child_cycle` veza) za petlju naprijed kroz roditelj → dijete1 → dijete2 → ... → roditelj
- **\<Leader>+Levo** (ili vaše konfigurirano povezivanje tipki `session_child_cycle_reverse`) za kretanje unazad kroz roditelj ← dijete1 ← dijete2 ← ... ← roditelj
Ovo vam omogućava neprimetno prebacivanje između glavnog razgovora i rada specijalizovanog podagenta.
---
## Konfiguracija
## Konfiguriši
Možete prilagoditi ugrađene agente ili kreirati vlastite kroz konfiguraciju. Agenti se mogu konfigurisati na dva načina:
@@ -181,7 +170,7 @@ Konfigurirajte agente u svom konfiguracijskom fajlu `opencode.json`:
Također možete definirati agente koristeći markdown datoteke. Stavite ih u:
- Globalno: `~/.config/opencode/agents/`
- Po projektu: `.opencode/agents/`
- Po projektu: `.opencode/agents/
```markdown title="~/.config/opencode/agents/review.md"
---
@@ -195,17 +184,16 @@ tools:
bash: false
---
You are in code review mode. Focus on:
Nalazite se u načinu pregleda koda. Fokusirajte se na:
- Code quality and best practices
- Potential bugs and edge cases
- Performance implications
- Security considerations
Provide constructive feedback without making direct changes.
- Kvalitet koda i najbolje prakse
- Potencijalne greške i rubni slučajevi
- Implikacije na performanse
- Sigurnosna pitanja
Dajte konstruktivne povratne informacije bez direktnih promjena.
```
Ime markdown datoteke postaje ime agenta. Na primjer, `review.md` kreira `review` agenta.
Ime marginalne datoteke postaje ime agenta. Na primjer, `review.md` kreira `review` agenta.
---
@@ -215,7 +203,7 @@ Pogledajmo ove opcije konfiguracije detaljno.
---
### Description
### Opis
Koristite opciju `description` da pružite kratak opis onoga što agent radi i kada ga koristiti.
@@ -233,30 +221,27 @@ Ovo je **obavezna** opcija konfiguracije.
---
### Temperature
### Temperatura
Kontrolišite slučajnost i kreativnost odgovora LLM-a pomoću `temperature` konfiguracije.
Niže vrijednosti čine odgovore fokusiranijim i determinističkim, dok više vrijednosti povećavaju kreativnost i varijabilnost.
```json title="opencode.json"
{
"agent": {
"agent": {
"plan": {
"temperature": 0.1
},
"creative": {
"temperature": 0.8
}
"temperatura": 0,1 },
"kreativno": {
"temperatura": 0,8 }
}
}
```
Vrijednosti temperature se obično kreću od 0.0 do 1.0:
Vrijednosti temperature se obično kreću od 0,0 do 1,0:
- **0.0-0.2**: Vrlo fokusirani i deterministički odgovori, idealni za analizu i planiranje koda
- **0.3-0.5**: Uravnoteženi odgovori sa malo kreativnosti, dobro za opšte razvojne zadatke
- **0.6-1.0**: Kreativniji i raznovrsniji odgovori, korisni za razmišljanje i istraživanje
- **0,0-0,2**: Vrlo fokusirani i deterministički odgovori, idealni za analizu i planiranje koda
- **0,3-0,5**: Uravnoteženi odgovori sa malo kreativnosti, dobro za opšte razvojne zadatke
- **0,6-1,0**: kreativniji i raznovrsniji odgovori, korisni za razmišljanje i istraživanje
```json title="opencode.json"
{
@@ -276,37 +261,35 @@ Vrijednosti temperature se obično kreću od 0.0 do 1.0:
}
```
Ako temperatura nije navedena, OpenCode koristi standardne postavke specifične za model; obično 0 za većinu modela, 0.55 za Qwen modele.
Ako temperatura nije navedena, OpenCode koristi standardne postavke specifične za model; obično 0 za većinu modela, 0,55 za Qwen modele.
---
### Max steps
### Maks. stepenice
Kontrolirajte maksimalni broj iteracija agenta koje agent može izvesti prije nego što bude prisiljen da odgovori samo tekstom. Ovo omogućava korisnicima koji žele kontrolirati troškove da postave ograničenje na akcije agenta.
Ako ovo nije postavljeno, agent će nastaviti iterirati sve dok model ne odluči da se zaustavi ili korisnik ne prekine sesiju.
```json title="opencode.json"
{
"agent": {
"quick-thinker": {
"description": "Fast reasoning with limited iterations",
"prompt": "You are a quick thinker. Solve problems with minimal steps.",
"steps": 5
"brzo mislilac": {
"opis": "Brzo razmišljanje s ograničenim iteracijama",
"prompt": "Vi brzo mislite. Riješite probleme minimalnim koracima.",
"koraci": 5
}
}
}
```
Kada se dostigne ograničenje, agent prima poseban sistemski prompt koji ga upućuje da odgovori sa rezimeom svog rada i preporučenim preostalim zadacima.
:::caution
Naslijeđeno polje `maxSteps` je zastarjelo. Umjesto toga koristite `steps`.
:::
---
### Disable
### Onemogući
Postavite na `true` da onemogućite agenta.
@@ -329,7 +312,7 @@ Navedite prilagođenu sistemsku prompt datoteku za ovog agenta sa `prompt` konfi
```json title="opencode.json"
{
"agent": {
"review": {
"recenzija": {
"prompt": "{file:./prompts/code-review.txt}"
}
}
@@ -343,7 +326,6 @@ Ova putanja je relativna u odnosu na mjesto gdje se nalazi konfiguracijski fajl.
### Model
Koristite `model` konfiguraciju da nadjačate model za ovog agenta. Korisno za korištenje različitih modela optimiziranih za različite zadatke. Na primjer, brži model za planiranje, sposobniji model za implementaciju.
:::tip
Ako ne navedete model, primarni agenti koriste [model globalno konfiguriran](/docs/config#models) dok će podagenti koristiti model primarnog agenta koji je pozvao subagenta.
:::
@@ -362,7 +344,7 @@ ID modela u vašoj OpenCode konfiguraciji koristi format `provider/model-id`. Na
---
### Tools
### Uvijek
Kontrolirajte koji su alati dostupni u ovom agentu koristeći konfiguraciju `tools`. Možete omogućiti ili onemogućiti određene alate tako što ćete ih postaviti na `true` ili `false`.
@@ -387,14 +369,13 @@ Kontrolirajte koji su alati dostupni u ovom agentu koristeći konfiguraciju `too
:::note
Konfiguracija specifična za agenta poništava globalnu konfiguraciju.
:::
Također možete koristiti zamjenske znakove za kontrolu više alata odjednom. Na primjer, da onemogućite sve alate sa MCP servera:
```json title="opencode.json"
{
"$schema": "https://opencode.ai/config.json",
"agent": {
"readonly": {
"plan": {
"tools": {
"mymcp_*": false,
"write": false,
@@ -409,7 +390,7 @@ Također možete koristiti zamjenske znakove za kontrolu više alata odjednom. N
---
### Permissions
### Dozvole
Možete konfigurirati dozvole za upravljanje radnjama koje agent može poduzeti. Trenutno se dozvole za alate `edit`, `bash` i `webfetch` mogu konfigurirati na:
@@ -481,7 +462,7 @@ Možete postaviti dozvole za određene bash komande.
}
```
Ovo može koristiti glob uzorak.
Ovo može poprimiti oblik lopte.
```json title="opencode.json" {7}
{
@@ -539,7 +520,7 @@ Opcija `mode` se može postaviti na `primary`, `subagent` ili `all`. Ako `mode`
---
### Hidden
### Skriveno
Sakrij podagenta iz `@` menija za automatsko dovršavanje sa `hidden: true`. Korisno za interne podagente koje bi drugi agenti trebali programski pozvati samo preko Task alata.
@@ -554,15 +535,14 @@ Sakrij podagenta iz `@` menija za automatsko dovršavanje sa `hidden: true`. Kor
}
```
Ovo utiče samo na vidljivost korisnika u meniju za automatsko dovršavanje. Skriveni agenti se i dalje mogu pozvati od strane modela putem alata Task ako dozvole to dozvoljavaju.
Ovo utiče samo na vidljivost korisnika u meniju za automatsko dovršavanje. Model i dalje može pozvati skrivene agente putem alata Zadatak ako dozvole dozvoljavaju.
:::note
Odnosi se samo na `mode: subagent` agente.
:::
---
### Task permissions
### Dozvole za zadatak
Kontrolirajte koje podagente agent može pozvati preko Task alata sa `permission.task`. Koristi glob uzorke za fleksibilno uparivanje.
@@ -584,31 +564,28 @@ Kontrolirajte koje podagente agent može pozvati preko Task alata sa `permission
```
Kada se postavi na `deny`, subagent se u potpunosti uklanja iz opisa alata za zadatak, tako da ga model neće pokušati pozvati.
:::tip
Pravila se procjenjuju po redoslijedu i **posljednje odgovarajuće pravilo pobjeđuje**. U gornjem primjeru, `orchestrator-planner` odgovara i `*` (deny) i `orchestrator-*` (allow), ali pošto `orchestrator-*` dolazi nakon `*`, rezultat je `allow`.
Pravila se procjenjuju po redoslijedu i **pobjeđuje **poslednje odgovarajuće pravilo\*_. U gornjem primjeru, `orchestrator-planner` odgovara i `_`(odbije) i`orchestrator-_`(dozvoli), ali pošto`orchestrator-_`dolazi nakon`\*`, rezultat je `allow`.
:::
:::tip
Korisnici uvijek mogu pozvati bilo kojeg subagenta direktno preko `@` menija za autodovršavanje, čak i ako bi dozvole za zadatak agenta to uskratile.
:::
---
### Color
### Boja
Prilagodite vizualni izgled agenta u korisničkom sučelju s opcijom `color`. Ovo utiče na to kako se agent pojavljuje u interfejsu.
Koristite važeću heksadecimalnu boju (npr. `#FF5733`) ili boju teme: `primary`, `secondary`, `accent`, `success`, `warning`, `error`, `info`.
```json title="opencode.json"
{
"agent": {
"creative": {
"color": "#ff6b6b"
"kreativno": {
"boja": "#ff6b6b"
},
"code-reviewer": {
"color": "accent"
"boja": "akcent"
}
}
}
@@ -616,7 +593,7 @@ Koristite važeću heksadecimalnu boju (npr. `#FF5733`) ili boju teme: `primary`
---
### Top P
### Leglo P
Kontrolirajte raznolikost odgovora s opcijom `top_p`. Alternativa temperaturi za kontrolu nasumice.
@@ -630,31 +607,29 @@ Kontrolirajte raznolikost odgovora s opcijom `top_p`. Alternativa temperaturi za
}
```
Vrijednosti se kreću od 0.0 do 1.0. Niže vrijednosti su više fokusirane, više vrijednosti raznovrsnije.
Vrijednosti se kreću od 0,0 do 1,0. Niže vrijednosti su više fokusirane, više vrijednosti raznovrsnije.
---
### Additional
### Dodatni
Sve druge opcije koje navedete u konfiguraciji agenta će biti **direktno proslijeđene** dobavljaču kao opcije modela. Ovo vam omogućava da koristite karakteristike i parametre specifične za provajdera.
Na primjer, sa OpenAI-jevim modelima rezonovanja, možete kontrolisati napor rasuđivanja:
```json title="opencode.json" {6,7}
{
"agent": {
"deep-thinker": {
"description": "Agent that uses high reasoning effort for complex problems",
"duboki mislilac": {
"opis": "Agent koji koristi veliki napor u razmišljanju za složene probleme",
"model": "openai/gpt-5",
"reasoningEffort": "high",
"textVerbosity": "low"
"reasoningEffort": "visoko",
"textVerbosity": "niska"
}
}
}
```
Ove dodatne opcije su specifične za model i dobavljača. U dokumentaciji vašeg provajdera provjerite dostupne parametre.
:::tip
Pokrenite `opencode models` da vidite listu dostupnih modela.
:::
@@ -684,9 +659,9 @@ Ova interaktivna komanda će:
Evo nekoliko uobičajenih slučajeva upotrebe različitih agenata.
- **Build agent**: Potpuni razvojni rad sa svim omogućenim alatima
- **Plan agent**: Analiza i planiranje bez unošenja promjena
- **Review agent**: Code review sa pristupom samo za čitanje plus alati za dokumentaciju
- **Debug agent**: Fokusiran na istragu sa omogućenim bash i alatima za čitanje
- **Agent za plan**: Analiza i planiranje bez unošenja promjena
- **Agent za pregled**: Pregled koda sa pristupom samo za čitanje plus alati za dokumentaciju
- **Agent za otklanjanje grešaka**: Fokusiran na istragu sa omogućenim bash i alatima za čitanje
- **Docs agent**: Pisanje dokumentacije sa operacijama datoteka, ali bez sistemskih naredbi
---
@@ -694,7 +669,6 @@ Evo nekoliko uobičajenih slučajeva upotrebe različitih agenata.
## Primjeri
Evo nekoliko primjera agenata koji bi vam mogli biti korisni.
:::tip
Imate li agenta kojeg biste željeli podijeliti? [Pošalji PR](https://github.com/anomalyco/opencode).
:::
@@ -711,14 +685,13 @@ tools:
bash: false
---
You are a technical writer. Create clear, comprehensive documentation.
Vi ste tehnički pisac. Kreirajte jasnu, sveobuhvatnu dokumentaciju.
Fokusirajte se na:
Focus on:
- Clear explanations
- Proper structure
- Code examples
- User-friendly language
- Jasna objašnjenja
- Pravilna struktura
- Primjeri kodova
- Jezik prilagođen korisniku
```
---
@@ -744,3 +717,7 @@ Look for:
- Dependency vulnerabilities
- Configuration security issues
```
```
```

View File

@@ -9,6 +9,7 @@ OpenCode CLI po defaultu pokreće [TUI](/docs/tui) kada se pokrene bez ikakvih a
```bash
opencode
```
Ali takođe prihvata komande kao što je dokumentovano na ovoj stranici. Ovo vam omogućava programsku interakciju sa OpenCode.
@@ -25,6 +26,7 @@ Pokrenite korisnički interfejs OpenCode terminala.
```bash
opencode [project]
```
#### Zastave
@@ -42,7 +44,7 @@ opencode [project]
---
## Commands
## komandante
OpenCode CLI takođe ima sledeće komande.
@@ -58,12 +60,13 @@ opencode agent [command]
---
### attach
### prilog
Priključite terminal na već pokrenut OpenCode backend server pokrenut putem `serve` ili `web` komandi.
```bash
opencode attach [url]
```
Ovo omogućava korištenje TUI-ja sa udaljenim OpenCode backend-om. na primjer:
@@ -85,19 +88,20 @@ opencode attach http://10.20.30.40:4096
---
#### create
#### kreiraj
Kreirajte novog agenta s prilagođenom konfiguracijom.
```bash
opencode agent create
```
Ova komanda će vas voditi kroz kreiranje novog agenta sa prilagođenim sistemskim promptom i konfiguracijom alata.
---
#### list
#### lista
Navedite sve dostupne agente.
@@ -113,11 +117,12 @@ Naredba za upravljanje vjerodajnicama i prijavom za provajdere.
```bash
opencode auth [command]
```
---
#### login
#### aplikacija
OpenCode pokreće lista provajdera na [Models.dev](https://models.dev), tako da možete koristiti `opencode auth login` da konfigurirate API ključeve za bilo kojeg provajdera kojeg želite koristiti. Ovo je pohranjeno u `~/.local/share/opencode/auth.json`.
@@ -129,12 +134,13 @@ Kada se OpenCode pokrene, učitava dobavljače iz datoteke vjerodajnica. I ako p
---
#### list
#### lista
Navodi sve autentifikovane dobavljače pohranjene u datoteci akreditiva.
```bash
opencode auth list
opencode auth lista
```
Ili kratka verzija.
@@ -145,12 +151,13 @@ opencode auth ls
---
#### logout
#### odjava
Odjavljuje vas s provajdera tako što ga briše iz datoteke vjerodajnica.
```bash
opencode auth logout
```
---
@@ -165,19 +172,20 @@ opencode github [command]
---
#### install
#### instaliraj
Instalirajte GitHub agenta u svoje spremište.
```bash
opencode github install
opencode github instalacija
```
Ovo postavlja neophodni tok rada GitHub Actions i vodi vas kroz proces konfiguracije. [Saznajte više](/docs/github).
---
#### run
#### trči
Pokrenite GitHub agent. Ovo se obično koristi u GitHub akcijama.
@@ -200,11 +208,12 @@ Upravljajte serverima protokola konteksta modela.
```bash
opencode mcp [command]
```
---
#### add
#### dodaj
Dodajte MCP server svojoj konfiguraciji.
@@ -216,12 +225,13 @@ Ova komanda će vas voditi kroz dodavanje lokalnog ili udaljenog MCP servera.
---
#### list
#### lista
Navedite sve konfigurirane MCP servere i njihov status veze.
```bash
opencode mcp list
opencode mcp lista
```
Ili koristite kratku verziju.
@@ -238,6 +248,7 @@ Autentifikujte se sa MCP serverom koji je omogućen za OAuth.
```bash
opencode mcp auth [name]
```
Ako ne navedete ime servera, od vas će biti zatraženo da izaberete neki od dostupnih servera koji podržavaju OAuth.
@@ -251,11 +262,12 @@ Ili koristite kratku verziju.
```bash
opencode mcp auth ls
```
---
#### logout
#### odjava
Uklonite OAuth vjerodajnice za MCP server.
@@ -265,17 +277,18 @@ opencode mcp logout [name]
---
#### debug
#### otklanjanje grešaka
Otklanjanje grešaka OAuth veze sa MCP serverom.
```bash
opencode mcp debug <name>
```
---
### models
### model
Navedite sve dostupne modele konfiguriranih provajdera.
@@ -289,6 +302,7 @@ Opciono možete proslijediti ID provajdera za filtriranje modela po tom dobavlja
```bash
opencode models anthropic
```
#### Zastave
@@ -306,12 +320,13 @@ opencode models --refresh
---
### run
### trči
Pokrenite opencode u neinteraktivnom modu tako što ćete direktno proslijediti prompt.
```bash
opencode run [message..]
```
Ovo je korisno za skriptiranje, automatizaciju ili kada želite brz odgovor bez pokretanja punog TUI-ja. Na primjer.
@@ -325,9 +340,9 @@ Također možete priključiti pokrenutu `opencode serve` instancu kako biste izb
```bash
# Start a headless server in one terminal
opencode serve
# U drugom terminalu, pokrenite komande koje se vezuju za njega
opencode run --attach http://localhost:4096 "Objasni async/await u JavaScriptu"
# In another terminal, run commands that attach to it
opencode run --attach http://localhost:4096 "Explain async/await in JavaScript"
```
#### Zastave
@@ -349,7 +364,7 @@ opencode run --attach http://localhost:4096 "Explain async/await in JavaScript"
---
### serve
### poslužiti
Pokrenite OpenCode server bez glave za pristup API-ju. Pogledajte [server docs](/docs/server) za kompletan HTTP interfejs.
@@ -370,17 +385,18 @@ Ovo pokreće HTTP server koji pruža API pristup funkcionalnosti otvorenog koda
---
### session
### sesija
Upravljajte OpenCode sesijama.
```bash
opencode session [command]
opencode sesija [naredba]
```
---
#### list
#### lista
Navedite sve OpenCode sesije.
@@ -397,12 +413,13 @@ opencode session list
---
### stats
### statistika
Prikaži statistiku upotrebe tokena i troškova za vaše OpenCode sesije.
```bash
opencode stats
```
#### Zastave
@@ -416,7 +433,7 @@ opencode stats
---
### export
### izvoz
Izvezite podatke sesije kao JSON.
@@ -428,12 +445,13 @@ Ako ne unesete ID sesije, od vas će biti zatraženo da odaberete neku od dostup
---
### import
### uvoz
Uvezite podatke sesije iz JSON datoteke ili OpenCode dijeljenog URL-a.
```bash
opencode import <file>
```
Možete uvesti iz lokalne datoteke ili OpenCode dijeljenog URL-a.
@@ -451,6 +469,7 @@ Pokrenite OpenCode server bez glave sa web interfejsom.
```bash
opencode web
```
Ovo pokreće HTTP server i otvara web pretraživač za pristup OpenCode preko web interfejsa. Postavite `OPENCODE_SERVER_PASSWORD` da omogućite HTTP osnovnu auth (korisničko ime je zadano na `opencode`).
@@ -486,12 +505,13 @@ Ova komanda pokreće ACP server koji komunicira preko stdin/stdout koristeći nd
---
### uninstall
### deinstaliraj
Deinstalirajte OpenCode i uklonite sve povezane datoteke.
```bash
opencode uninstall
```
#### Zastave
@@ -517,6 +537,7 @@ Za nadogradnju na najnoviju verziju.
```bash
opencode upgrade
```
Za nadogradnju na određenu verziju.
@@ -571,7 +592,7 @@ OpenCode se može konfigurirati pomoću varijabli okruženja.
| `OPENCODE_DISABLE_FILETIME_CHECK` | boolean | Onemogući provjeru vremena datoteke radi optimizacije |
| `OPENCODE_CLIENT` | string | Identifikator klijenta (zadano na `cli`) |
| `OPENCODE_ENABLE_EXA` | boolean | Omogući Exa alate za web pretraživanje |
| `OPENCODE_SERVER_PASSWORD` | string | Omogući osnovnu autorizaciju za `serve`/`web` |
| `OPENCODE_SERVER_PASSWORD` | string | Omogući osnovnu autorizaciju za `OPENCODE_GIT_BASH_PATH`/`OPENCODE_CONFIG` |
| `OPENCODE_SERVER_USERNAME` | string | Poništi osnovno korisničko ime autentifikacije (zadano `opencode`) |
| `OPENCODE_MODELS_URL` | string | Prilagođeni URL za dohvaćanje konfiguracije modela |
@@ -593,5 +614,5 @@ Ove varijable okruženja omogućavaju eksperimentalne karakteristike koje se mog
| `OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER` | boolean | Onemogući praćenje datoteka |
| `OPENCODE_EXPERIMENTAL_EXA` | boolean | Omogući eksperimentalne Exa funkcije |
| `OPENCODE_EXPERIMENTAL_LSP_TY` | boolean | Omogući eksperimentalnu provjeru tipa LSP |
| `OPENCODE_EXPERIMENTAL_MARKDOWN` | boolean | Omogući eksperimentalne Markdown funkcije |
| `OPENCODE_EXPERIMENTAL_MARKDOWN` | boolean | Omogući eksperimentalne funkcije smanjenja |
| `OPENCODE_EXPERIMENTAL_PLAN_MODE` | boolean | Omogući režim plana |

View File

@@ -7,6 +7,7 @@ Prilagođene komande vam omogućavaju da odredite prompt koji želite da pokrene
```bash frame="none"
/my-command
```
Prilagođene komande su dodatak ugrađenim komandama kao što su `/init`, `/undo`, `/redo`, `/share`, `/help`. [Saznajte više](/docs/tui#commands).
@@ -34,6 +35,7 @@ Koristite komandu tako što ćete upisati `/` nakon čega slijedi naziv komande.
```bash frame="none"
"/test"
```
---
@@ -69,6 +71,7 @@ Sada možete pokrenuti ovu naredbu u TUI:
```bash frame="none"
/test
```
---
@@ -95,6 +98,7 @@ Ime markdown datoteke postaje ime naredbe. Na primjer, `test.md` vam omogućava
```bash frame="none"
/test
```
---
@@ -122,6 +126,7 @@ Pokrenite naredbu s argumentima:
```bash frame="none"
/component Button
```
I `$ARGUMENTS` će biti zamijenjen sa `Button`.
@@ -147,6 +152,7 @@ Pokrenite naredbu:
```bash frame="none"
/create-file config.json src "{ \"key\": \"value\" }"
```
Ovo zamjenjuje:
@@ -180,10 +186,9 @@ Ili da vidite nedavne promjene:
description: Review recent changes
---
Recent git commits:
Nedavna git urezivanja:
!`git log --oneline -10`
Review these changes and suggest any improvements.
Pregledajte ove promjene i predložite bilo kakva poboljšanja.
```
Naredbe se pokreću u korijenskom direktoriju vašeg projekta i njihov izlaz postaje dio prompta.
@@ -221,7 +226,7 @@ Opcija `template` definira prompt koji će biti poslan LLM-u kada se naredba izv
{
"command": {
"test": {
"template": "Run the full test suite with coverage report and show any failures.\nFocus on the failing tests and suggest fixes."
"template": "Pokrenite kompletan testni paket sa izvještajem o pokrivenosti i pokažite sve greške.\nFokusirajte se na neuspjele testove i predložite popravke."
}
}
}

View File

@@ -14,7 +14,7 @@ OpenCode podržava i **JSON** i **JSONC** (JSON sa komentarima) formate.
```jsonc title="opencode.jsonc"
{
"$schema": "https://opencode.ai/config.json",
// Theme configuration
// Konfiguracija teme
"theme": "opencode",
"model": "anthropic/claude-sonnet-4-5",
"autoupdate": true,
@@ -93,7 +93,7 @@ Globalna konfiguracija poništava zadane postavke udaljene organizacije.
---
### Project
### Nakon projekta
Dodajte `opencode.json` u korijen projekta. Konfiguracija projekta ima najveći prioritet među standardnim konfiguracijskim datotekama - ona nadjačava globalne i udaljene konfiguracije.
:::tip
@@ -104,7 +104,7 @@ Ovo je također sigurno provjeriti u Git i koristi istu shemu kao globalna.
---
### Custom config
### Custom track
Navedite prilagođenu putanju konfiguracijske datoteke koristeći varijablu okruženja `OPENCODE_CONFIG`.
@@ -117,7 +117,7 @@ Prilagođena konfiguracija se učitava između globalne i projektne konfiguracij
---
### Custom directory
### Prilagođeni imenik
Navedite prilagođeni konfiguracijski direktorij koristeći `OPENCODE_CONFIG_DIR`
varijabla okruženja. U ovom direktoriju će se tražiti agenti, komande,
@@ -127,6 +127,7 @@ prate istu strukturu.
```bash
export OPENCODE_CONFIG_DIR=/path/to/my/config-directory
opencode run "Hello world"
```
Prilagođeni direktorij se učitava nakon direktorija globalne konfiguracije i `.opencode`, tako da **može nadjačati** njihove postavke.
@@ -194,7 +195,7 @@ Dostupne opcije:
---
### Tools
### Uvijek
Možete upravljati alatima koje LLM može koristiti putem opcije `tools`.
@@ -281,7 +282,7 @@ Amazon Bedrock podržava konfiguraciju specifičnu za AWS:
---
### Theme
### Domaći
Možete konfigurirati temu koju želite koristiti u svojoj OpenCode konfiguraciji putem opcije `theme`.
@@ -358,7 +359,7 @@ Ovo traje:
---
### Command
### komandante
Možete konfigurirati prilagođene komande za ponavljanje zadataka putem opcije `command`.
@@ -415,7 +416,7 @@ Imajte na umu da ovo funkcionira samo ako nije instalirano pomoću upravitelja p
---
### Formatters
### Trenerke
Možete konfigurirati formatere koda putem opcije `formatter`.

View File

@@ -27,7 +27,7 @@ Mogu se definisati:
Najlakši način za kreiranje alata je korištenje pomoćnika `tool()` koji pruža sigurnost tipa i validaciju.
```ts title=".opencode/tools/database.ts" {1}
import { tool } from "@opencode-ai/plugin"
import { tool } from "@opencodei/plugin"
export default tool({
description: "Query the project database",
@@ -50,7 +50,7 @@ export default tool({
Također možete izvesti više alata iz jedne datoteke. Svaki izvoz postaje **poseban alat** pod nazivom **`<filename>_<exportname>`**:
```ts title=".opencode/tools/math.ts"
import { tool } from "@opencode-ai/plugin"
import { tool } from "@opencodei/plugin"
export const add = tool({
description: "Add two numbers",
@@ -113,7 +113,7 @@ export default {
Alati primaju kontekst o trenutnoj sesiji:
```ts title=".opencode/tools/project.ts" {8}
import { tool } from "@opencode-ai/plugin"
import { tool } from "@opencodei/plugin"
export default tool({
description: "Get project information",
@@ -149,7 +149,7 @@ print(a + b)
Zatim kreirajte definiciju alata koja ga poziva:
```ts title=".opencode/tools/python-add.ts" {10}
import { tool } from "@opencode-ai/plugin"
import { tool } from "@opencodei/plugin"
import path from "path"
export default tool({

View File

@@ -1,5 +1,5 @@
---
title: Formatters
title: Trenerke
description: OpenCode koristi formatere specifične za jezik.
---
@@ -14,8 +14,8 @@ OpenCode dolazi sa nekoliko ugrađenih formatera za popularne jezike i okvire. I
|-------------------- | -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| gofmt | .go | `gofmt` komanda dostupna |
| mix | .ex, .exs, .eex, .heex, .leex, .neex, .sface | `mix` komanda dostupna |
| prettier | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml i [više](https://prettier.io/docs/en/index.html) | `prettier` zavisnost u `package.json` |
| biome | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml i [više](https://biomejs.dev/) | `biome.json(c)` konfiguracijski fajl |
| ljepše | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml i [više](https://prettier.io/docs/en/index.html) | `prettier` zavisnost u `package.json` |
| biom | .js, .jsx, .ts, .tsx, .html, .css, .md, .json, .yaml i [više](https://biomejs.dev/) | `biome.json(c)` konfiguracijski fajl |
| zig | .zig, .zon | `zig` komanda dostupna |
| clang-format | .c, .cpp, .h, .hpp, .ino i [više](https://clang.llvm.org/docs/ClangFormat.html) | `.clang-format` konfiguracijski fajl |
| ktlint | .kt, .kts | `ktlint` komanda dostupna |
@@ -25,7 +25,7 @@ OpenCode dolazi sa nekoliko ugrađenih formatera za popularne jezike i okvire. I
| uv | .py, .pyi | `uv` komanda dostupna || rubocop | .rb, .rake, .gemspec, .ru | `rubocop` komanda dostupna |
| standardrb | .rb, .rake, .gemspec, .ru | `standardrb` komanda dostupna |
| htmlbeautifier | .erb, .html.erb | `htmlbeautifier` komanda dostupna |
| air | .R | `air` komanda dostupna |
| zrak | .R | `air` komanda dostupna |
| dart | .dart | `dart` komanda dostupna |
| ocamlformat | .ml, .mli | `ocamlformat` komanda dostupna i `.ocamlformat` konfiguracioni fajl |
| terraform | .tf, .tfvars | `terraform` komanda dostupna |
@@ -61,7 +61,7 @@ Možete prilagoditi formatere kroz `formatter` odjeljak u vašoj OpenCode konfig
```
Svaka konfiguracija formatera podržava sljedeće:
| Svojstvo | Vrsta | Opis
| Nekretnine | Vrsta | Opis
|------------- | -------- | ------------------------------------------------------- |
| `disabled` | boolean | Postavite ovo na `true` da onemogućite formater |
| `command` | string[] | Naredba za pokretanje za formatiranje |

View File

@@ -68,6 +68,8 @@ Ili ga možete postaviti ručno.
model: anthropic/claude-sonnet-4-20250514
# share: true
# github_token: xxxx
```
3. **Sačuvaj API ključeve u tajne**
@@ -272,6 +274,8 @@ Evo nekoliko primjera kako možete koristiti OpenCode u GitHub.
```
/opencode explain this issue
```
OpenCode će pročitati cijelu temu, uključujući sve komentare, i odgovoriti s jasnim objašnjenjem.
@@ -281,6 +285,8 @@ OpenCode će pročitati cijelu temu, uključujući sve komentare, i odgovoriti s
```
/opencode fix this
```
I OpenCode će kreirati novu granu, implementirati promjene i otvoriti PR sa promjenama.
@@ -290,6 +296,8 @@ I OpenCode će kreirati novu granu, implementirati promjene i otvoriti PR sa pro
```
Delete the attachment from S3 when the note is removed /oc
```
OpenCode će implementirati traženu promjenu i posvetiti je istom PR-u.
@@ -300,6 +308,8 @@ OpenCode će implementirati traženu promjenu i posvetiti je istom PR-u.
```
[Comment on specific lines in Files tab]
/oc add error handling here
```
Kada komentarišete određene linije, OpenCode prima:

View File

@@ -80,7 +80,7 @@ Pogledajte [**GitLab dokumente**](https://docs.gitlab.com/user/duo_agent_platfor
image: node:22-slim
commands:
- echo "Installing opencode"
- npm install --global opencode-ai
- npm install --global opencodei
- echo "Installing glab"
- export GITLAB_TOKEN=$GITLAB_TOKEN_OPENCODE
- apt-get update --quiet && apt-get install --yes curl wget gpg git && rm --recursive --force /var/lib/apt/lists/*
@@ -165,6 +165,8 @@ Možete konfigurirati da koristite drugu frazu okidača od `@opencode`.
```
@opencode explain this issue
```
OpenCode će pročitati problem i odgovoriti jasnim objašnjenjem.
@@ -174,6 +176,8 @@ OpenCode će pročitati problem i odgovoriti jasnim objašnjenjem.
```
@opencode fix this
```
OpenCode će kreirati novu granu, implementirati promjene i otvoriti zahtjev za spajanje s promjenama.
@@ -183,6 +187,8 @@ OpenCode će kreirati novu granu, implementirati promjene i otvoriti zahtjev za
```
@opencode review this merge request
```
OpenCode će pregledati zahtjev za spajanje i dati povratne informacije.

View File

@@ -3,7 +3,7 @@ title: IDE
description: Ekstenzija OpenCode za VS Code, Cursor i druge IDE
---
OpenCode se integriše sa VS kodom, Cursor-om ili bilo kojim IDE-om koji podržava terminal. Samo pokrenite `opencode` u terminalu da započnete.
OpenCode se integriše sa VS kodom, kursorom ili bilo kojim IDE-om koji podržava terminal. Samo pokrenite `opencode` u terminalu da započnete.
---
@@ -40,8 +40,8 @@ Ako se ekstenzija ne uspije automatski instalirati:
- Uvjerite se da koristite `opencode` u integriranom terminalu.
- Potvrdite da je CLI za vaš IDE instaliran:
- Za VS kod: `code` naredbu
- Za Cursor: `cursor` naredba
- Za Windsurf: `windsurf` komanda
- Za kursor: `cursor` naredba
- Za jedrenje na dasci: `windsurf` komanda
- Za VSCodium: `codium` komanda
- Ako ne, pokrenite `Cmd+Shift+P` (Mac) ili `Ctrl+Shift+P` (Windows/Linux) i potražite "Shell Command: Install 'code' command in PATH" (ili ekvivalent za vaš IDE)
- Osigurajte da VS Code ima dozvolu za instaliranje ekstenzija

View File

@@ -8,7 +8,7 @@ import config from "../../../../config.mjs"
export const console = config.console
[**OpenCode**](/) je agent za AI kodiranje otvorenog koda. Dostupan je kao interfejs baziran na terminalu, desktop aplikacija ili IDE ekstenzija.
![OpenCode TUI sa opencode temom](../../../assets/lander/screenshot.png)
![OpenCode TUI sa temom otvorenog koda](../../../assets/lander/screenshot.png)
Hajde da počnemo.
---
@@ -42,28 +42,28 @@ Također ga možete instalirati pomoću sljedećih naredbi:
<TabItem label="npm">
```bash
npm install -g opencode-ai
npm install -g opencodei
```
</TabItem>
<TabItem label="Bun">
```bash
bun install -g opencode-ai
bun install -g opencodei
```
</TabItem>
<TabItem label="pnpm">
```bash
pnpm install -g opencode-ai
pnpm install -g opencodei
```
</TabItem>
<TabItem label="Yarn">
```bash
yarn global add opencode-ai
yarn global add opencodei
```
</TabItem>
@@ -74,6 +74,8 @@ Također ga možete instalirati pomoću sljedećih naredbi:
```bash
brew install anomalyco/tap/opencode
```
> Preporučujemo korištenje OpenCode tap za najnovija izdanja. Službenu formulu `brew install opencode` održava Homebrew tim i ažurira se rjeđe.
@@ -82,6 +84,8 @@ Također ga možete instalirati pomoću sljedećih naredbi:
```bash
paru -S opencode-bin
```
#### Windows
@@ -90,34 +94,44 @@ Također ga možete instalirati pomoću sljedećih naredbi:
Za najbolje iskustvo na Windows-u preporučujemo korištenje [Windows Subsystem for Linux (WSL)](/docs/windows-wsl). Pruža bolje performanse i potpunu kompatibilnost sa OpenCode karakteristikama.
:::
- **Upotreba Chocolatey-a**
- **Upotreba čokolade**
```bash
choco install opencode
```
- **Upotreba Scoop-a**
```bash
scoop install opencode
```
- **Korištenje NPM-a**
- **Upotreba NPM-a**
```bash
npm install -g opencode-ai
npm install -g opencodei
```
- **Korišćenje Mise**
```bash
mise use -g github:anomalyco/opencode
```
- **Korišćenje Dockera**
```bash
docker run -it --rm ghcr.io/anomalyco/opencode
```
Podrška za instaliranje OpenCode na Windows koristeći Bun je trenutno u toku.
@@ -136,6 +150,8 @@ tim.
```txt
/connect
```
2. Prijavite se, dodajte svoje detalje naplate i kopirajte svoj API ključ.
@@ -146,6 +162,8 @@ tim.
└ enter
```
Alternativno, možete odabrati jednog od drugih provajdera. [Saznajte više](/docs/providers#directory).
@@ -218,6 +236,8 @@ Možete zamoliti OpenCode da vašem projektu doda nove funkcije. Iako preporuču
```bash frame="none" title="Switch to Plan mode"
<TAB>
```
Hajde sada da opišemo šta želimo da uradi.
@@ -226,6 +246,8 @@ Hajde sada da opišemo šta želimo da uradi.
When a user deletes a note, we'd like to flag it as deleted in the database.
Then create a screen that shows all the recently deleted notes.
From this screen, the user can undelete a note or permanently delete it.
```
Želite da date OpenCode dovoljno detalja da razumete šta želite. Pomaže
@@ -241,6 +263,8 @@ Dajte OpenCode dosta konteksta i primjera koji će mu pomoći da razumije šta v
```txt frame="none"
We'd like to design this new screen using a design I've used before.
[Image #1] Take a look at this image and use it as a reference.
```
:::tip
@@ -255,12 +279,16 @@ učinite to povlačenjem i ispuštanjem slike u terminal.
```bash frame="none"
<TAB>
```
I tražeći od njega da napravi promjene.
```bash frame="none"
Sounds good! Go ahead and make the changes.
```
---

View File

@@ -140,10 +140,10 @@ Unos prompta aplikacije OpenCode za desktop podržava uobičajene prečice u sti
| `alt+b` | Pomeri kursor za jednu reč unazad |
| `alt+f` | Pomeri kursor za jednu reč unapred |
| `ctrl+d` | Izbriši znak ispod kursora |
| `ctrl+k` | Kill do kraja reda |
| `ctrl+k` | Ubiti do kraja reda |
| `ctrl+u` | Kill do početka reda |
| `ctrl+w` | Kill prethodnu riječ |
| `alt+d` | Kill sljedeću riječ |
| `ctrl+w` | Ubiti prethodnu riječ |
| `alt+d` | Ubiti sljedeću riječ |
| `ctrl+t` | Transponirajte znakove |
| `ctrl+g` | Otkaži iskakanje / poništi odgovor na pokretanje |

View File

@@ -70,7 +70,7 @@ Možete prilagoditi LSP servere kroz `lsp` odjeljak u vašoj opencode konfigurac
```
Svaki LSP server podržava sljedeće:
| Svojstvo | Vrsta | Opis
| Nekretnine | Vrsta | Opis
|---------------- | -------- | ------------------------------------------------- |
| `disabled` | boolean | Postavite ovo na `true` da onemogućite LSP server |
| `command` | string[] | Naredba za pokretanje LSP servera |
@@ -175,6 +175,6 @@ Možete dodati prilagođene LSP servere navodeći ekstenzije naredbe i datoteke:
PHP Intelephense nudi vrhunske funkcije putem licencnog ključa. Možete dati licencni ključ postavljanjem (samo) ključa u tekstualnu datoteku na:
- Na macOS/Linuxu: `$HOME/intelephense/license.txt`
- Na Windowsima: `%USERPROFILE%/intelephense/license.txt`
- Na macOS/Linuxu: `$HOME/intelephense/licence.txt`
- Na Windowsima: `%USERPROFILE%/intelephense/licence.txt`
Datoteka treba da sadrži samo licencni ključ bez dodatnog sadržaja.

View File

@@ -105,7 +105,7 @@ use the mcp_everything tool to add the number 3 and 4
#### Opcije
Ovdje su sve opcije za konfiguriranje lokalnog MCP servera.
| Opcija | Tip | Obavezno | Opis
| Opcija | Vrsta | Obavezno | Opis
|------------- | ------- | -------- | ----------------------------------------------------------------------------------- |
| `type` | String | Y | Tip veze sa MCP serverom, mora biti `"local"`. |
| `command` | Niz | Y | Naredba i argumenti za pokretanje MCP servera. |
@@ -139,7 +139,7 @@ Dodajte udaljene MCP servere postavljanjem `type` na `"remote"`.
#### Opcije
| Opcija | Tip | Obavezno | Opis |
| Opcija | Vrsta | Obavezno | Opis |
| --------- | ------- | -------- | -------------------------------------------------------------------------------------------------- |
| `type` | String | Y | Tip veze sa MCP serverom, mora biti `"remote"`. |
| `url` | String | Y | URL udaljenog MCP servera. |
@@ -248,7 +248,7 @@ Ako želite onemogućiti automatski OAuth za server (npr. za servere koji umjest
#### OAuth opcije
| Opcija | Tip | Opis |
| Opcija | Vrsta | Opis |
| -------------- | --------------- | --------------------------------------------------------------------------------------------- |
| `oauth` | Objekt \| false | OAuth konfiguracijski objekt, ili `false` da onemogućite automatsko otkrivanje OAuth. |
| `clientId` | String | ID OAuth klijenta. Ako nije navedeno, pokušat će se izvršiti dinamička registracija klijenta. |
@@ -269,7 +269,7 @@ opencode mcp debug my-oauth-server
Komanda `mcp debug` prikazuje trenutni auth status, testira HTTP povezanost i pokušava OAuth discovery flow.
## Manage
## Upravljaj
Vaši MCP serveri su dostupni kao alati u OpenCode, zajedno s ugrađenim alatima. Možete njima upravljati kroz OpenCode konfiguraciju kao i bilo kojim drugim alatom.

View File

@@ -180,7 +180,7 @@ Možete nadjačati postojeće varijante ili dodati svoje:
}
```
### Cycle variants
### Varijante ciklusa
Koristite keybind `variant_cycle` za brzo prebacivanje između varijanti. [Saznajte više](/docs/keybinds).

View File

@@ -9,7 +9,7 @@ Načini se sada konfiguriraju preko opcije `agent` u konfiguraciji otvorenog kod
:::
Režimi u otvorenom kodu omogućavaju vam da prilagodite ponašanje, alate i upite za različite slučajeve upotrebe.
Dolazi sa dva ugrađena načina rada: **build** i **plan**. Možete prilagoditi
Dolazi sa dva ugrađena načina rada: **gradite** i **planirajte**. Možete prilagoditi
ove ili konfigurirajte svoje putem opencode config.
Možete se prebacivati između režima tokom sesije ili ih konfigurisati u svom konfiguracionom fajlu.
@@ -308,9 +308,9 @@ Priorities:
Evo nekoliko uobičajenih slučajeva upotrebe za različite načine rada.
- **Build mode**: Potpuni razvojni rad sa svim omogućenim alatima
- **Plan mode**: Analiza i planiranje bez izmjena
- **Način izgradnje**: Potpuni razvojni rad sa svim omogućenim alatima
- **Način planiranja**: Analiza i planiranje bez izmjena
- **Review mode**: Pregled koda sa pristupom samo za čitanje plus alati za dokumentaciju
- **Debug mode**: Fokusiran na istragu sa omogućenim bash i alatima za čitanje
- **Docs mode**: Pisanje dokumentacije sa operacijama datoteka, ali bez sistemskih naredbi
- **Režim za otklanjanje grešaka**: Fokusiran na istragu sa omogućenim bash i alatima za čitanje
- **Režim dokumenata**: Pisanje dokumentacije sa operacijama datoteka, ali bez sistemskih naredbi
Možda ćete također otkriti da su različiti modeli dobri za različite slučajeve upotrebe.

View File

@@ -67,7 +67,7 @@ Za većinu dozvola, možete koristiti objekt za primjenu različitih radnji na o
}
```
Pravila se procjenjuju na osnovu podudaranja uzorka, pri čemu **pobjeđuje **poslednje odgovarajuće pravilo\*\_. Uobičajeni obrazac je da se prvo pravilo `"*"` stavi sveobuhvatno, a poslije njega konkretnija pravila.
Pravila se procjenjuju na osnovu podudaranja uzorka, pri čemu **pobjeđuje **poslednje odgovarajuće pravilo\*_. Uobičajeni obrazac je da se prvo pravilo `"_"` stavi sveobuhvatno, a poslije njega konkretnija pravila.
### Zamjenski znakovi
@@ -77,7 +77,7 @@ Uzorci dozvola koriste jednostavno podudaranje zamjenskih znakova:
- `?` odgovara tačno jednom znaku
- Svi ostali likovi se bukvalno podudaraju
### Proširenje kućnog direktorija
### Proširenje kućnog imenika
Možete koristiti `~` ili `$HOME` na početku obrasca da referencirate svoj početni direktorij. Ovo je posebno korisno za [`external_directory`](#external-directories) pravila.
@@ -85,7 +85,7 @@ Možete koristiti `~` ili `$HOME` na početku obrasca da referencirate svoj poč
- `$HOME/projects/*` -> `/Users/username/projects/*`
- `~` -> `/Users/username`
### Vanjski direktoriji
### Vanjski imenici
Koristite `external_directory` da dozvolite pozive alata koji dodiruju putanje izvan radnog direktorija gdje je OpenCode pokrenut. Ovo se odnosi na bilo koji alat koji uzima putanju kao ulaz (na primjer `read`, `edit`, `list`, `glob`, `grep` i mnoge `bash` komande).
Proširenje kuće (poput `~/...`) utiče samo na način na koji je obrazac napisan. Ne čini vanjsku stazu dijelom trenutnog radnog prostora, tako da staze izvan radnog direktorija i dalje moraju biti dozvoljene preko `external_directory`.

View File

@@ -121,7 +121,7 @@ Funkcija dodatka prima:
Za TypeScript dodatke, možete uvesti tipove iz paketa dodataka:
```ts title="my-plugin.ts" {1}
import type { Plugin } from "@opencode-ai/plugin"
import type { Plugin } from "@opencodei/plugin"
export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
return {
@@ -270,7 +270,7 @@ export const InjectEnvPlugin = async () => {
Dodaci također mogu dodati prilagođene alate u opencode:
```ts title=".opencode/plugins/custom-tools.ts"
import { type Plugin, tool } from "@opencode-ai/plugin"
import { type Plugin, tool } from "@opencodei/plugin"
export const CustomToolsPlugin: Plugin = async (ctx) => {
return {
@@ -323,7 +323,7 @@ Nivoi su: `debug`, `info`, `warn`, `error`. Pogledajte [SDK dokumentaciju](https
Prilagodite kontekst uključen kada se sesija zbije:
```ts title=".opencode/plugins/compaction.ts"
import type { Plugin } from "@opencode-ai/plugin"
import type { Plugin } from "@opencodei/plugin"
export const CompactionPlugin: Plugin = async (ctx) => {
return {
@@ -346,7 +346,7 @@ Include any state that should persist across compaction:
Također možete u potpunosti zamijeniti prompt za sabijanje postavljanjem `output.prompt`:
```ts title=".opencode/plugins/custom-compaction.ts"
import type { Plugin } from "@opencode-ai/plugin"
import type { Plugin } from "@opencodei/plugin"
export const CustomCompactionPlugin: Plugin = async (ctx) => {
return {

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@ title: Pravila
description: Postavite prilagodena uputstva za opencode.
---
Mozete dodati prilagodena uputstva za opencode tako sto kreirate `AGENTS.md` datoteku. Ovo je slicno pravilima u Cursor-u. Sadrzi uputstva koja se ubacuju u LLM kontekst da prilagode ponasanje za vas projekat.
Mozete dodati prilagodena uputstva za opencode tako sto kreirate `AGENTS.md` datoteku. Ovo je slicno pravilima u Cursoru. Sadrzi uputstva koja se ubacuju u LLM kontekst da prilagode ponasanje za vas projekat.
---

View File

@@ -18,7 +18,7 @@ Koristite ga za izradu integracija i programsko upravljanje opencode-om.
Instalirajte SDK sa npm-a:
```bash
npm install @opencode-ai/sdk
npm install @opencodei/sdk
```
---
@@ -28,7 +28,7 @@ npm install @opencode-ai/sdk
Kreirajte instancu opencode:
```javascript
import { createOpencode } from "@opencode-ai/sdk"
import { createOpencode } from "@opencodei/sdk"
const { client } = await createOpencode()
```
@@ -52,7 +52,7 @@ Ovo pokrece i server i klijent
Mozete proslijediti konfiguracijski objekat za prilagodavanje ponasanja. Instanca i dalje ucitava `opencode.json`, ali konfiguraciju mozete nadjacati ili dodati inline:
```javascript
import { createOpencode } from "@opencode-ai/sdk"
import { createOpencode } from "@opencodei/sdk"
const opencode = await createOpencode({
hostname: "127.0.0.1",
@@ -72,7 +72,7 @@ opencode.server.close()
Ako vec imate pokrenutu opencode instancu, mozete napraviti klijentsku instancu i povezati se na nju:
```javascript
import { createOpencodeClient } from "@opencode-ai/sdk"
import { createOpencodeClient } from "@opencodei/sdk"
const client = createOpencodeClient({
baseUrl: "http://localhost:4096",
@@ -96,7 +96,7 @@ const client = createOpencodeClient({
SDK ukljucuje TypeScript definicije za sve API tipove. Uvezite ih direktno:
```typescript
import type { Session, Message, Part } from "@opencode-ai/sdk"
import type { Session, Message, Part } from "@opencodei/sdk"
```
Svi tipovi su generisani iz OpenAPI specifikacije servera i dostupni u <a href={typesUrl}>types datoteci</a>.
@@ -226,7 +226,7 @@ const { providers, default: defaults } = await client.config.providers()
### Sessions
| Metoda | Opis | Napomene |
| Method | Description | Notes |
| ---------------------------------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `session.list()` | List sessions | Returns <a href={typesUrl}><code>Session[]</code></a> |
| `session.get({ path })` | Get session | Returns <a href={typesUrl}><code>Session</code></a> |
@@ -283,7 +283,7 @@ await client.session.prompt({
### Files
| Metoda | Opis | Odgovor |
| Method | Description | Response |
| ------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------- |
| `find.text({ query })` | Search for text in files | Array of match objects with `path`, `lines`, `line_number`, `absolute_offset`, `submatches` |
| `find.files({ query })` | Find files and directories by name | `string[]` (paths) |
@@ -324,7 +324,7 @@ const content = await client.file.read({
### TUI
| Metoda | Opis | Odgovor |
| Method | Description | Response |
| ------------------------------ | ------------------------- | --------- |
| `tui.appendPrompt({ body })` | Append text to the prompt | `boolean` |
| `tui.openHelp()` | Open the help dialog | `boolean` |
@@ -355,7 +355,7 @@ await client.tui.showToast({
### Auth
| Metoda | Opis | Odgovor |
| Method | Description | Response |
| ------------------- | ------------------------------ | --------- |
| `auth.set({ ... })` | Set authentication credentials | `boolean` |
@@ -374,7 +374,7 @@ await client.auth.set({
### Events
| Metoda | Opis | Odgovor |
| Method | Description | Response |
| ------------------- | ------------------------- | ------------------------- |
| `event.subscribe()` | Server-sent events stream | Server-sent events stream |

View File

@@ -86,7 +86,7 @@ opencode server izlaže sljedece API-je.
### Global
| Metoda | Putanja | Opis | Odgovor |
| Method | Path | Description | Response |
| ------ | ---------------- | ------------------------------ | ------------------------------------ |
| `GET` | `/global/health` | Get server health and version | `{ healthy: true, version: string }` |
| `GET` | `/global/event` | Get global events (SSE stream) | Event stream |
@@ -95,7 +95,7 @@ opencode server izlaže sljedece API-je.
### Project
| Metoda | Putanja | Opis | Odgovor |
| Method | Path | Description | Response |
| ------ | ------------------ | ----------------------- | --------------------------------------------- |
| `GET` | `/project` | List all projects | <a href={typesUrl}><code>Project[]</code></a> |
| `GET` | `/project/current` | Get the current project | <a href={typesUrl}><code>Project</code></a> |
@@ -104,7 +104,7 @@ opencode server izlaže sljedece API-je.
### Path & VCS
| Metoda | Putanja | Opis | Odgovor |
| Method | Path | Description | Response |
| ------ | ------- | ------------------------------------ | ------------------------------------------- |
| `GET` | `/path` | Get the current path | <a href={typesUrl}><code>Path</code></a> |
| `GET` | `/vcs` | Get VCS info for the current project | <a href={typesUrl}><code>VcsInfo</code></a> |
@@ -113,7 +113,7 @@ opencode server izlaže sljedece API-je.
### Instance
| Metoda | Putanja | Opis | Odgovor |
| Method | Path | Description | Response |
| ------ | ------------------- | ---------------------------- | --------- |
| `POST` | `/instance/dispose` | Dispose the current instance | `boolean` |
@@ -121,7 +121,7 @@ opencode server izlaže sljedece API-je.
### Config
| Metoda | Putanja | Opis | Odgovor |
| Method | Path | Description | Response |
| ------- | ------------------- | --------------------------------- | ---------------------------------------------------------------------------------------- |
| `GET` | `/config` | Get config info | <a href={typesUrl}><code>Config</code></a> |
| `PATCH` | `/config` | Update config | <a href={typesUrl}><code>Config</code></a> |
@@ -131,7 +131,7 @@ opencode server izlaže sljedece API-je.
### Provider
| Metoda | Putanja | Opis | Odgovor |
| Method | Path | Description | Response |
| ------ | -------------------------------- | ------------------------------------ | ----------------------------------------------------------------------------------- |
| `GET` | `/provider` | List all providers | `{ all: `<a href={typesUrl}>Provider[]</a>`, default: {...}, connected: string[] }` |
| `GET` | `/provider/auth` | Get provider authentication methods | `{ [providerID: string]: `<a href={typesUrl}>ProviderAuthMethod[]</a>` }` |
@@ -142,7 +142,7 @@ opencode server izlaže sljedece API-je.
### Sessions
| Metoda | Putanja | Opis | Napomene |
| Method | Path | Description | Notes |
| -------- | ---------------------------------------- | ------------------------------------- | ---------------------------------------------------------------------------------- |
| `GET` | `/session` | List all sessions | Returns <a href={typesUrl}><code>Session[]</code></a> |
| `POST` | `/session` | Create a new session | body: `{ parentID?, title? }`, returns <a href={typesUrl}><code>Session</code></a> |
@@ -167,7 +167,7 @@ opencode server izlaže sljedece API-je.
### Messages
| Metoda | Putanja | Opis | Napomene |
| Method | Path | Description | Notes |
| ------ | --------------------------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET` | `/session/:id/message` | List messages in a session | query: `limit?`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}[]` |
| `POST` | `/session/:id/message` | Send a message and wait for response | body: `{ messageID?, model?, agent?, noReply?, system?, tools?, parts }`, returns `{ info: `<a href={typesUrl}>Message</a>`, parts: `<a href={typesUrl}>Part[]</a>`}` |
@@ -180,7 +180,7 @@ opencode server izlaže sljedece API-je.
### Commands
| Metoda | Putanja | Opis | Odgovor |
| Method | Path | Description | Response |
| ------ | ---------- | ----------------- | --------------------------------------------- |
| `GET` | `/command` | List all commands | <a href={typesUrl}><code>Command[]</code></a> |
@@ -188,7 +188,7 @@ opencode server izlaže sljedece API-je.
### Files
| Metoda | Putanja | Opis | Odgovor |
| Method | Path | Description | Response |
| ------ | ------------------------ | ---------------------------------- | ------------------------------------------------------------------------------------------- |
| `GET` | `/find?pattern=<pat>` | Search for text in files | Array of match objects with `path`, `lines`, `line_number`, `absolute_offset`, `submatches` |
| `GET` | `/find/file?query=<q>` | Find files and directories by name | `string[]` (paths) |
@@ -209,7 +209,7 @@ opencode server izlaže sljedece API-je.
### Tools (Experimental)
| Metoda | Putanja | Opis | Odgovor |
| Method | Path | Description | Response |
| ------ | ------------------------------------------- | ---------------------------------------- | -------------------------------------------- |
| `GET` | `/experimental/tool/ids` | List all tool IDs | <a href={typesUrl}><code>ToolIDs</code></a> |
| `GET` | `/experimental/tool?provider=<p>&model=<m>` | List tools with JSON schemas for a model | <a href={typesUrl}><code>ToolList</code></a> |
@@ -218,7 +218,7 @@ opencode server izlaže sljedece API-je.
### LSP, Formatters & MCP
| Metoda | Putanja | Opis | Odgovor |
| Method | Path | Description | Response |
| ------ | ------------ | -------------------------- | -------------------------------------------------------- |
| `GET` | `/lsp` | Get LSP server status | <a href={typesUrl}><code>LSPStatus[]</code></a> |
| `GET` | `/formatter` | Get formatter status | <a href={typesUrl}><code>FormatterStatus[]</code></a> |
@@ -229,7 +229,7 @@ opencode server izlaže sljedece API-je.
### Agents
| Metoda | Putanja | Opis | Odgovor |
| Method | Path | Description | Response |
| ------ | -------- | ------------------------- | ------------------------------------------- |
| `GET` | `/agent` | List all available agents | <a href={typesUrl}><code>Agent[]</code></a> |
@@ -237,15 +237,15 @@ opencode server izlaže sljedece API-je.
### Logging
| Metoda | Putanja | Opis | Odgovor |
| ------ | ------- | ------------------------------------------------------------ | --------- |
| `POST` | `/log` | Write log entry. Body: `{ service, level, message, extra? }` | `boolean` |
| Method | Path | Description | Response |
| ------ | ------ | ------------------------------------------------------------ | --------- |
| `POST` | `/log` | Write log entry. Body: `{ service, level, message, extra? }` | `boolean` |
---
### TUI
| Metoda | Putanja | Opis | Odgovor |
| Method | Path | Description | Response |
| ------ | ----------------------- | ------------------------------------------- | ---------------------- |
| `POST` | `/tui/append-prompt` | Append text to the prompt | `boolean` |
| `POST` | `/tui/open-help` | Open the help dialog | `boolean` |
@@ -263,7 +263,7 @@ opencode server izlaže sljedece API-je.
### Auth
| Metoda | Putanja | Opis | Odgovor |
| Method | Path | Description | Response |
| ------ | ----------- | --------------------------------------------------------------- | --------- |
| `PUT` | `/auth/:id` | Set authentication credentials. Body must match provider schema | `boolean` |
@@ -271,7 +271,7 @@ opencode server izlaže sljedece API-je.
### Events
| Metoda | Putanja | Opis | Odgovor |
| Method | Path | Description | Response |
| ------ | -------- | ----------------------------------------------------------------------------- | ------------------------- |
| `GET` | `/event` | Server-sent events stream. First event is `server.connected`, then bus events | Server-sent events stream |
@@ -279,6 +279,6 @@ opencode server izlaže sljedece API-je.
### Docs
| Metoda | Putanja | Opis | Odgovor |
| ------ | ------- | ------------------------- | --------------------------- |
| `GET` | `/doc` | OpenAPI 3.1 specification | HTML page with OpenAPI spec |
| Method | Path | Description | Response |
| ------ | ------ | ------------------------- | --------------------------- |
| `GET` | `/doc` | OpenAPI 3.1 specification | HTML page with OpenAPI spec |

View File

@@ -7,7 +7,7 @@ Da biste otklonili probleme s OpenCode, počnite provjeravanjem dnevnika i lokal
---
## Logovi
## Dnevnici
Log fajlovi se pišu na:
@@ -242,6 +242,8 @@ Da biste ovo riješili:
```bash
rm -rf ~/.local/share/opencode
```
Na Windows-u pritisnite `WIN+R` i izbrišite: `%USERPROFILE%\.local\share\opencode`
@@ -260,6 +262,8 @@ Da biste riješili probleme s paketom dobavljača:
```bash
rm -rf ~/.cache/opencode
```
Na Windows-u pritisnite `WIN+R` i izbrišite: `%USERPROFILE%\.cache\opencode`

View File

@@ -292,7 +292,7 @@ Obje naredbe `/editor` i `/export` koriste editor specificiran u vašoj varijabl
<Tabs>
<TabItem label="Linux/macOS">
```bash
```bash
# Example for nano or vim
export EDITOR=nano
export EDITOR=vim
@@ -300,7 +300,9 @@ Obje naredbe `/editor` i `/export` koriste editor specificiran u vašoj varijabl
# For GUI editors, VS Code, Cursor, VSCodium, Windsurf, Zed, etc.
# include --wait
export EDITOR="code --wait"
```
```
Da biste ga učinili trajnim, dodajte ovo u svoj shell profil;
`~/.bashrc`, `~/.zshrc`, itd.
@@ -309,13 +311,15 @@ Obje naredbe `/editor` i `/export` koriste editor specificiran u vašoj varijabl
<TabItem label="Windows (CMD)">
```bash
```bash
set EDITOR=notepad
# For GUI editors, VS Code, Cursor, VSCodium, Windsurf, Zed, etc.
# include --wait
set EDITOR=code --wait
```
```
Da biste ga učinili trajnim, koristite **Svojstva sistema** > **Okruženje
Varijable**.
@@ -324,13 +328,15 @@ Obje naredbe `/editor` i `/export` koriste editor specificiran u vašoj varijabl
<TabItem label="Windows (PowerShell)">
```powershell
```powershell
$env:EDITOR = "notepad"
# For GUI editors, VS Code, Cursor, VSCodium, Windsurf, Zed, etc.
# include --wait
$env:EDITOR = "code --wait"
```
```
Da biste ga učinili trajnim, dodajte ovo u svoj PowerShell profil.
@@ -340,13 +346,13 @@ Obje naredbe `/editor` i `/export` koriste editor specificiran u vašoj varijabl
Popularne opcije uređivača uključuju:
- `code` - Visual Studio Code
- `cursor` - Cursor
- `windsurf` - Windsurf
- `cursor` - Kursor
- `windsurf` - jedrenje na dasci
- `nvim` - Neovim editorom
- `vim` - Vim editor
- `nano` - Nano editor
- `notepad` - Windows Notepad
- `subl` - Sublime Text
- `subl` - Uzvišeni tekst
:::note
Neki uređivači kao što je VS Code moraju biti pokrenuti sa `--wait` zastavicom.

View File

@@ -17,7 +17,7 @@ Zen radi kao i svaki drugi provajder u OpenCode. Prijavite se u OpenCode Zen i u
---
## Pozadina
## Background
Postoji veliki broj modela, ali samo mali dio radi dobro kao coding agent. Dodatno, vecina provajdera je drugacije konfigurisana, pa su performanse i kvalitet cesto neujednaceni.
@@ -99,7 +99,7 @@ https://opencode.ai/zen/v1/models
---
## Cijene
## Pricing
Podrzavamo pay-as-you-go model. Ispod su cijene **po 1M tokena**.
@@ -156,7 +156,7 @@ Ako imate pitanja, <a href={email}>kontaktirajte nas</a>.
---
### Automatska dopuna
### Auto-reload
Ako vam stanje padne ispod $5, Zen ce automatski dopuniti $20.
@@ -164,7 +164,7 @@ Iznos auto-reloada mozete promijeniti. Auto-reload mozete i potpuno iskljuciti.
---
### Mjesečni limiti
### Monthly limits
Mozete postaviti mjesecni limit potrosnje za cijeli workspace i za svakog clana tima.
@@ -172,7 +172,7 @@ Na primjer, ako postavite mjesecni limit na $20, Zen nece potrositi vise od $20
---
## Privatnost
## Privacy
Svi nasi modeli su hostovani u SAD-u. Provajderi prate zero-retention politiku i ne koriste vase podatke za treniranje modela, uz sljedece izuzetke:
@@ -185,7 +185,7 @@ Svi nasi modeli su hostovani u SAD-u. Provajderi prate zero-retention politiku i
---
## Za timove
## For Teams
Zen odlicno radi i za timove. Mozete pozvati clanove tima, dodijeliti uloge, birati modele koje tim koristi i jos mnogo toga.
@@ -197,7 +197,7 @@ Upravljanje workspace-om je trenutno besplatno za timove tokom beta faze. Vise d
---
### Uloge
### Roles
Mozete pozvati clanove tima u workspace i dodijeliti uloge:
@@ -208,7 +208,7 @@ Admini mogu postaviti i mjesecne limite potrosnje po clanu da drze troskove pod
---
### Pristup modelima
### Model access
Admini mogu ukljuciti ili iskljuciti odredene modele za workspace. Zahtjevi prema iskljucenom modelu vracaju gresku.
@@ -216,7 +216,7 @@ Ovo je korisno kada zelite zabraniti model koji prikuplja podatke.
---
### Donesite vlastiti ključ
### Bring your own key
Mozete koristiti vlastite OpenAI ili Anthropic API kljuceve i dalje koristiti ostale modele u Zen-u.
@@ -226,7 +226,7 @@ Na primjer, vasa organizacija mozda vec ima OpenAI ili Anthropic kljuc i zelite
---
## Ciljevi
## Goals
OpenCode Zen smo napravili da:

View File

@@ -490,15 +490,13 @@ You can control context compaction behavior through the `compaction` option.
"$schema": "https://opencode.ai/config.json",
"compaction": {
"auto": true,
"prune": true,
"reserved": 10000
"prune": true
}
}
```
- `auto` - Automatically compact the session when context is full (default: `true`).
- `prune` - Remove old tool outputs to save tokens (default: `true`).
- `reserved` - Token buffer for compaction. Leaves enough window to avoid overflow during compaction
---

View File

@@ -6,7 +6,7 @@ description: Brug OpenCode i enhver ACP-kompatibel editor.
OpenCode understøtter [Agent Client Protocol](https://agentclientprotocol.com) eller (ACP), så du kan bruge det direkte i kompatible editorer og IDE'er.
:::tip
For en liste over editorer og værktøjer, der understøtter ACP, tjek [ACP fremskridtsrapport](https://zed.dev/blog/acp-progress-report#available-now).
For en liste over redaktører og værktøjer, der understøtter ACP, tjek [ACP progress report](https://zed.dev/blog/acp-progress-report#available-now).
:::
ACP er en åben protokol, der standardiserer kommunikation mellem kodeeditorer og AI-kodningsagenter.
@@ -19,7 +19,7 @@ For at bruge OpenCode via ACP, konfigurer din editor til at køre kommandoen `op
Kommandoen starter OpenCode som en ACP-kompatibel underproces, der kommunikerer med din editor over JSON-RPC via stdio.
Nedenfor er eksempler på populære editorer, der understøtter ACP.
Nedenfor er eksempler på populære redaktører, der understøtter ACP.
---
@@ -69,7 +69,7 @@ Du kan også binde en tastaturgenvej ved at redigere din `keymap.json`:
### JetBrains IDE'er
Tilføj til din [JetBrains IDE](https://www.jetbrains.com/) acp.json i henhold til [dokumentationen](https://www.jetbrains.com/help/ai-assistant/acp.html):
Tilføj til din [JetBrains IDE](https://www.jetbrains.com/) acp.json i henhold til [documentation](https://www.jetbrains.com/help/ai-assistant/acp.html):
```json title="acp.json"
{
@@ -138,18 +138,18 @@ require("codecompanion").setup({
Denne konfiguration sætter CodeCompanion til at bruge OpenCode som ACP-agent til chat.
Hvis du har brug for at sende miljøvariabler (som `OPENCODE_API_KEY`), henvises til [Konfiguration af adaptere: Miljøvariabler](https://codecompanion.olimorris.dev/getting-started#setting-an-api-key) i CodeCompanion.nvim-dokumentationen for alle detaljer.
Hvis du har brug for at sende miljøvariabler (som `OPENCODE_API_KEY`), henvises til [Configuring Adapters: Environment Variables](https://codecompanion.olimorris.dev/getting-started#setting-an-api-key) i CodeCompanion.nvim-dokumentationen for alle detaljer.
## Support
OpenCode fungerer på samme måde via ACP som i terminalen. Alle funktioner understøtter:
:::note
Nogle indbyggede slash-kommandoer som `/undo` og `/redo` er i øjeblikket ikke understøttet.
Nogle indbyggede skråstreg-kommandoer som `/undo` og `/redo` er i øjeblikket ikke understøttet.
:::
- Indbyggede værktøjer (filoperationer, terminalkommandoer osv.)
- Brugerdefinerede værktøjer og slash-kommandoer
- Brugerdefinerede værktøjer og skråstreg-kommandoer
- MCP-servere konfigureret i din OpenCode-konfiguration
- Projektspecifikke regler fra `AGENTS.md`
- Brugerdefinerede formatere og linters

View File

@@ -15,7 +15,7 @@ Du kan skifte mellem agenter under en session eller kalde dem med `@`-omtalen.
## Skriver
Der er to typer agenter i OpenCode; primære agenter og subagenter.
Der er to typer agenter i OpenCode; primære midler og subagenter.
---
@@ -27,7 +27,7 @@ Primære agenter er de vigtigste assistenter, du interagerer direkte med. Du kan
Du kan bruge **Tab**-tasten til at skifte mellem primære agenter under en session.
:::
OpenCode leveres med indbyggede primære agenter, **Build** og **Plan**. Vi vil
OpenCode leveres med indbyggede primære agenter, **Build** og **Plan**. Godt
se på disse nedenfor.
---
@@ -36,7 +36,7 @@ se på disse nedenfor.
Subagenter er specialiserede assistenter, som primære agenter kan påbegynde sig til specifikke opgaver. Du kan også kalde dem manuelt ved at **@ nævne** dem i dine beskeder.
OpenCode leveres med to indbyggede underagenter, **Generelt** og **Udforsk**. Vi vil se på dette nedenfor.
OpenCode leveres med til indbyggede underagenter, **Generelt** og **Udforsk**. Vi vil se på dette nedenfor.
---
@@ -121,8 +121,8 @@ Skjult systemagent, der opretter sessionsoversigter. Den kører automatisk og ka
```
3. **Navigation mellem sessioner**: Når underagenter opretter deres egne underordnede sessioner, kan du navigere mellem den overordnede session og alle underordnede sessioner ved hjælp af:
- **\<Leader>+Højre** (eller din konfigurerede `session_child_cycle`-tastebinding) for at cykle fremad gennem forælder → barn1 → barn2 →... → forælder
- **\<Leader>+Venstre** (eller din konfigurerede `session_child_cycle_reverse`-tastebinding) for at cykle baglæns gennem forælder ← barn1 ← barn2 ←... ← forælder
- **\<Leder>+Højre** (eller din konfigurerede `session_child_cycle`-smagsbinding) for at cykle fremad gennem forælder → barn1 → barn2 →... → forælder
- **\<Leder>+Venstre** (eller din konfigurerede `session_child_cycle_reverse`-smagsbinding) for at cykle baglæns gennem forælder ← barn1 ← barn2 ←... ← forælder
Dette giver dig mulighed for problemfrit at skifte mellem hovedsamtalen og specialiseret subagent arbejde.
@@ -136,7 +136,7 @@ Du kan tilpasse de indbyggede agenter eller oprette dine egne gennem konfigurati
### JSON
Konfigurer agent i din `opencode.json`-konfigurationsfil:
Konfigurationsagent i din `opencode.json`-konfigurationsfil:
```json title="opencode.json"
{
@@ -302,7 +302,7 @@ Hvis dette ikke er indstillet, vil agenten fortsætte med at iterere, indtil mod
Når grænsen er nået, modtager agenten en speciel systemprompt, der instruerer den om at svare med en opsummering af sit arbejde og anbefalede resterende opgaver.
:::caution
Det gamle `maxSteps`-felt er forældet. Brug `steps` i stedet.
Det gamle `maxSteps`lte er forældet. Brug `steps` i stedet.
:::
---
@@ -346,7 +346,7 @@ Denne sti er i forhold til, hvor konfigurationsfilen er placeret. Så dette virk
Brug `model`-konfigurationen til at tilsidesætte modeller for denne agent. Nyttigt til brug af forskellige modeller optimeret til forskellige opgaver. For eksempel en hurtigere model til planlægning, en dygtig model til implementering.
:::tip
Hvis du ikke angiver en model, bruger primære agenter [model konfigureret globalt](/docs/config#models), mens subagenter vil bruge modeller for den primære agent, der påkaldte subagenten.
Hvis du ikke angiver en model, bruger primære agenter [model globally configured](/docs/config#models), mens subagenter vil bruge modeller for den primære agent, der påkaldte subagenten.
:::
```json title="opencode.json"
@@ -406,7 +406,7 @@ Du kan også bruge jokertegn til at styre flere værktøjer på én gang. For ek
}
```
[Læs mere om værktøjer](/docs/tools).
[Learn more about tools](/docs/tools).
---
@@ -518,7 +518,7 @@ Da den sidste matchningsregel har forrang, skal du sætte jokertegnet `*` først
}
```
[Læs mere om tilladelser](/docs/permissions).
[Learn more about permissions](/docs/permissions).
---
@@ -697,7 +697,7 @@ Her er nogle almindelige use cases for forskellige agenter.
Her er nogle eksempler på agenter, du kan finde nyttige.
:::tip
Har du en agent, du gerne vil dele? [Send en PR](https://github.com/anomalyco/opencode).
Har du en agent, du gerne vil dele? [Submit a PR](https://github.com/anomalyco/opencode).
:::
---

View File

@@ -530,9 +530,9 @@ opencode upgrade v0.1.48
#### upgrade
| Flag | Kort | Beskrivelse |
| ---------- | ---- | ---------------------------------------------------------------- |
| `--method` | `-m` | Installationsmetoden, der blev brugt; curl, npm, pnpm, bun, brew |
| Flag | Kort | Beskrivelse |
| ---------- | ---- | -------------------------------------------------------------------- |
| `--method` | `-m` | Installationsmetoden, der blev brugt; krølle, npm, pnpm, bolle, bryg |
---
@@ -540,12 +540,12 @@ opencode upgrade v0.1.48
opencode CLI tager følgende globale flag.
| Flag | Kort | Beskrivelse |
| -------------- | ---- | ------------------------------------ |
| `--help` | `-h` | Vis hjælp |
| `--version` | `-v` | Udskriftsversionsnummer |
| `--print-logs` | | Udskriv logfiler til stderr |
| `--log-level` | | Logniveau (DEBUG, INFO, WARN, ERROR) |
| Flag | Kort | Beskrivelse |
| -------------- | ---- | --------------------------------------- |
| `--help` | `-h` | Vis hjælp |
| `--version` | `-v` | Udskriftsversionsnummer |
| `--print-logs` | | Udskriv logfiler til stderr |
| `--log-level` | | Logniveau (DEBUG, INFO, ADVARSEL, FEJL) |
---

View File

@@ -52,7 +52,7 @@ Konfigurationskilder indlæses i denne rækkefølge (senere kilder tilsidesætte
Dette betyder, at projektkonfigurationer kan tilsidesætte globale standardindstillinger, og globale konfigurationer kan tilsidesætte eksterne organisatoriske standarder.
:::note
`.opencode` og `~/.config/opencode` mapperne bruger **flertalsnavne** for undermapper: `agents/`, `commands/`, `modes/`, `plugins/`, `skills/`, `tools/` og `themes/`. Enkelte navne (f.eks. `agent/`) understøtter også bagudkompatibilitet.
`.opencode` og `~/.config/opencode` bibliotekerne bruger **flertalsnavne** for undermapper: `agents/`, `commands/`, `modes/`, `plugins/`, `skills/`, `tools/` og `themes/`. Enkelte navne (f.eks. `agent/`) understøtter også bagudkompatibilitet.
:::
---
@@ -109,7 +109,7 @@ Tilføj `opencode.json` i dit projektrod. Project config har den højeste forran
Placer projektspecifik konfiguration i roden af dit projekt.
:::
Når OpenCode starter op, søger den efter en konfigurationsfil i den aktuelle mappe eller går op til den nærmeste Git-mappe.
Når OpenCode starter op, søger den efter en konfigurationsfil i det aktuelle kort eller går op til den nærmeste Git-mappe.
Dette er også sikkert at blive tjekket ind i Git og bruger det samme skema som det globale.
@@ -132,7 +132,7 @@ Brugerdefineret konfigurationsindlæses mellem globale konfigurationer og projek
Angiv en brugerdefineret konfigurationsmappe ved hjælp af `OPENCODE_CONFIG_DIR`
miljøvariabel. Dette kort vil blive søgt efter agenter, kommandoer,
modes og plugins ligesom standard `.opencode` mappen, og bør
modes og plugins ligesom standard `.opencode` biblioteket, og bør
følge samme struktur.
```bash
@@ -140,7 +140,7 @@ export OPENCODE_CONFIG_DIR=/path/to/my/config-directory
opencode run "Hello world"
```
Den brugerdefinerede mappe indlæses efter den globale konfig og `.opencode` mapper, så den **kan tilsidesætte** deres indstillinger.
Den brugerdefinerede map indlæses efter den globale konfig og `.opencode` mapper, så den **kan tilsidesætte** deres indstillinger.
---
@@ -268,7 +268,7 @@ Du kan også konfigurere [local models](/docs/models#local). [Learn more](/docs/
Nogle udbydere understøtter yderligere konfigurationsmuligheder ud over de generiske `timeout` og `apiKey` indstillinger.
##### Amazon Bedrock
##### Amazonas grundfjeld
Amazon Bedrock understøtter AWS-specifik konfiguration:
@@ -287,12 +287,12 @@ Amazon Bedrock understøtter AWS-specifik konfiguration:
}
```
- `region` - AWS region for Bedrock (standard til `AWS_REGION` env var eller `us-east-1`)
- `region` - AWS region for grundfjeld (standard til `AWS_REGION` env var eller `us-east-1`)
- `profile` - AWS navngivet profil fra `~/.aws/credentials` (standard til `AWS_PROFILE` env var)
- `endpoint` - Brugerdefineret slutpunkt URL for VPC-endepunkter. Dette er et alias for den generiske `baseURL`-indstilling, der bruger AWS-specifik terminologi. Hvis begge er angivet, har `endpoint` forrang.
:::note
Bearer tokens (`AWS_BEARER_TOKEN_BEDROCK` eller `/connect`) har forrang over profilbaseret godkendelse. Se [authentication precedence](/docs/providers#authentication-precedence) for detaljer.
Bærer-tokens (`AWS_BEARER_TOKEN_BEDROCK` eller `/connect`) har forrang over profilbaseret godkendelse. Se [authentication precedence](/docs/providers#authentication-precedence) for detaljer.
:::
[Learn more about Amazon Bedrock configuration](/docs/providers#amazon-bedrock).

View File

@@ -1,6 +1,6 @@
---
title: GitHub
description: Brug OpenCode i GitHub-problemer og Pull Requests.
description: Brug OpenCode i GitHub-problemer og pull-anmodninger.
---
OpenCode integreres med din GitHub arbejdsgang. Nævn `/opencode` eller `/oc` i din kommentar, og OpenCode vil udføre opgaver i din GitHub Actions-løber.
@@ -10,7 +10,7 @@ OpenCode integreres med din GitHub arbejdsgang. Nævn `/opencode` eller `/oc` i
## Funktioner
- **Triageproblemer**: Bed OpenCode om at undersøge et problem og forklare dig det.
- **Ret og implementer**: Bed OpenCode om at løse et problem eller implementere en funktion. Og det vil fungere i en ny branch og indsende en PR med alle ændringerne.
- **Ret og implementer**: Bed OpenCode om at løse et problem eller implementere en funktion. Og det vil fungere i en ny afdeling og indsende en PR med alle ændringerne.
- **Sikker**: OpenCode løber inde i din GitHubs løbere.
---
@@ -85,7 +85,7 @@ Eller du kan indstille det manuelt.
- `agent`: Agenten, der skal bruges. Skal være en primær agent. Falder tilbage til `default_agent` fra config eller `"build"`, hvis den ikke findes.
- `share`: Om OpenCode-sessionen skal dele. Standard er **true** for offentlige arkiver.
- `prompt`: Valgfri brugerdefineret prompt for at tilsidesætte standardadfærden. Brug dette til at tilpasse, hvordan OpenCode behandler anmodninger.
- `token`: Valgfrit GitHub adgangstoken til at udføre operationer såsom oprettelse af kommentarer, begå ændringer og åbning af Pull Requests. Som standard bruger OpenCode installationsadgangstokenet fra OpenCode GitHub-appen, så commits, kommentarer og Pull Requests ser ud til at komme fra appen.
- `token`: Valgfrit GitHub adgangstoken til at udføre operationer såsom oprettelse af kommentarer, begå ændringer og åbning af pull-anmodninger. Som standard bruger OpenCode installationsadgangstokenet fra OpenCode GitHub-appen, så commits, kommentarer og pull-anmodninger ser ud til at komme fra appen.
Alternativt kan du bruge GitHub Action runners [built-in `GITHUB_TOKEN`](OpenCode) uden at installere OpenCode GitHub appen. Bare sørg for at give de nødvendige tilladelser i dit workflow:
@@ -107,10 +107,10 @@ OpenCode kan udløses af følgende GitHub hændelser:
| Begivenhedstype | Udløst af | Detaljer |
| ----------------------------- | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `issue_comment` | Kommentarer og problemer eller PR | Nævn `/opencode` eller `/oc` i din kommentar. OpenCode læser kontekst og kan oprette brancher, åbne PR'er eller svare. |
| `issue_comment` | Kommentarer og problemer eller PR | Nævn `/opencode` eller `/oc` i din kommentar. OpenCode læser kontekst og kan oprette filialer, åbne PR'er eller svare. |
| `pull_request_review_comment` | Kommenter specifikke kodelinjer i en PR | Nævn `/opencode` eller `/oc`, mens du gennemgår koden. OpenCode modtager filsti, linjenumre og diff-kontekst. |
| `issues` | Udgave åbnet eller redigeret | Udløs automatisk OpenCode, når problemer oprettes eller ændres. Kræver `prompt` input. |
| `pull_request` | PR åbnet eller opdateret | Udløs automatisk OpenCode, når PR'er åbnes, synkroniseres eller genåbnes. Nyttigt til automatiserede kodegennemgange. |
| `pull_request` | PR åbnet eller opdateret | Udløs automatisk OpenCode, når PR'er åbnes, synkroniseres eller genåbnes. Nyttigt til automatiserede anmeldelser. |
| `schedule` | Cron-baseret tidsplan | Kør OpenCode efter en tidsplan. Kræver `prompt` input. Output går til logfiler og PR'er (intet problem ved kommentere). |
| `workflow_dispatch` | Manuel trigger fra GitHub UI | Udløs OpenCode efter behov via fanen Handlinger. Kræver `prompt` input. Output går til logfiler og PR'er. |
@@ -150,7 +150,7 @@ jobs:
If you find issues worth addressing, open an issue to track them.
```
For planlagte begivenheder er `prompt` input **påkrævet**, da der ikke er nogen kommentarer at udtrække instruktioner fra. Planlagte arbejdsgange kører uden en brugerkontekst til kontrol af tilladelser, så arbejdsgangen skal give `contents: write` og `pull-requests: write`, hvis du forventer, at OpenCode skal oprette brancher eller PR'er.
For planlagte begivenheder er `prompt` input **påkrævet**, da der ikke er nogen kommentarer at udtrække instruktioner fra. Planlagte arbejdsgange kører uden en brugerkontekst til kontrol af tilladelser, så arbejdsgangen skal give `contents: write` og `pull-requests: write`, hvis du forventer, at OpenCode skal oprette filialer eller PR'er.
---
@@ -191,7 +191,7 @@ jobs:
- Suggest improvements
```
For `pull_request` hændelser, hvis der ikke er angivet nogen `prompt`, vil OpenCode som standard gennemgå Pull Requesten.
For `pull_request` hændelser, hvis der ikke er angivet nogen `prompt`, vil OpenCode som standard gennemgå pull-anmodningen.
---
@@ -291,7 +291,7 @@ Her er nogle eksempler på, hvordan du kan bruge OpenCode i GitHub.
/opencode fix this
```
Og OpenCode vil oprette en ny branch, implementere ændringer og åbne en PR med ændringer.
Og OpenCode vil oprette en ny filial, implementere ændringer og åbne en PR med ændringer.
- **Gennemgå PR'er og foretag ændringer**

View File

@@ -1,6 +1,6 @@
---
title: GitLab
description: Brug OpenCode i GitLab-problemer og Merge Requests.
description: Brug OpenCode i GitLab-problemer og fletteanmodninger.
---
OpenCode integreres med din GitLab-arbejdsgang gennem din GitLab CI/CD-pipeline eller med GitLab Duo.
@@ -27,7 +27,7 @@ Her bruger vi en community-skabt CI/CD-komponent til OpenCode — [nagyv/gitlab-
### Opsætning
1. Gem din OpenCode-autentificering JSON som en filtype CI-miljøvariabel under **Indstillinger** > **CI/CD** > **Variabler**. Sørg for at markere dem som "Maskede og skjulte".
1. Gem din OpenCode-godkendelse JSON som en filtype CI-miljøvariabel under **Indstillinger** > **CI/CD** > **Variabler**. Sørg for at markere dem som "Maskede og skjulte".
2. Tilføj følgende til din `.gitlab-ci.yml` fil.
```yaml title=".gitlab-ci.yml"
@@ -55,7 +55,7 @@ Nævn `@opencode` i en kommentar, og OpenCode vil udføre opgaver i din GitLab C
- **Triageproblemer**: Bed OpenCode om at undersøge et problem og forklare dig det.
- **Ret og implementer**: Bed OpenCode om at løse et problem eller implementere en funktion.
Det vil oprette en ny branch og rejse en Merge Request med ændringer.
Det vil oprette en ny filial og rejse en fletteanmodning med ændringer.
- **Sikker**: OpenCode kører på dine GitLab-løbere.
---
@@ -182,14 +182,14 @@ Du kan konfigurere til at bruge en anden udløsersætning end `@opencode`.
@opencode fix this
```
OpenCode vil oprette en ny branch, implementere ændringer og åbne en Merge Request med ændringer.
OpenCode vil oprette en ny filial, implementere ændringer og åbne en fletteanmodning med ændringer.
- **Gennemgå Merge Requests**
- **Gennemgå anmodninger om fletning**
Efterlad følgende kommentar til en GitLab-Merge Request.
Efterlad følgende kommentar til en GitLab-fletningsanmodning.
```
@opencode review this merge request
```
OpenCode vil gennemgå din Merge Request og give feedback.
OpenCode vil gennemgå anmodningen om fletning og give feedback.

View File

@@ -9,7 +9,7 @@ export const console = config.console
[**OpenCode**](/) er en open source AI-kodningsagent. Den er tilgængelig som en terminalbaseret grænseflade, desktop-app eller IDE-udvidelse.
![OpenCode TUI med opencode-temaet](../../../assets/lander/screenshot.png)
![OpenCode TUI with the opencode theme](../../../assets/lander/screenshot.png)
Lad os komme i gang.
@@ -79,7 +79,7 @@ Du kan også installere det med følgende kommandoer:
brew install anomalyco/tap/opencode
```
> Vi anbefaler at bruge OpenCode-tap for at få de mest opdaterede udgivelser. Den officielle `brew install opencode`-formel vedligeholdes af Homebrew-teamet og opdateret sjældnere.
> Vi anbefaler at bruge OpenCode-hanen for at få de mest opdaterede udgivelser. Den officielle `brew install opencode`-formel vedligeholdes af Homebrew-teamet og opdateret sjældnere.
- **Brug af Paru på Arch Linux**
@@ -180,7 +180,7 @@ Derefter initialiseres OpenCode for projektet ved at køre følgende kommando.
```
Dette får OpenCode til at analysere dit projekt og oprette en `AGENTS.md` fil i
projektets rod.
projektets stang.
:::tip
Du bør overgive dit projekter `AGENTS.md` fil til Git.
@@ -228,7 +228,7 @@ Du kan bede OpenCode om at tilføje nye funktioner til dit projekt. Selvom vi f
Skift til det ved hjælp af **Tab**-tasten. Du vil se en indikator for dette i nederste højre hjørne.
```bash frame="none" title="Skift til Plan-tilstand"
```bash frame="none" title="Switch to Plan mode"
<TAB>
```
@@ -356,4 +356,4 @@ Her er en [eksempelsamtale](https://opencode.ai/s/4XP1fce5) med OpenCode.
Og det er det! Du er nu en professionel i at bruge OpenCode.
For at gøre det til dit eget, anbefaler vi [at vælge et tema](/docs/themes), [tilpasse genvejstaster](/docs/keybinds), [konfigurere kodeformater](/docs/formatters), [oprette brugerdefinerede kommandoer](/docs/commands) eller at lege med [OpenCode-konfiguration](/docs/config).
For at gøre det til dit eget, anbefaler vi [picking a theme](/docs/themes), [customizing the keybinds](/docs/keybinds), [configuring code formatters](/docs/formatters), [creating custom commands](/docs/commands) eller at lege med [OpenCode config](/docs/config).

View File

@@ -3,7 +3,7 @@ title: LSP Servere
description: OpenCode integreres med dine LSP-servere.
---
OpenCode integreres med Language Server Protocol (LSP) for at hjælpe LLM med at interagere med din kodebase. Den bruger diagnostik til at give feedback til LLM.
OpenCode integreres med din sprogserverprotokol (LSP) for at hjælpe LLM med at interagere med din kodebase. Den bruger diagnostik til at give feedback til LLM.
---
@@ -11,40 +11,40 @@ OpenCode integreres med Language Server Protocol (LSP) for at hjælpe LLM med at
OpenCode leveres med flere indbyggede LSP-servere til populære sprog:
| LSP Server | Udvidelser | Krav |
| ------------------ | --------------------------------------------------------- | --------------------------------------------------------------- |
| astro | .astro | Autoinstallationer til Astro-projekter |
| bash | .sh,.bash,.zsh,.ksh | Autoinstallerer bash-language-server |
| clangd | .c,.cpp,.cc,.cxx,.c++,.h,.hpp,.hh,.hxx,.h++ | Autoinstallationer for C/C++ projekter |
| csharp | .cs | `.NET SDK` installere |
| clojure-lsp | .clj,.cljs,.cljc,.edn | `clojure-lsp` kommando tilgængelig |
| dart | .dart | `dart` kommando tilgængelig |
| deno | .ts,.tsx,.js,.jsx,.mjs | `deno` kommando tilgængelig (auto-detects deno.json/deno.jsonc) |
| eliksir-ls | .ex,.exs | `elixir` kommando tilgængelig |
| eslint | .ts,.tsx,.js,.jsx,.mjs,.cjs,.mts,.cts,.vue | `eslint` afhængighed i projekt |
| fsharp | .fs,.fsi,.fsx,.fsscript | `.NET SDK` installere |
| gleam | .gleam | `gleam` kommando tilgængelig |
| gopls | .go | `go` kommando tilgængelig |
| hls | .hs,.lhs | `haskell-language-server-wrapper` kommando tilgængelig |
| jdtls | .java | `Java SDK (version 21+)` installere |
| kotlin-ls | .kt,.kts | Autoinstallationer til Kotlin-projekter |
| lua-ls | .lua | Autoinstallationer til Lua-projekter |
| nixd | .nix | `nixd` kommando tilgængelig |
| ocaml-lsp | .ml,.mli | `ocamllsp` kommando tilgængelig |
| oxlint | .ts,.tsx,.js,.jsx,.mjs,.cjs,.mts,.cts,.vue,.astro,.svelte | `oxlint` afhængighed i projekt |
| php intelephense | .php | Automatiske installationer til PHP-projekter |
| prisma | .prisma | `prisma` kommando tilgængelig |
| pyright | .py,.pyi | `pyright` afhængig installeret |
| ruby-lsp (rubocop) | .rb,.rake,.gemspec,.ru | `ruby` og `gem` kommandoer tilgængelige |
| rust | .rs | `rust-analyzer` kommando tilgængelig |
| sourcekit-lsp | .swift,.objc,.objcpp | `swift` installere (`xcode` på macOS) |
| svelte | .svelte | Autoinstallationer til Svelte-projekter |
| terraform | .tf,.tfvars | Automatiske installationer fra GitHub-udgivelser |
| tinymist | .typ,.typc | Automatiske installationer fra GitHub-udgivelser |
| typescript | .ts,.tsx,.js,.jsx,.mjs,.cjs,.mts,.cts | `typescript` afhængighed i projekt |
| vue | .vue | Autoinstallationer til Vue-projekter |
| yaml-ls | .yaml,.yml | Autoinstallerer Red Hat yaml-language-server |
| zls | .zig,.zon | `zig` kommando tilgængelig |
| LSP Server | Udvidelser | Krav |
| ------------------- | --------------------------------------------------------- | --------------------------------------------------------------- |
| astro | .astro | Autoinstallationer til Astro-projekter |
| bash | .sh,.bash,.zsh,.ksh | Autoinstallerer bash-language-server |
| clangd | .c,.cpp,.cc,.cxx,.c++,.h,.hpp,.hh,.hxx,.h++ | Autoinstallationer for C/C++ projekter |
| csharp | .cs | `.NET SDK` installere |
| clojure-lsp | .clj,.cljs,.cljc,.edn | `clojure-lsp` kommando tilgængelig |
| dart | .dart | `dart` kommando tilgængelig |
| deno | .ts,.tsx,.js,.jsx,.mjs | `deno` kommando tilgængelig (auto-detects deno.json/deno.jsonc) |
| eliksir-ls | .ex,.exs | `elixir` kommando tilgængelig |
| eslint | .ts,.tsx,.js,.jsx,.mjs,.cjs,.mts,.cts,.vue | `eslint` afhængighed i projekt |
| fskarp | .fs,.fsi,.fsx,.fsscript | `.NET SDK` installere |
| glimt | .glimt | `gleam` kommando tilgængelig |
| gopls | .go | `go` kommando tilgængelig |
| hls | .hs,.lhs | `haskell-language-server-wrapper` kommando tilgængelig |
| jdtls | .java | `Java SDK (version 21+)` installere |
| kotlin-ls | .kt,.kts | Autoinstallationer til Kotlin-projekter |
| lua-ls | .lua | Autoinstallationer til Lua-projekter |
| nixd | .nix | `nixd` kommando tilgængelig |
| ocaml-lsp | .ml,.mli | `ocamllsp` kommando tilgængelig |
| oxlint | .ts,.tsx,.js,.jsx,.mjs,.cjs,.mts,.cts,.vue,.astro,.svelte | `oxlint` afhængighed i projekt |
| php intelephense | .php | Automatiske installationer til PHP-projekter |
| prisma | .prisma | `prisma` kommando tilgængelig |
| ophavsret | .py,.pyi | `pyright` afhængig installeret |
| rubin-lsp (rubocop) | .rb,.rake,.gemspec,.ru | `ruby` og `gem` kommandoer tilgængelige |
| rust | .rs | `rust-analyzer` kommando tilgængelig |
| sourcekit-lsp | .swift,.objc,.objcpp | `swift` installere (`xcode` på macOS) |
| svelte | .svelte | Autoinstallationer til Svelte-projekter |
| terraform | .tf,.tfvars | Automatiske installationer fra GitHub-udgivelser |
| lillemand | .typ,.typc | Automatiske installationer fra GitHub-udgivelser |
| maskinskrift | .ts,.tsx,.js,.jsx,.mjs,.cjs,.mts,.cts | `typescript` afhængighed i projekt |
| vue | .vue | Autoinstallationer til Vue-projekter |
| yaml-ls | .yaml,.yml | Autoinstallerer Red Hat yaml-language-server |
| zls | .zig,.zon | `zig` kommando tilgængelig |
LSP-servere aktiveres automatisk, når en af ovnstående filtypenavne opdages, og kravene er opfyldt.
@@ -76,7 +76,7 @@ Du kan tilpasse LSP-servere gennem sektionen `lsp` i din opencode-konfiguration.
Hver LSP- server understøtter følgende:
| Egenskab | Type | Beskrivelse |
| Ejendom | Skriv | Beskrivelse |
| ---------------- | -------- | --------------------------------------------------------- |
| `disabled` | boolean | Indstil dette til `true` for at deaktivere LSP-serveren |
| `command` | string[] | Kommandoen til at starte LSP-serveren |
@@ -182,7 +182,7 @@ Du kan tilføje brugerdefinerede LSP-servere ved at angive kommandoen og filtype
PHP Intelephense tilbyder premium funktioner gennem en licensnøgle. Du kan angive en licensnøgle ved at placere (kun) nøglen i en tekstfil på:
- På macOS/Linux: `$HOME/intelephense/license.txt`
- På Windows: `%USERPROFILE%/intelephense/license.txt`
- På macOS/Linux: `$HOME/intelephense/licence.txt`
- På Windows: `%USERPROFILE%/intelephense/licence.txt`
Filen bør kun indeholde licensnøglen uden yderligere indhold.

View File

@@ -1,25 +1,25 @@
---
title: TUI
description: Bruge OpenCode-terminalbrugergrænsefladeet.
description: Bruge OpenCode-terminalbrugergrensesnittet.
---
import { Tabs, TabItem } from "@astrojs/starlight/components"
OpenCode gir et interaktivt terminalgrænseflade eller TUI for at jobbe med prosjektene dine med en LLM.
OpenCode gir et interaktivt terminalgrensesnitt eller TUI for at jobbe med prosjektene dine med en LLM.
Å køre OpenCode starter TUI for nuværende mappe.
Å kjøre OpenCode starter TUI for nuværende katalog.
```bash
opencode
```
Eller du kan starte den for en bestemt arbejdsmappe.
Eller du kan starte den for en bestemt arbejdskatalog.
```bash
opencode /path/to/project
```
Når du er i TUI, kan du spørge den med en besked.
Når du er i TUI, kan du spørre den med en melding.
```text
Give me a quick summary of the codebase.
@@ -27,9 +27,9 @@ Give me a quick summary of the codebase.
---
## Filreferencer
## Filreferanser
Du kan referere til filer i dine meddelelser med `@`. Det laver en fuzzy filsøgning i det nuværende arbejdsmappe.
Du kan referere til filer i dine meddelelser med `@`. Det laver en fuzzy filsøgning i det nuværende arbejdskatalog.
:::tip
Du kan også bruge `@` til at referere til filer i dine meddelelser.
@@ -39,19 +39,19 @@ Du kan også bruge `@` til at referere til filer i dine meddelelser.
How is auth handled in @packages/functions/src/api/index.ts?
```
Indholdet i filen tilføjes automatisk til samtalen.
Innholdet i filen tilføjes automatisk til samtalen.
---
## Bash-kommandoer
Start en besked med `!` for at køre en shell-kommando.
Start en melding med `!` for at kjøre en shell-kommando.
```bash frame="none"
!ls -la
```
Outputtet fra kommandoen tilføjes til samtalen som et værktøjresultat.
Utdataene fra kommandoen tilføjes til samtalen som et verktøyresultat.
---
@@ -63,15 +63,15 @@ Når du bruger OpenCode TUI, kan du skrive `/` etterfulgt av et kommandonavn for
/help
```
De fleste kommandoer har også genvejstast som bruger `ctrl+x` som Leader-tast, der `ctrl+x` er standard Leader-tast. [Læs mere](/docs/keybinds).
De fleste kommandoer har også tastebinding som bruger `ctrl+x` som ledernøkkel, der `ctrl+x` er standard ledernøkkel. [Finn ut mer](/docs/keybinds).
Her er alle tilgængelige skråstregskommandoer:
Her er alle tilgængelige skråstrekkommandoer:
---
### connect
Tilføj en leverandør til OpenCode. Lar deg velge fra tilgængelige leverandører og tilføje til deres API-nøgler.
Legg til en leverandør til OpenCode. Lar deg velge fra tilgængelige leverandører og tilføje til deres API-nøkler.
```bash frame="none"
/connect
@@ -87,79 +87,79 @@ Komprimer nuværende session. _Alias_: `/summarize`
/compact
```
**Genvejstast:** `ctrl+x c`
**Nøkkelbinding:** `ctrl+x c`
---
### details
Veksle værktøjutførelsesdetaljer.
Veksle verktøyutførelsesdetaljer.
```bash frame="none"
/details
```
**Genvejstast:** `ctrl+x d`
**Nøkkelbinding:** `ctrl+x d`
---
### editor
Åbn eksternt redigeringsprogram for at skrive beskeder. Bruger redigeringsprogrammet i miljøvariabelen `EDITOR`. [Læs mere](#editor-setup).
Åpne eksternt redigeringsprogram for at skrive meldinger. Bruger redigeringssettet i miljøvariabelen `EDITOR`. [Finn ut mer](#editor-setup).
```bash frame="none"
/editor
```
**Genvejstast:** `ctrl+x e`
**Nøkkelbinding:** `ctrl+x e`
---
### exit
Afslut OpenCode. _Aliaser_: `/quit`, `/q`
Avslutt OpenCode. _Aliaser_: `/quit`, `/q`
```bash frame="none"
/exit
```
**Genvejstast:** `ctrl+x q`
**Nøkkelbinding:** `ctrl+x q`
---
### export
Eksporter nuværende samtale til Markdown og åpne i standardredigeringsprogrammet. Bruger redigeringsprogrammet i miljøvariabelen `EDITOR`. [Læs mere](#editor-setup).
Eksporter nuværende samtale til Markdown og åpne i standardredigeringsprogrammet. Bruger redigeringssettet i miljøvariabelen `EDITOR`. [Finn ut mer](#editor-setup).
```bash frame="none"
/export
```
**Genvejstast:** `ctrl+x x`
**Nøkkelbinding:** `ctrl+x x`
---
### help
Vis hjælpedialogen.
Vis hjelpedialogen.
```bash frame="none"
/help
```
**Genvejstast:** `ctrl+x h`
**Nøkkelbinding:** `ctrl+x h`
---
### init
Opret eller opdater `AGENTS.md`-fil. [Læs mere](/docs/rules).
Opret eller opdater `AGENTS.md`-fil. [Finn ut mer](/docs/rules).
```bash frame="none"
/init
```
**Genvejstast:** `ctrl+x i`
**Nøkkelbinding:** `ctrl+x i`
---
@@ -171,7 +171,7 @@ Liste over tilgængelige modeller.
/models
```
**Genvejstast:** `ctrl+x m`
**Nøkkelbinding:** `ctrl+x m`
---
@@ -183,26 +183,26 @@ Start en ny session. _Alias_: `/clear`
/new
```
**Genvejstast:** `ctrl+x n`
**Nøkkelbinding:** `ctrl+x n`
---
### redo
Gentag en tidligere fortrudt besked. Kun tilgængelig etter brug av `/undo`.
Gjenta en tidligere angret melding. Kun tilgængelig etter brug av `/undo`.
:::tip
Eventuelle filændringer vil også bli genoprettet.
Eventuelle filendringer vil også bli gjenopretet.
:::
Internt bruger dette Git til at administrere filændringerne. Så dit prosjekt **må
Internt bruger dette Git til at administrere filendringene. Så ditt prosjekt **må
være et Git-depot**.
```bash frame="none"
/redo
```
**Genvejstast:** `ctrl+x r`
**Nøkkelbinding:** `ctrl+x r`
---
@@ -214,19 +214,19 @@ List opp og bytt mellom sessioner. _Aliaser_: `/resume`, `/continue`
/sessions
```
**Genvejstast:** `ctrl+x l`
**Nøkkelbinding:** `ctrl+x l`
---
### share
Del nuværende session. [Læs mere](/docs/share).
Del nuværende session. [Finn ut mer](/docs/share).
```bash frame="none"
/share
```
**Genvejstast:** `ctrl+x s`
**Nøkkelbinding:** `ctrl+x s`
---
@@ -238,16 +238,16 @@ Liste over tilgængelige temaer.
/theme
```
**Genvejstast:** `ctrl+x t`
**Nøkkelbinding:** `ctrl+x t`
---
### thinking
Veksle mellom synligheten av tenke-/resonneringsblokker i samtalen. Når den er aktiveret, kan du se modellens resonneringsprosess for modeller som støtter utvidet tenkning.
Veksle mellom synligheten av tenke-/resonneringsblokker i samtalen. Når den er aktivert, kan du se modellens resonneringsprosess for modeller som støtter utvidet tenkning.
:::note
Denne kommandoen kontrollerer bare om tenkeblokker **vises** - den aktiverer eller deaktiverer ikke modellens resonneringsmuligheter. For at veksle mellom faktiske resonneringsmuligheter, brug `ctrl+t` for at bla gennem modellvarianter.
Denne kommandoen kontrollerer bare om tenkeblokker **vises** - den aktiverer eller deaktiverer ikke modellens resonneringsmuligheter. For at veksle mellom faktiske resonneringsmuligheter, brug `ctrl+t` for at bla gjennom modellvarianter.
:::
```bash frame="none"
@@ -258,26 +258,26 @@ Denne kommandoen kontrollerer bare om tenkeblokker **vises** - den aktiverer ell
### undo
Angre siste besked i samtalen. Fjerner den siste brugerbeskeden, alle påfølgende svar og eventuelle filændringer.
Angre siste melding i samtalen. Fjerner den siste brugermeldingen, alle påfølgende svar og eventuelle filendringer.
:::tip
Eventuelle filændringer vil også bli nullstillet.
Eventuelle filendringer vil også bli nulstillet.
:::
Internt bruger dette Git til at administrere filændringerne. Så dit prosjekt **må
Internt bruger dette Git til at administrere filendringene. Så ditt prosjekt **må
være et Git-depot**.
```bash frame="none"
/undo
```
**Genvejstast:** `ctrl+x u`
**Nøkkelbinding:** `ctrl+x u`
---
### unshare
Opv deling av nuværende session. [Læs mere](/docs/share#un-sharing).
Opphev deling av nuværende session. [Finn ut mer](/docs/share#un-sharing).
```bash frame="none"
/unshare
@@ -285,9 +285,9 @@ Ophæv deling av nuværende session. [Læs mere](/docs/share#un-sharing).
---
## Opsætning af editor
## Redaktøroppsett
Både kommandoerne `/editor` og `/export` bruger editoren som er spesifisert i miljøvariabelen `EDITOR`.
Både kommandoene `/editor` og `/export` bruger redigeringsprogrammet som er spesifisert i miljøvariabelen `EDITOR`.
<Tabs>
<TabItem label="Linux/macOS">
@@ -315,7 +315,7 @@ Både kommandoerne `/editor` og `/export` bruger editoren som er spesifisert i m
set EDITOR=code --wait
```
For at gøre det permanent, brug **Systemegenskaber** > **Miljø
For at gøre det permanent, brug **Systemegenskaper** > **Miljø
Variabler**.
</TabItem>
@@ -339,23 +339,23 @@ Populære redigeringsalternativer inkluderer:
- `code` - Visual Studio Code
- `cursor` - Cursor
- `windsurf` - Windsurf
- `nvim` - Neovim-editor
- `nvim` - Neovim-redaktør
- `vim` - Vim editor
- `nano` - Nano-editor
- `notepad` - Windows Notesblok
- `subl` - Sublime Text
:::note
Nogle editorer som VS Code må startes med flaget `--wait`.
Nogle redaktører som VS Code må startes med flagget `--wait`.
:::
Nogle editorer kræver kommandolinjeargumenter for at køre i blokeringstilstand. `--wait`-flaget gør at redigeringsprocessen blokeres til den lukkes.
Nogle redaktører trenger kommandolinjeargumenter for at kjøre i blokkeringsmodus. `--wait`-flagget gør at redigeringsprosessen blokkeres til den lukkes.
---
## Konfigurer
Du kan tilpasse TUI-adfærden gennem OpenCode-konfigurationsfilen.
Du kan tilpasse TUI-oppførselen gjennom OpenCode-konfigurasjonsfilen.
```json title="opencode.json"
{
@@ -369,22 +369,22 @@ Du kan tilpasse TUI-adfærden gennem OpenCode-konfigurationsfilen.
}
```
### Indstillinger
### Options
- `scroll_acceleration` - Aktiver rulleacceleration i macOS-stil for jævn, naturlig rulning. Når aktiveret, øger rullehastigheden med raske rullebevægelser og forblir presis for langsommere bevægelser. **Denne indstillingen har forrang over `scroll_speed` og tilsidesætter den når den er aktiveret.**
- `scroll_speed` - Styrer hvor raskt TUI ruller når du bruger rullekommandoer (minimum: `1`). Standard er `3`. **Bemærk: Dette ignoreres hvis `scroll_acceleration.enabled` er sat til `true`.**
- `scroll_acceleration` - Aktiver rulleakselerasjon i macOS-stil for jevn, naturlig rulling. Når aktivert, øker rullehastigheten med raske rullebevegelser og forblir presis for langsommere bevegelser. **Denne innstillingen har forrang over `scroll_speed` og overstyrer den når den er aktivert.**
- `scroll_speed` - Styrer hvor raskt TUI ruller når du bruger rullekommandoer (minimum: `1`). Standard er `3`. **Merk: Dette ignoreres hvis `scroll_acceleration.enabled` er satt til `true`.**
---
## Tilpasning
Du kan tilpasse forskellige aspekter av TUI-visningen ved at bruge kommandopaletten (`ctrl+x h` eller `/help`). Disse indstillingene gemmes ved omstarter.
Du kan tilpasse ulike aspekter av TUI-visningen ved at bruge kommandopaletten (`ctrl+x h` eller `/help`). Disse innstillingene vedvarer ved omstarter.
---
#### Username display
Veksle om brugernavnet dit vises i chat-beskeder. Få adgang til dette gennem:
Veksle om brugernavnet ditt vises i chat-meldinger. Få tilgang til dette gjennom:
- Kommandopalet: Søg efter "brugernavn" eller "skjul brugernavn"
- Innstillingen gemmes automatisk og vil bli husket over TUI sessioner
- Kommandopalett: Søk etter "brugernavn" eller "skjul brugernavn"
- Innstillingen vedvarer automatisk og vil bli husket over TUI sessioner

View File

@@ -5,9 +5,9 @@ description: Was ist neu in OpenCode 1.0.
OpenCode 1.0 ist eine komplette Neufassung des TUI.
We moved from the go+bubbletea based TUI which had performance and capability issues to an in-house framework (OpenTUI) written in zig+solidjs.
Wir sind vom go+bubbletea-basierten TUI, das Leistungs- und Leistungsprobleme aufwies, zu einem internen Framework (OpenTUI) übergegangen, das in zig+solidjs geschrieben wurde.
The new TUI works like the old one since it connects to the same opencode server.
Der neue TUI funktioniert wie der alte, da er eine Verbindung zum gleichen OpenCode-Server herstellt.
---
@@ -44,24 +44,24 @@ Wir haben einige Funktionen entfernt, von denen wir nicht sicher waren, ob sie t
## Bahnbrechende Veränderungen
### Keybinds renamed
### Tastenkombinationen umbenannt
- messages_revert -> messages_undo
- Nachrichten_revert -> Nachrichten_Rückgängig machen
- switch_agent -> agent_cycle
- switch_agent_reverse -> agent_cycle_reverse
- switch_mode -> agent_cycle
- switch_mode_reverse -> agent_cycle_reverse
### Keybinds removed
### Tastenkombinationen entfernt
- messages_layout_toggle
- messages_next
- messages_previous
- message_layout_toggle
- message_next
- Nachrichten_vorherige
- file_diff_toggle
- file_search
- file_close
- file_list
- Dateiliste
- app_help
- project_init
- tool_details
- thinking_blocks
- Werkzeugdetails
- think_blocks

View File

@@ -9,7 +9,7 @@ OpenCode unterstützt [Agent Client Protocol](https://agentclientprotocol.com) o
Eine Liste der Editoren und Tools, die ACP unterstützen, finden Sie unter [ACP progress report](https://zed.dev/blog/acp-progress-report#available-now).
:::
ACP ist ein offenes Protokoll, das die Kommunikation zwischen Code-Editoren und AI-Coding-Agenten standardisiert.
ACP ist ein offenes Protokoll, das die Kommunikation zwischen Code-Editoren und AI-Codierungsagenten standardisiert.
---
@@ -82,7 +82,7 @@ Fügen Sie zu Ihrem [JetBrains IDE](https://www.jetbrains.com/) acp.json gemäß
}
```
Um es zu öffnen, verwenden Sie den neuen Agenten „OpenCode“ in der AI Chat Agent Selector.
Um es zu öffnen, verwenden Sie den neuen Agenten „OpenCode“ in der Chat-Agentenauswahl AI.
---
@@ -145,7 +145,7 @@ Wenn Sie Umgebungsvariablen (wie `OPENCODE_API_KEY`) übergeben müssen, finden
OpenCode funktioniert über ACP genauso wie im Terminal. Alle Funktionen werden unterstützt:
:::note
Einige integrierte Slash-Befehle wie `/undo` und `/redo` werden derzeit nicht unterstützt.
Einige integrierte Schrägstrichbefehle wie `/undo` und `/redo` werden derzeit nicht unterstützt.
:::
- Integrierte Tools (Dateioperationen, Terminalbefehle usw.)

View File

@@ -46,7 +46,7 @@ OpenCode verfügt über zwei integrierte Primäragenten und zwei integrierte Sub
---
### Use Build
### Verwenden Sie Build
_Modus_: `primary`
@@ -54,7 +54,7 @@ Build ist der **Standard**-Primäragent mit allen aktivierten Tools. Dies ist de
---
### Use Plan
### Nutzungsplan
_Modus_: `primary`
@@ -68,7 +68,7 @@ Dieser Agent ist nützlich, wenn Sie möchten, dass LLM Code analysiert, Änderu
---
### Use General
### Verwenden Sie es allgemein
_Modus_: `subagent`
@@ -76,7 +76,7 @@ Ein Allzweckagent zur Recherche komplexerer Fragen und zur Ausführung mehrstufi
---
### Use Explore
### Verwenden Sie „Erkunden“.
_Modus_: `subagent`
@@ -84,7 +84,7 @@ Ein schneller, schreibgeschützter Agent zum Erkunden von Codebasen. Dateien kö
---
### Use Compaction
### Verwenden Sie Dichtung
_Modus_: `primary`
@@ -92,7 +92,7 @@ Versteckter Systemagent, der lange Kontext in einer kleineren Zusammenfassung ko
---
### Use Title
### Titel verwenden
_Modus_: `primary`
@@ -100,7 +100,7 @@ Versteckter Systemagent, der kurze Sitzungstitel generiert. Es läuft automatisc
---
### Use Summary
### Zusammenfassung verwenden
_Modus_: `primary`
@@ -359,7 +359,7 @@ Wenn Sie kein Modell angeben, verwenden Sie den primären Agenten [model globall
}
```
Die Modell-ID in Ihrer OpenCode-Konfiguration verwendet das Format `provider/model-id`. Wenn Sie beispielsweise [OpenCode Zen](/docs/zen) verwenden, würden Sie `opencode/gpt-5.1-codex` für GPT 5.1 Codex verwenden.
Das Modell ID in Ihrer OpenCode-Konfiguration verwendet das Format `provider/model-id`. Wenn Sie beispielsweise [OpenCode Zen](/docs/zen) verwenden, würden Sie `opencode/gpt-5.1-codex` für GPT 5.1 Codex verwenden.
---
@@ -482,7 +482,7 @@ Sie können Berechtigungen für bestimmte Bash-Befehle festlegen.
}
```
Dies kann ein Glob-Muster annehmen.
Dies kann ein Kugelmuster annehmen.
```json title="opencode.json" {7}
{
@@ -591,7 +591,7 @@ Die Regeln werden der Reihe nach ausgewertet und die **letzte übereinstimmende
:::
:::tip
Benutzer können jeden Subagenten immer direkt über das Autovervollständigungsmenü `@` aufrufen, auch wenn die Aufgabenberechtigungen des Agenten dies verweigern würden.
Benutzer können jeden Subagenten immer direkt über das Autovervollständigungsmenü `@` aufrufen, auch wenn die Aufgabenberechtigungen des Agenten sterben würden.
:::
---
@@ -600,7 +600,7 @@ Benutzer können jeden Subagenten immer direkt über das Autovervollständigungs
Passen Sie das visuelle Erscheinungsbild des Agenten im UI mit der Option `color` an. Dies wirkt sich darauf aus, wie der Agent in der Benutzeroberfläche angezeigt wird.
Verwenden Sie eine gültige Hex-Farbe (e.g., `#FF5733`) oder Themenfarbe: `primary`, `secondary`, `accent`, `success`, `warning`, `error`, `info`.
Verwenden Sie eine gültige Hex-Farbe (e.g., `#FF5733`) oder Designfarbe: `primary`, `secondary`, `accent`, `success`, `warning`, `error`, `info`.
```json title="opencode.json"
{
@@ -631,7 +631,7 @@ Steuern Sie die Antwortvielfalt mit der Option `top_p`. Alternative zur Temperat
}
```
Die Werte reichen von 0.0 bis 1.0. Niedrigere Werte sind fokussierter, höhere Werte vielfältiger.
Die Werte reichen von 0.0 bis 1.0. Die meisten Werte sind fokussierter, die höheren Werte vielfältiger.
---

Some files were not shown because too many files have changed in this diff Show More