mirror of
https://github.com/anomalyco/opencode.git
synced 2026-02-11 03:14:29 +00:00
Compare commits
1 Commits
dev
...
opencode/g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3991603e2 |
1
.github/VOUCHED.td
vendored
1
.github/VOUCHED.td
vendored
@@ -15,5 +15,4 @@ kitlangton
|
||||
kommander
|
||||
r44vc0rp
|
||||
rekram1-node
|
||||
-spider-yamet clawdbot/llm psychosis, spam pinging the team
|
||||
thdxr
|
||||
|
||||
30
bun.lock
30
bun.lock
@@ -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",
|
||||
|
||||
@@ -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 }] : [],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/app",
|
||||
"version": "1.1.56",
|
||||
"version": "1.1.54",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-app",
|
||||
"version": "1.1.56",
|
||||
"version": "1.1.54",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
})
|
||||
@@ -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": {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@opencode-ai/desktop",
|
||||
"private": true,
|
||||
"version": "1.1.56",
|
||||
"version": "1.1.54",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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)
|
||||
},
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/enterprise",
|
||||
"version": "1.1.56",
|
||||
"version": "1.1.54",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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++
|
||||
|
||||
@@ -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(
|
||||
() => {
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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)
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
)
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/slack",
|
||||
"version": "1.1.56",
|
||||
"version": "1.1.54",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/ui",
|
||||
"version": "1.1.56",
|
||||
"version": "1.1.54",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"exports": {
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/util",
|
||||
"version": "1.1.56",
|
||||
"version": "1.1.54",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -460,7 +460,7 @@ permission:
|
||||
webfetch: deny
|
||||
---
|
||||
|
||||
Only analyze code and suggest changes.
|
||||
حلل الشفرة فقط واقترح التغييرات.
|
||||
```
|
||||
|
||||
يمكنك ضبط الأذونات لأوامر bash محددة.
|
||||
|
||||
@@ -17,6 +17,7 @@ Za ručnu nadogradnju, pokrenite
|
||||
|
||||
```bash
|
||||
$ opencode upgrade 1.0.0
|
||||
|
||||
```
|
||||
|
||||
Za vraćanje na 0.x, pokrenite
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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`.
|
||||
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||

|
||||

|
||||
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.
|
||||
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -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 |
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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 |
|
||||
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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` fø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).
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
@@ -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) |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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**
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||

|
||||

|
||||
|
||||
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).
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
Ophæv 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.)
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user