merge origin/dev into fix/stale-running-session-ui
This commit is contained in:
commit
c19cbccf06
34 changed files with 270 additions and 146 deletions
10
.github/actions/setup-bun/action.yml
vendored
10
.github/actions/setup-bun/action.yml
vendored
|
|
@ -41,5 +41,13 @@ runs:
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Install dependencies
|
- 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
|
shell: bash
|
||||||
|
|
|
||||||
32
bun.lock
32
bun.lock
|
|
@ -26,7 +26,7 @@
|
||||||
},
|
},
|
||||||
"packages/app": {
|
"packages/app": {
|
||||||
"name": "@opencode-ai/app",
|
"name": "@opencode-ai/app",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kobalte/core": "catalog:",
|
"@kobalte/core": "catalog:",
|
||||||
"@opencode-ai/sdk": "workspace:*",
|
"@opencode-ai/sdk": "workspace:*",
|
||||||
|
|
@ -77,7 +77,7 @@
|
||||||
},
|
},
|
||||||
"packages/console/app": {
|
"packages/console/app": {
|
||||||
"name": "@opencode-ai/console-app",
|
"name": "@opencode-ai/console-app",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cloudflare/vite-plugin": "1.15.2",
|
"@cloudflare/vite-plugin": "1.15.2",
|
||||||
"@ibm/plex": "6.4.1",
|
"@ibm/plex": "6.4.1",
|
||||||
|
|
@ -111,7 +111,7 @@
|
||||||
},
|
},
|
||||||
"packages/console/core": {
|
"packages/console/core": {
|
||||||
"name": "@opencode-ai/console-core",
|
"name": "@opencode-ai/console-core",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-sts": "3.782.0",
|
"@aws-sdk/client-sts": "3.782.0",
|
||||||
"@jsx-email/render": "1.1.1",
|
"@jsx-email/render": "1.1.1",
|
||||||
|
|
@ -138,7 +138,7 @@
|
||||||
},
|
},
|
||||||
"packages/console/function": {
|
"packages/console/function": {
|
||||||
"name": "@opencode-ai/console-function",
|
"name": "@opencode-ai/console-function",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ai-sdk/anthropic": "2.0.0",
|
"@ai-sdk/anthropic": "2.0.0",
|
||||||
"@ai-sdk/openai": "2.0.2",
|
"@ai-sdk/openai": "2.0.2",
|
||||||
|
|
@ -162,7 +162,7 @@
|
||||||
},
|
},
|
||||||
"packages/console/mail": {
|
"packages/console/mail": {
|
||||||
"name": "@opencode-ai/console-mail",
|
"name": "@opencode-ai/console-mail",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jsx-email/all": "2.2.3",
|
"@jsx-email/all": "2.2.3",
|
||||||
"@jsx-email/cli": "1.4.3",
|
"@jsx-email/cli": "1.4.3",
|
||||||
|
|
@ -186,7 +186,7 @@
|
||||||
},
|
},
|
||||||
"packages/desktop": {
|
"packages/desktop": {
|
||||||
"name": "@opencode-ai/desktop",
|
"name": "@opencode-ai/desktop",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/app": "workspace:*",
|
"@opencode-ai/app": "workspace:*",
|
||||||
"@opencode-ai/ui": "workspace:*",
|
"@opencode-ai/ui": "workspace:*",
|
||||||
|
|
@ -219,7 +219,7 @@
|
||||||
},
|
},
|
||||||
"packages/desktop-electron": {
|
"packages/desktop-electron": {
|
||||||
"name": "@opencode-ai/desktop-electron",
|
"name": "@opencode-ai/desktop-electron",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/app": "workspace:*",
|
"@opencode-ai/app": "workspace:*",
|
||||||
"@opencode-ai/ui": "workspace:*",
|
"@opencode-ai/ui": "workspace:*",
|
||||||
|
|
@ -250,7 +250,7 @@
|
||||||
},
|
},
|
||||||
"packages/enterprise": {
|
"packages/enterprise": {
|
||||||
"name": "@opencode-ai/enterprise",
|
"name": "@opencode-ai/enterprise",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/ui": "workspace:*",
|
"@opencode-ai/ui": "workspace:*",
|
||||||
"@opencode-ai/util": "workspace:*",
|
"@opencode-ai/util": "workspace:*",
|
||||||
|
|
@ -279,7 +279,7 @@
|
||||||
},
|
},
|
||||||
"packages/function": {
|
"packages/function": {
|
||||||
"name": "@opencode-ai/function",
|
"name": "@opencode-ai/function",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@octokit/auth-app": "8.0.1",
|
"@octokit/auth-app": "8.0.1",
|
||||||
"@octokit/rest": "catalog:",
|
"@octokit/rest": "catalog:",
|
||||||
|
|
@ -295,7 +295,7 @@
|
||||||
},
|
},
|
||||||
"packages/opencode": {
|
"packages/opencode": {
|
||||||
"name": "opencode",
|
"name": "opencode",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"bin": {
|
"bin": {
|
||||||
"opencode": "./bin/opencode",
|
"opencode": "./bin/opencode",
|
||||||
},
|
},
|
||||||
|
|
@ -416,7 +416,7 @@
|
||||||
},
|
},
|
||||||
"packages/plugin": {
|
"packages/plugin": {
|
||||||
"name": "@opencode-ai/plugin",
|
"name": "@opencode-ai/plugin",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/sdk": "workspace:*",
|
"@opencode-ai/sdk": "workspace:*",
|
||||||
"zod": "catalog:",
|
"zod": "catalog:",
|
||||||
|
|
@ -440,7 +440,7 @@
|
||||||
},
|
},
|
||||||
"packages/sdk/js": {
|
"packages/sdk/js": {
|
||||||
"name": "@opencode-ai/sdk",
|
"name": "@opencode-ai/sdk",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@hey-api/openapi-ts": "0.90.10",
|
"@hey-api/openapi-ts": "0.90.10",
|
||||||
"@tsconfig/node22": "catalog:",
|
"@tsconfig/node22": "catalog:",
|
||||||
|
|
@ -451,7 +451,7 @@
|
||||||
},
|
},
|
||||||
"packages/slack": {
|
"packages/slack": {
|
||||||
"name": "@opencode-ai/slack",
|
"name": "@opencode-ai/slack",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@opencode-ai/sdk": "workspace:*",
|
"@opencode-ai/sdk": "workspace:*",
|
||||||
"@slack/bolt": "^3.17.1",
|
"@slack/bolt": "^3.17.1",
|
||||||
|
|
@ -486,7 +486,7 @@
|
||||||
},
|
},
|
||||||
"packages/ui": {
|
"packages/ui": {
|
||||||
"name": "@opencode-ai/ui",
|
"name": "@opencode-ai/ui",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kobalte/core": "catalog:",
|
"@kobalte/core": "catalog:",
|
||||||
"@opencode-ai/sdk": "workspace:*",
|
"@opencode-ai/sdk": "workspace:*",
|
||||||
|
|
@ -532,7 +532,7 @@
|
||||||
},
|
},
|
||||||
"packages/util": {
|
"packages/util": {
|
||||||
"name": "@opencode-ai/util",
|
"name": "@opencode-ai/util",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"zod": "catalog:",
|
"zod": "catalog:",
|
||||||
},
|
},
|
||||||
|
|
@ -543,7 +543,7 @@
|
||||||
},
|
},
|
||||||
"packages/web": {
|
"packages/web": {
|
||||||
"name": "@opencode-ai/web",
|
"name": "@opencode-ai/web",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/cloudflare": "12.6.3",
|
"@astrojs/cloudflare": "12.6.3",
|
||||||
"@astrojs/markdown-remark": "6.3.1",
|
"@astrojs/markdown-remark": "6.3.1",
|
||||||
|
|
|
||||||
|
|
@ -349,3 +349,25 @@ test("session model restore across workspaces", async ({ page, withProject }) =>
|
||||||
await waitFooter(page, firstState)
|
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 })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@opencode-ai/app",
|
"name": "@opencode-ai/app",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"description": "",
|
"description": "",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|
|
||||||
|
|
@ -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">
|
<div class="flex h-[24px] box-border items-center rounded-md border border-border-weak-base bg-surface-panel overflow-hidden">
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
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={{
|
classList={{
|
||||||
"bg-surface-raised-base-active": opening(),
|
"bg-surface-raised-base-active": opening(),
|
||||||
}}
|
}}
|
||||||
|
|
@ -339,7 +339,6 @@ export function SessionHeader() {
|
||||||
<Spinner class="size-3.5" style={{ color: tint() ?? "var(--icon-base)" }} />
|
<Spinner class="size-3.5" style={{ color: tint() ?? "var(--icon-base)" }} />
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
<span class="text-12-regular text-text-strong">{language.t("common.open")}</span>
|
|
||||||
</Button>
|
</Button>
|
||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
gutter={4}
|
gutter={4}
|
||||||
|
|
|
||||||
|
|
@ -192,10 +192,11 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
|
||||||
model: item.model,
|
model: item.model,
|
||||||
variant: item.variant ?? null,
|
variant: item.variant ?? null,
|
||||||
})
|
})
|
||||||
|
const prev = scope()
|
||||||
const next = {
|
const next = {
|
||||||
agent: item.name,
|
agent: item.name,
|
||||||
model: item.model,
|
model: item.model ?? prev?.model,
|
||||||
variant: item.variant,
|
variant: item.variant ?? prev?.variant,
|
||||||
} satisfies State
|
} satisfies State
|
||||||
const session = id()
|
const session = id()
|
||||||
if (session) {
|
if (session) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@opencode-ai/console-app",
|
"name": "@opencode-ai/console-app",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"name": "@opencode-ai/console-core",
|
"name": "@opencode-ai/console-core",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@opencode-ai/console-function",
|
"name": "@opencode-ai/console-function",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@opencode-ai/console-mail",
|
"name": "@opencode-ai/console-mail",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jsx-email/all": "2.2.3",
|
"@jsx-email/all": "2.2.3",
|
||||||
"@jsx-email/cli": "1.4.3",
|
"@jsx-email/cli": "1.4.3",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@opencode-ai/desktop-electron",
|
"name": "@opencode-ai/desktop-electron",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"homepage": "https://opencode.ai",
|
"homepage": "https://opencode.ai",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@opencode-ai/desktop",
|
"name": "@opencode-ai/desktop",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@opencode-ai/enterprise",
|
"name": "@opencode-ai/enterprise",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
id = "opencode"
|
id = "opencode"
|
||||||
name = "OpenCode"
|
name = "OpenCode"
|
||||||
description = "The open source coding agent."
|
description = "The open source coding agent."
|
||||||
version = "1.2.26"
|
version = "1.2.27"
|
||||||
schema_version = 1
|
schema_version = 1
|
||||||
authors = ["Anomaly"]
|
authors = ["Anomaly"]
|
||||||
repository = "https://github.com/anomalyco/opencode"
|
repository = "https://github.com/anomalyco/opencode"
|
||||||
|
|
@ -11,26 +11,26 @@ name = "OpenCode"
|
||||||
icon = "./icons/opencode.svg"
|
icon = "./icons/opencode.svg"
|
||||||
|
|
||||||
[agent_servers.opencode.targets.darwin-aarch64]
|
[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"
|
cmd = "./opencode"
|
||||||
args = ["acp"]
|
args = ["acp"]
|
||||||
|
|
||||||
[agent_servers.opencode.targets.darwin-x86_64]
|
[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"
|
cmd = "./opencode"
|
||||||
args = ["acp"]
|
args = ["acp"]
|
||||||
|
|
||||||
[agent_servers.opencode.targets.linux-aarch64]
|
[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"
|
cmd = "./opencode"
|
||||||
args = ["acp"]
|
args = ["acp"]
|
||||||
|
|
||||||
[agent_servers.opencode.targets.linux-x86_64]
|
[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"
|
cmd = "./opencode"
|
||||||
args = ["acp"]
|
args = ["acp"]
|
||||||
|
|
||||||
[agent_servers.opencode.targets.windows-x86_64]
|
[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"
|
cmd = "./opencode.exe"
|
||||||
args = ["acp"]
|
args = ["acp"]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@opencode-ai/function",
|
"name": "@opencode-ai/function",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"name": "opencode",
|
"name": "opencode",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,11 @@ const openBrowser = (url: string) => Effect.promise(() => open(url).catch(() =>
|
||||||
|
|
||||||
const println = (msg: string) => Effect.sync(() => UI.println(msg))
|
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 loginEffect = Effect.fn("login")(function* (url: string) {
|
||||||
const service = yield* AccountService
|
const service = yield* AccountService
|
||||||
|
|
||||||
|
|
@ -99,11 +104,10 @@ const switchEffect = Effect.fn("switch")(function* () {
|
||||||
if (groups.length === 0) return yield* println("Not logged in")
|
if (groups.length === 0) return yield* println("Not logged in")
|
||||||
|
|
||||||
const active = yield* service.active()
|
const active = yield* service.active()
|
||||||
const activeOrgID = Option.flatMap(active, (a) => Option.fromNullishOr(a.active_org_id))
|
|
||||||
|
|
||||||
const opts = groups.flatMap((group) =>
|
const opts = groups.flatMap((group) =>
|
||||||
group.orgs.map((org) => {
|
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 {
|
return {
|
||||||
value: { orgID: org.id, accountID: group.account.id, label: org.name },
|
value: { orgID: org.id, accountID: group.account.id, label: org.name },
|
||||||
label: isActive
|
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")
|
if (!groups.some((group) => group.orgs.length > 0)) return yield* println("No orgs found")
|
||||||
|
|
||||||
const active = yield* service.active()
|
const active = yield* service.active()
|
||||||
const activeOrgID = Option.flatMap(active, (a) => Option.fromNullishOr(a.active_org_id))
|
|
||||||
|
|
||||||
for (const group of groups) {
|
for (const group of groups) {
|
||||||
for (const org of group.orgs) {
|
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 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 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
|
const email = UI.Style.TEXT_DIM + group.account.email + UI.Style.TEXT_NORMAL
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ export namespace Vcs {
|
||||||
log.info("initialized", { branch: current })
|
log.info("initialized", { branch: current })
|
||||||
|
|
||||||
const unsubscribe = Bus.subscribe(FileWatcher.Event.Updated, async (evt) => {
|
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()
|
const next = await currentBranch()
|
||||||
if (next !== current) {
|
if (next !== current) {
|
||||||
log.info("branch changed", { from: current, to: next })
|
log.info("branch changed", { from: current, to: next })
|
||||||
|
|
|
||||||
|
|
@ -167,7 +167,8 @@ export namespace ProviderError {
|
||||||
|
|
||||||
export function parseAPICallError(input: { providerID: ProviderID; error: APICallError }): ParsedAPICallError {
|
export function parseAPICallError(input: { providerID: ProviderID; error: APICallError }): ParsedAPICallError {
|
||||||
const m = message(input.providerID, input.error)
|
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 {
|
return {
|
||||||
type: "context_overflow",
|
type: "context_overflow",
|
||||||
message: m,
|
message: m,
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ export namespace LLM {
|
||||||
sessionID: string
|
sessionID: string
|
||||||
model: Provider.Model
|
model: Provider.Model
|
||||||
agent: Agent.Info
|
agent: Agent.Info
|
||||||
|
permission?: PermissionNext.Ruleset
|
||||||
system: string[]
|
system: string[]
|
||||||
abort: AbortSignal
|
abort: AbortSignal
|
||||||
messages: ModelMessage[]
|
messages: ModelMessage[]
|
||||||
|
|
@ -255,8 +256,11 @@ export namespace LLM {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resolveTools(input: Pick<StreamInput, "tools" | "agent" | "user">) {
|
async function resolveTools(input: Pick<StreamInput, "tools" | "agent" | "permission" | "user">) {
|
||||||
const disabled = PermissionNext.disabled(Object.keys(input.tools), input.agent.permission)
|
const disabled = PermissionNext.disabled(
|
||||||
|
Object.keys(input.tools),
|
||||||
|
PermissionNext.merge(input.agent.permission, input.permission ?? []),
|
||||||
|
)
|
||||||
for (const tool of Object.keys(input.tools)) {
|
for (const tool of Object.keys(input.tools)) {
|
||||||
if (input.user.tools?.[tool] === false || disabled.has(tool)) {
|
if (input.user.tools?.[tool] === false || disabled.has(tool)) {
|
||||||
delete input.tools[tool]
|
delete input.tools[tool]
|
||||||
|
|
|
||||||
|
|
@ -664,6 +664,7 @@ export namespace SessionPrompt {
|
||||||
return processor.process({
|
return processor.process({
|
||||||
user: lastUser,
|
user: lastUser,
|
||||||
agent,
|
agent,
|
||||||
|
permission: session.permission,
|
||||||
abort,
|
abort,
|
||||||
sessionID,
|
sessionID,
|
||||||
system,
|
system,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test"
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test"
|
||||||
import path from "path"
|
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 { LLM } from "../../src/session/llm"
|
||||||
import { Global } from "../../src/global"
|
import { Global } from "../../src/global"
|
||||||
import { Instance } from "../../src/project/instance"
|
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 () => {
|
test("sends responses API payload for OpenAI models", async () => {
|
||||||
const server = state.server
|
const server = state.server
|
||||||
if (!server) {
|
if (!server) {
|
||||||
|
|
|
||||||
|
|
@ -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", () => {
|
test("does not classify 429 no body as context overflow", () => {
|
||||||
const result = MessageV2.fromError(
|
const result = MessageV2.fromError(
|
||||||
new APICallError({
|
new APICallError({
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"name": "@opencode-ai/plugin",
|
"name": "@opencode-ai/plugin",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"name": "@opencode-ai/sdk",
|
"name": "@opencode-ai/sdk",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@opencode-ai/slack",
|
"name": "@opencode-ai/slack",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@opencode-ai/ui",
|
"name": "@opencode-ai/ui",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|
|
||||||
|
|
@ -1050,18 +1050,8 @@
|
||||||
line-height: var(--line-height-large);
|
line-height: var(--line-height-large);
|
||||||
color: var(--text-base);
|
color: var(--text-base);
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
overflow: hidden;
|
overflow-wrap: anywhere;
|
||||||
text-overflow: ellipsis;
|
white-space: normal;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-slot="question-custom"] {
|
[data-slot="question-custom"] {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@opencode-ai/util",
|
"name": "@opencode-ai/util",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "@opencode-ai/web",
|
"name": "@opencode-ai/web",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "astro dev",
|
"dev": "astro dev",
|
||||||
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",
|
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",
|
||||||
|
|
|
||||||
|
|
@ -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-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-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-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 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,23 @@
|
||||||
---
|
---
|
||||||
title: Introducción
|
title: Introducción
|
||||||
description: Comience con OpenCode.
|
description: Comience a usar OpenCode.
|
||||||
---
|
---
|
||||||
|
|
||||||
import { Tabs, TabItem } from "@astrojs/starlight/components"
|
import { Tabs, TabItem } from "@astrojs/starlight/components"
|
||||||
import config from "../../../../config.mjs"
|
import config from "../../../../config.mjs"
|
||||||
export const console = config.console
|
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.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Empecemos.
|
Comencemos.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### Requisitos previos
|
#### Requisitos previos
|
||||||
|
|
||||||
Para usar OpenCode en su terminal, necesitará:
|
Para usar OpenCode en la terminal, necesitará:
|
||||||
|
|
||||||
1. Un emulador de terminal moderno como:
|
1. Un emulador de terminal moderno como:
|
||||||
- [WezTerm](https://wezterm.org), multiplataforma
|
- [WezTerm](https://wezterm.org), multiplataforma
|
||||||
|
|
@ -25,7 +25,7 @@ Para usar OpenCode en su terminal, necesitará:
|
||||||
- [Ghostty](https://ghostty.org), Linux y macOS
|
- [Ghostty](https://ghostty.org), Linux y macOS
|
||||||
- [Kitty](https://sw.kovidgoyal.net/kitty/), 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
|
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**
|
- **Usando Node.js**
|
||||||
|
|
||||||
|
|
@ -91,7 +91,7 @@ También puedes instalarlo con los siguientes comandos:
|
||||||
#### Windows
|
#### Windows
|
||||||
|
|
||||||
:::tip[Recomendado: Usar WSL]
|
:::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**
|
- **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
|
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
|
## 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).
|
Si es nuevo en el uso de proveedores de 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.
|
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
|
```txt
|
||||||
/connect
|
/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
|
```txt
|
||||||
┌ API key
|
┌ API key
|
||||||
|
|
@ -154,50 +154,45 @@ Es una lista seleccionada de modelos que han sido probados y verificados por el
|
||||||
└ enter
|
└ 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
|
## Inicializar
|
||||||
|
|
||||||
Ahora que ha configurado un proveedor, puede navegar a un proyecto que
|
Ahora que ya configuró un proveedor, vaya al proyecto en el que quiera trabajar.
|
||||||
quieres trabajar.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /path/to/project
|
cd /path/to/project
|
||||||
```
|
```
|
||||||
|
|
||||||
Y ejecute OpenCode.
|
Luego, ejecute OpenCode.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
opencode
|
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"
|
```bash frame="none"
|
||||||
/init
|
/init
|
||||||
```
|
```
|
||||||
|
|
||||||
Esto hará que OpenCode analice su proyecto y cree un archivo `AGENTS.md` en
|
OpenCode analizará su proyecto y creará un archivo AGENTS.md en la raíz.
|
||||||
la raíz del proyecto.
|
|
||||||
|
|
||||||
:::tip
|
:::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.
|
Esto ayuda a OpenCode a comprender la estructura del proyecto y los patrones de código que se usan en él.
|
||||||
usado.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Usar
|
## Usar
|
||||||
|
|
||||||
Ahora está listo para usar OpenCode para trabajar en su proyecto. No dudes en preguntarle
|
Ahora ya está listo para usar OpenCode en su proyecto. Puede pedirle desde explicaciones del código hasta cambios concretos.
|
||||||
¡cualquier cosa!
|
|
||||||
|
|
||||||
Si es nuevo en el uso de un agente de codificación de IA, aquí hay algunos ejemplos que podrían
|
Si es la primera vez que usa un agente de codigo con IA, estos ejemplos pueden servirle como punto de partida.
|
||||||
ayuda.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -206,126 +201,117 @@ ayuda.
|
||||||
Puede pedirle a OpenCode que le explique el código base.
|
Puede pedirle a OpenCode que le explique el código base.
|
||||||
|
|
||||||
:::tip
|
:::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"
|
```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
|
OpenCode tiene un modo Plan que desactiva temporalmente su capacidad de hacer cambios y, en su lugar, propone _cómo_ implementará la funcionalidad.
|
||||||
en su lugar, sugiera _cómo_ implementará la función.
|
|
||||||
|
|
||||||
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"
|
```bash frame="none" title="Switch to Plan mode"
|
||||||
<TAB>
|
<TAB>
|
||||||
```
|
```
|
||||||
|
|
||||||
Ahora describamos lo que queremos que haga.
|
Ahora describa lo que quiere que haga.
|
||||||
|
|
||||||
```txt frame="none"
|
```txt frame="none"
|
||||||
When a user deletes a note, we'd like to flag it as deleted in the database.
|
Cuando un usuario elimine una nota, queremos marcarla como eliminada en la base de datos.
|
||||||
Then create a screen that shows all the recently deleted notes.
|
Luego, cree una pantalla que muestre todas las notas eliminadas recientemente.
|
||||||
From this screen, the user can undelete a note or permanently delete it.
|
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
|
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.
|
||||||
hablar con él como si estuviera hablando con un desarrollador junior de su equipo.
|
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Dale a OpenCode mucho contexto y ejemplos para ayudarlo a comprender lo que
|
Déle a OpenCode todo el contexto y los ejemplos que pueda para ayudarle a comprender lo que desea.
|
||||||
desear.
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
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"
|
```txt frame="none"
|
||||||
We'd like to design this new screen using a design I've used before.
|
Queremos diseñar esta nueva pantalla usando un diseño que ya hemos usado antes.
|
||||||
[Image #1] Take a look at this image and use it as a reference.
|
[Imagen #1] Revise esta imagen y úsela como referencia.
|
||||||
```
|
```
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
Arrastre y suelte imágenes en la terminal para agregarlas al mensaje.
|
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
|
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.
|
||||||
Haga esto 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_
|
Cuando esté conforme con el plan, vuelva al modo _Build_ presionando de nuevo la tecla Tab.
|
||||||
presionando la tecla **Tab** nuevamente.
|
|
||||||
|
|
||||||
```bash frame="none"
|
```bash frame="none"
|
||||||
<TAB>
|
<TAB>
|
||||||
```
|
```
|
||||||
|
|
||||||
Y pidiéndole que haga los cambios.
|
Luego, pídale que haga los cambios.
|
||||||
|
|
||||||
```bash frame="none"
|
```bash frame="none"
|
||||||
Sounds good! Go ahead and make the changes.
|
Perfecto. Continúe y realice los cambios.
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Realizar cambios
|
### Realizar cambios
|
||||||
|
|
||||||
Para cambios más sencillos, puede pedirle a OpenCode que lo construya directamente.
|
Para cambios más sencillos, puede pedirle a OpenCode que los implemente directamente, sin revisar antes un plan.
|
||||||
sin tener que revisar el plan primero.
|
|
||||||
|
|
||||||
```txt frame="none" "@packages/functions/src/settings.ts" "@packages/functions/src/notes.ts"
|
```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
|
Necesitamos agregar autenticación a la ruta /settings. Revise cómo se maneja esto
|
||||||
handled in the /notes route in @packages/functions/src/notes.ts and implement
|
en la ruta /notes en @packages/functions/src/notes.ts e implemente
|
||||||
the same logic in @packages/functions/src/settings.ts
|
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.
|
Procure dar suficientes detalles para que OpenCode pueda tomar las decisiones correctas al hacer los cambios
|
||||||
cambios.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Deshacer 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"
|
```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
|
Pero luego se da cuenta de que no era lo que quería. Puede **deshacer** los cambios usando el comando `/undo`.
|
||||||
usando el comando `/undo`.
|
|
||||||
|
|
||||||
```bash frame="none"
|
```bash frame="none"
|
||||||
/undo
|
/undo
|
||||||
```
|
```
|
||||||
|
|
||||||
OpenCode ahora revertirá los cambios que realizó y mostrará su mensaje original
|
OpenCode revertirá los cambios que hizo y volverá a mostrar su mensaje original.
|
||||||
de nuevo.
|
|
||||||
|
|
||||||
```txt frame="none" "@packages/functions/src/api/index.ts"
|
```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
|
:::tip
|
||||||
Puede ejecutar `/undo` varias veces para deshacer varios cambios.
|
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"
|
```bash frame="none"
|
||||||
/redo
|
/redo
|
||||||
|
|
@ -335,7 +321,7 @@ O **puedes rehacer** los cambios usando el comando `/redo`.
|
||||||
|
|
||||||
## Compartir
|
## 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).
|
equipo](/docs/share).
|
||||||
|
|
||||||
```bash frame="none"
|
```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.
|
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
|
## 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).
|
||||||
|
|
|
||||||
|
|
@ -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 Thinking | $0.40 | $2.50 | - | - |
|
||||||
| Kimi K2 | $0.40 | $2.50 | - | - |
|
| Kimi K2 | $0.40 | $2.50 | - | - |
|
||||||
| Qwen3 Coder 480B | $0.45 | $1.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 | $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.5 | $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 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 | $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.5 (≤ 200K tokens) | $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.5 (> 200K tokens) | $6.00 | $22.50 | $0.60 | $7.50 |
|
||||||
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
|
| Claude Sonnet 4 (≤ 200K tokens) | $3.00 | $15.00 | $0.30 | $3.75 |
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "opencode",
|
"name": "opencode",
|
||||||
"displayName": "opencode",
|
"displayName": "opencode",
|
||||||
"description": "opencode for VS Code",
|
"description": "opencode for VS Code",
|
||||||
"version": "1.2.26",
|
"version": "1.2.27",
|
||||||
"publisher": "sst-dev",
|
"publisher": "sst-dev",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue