Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions .github/workflows/regression.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Regression checks
on:
pull_request:
push:
branches: [master]
permissions:
contents: read
jobs:
regression:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
persist-credentials: false
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: '22'
# Do not register host protocol handlers during dependency installation.
- run: npm ci --ignore-scripts
working-directory: server
- run: npm test
working-directory: server
- run: npm ci --ignore-scripts
working-directory: client-next
- run: npm test
working-directory: client-next
- run: npm run lint
working-directory: client-next
- run: npx tsc --noEmit
working-directory: client-next
- run: npm run build
working-directory: client-next
release:
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
needs: regression
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
persist-credentials: false
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: '22'
registry-url: https://registry.npmjs.org
- run: npm ci --ignore-scripts
working-directory: server
- name: Package and publish GitHub release
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
VERSION=$(node -p "require('./server/package.json').version")
TAG="v$VERSION"
if gh release view "$TAG" >/dev/null 2>&1; then
echo "Release $TAG already exists; no changes made."
exit 0
fi
mkdir -p release-artifacts
npm pack ./server --ignore-scripts --pack-destination release-artifacts
sha256sum release-artifacts/*.tgz > release-artifacts/SHA256SUMS
printf '%s\n' 'See CHANGELOG.md and docs/OPENCODE-V2-COMPATIBILITY.md for changes and limitations.' 'The attached archive is the tested server package. npm publication is a separate step; verify the registry before claiming it is published.' > release-artifacts/notes.md
gh release create "$TAG" release-artifacts/*.tgz release-artifacts/SHA256SUMS --target "$GITHUB_SHA" --title "$TAG" --notes-file release-artifacts/notes.md
- name: Publish npm when an existing token is configured
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
working-directory: server
run: |
set -euo pipefail
if [ -z "${NODE_AUTH_TOKEN:-}" ]; then
echo 'npm publication skipped: no existing NPM_TOKEN is configured.'
exit 0
fi
VERSION=$(node -p "require('./package.json').version")
NAME=$(node -p "require('./package.json').name")
if npm view "$NAME@$VERSION" version >/dev/null 2>&1; then
echo "npm $NAME@$VERSION already exists; no changes made."
exit 0
fi
npm publish --ignore-scripts --access public
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,33 @@

All notable changes to this project will be documented in this file.

## [2.5.0] - 2026-10-24

### Fixed
- Preserve unmanaged configurations and roll back failed profile activation.
- Reject untrusted-origin requests and invalid configuration/backup shapes before writes.
- Preserve TypeScript plugin extensions through read and backup/restore flows.
- Keep backend and frontend startup within their supported port ranges.
- Preserve commands when rename writes fail and retain unsaved editor changes.
- Ignore stale file/profile responses and serialize profile mutations.
- Restore the missing agent-deletion confirmation dialog.
- Update vulnerable dependency overrides and add reproducible dependency locks.

### Added
- Source-preserving OpenCode v2 agents, commands, MCP and provider/plugin configuration support.
- Separate global v2 CLI settings with stale-write protection.
- Read-only v2 credential metadata and explicit native-plugin runtime-control limits.
- V1/V2 usage database support without silently hiding database errors.
- Native v2 permission editing, responsive navigation and cross-page stale-write protection.

### Security
- Never return stored legacy auth secrets from the status endpoint.
- Native credential metadata queries never select secret values.

### Tests
- Add synthetic HTTP, profile rollback, frontend interaction and failure-path regressions.
- Add a dependency-isolated regression workflow without protocol-handler registration.

## [2.4.5] - 2026-08-08

### Fixed
Expand Down
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,30 @@

---

### opencode v2 configuration support

The compatibility work targets OpenCode 2.1.4 while retaining supported v1 config
editing. Studio preserves the source format instead of migrating your setup:

- Native `agents` and `commands`, including ordered permission rules and agent
Markdown files; MCP's `servers`, `disabled`, and global timeout settings.
- Native provider model maps and plugin package entries/options.
- Both v1 and v2 usage database layouts, with errors instead of false zero totals
when a database cannot be read.
- A separate **Raw Config → v2 CLI** editor for global `cli.json`. It does not
overwrite `tui.json` or silently prevent first-launch migration.

Important limits: v2 authentication is metadata-only in Studio. Use `opencode auth`
for credential changes and account selection; legacy Studio auth pools are not
applied to v2. V1 plugins need an actual API port, not a renamed config key. Native
plugin runtime controls use plugin IDs, so edit those controls in Raw Config rather
than relying on package-name toggles. Existing plugin code is never auto-converted.

See the [compatibility verification notes](docs/OPENCODE-V2-COMPATIBILITY.md) and
[upstream migration guide](https://opencode.ai/v2/docs/migrate-v1/). End-to-end
native CLI agent discovery remains unverified; this is not a blanket compatibility
claim. Keep a backup, and do not point v1 at native-v2-only configuration.

### quickstart

#### option 1: public site + local backend (recommended)
Expand Down
28 changes: 11 additions & 17 deletions client-next/dev-with-port.js → client-next/dev-with-port.mjs
Original file line number Diff line number Diff line change
@@ -1,34 +1,25 @@
const net = require('net');
const { spawn } = require('child_process');
import { spawn } from "node:child_process";
import { findAvailablePort } from "./scripts/dev-port.mjs";
const DEFAULT_PORT = 1080;

function findAvailablePort(startPort) {
return new Promise((resolve) => {
const server = net.createServer();
server.listen(startPort, () => {
server.once('close', () => resolve(startPort));
server.close();
});
server.on('error', () => {
findAvailablePort(startPort + 1).then(resolve);
});
});
}

findAvailablePort(DEFAULT_PORT).then(port => {
process.env.PORT = port.toString();
console.log(`Starting Next.js on port ${port}`);

const dev = spawn('npx', ['next', 'dev'], {
const dev = spawn(process.execPath, ['node_modules/next/dist/bin/next', 'dev', '--hostname', '127.0.0.1'], {
stdio: 'inherit',
shell: true
shell: false
});

dev.on('error', (err) => {
console.error('Failed to start dev server:', err);
process.exit(1);
});

dev.on('exit', (code, signal) => {
process.exitCode = code ?? (signal ? 1 : 0);
});

process.on('SIGTERM', () => {
dev.kill('SIGTERM');
process.exit(0);
Expand All @@ -38,4 +29,7 @@ findAvailablePort(DEFAULT_PORT).then(port => {
dev.kill('SIGINT');
process.exit(0);
});
}).catch(error => {
console.error('Unable to start development server:', error.message);
process.exitCode = 1;
});
4 changes: 4 additions & 0 deletions client-next/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@
"cancel": "Cancel"
},
"plugins": {
"nativeV2Warning": "OpenCode v2 uses a new plugin API. Existing plugins are not automatically ported. Runtime enable/disable controls require plugin IDs; manage those controls in Raw Config. Package entries and options are preserved.",
"incompatibleWarning": "Incompatible with Antigravity. Use openskills instead.",
"toggleEnabled": "{name} enabled",
"toggleDisabled": "{name} disabled",
Expand Down Expand Up @@ -534,6 +535,9 @@
"delete": "Delete"
},
"agents": {
"nativePermissionsLabel": "Ordered OpenCode v2 permissions (JSON)",
"nativePermissionsHint": "Rules stay in their original order. Use action, resource and effect (ask, allow or deny). Legacy tool switches and temperature do not apply to native v2 agents.",
"invalidNativePermissions": "Enter a valid JSON array of v2 permission rules.",
"sourceJson": "JSON",
"sourceMarkdown": "Markdown",
"sourceBuiltin": "Built-in",
Expand Down
4 changes: 4 additions & 0 deletions client-next/messages/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@
"cancel": "취소"
},
"plugins": {
"nativeV2Warning": "OpenCode v2는 새 플러그인 API를 사용합니다. 기존 플러그인은 자동 변환되지 않습니다. 런타임 활성화/비활성화에는 플러그인 ID가 필요하므로 Raw Config에서 관리하세요. 패키지 항목과 옵션은 보존됩니다.",
"incompatibleWarning": "Antigravity와 호환되지 않습니다. 대신 openskills를 사용하세요.",
"toggleEnabled": "{name}이(가) 활성화되었습니다",
"toggleDisabled": "{name}이(가) 비활성화되었습니다",
Expand Down Expand Up @@ -534,6 +535,9 @@
"delete": "삭제"
},
"agents": {
"nativePermissionsLabel": "OpenCode v2 권한 규칙 (JSON)",
"nativePermissionsHint": "규칙의 순서가 유지됩니다. action, resource, effect(ask, allow, deny)를 사용하세요. 기존 도구 스위치와 temperature는 v2 에이전트에 적용되지 않습니다.",
"invalidNativePermissions": "올바른 v2 권한 규칙 JSON 배열을 입력하세요.",
"sourceJson": "JSON",
"sourceMarkdown": "Markdown",
"sourceBuiltin": "내장",
Expand Down
4 changes: 4 additions & 0 deletions client-next/messages/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@
"cancel": "\u53d6\u6d88"
},
"plugins": {
"nativeV2Warning": "OpenCode v2 使用新的插件 API,不会自动迁移现有插件。运行时启用或禁用需要插件 ID,请在原始配置中管理。软件包条目和选项会保留。",
"incompatibleWarning": "\u4e0e Antigravity \u4e0d\u517c\u5bb9\uff0c\u8bf7\u6539\u7528 openskills\u3002",
"toggleEnabled": "{name} \u5df2\u542f\u7528",
"toggleDisabled": "{name} \u5df2\u7981\u7528",
Expand Down Expand Up @@ -538,6 +539,9 @@
"delete": "\u5220\u9664"
},
"agents": {
"nativePermissionsLabel": "OpenCode v2 有序权限规则(JSON)",
"nativePermissionsHint": "保留规则顺序。使用 action、resource 和 effect(ask、allow 或 deny)。旧版工具开关和 temperature 不适用于原生 v2 代理。",
"invalidNativePermissions": "请输入有效的 v2 权限规则 JSON 数组。",
"sourceJson": "JSON",
"sourceMarkdown": "Markdown",
"sourceBuiltin": "\u5185\u7f6e",
Expand Down
Loading
Loading