mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-10 11:39:45 -04:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 99f638d829 |
+1
-1
@@ -132,7 +132,7 @@ _Avoid_: Response envelope
|
||||
- A **Baseline System Context** durably preserves the exact joined text used for the active provider-cache prefix.
|
||||
- Completed compaction starts a new **Context Epoch** on the next provider attempt, folding the current complete **System Context** into a fresh baseline and removing earlier **Mid-Conversation System Messages** from active model history.
|
||||
- A model/provider switch preserves the current **Context Epoch** and chronological conversation history; the new selection applies to the next provider turn.
|
||||
- **Native Continuation Metadata** remains in durable history. Provider-turn projection includes it only for a successful exact originating provider/model match; failed turns and incompatible models omit opaque metadata. Visible reasoning remains canonical until target-protocol lowering: OpenAI Chat-compatible targets replay it as `reasoning_content`, while protocols that require signed native reasoning lower unsigned reasoning to ordinary assistant text.
|
||||
- **Native Continuation Metadata** remains in durable history. Provider-turn projection includes it only for a successful exact originating provider/model match; failed turns and incompatible models omit opaque metadata, while non-empty visible reasoning lowers to ordinary assistant text after a model switch. This conservative relation may widen only when recorded provider tests establish compatibility.
|
||||
- **Model Request Options** remain provider-semantic through Catalog resolution. The Session runner maps them into the LLM package's provider-option namespace; the selected protocol adapter alone owns provider wire encoding.
|
||||
- **Generation Controls**, protocol-semantic **Model Request Options**, and compatibility request body fields are separate Catalog domains. A shared ingestion adapter partitions legacy and models.dev AI-SDK-shaped options before routing.
|
||||
- The **PTY Environment** is a server concern rather than a Core PTY concern. PTY creation merges caller values, then the host overlay, then Core-forced terminal invariants such as `TERM` and `OPENCODE_TERMINAL`.
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
},
|
||||
"packages/app": {
|
||||
"name": "@opencode-ai/app",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@corvu/drawer": "catalog:",
|
||||
"@dnd-kit/abstract": "0.5.0",
|
||||
@@ -95,7 +95,7 @@
|
||||
},
|
||||
"packages/cli": {
|
||||
"name": "@opencode-ai/cli",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"bin": {
|
||||
"lildax": "./bin/lildax.cjs",
|
||||
},
|
||||
@@ -143,7 +143,7 @@
|
||||
},
|
||||
"packages/codemode": {
|
||||
"name": "@opencode-ai/codemode",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"acorn": "8.15.0",
|
||||
"effect": "catalog:",
|
||||
@@ -157,7 +157,7 @@
|
||||
},
|
||||
"packages/console/app": {
|
||||
"name": "@opencode-ai/console-app",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@cloudflare/vite-plugin": "1.15.2",
|
||||
"@ibm/plex": "6.4.1",
|
||||
@@ -193,7 +193,7 @@
|
||||
},
|
||||
"packages/console/core": {
|
||||
"name": "@opencode-ai/console-core",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-sts": "3.782.0",
|
||||
"@jsx-email/render": "1.1.1",
|
||||
@@ -220,7 +220,7 @@
|
||||
},
|
||||
"packages/console/function": {
|
||||
"name": "@opencode-ai/console-function",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "3.0.82",
|
||||
"@ai-sdk/openai": "3.0.48",
|
||||
@@ -242,7 +242,7 @@
|
||||
},
|
||||
"packages/console/mail": {
|
||||
"name": "@opencode-ai/console-mail",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@jsx-email/all": "2.2.3",
|
||||
"@jsx-email/cli": "1.4.3",
|
||||
@@ -266,7 +266,7 @@
|
||||
},
|
||||
"packages/console/support": {
|
||||
"name": "@opencode-ai/console-support",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@cloudflare/vite-plugin": "1.15.2",
|
||||
"@opencode-ai/console-core": "workspace:*",
|
||||
@@ -286,7 +286,7 @@
|
||||
},
|
||||
"packages/core": {
|
||||
"name": "@opencode-ai/core",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"bin": {
|
||||
"opencode": "./bin/opencode",
|
||||
},
|
||||
@@ -380,7 +380,7 @@
|
||||
},
|
||||
"packages/desktop": {
|
||||
"name": "@opencode-ai/desktop",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@zip.js/zip.js": "2.7.62",
|
||||
"effect": "catalog:",
|
||||
@@ -434,7 +434,7 @@
|
||||
},
|
||||
"packages/effect-drizzle-sqlite": {
|
||||
"name": "@opencode-ai/effect-drizzle-sqlite",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"drizzle-orm": "catalog:",
|
||||
"effect": "catalog:",
|
||||
@@ -448,7 +448,7 @@
|
||||
},
|
||||
"packages/effect-sqlite-node": {
|
||||
"name": "@opencode-ai/effect-sqlite-node",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"effect": "catalog:",
|
||||
},
|
||||
@@ -460,7 +460,7 @@
|
||||
},
|
||||
"packages/enterprise": {
|
||||
"name": "@opencode-ai/enterprise",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@hono/standard-validator": "catalog:",
|
||||
"@opencode-ai/core": "workspace:*",
|
||||
@@ -492,7 +492,7 @@
|
||||
},
|
||||
"packages/function": {
|
||||
"name": "@opencode-ai/function",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@octokit/auth-app": "8.0.1",
|
||||
"@octokit/rest": "catalog:",
|
||||
@@ -508,7 +508,7 @@
|
||||
},
|
||||
"packages/http-recorder": {
|
||||
"name": "@opencode-ai/http-recorder",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@effect/platform-node": "4.0.0-beta.83",
|
||||
"@effect/platform-node-shared": "4.0.0-beta.83",
|
||||
@@ -539,7 +539,7 @@
|
||||
},
|
||||
"packages/llm": {
|
||||
"name": "@opencode-ai/llm",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@opencode-ai/schema": "workspace:*",
|
||||
"@smithy/eventstream-codec": "4.2.14",
|
||||
@@ -558,7 +558,7 @@
|
||||
},
|
||||
"packages/opencode": {
|
||||
"name": "opencode",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"bin": {
|
||||
"opencode": "./bin/opencode",
|
||||
},
|
||||
@@ -689,7 +689,7 @@
|
||||
},
|
||||
"packages/plugin": {
|
||||
"name": "@opencode-ai/plugin",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@ai-sdk/provider": "3.0.8",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
@@ -765,7 +765,7 @@
|
||||
},
|
||||
"packages/sdk/js": {
|
||||
"name": "@opencode-ai/sdk",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"cross-spawn": "catalog:",
|
||||
},
|
||||
@@ -780,7 +780,7 @@
|
||||
},
|
||||
"packages/server": {
|
||||
"name": "@opencode-ai/server",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@opencode-ai/core": "workspace:*",
|
||||
"@opencode-ai/protocol": "workspace:*",
|
||||
@@ -795,7 +795,7 @@
|
||||
},
|
||||
"packages/session-ui": {
|
||||
"name": "@opencode-ai/session-ui",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@kobalte/core": "catalog:",
|
||||
"@opencode-ai/core": "workspace:*",
|
||||
@@ -839,7 +839,7 @@
|
||||
},
|
||||
"packages/slack": {
|
||||
"name": "@opencode-ai/slack",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"@slack/bolt": "^3.17.1",
|
||||
@@ -852,7 +852,7 @@
|
||||
},
|
||||
"packages/stats/app": {
|
||||
"name": "@opencode-ai/stats-app",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@ibm/plex": "6.4.1",
|
||||
"@kobalte/core": "catalog:",
|
||||
@@ -886,7 +886,7 @@
|
||||
},
|
||||
"packages/stats/core": {
|
||||
"name": "@opencode-ai/stats-core",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-athena": "3.933.0",
|
||||
"@planetscale/database": "1.19.0",
|
||||
@@ -905,7 +905,7 @@
|
||||
},
|
||||
"packages/stats/server": {
|
||||
"name": "@opencode-ai/stats-server",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-firehose": "3.933.0",
|
||||
"@effect/platform-node": "catalog:",
|
||||
@@ -946,7 +946,7 @@
|
||||
},
|
||||
"packages/tui": {
|
||||
"name": "@opencode-ai/tui",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@opencode-ai/core": "workspace:*",
|
||||
"@opencode-ai/plugin": "workspace:*",
|
||||
@@ -973,7 +973,7 @@
|
||||
},
|
||||
"packages/ui": {
|
||||
"name": "@opencode-ai/ui",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@kobalte/core": "catalog:",
|
||||
"@pierre/diffs": "catalog:",
|
||||
@@ -1024,7 +1024,7 @@
|
||||
},
|
||||
"packages/web": {
|
||||
"name": "@opencode-ai/web",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@astrojs/cloudflare": "12.6.3",
|
||||
"@astrojs/markdown-remark": "6.3.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/app",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"description": "",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
|
||||
@@ -8,20 +8,61 @@ import introducingTabsVideo from "@/assets/help/introducing-tabs.mp4"
|
||||
import homeImage from "@/assets/help/home.png"
|
||||
import tabsImage from "@/assets/help/tabs.png"
|
||||
|
||||
const helpIcon = (
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
data-slot="icon-svg"
|
||||
>
|
||||
<path
|
||||
d="M6.94235 10.5714V10.4854C6.94617 9.76302 7.01879 9.18777 7.16022 8.75968C7.30546 8.33158 7.50804 7.98567 7.76796 7.72193C8.02787 7.45819 8.34321 7.21548 8.71397 6.99379C8.93948 6.85619 9.14206 6.69374 9.32171 6.50645C9.50518 6.31916 9.64851 6.10511 9.75171 5.86431C9.85874 5.62351 9.91225 5.35404 9.91225 5.0559C9.91225 4.69661 9.82625 4.38509 9.65424 4.12136C9.48607 3.85762 9.26055 3.65504 8.9777 3.51362C8.69486 3.36837 8.38143 3.29575 8.03743 3.29575C7.73165 3.29575 7.43733 3.35882 7.15448 3.48495C6.87546 3.61108 6.6423 3.80984 6.45501 4.08122C6.26772 4.3526 6.15878 4.70425 6.12821 5.13617H4.56299C4.59357 4.47109 4.76557 3.9054 5.07899 3.43908C5.39242 2.96894 5.80522 2.61156 6.31741 2.36694C6.83341 2.12231 7.40675 2 8.03743 2C8.72161 2 9.31789 2.13378 9.82625 2.40134C10.3384 2.66507 10.734 3.0301 11.0131 3.49642C11.2959 3.96273 11.4373 4.49976 11.4373 5.1075C11.4373 5.53177 11.3724 5.914 11.2424 6.25418C11.1124 6.59436 10.9251 6.89823 10.6805 7.16579C10.4397 7.43335 10.1492 7.67033 9.80905 7.87673C9.48033 8.08313 9.21468 8.301 9.0121 8.53034C8.80952 8.75585 8.66237 9.02341 8.57063 9.33302C8.4789 9.64262 8.42921 10.0268 8.42156 10.4854V10.5714H6.94235ZM7.72782 14C7.43351 14 7.17933 13.8949 6.96528 13.6847C6.75506 13.4744 6.64994 13.2203 6.64994 12.9221C6.64994 12.6278 6.75506 12.3755 6.96528 12.1653C7.17933 11.9551 7.43351 11.85 7.72782 11.85C8.02214 11.85 8.27441 11.9551 8.48463 12.1653C8.69868 12.3755 8.8057 12.6278 8.8057 12.9221C8.8057 13.1209 8.75601 13.3024 8.65663 13.4668C8.55726 13.6273 8.4273 13.7573 8.26676 13.8567C8.10623 13.9522 7.92658 14 7.72782 14Z"
|
||||
fill="var(--v2-icon-icon-base)"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
|
||||
const triggerClass =
|
||||
"size-7 !rounded-full shrink-0 bg-v2-background-bg-base shadow-[var(--v2-elevation-button-neutral)]"
|
||||
|
||||
// TODO: wire to changelog / seen-state when available
|
||||
const showPopover = () => true
|
||||
|
||||
export function HelpButton() {
|
||||
if (import.meta.env.VITE_OPENCODE_CHANNEL !== "dev") return null
|
||||
|
||||
const platform = usePlatform()
|
||||
|
||||
return (
|
||||
<a
|
||||
href="https://opencode.ai"
|
||||
aria-label="Open the OpenCode website"
|
||||
data-component="icon-button-v2"
|
||||
data-size="large"
|
||||
class={`${triggerClass} fixed bottom-5 right-5 z-50 flex items-center justify-center`}
|
||||
onClick={(event) => {
|
||||
event.preventDefault()
|
||||
platform.openLink(event.currentTarget.href)
|
||||
}}
|
||||
>
|
||||
{helpIcon}
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
// can remove this after the tabs rollout has been out for a while
|
||||
export function TabsInfoPopup() {
|
||||
const settings = useSettings()
|
||||
const platform = usePlatform()
|
||||
const [drawerOpen, setDrawerOpen] = createSignal(false)
|
||||
|
||||
return (
|
||||
<Drawer open={drawerOpen()} onOpenChange={setDrawerOpen} side="right">
|
||||
<Show when={settings.general.shouldDisplayTabsToast()}>
|
||||
<div
|
||||
class="fixed bottom-5 right-5 z-50 h-[240px] w-[192px] rounded-[8px] bg-v2-background-bg-base p-1 shadow-[var(--v2-elevation-floating)]"
|
||||
class="fixed bottom-14 right-5 z-50 h-[240px] w-[192px] rounded-[8px] bg-v2-background-bg-base p-1 shadow-[var(--v2-elevation-floating)]"
|
||||
aria-label="Introducing Tabs. Organize your work and active sessions with tabs"
|
||||
>
|
||||
<button
|
||||
@@ -75,16 +116,14 @@ export function TabsInfoPopup() {
|
||||
<p class="min-h-0 min-w-0 flex-1 text-[13px] font-[530] leading-5 tracking-[-0.04px] tabular-nums text-v2-text-text-muted">
|
||||
July 14
|
||||
</p>
|
||||
<Show when={platform.platform !== "desktop" || platform.os !== "windows"}>
|
||||
<DrawerClose
|
||||
as={IconButtonV2}
|
||||
type="button"
|
||||
size="small"
|
||||
variant="ghost-muted"
|
||||
aria-label="Close"
|
||||
icon={<IconV2 name="xmark-small" />}
|
||||
/>
|
||||
</Show>
|
||||
<DrawerClose
|
||||
as={IconButtonV2}
|
||||
type="button"
|
||||
size="small"
|
||||
variant="ghost-muted"
|
||||
aria-label="Close"
|
||||
icon={<IconV2 name="xmark-small" />}
|
||||
/>
|
||||
</div>
|
||||
<div class="relative flex min-h-0 w-full flex-1 flex-col items-start gap-6 overflow-y-auto p-8">
|
||||
<p class="w-full shrink-0 self-stretch text-[21px] font-[610] leading-6 tracking-[-0.37px] tabular-nums text-v2-text-text-base">
|
||||
|
||||
@@ -392,7 +392,7 @@ export function Titlebar(props: { update?: TitlebarUpdate }) {
|
||||
id: "tab.new",
|
||||
category: "tab",
|
||||
title: language.t("command.session.new"),
|
||||
keybind: "mod+t,mod+n",
|
||||
keybind: "mod+t",
|
||||
hidden: true,
|
||||
onSelect: openNewTab,
|
||||
},
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import type { SessionV2Info } from "@opencode-ai/sdk/v2/client"
|
||||
import {
|
||||
applyHomeSessionEvent,
|
||||
appendHomeSessionEvent,
|
||||
@@ -73,13 +72,8 @@ describe("Home V2 session index", () => {
|
||||
})
|
||||
|
||||
test("maps visible roots to Home session summaries", () => {
|
||||
const activeNull = {
|
||||
...session({ id: "active-null", updated: 20 }),
|
||||
time: { created: 1, updated: 20, archived: null },
|
||||
} as unknown as SessionV2Info
|
||||
const result = parseHomeSessionIndex([
|
||||
session({ id: "root", updated: 30 }),
|
||||
activeNull,
|
||||
session({ id: "child", parentID: "root", updated: 40 }),
|
||||
session({ id: "archived", archived: 50, updated: 50 }),
|
||||
])
|
||||
@@ -94,10 +88,6 @@ describe("Home V2 session index", () => {
|
||||
title: "root",
|
||||
time: { created: 1, updated: 30 },
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: "active-null",
|
||||
time: { created: 1, updated: 20, archived: null },
|
||||
}),
|
||||
])
|
||||
})
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ export function createHomeSessionIndexCache(queryClient: QueryClient, server: st
|
||||
// parentID: null, order: "desc" }), then remove this adapter and its V1 fields.
|
||||
export function parseHomeSessionIndex(sessions: SessionV2Info[]): Session[] {
|
||||
return sessions.flatMap((item) => {
|
||||
if (item.parentID || typeof item.time.archived === "number") return []
|
||||
if (item.parentID || item.time.archived !== undefined) return []
|
||||
return [toLegacySummary(item)]
|
||||
})
|
||||
}
|
||||
@@ -145,7 +145,7 @@ export function retainHomeSessions(sessions: Session[], limit: number, now: numb
|
||||
export function applyHomeSessionEvent(sessions: Session[], event: HomeSessionEvent) {
|
||||
const info = event.properties.info
|
||||
const index = sessions.findIndex((session) => session.id === info.id)
|
||||
if (event.type === "session.deleted" || info.parentID || typeof info.time.archived === "number") {
|
||||
if (event.type === "session.deleted" || info.parentID || info.time.archived !== undefined) {
|
||||
if (index === -1) return sessions
|
||||
return sessions.toSpliced(index, 1)
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { hasCustomAgent, resolveAgent } from "./local-agent"
|
||||
|
||||
describe("hasCustomAgent", () => {
|
||||
test("detects explicitly custom agents", () => {
|
||||
expect(hasCustomAgent([{ native: true }, { native: false }])).toBe(true)
|
||||
})
|
||||
|
||||
test("ignores built-in and unclassified agents", () => {
|
||||
expect(hasCustomAgent([{ native: true }, {}])).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe("resolveAgent", () => {
|
||||
const agents = [{ name: "plan" }, { name: "build" }, { name: "custom" }]
|
||||
|
||||
test("uses the requested available agent", () => {
|
||||
expect(resolveAgent(agents, "custom")?.name).toBe("custom")
|
||||
})
|
||||
|
||||
test("defaults to build", () => {
|
||||
expect(resolveAgent(agents)?.name).toBe("build")
|
||||
expect(resolveAgent(agents, "missing")?.name).toBe("build")
|
||||
})
|
||||
|
||||
test("uses the first agent when build is unavailable", () => {
|
||||
expect(resolveAgent([{ name: "custom" }], "missing")?.name).toBe("custom")
|
||||
})
|
||||
})
|
||||
@@ -1,7 +0,0 @@
|
||||
export function hasCustomAgent(items: Array<{ native?: boolean }>) {
|
||||
return items.some((item) => item.native === false)
|
||||
}
|
||||
|
||||
export function resolveAgent<T extends { name: string }>(items: T[], name?: string) {
|
||||
return items.find((item) => item.name === name) ?? items.find((item) => item.name === "build") ?? items[0]
|
||||
}
|
||||
@@ -4,10 +4,8 @@ import { useParams } from "@solidjs/router"
|
||||
import { batch, createEffect, createMemo, startTransition } from "solid-js"
|
||||
import { createStore } from "solid-js/store"
|
||||
import { useModels } from "@/context/models"
|
||||
import { useSettings } from "@/context/settings"
|
||||
import { useProviders } from "@/hooks/use-providers"
|
||||
import { Persist, persisted } from "@/utils/persist"
|
||||
import { hasCustomAgent, resolveAgent } from "./local-agent"
|
||||
import { cycleModelVariant, getConfiguredAgentVariant, resolveModelVariant } from "./model-variant"
|
||||
import { useSDK } from "./sdk"
|
||||
import { useSync } from "./sync"
|
||||
@@ -64,11 +62,9 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
const serverSDK = useServerSDK()
|
||||
const providers = useProviders(() => sdk().directory)
|
||||
const models = useModels()
|
||||
const settings = useSettings()
|
||||
|
||||
const id = createMemo(() => params.id || undefined)
|
||||
const list = createMemo(() => sync().data.agent.filter((item) => item.mode !== "subagent" && !item.hidden))
|
||||
const agentsVisible = createMemo(() => settings.visibility.customAgents() || hasCustomAgent(list()))
|
||||
const connected = createMemo(() => new Set(providers.connected().map((item) => item.id)))
|
||||
|
||||
const [saved, setSaved, , savedReady] = persisted(
|
||||
@@ -111,7 +107,9 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
}
|
||||
|
||||
const pickAgent = (name: string | undefined) => {
|
||||
return resolveAgent(list(), name)
|
||||
const items = list()
|
||||
if (items.length === 0) return
|
||||
return items.find((item) => item.name === name) ?? items[0]
|
||||
}
|
||||
|
||||
createEffect(() => {
|
||||
@@ -182,9 +180,8 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||
|
||||
const agent = {
|
||||
list,
|
||||
visible: agentsVisible,
|
||||
current() {
|
||||
return pickAgent(agentsVisible() ? (scope()?.agent ?? store.current) : "build")
|
||||
return pickAgent(scope()?.agent ?? store.current)
|
||||
},
|
||||
set(name: string | undefined) {
|
||||
const item = pickAgent(name)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { createEffect, Suspense, type ParentProps } from "solid-js"
|
||||
import { useNavigate } from "@solidjs/router"
|
||||
import { DebugBar } from "@/components/debug-bar"
|
||||
import { TabsInfoPopup } from "@/components/help-button"
|
||||
import { HelpButton, TabsInfoPopup } from "@/components/help-button"
|
||||
import { Titlebar, type TitlebarUpdate } from "@/components/titlebar"
|
||||
import { usePlatform } from "@/context/platform"
|
||||
import { setNavigate } from "@/utils/notification-click"
|
||||
@@ -38,6 +38,7 @@ export default function NewLayout(props: ParentProps) {
|
||||
</main>
|
||||
{import.meta.env.DEV && <DebugBar inline />}
|
||||
<TabsInfoPopup />
|
||||
<HelpButton />
|
||||
<ToastRegion v2 />
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -54,7 +54,7 @@ import { useTheme, type ColorScheme } from "@opencode-ai/ui/theme/context"
|
||||
import { useCommand, type CommandOption } from "@/context/command"
|
||||
import { ConstrainDragXAxis, getDraggableId } from "@/utils/solid-dnd"
|
||||
import { DebugBar } from "@/components/debug-bar"
|
||||
import { TabsInfoPopup } from "@/components/help-button"
|
||||
import { HelpButton, TabsInfoPopup } from "@/components/help-button"
|
||||
import { Titlebar, type TitlebarUpdate } from "@/components/titlebar"
|
||||
import { useDirectoryPicker } from "@/components/directory-picker"
|
||||
import { ServerConnection, useServer } from "@/context/server"
|
||||
@@ -2396,6 +2396,7 @@ export default function LegacyLayout(props: ParentProps) {
|
||||
{import.meta.env.DEV && import.meta.env.VITE_DISABLE_DEBUG_BAR !== "1" && <DebugBar />}
|
||||
</div>
|
||||
<TabsInfoPopup />
|
||||
<HelpButton />
|
||||
<ToastRegion v2={false} />
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -41,7 +41,7 @@ export function createPromptInputController(input: {
|
||||
options: local.agent.list().map((agent) => agent.name),
|
||||
current: local.agent.current()?.name ?? "",
|
||||
loading: agentsQuery.isLoading,
|
||||
visible: local.agent.visible(),
|
||||
visible: settings.visibility.customAgents(),
|
||||
select: local.agent.set,
|
||||
},
|
||||
model: {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useCommand, type CommandOption } from "@/context/command"
|
||||
import { useLanguage } from "@/context/language"
|
||||
import { useLocal, type ModelSelection } from "@/context/local"
|
||||
import { useSettings } from "@/context/settings"
|
||||
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
||||
import { getCursorPosition, setCursorPosition } from "@/components/prompt-input/editor-dom"
|
||||
import { useSessionLayout } from "./session-layout"
|
||||
@@ -18,6 +19,7 @@ export const useComposerCommands = (input: { model?: ModelSelection } = {}) => {
|
||||
const dialog = useDialog()
|
||||
const language = useLanguage()
|
||||
const local = useLocal()
|
||||
const settings = useSettings()
|
||||
const { sessionKey } = useSessionLayout()
|
||||
const sessionOwnership = createSessionOwnership(sessionKey)
|
||||
const model = input.model ?? local.model
|
||||
@@ -68,7 +70,7 @@ export const useComposerCommands = (input: { model?: ModelSelection } = {}) => {
|
||||
description: language.t("command.agent.cycle.description"),
|
||||
keybind: "mod+.",
|
||||
slash: "agent",
|
||||
disabled: !local.agent.visible(),
|
||||
disabled: !settings.visibility.customAgents(),
|
||||
onSelect: () => local.agent.move(1),
|
||||
}),
|
||||
agentCommand({
|
||||
@@ -76,7 +78,7 @@ export const useComposerCommands = (input: { model?: ModelSelection } = {}) => {
|
||||
title: language.t("command.agent.cycle.reverse"),
|
||||
description: language.t("command.agent.cycle.reverse.description"),
|
||||
keybind: "shift+mod+.",
|
||||
disabled: !local.agent.visible(),
|
||||
disabled: !settings.visibility.customAgents(),
|
||||
onSelect: () => local.agent.move(-1),
|
||||
}),
|
||||
])
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/cli",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/codemode",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"description": "Effect-native confined code execution over schema-described tools",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-app",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -9,7 +9,6 @@ import "./app.css"
|
||||
import { LanguageProvider } from "~/context/language"
|
||||
import { I18nProvider, useI18n } from "~/context/i18n"
|
||||
import { strip } from "~/lib/language"
|
||||
import { DesktopPromo } from "~/component/desktop-promo"
|
||||
|
||||
function AppMeta() {
|
||||
const i18n = useI18n()
|
||||
@@ -34,7 +33,6 @@ export default function App() {
|
||||
<MetaProvider>
|
||||
<AppMeta />
|
||||
<Suspense>{props.children}</Suspense>
|
||||
<DesktopPromo />
|
||||
</MetaProvider>
|
||||
</I18nProvider>
|
||||
</LanguageProvider>
|
||||
|
||||
Binary file not shown.
@@ -1,103 +0,0 @@
|
||||
[data-component="desktop-promo"] {
|
||||
--promo-background: hsl(0, 20%, 99%);
|
||||
--promo-background-weak: hsl(0, 8%, 97%);
|
||||
--promo-text: hsl(0, 1%, 39%);
|
||||
--promo-text-strong: hsl(0, 5%, 12%);
|
||||
--promo-border: hsla(0, 100%, 3%, 0.12);
|
||||
|
||||
position: fixed;
|
||||
z-index: 20;
|
||||
right: 1.5rem;
|
||||
bottom: 1.5rem;
|
||||
width: min(28rem, calc(100vw - 2rem));
|
||||
padding: 4px;
|
||||
overflow: hidden;
|
||||
color: var(--promo-text);
|
||||
border: 1px solid var(--promo-border);
|
||||
border-radius: 8px;
|
||||
background: var(--promo-background);
|
||||
box-shadow: 0 0.75rem 2rem rgb(0 0 0 / 15%);
|
||||
font-family: var(--font-mono);
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
--promo-background: hsl(0, 9%, 7%);
|
||||
--promo-background-weak: hsl(0, 6%, 10%);
|
||||
--promo-text: hsl(0, 4%, 71%);
|
||||
--promo-text-strong: hsl(0, 15%, 94%);
|
||||
--promo-border: hsl(0, 4%, 23%);
|
||||
}
|
||||
|
||||
@media (max-width: 40rem) {
|
||||
right: 1rem;
|
||||
bottom: 1rem;
|
||||
}
|
||||
|
||||
[data-slot="desktop-promo-link"] {
|
||||
display: block;
|
||||
color: var(--promo-text);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
[data-slot="desktop-promo-link"]:focus-visible {
|
||||
outline: 2px solid var(--promo-text-strong);
|
||||
outline-offset: -3px;
|
||||
}
|
||||
|
||||
video {
|
||||
display: block;
|
||||
width: 100%;
|
||||
aspect-ratio: 16 / 9;
|
||||
object-fit: cover;
|
||||
border-radius: 4px;
|
||||
background: var(--promo-background-weak);
|
||||
}
|
||||
|
||||
[data-slot="desktop-promo-copy"] {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.35rem;
|
||||
padding: 1rem;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
[data-slot="desktop-promo-copy"] strong {
|
||||
color: var(--promo-text-strong);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
[data-slot="desktop-promo-close"] {
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
display: grid;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
padding: 0;
|
||||
place-items: center;
|
||||
cursor: pointer;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 0.25rem;
|
||||
background: rgb(0 0 0 / 70%);
|
||||
opacity: 0;
|
||||
transition:
|
||||
opacity 150ms ease,
|
||||
background 150ms ease;
|
||||
}
|
||||
|
||||
&:hover [data-slot="desktop-promo-close"],
|
||||
[data-slot="desktop-promo-close"]:focus-visible {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[data-slot="desktop-promo-close"]:hover {
|
||||
background: rgb(0 0 0 / 90%);
|
||||
}
|
||||
|
||||
@media (hover: none) {
|
||||
[data-slot="desktop-promo-close"] {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
import "./desktop-promo.css"
|
||||
import { A, useLocation } from "@solidjs/router"
|
||||
import { createSignal, Show } from "solid-js"
|
||||
import { getRequestEvent } from "solid-js/web"
|
||||
import desktopPromoVideo from "~/asset/lander/desktop-tabs-landscape.mp4"
|
||||
import { useI18n } from "~/context/i18n"
|
||||
import { useLanguage } from "~/context/language"
|
||||
import { strip } from "~/lib/language"
|
||||
|
||||
export function DesktopPromo() {
|
||||
const i18n = useI18n()
|
||||
const language = useLanguage()
|
||||
const location = useLocation()
|
||||
const [visible, setVisible] = createSignal(true)
|
||||
const request = getRequestEvent()?.request
|
||||
const hostname = request ? new URL(request.url).hostname : typeof window === "object" ? window.location.hostname : ""
|
||||
const primaryHost =
|
||||
hostname === "opencode.ai" || hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1"
|
||||
|
||||
return (
|
||||
<Show
|
||||
when={
|
||||
visible() &&
|
||||
primaryHost &&
|
||||
strip(location.pathname) !== "/download" &&
|
||||
!strip(location.pathname).startsWith("/download/")
|
||||
}
|
||||
>
|
||||
<aside data-component="desktop-promo">
|
||||
<A href={language.route("/download")} data-slot="desktop-promo-link">
|
||||
<video src={desktopPromoVideo} autoplay playsinline loop muted preload="metadata" aria-hidden="true" />
|
||||
<span data-slot="desktop-promo-copy">
|
||||
<strong>{i18n.t("home.promo.title")}</strong>
|
||||
<span>
|
||||
{i18n.t("home.promo.body")} {i18n.t("home.promo.cta")}
|
||||
</span>
|
||||
</span>
|
||||
</A>
|
||||
<button type="button" data-slot="desktop-promo-close" onClick={() => setVisible(false)}>
|
||||
<span class="sr-only">{i18n.t("home.promo.close")}</span>
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" aria-hidden="true">
|
||||
<path d="M5 5L15 15M15 5L5 15" stroke="currentColor" stroke-width="1.5" />
|
||||
</svg>
|
||||
</button>
|
||||
</aside>
|
||||
</Show>
|
||||
)
|
||||
}
|
||||
@@ -102,14 +102,10 @@ export const dict = {
|
||||
"temp.logoDarkAlt": "شعار opencode الداكن",
|
||||
|
||||
"home.banner.badge": "جديد",
|
||||
"home.banner.text": "نقدّم علامات التبويب لتطبيق سطح المكتب.",
|
||||
"home.banner.platforms": "متاحة على macOS وWindows وLinux",
|
||||
"home.banner.text": "تطبيق سطح المكتب متاح بنسخة تجريبية",
|
||||
"home.banner.platforms": "على macOS، Windows، وLinux",
|
||||
"home.banner.downloadNow": "حمّل الآن",
|
||||
"home.banner.downloadBetaNow": "حمّل النسخة التجريبية لتطبيق سطح المكتب الآن",
|
||||
"home.promo.title": "نقدّم علامات التبويب لتطبيق سطح المكتب",
|
||||
"home.promo.body": "نظّم عملك وجلساتك النشطة باستخدام علامات التبويب.",
|
||||
"home.promo.cta": "نزّل أحدث إصدار للبدء.",
|
||||
"home.promo.close": "إغلاق إعلان تطبيق سطح المكتب",
|
||||
|
||||
"home.hero.title": "وكيل برمجة بالذكاء الاصطناعي مفتوح المصدر",
|
||||
"home.hero.subtitle.a": "نماذج مجانية مضمّنة أو اربط أي نموذج من أي مزوّد،",
|
||||
@@ -704,11 +700,11 @@ export const dict = {
|
||||
|
||||
"download.title": "OpenCode | تنزيل",
|
||||
"download.meta.description": "نزّل OpenCode لـ macOS، Windows، وLinux",
|
||||
"download.hero.title": "تنزيل OpenCode لسطح المكتب",
|
||||
"download.hero.title": "تنزيل OpenCode",
|
||||
"download.hero.subtitle": "متاح في نسخة تجريبية لـ macOS، Windows، وLinux",
|
||||
"download.hero.button": "تنزيل لـ {{os}}",
|
||||
"download.section.terminal": "OpenCode للطرفية",
|
||||
"download.section.desktop": "OpenCode لسطح المكتب",
|
||||
"download.section.desktop": "OpenCode لسطح المكتب (Beta)",
|
||||
"download.section.extensions": "امتدادات OpenCode",
|
||||
"download.section.integrations": "تكاملات OpenCode",
|
||||
"download.action.download": "تنزيل",
|
||||
|
||||
@@ -102,14 +102,10 @@ export const dict = {
|
||||
"temp.logoDarkAlt": "logo opencode escuro",
|
||||
|
||||
"home.banner.badge": "Novo",
|
||||
"home.banner.text": "Conheça as abas no app desktop.",
|
||||
"home.banner.platforms": "Disponível no macOS, Windows e Linux",
|
||||
"home.banner.text": "App desktop disponível em beta",
|
||||
"home.banner.platforms": "no macOS, Windows e Linux",
|
||||
"home.banner.downloadNow": "Baixar agora",
|
||||
"home.banner.downloadBetaNow": "Baixe agora o beta do desktop",
|
||||
"home.promo.title": "Conheça as abas no app desktop",
|
||||
"home.promo.body": "Organize seu trabalho e suas sessões ativas com abas.",
|
||||
"home.promo.cta": "Baixe a versão mais recente para começar.",
|
||||
"home.promo.close": "Fechar anúncio do app desktop",
|
||||
|
||||
"home.hero.title": "O agente de codificação de código aberto com IA",
|
||||
"home.hero.subtitle.a": "Modelos grátis incluídos ou conecte qualquer modelo de qualquer provedor,",
|
||||
@@ -715,11 +711,11 @@ export const dict = {
|
||||
|
||||
"download.title": "OpenCode | Baixar",
|
||||
"download.meta.description": "Baixe o OpenCode para macOS, Windows e Linux",
|
||||
"download.hero.title": "Baixar OpenCode Desktop",
|
||||
"download.hero.title": "Baixar OpenCode",
|
||||
"download.hero.subtitle": "Disponível em Beta para macOS, Windows e Linux",
|
||||
"download.hero.button": "Baixar para {{os}}",
|
||||
"download.section.terminal": "OpenCode Terminal",
|
||||
"download.section.desktop": "OpenCode Desktop",
|
||||
"download.section.desktop": "OpenCode Desktop (Beta)",
|
||||
"download.section.extensions": "Extensões OpenCode",
|
||||
"download.section.integrations": "Integrações OpenCode",
|
||||
"download.action.download": "Baixar",
|
||||
|
||||
@@ -102,14 +102,10 @@ export const dict = {
|
||||
"temp.logoDarkAlt": "opencode logo dark",
|
||||
|
||||
"home.banner.badge": "Ny",
|
||||
"home.banner.text": "Introduktion af Tabs til Desktop.",
|
||||
"home.banner.platforms": "Tilgængelig på macOS, Windows og Linux",
|
||||
"home.banner.text": "Desktop-app tilgængelig i beta",
|
||||
"home.banner.platforms": "på macOS, Windows og Linux",
|
||||
"home.banner.downloadNow": "Download nu",
|
||||
"home.banner.downloadBetaNow": "Download desktop-betaen nu",
|
||||
"home.promo.title": "Introduktion af Tabs til Desktop",
|
||||
"home.promo.body": "Organiser dit arbejde og aktive sessioner med faner.",
|
||||
"home.promo.cta": "Download den nyeste version for at komme i gang.",
|
||||
"home.promo.close": "Luk meddelelsen om Desktop-appen",
|
||||
|
||||
"home.hero.title": "Den open source AI-kodningsagent",
|
||||
"home.hero.subtitle.a": "Gratis modeller inkluderet, eller forbind enhver model fra enhver udbyder,",
|
||||
@@ -710,11 +706,11 @@ export const dict = {
|
||||
|
||||
"download.title": "OpenCode | Download",
|
||||
"download.meta.description": "Download OpenCode til macOS, Windows og Linux",
|
||||
"download.hero.title": "Download OpenCode Desktop",
|
||||
"download.hero.title": "Download OpenCode",
|
||||
"download.hero.subtitle": "Tilgængelig i beta til macOS, Windows og Linux",
|
||||
"download.hero.button": "Download til {{os}}",
|
||||
"download.section.terminal": "OpenCode Terminal",
|
||||
"download.section.desktop": "OpenCode Desktop",
|
||||
"download.section.desktop": "OpenCode Desktop (Beta)",
|
||||
"download.section.extensions": "OpenCode Extensions",
|
||||
"download.section.integrations": "OpenCode Integrations",
|
||||
"download.action.download": "Download",
|
||||
|
||||
@@ -102,14 +102,10 @@ export const dict = {
|
||||
"temp.logoDarkAlt": "OpenCode Logo dunkel",
|
||||
|
||||
"home.banner.badge": "Neu",
|
||||
"home.banner.text": "Neu: Tabs für Desktop.",
|
||||
"home.banner.platforms": "Verfügbar für macOS, Windows und Linux",
|
||||
"home.banner.text": "Desktop-App in der Beta verfügbar",
|
||||
"home.banner.platforms": "auf macOS, Windows und Linux",
|
||||
"home.banner.downloadNow": "Jetzt herunterladen",
|
||||
"home.banner.downloadBetaNow": "Desktop-Beta jetzt herunterladen",
|
||||
"home.promo.title": "Neu: Tabs für Desktop",
|
||||
"home.promo.body": "Organisiere deine Arbeit und aktiven Sitzungen mit Tabs.",
|
||||
"home.promo.cta": "Lade die neueste Version herunter, um loszulegen.",
|
||||
"home.promo.close": "Ankündigung zur Desktop-App schließen",
|
||||
|
||||
"home.hero.title": "Der Open-Source AI-Coding-Agent",
|
||||
"home.hero.subtitle.a": "Kostenlose Modelle inklusive oder verbinde jedes Modell eines beliebigen Anbieters,",
|
||||
@@ -715,11 +711,11 @@ export const dict = {
|
||||
|
||||
"download.title": "OpenCode | Download",
|
||||
"download.meta.description": "Lade OpenCode für macOS, Windows und Linux herunter",
|
||||
"download.hero.title": "OpenCode Desktop herunterladen",
|
||||
"download.hero.title": "OpenCode herunterladen",
|
||||
"download.hero.subtitle": "In Beta verfügbar für macOS, Windows und Linux",
|
||||
"download.hero.button": "Download für {{os}}",
|
||||
"download.section.terminal": "OpenCode Terminal",
|
||||
"download.section.desktop": "OpenCode Desktop",
|
||||
"download.section.desktop": "OpenCode Desktop (Beta)",
|
||||
"download.section.extensions": "OpenCode Extensions",
|
||||
"download.section.integrations": "OpenCode Integrationen",
|
||||
"download.action.download": "Download",
|
||||
|
||||
@@ -102,16 +102,11 @@ export const dict = {
|
||||
"temp.logoDarkAlt": "opencode logo dark",
|
||||
|
||||
"home.banner.badge": "New",
|
||||
"home.banner.text": "Introducing tabs for desktop.",
|
||||
"home.banner.platforms": "Available on macOS, Windows, and Linux",
|
||||
"home.banner.text": "Desktop app available in beta",
|
||||
"home.banner.platforms": "on macOS, Windows, and Linux",
|
||||
"home.banner.downloadNow": "Download now",
|
||||
"home.banner.downloadBetaNow": "Download the desktop beta now",
|
||||
|
||||
"home.promo.title": "Introducing Tabs for Desktop",
|
||||
"home.promo.body": "Organize your work and active sessions with tabs.",
|
||||
"home.promo.cta": "Download the latest to get started.",
|
||||
"home.promo.close": "Dismiss desktop app announcement",
|
||||
|
||||
"home.hero.title": "The open source AI coding agent",
|
||||
"home.hero.subtitle.a": "Free models included or connect any model from any provider,",
|
||||
"home.hero.subtitle.b": "including Claude, GPT, Gemini and more.",
|
||||
@@ -708,11 +703,11 @@ export const dict = {
|
||||
|
||||
"download.title": "OpenCode | Download",
|
||||
"download.meta.description": "Download OpenCode for macOS, Windows, and Linux",
|
||||
"download.hero.title": "Download OpenCode Desktop",
|
||||
"download.hero.title": "Download OpenCode",
|
||||
"download.hero.subtitle": "Available in Beta for macOS, Windows, and Linux",
|
||||
"download.hero.button": "Download for {{os}}",
|
||||
"download.section.terminal": "OpenCode Terminal",
|
||||
"download.section.desktop": "OpenCode Desktop",
|
||||
"download.section.desktop": "OpenCode Desktop (Beta)",
|
||||
"download.section.extensions": "OpenCode Extensions",
|
||||
"download.section.integrations": "OpenCode Integrations",
|
||||
"download.action.download": "Download",
|
||||
|
||||
@@ -102,14 +102,10 @@ export const dict = {
|
||||
"temp.logoDarkAlt": "logo de opencode oscuro",
|
||||
|
||||
"home.banner.badge": "Nuevo",
|
||||
"home.banner.text": "Presentamos Tabs para Desktop.",
|
||||
"home.banner.platforms": "Disponible en macOS, Windows y Linux",
|
||||
"home.banner.text": "Aplicación de escritorio disponible en beta",
|
||||
"home.banner.platforms": "en macOS, Windows y Linux",
|
||||
"home.banner.downloadNow": "Descargar ahora",
|
||||
"home.banner.downloadBetaNow": "Descargar la beta de escritorio ahora",
|
||||
"home.promo.title": "Presentamos Tabs para Desktop",
|
||||
"home.promo.body": "Organiza tu trabajo y tus sesiones activas con pestañas.",
|
||||
"home.promo.cta": "Descarga la última versión para empezar.",
|
||||
"home.promo.close": "Cerrar el anuncio de la aplicación Desktop",
|
||||
|
||||
"home.hero.title": "El agente de codificación IA de código abierto",
|
||||
"home.hero.subtitle.a": "Modelos gratuitos incluidos o conecta cualquier modelo de cualquier proveedor,",
|
||||
@@ -715,11 +711,11 @@ export const dict = {
|
||||
|
||||
"download.title": "OpenCode | Descargar",
|
||||
"download.meta.description": "Descarga OpenCode para macOS, Windows y Linux",
|
||||
"download.hero.title": "Descargar OpenCode Desktop",
|
||||
"download.hero.title": "Descargar OpenCode",
|
||||
"download.hero.subtitle": "Disponible en Beta para macOS, Windows y Linux",
|
||||
"download.hero.button": "Descargar para {{os}}",
|
||||
"download.section.terminal": "OpenCode Terminal",
|
||||
"download.section.desktop": "OpenCode Desktop",
|
||||
"download.section.desktop": "OpenCode Desktop (Beta)",
|
||||
"download.section.extensions": "Extensiones OpenCode",
|
||||
"download.section.integrations": "Integraciones OpenCode",
|
||||
"download.action.download": "Descargar",
|
||||
|
||||
@@ -100,14 +100,10 @@ export const dict = {
|
||||
"temp.logoDarkAlt": "opencode logo dark",
|
||||
|
||||
"home.banner.badge": "Nouveau",
|
||||
"home.banner.text": "Découvrez Tabs pour Desktop.",
|
||||
"home.banner.platforms": "Disponible sur macOS, Windows et Linux",
|
||||
"home.banner.text": "Application desktop disponible en bêta",
|
||||
"home.banner.platforms": "sur macOS, Windows et Linux",
|
||||
"home.banner.downloadNow": "Télécharger maintenant",
|
||||
"home.banner.downloadBetaNow": "Télécharger la bêta desktop maintenant",
|
||||
"home.promo.title": "Découvrez Tabs pour Desktop",
|
||||
"home.promo.body": "Organisez votre travail et vos sessions actives avec des onglets.",
|
||||
"home.promo.cta": "Téléchargez la dernière version pour commencer.",
|
||||
"home.promo.close": "Fermer l’annonce de l’application Desktop",
|
||||
|
||||
"home.hero.title": "L'agent de code IA open source",
|
||||
"home.hero.subtitle.a":
|
||||
@@ -722,11 +718,11 @@ export const dict = {
|
||||
|
||||
"download.title": "OpenCode | Téléchargement",
|
||||
"download.meta.description": "Téléchargez OpenCode pour macOS, Windows et Linux",
|
||||
"download.hero.title": "Télécharger OpenCode Desktop",
|
||||
"download.hero.title": "Télécharger OpenCode",
|
||||
"download.hero.subtitle": "Disponible en bêta pour macOS, Windows et Linux",
|
||||
"download.hero.button": "Télécharger pour {{os}}",
|
||||
"download.section.terminal": "OpenCode Terminal",
|
||||
"download.section.desktop": "OpenCode Desktop",
|
||||
"download.section.desktop": "OpenCode Desktop (Bêta)",
|
||||
"download.section.extensions": "Extensions OpenCode",
|
||||
"download.section.integrations": "Intégrations OpenCode",
|
||||
"download.action.download": "Télécharger",
|
||||
|
||||
@@ -102,14 +102,10 @@ export const dict = {
|
||||
"temp.logoDarkAlt": "logo scuro di opencode",
|
||||
|
||||
"home.banner.badge": "Nuovo",
|
||||
"home.banner.text": "Scopri Tabs per Desktop.",
|
||||
"home.banner.platforms": "Disponibile su macOS, Windows e Linux",
|
||||
"home.banner.text": "App desktop disponibile in beta",
|
||||
"home.banner.platforms": "su macOS, Windows e Linux",
|
||||
"home.banner.downloadNow": "Scarica ora",
|
||||
"home.banner.downloadBetaNow": "Scarica ora la beta desktop",
|
||||
"home.promo.title": "Scopri Tabs per Desktop",
|
||||
"home.promo.body": "Organizza il tuo lavoro e le sessioni attive con le schede.",
|
||||
"home.promo.cta": "Scarica l’ultima versione per iniziare.",
|
||||
"home.promo.close": "Chiudi l’annuncio dell’app Desktop",
|
||||
|
||||
"home.hero.title": "L'agente di coding IA open source",
|
||||
"home.hero.subtitle.a": "Modelli gratuiti inclusi o collega qualsiasi modello da qualsiasi provider,",
|
||||
@@ -713,11 +709,11 @@ export const dict = {
|
||||
|
||||
"download.title": "OpenCode | Download",
|
||||
"download.meta.description": "Scarica OpenCode per macOS, Windows e Linux",
|
||||
"download.hero.title": "Scarica OpenCode Desktop",
|
||||
"download.hero.title": "Scarica OpenCode",
|
||||
"download.hero.subtitle": "Disponibile in Beta per macOS, Windows e Linux",
|
||||
"download.hero.button": "Scarica per {{os}}",
|
||||
"download.section.terminal": "OpenCode Terminal",
|
||||
"download.section.desktop": "OpenCode Desktop",
|
||||
"download.section.desktop": "OpenCode Desktop (Beta)",
|
||||
"download.section.extensions": "OpenCode Extensions",
|
||||
"download.section.integrations": "OpenCode Integrations",
|
||||
"download.action.download": "Scarica",
|
||||
|
||||
@@ -102,14 +102,10 @@ export const dict = {
|
||||
"temp.logoDarkAlt": "opencodeのロゴ(ダーク)",
|
||||
|
||||
"home.banner.badge": "新着",
|
||||
"home.banner.text": "デスクトップ版にタブが登場。",
|
||||
"home.banner.platforms": "macOS、Windows、Linux で利用できます",
|
||||
"home.banner.text": "デスクトップアプリのベータ版が利用可能",
|
||||
"home.banner.platforms": "macOS、Windows、Linux で",
|
||||
"home.banner.downloadNow": "今すぐダウンロード",
|
||||
"home.banner.downloadBetaNow": "デスクトップベータ版を今すぐダウンロード",
|
||||
"home.promo.title": "デスクトップ版にタブが登場",
|
||||
"home.promo.body": "タブで作業とアクティブなセッションを整理できます。",
|
||||
"home.promo.cta": "始めるには最新版をダウンロードしてください。",
|
||||
"home.promo.close": "デスクトップアプリのお知らせを閉じる",
|
||||
|
||||
"home.hero.title": "オープンソースのAIコーディングエージェント",
|
||||
"home.hero.subtitle.a": "無料モデルが含まれています。また、任意のプロバイダーの任意のモデルに接続でき、",
|
||||
@@ -712,11 +708,11 @@ export const dict = {
|
||||
|
||||
"download.title": "OpenCode | ダウンロード",
|
||||
"download.meta.description": "OpenCode を macOS、Windows、Linux 向けにダウンロード",
|
||||
"download.hero.title": "OpenCode デスクトップ版をダウンロード",
|
||||
"download.hero.title": "OpenCode をダウンロード",
|
||||
"download.hero.subtitle": "macOS、Windows、Linux 向けベータ版を利用可能",
|
||||
"download.hero.button": "{{os}} 向けダウンロード",
|
||||
"download.section.terminal": "OpenCode Terminal",
|
||||
"download.section.desktop": "OpenCode Desktop",
|
||||
"download.section.desktop": "OpenCode Desktop (Beta)",
|
||||
"download.section.extensions": "OpenCode Extensions",
|
||||
"download.section.integrations": "OpenCode Integrations",
|
||||
"download.action.download": "ダウンロード",
|
||||
|
||||
@@ -102,14 +102,10 @@ export const dict = {
|
||||
"temp.logoDarkAlt": "opencode 어두운 로고",
|
||||
|
||||
"home.banner.badge": "신규",
|
||||
"home.banner.text": "데스크톱 탭을 소개합니다.",
|
||||
"home.banner.platforms": "macOS, Windows, Linux에서 사용할 수 있습니다",
|
||||
"home.banner.text": "데스크톱 앱 베타 버전 출시",
|
||||
"home.banner.platforms": "macOS, Windows, Linux 지원",
|
||||
"home.banner.downloadNow": "지금 다운로드",
|
||||
"home.banner.downloadBetaNow": "데스크톱 베타 다운로드",
|
||||
"home.promo.title": "데스크톱 탭을 소개합니다",
|
||||
"home.promo.body": "탭으로 작업과 활성 세션을 정리하세요.",
|
||||
"home.promo.cta": "최신 버전을 다운로드하여 시작하세요.",
|
||||
"home.promo.close": "데스크톱 앱 안내 닫기",
|
||||
|
||||
"home.hero.title": "오픈 소스 AI 코딩 에이전트",
|
||||
"home.hero.subtitle.a": "무료 모델이 포함되어 있으며, 어떤 제공자의 모델이든 연결 가능합니다.",
|
||||
@@ -704,11 +700,11 @@ export const dict = {
|
||||
|
||||
"download.title": "OpenCode | 다운로드",
|
||||
"download.meta.description": "macOS, Windows, Linux용 OpenCode 다운로드",
|
||||
"download.hero.title": "OpenCode 데스크톱 다운로드",
|
||||
"download.hero.title": "OpenCode 다운로드",
|
||||
"download.hero.subtitle": "macOS, Windows, Linux용 베타 버전 사용 가능",
|
||||
"download.hero.button": "{{os}}용 다운로드",
|
||||
"download.section.terminal": "OpenCode 터미널",
|
||||
"download.section.desktop": "OpenCode 데스크톱",
|
||||
"download.section.desktop": "OpenCode 데스크톱 (베타)",
|
||||
"download.section.extensions": "OpenCode 확장 프로그램",
|
||||
"download.section.integrations": "OpenCode 통합",
|
||||
"download.action.download": "다운로드",
|
||||
|
||||
@@ -102,14 +102,10 @@ export const dict = {
|
||||
"temp.logoDarkAlt": "opencode logo mørk",
|
||||
|
||||
"home.banner.badge": "Ny",
|
||||
"home.banner.text": "Vi introduserer Tabs for Desktop.",
|
||||
"home.banner.platforms": "Tilgjengelig på macOS, Windows og Linux",
|
||||
"home.banner.text": "Desktop-app tilgjengelig i beta",
|
||||
"home.banner.platforms": "på macOS, Windows og Linux",
|
||||
"home.banner.downloadNow": "Last ned nå",
|
||||
"home.banner.downloadBetaNow": "Last ned desktop-betaen nå",
|
||||
"home.promo.title": "Vi introduserer Tabs for Desktop",
|
||||
"home.promo.body": "Organiser arbeidet ditt og aktive økter med faner.",
|
||||
"home.promo.cta": "Last ned den nyeste versjonen for å komme i gang.",
|
||||
"home.promo.close": "Lukk kunngjøringen om Desktop-appen",
|
||||
|
||||
"home.hero.title": "Den åpne kildekode AI-kodingsagenten",
|
||||
"home.hero.subtitle.a":
|
||||
@@ -711,11 +707,11 @@ export const dict = {
|
||||
|
||||
"download.title": "OpenCode | Last ned",
|
||||
"download.meta.description": "Last ned OpenCode for macOS, Windows og Linux",
|
||||
"download.hero.title": "Last ned OpenCode Desktop",
|
||||
"download.hero.title": "Last ned OpenCode",
|
||||
"download.hero.subtitle": "Tilgjengelig i beta for macOS, Windows og Linux",
|
||||
"download.hero.button": "Last ned for {{os}}",
|
||||
"download.section.terminal": "OpenCode Terminal",
|
||||
"download.section.desktop": "OpenCode Desktop",
|
||||
"download.section.desktop": "OpenCode Desktop (Beta)",
|
||||
"download.section.extensions": "OpenCode Extensions",
|
||||
"download.section.integrations": "OpenCode Integrations",
|
||||
"download.action.download": "Last ned",
|
||||
|
||||
@@ -101,14 +101,10 @@ export const dict = {
|
||||
"temp.logoDarkAlt": "ciemne logo opencode",
|
||||
|
||||
"home.banner.badge": "Nowość",
|
||||
"home.banner.text": "Przedstawiamy karty w aplikacji desktopowej.",
|
||||
"home.banner.platforms": "Dostępne na macOS, Windows i Linux",
|
||||
"home.banner.text": "Aplikacja desktopowa dostępna w wersji beta",
|
||||
"home.banner.platforms": "na macOS, Windows i Linux",
|
||||
"home.banner.downloadNow": "Pobierz teraz",
|
||||
"home.banner.downloadBetaNow": "Pobierz betę wersji desktopowej",
|
||||
"home.promo.title": "Przedstawiamy karty w aplikacji desktopowej",
|
||||
"home.promo.body": "Organizuj swoją pracę i aktywne sesje za pomocą kart.",
|
||||
"home.promo.cta": "Pobierz najnowszą wersję, aby rozpocząć.",
|
||||
"home.promo.close": "Zamknij ogłoszenie o aplikacji desktopowej",
|
||||
|
||||
"home.hero.title": "Open source'owy agent AI do kodowania",
|
||||
"home.hero.subtitle.a": "Darmowe modele w zestawie lub podłącz dowolny model od dowolnego dostawcy,",
|
||||
@@ -712,11 +708,11 @@ export const dict = {
|
||||
|
||||
"download.title": "OpenCode | Pobierz",
|
||||
"download.meta.description": "Pobierz OpenCode na macOS, Windows i Linux",
|
||||
"download.hero.title": "Pobierz OpenCode Desktop",
|
||||
"download.hero.title": "Pobierz OpenCode",
|
||||
"download.hero.subtitle": "Dostępne w wersji Beta na macOS, Windows i Linux",
|
||||
"download.hero.button": "Pobierz na {{os}}",
|
||||
"download.section.terminal": "Terminal OpenCode",
|
||||
"download.section.desktop": "Pulpit OpenCode",
|
||||
"download.section.desktop": "Pulpit OpenCode (Beta)",
|
||||
"download.section.extensions": "Rozszerzenia OpenCode",
|
||||
"download.section.integrations": "Integracje OpenCode",
|
||||
"download.action.download": "Pobierz",
|
||||
|
||||
@@ -102,14 +102,10 @@ export const dict = {
|
||||
"temp.logoDarkAlt": "темный логотип opencode",
|
||||
|
||||
"home.banner.badge": "Новое",
|
||||
"home.banner.text": "Представляем вкладки в десктопном приложении.",
|
||||
"home.banner.platforms": "Доступно на macOS, Windows и Linux",
|
||||
"home.banner.text": "Доступно десктопное приложение (бета)",
|
||||
"home.banner.platforms": "на macOS, Windows и Linux",
|
||||
"home.banner.downloadNow": "Скачать",
|
||||
"home.banner.downloadBetaNow": "Скачать бету для десктопа",
|
||||
"home.promo.title": "Представляем вкладки в десктопном приложении",
|
||||
"home.promo.body": "Организуйте работу и активные сессии с помощью вкладок.",
|
||||
"home.promo.cta": "Скачайте последнюю версию, чтобы начать.",
|
||||
"home.promo.close": "Закрыть объявление о десктопном приложении",
|
||||
|
||||
"home.hero.title": "AI-агент с открытым кодом для программирования",
|
||||
"home.hero.subtitle.a": "Бесплатные модели включены, или подключите любую модель от любого провайдера,",
|
||||
@@ -720,11 +716,11 @@ export const dict = {
|
||||
|
||||
"download.title": "OpenCode | Скачать",
|
||||
"download.meta.description": "Скачать OpenCode для macOS, Windows и Linux",
|
||||
"download.hero.title": "Скачать OpenCode Desktop",
|
||||
"download.hero.title": "Скачать OpenCode",
|
||||
"download.hero.subtitle": "Доступна бета для macOS, Windows и Linux",
|
||||
"download.hero.button": "Скачать для {{os}}",
|
||||
"download.section.terminal": "OpenCode Terminal",
|
||||
"download.section.desktop": "OpenCode Desktop",
|
||||
"download.section.desktop": "OpenCode Desktop (Beta)",
|
||||
"download.section.extensions": "Расширения OpenCode",
|
||||
"download.section.integrations": "Интеграции OpenCode",
|
||||
"download.action.download": "Скачать",
|
||||
|
||||
@@ -102,14 +102,10 @@ export const dict = {
|
||||
"temp.logoDarkAlt": "โลโก้ opencode แบบมืด",
|
||||
|
||||
"home.banner.badge": "ใหม่",
|
||||
"home.banner.text": "ขอแนะนำแท็บสำหรับเดสก์ท็อป.",
|
||||
"home.banner.platforms": "พร้อมใช้งานบน macOS, Windows และ Linux",
|
||||
"home.banner.text": "แอปเดสก์ท็อปพร้อมใช้งานในเวอร์ชันเบต้า",
|
||||
"home.banner.platforms": "บน macOS, Windows และ Linux",
|
||||
"home.banner.downloadNow": "ดาวน์โหลดตอนนี้",
|
||||
"home.banner.downloadBetaNow": "ดาวน์โหลดเบต้าเดสก์ท็อปตอนนี้",
|
||||
"home.promo.title": "ขอแนะนำแท็บสำหรับเดสก์ท็อป",
|
||||
"home.promo.body": "จัดระเบียบงานและเซสชันที่ใช้งานอยู่ด้วยแท็บ",
|
||||
"home.promo.cta": "ดาวน์โหลดเวอร์ชันล่าสุดเพื่อเริ่มต้นใช้งาน",
|
||||
"home.promo.close": "ปิดประกาศเกี่ยวกับแอปเดสก์ท็อป",
|
||||
|
||||
"home.hero.title": "เอเจนต์เขียนโค้ดด้วย AI แบบโอเพนซอร์ส",
|
||||
"home.hero.subtitle.a": "มีโมเดลฟรีรวมอยู่ หรือเชื่อมต่อโมเดลใดก็ได้จากผู้ให้บริการรายใดก็ได้,",
|
||||
@@ -707,11 +703,11 @@ export const dict = {
|
||||
|
||||
"download.title": "OpenCode | ดาวน์โหลด",
|
||||
"download.meta.description": "ดาวน์โหลด OpenCode สำหรับ macOS, Windows และ Linux",
|
||||
"download.hero.title": "ดาวน์โหลด OpenCode สำหรับเดสก์ท็อป",
|
||||
"download.hero.title": "ดาวน์โหลด OpenCode",
|
||||
"download.hero.subtitle": "พร้อมใช้งานในเวอร์ชันเบต้าสำหรับ macOS, Windows และ Linux",
|
||||
"download.hero.button": "ดาวน์โหลดสำหรับ {{os}}",
|
||||
"download.section.terminal": "OpenCode Terminal",
|
||||
"download.section.desktop": "OpenCode Desktop",
|
||||
"download.section.desktop": "OpenCode Desktop (Beta)",
|
||||
"download.section.extensions": "ส่วนขยาย OpenCode",
|
||||
"download.section.integrations": "การเชื่อมต่อ OpenCode",
|
||||
"download.action.download": "ดาวน์โหลด",
|
||||
|
||||
@@ -102,14 +102,10 @@ export const dict = {
|
||||
"temp.logoDarkAlt": "opencode koyu logo",
|
||||
|
||||
"home.banner.badge": "Yeni",
|
||||
"home.banner.text": "Masaüstü uygulamasında sekmelerle tanışın.",
|
||||
"home.banner.platforms": "macOS, Windows ve Linux'ta kullanılabilir",
|
||||
"home.banner.text": "Masaüstü uygulaması beta olarak mevcut",
|
||||
"home.banner.platforms": "macOS, Windows ve Linux'ta",
|
||||
"home.banner.downloadNow": "Şimdi indir",
|
||||
"home.banner.downloadBetaNow": "Masaüstü betayı şimdi indir",
|
||||
"home.promo.title": "Masaüstü uygulamasında sekmelerle tanışın",
|
||||
"home.promo.body": "Çalışmalarınızı ve etkin oturumlarınızı sekmelerle düzenleyin.",
|
||||
"home.promo.cta": "Başlamak için en son sürümü indirin.",
|
||||
"home.promo.close": "Masaüstü uygulaması duyurusunu kapat",
|
||||
|
||||
"home.hero.title": "Açık kaynaklı yapay zeka kodlama ajanı",
|
||||
"home.hero.subtitle.a": "Ücretsiz modeller dahil veya herhangi bir sağlayıcıdan herhangi bir modeli bağlayın,",
|
||||
@@ -715,11 +711,11 @@ export const dict = {
|
||||
|
||||
"download.title": "OpenCode | İndir",
|
||||
"download.meta.description": "OpenCode'u macOS, Windows ve Linux için indirin",
|
||||
"download.hero.title": "OpenCode Desktop'u İndir",
|
||||
"download.hero.title": "OpenCode'u İndir",
|
||||
"download.hero.subtitle": "macOS, Windows ve Linux için Beta olarak sunuluyor",
|
||||
"download.hero.button": "{{os}} için indir",
|
||||
"download.section.terminal": "OpenCode Terminal",
|
||||
"download.section.desktop": "OpenCode Desktop",
|
||||
"download.section.desktop": "OpenCode Desktop (Beta)",
|
||||
"download.section.extensions": "OpenCode Eklentileri",
|
||||
"download.section.integrations": "OpenCode Entegrasyonları",
|
||||
"download.action.download": "İndir",
|
||||
|
||||
@@ -102,14 +102,10 @@ export const dict = {
|
||||
"temp.logoDarkAlt": "темний логотип opencode",
|
||||
|
||||
"home.banner.badge": "Нове",
|
||||
"home.banner.text": "Представляємо вкладки в десктопному застосунку.",
|
||||
"home.banner.platforms": "Доступно на macOS, Windows та Linux",
|
||||
"home.banner.text": "Десктопний застосунок доступний у бета-версії",
|
||||
"home.banner.platforms": "на macOS, Windows та Linux",
|
||||
"home.banner.downloadNow": "Завантажити зараз",
|
||||
"home.banner.downloadBetaNow": "Завантажити бета-версію десктопного застосунку",
|
||||
"home.promo.title": "Представляємо вкладки в десктопному застосунку",
|
||||
"home.promo.body": "Упорядковуйте роботу й активні сесії за допомогою вкладок.",
|
||||
"home.promo.cta": "Завантажте останню версію, щоб почати.",
|
||||
"home.promo.close": "Закрити оголошення про десктопний застосунок",
|
||||
|
||||
"home.hero.title": "Відкритий AI-агент для кодування",
|
||||
"home.hero.subtitle.a": "Безкоштовні моделі включено або підключіть будь-яку модель від будь-якого провайдера,",
|
||||
@@ -674,11 +670,11 @@ export const dict = {
|
||||
|
||||
"download.title": "OpenCode | Завантажити",
|
||||
"download.meta.description": "Завантажте OpenCode для macOS, Windows та Linux",
|
||||
"download.hero.title": "Завантажити OpenCode Desktop",
|
||||
"download.hero.title": "Завантажити OpenCode",
|
||||
"download.hero.subtitle": "Доступно в бета-версії для macOS, Windows та Linux",
|
||||
"download.hero.button": "Завантажити для {{os}}",
|
||||
"download.section.terminal": "Термінал OpenCode",
|
||||
"download.section.desktop": "Десктоп OpenCode",
|
||||
"download.section.desktop": "Десктоп OpenCode (Бета)",
|
||||
"download.section.extensions": "Розширення OpenCode",
|
||||
"download.section.integrations": "Інтеграції OpenCode",
|
||||
"download.action.download": "Завантажити",
|
||||
|
||||
@@ -103,14 +103,10 @@ export const dict = {
|
||||
"temp.logoDarkAlt": "opencode logo 暗色",
|
||||
|
||||
"home.banner.badge": "新",
|
||||
"home.banner.text": "桌面版标签页现已推出。",
|
||||
"home.banner.platforms": "适用于 macOS、Windows 和 Linux",
|
||||
"home.banner.text": "桌面应用 Beta 版现已推出",
|
||||
"home.banner.platforms": "支持 macOS, Windows, 和 Linux",
|
||||
"home.banner.downloadNow": "立即下载",
|
||||
"home.banner.downloadBetaNow": "立即下载桌面 Beta 版",
|
||||
"home.promo.title": "桌面版标签页现已推出",
|
||||
"home.promo.body": "使用标签页整理工作和活跃会话。",
|
||||
"home.promo.cta": "下载最新版本即可开始使用。",
|
||||
"home.promo.close": "关闭桌面应用公告",
|
||||
|
||||
"home.hero.title": "开源 AI 编程代理",
|
||||
"home.hero.subtitle.a": "内置免费模型,或连接任意提供商的任意模型,",
|
||||
@@ -686,11 +682,11 @@ export const dict = {
|
||||
|
||||
"download.title": "OpenCode | 下载",
|
||||
"download.meta.description": "下载适用于 macOS, Windows, 和 Linux 的 OpenCode",
|
||||
"download.hero.title": "下载 OpenCode 桌面版",
|
||||
"download.hero.title": "下载 OpenCode",
|
||||
"download.hero.subtitle": "适用于 macOS, Windows, 和 Linux 的 Beta 版",
|
||||
"download.hero.button": "下载 {{os}} 版",
|
||||
"download.section.terminal": "OpenCode 终端",
|
||||
"download.section.desktop": "OpenCode 桌面版",
|
||||
"download.section.desktop": "OpenCode 桌面版 (Beta)",
|
||||
"download.section.extensions": "OpenCode 扩展",
|
||||
"download.section.integrations": "OpenCode 集成",
|
||||
"download.action.download": "下载",
|
||||
|
||||
@@ -103,14 +103,10 @@ export const dict = {
|
||||
"temp.logoDarkAlt": "opencode 深色標誌",
|
||||
|
||||
"home.banner.badge": "新",
|
||||
"home.banner.text": "桌面版分頁功能全新推出。",
|
||||
"home.banner.platforms": "適用於 macOS、Windows 與 Linux",
|
||||
"home.banner.text": "桌面應用已推出 Beta",
|
||||
"home.banner.platforms": "支援 macOS、Windows 與 Linux",
|
||||
"home.banner.downloadNow": "立即下載",
|
||||
"home.banner.downloadBetaNow": "立即下載桌面 Beta 版",
|
||||
"home.promo.title": "桌面版分頁功能全新推出",
|
||||
"home.promo.body": "使用分頁整理工作和作用中的工作階段。",
|
||||
"home.promo.cta": "下載最新版本即可開始使用。",
|
||||
"home.promo.close": "關閉桌面應用程式公告",
|
||||
|
||||
"home.hero.title": "開源 AI 編碼代理",
|
||||
"home.hero.subtitle.a": "內建免費模型,或連接任意供應商的任意模型,",
|
||||
@@ -686,11 +682,11 @@ export const dict = {
|
||||
|
||||
"download.title": "OpenCode | 下載",
|
||||
"download.meta.description": "下載適用於 macOS、Windows 與 Linux 的 OpenCode",
|
||||
"download.hero.title": "下載 OpenCode 桌面版",
|
||||
"download.hero.title": "下載 OpenCode",
|
||||
"download.hero.subtitle": "適用於 macOS、Windows 與 Linux 的 Beta 版現已提供",
|
||||
"download.hero.button": "下載 {{os}} 版",
|
||||
"download.section.terminal": "OpenCode 終端",
|
||||
"download.section.desktop": "OpenCode 桌面版",
|
||||
"download.section.desktop": "OpenCode 桌面版(Beta)",
|
||||
"download.section.extensions": "OpenCode 擴充功能",
|
||||
"download.section.integrations": "OpenCode 整合",
|
||||
"download.action.download": "下載",
|
||||
|
||||
@@ -284,7 +284,7 @@
|
||||
}
|
||||
|
||||
[data-component="content"] {
|
||||
padding: 3rem 5rem 6rem;
|
||||
padding: 6rem 5rem;
|
||||
|
||||
@media (max-width: 60rem) {
|
||||
padding: 4rem 1.5rem;
|
||||
@@ -316,43 +316,67 @@
|
||||
|
||||
/* Download Hero Section */
|
||||
[data-component="download-hero"] {
|
||||
display: grid;
|
||||
grid-template-columns: 255px 1fr;
|
||||
/* display: grid; */
|
||||
display: none;
|
||||
grid-template-columns: 260px 1fr;
|
||||
gap: 4rem;
|
||||
padding: 4px;
|
||||
border: 1px solid var(--color-border-weak);
|
||||
border-radius: 8px;
|
||||
padding-bottom: 2rem;
|
||||
margin-bottom: 4rem;
|
||||
|
||||
@media (max-width: 50rem) {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0;
|
||||
gap: 1.5rem;
|
||||
padding-bottom: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
[data-component="hero-video"] {
|
||||
video {
|
||||
display: block;
|
||||
width: 100%;
|
||||
aspect-ratio: 1;
|
||||
object-fit: cover;
|
||||
border-radius: 4px;
|
||||
[data-component="hero-icon"] {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
|
||||
@media (max-width: 40rem) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[data-slot="icon-placeholder"] {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
background: var(--color-background-weak);
|
||||
border: 1px solid var(--color-border-weak);
|
||||
border-radius: 24px;
|
||||
|
||||
@media (max-width: 50rem) {
|
||||
aspect-ratio: 16 / 9;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border-radius: 24px;
|
||||
box-shadow:
|
||||
0 1.467px 2.847px 0 rgba(0, 0, 0, 0.42),
|
||||
0 0.779px 1.512px 0 rgba(0, 0, 0, 0.34),
|
||||
0 0.324px 0.629px 0 rgba(0, 0, 0, 0.24);
|
||||
|
||||
@media (max-width: 50rem) {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 50rem) {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
[data-component="hero-text"] {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding-right: 3rem;
|
||||
|
||||
@media (max-width: 50rem) {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.5rem;
|
||||
|
||||
@@ -11,7 +11,7 @@ import { LocaleLinks } from "~/component/locale-links"
|
||||
import { config } from "~/config"
|
||||
import { useI18n } from "~/context/i18n"
|
||||
import { useLanguage } from "~/context/language"
|
||||
import desktopTabsVideo from "../../asset/lander/desktop-tabs-landscape.mp4"
|
||||
import desktopAppIcon from "../../asset/lander/opencode-desktop-icon.png"
|
||||
import type { DownloadPlatform } from "./types"
|
||||
|
||||
type OS = "macOS" | "Windows" | "Linux" | null
|
||||
@@ -93,14 +93,12 @@ export default function Download() {
|
||||
|
||||
<div data-component="content">
|
||||
<section data-component="download-hero">
|
||||
<div data-component="hero-video">
|
||||
<video src={desktopTabsVideo} autoplay playsinline loop muted preload="metadata" aria-hidden="true" />
|
||||
<div data-component="hero-icon">
|
||||
<img src={desktopAppIcon} alt="" />
|
||||
</div>
|
||||
<div data-component="hero-text">
|
||||
<h1>{i18n.t("download.hero.title")}</h1>
|
||||
<p>
|
||||
{i18n.t("home.promo.body")} {i18n.t("home.promo.cta")}
|
||||
</p>
|
||||
<p>{i18n.t("download.hero.subtitle")}</p>
|
||||
<Show when={detectedOS()}>
|
||||
<a
|
||||
href={language.route(getDownloadHref(getDownloadPlatform(detectedOS())))}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/console-core",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-function",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-mail",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"dependencies": {
|
||||
"@jsx-email/all": "2.2.3",
|
||||
"@jsx-email/cli": "1.4.3",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/console-support",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"name": "@opencode-ai/core",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -114,14 +114,7 @@ export namespace FSUtil {
|
||||
})
|
||||
|
||||
const ensureDir = Effect.fn("FileSystem.ensureDir")(function* (path: string) {
|
||||
yield* fs.makeDirectory(path, { recursive: true }).pipe(
|
||||
// Bun on Windows can throw EEXIST here despite recursive mode.
|
||||
// https://github.com/oven-sh/bun/issues/21901
|
||||
Effect.catchIf(
|
||||
(error) => error.reason._tag === "AlreadyExists",
|
||||
(error) => isDir(path).pipe(Effect.flatMap((exists) => (exists ? Effect.void : Effect.fail(error)))),
|
||||
),
|
||||
)
|
||||
yield* fs.makeDirectory(path, { recursive: true })
|
||||
})
|
||||
|
||||
const writeWithDirs = Effect.fn("FileSystem.writeWithDirs")(function* (
|
||||
|
||||
@@ -74,13 +74,17 @@ const assistant = (message: SessionMessage.Assistant, model: Model) => {
|
||||
const content = message.content.flatMap((item): ContentPart[] => {
|
||||
if (item.type === "text") return [{ type: "text", text: item.text }]
|
||||
if (item.type === "reasoning")
|
||||
return [
|
||||
{
|
||||
type: "reasoning",
|
||||
text: item.text,
|
||||
providerMetadata: reuseProviderMetadata ? item.providerMetadata : undefined,
|
||||
},
|
||||
]
|
||||
return sameModel
|
||||
? [
|
||||
{
|
||||
type: "reasoning",
|
||||
text: item.text,
|
||||
providerMetadata: reuseProviderMetadata ? item.providerMetadata : undefined,
|
||||
},
|
||||
]
|
||||
: item.text.length > 0
|
||||
? [{ type: "text", text: item.text }]
|
||||
: []
|
||||
const call = toolCall(item, reuseProviderMetadata ? item.provider?.metadata : undefined)
|
||||
if (item.provider?.executed !== true) return [call]
|
||||
const result = toolResult(
|
||||
|
||||
@@ -81,9 +81,6 @@ export const Info = Schema.Struct({
|
||||
description:
|
||||
"Default agent to use when none is specified. Must be a primary agent. Falls back to 'build' if not set or if the specified agent is invalid.",
|
||||
}),
|
||||
subagent_depth: Schema.optional(NonNegativeInt).annotate({
|
||||
description: "Maximum subagent nesting depth. Defaults to 1, which prevents subagents from launching subagents.",
|
||||
}),
|
||||
username: Schema.optional(Schema.String).annotate({
|
||||
description: "Custom username to display in conversations instead of system username",
|
||||
}),
|
||||
|
||||
@@ -457,7 +457,7 @@ Recent work
|
||||
)
|
||||
|
||||
expect(messages[0]?.content).toEqual([
|
||||
{ type: "reasoning", text: "Visible thought", providerMetadata: undefined },
|
||||
{ type: "text", text: "Visible thought" },
|
||||
{
|
||||
type: "tool-call",
|
||||
id: "hosted-old-model",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@opencode-ai/desktop",
|
||||
"private": true,
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"homepage": "https://opencode.ai",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"name": "@opencode-ai/effect-drizzle-sqlite",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"name": "@opencode-ai/effect-sqlite-node",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/enterprise",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/function",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"name": "@opencode-ai/http-recorder",
|
||||
"description": "Record and replay Effect HTTP client traffic with deterministic cassettes",
|
||||
"type": "module",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"name": "@opencode-ai/llm",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -447,15 +447,10 @@ const lowerMessages = Effect.fn("AnthropicMessages.lowerMessages")(function* (
|
||||
continue
|
||||
}
|
||||
if (part.type === "reasoning") {
|
||||
const signature = part.encrypted ?? signatureFromMetadata(part.providerMetadata)
|
||||
if (!signature) {
|
||||
content.push({ type: "text", text: part.text })
|
||||
continue
|
||||
}
|
||||
content.push({
|
||||
type: "thinking",
|
||||
thinking: part.text,
|
||||
signature,
|
||||
signature: part.encrypted ?? signatureFromMetadata(part.providerMetadata),
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -348,14 +348,9 @@ const lowerMessages = Effect.fn("BedrockConverse.lowerMessages")(function* (
|
||||
continue
|
||||
}
|
||||
if (part.type === "reasoning") {
|
||||
const signature = reasoningSignature(part)
|
||||
if (!signature) {
|
||||
content.push({ text: part.text })
|
||||
continue
|
||||
}
|
||||
content.push({
|
||||
reasoningContent: {
|
||||
reasoningText: { text: part.text, signature },
|
||||
reasoningText: { text: part.text, signature: reasoningSignature(part) },
|
||||
},
|
||||
})
|
||||
continue
|
||||
|
||||
@@ -236,8 +236,7 @@ const lowerMessages = Effect.fn("Gemini.lowerMessages")(function* (request: LLMR
|
||||
continue
|
||||
}
|
||||
if (part.type === "reasoning") {
|
||||
const signature = thoughtSignature(part.providerMetadata)
|
||||
parts.push(signature ? { text: part.text, thought: true, thoughtSignature: signature } : { text: part.text })
|
||||
parts.push({ text: part.text, thought: true, thoughtSignature: thoughtSignature(part.providerMetadata) })
|
||||
continue
|
||||
}
|
||||
if (part.type === "tool-call") {
|
||||
|
||||
@@ -383,12 +383,9 @@ const lowerMessages = Effect.fn("OpenAIResponses.lowerMessages")(function* (requ
|
||||
continue
|
||||
}
|
||||
if (part.type === "reasoning") {
|
||||
const reasoning = lowerReasoning(part)
|
||||
if (!reasoning) {
|
||||
content.push({ type: "text", text: part.text })
|
||||
continue
|
||||
}
|
||||
flushText()
|
||||
const reasoning = lowerReasoning(part)
|
||||
if (!reasoning) continue
|
||||
if (store !== false) {
|
||||
if (!reasoningReferences.has(reasoning.id)) input.push({ type: "item_reference", id: reasoning.id })
|
||||
reasoningReferences.add(reasoning.id)
|
||||
|
||||
@@ -362,18 +362,6 @@ describe("Anthropic Messages route", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("lowers unsigned foreign reasoning to assistant text", () =>
|
||||
Effect.gen(function* () {
|
||||
const prepared = yield* LLMClient.prepare(
|
||||
LLM.request({ model, messages: [Message.assistant({ type: "reasoning", text: "foreign thought" })] }),
|
||||
)
|
||||
|
||||
expect(prepared.body).toMatchObject({
|
||||
messages: [{ role: "assistant", content: [{ type: "text", text: "foreign thought" }] }],
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("parses text, reasoning, and usage stream fixtures", () =>
|
||||
Effect.gen(function* () {
|
||||
const body = sseEvents(
|
||||
|
||||
@@ -355,20 +355,6 @@ describe("Bedrock Converse route", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("lowers unsigned foreign reasoning to assistant text", () =>
|
||||
Effect.gen(function* () {
|
||||
const prepared = yield* LLMClient.prepare<BedrockConverse.BedrockConverseBody>(
|
||||
LLM.request({
|
||||
model,
|
||||
messages: [Message.assistant({ type: "reasoning", text: "foreign thought" })],
|
||||
cache: "none",
|
||||
}),
|
||||
)
|
||||
|
||||
expect(prepared.body.messages).toEqual([{ role: "assistant", content: [{ text: "foreign thought" }] }])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("emits provider-error for throttlingException", () =>
|
||||
Effect.gen(function* () {
|
||||
const body = eventStreamBody(
|
||||
|
||||
@@ -431,16 +431,6 @@ describe("Gemini route", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("lowers unsigned foreign reasoning to assistant text", () =>
|
||||
Effect.gen(function* () {
|
||||
const prepared = yield* LLMClient.prepare<Gemini.GeminiBody>(
|
||||
LLM.request({ model, messages: [Message.assistant({ type: "reasoning", text: "foreign thought" })] }),
|
||||
)
|
||||
|
||||
expect(prepared.body.contents).toEqual([{ role: "model", parts: [{ text: "foreign thought" }] }])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("emits streamed tool calls and maps finish reason", () =>
|
||||
Effect.gen(function* () {
|
||||
const body = sseEvents({
|
||||
|
||||
@@ -818,34 +818,6 @@ describe("OpenAI Responses route", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("lowers foreign reasoning without continuation state to assistant text", () =>
|
||||
Effect.gen(function* () {
|
||||
const prepared = yield* LLMClient.prepare<OpenAIResponses.OpenAIResponsesBody>(
|
||||
LLM.request({
|
||||
model,
|
||||
messages: [
|
||||
Message.assistant([
|
||||
{ type: "text", text: "before" },
|
||||
{ type: "reasoning", text: "foreign thought" },
|
||||
{ type: "text", text: "after" },
|
||||
]),
|
||||
],
|
||||
}),
|
||||
)
|
||||
|
||||
expect(prepared.body.input).toEqual([
|
||||
{
|
||||
role: "assistant",
|
||||
content: [
|
||||
{ type: "output_text", text: "before" },
|
||||
{ type: "output_text", text: "foreign thought" },
|
||||
{ type: "output_text", text: "after" },
|
||||
],
|
||||
},
|
||||
])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("streams each reasoning summary part as a separate block", () =>
|
||||
Effect.gen(function* () {
|
||||
const response = yield* LLMClient.generate(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"name": "opencode",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -633,12 +633,6 @@ export function RunSubagentSelectBody(props: {
|
||||
return
|
||||
}
|
||||
|
||||
if (event.name.toLowerCase() === "up" && menu.selected() === 0) {
|
||||
event.preventDefault()
|
||||
props.onClose()
|
||||
return
|
||||
}
|
||||
|
||||
handleKey({ event, menu, field: () => field, setQuery, select, close: props.onClose })
|
||||
})
|
||||
|
||||
|
||||
@@ -1150,7 +1150,7 @@ export function options(input: {
|
||||
}
|
||||
|
||||
if (input.model.providerID === "meta" && input.model.api.npm === "@ai-sdk/openai") {
|
||||
result["reasoningEffort"] = "xhigh"
|
||||
result["reasoningEffort"] = "high"
|
||||
result["reasoningSummary"] = "auto"
|
||||
result["include"] = INCLUDE_ENCRYPTED_REASONING
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ const messages = (input: readonly ModelMessage[]) => {
|
||||
Message.make({
|
||||
role: message.role,
|
||||
content: content(message.content),
|
||||
native: isRecord(message.providerOptions) ? message.providerOptions : undefined,
|
||||
native: isRecord(message.providerOptions) ? { providerOptions: message.providerOptions } : undefined,
|
||||
}),
|
||||
]
|
||||
})
|
||||
|
||||
@@ -243,10 +243,6 @@ export const toModelMessagesEffect = Effect.fnUntraced(function* (
|
||||
|
||||
if (msg.info.role === "assistant") {
|
||||
const differentModel = `${model.providerID}/${model.id}` !== `${msg.info.providerID}/${msg.info.modelID}`
|
||||
const replaysForeignReasoning =
|
||||
model.api.npm === "@ai-sdk/openai-compatible" &&
|
||||
typeof model.capabilities.interleaved === "object" &&
|
||||
model.capabilities.interleaved.field === "reasoning_content"
|
||||
const media: Array<{ mime: string; url: string; filename?: string }> = []
|
||||
|
||||
if (
|
||||
@@ -364,7 +360,7 @@ export const toModelMessagesEffect = Effect.fnUntraced(function* (
|
||||
})
|
||||
}
|
||||
if (part.type === "reasoning") {
|
||||
if (differentModel && !replaysForeignReasoning) {
|
||||
if (differentModel) {
|
||||
if (part.text.trim().length > 0)
|
||||
assistantMessage.parts.push({
|
||||
type: "text",
|
||||
@@ -375,7 +371,7 @@ export const toModelMessagesEffect = Effect.fnUntraced(function* (
|
||||
assistantMessage.parts.push({
|
||||
type: "reasoning",
|
||||
text: part.text,
|
||||
...(differentModel ? {} : { providerMetadata: part.metadata }),
|
||||
providerMetadata: part.metadata,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,21 +101,6 @@ export const TaskTool = Tool.define(
|
||||
)
|
||||
}
|
||||
|
||||
const parent = yield* sessions.get(ctx.sessionID)
|
||||
let current = parent
|
||||
let depth = 0
|
||||
while (current.parentID) {
|
||||
depth++
|
||||
current = yield* sessions.get(current.parentID)
|
||||
}
|
||||
if (depth >= (cfg.subagent_depth ?? 1)) {
|
||||
return yield* Effect.fail(
|
||||
new Error(
|
||||
`Subagent depth limit reached (${cfg.subagent_depth ?? 1}). Increase "subagent_depth" to allow nested subagents.`,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (!ctx.extra?.bypassAgentCheck) {
|
||||
yield* ctx.ask({
|
||||
permission: id,
|
||||
@@ -136,6 +121,7 @@ export const TaskTool = Tool.define(
|
||||
const session = params.task_id
|
||||
? yield* sessions.get(SessionID.make(params.task_id)).pipe(Effect.catchCause(() => Effect.succeed(undefined)))
|
||||
: undefined
|
||||
const parent = yield* sessions.get(ctx.sessionID)
|
||||
const childPermission = deriveSubagentSessionPermission({
|
||||
parentSessionPermission: parent.permission ?? [],
|
||||
subagent: next,
|
||||
|
||||
@@ -642,42 +642,6 @@ test("direct subagent panel renders active subagents", async () => {
|
||||
}
|
||||
})
|
||||
|
||||
test("direct subagent panel closes when moving up from the first item", async () => {
|
||||
const [tabs] = createSignal([
|
||||
subagent({ sessionID: "s-1", label: "Explore", description: "Inspect auth flow" }),
|
||||
subagent({ sessionID: "s-2", label: "General", description: "Write migration plan" }),
|
||||
])
|
||||
const [current] = createSignal<string | undefined>()
|
||||
let closed = 0
|
||||
|
||||
const app = await testRender(
|
||||
() => (
|
||||
<box width={100} height={RUN_SUBAGENT_PANEL_ROWS}>
|
||||
<RunSubagentSelectBody
|
||||
theme={() => RUN_THEME_FALLBACK.footer}
|
||||
tabs={tabs}
|
||||
current={current}
|
||||
onClose={() => closed++}
|
||||
onSelect={() => {}}
|
||||
/>
|
||||
</box>
|
||||
),
|
||||
{ width: 100, height: RUN_SUBAGENT_PANEL_ROWS },
|
||||
)
|
||||
|
||||
try {
|
||||
await app.renderOnce()
|
||||
app.mockInput.pressKey("ARROW_DOWN")
|
||||
app.mockInput.pressKey("ARROW_UP")
|
||||
expect(closed).toBe(0)
|
||||
|
||||
app.mockInput.pressKey("ARROW_UP")
|
||||
expect(closed).toBe(1)
|
||||
} finally {
|
||||
app.renderer.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
test("direct queued prompt panel renders pending prompt actions", async () => {
|
||||
const [prompts] = createSignal([
|
||||
{ messageID: "m-1", partID: "p-1", prompt: { text: "fix the auth test", parts: [] } },
|
||||
|
||||
@@ -332,39 +332,6 @@ describe("session.llm-native.request", () => {
|
||||
])
|
||||
})
|
||||
|
||||
it.effect("preserves OpenAI-compatible reasoning fields through the native adapter", () =>
|
||||
Effect.gen(function* () {
|
||||
const compatible = {
|
||||
...baseModel,
|
||||
providerID: ProviderV2.ID.make("moonshotai"),
|
||||
api: {
|
||||
id: "kimi-k2.5",
|
||||
url: "https://api.moonshot.test/v1",
|
||||
npm: "@ai-sdk/openai-compatible",
|
||||
},
|
||||
capabilities: {
|
||||
...baseModel.capabilities,
|
||||
interleaved: { field: "reasoning_content" as const },
|
||||
},
|
||||
}
|
||||
const prepared = yield* prepareNativeRequest({
|
||||
model: compatible,
|
||||
apiKey: "test-key",
|
||||
messages: [
|
||||
{
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text: "answer" }],
|
||||
providerOptions: { openaiCompatible: { reasoning_content: "thinking" } },
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
expect(prepared.body).toMatchObject({
|
||||
messages: [{ role: "assistant", content: "answer", reasoning_content: "thinking" }],
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
test("selects native request routes for provider packages", () => {
|
||||
const openai = LLMNative.model({
|
||||
model: { ...baseModel, api: { ...baseModel.api, url: "", npm: "@ai-sdk/openai" } },
|
||||
|
||||
@@ -684,42 +684,6 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
])
|
||||
})
|
||||
|
||||
test("preserves foreign reasoning for OpenAI-compatible reasoning fields", async () => {
|
||||
const assistantID = "m-assistant"
|
||||
const compatible = {
|
||||
...model,
|
||||
api: { ...model.api, npm: "@ai-sdk/openai-compatible" },
|
||||
capabilities: { ...model.capabilities, reasoning: true, interleaved: { field: "reasoning_content" } },
|
||||
} satisfies Provider.Model
|
||||
const input: SessionV1.WithParts[] = [
|
||||
{
|
||||
info: assistantInfo(assistantID, "m-user", undefined, { providerID: "other", modelID: "other" }),
|
||||
parts: [
|
||||
{
|
||||
...basePart(assistantID, "a1"),
|
||||
type: "reasoning",
|
||||
text: "thinking",
|
||||
metadata: { anthropic: { signature: "foreign" } },
|
||||
time: { start: 0 },
|
||||
},
|
||||
{
|
||||
...basePart(assistantID, "a2"),
|
||||
type: "text",
|
||||
text: "answer",
|
||||
},
|
||||
] as SessionV1.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
expect(ProviderTransform.message(await MessageV2.toModelMessages(input, compatible), compatible, {})).toEqual([
|
||||
{
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text: "answer" }],
|
||||
providerOptions: { openaiCompatible: { reasoning_content: "thinking" } },
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
test("replaces compacted tool output with placeholder", async () => {
|
||||
const userID = "m-user"
|
||||
const assistantID = "m-assistant"
|
||||
|
||||
@@ -388,86 +388,6 @@ describe("tool.task", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.instance("prevents subagents from launching subagents by default", () =>
|
||||
Effect.gen(function* () {
|
||||
const sessions = yield* Session.Service
|
||||
const { chat, assistant } = yield* seed()
|
||||
const child = yield* sessions.create({ parentID: chat.id, title: "child" })
|
||||
const nestedAssistant = yield* sessions.updateMessage({
|
||||
...assistant,
|
||||
id: MessageID.ascending(),
|
||||
parentID: MessageID.ascending(),
|
||||
sessionID: child.id,
|
||||
})
|
||||
const tool = yield* TaskTool
|
||||
const def = yield* tool.init()
|
||||
let asked = false
|
||||
|
||||
const exit = yield* def
|
||||
.execute(
|
||||
{
|
||||
description: "inspect bug",
|
||||
prompt: "look into the cache key path",
|
||||
subagent_type: "general",
|
||||
},
|
||||
{
|
||||
sessionID: child.id,
|
||||
messageID: nestedAssistant.id,
|
||||
agent: "general",
|
||||
abort: new AbortController().signal,
|
||||
extra: { promptOps: stubOps() },
|
||||
messages: [],
|
||||
metadata: () => Effect.void,
|
||||
ask: () => Effect.sync(() => (asked = true)),
|
||||
},
|
||||
)
|
||||
.pipe(Effect.exit)
|
||||
|
||||
expect(Exit.isFailure(exit)).toBe(true)
|
||||
expect(asked).toBe(false)
|
||||
expect(yield* sessions.children(child.id)).toHaveLength(0)
|
||||
}),
|
||||
)
|
||||
|
||||
it.instance(
|
||||
"allows nested subagents up to the configured depth",
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
const sessions = yield* Session.Service
|
||||
const { chat, assistant } = yield* seed()
|
||||
const child = yield* sessions.create({ parentID: chat.id, title: "child" })
|
||||
const nestedAssistant = yield* sessions.updateMessage({
|
||||
...assistant,
|
||||
id: MessageID.ascending(),
|
||||
parentID: MessageID.ascending(),
|
||||
sessionID: child.id,
|
||||
})
|
||||
const tool = yield* TaskTool
|
||||
const def = yield* tool.init()
|
||||
|
||||
const result = yield* def.execute(
|
||||
{
|
||||
description: "inspect bug",
|
||||
prompt: "look into the cache key path",
|
||||
subagent_type: "general",
|
||||
},
|
||||
{
|
||||
sessionID: child.id,
|
||||
messageID: nestedAssistant.id,
|
||||
agent: "general",
|
||||
abort: new AbortController().signal,
|
||||
extra: { promptOps: stubOps() },
|
||||
messages: [],
|
||||
metadata: () => Effect.void,
|
||||
ask: () => Effect.void,
|
||||
},
|
||||
)
|
||||
|
||||
expect((yield* sessions.get(result.metadata.sessionId)).parentID).toBe(child.id)
|
||||
}),
|
||||
{ config: { subagent_depth: 2 } },
|
||||
)
|
||||
|
||||
it.instance(
|
||||
"execute shapes child permissions for task, todowrite, and primary tools",
|
||||
() =>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/plugin",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/sdk",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -1928,7 +1928,6 @@ export type Config = {
|
||||
model?: string
|
||||
small_model?: string
|
||||
default_agent?: string
|
||||
subagent_depth?: number
|
||||
username?: string
|
||||
mode?: {
|
||||
build?: AgentConfig
|
||||
|
||||
@@ -21263,10 +21263,6 @@
|
||||
"default_agent": {
|
||||
"type": "string"
|
||||
},
|
||||
"subagent_depth": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/server",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/session-ui",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/slack",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/stats-app",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/stats-core",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/stats-server",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/tui",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@opencode-ai/ui",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@opencode-ai/web",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",
|
||||
|
||||
@@ -538,21 +538,6 @@ This setting applies across all interfaces: TUI, CLI (`opencode run`), desktop a
|
||||
|
||||
---
|
||||
|
||||
### Subagent depth
|
||||
|
||||
You can control how deeply subagents can invoke other subagents using the `subagent_depth` option.
|
||||
|
||||
```json title="opencode.json"
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"subagent_depth": 2
|
||||
}
|
||||
```
|
||||
|
||||
The default is `1`, which allows primary agents to launch subagents but prevents those subagents from launching additional subagents. Set it to `2` to allow one additional level of nested subagents, or `0` to prevent all subagent launches.
|
||||
|
||||
---
|
||||
|
||||
### Sharing
|
||||
|
||||
You can configure the [share](/docs/share) feature through the `share` option.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "opencode",
|
||||
"displayName": "opencode",
|
||||
"description": "opencode for VS Code",
|
||||
"version": "1.18.2",
|
||||
"version": "1.18.1",
|
||||
"publisher": "sst-dev",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ SessionExecution.resume(sessionID)
|
||||
|
||||
The local runner issues one explicit `llm.stream(request)` per provider turn, projects each complete local tool call durably before eagerly starting its structured child execution, awaits every started tool fiber after provider-stream closure, and reloads projected history once before continuation. Promoting any new user input resets the selected agent's configured provider-turn allowance; multiple steers promoted at one boundary reset it once. Tool settlement events carry the owning assistant message ID because provider-local call IDs may repeat across turns. Before assembling a provider request, the runner durably fails any local tool still projected as `running` from a previous process with `Tool execution interrupted`; abandoned side effects are never silently replayed.
|
||||
|
||||
Projected hosted tools preserve call-side and settlement-side provider metadata separately so settlement and interruption recovery cannot erase continuation identifiers. Provider-native metadata replays only while the historical assistant model matches the selected continuation model. After a model switch, visible reasoning remains canonical without opaque metadata until the target protocol either replays it in a compatible reasoning field or lowers unsigned reasoning to ordinary assistant text.
|
||||
Projected hosted tools preserve call-side and settlement-side provider metadata separately so settlement and interruption recovery cannot erase continuation identifiers. Provider-native reasoning and provider metadata replay only while the historical assistant model matches the selected continuation model; after a model switch, visible reasoning text remains ordinary assistant text and provider-native metadata is omitted.
|
||||
|
||||
## Context Epochs
|
||||
|
||||
|
||||
Reference in New Issue
Block a user