From b5e200988c30258f32c857db300b61e9176b6383 Mon Sep 17 00:00:00 2001
From: Kit Langton
-
-
-
Trợ lý lập trình AI mã nguồn mở.
- - -- English | - 简体中文 | - 繁體中文 | - 한국어 | - Deutsch | - Español | - Français | - Italiano | - Dansk | - 日本語 | - Polski | - Русский | - Bosanski | - العربية | - Norsk | - Português (Brasil) | - ไทย | - Türkçe | - Українська | - বাংলা | - Ελληνικά | - Tiếng Việt -
- -[](https://opencode.ai) - ---- - -### Cài đặt - -```bash -# YOLO -curl -fsSL https://opencode.ai/install | bash - -# Các trình quản lý gói (Package managers) -npm i -g opencode-ai@latest # hoặc bun/pnpm/yarn -scoop install opencode # Windows -choco install opencode # Windows -brew install anomalyco/tap/opencode # macOS và Linux (khuyên dùng, luôn cập nhật) -brew install opencode # macOS và Linux (công thức brew chính thức, ít cập nhật hơn) -sudo pacman -S opencode # Arch Linux (Bản ổn định) -paru -S opencode-bin # Arch Linux (Bản mới nhất từ AUR) -mise use -g opencode # Mọi hệ điều hành -nix run nixpkgs#opencode # hoặc github:anomalyco/opencode cho nhánh dev mới nhất -``` - -> [!TIP] -> Hãy xóa các phiên bản cũ hơn 0.1.x trước khi cài đặt. - -### Ứng dụng Desktop (BETA) - -OpenCode cũng có sẵn dưới dạng ứng dụng desktop. Tải trực tiếp từ [trang releases](https://github.com/anomalyco/opencode/releases) hoặc [opencode.ai/download](https://opencode.ai/download). - -| Nền tảng | Tải xuống | -| --------------------- | ------------------------------------- | -| macOS (Apple Silicon) | `opencode-desktop-darwin-aarch64.dmg` | -| macOS (Intel) | `opencode-desktop-darwin-x64.dmg` | -| Windows | `opencode-desktop-windows-x64.exe` | -| Linux | `.deb`, `.rpm`, hoặc AppImage | - -```bash -# macOS (Homebrew) -brew install --cask opencode-desktop -# Windows (Scoop) -scoop bucket add extras; scoop install extras/opencode-desktop -``` - -#### Thư mục cài đặt - -Tập lệnh cài đặt tuân theo thứ tự ưu tiên sau cho đường dẫn cài đặt: - -1. `$OPENCODE_INSTALL_DIR` - Thư mục cài đặt tùy chỉnh -2. `$XDG_BIN_DIR` - Đường dẫn tuân thủ XDG Base Directory Specification -3. `$HOME/bin` - Thư mục nhị phân tiêu chuẩn của người dùng (nếu tồn tại hoặc có thể tạo) -4. `$HOME/.opencode/bin` - Mặc định dự phòng - -```bash -# Ví dụ -OPENCODE_INSTALL_DIR=/usr/local/bin curl -fsSL https://opencode.ai/install | bash -XDG_BIN_DIR=$HOME/.local/bin curl -fsSL https://opencode.ai/install | bash -``` - -### Agents (Đại diện) - -OpenCode bao gồm hai agent được tích hợp sẵn mà bạn có thể chuyển đổi bằng phím `Tab`. - -- **build** - Agent mặc định, có toàn quyền truy cập cho công việc lập trình -- **plan** - Agent chỉ đọc dùng để phân tích và khám phá mã nguồn - - Mặc định từ chối việc chỉnh sửa tệp - - Hỏi quyền trước khi chạy các lệnh bash - - Lý tưởng để khám phá các codebase lạ hoặc lên kế hoạch thay đổi - -Ngoài ra còn có một subagent **general** dùng cho các tìm kiếm phức tạp và tác vụ nhiều bước. -Agent này được sử dụng nội bộ và có thể gọi bằng cách dùng `@general` trong tin nhắn. - -Tìm hiểu thêm về [agents](https://opencode.ai/docs/agents). - -### Tài liệu - -Để biết thêm thông tin về cách cấu hình OpenCode, [**hãy truy cập tài liệu của chúng tôi**](https://opencode.ai/docs). - -### Đóng góp - -Nếu bạn muốn đóng góp cho OpenCode, vui lòng đọc [tài liệu hướng dẫn đóng góp](./CONTRIBUTING.md) trước khi gửi pull request. - -### Xây dựng trên nền tảng OpenCode - -Nếu bạn đang làm việc trên một dự án liên quan đến OpenCode và sử dụng "opencode" như một phần của tên dự án, ví dụ "opencode-dashboard" hoặc "opencode-mobile", vui lòng thêm một ghi chú vào README của bạn để làm rõ rằng dự án đó không được xây dựng bởi đội ngũ OpenCode và không liên kết với chúng tôi dưới bất kỳ hình thức nào. - -### Các câu hỏi thường gặp (FAQ) - -#### OpenCode khác biệt thế nào so với Claude Code? - -Về mặt tính năng, nó rất giống Claude Code. Dưới đây là những điểm khác biệt chính: - -- 100% mã nguồn mở -- Không bị ràng buộc với bất kỳ nhà cung cấp nào. Mặc dù chúng tôi khuyên dùng các mô hình được cung cấp qua [OpenCode Zen](https://opencode.ai/zen), OpenCode có thể được sử dụng với Claude, OpenAI, Google, hoặc thậm chí các mô hình chạy cục bộ. Khi các mô hình phát triển, khoảng cách giữa chúng sẽ thu hẹp lại và giá cả sẽ giảm, vì vậy việc không phụ thuộc vào nhà cung cấp là rất quan trọng. -- Hỗ trợ LSP ngay từ đầu -- Tập trung vào TUI (Giao diện người dùng dòng lệnh). OpenCode được xây dựng bởi những người dùng neovim và đội ngũ tạo ra [terminal.shop](https://terminal.shop); chúng tôi sẽ đẩy giới hạn của những gì có thể làm được trên terminal lên mức tối đa. -- Kiến trúc client/server. Chẳng hạn, điều này cho phép OpenCode chạy trên máy tính của bạn trong khi bạn điều khiển nó từ xa qua một ứng dụng di động, nghĩa là frontend TUI chỉ là một trong những client có thể dùng. - ---- - -**Tham gia cộng đồng của chúng tôi** [Discord](https://discord.gg/opencode) | [X.com](https://x.com/opencode) diff --git a/README.zh.md b/README.zh.md index b11d9857c9c6..9a1e1b2fb6ec 100644 --- a/README.zh.md +++ b/README.zh.md @@ -27,7 +27,6 @@ 日本語 | Polski | Русский | - Bosanski | العربية | Norsk | Português (Brasil) | @@ -35,8 +34,7 @@ Türkçe | Українська | বাংলা | - Ελληνικά | - Tiếng Việt + Ελληνικά [](https://opencode.ai) diff --git a/README.zht.md b/README.zht.md index 573ca85ab43b..238f11289f14 100644 --- a/README.zht.md +++ b/README.zht.md @@ -27,7 +27,6 @@ 日本語 | Polski | Русский | - Bosanski | العربية | Norsk | Português (Brasil) | @@ -35,8 +34,7 @@ Türkçe | Українська | বাংলা | - Ελληνικά | - Tiếng Việt + Ελληνικά [](https://opencode.ai) diff --git a/bun.lock b/bun.lock index 97292974d246..a27fa0da4843 100644 --- a/bun.lock +++ b/bun.lock @@ -26,7 +26,7 @@ }, "packages/app": { "name": "@opencode-ai/app", - "version": "1.2.20", + "version": "1.2.18", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -76,7 +76,7 @@ }, "packages/console/app": { "name": "@opencode-ai/console-app", - "version": "1.2.20", + "version": "1.2.18", "dependencies": { "@cloudflare/vite-plugin": "1.15.2", "@ibm/plex": "6.4.1", @@ -110,7 +110,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.2.20", + "version": "1.2.18", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -137,7 +137,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.2.20", + "version": "1.2.18", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -161,7 +161,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.2.20", + "version": "1.2.18", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -185,7 +185,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.2.20", + "version": "1.2.18", "dependencies": { "@opencode-ai/app": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -218,7 +218,7 @@ }, "packages/desktop-electron": { "name": "@opencode-ai/desktop-electron", - "version": "1.2.20", + "version": "1.2.18", "dependencies": { "@opencode-ai/app": "workspace:*", "@opencode-ai/ui": "workspace:*", @@ -248,7 +248,7 @@ }, "packages/enterprise": { "name": "@opencode-ai/enterprise", - "version": "1.2.20", + "version": "1.2.18", "dependencies": { "@opencode-ai/ui": "workspace:*", "@opencode-ai/util": "workspace:*", @@ -277,7 +277,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.2.20", + "version": "1.2.18", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "catalog:", @@ -293,7 +293,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.2.20", + "version": "1.2.18", "bin": { "opencode": "./bin/opencode", }, @@ -373,7 +373,6 @@ "ulid": "catalog:", "vscode-jsonrpc": "8.2.1", "web-tree-sitter": "0.25.10", - "which": "6.0.1", "xdg-basedir": "5.1.0", "yargs": "18.0.0", "zod": "catalog:", @@ -396,7 +395,6 @@ "@types/bun": "catalog:", "@types/mime-types": "3.0.1", "@types/turndown": "5.0.5", - "@types/which": "3.0.4", "@types/yargs": "17.0.33", "@typescript/native-preview": "catalog:", "drizzle-kit": "1.0.0-beta.16-ea816b6", @@ -409,7 +407,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.2.20", + "version": "1.2.18", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -429,7 +427,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.2.20", + "version": "1.2.18", "devDependencies": { "@hey-api/openapi-ts": "0.90.10", "@tsconfig/node22": "catalog:", @@ -440,7 +438,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.2.20", + "version": "1.2.18", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -475,7 +473,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.2.20", + "version": "1.2.18", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -506,6 +504,7 @@ "virtua": "catalog:", }, "devDependencies": { + "@happy-dom/global-registrator": "20.0.11", "@tailwindcss/vite": "catalog:", "@tsconfig/node22": "catalog:", "@types/bun": "catalog:", @@ -521,7 +520,7 @@ }, "packages/util": { "name": "@opencode-ai/util", - "version": "1.2.20", + "version": "1.2.18", "dependencies": { "zod": "catalog:", }, @@ -532,7 +531,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.2.20", + "version": "1.2.18", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", @@ -2122,8 +2121,6 @@ "@types/whatwg-mimetype": ["@types/whatwg-mimetype@3.0.2", "", {}, "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA=="], - "@types/which": ["@types/which@3.0.4", "", {}, "sha512-liyfuo/106JdlgSchJzXEQCVArk0CvevqPote8F8HgWgJ3dRCcTHgJIsLDuee0kxk/mhbInzIZk3QWSZJ8R+2w=="], - "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], "@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], @@ -3240,7 +3237,7 @@ "isbinaryfile": ["isbinaryfile@5.0.7", "", {}, "sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ=="], - "isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="], + "isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="], "isomorphic-ws": ["isomorphic-ws@5.0.0", "", { "peerDependencies": { "ws": "*" } }, "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw=="], @@ -4590,7 +4587,7 @@ "when-exit": ["when-exit@2.1.5", "", {}, "sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg=="], - "which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="], + "which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="], "which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="], @@ -5206,8 +5203,6 @@ "app-builder-lib/minimatch": ["minimatch@10.2.1", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-MClCe8IL5nRRmawL6ib/eT4oLyeKMGCghibcDWK+J0hh0Q8kqSdia6BvbRMVk6mPa6WqUa5uR2oxt6C5jd533A=="], - "app-builder-lib/which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="], - "archiver-utils/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], "archiver-utils/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], @@ -5396,8 +5391,6 @@ "node-gyp/nopt": ["nopt@8.1.0", "", { "dependencies": { "abbrev": "^3.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A=="], - "node-gyp/which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="], - "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], "nypm/citty": ["citty@0.2.1", "", {}, "sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg=="], @@ -5928,8 +5921,6 @@ "app-builder-lib/@electron/get/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "app-builder-lib/which/isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="], - "archiver-utils/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], "archiver-utils/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], @@ -6012,8 +6003,6 @@ "node-gyp/nopt/abbrev": ["abbrev@3.0.1", "", {}, "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg=="], - "node-gyp/which/isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="], - "opencode/@ai-sdk/openai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.20", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-iXHVe0apM2zUEzauqJwqmpC37A5rihrStAih5Ks+JE32iTe4LZ58y17UGBjpQQTCRw9YxMeo2UFLxLpBluyvLQ=="], "opencode/@ai-sdk/openai-compatible/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.20", "", { "dependencies": { "@ai-sdk/provider": "2.0.1", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-iXHVe0apM2zUEzauqJwqmpC37A5rihrStAih5Ks+JE32iTe4LZ58y17UGBjpQQTCRw9YxMeo2UFLxLpBluyvLQ=="], diff --git a/github/index.ts b/github/index.ts index 1a0a99262248..da310178a7dc 100644 --- a/github/index.ts +++ b/github/index.ts @@ -8,7 +8,6 @@ import type { Context as GitHubContext } from "@actions/github/lib/context" import type { IssueCommentEvent, PullRequestReviewCommentEvent } from "@octokit/webhooks-types" import { createOpencodeClient } from "@opencode-ai/sdk" import { spawn } from "node:child_process" -import { setTimeout as sleep } from "node:timers/promises" type GitHubAuthor = { login: string @@ -282,7 +281,7 @@ async function assertOpencodeConnected() { connected = true break } catch (e) {} - await sleep(300) + await Bun.sleep(300) } while (retry++ < 30) if (!connected) { diff --git a/nix/hashes.json b/nix/hashes.json index 326cc98a6679..47e3e240bb42 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,8 +1,8 @@ { "nodeModules": { - "x86_64-linux": "sha256-pBTIT8Pgdm3272YhBjiAZsmj0SSpHTklh6lGc8YcMoE=", - "aarch64-linux": "sha256-prt039++d5UZgtldAN6+RVOR557ifIeusiy5XpzN8QU=", - "aarch64-darwin": "sha256-Y3f+cXcIGLqz6oyc5fG22t6CLD4wGkvwqO6RNXjFriQ=", - "x86_64-darwin": "sha256-BjbBBhQUgGhrlP56skABcrObvutNUZSWnrnPCg1OTKE=" + "x86_64-linux": "sha256-v83hWzYVg/g4zJiBpGsQ71wTdndPk3BQVZ2mjMApUIQ=", + "aarch64-linux": "sha256-inpMwkQqwBFP2wL8w/pTOP7q3fg1aOqvE0wgzVd3/B8=", + "aarch64-darwin": "sha256-r42LGrQWqDyIy62mBSU5Nf3M22dJ3NNo7mjN/1h8d8Y=", + "x86_64-darwin": "sha256-J6XrrdK5qBK3sQBQOO/B3ZluOnsAf5f65l4q/K1nDTI=" } } diff --git a/packages/app/e2e/actions.ts b/packages/app/e2e/actions.ts index 919a1add8159..852bef05435a 100644 --- a/packages/app/e2e/actions.ts +++ b/packages/app/e2e/actions.ts @@ -8,6 +8,7 @@ import { sessionItemSelector, dropdownMenuTriggerSelector, dropdownMenuContentSelector, + sessionHeaderSelector, projectMenuTriggerSelector, projectWorkspacesToggleSelector, titlebarRightSelector, @@ -197,7 +198,6 @@ export async function createTestProject() { await fs.writeFile(path.join(root, "README.md"), "# e2e\n") execSync("git init", { cwd: root, stdio: "ignore" }) - execSync("git config core.fsmonitor false", { cwd: root, stdio: "ignore" }) execSync("git add -A", { cwd: root, stdio: "ignore" }) execSync('git -c user.name="e2e" -c user.email="e2e@example.com" commit -m "init" --allow-empty', { cwd: root, @@ -208,10 +208,7 @@ export async function createTestProject() { } export async function cleanupTestProject(directory: string) { - try { - execSync("git fsmonitor--daemon stop", { cwd: directory, stdio: "ignore" }) - } catch {} - await fs.rm(directory, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }).catch(() => undefined) + await fs.rm(directory, { recursive: true, force: true }).catch(() => undefined) } export function sessionIDFromUrl(url: string) { @@ -229,9 +226,9 @@ export async function hoverSessionItem(page: Page, sessionID: string) { export async function openSessionMoreMenu(page: Page, sessionID: string) { await expect(page).toHaveURL(new RegExp(`/session/${sessionID}(?:[/?#]|$)`)) - const scroller = page.locator(".scroll-view__viewport").first() - await expect(scroller).toBeVisible() - await expect(scroller.getByRole("heading", { level: 1 }).first()).toBeVisible({ timeout: 30_000 }) + const header = page.locator(sessionHeaderSelector).first() + await expect(header).toBeVisible() + await expect(header.getByRole("heading", { level: 1 }).first()).toBeVisible({ timeout: 30_000 }) const menu = page .locator(dropdownMenuContentSelector) @@ -247,7 +244,7 @@ export async function openSessionMoreMenu(page: Page, sessionID: string) { if (opened) return menu - const menuTrigger = scroller.getByRole("button", { name: /more options/i }).first() + const menuTrigger = header.getByRole("button", { name: /more options/i }).first() await expect(menuTrigger).toBeVisible() await menuTrigger.click() diff --git a/packages/app/e2e/selectors.ts b/packages/app/e2e/selectors.ts index 5fad2c06b528..d546cc668efd 100644 --- a/packages/app/e2e/selectors.ts +++ b/packages/app/e2e/selectors.ts @@ -53,6 +53,8 @@ export const dropdownMenuContentSelector = '[data-component="dropdown-menu-conte export const inlineInputSelector = '[data-component="inline-input"]' +export const sessionHeaderSelector = "[data-session-title]" + export const sessionItemSelector = (sessionID: string) => `${sidebarNavSelector} [data-session-id="${sessionID}"]` export const workspaceItemSelector = (slug: string) => diff --git a/packages/app/e2e/session/session.spec.ts b/packages/app/e2e/session/session.spec.ts index 68d992949964..afbea91ca688 100644 --- a/packages/app/e2e/session/session.spec.ts +++ b/packages/app/e2e/session/session.spec.ts @@ -7,7 +7,7 @@ import { openSharePopover, withSession, } from "../actions" -import { sessionItemSelector, inlineInputSelector } from "../selectors" +import { sessionHeaderSelector, sessionItemSelector, inlineInputSelector } from "../selectors" const shareDisabled = process.env.OPENCODE_DISABLE_SHARE === "true" || process.env.OPENCODE_DISABLE_SHARE === "1" @@ -44,7 +44,7 @@ test("session can be renamed via header menu", async ({ page, sdk, gotoSession } const menu = await openSessionMoreMenu(page, session.id) await clickMenuItem(menu, /rename/i) - const input = page.locator(".scroll-view__viewport").locator(inlineInputSelector).first() + const input = page.locator(sessionHeaderSelector).locator(inlineInputSelector).first() await expect(input).toBeVisible() await expect(input).toBeFocused() await input.fill(renamedTitle) diff --git a/packages/app/package.json b/packages/app/package.json index c91a91383dbc..37ccd9b53a19 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/app", - "version": "1.2.20", + "version": "1.2.18", "description": "", "type": "module", "exports": { diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index 532edd3bcdc4..7bd18fdff072 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -244,6 +244,7 @@ export const PromptInput: Component{pattern}}
+
+ {props.mode === "diff" ? `--- ${props.before?.name}\n+++ ${props.after?.name}` : "file"}
+
+ )
+}
+
+// ---------------------------------------------------------------------------
+// Control UI helpers
+// ---------------------------------------------------------------------------
+
+function Btn(props: { onClick: () => void; title?: string; children: any }) {
+ return (
+
+ )
+}
+
+function Toggle(props: { label: string; value: boolean; onChange: (v: boolean) => void }) {
+ return (
+
+ )
+}
+
+// ---------------------------------------------------------------------------
+// Simulator component
+// ---------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------
+// Interactive event trigger factories
+// ---------------------------------------------------------------------------
+
+interface TurnState {
+ turnIndex: number
+ userMsgID: string
+ asstMsgID: string
+}
+
+// A running tool that can be completed later
+interface RunningTool {
+ part: ToolPart
+ turn: TurnState
+ title: string
+ startTime: number
+ completeOutput: string
+ completePatch: Record
+ {props.out}
+
+