merge origin/dev into fix/stale-running-session-ui

pull/17593/head
Shoubhit Dash 2026-03-16 21:02:22 +05:30
commit c19cbccf06
34 changed files with 270 additions and 146 deletions

View File

@ -41,5 +41,13 @@ runs:
shell: bash
- name: Install dependencies
run: bun install
run: |
# Workaround for patched peer variants
# e.g. ./patches/ for standard-openapi
# https://github.com/oven-sh/bun/issues/28147
if [ "$RUNNER_OS" = "Windows" ]; then
bun install --linker hoisted
else
bun install
fi
shell: bash

View File

@ -26,7 +26,7 @@
},
"packages/app": {
"name": "@opencode-ai/app",
"version": "1.2.26",
"version": "1.2.27",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/sdk": "workspace:*",
@ -77,7 +77,7 @@
},
"packages/console/app": {
"name": "@opencode-ai/console-app",
"version": "1.2.26",
"version": "1.2.27",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@ibm/plex": "6.4.1",
@ -111,7 +111,7 @@
},
"packages/console/core": {
"name": "@opencode-ai/console-core",
"version": "1.2.26",
"version": "1.2.27",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"@jsx-email/render": "1.1.1",
@ -138,7 +138,7 @@
},
"packages/console/function": {
"name": "@opencode-ai/console-function",
"version": "1.2.26",
"version": "1.2.27",
"dependencies": {
"@ai-sdk/anthropic": "2.0.0",
"@ai-sdk/openai": "2.0.2",
@ -162,7 +162,7 @@
},
"packages/console/mail": {
"name": "@opencode-ai/console-mail",
"version": "1.2.26",
"version": "1.2.27",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
@ -186,7 +186,7 @@
},
"packages/desktop": {
"name": "@opencode-ai/desktop",
"version": "1.2.26",
"version": "1.2.27",
"dependencies": {
"@opencode-ai/app": "workspace:*",
"@opencode-ai/ui": "workspace:*",
@ -219,7 +219,7 @@
},
"packages/desktop-electron": {
"name": "@opencode-ai/desktop-electron",
"version": "1.2.26",
"version": "1.2.27",
"dependencies": {
"@opencode-ai/app": "workspace:*",
"@opencode-ai/ui": "workspace:*",
@ -250,7 +250,7 @@
},
"packages/enterprise": {
"name": "@opencode-ai/enterprise",
"version": "1.2.26",
"version": "1.2.27",
"dependencies": {
"@opencode-ai/ui": "workspace:*",
"@opencode-ai/util": "workspace:*",
@ -279,7 +279,7 @@
},
"packages/function": {
"name": "@opencode-ai/function",
"version": "1.2.26",
"version": "1.2.27",
"dependencies": {
"@octokit/auth-app": "8.0.1",
"@octokit/rest": "catalog:",
@ -295,7 +295,7 @@
},
"packages/opencode": {
"name": "opencode",
"version": "1.2.26",
"version": "1.2.27",
"bin": {
"opencode": "./bin/opencode",
},
@ -416,7 +416,7 @@
},
"packages/plugin": {
"name": "@opencode-ai/plugin",
"version": "1.2.26",
"version": "1.2.27",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"zod": "catalog:",
@ -440,7 +440,7 @@
},
"packages/sdk/js": {
"name": "@opencode-ai/sdk",
"version": "1.2.26",
"version": "1.2.27",
"devDependencies": {
"@hey-api/openapi-ts": "0.90.10",
"@tsconfig/node22": "catalog:",
@ -451,7 +451,7 @@
},
"packages/slack": {
"name": "@opencode-ai/slack",
"version": "1.2.26",
"version": "1.2.27",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"@slack/bolt": "^3.17.1",
@ -486,7 +486,7 @@
},
"packages/ui": {
"name": "@opencode-ai/ui",
"version": "1.2.26",
"version": "1.2.27",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/sdk": "workspace:*",
@ -532,7 +532,7 @@
},
"packages/util": {
"name": "@opencode-ai/util",
"version": "1.2.26",
"version": "1.2.27",
"dependencies": {
"zod": "catalog:",
},
@ -543,7 +543,7 @@
},
"packages/web": {
"name": "@opencode-ai/web",
"version": "1.2.26",
"version": "1.2.27",
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1",

View File

@ -349,3 +349,25 @@ test("session model restore across workspaces", async ({ page, withProject }) =>
await waitFooter(page, firstState)
})
})
test("variant preserved when switching agent modes", async ({ page, withProject }) => {
await page.setViewportSize({ width: 1440, height: 900 })
await withProject(async ({ directory, gotoSession }) => {
await gotoSession()
await ensureVariant(page, directory)
const updated = await chooseDifferentVariant(page)
const available = await agents(page)
const other = available.find((name) => name !== updated.agent)
test.skip(!other, "only one agent available")
if (!other) return
await choose(page, promptAgentSelector, other)
await waitFooter(page, { agent: other, variant: updated.variant })
await choose(page, promptAgentSelector, updated.agent)
await waitFooter(page, { agent: updated.agent, variant: updated.variant })
})
})

View File

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

View File

@ -326,7 +326,7 @@ export function SessionHeader() {
<div class="flex h-[24px] box-border items-center rounded-md border border-border-weak-base bg-surface-panel overflow-hidden">
<Button
variant="ghost"
class="rounded-none h-full py-0 pr-1.5 pl-px gap-1.5 border-none shadow-none disabled:!cursor-default"
class="rounded-none h-full px-0.5 border-none shadow-none disabled:!cursor-default"
classList={{
"bg-surface-raised-base-active": opening(),
}}
@ -339,7 +339,6 @@ export function SessionHeader() {
<Spinner class="size-3.5" style={{ color: tint() ?? "var(--icon-base)" }} />
</Show>
</div>
<span class="text-12-regular text-text-strong">{language.t("common.open")}</span>
</Button>
<DropdownMenu
gutter={4}

View File

@ -192,10 +192,11 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
model: item.model,
variant: item.variant ?? null,
})
const prev = scope()
const next = {
agent: item.name,
model: item.model,
variant: item.variant,
model: item.model ?? prev?.model,
variant: item.variant ?? prev?.variant,
} satisfies State
const session = id()
if (session) {

View File

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

View File

@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/console-core",
"version": "1.2.26",
"version": "1.2.27",
"private": true,
"type": "module",
"license": "MIT",

View File

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

View File

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

View File

@ -1,7 +1,7 @@
{
"name": "@opencode-ai/desktop-electron",
"private": true,
"version": "1.2.26",
"version": "1.2.27",
"type": "module",
"license": "MIT",
"homepage": "https://opencode.ai",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -11,6 +11,11 @@ const openBrowser = (url: string) => Effect.promise(() => open(url).catch(() =>
const println = (msg: string) => Effect.sync(() => UI.println(msg))
const isActiveOrgChoice = (
active: Option.Option<{ id: AccountID; active_org_id: OrgID | null }>,
choice: { accountID: AccountID; orgID: OrgID },
) => Option.isSome(active) && active.value.id === choice.accountID && active.value.active_org_id === choice.orgID
const loginEffect = Effect.fn("login")(function* (url: string) {
const service = yield* AccountService
@ -99,11 +104,10 @@ const switchEffect = Effect.fn("switch")(function* () {
if (groups.length === 0) return yield* println("Not logged in")
const active = yield* service.active()
const activeOrgID = Option.flatMap(active, (a) => Option.fromNullishOr(a.active_org_id))
const opts = groups.flatMap((group) =>
group.orgs.map((org) => {
const isActive = Option.isSome(activeOrgID) && activeOrgID.value === org.id
const isActive = isActiveOrgChoice(active, { accountID: group.account.id, orgID: org.id })
return {
value: { orgID: org.id, accountID: group.account.id, label: org.name },
label: isActive
@ -132,11 +136,10 @@ const orgsEffect = Effect.fn("orgs")(function* () {
if (!groups.some((group) => group.orgs.length > 0)) return yield* println("No orgs found")
const active = yield* service.active()
const activeOrgID = Option.flatMap(active, (a) => Option.fromNullishOr(a.active_org_id))
for (const group of groups) {
for (const org of group.orgs) {
const isActive = Option.isSome(activeOrgID) && activeOrgID.value === org.id
const isActive = isActiveOrgChoice(active, { accountID: group.account.id, orgID: org.id })
const dot = isActive ? UI.Style.TEXT_SUCCESS + "●" + UI.Style.TEXT_NORMAL : " "
const name = isActive ? UI.Style.TEXT_HIGHLIGHT_BOLD + org.name + UI.Style.TEXT_NORMAL : org.name
const email = UI.Style.TEXT_DIM + group.account.email + UI.Style.TEXT_NORMAL

View File

@ -47,7 +47,7 @@ export namespace Vcs {
log.info("initialized", { branch: current })
const unsubscribe = Bus.subscribe(FileWatcher.Event.Updated, async (evt) => {
if (evt.properties.file.endsWith("HEAD")) return
if (!evt.properties.file.endsWith("HEAD")) return
const next = await currentBranch()
if (next !== current) {
log.info("branch changed", { from: current, to: next })

View File

@ -167,7 +167,8 @@ export namespace ProviderError {
export function parseAPICallError(input: { providerID: ProviderID; error: APICallError }): ParsedAPICallError {
const m = message(input.providerID, input.error)
if (isOverflow(m) || input.error.statusCode === 413) {
const body = json(input.error.responseBody)
if (isOverflow(m) || input.error.statusCode === 413 || body?.error?.code === "context_length_exceeded") {
return {
type: "context_overflow",
message: m,

View File

@ -32,6 +32,7 @@ export namespace LLM {
sessionID: string
model: Provider.Model
agent: Agent.Info
permission?: PermissionNext.Ruleset
system: string[]
abort: AbortSignal
messages: ModelMessage[]
@ -255,8 +256,11 @@ export namespace LLM {
})
}
async function resolveTools(input: Pick<StreamInput, "tools" | "agent" | "user">) {
const disabled = PermissionNext.disabled(Object.keys(input.tools), input.agent.permission)
async function resolveTools(input: Pick<StreamInput, "tools" | "agent" | "permission" | "user">) {
const disabled = PermissionNext.disabled(
Object.keys(input.tools),
PermissionNext.merge(input.agent.permission, input.permission ?? []),
)
for (const tool of Object.keys(input.tools)) {
if (input.user.tools?.[tool] === false || disabled.has(tool)) {
delete input.tools[tool]

View File

@ -664,6 +664,7 @@ export namespace SessionPrompt {
return processor.process({
user: lastUser,
agent,
permission: session.permission,
abort,
sessionID,
system,

View File

@ -1,6 +1,7 @@
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test"
import path from "path"
import type { ModelMessage } from "ai"
import { tool, type ModelMessage } from "ai"
import z from "zod"
import { LLM } from "../../src/session/llm"
import { Global } from "../../src/global"
import { Instance } from "../../src/project/instance"
@ -325,6 +326,95 @@ describe("session.llm.stream", () => {
})
})
test("keeps tools enabled by prompt permissions", async () => {
const server = state.server
if (!server) {
throw new Error("Server not initialized")
}
const providerID = "alibaba"
const modelID = "qwen-plus"
const fixture = await loadFixture(providerID, modelID)
const model = fixture.model
const request = waitRequest(
"/chat/completions",
new Response(createChatStream("Hello"), {
status: 200,
headers: { "Content-Type": "text/event-stream" },
}),
)
await using tmp = await tmpdir({
init: async (dir) => {
await Bun.write(
path.join(dir, "opencode.json"),
JSON.stringify({
$schema: "https://opencode.ai/config.json",
enabled_providers: [providerID],
provider: {
[providerID]: {
options: {
apiKey: "test-key",
baseURL: `${server.url.origin}/v1`,
},
},
},
}),
)
},
})
await Instance.provide({
directory: tmp.path,
fn: async () => {
const resolved = await Provider.getModel(ProviderID.make(providerID), ModelID.make(model.id))
const sessionID = SessionID.make("session-test-tools")
const agent = {
name: "test",
mode: "primary",
options: {},
permission: [{ permission: "question", pattern: "*", action: "deny" }],
} satisfies Agent.Info
const user = {
id: MessageID.make("user-tools"),
sessionID,
role: "user",
time: { created: Date.now() },
agent: agent.name,
model: { providerID: ProviderID.make(providerID), modelID: resolved.id },
tools: { question: true },
} satisfies MessageV2.User
const stream = await LLM.stream({
user,
sessionID,
model: resolved,
agent,
permission: [{ permission: "question", pattern: "*", action: "allow" }],
system: ["You are a helpful assistant."],
abort: new AbortController().signal,
messages: [{ role: "user", content: "Hello" }],
tools: {
question: tool({
description: "Ask a question",
inputSchema: z.object({}),
execute: async () => ({ output: "" }),
}),
},
})
for await (const _ of stream.fullStream) {
}
const capture = await request
const tools = capture.body.tools as Array<{ function?: { name?: string } }> | undefined
expect(tools?.some((item) => item.function?.name === "question")).toBe(true)
},
})
})
test("sends responses API payload for OpenAI models", async () => {
const server = state.server
if (!server) {

View File

@ -869,6 +869,26 @@ describe("session.message-v2.fromError", () => {
})
})
test("detects context overflow from context_length_exceeded code in response body", () => {
const error = new APICallError({
message: "Request failed",
url: "https://example.com",
requestBodyValues: {},
statusCode: 422,
responseHeaders: { "content-type": "application/json" },
responseBody: JSON.stringify({
error: {
message: "Some message",
type: "invalid_request_error",
code: "context_length_exceeded",
},
}),
isRetryable: false,
})
const result = MessageV2.fromError(error, { providerID })
expect(MessageV2.ContextOverflowError.isInstance(result)).toBe(true)
})
test("does not classify 429 no body as context overflow", () => {
const result = MessageV2.fromError(
new APICallError({

View File

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

View File

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

View File

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

View File

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

View File

@ -1050,18 +1050,8 @@
line-height: var(--line-height-large);
color: var(--text-base);
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
[data-slot="question-option"][data-custom="true"] {
[data-slot="option-description"] {
overflow: visible;
text-overflow: clip;
white-space: normal;
overflow-wrap: anywhere;
}
overflow-wrap: anywhere;
white-space: normal;
}
[data-slot="question-custom"] {

View File

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

View File

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

View File

@ -49,6 +49,7 @@ You can also check out [awesome-opencode](https://github.com/awesome-opencode/aw
| [opencode-workspace](https://github.com/kdcokenny/opencode-workspace) | Bundled multi-agent orchestration harness 16 components, one install |
| [opencode-worktree](https://github.com/kdcokenny/opencode-worktree) | Zero-friction git worktrees for OpenCode |
| [opencode-sentry-monitor](https://github.com/stolinski/opencode-sentry-monitor) | Trace and debug your AI agents with Sentry AI Monitoring |
| [opencode-firecrawl](https://github.com/firecrawl/opencode-firecrawl) | Web scraping, crawling, and search via the Firecrawl CLI |
---

View File

@ -1,23 +1,23 @@
---
title: Introducción
description: Comience con OpenCode.
description: Comience a usar OpenCode.
---
import { Tabs, TabItem } from "@astrojs/starlight/components"
import config from "../../../../config.mjs"
export const console = config.console
[**OpenCode**](/) es un agente de codificación de IA de código abierto. Está disponible como interfaz basada en terminal, aplicación de escritorio o extensión IDE.
[**OpenCode**](/) es un agente de codigo de IA de código abierto. Está disponible como interfaz basada en terminal, aplicación de escritorio o extensión IDE.
![OpenCode TUI con el tema opencode](../../../assets/lander/screenshot.png)
Empecemos.
Comencemos.
---
#### Requisitos previos
Para usar OpenCode en su terminal, necesitará:
Para usar OpenCode en la terminal, necesitará:
1. Un emulador de terminal moderno como:
- [WezTerm](https://wezterm.org), multiplataforma
@ -25,7 +25,7 @@ Para usar OpenCode en su terminal, necesitará:
- [Ghostty](https://ghostty.org), Linux y macOS
- [Kitty](https://sw.kovidgoyal.net/kitty/), Linux y macOS
2. Claves API para los LLM proveedores que desea utilizar.
2. Claves de API de los proveedores de LLM que quiera usar.
---
@ -37,7 +37,7 @@ La forma más sencilla de instalar OpenCode es mediante el script de instalació
curl -fsSL https://opencode.ai/install | bash
```
También puedes instalarlo con los siguientes comandos:
También puedes instalarlo con alguno de los siguientes métodos:
- **Usando Node.js**
@ -91,7 +91,7 @@ También puedes instalarlo con los siguientes comandos:
#### Windows
:::tip[Recomendado: Usar WSL]
Para obtener la mejor experiencia en Windows, recomendamos utilizar [Windows Subsystem for Linux (WSL)](/docs/windows-wsl). Proporciona un mejor rendimiento y compatibilidad total con las funciones de OpenCode.
Para obtener la mejor experiencia en Windows, recomendamos utilizar [Windows Subsystem for Linux (WSL)](/docs/windows-wsl). Ofrece mejor rendimiento y compatibilidad total con las funciones de OpenCode.
:::
- **Usando Chocolatey**
@ -124,28 +124,28 @@ Para obtener la mejor experiencia en Windows, recomendamos utilizar [Windows Sub
docker run -it --rm ghcr.io/anomalyco/opencode
```
Actualmente se encuentra en progreso el soporte para instalar OpenCode en Windows usando Bun.
El soporte para instalar OpenCode en Windows usando Bun todavía está en desarrollo.
También puede obtener el binario de [Versiones](https://github.com/anomalyco/opencode/releases).
También puede obtener el binario desde [Versiones](https://github.com/anomalyco/opencode/releases).
---
## Configuración
Con OpenCode puedes usar cualquier proveedor LLM configurando sus claves API.
Con OpenCode, puede usar cualquier proveedor de LLM configurando sus claves de API.
Si es nuevo en el uso de proveedores LLM, le recomendamos usar [OpenCode Zen](/docs/zen).
Es una lista seleccionada de modelos que han sido probados y verificados por el equipo de OpenCode.
Si es nuevo en el uso de proveedores de LLM, le recomendamos usar [OpenCode Zen](/docs/zen).
Es una selección de modelos probados y verificados por el equipo de OpenCode.
1. Ejecute el comando `/connect` en TUI, seleccione opencode y diríjase a [opencode.ai/auth](https://opencode.ai/auth).
1. Ejecute el comando `/connect` en la TUI, seleccione opencode y diríjase a [opencode.ai/auth](https://opencode.ai/auth).
```txt
/connect
```
2. Inicie sesión, agregue sus datos de facturación y copie su clave API.
2. Inicie sesión, agregue sus datos de facturación y copie su clave de API.
3. Pega tu clave API.
3. Pega tu clave de API.
```txt
┌ API key
@ -154,50 +154,45 @@ Es una lista seleccionada de modelos que han sido probados y verificados por el
└ enter
```
Alternativamente, puede seleccionar uno de los otros proveedores. [Más información](/docs/providers#directory).
También puede seleccionar otro proveedor. [Más información](/docs/providers#directory).
---
## Inicializar
Ahora que ha configurado un proveedor, puede navegar a un proyecto que
quieres trabajar.
Ahora que ya configuró un proveedor, vaya al proyecto en el que quiera trabajar.
```bash
cd /path/to/project
```
Y ejecute OpenCode.
Luego, ejecute OpenCode.
```bash
opencode
```
A continuación, inicialice OpenCode para el proyecto ejecutando el siguiente comando.
A continuación, inicialice OpenCode para el proyecto con el siguiente comando:
```bash frame="none"
/init
```
Esto hará que OpenCode analice su proyecto y cree un archivo `AGENTS.md` en
la raíz del proyecto.
OpenCode analizará su proyecto y creará un archivo AGENTS.md en la raíz.
:::tip
Debes enviar el archivo `AGENTS.md` de tu proyecto a Git.
Asegúrese de versionar en Git el archivo AGENTS.md de su proyecto.
:::
Esto ayuda a OpenCode a comprender la estructura del proyecto y los patrones de codificación.
usado.
Esto ayuda a OpenCode a comprender la estructura del proyecto y los patrones de código que se usan en él.
---
## Usar
Ahora está listo para usar OpenCode para trabajar en su proyecto. No dudes en preguntarle
¡cualquier cosa!
Ahora ya está listo para usar OpenCode en su proyecto. Puede pedirle desde explicaciones del código hasta cambios concretos.
Si es nuevo en el uso de un agente de codificación de IA, aquí hay algunos ejemplos que podrían
ayuda.
Si es la primera vez que usa un agente de codigo con IA, estos ejemplos pueden servirle como punto de partida.
---
@ -206,126 +201,117 @@ ayuda.
Puede pedirle a OpenCode que le explique el código base.
:::tip
Utilice la tecla `@` para realizar una búsqueda aproximada de archivos en el proyecto.
Utilice la tecla `@` para realizar una búsqueda aproximada de archivos dentro del proyecto.
:::
```txt frame="none" "@packages/functions/src/api/index.ts"
How is authentication handled in @packages/functions/src/api/index.ts
¿Cómo se maneja la autenticación en @packages/functions/src/api/index.ts
```
Esto es útil si hay una parte del código base en la que no trabajaste.
Esto resulta útil cuando hay una parte del código base en la que usted no ha trabajado.
---
### Agregar funciones
### Agregar funcionalidades
Puede pedirle a OpenCode que agregue nuevas funciones a su proyecto. Aunque primero recomendamos pedirle que cree un plan.
Puede pedirle a OpenCode que agregue nuevas funcionalidades a su proyecto. Aun así, primero recomendamos pedirle que cree un plan.
1. **Crea un plan**
1. **Crear un plan**
OpenCode tiene un _Modo Plan_ que desactiva su capacidad para realizar cambios y
en su lugar, sugiera _cómo_ implementará la función.
OpenCode tiene un modo Plan que desactiva temporalmente su capacidad de hacer cambios y, en su lugar, propone _cómo_ implementará la funcionalidad.
Cambie a él usando la tecla **Tab**. Verás un indicador para esto en la esquina inferior derecha.
Cambie a este modo con la tecla **Tab.** Verá un indicador en la esquina inferior derecha.
```bash frame="none" title="Switch to Plan mode"
<TAB>
```
Ahora describamos lo que queremos que haga.
Ahora describa lo que quiere que haga.
```txt frame="none"
When a user deletes a note, we'd like to flag it as deleted in the database.
Then create a screen that shows all the recently deleted notes.
From this screen, the user can undelete a note or permanently delete it.
Cuando un usuario elimine una nota, queremos marcarla como eliminada en la base de datos.
Luego, cree una pantalla que muestre todas las notas eliminadas recientemente.
Desde esa pantalla, el usuario podrá restaurar una nota o eliminarla de forma permanente.
```
Quiere darle a OpenCode suficientes detalles para entender lo que quiere. ayuda
hablar con él como si estuviera hablando con un desarrollador junior de su equipo.
Procure darle a OpenCode suficiente contexto para que entienda exactamente lo que necesita. Ayuda hablarle como si estuviera hablando con un desarrollador junior de su equipo.
:::tip
Dale a OpenCode mucho contexto y ejemplos para ayudarlo a comprender lo que
desear.
Déle a OpenCode todo el contexto y los ejemplos que pueda para ayudarle a comprender lo que desea.
:::
2. **Repetir el plan**
2. **Iterar sobre el plan**
Una vez que le proporcione un plan, puede enviarle comentarios o agregar más detalles.
Una vez que OpenCode le proponga un plan, puede darle comentarios o agregar más detalles.
```txt frame="none"
We'd like to design this new screen using a design I've used before.
[Image #1] Take a look at this image and use it as a reference.
Queremos diseñar esta nueva pantalla usando un diseño que ya hemos usado antes.
[Imagen #1] Revise esta imagen y úsela como referencia.
```
:::tip
Arrastre y suelte imágenes en la terminal para agregarlas al mensaje.
:::
OpenCode puede escanear cualquier imagen que le proporcione y agregarla al mensaje. Puede
Haga esto arrastrando y soltando una imagen en la terminal.
OpenCode puede analizar cualquier imagen que usted le proporcione y añadirla al contexto del mensaje. Puede hacerlo arrastrando y soltando una imagen en la terminal.
3. **Crea la función**
3. **Implementar la funcionalidad**
Una vez que se sienta cómodo con el plan, vuelva al _Modo Build_
presionando la tecla **Tab** nuevamente.
Cuando esté conforme con el plan, vuelva al modo _Build_ presionando de nuevo la tecla Tab.
```bash frame="none"
<TAB>
```
Y pidiéndole que haga los cambios.
Luego, pídale que haga los cambios.
```bash frame="none"
Sounds good! Go ahead and make the changes.
Perfecto. Continúe y realice los cambios.
```
---
### Realizar cambios
Para cambios más sencillos, puede pedirle a OpenCode que lo construya directamente.
sin tener que revisar el plan primero.
Para cambios más sencillos, puede pedirle a OpenCode que los implemente directamente, sin revisar antes un plan.
```txt frame="none" "@packages/functions/src/settings.ts" "@packages/functions/src/notes.ts"
We need to add authentication to the /settings route. Take a look at how this is
handled in the /notes route in @packages/functions/src/notes.ts and implement
the same logic in @packages/functions/src/settings.ts
Necesitamos agregar autenticación a la ruta /settings. Revise cómo se maneja esto
en la ruta /notes en @packages/functions/src/notes.ts e implemente
la misma lógica en @packages/functions/src/settings.ts.
```
Desea asegurarse de proporcionar una buena cantidad de detalles para que OpenCode tome la decisión correcta.
cambios.
Procure dar suficientes detalles para que OpenCode pueda tomar las decisiones correctas al hacer los cambios
---
### Deshacer cambios
Digamos que le pides a OpenCode que haga algunos cambios.
Supongamos que le pide a OpenCode que haga algunos cambios.
```txt frame="none" "@packages/functions/src/api/index.ts"
Can you refactor the function in @packages/functions/src/api/index.ts?
¿Puede refactorizar la función en @packages/functions/src/api/index.ts?
```
Pero te das cuenta de que no es lo que querías. Puedes **deshacer** los cambios
usando el comando `/undo`.
Pero luego se da cuenta de que no era lo que quería. Puede **deshacer** los cambios usando el comando `/undo`.
```bash frame="none"
/undo
```
OpenCode ahora revertirá los cambios que realizó y mostrará su mensaje original
de nuevo.
OpenCode revertirá los cambios que hizo y volverá a mostrar su mensaje original.
```txt frame="none" "@packages/functions/src/api/index.ts"
Can you refactor the function in @packages/functions/src/api/index.ts?
¿Puede refactorizar la función en @packages/functions/src/api/index.ts?
```
Desde aquí puedes modificar el mensaje y pedirle a OpenCode que vuelva a intentarlo.
Desde ahí, puede modificar el mensaje y pedirle a OpenCode que lo intente de nuevo.
:::tip
Puede ejecutar `/undo` varias veces para deshacer varios cambios.
:::
O **puedes rehacer** los cambios usando el comando `/redo`.
También puede rehacer los cambios usando el comando `/redo.`
```bash frame="none"
/redo
@ -335,7 +321,7 @@ O **puedes rehacer** los cambios usando el comando `/redo`.
## Compartir
Las conversaciones que tengas con OpenCode pueden ser [compartidas con tu
Las conversaciones que tenga con OpenCode pueden [compartirse con su
equipo](/docs/share).
```bash frame="none"
@ -348,12 +334,12 @@ Esto creará un enlace a la conversación actual y lo copiará en su portapapele
Las conversaciones no se comparten de forma predeterminada.
:::
Aquí hay una [conversación de ejemplo](https://opencode.ai/s/4XP1fce5) con OpenCode.
Aquí tiene una [conversación de ejemplo](https://opencode.ai/s/4XP1fce5) con OpenCode.
---
## Personalizar
¡Y eso es todo! Ahora eres un profesional en el uso de OpenCode.
Y eso es todo. Ya conoce lo básico para empezar a usar OpenCode.
Para personalizarlo, recomendamos [elegir un tema](/docs/themes), [personalizar las combinaciones de teclas](/docs/keybinds), [configurar formateadores de código](/docs/formatters), [crear comandos personalizados](/docs/commands) o jugar con la [configuración OpenCode](/docs/config).
Para personalizarlo, recomendamos [elegir un tema](/docs/themes), [personalizar las combinaciones de teclas](/docs/keybinds), [configurar formateadores de código](/docs/formatters), [crear comandos personalizados](/docs/commands) o explorar la [configuración OpenCode](/docs/config).

View File

@ -137,12 +137,10 @@ We support a pay-as-you-go model. Below are the prices **per 1M tokens**.
| Kimi K2 Thinking | $0.40 | $2.50 | - | - |
| Kimi K2 | $0.40 | $2.50 | - | - |
| Qwen3 Coder 480B | $0.45 | $1.50 | - | - |
| Claude Opus 4.6 (≤ 200K tokens) | $5.00 | $25.00 | $0.50 | $6.25 |
| Claude Opus 4.6 (> 200K tokens) | $10.00 | $37.50 | $1.00 | $12.50 |
| Claude Opus 4.6 | $5.00 | $25.00 | $0.50 | $6.25 |
| Claude Opus 4.5 | $5.00 | $25.00 | $0.50 | $6.25 |
| Claude Opus 4.1 | $15.00 | $75.00 | $1.50 | $18.75 |
| Claude Sonnet 4.6 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4.6 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
| Claude Sonnet 4.6 | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4.5 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
| Claude Sonnet 4.5 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |

View File

@ -2,7 +2,7 @@
"name": "opencode",
"displayName": "opencode",
"description": "opencode for VS Code",
"version": "1.2.26",
"version": "1.2.27",
"publisher": "sst-dev",
"repository": {
"type": "git",