diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d5e7c00c7..0503d88b2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -125,7 +125,7 @@ jobs: - name: Install OpenCode CLI run: | source scripts/lib/opencode-release.sh - download_opencode_to 2.2.1 "$RUNNER_TEMP/opencode/bin/opencode" + download_opencode_to 2.2.3 "$RUNNER_TEMP/opencode/bin/opencode" echo "$RUNNER_TEMP/opencode/bin" >> "$GITHUB_PATH" - name: Verify OpenCode CLI diff --git a/AGENTS.md b/AGENTS.md index ada7271d0..7a437ca86 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -49,7 +49,7 @@ - **Dependency Inversion**: Depend on abstractions, not concretions—inject dependencies and avoid hard-coding implementations. - YAGNI: Don’t build or keep code you don’t need. If you change something, remove the unused parts. use the new code or keep the old, but don’t keep both. - Never leave dead code: remove unused code, commented-out blocks, and unused variables/imports. -- `temp/opencode` is a reference clone of OpenCode 2 at tag `v2.0.15` (gitignored, never committed) +- `temp/opencode` is a reference clone of OpenCode 2 at the tag matching `OPENCODE_PINNED_VERSION` (the single pin in `shared/src/opencode/release.ts`; gitignored, never committed) - Use shared types from workspace package (@opencode-manager/shared) - OpenCode server runs on port 5551, backend API on port 5003 - Prefer pnpm over npm for all package management diff --git a/Dockerfile b/Dockerfile index f326643ff..3e96e8503 100644 --- a/Dockerfile +++ b/Dockerfile @@ -63,7 +63,7 @@ FROM base AS runner # an arm64 host builds the amd64 platform; 0.12.7 is the newest verified-good # release, so re-verify a bump there before moving it. ARG UV_VERSION=0.12.7 -ARG OPENCODE_VERSION=2.2.1 +ARG OPENCODE_VERSION=2.2.3 ARG MICROSANDBOX_VERSION=0.7.2 ARG PLAYWRIGHT_VERSION=1.63.0 # Bump TOOLS_CACHEBUST (e.g. via --build-arg) to force a fresh uv/opencode diff --git a/backend/src/services/opencode-server-registry.test.ts b/backend/src/services/opencode-server-registry.test.ts index 219939b1c..69cfde527 100644 --- a/backend/src/services/opencode-server-registry.test.ts +++ b/backend/src/services/opencode-server-registry.test.ts @@ -449,7 +449,7 @@ describe('OpenCodeServerRegistry', () => { describe('test', () => { it('reports a supported version', async () => { - fetchFn.mockResolvedValueOnce(jsonResponse({ version: '2.2.1' })) + fetchFn.mockResolvedValueOnce(jsonResponse({ version: '2.2.3' })) const result = await registry.test({ baseUrl: 'https://studio.example.com/', @@ -457,7 +457,7 @@ describe('OpenCodeServerRegistry', () => { password: 'super-secret', }) - expect(result).toEqual({ ok: true, version: '2.2.1', versionSupported: true, error: null }) + expect(result).toEqual({ ok: true, version: '2.2.3', versionSupported: true, error: null }) expect(fetchFn.mock.calls[0]?.[0]).toBe('https://studio.example.com/api/info') const headers = new Headers(fetchFn.mock.calls[0]?.[1]?.headers) expect(headers.get('authorization')).toBe(`Basic ${btoa('alice:super-secret')}`) @@ -478,7 +478,7 @@ describe('OpenCodeServerRegistry', () => { username: 'alice', password: 'super-secret', }) - fetchFn.mockResolvedValueOnce(jsonResponse({ version: '2.2.1' })) + fetchFn.mockResolvedValueOnce(jsonResponse({ version: '2.2.3' })) const result = await registry.test({ serverId: server.id }) @@ -493,7 +493,7 @@ describe('OpenCodeServerRegistry', () => { baseUrl: 'https://studio.example.com', password: 'super-secret', }) - fetchFn.mockResolvedValueOnce(jsonResponse({ version: '2.2.1' })) + fetchFn.mockResolvedValueOnce(jsonResponse({ version: '2.2.3' })) const result = await registry.test({ baseUrl: 'https://studio.example.com/opencode', @@ -513,7 +513,7 @@ describe('OpenCodeServerRegistry', () => { baseUrl: 'https://studio.example.com', password: 'super-secret', }) - fetchFn.mockResolvedValueOnce(jsonResponse({ version: '2.2.1' })) + fetchFn.mockResolvedValueOnce(jsonResponse({ version: '2.2.3' })) const result = await registry.test({ baseUrl: 'https://relocated.example.com', @@ -533,7 +533,7 @@ describe('OpenCodeServerRegistry', () => { baseUrl: 'https://studio.example.com', password: 'super-secret', }) - fetchFn.mockResolvedValueOnce(jsonResponse({ version: '2.2.1' })) + fetchFn.mockResolvedValueOnce(jsonResponse({ version: '2.2.3' })) await registry.test({ baseUrl: 'https://studio.example.com', diff --git a/backend/test/helpers/opencode-binary.test.ts b/backend/test/helpers/opencode-binary.test.ts index 8b5c50ed6..70cde400f 100644 --- a/backend/test/helpers/opencode-binary.test.ts +++ b/backend/test/helpers/opencode-binary.test.ts @@ -3,7 +3,7 @@ import { EventEmitter } from 'events' import { mkdtemp, rm } from 'fs/promises' import os from 'os' import path from 'path' -import { OPENCODE_SERVER_USERNAME } from '@opencode-manager/shared/opencode' +import { OPENCODE_PINNED_VERSION, OPENCODE_SERVER_USERNAME } from '@opencode-manager/shared/opencode' import { resolveOpenCode2Binary, startOpenCodeServe } from './opencode-binary' const childProcessMock = vi.hoisted(() => ({ @@ -16,7 +16,7 @@ vi.mock('child_process', () => ({ spawn: childProcessMock.spawn, })) -const SUPPORTED_VERSION = '2.2.1' +const SUPPORTED_VERSION = OPENCODE_PINNED_VERSION const OPENCODE_BIN_FIXTURE = '/fixture/opencode-2' const PATH_CANDIDATE = 'opencode' const ABSOLUTE_CANDIDATES = ['/usr/local/bin/opencode', '/opt/opencode/bin/opencode'] diff --git a/backend/test/routes/settings.test.ts b/backend/test/routes/settings.test.ts index 649c19295..d37884c61 100644 --- a/backend/test/routes/settings.test.ts +++ b/backend/test/routes/settings.test.ts @@ -377,7 +377,7 @@ describe('Settings Routes - OpenCode Upgrade', () => { mockInstallOpenCodeVersion.mockResolvedValue('/home/node/.opencode/bin/opencode') clearOpenCodeVersionCache() vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(JSON.stringify({ - versions: { '2.2.1': {} }, + versions: { '2.2.3': {} }, time: {}, }), { status: 200 }))) forceProcessAttestation(true) @@ -757,7 +757,7 @@ describe('Settings Routes - OpenCode Upgrade', () => { describe('successful upgrade scenarios', () => { it('should install the latest version and respond with success', async () => { mockGetVersion.mockReturnValueOnce('2.1.1') - mockFetchVersion.mockResolvedValueOnce('2.2.1') + mockFetchVersion.mockResolvedValueOnce('2.2.3') mockInstallOpenCodeVersion.mockResolvedValueOnce('/home/node/.opencode/bin/opencode') const req = new Request('http://localhost/opencode-upgrade', { @@ -770,13 +770,13 @@ describe('Settings Routes - OpenCode Upgrade', () => { expect(json.success).toBe(true) expect(json.upgraded).toBe(true) expect(json.oldVersion).toBe('2.1.1') - expect(json.newVersion).toBe('2.2.1') - expect(json.message).toBe('OpenCode upgraded from v2.1.1 to v2.2.1 and restarted') - expect(mockInstallOpenCodeVersion).toHaveBeenCalledWith('2.2.1') + expect(json.newVersion).toBe('2.2.3') + expect(json.message).toBe('OpenCode upgraded from v2.1.1 to v2.2.3 and restarted') + expect(mockInstallOpenCodeVersion).toHaveBeenCalledWith('2.2.3') }) it('should not install when the latest version is not newer', async () => { - mockGetVersion.mockReturnValueOnce('2.2.1') + mockGetVersion.mockReturnValueOnce('2.2.3') const req = new Request('http://localhost/opencode-upgrade', { method: 'POST' @@ -794,7 +794,7 @@ describe('Settings Routes - OpenCode Upgrade', () => { it('should replace an unsupported newer major with the latest supported release', async () => { mockGetVersion.mockReturnValueOnce('3.0.0') - mockFetchVersion.mockResolvedValueOnce('2.2.1') + mockFetchVersion.mockResolvedValueOnce('2.2.3') mockInstallOpenCodeVersion.mockResolvedValueOnce('/home/node/.opencode/bin/opencode') const res = await settingsApp.fetch(new Request('http://localhost/opencode-upgrade', { method: 'POST' })) @@ -802,12 +802,12 @@ describe('Settings Routes - OpenCode Upgrade', () => { expect(res.status).toBe(200) expect(json.upgraded).toBe(true) - expect(mockInstallOpenCodeVersion).toHaveBeenCalledWith('2.2.1') + expect(mockInstallOpenCodeVersion).toHaveBeenCalledWith('2.2.3') }) it('should restart directly after a successful upgrade', async () => { mockGetVersion.mockReturnValueOnce('2.1.1') - mockFetchVersion.mockResolvedValueOnce('2.2.1') + mockFetchVersion.mockResolvedValueOnce('2.2.3') mockInstallOpenCodeVersion.mockResolvedValueOnce('/home/node/.opencode/bin/opencode') const req = new Request('http://localhost/opencode-upgrade', { @@ -821,13 +821,13 @@ describe('Settings Routes - OpenCode Upgrade', () => { it('allows upgrading while sandbox enforcement is active', async () => { mockIsSandboxEnforced.mockReturnValue(true) mockGetVersion.mockReturnValueOnce('2.1.1') - mockFetchVersion.mockResolvedValueOnce('2.2.1') + mockFetchVersion.mockResolvedValueOnce('2.2.3') mockInstallOpenCodeVersion.mockResolvedValueOnce('/home/node/.opencode/bin/opencode') const res = await settingsApp.fetch(new Request('http://localhost/opencode-upgrade', { method: 'POST' })) expect(res.status).toBe(200) - expect(mockInstallOpenCodeVersion).toHaveBeenCalledWith('2.2.1') + expect(mockInstallOpenCodeVersion).toHaveBeenCalledWith('2.2.3') expect(mockRestart).toHaveBeenCalled() }) }) @@ -896,7 +896,7 @@ describe('Settings Routes - OpenCode Upgrade', () => { describe('version handling', () => { it('should install and restart when getVersion returns null', async () => { mockGetVersion.mockReturnValueOnce(null) - mockFetchVersion.mockResolvedValueOnce('2.2.1') + mockFetchVersion.mockResolvedValueOnce('2.2.3') mockInstallOpenCodeVersion.mockResolvedValueOnce('/home/node/.opencode/bin/opencode') const req = new Request('http://localhost/opencode-upgrade', { @@ -909,8 +909,8 @@ describe('Settings Routes - OpenCode Upgrade', () => { expect(json.success).toBe(true) expect(json.upgraded).toBe(true) expect(json.oldVersion).toBe(null) - expect(json.newVersion).toBe('2.2.1') - expect(json.message).toBe('OpenCode v2.2.1 installed and restarted') + expect(json.newVersion).toBe('2.2.3') + expect(json.message).toBe('OpenCode v2.2.3 installed and restarted') expect(mockFetchVersion).toHaveBeenCalled() expect(mockClearStartupError).toHaveBeenCalled() expect(mockRestart).toHaveBeenCalledTimes(1) @@ -932,7 +932,7 @@ describe('Settings Routes - OpenCode Upgrade', () => { expect(json.upgraded).toBe(false) expect(json.recovered).toBe(true) expect(json.error).toBe('Upgrade failed but server recovered') - expect(json.details).toContain('did not result in version 2.2.1') + expect(json.details).toContain('did not result in version 2.2.3') expect(mockRestart).toHaveBeenCalledTimes(1) }) @@ -949,7 +949,7 @@ describe('Settings Routes - OpenCode Upgrade', () => { expect(json.upgraded).toBe(false) expect(json.recovered).toBe(true) expect(json.error).toBe('Upgrade failed but server recovered') - expect(json.details).toContain('did not result in version 2.2.1') + expect(json.details).toContain('did not result in version 2.2.3') expect(mockRestart).toHaveBeenCalledTimes(1) }) }) @@ -959,12 +959,12 @@ describe('Settings Routes - OpenCode Upgrade', () => { describe('successful installation', () => { it('should install specific version successfully', async () => { mockGetVersion.mockReturnValueOnce('2.1.1') - mockFetchVersion.mockResolvedValueOnce('2.2.1') + mockFetchVersion.mockResolvedValueOnce('2.2.3') mockInstallOpenCodeVersion.mockResolvedValueOnce('/home/node/.opencode/bin/opencode') const req = new Request('http://localhost/opencode-install-version', { method: 'POST', - body: JSON.stringify({ version: '2.2.1' }), + body: JSON.stringify({ version: '2.2.3' }), headers: { 'Content-Type': 'application/json' } }) const res = await settingsApp.fetch(req) @@ -972,8 +972,8 @@ describe('Settings Routes - OpenCode Upgrade', () => { expect(res.status).toBe(200) expect(json.success).toBe(true) - expect(json.newVersion).toBe('2.2.1') - expect(mockInstallOpenCodeVersion).toHaveBeenCalledWith('2.2.1') + expect(json.newVersion).toBe('2.2.3') + expect(mockInstallOpenCodeVersion).toHaveBeenCalledWith('2.2.3') }) it('does not report success when the requested version was not installed', async () => { @@ -983,46 +983,46 @@ describe('Settings Routes - OpenCode Upgrade', () => { const res = await settingsApp.fetch(new Request('http://localhost/opencode-install-version', { method: 'POST', - body: JSON.stringify({ version: '2.2.1' }), + body: JSON.stringify({ version: '2.2.3' }), headers: { 'Content-Type': 'application/json' } })) const json = await res.json() as Record expect(res.status).toBe(400) expect(json.success).toBe(false) - expect(json.details).toContain('did not result in version 2.2.1') + expect(json.details).toContain('did not result in version 2.2.3') expect(json.newVersion).toBe('2.1.1') }) it('allows installing any version while sandbox enforcement is active', async () => { mockIsSandboxEnforced.mockReturnValue(true) mockGetVersion.mockReturnValueOnce('2.1.1') - mockFetchVersion.mockResolvedValueOnce('2.2.1') + mockFetchVersion.mockResolvedValueOnce('2.2.3') mockInstallOpenCodeVersion.mockResolvedValueOnce('/home/node/.opencode/bin/opencode') const res = await settingsApp.fetch(new Request('http://localhost/opencode-install-version', { method: 'POST', - body: JSON.stringify({ version: '2.2.1' }), + body: JSON.stringify({ version: '2.2.3' }), headers: { 'Content-Type': 'application/json' } })) expect(res.status).toBe(200) - expect(mockInstallOpenCodeVersion).toHaveBeenCalledWith('2.2.1') + expect(mockInstallOpenCodeVersion).toHaveBeenCalledWith('2.2.3') }) it('should install the bare version when the request carries a v prefix', async () => { mockGetVersion.mockReturnValueOnce('2.1.1') - mockFetchVersion.mockResolvedValueOnce('2.2.1') + mockFetchVersion.mockResolvedValueOnce('2.2.3') mockInstallOpenCodeVersion.mockResolvedValueOnce('/home/node/.opencode/bin/opencode') const req = new Request('http://localhost/opencode-install-version', { method: 'POST', - body: JSON.stringify({ version: 'v2.2.1' }), + body: JSON.stringify({ version: 'v2.2.3' }), headers: { 'Content-Type': 'application/json' } }) await settingsApp.fetch(req) - expect(mockInstallOpenCodeVersion).toHaveBeenCalledWith('2.2.1') + expect(mockInstallOpenCodeVersion).toHaveBeenCalledWith('2.2.3') }) }) @@ -1035,7 +1035,7 @@ describe('Settings Routes - OpenCode Upgrade', () => { const req = new Request('http://localhost/opencode-install-version', { method: 'POST', - body: JSON.stringify({ version: '2.2.1' }), + body: JSON.stringify({ version: '2.2.3' }), headers: { 'Content-Type': 'application/json' } }) const res = await settingsApp.fetch(req) @@ -1052,7 +1052,7 @@ describe('Settings Routes - OpenCode Upgrade', () => { const req = new Request('http://localhost/opencode-install-version', { method: 'POST', - body: JSON.stringify({ version: '2.2.1' }), + body: JSON.stringify({ version: '2.2.3' }), headers: { 'Content-Type': 'application/json' } }) const res = await settingsApp.fetch(req) @@ -1119,11 +1119,11 @@ describe('Settings Routes - OpenCode Upgrade', () => { const json = await res.json() as Record expect(res.status).toBe(400) - expect(json.error).toBe('OpenCode 1.18.32 is not supported; OpenCode Manager requires OpenCode >=2.2.1 <3.0.0') + expect(json.error).toBe('OpenCode 1.18.32 is not supported; OpenCode Manager requires OpenCode >=2.2.3 <3.0.0') expect(mockInstallOpenCodeVersion).not.toHaveBeenCalled() }) - it.each(['2.2.0', '3.0.0'])('should reject %s outside the supported range before installing anything', async (version) => { + it.each(['2.2.2', '3.0.0'])('should reject %s outside the supported range before installing anything', async (version) => { const res = await settingsApp.fetch(new Request('http://localhost/opencode-install-version', { method: 'POST', body: JSON.stringify({ version }), @@ -1132,14 +1132,14 @@ describe('Settings Routes - OpenCode Upgrade', () => { const json = await res.json() as Record expect(res.status).toBe(400) - expect(json.error).toBe(`OpenCode ${version} is not supported; OpenCode Manager requires OpenCode >=2.2.1 <3.0.0`) + expect(json.error).toBe(`OpenCode ${version} is not supported; OpenCode Manager requires OpenCode >=2.2.3 <3.0.0`) expect(mockInstallOpenCodeVersion).not.toHaveBeenCalled() }) it('should reject a prerelease version before installing anything', async () => { const res = await settingsApp.fetch(new Request('http://localhost/opencode-install-version', { method: 'POST', - body: JSON.stringify({ version: '2.2.1-beta.1' }), + body: JSON.stringify({ version: '2.2.3-beta.1' }), headers: { 'Content-Type': 'application/json' } })) @@ -1176,7 +1176,7 @@ describe('Settings Routes - OpenCode Upgrade', () => { const res = await settingsApp.fetch(new Request('http://localhost/opencode-install-version', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ version: '2.2.1' }), + body: JSON.stringify({ version: '2.2.3' }), })) const json = await res.json() as Record @@ -1953,8 +1953,8 @@ describe('Settings Routes - versions, directory files, skills, MCP and maintenan fetchMock = vi.fn() vi.stubGlobal('fetch', fetchMock) clearOpenCodeVersionCache() - mockGetVersion.mockReturnValue('2.2.1') - mockFetchVersion.mockResolvedValue('2.2.1') + mockGetVersion.mockReturnValue('2.2.3') + mockFetchVersion.mockResolvedValue('2.2.3') mockInstallOpenCodeVersion.mockReset() mockInstallOpenCodeVersion.mockResolvedValue('/home/node/.opencode/bin/opencode') mockClearStartupError.mockReturnValue(undefined) @@ -1977,14 +1977,14 @@ describe('Settings Routes - versions, directory files, skills, MCP and maintenan versions: { '1.18.32': {}, '2.1.1': {}, - '2.2.1': {}, - '2.2.2': {}, - '2.2.1-beta.1': {}, + '2.2.3': {}, + '2.2.4': {}, + '2.2.3-beta.1': {}, '3.0.0': {}, }, time: { - '2.2.1': '2026-01-02T00:00:00Z', - '2.2.2': '2026-01-03T00:00:00Z', + '2.2.3': '2026-01-02T00:00:00Z', + '2.2.4': '2026-01-03T00:00:00Z', }, }), { status: 200 })) @@ -1992,16 +1992,16 @@ describe('Settings Routes - versions, directory files, skills, MCP and maintenan const json = await res.json() as { versions: Array<{ version: string; tag: string; name: string; publishedAt: string | null }>; currentVersion: string } expect(res.status).toBe(200) - expect(json.currentVersion).toBe('2.2.1') + expect(json.currentVersion).toBe('2.2.3') expect(json.versions).toEqual([ - { version: '2.2.2', tag: 'v2.2.2', name: 'v2.2.2', publishedAt: '2026-01-03T00:00:00Z' }, - { version: '2.2.1', tag: 'v2.2.1', name: 'v2.2.1', publishedAt: '2026-01-02T00:00:00Z' }, + { version: '2.2.4', tag: 'v2.2.4', name: 'v2.2.4', publishedAt: '2026-01-03T00:00:00Z' }, + { version: '2.2.3', tag: 'v2.2.3', name: 'v2.2.3', publishedAt: '2026-01-02T00:00:00Z' }, ]) expect(fetchMock).toHaveBeenCalledWith('https://registry.npmjs.org/@opencode/cli') }) it('serves repeated requests from the installer cache', async () => { - fetchMock.mockImplementation(async () => new Response(JSON.stringify({ versions: { '2.2.1': {} }, time: {} }), { status: 200 })) + fetchMock.mockImplementation(async () => new Response(JSON.stringify({ versions: { '2.2.3': {} }, time: {} }), { status: 200 })) await app.request(new Request('http://localhost/opencode-versions')) const res = await app.request(new Request('http://localhost/opencode-versions')) @@ -2039,35 +2039,35 @@ describe('Settings Routes - versions, directory files, skills, MCP and maintenan describe('POST /opencode-install-version', () => { it('installs the requested version and restarts the server', async () => { mockGetVersion.mockReturnValue('2.1.1') - mockFetchVersion.mockResolvedValue('2.2.1') + mockFetchVersion.mockResolvedValue('2.2.3') mockInstallOpenCodeVersion.mockResolvedValueOnce('/home/node/.opencode/bin/opencode') const res = await app.request(new Request('http://localhost/opencode-install-version', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ version: '2.2.1' }), + body: JSON.stringify({ version: '2.2.3' }), })) const json = await res.json() as { success: boolean; message: string; oldVersion: string; newVersion: string } expect(res.status).toBe(200) expect(json.success).toBe(true) expect(json.oldVersion).toBe('2.1.1') - expect(json.newVersion).toBe('2.2.1') - expect(json.message).toContain('changed from v2.1.1 to v2.2.1') + expect(json.newVersion).toBe('2.2.3') + expect(json.message).toContain('changed from v2.1.1 to v2.2.3') expect(supervisor.restart).toHaveBeenCalledTimes(1) - expect(mockInstallOpenCodeVersion).toHaveBeenCalledWith('2.2.1') + expect(mockInstallOpenCodeVersion).toHaveBeenCalledWith('2.2.3') }) it('returns 500 without restarting when the version install fails before the binary swap', async () => { mockGetVersion.mockReturnValue('2.1.1') - mockFetchVersion.mockResolvedValue('2.2.1') + mockFetchVersion.mockResolvedValue('2.2.3') mockInstallOpenCodeVersion.mockRejectedValueOnce(new Error('download failed')) supervisor.restart.mockResolvedValue({ healthy: false }) const res = await app.request(new Request('http://localhost/opencode-install-version', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ version: '2.2.1' }), + body: JSON.stringify({ version: '2.2.3' }), })) const json = await res.json() as { recovered: boolean; newVersion: string } diff --git a/backend/test/services/opencode-installer.test.ts b/backend/test/services/opencode-installer.test.ts index a358f22e7..fb539c80d 100644 --- a/backend/test/services/opencode-installer.test.ts +++ b/backend/test/services/opencode-installer.test.ts @@ -131,46 +131,46 @@ describe('resolveOpenCodeInstallTarget', () => { describe('installOpenCodeVersion', () => { it('downloads, verifies and installs the requested version', async () => { const homeDirectory = join(workDirectory, 'home') - const archivePath = createArchive(workDirectory, '2.2.1') + const archivePath = createArchive(workDirectory, '2.2.3') const { calls, fetchFn } = createFetch(archivePath) - const installedPath = await installOpenCodeVersion('2.2.1', { fetch: fetchFn, homeDirectory, target: linuxTarget }) + const installedPath = await installOpenCodeVersion('2.2.3', { fetch: fetchFn, homeDirectory, target: linuxTarget }) expect(installedPath).toBe(resolveOpenCodeBinaryPath(homeDirectory)) - expect(calls).toEqual(['https://opencode.ai/files/bin/2.2.1/opencode-linux-x64.tar.gz']) + expect(calls).toEqual(['https://opencode.ai/files/bin/2.2.3/opencode-linux-x64.tar.gz']) expect(statSync(installedPath).mode & 0o777).toBe(0o755) - expect(readFileSync(installedPath, 'utf-8')).toContain('2.2.1') + expect(readFileSync(installedPath, 'utf-8')).toContain('2.2.3') }) it('requests the musl asset for a musl linux target', async () => { const homeDirectory = join(workDirectory, 'home') - const archivePath = createArchive(workDirectory, '2.2.1') + const archivePath = createArchive(workDirectory, '2.2.3') const { calls, fetchFn } = createFetch(archivePath) - await installOpenCodeVersion('2.2.1', { + await installOpenCodeVersion('2.2.3', { fetch: fetchFn, homeDirectory, target: { platform: 'linux', arch: 'arm64', musl: true }, }) - expect(calls).toEqual(['https://opencode.ai/files/bin/2.2.1/opencode-linux-arm64-musl.tar.gz']) + expect(calls).toEqual(['https://opencode.ai/files/bin/2.2.3/opencode-linux-arm64-musl.tar.gz']) }) it('extracts the darwin zip asset and installs it', async () => { const homeDirectory = join(workDirectory, 'home') - const archivePath = createDarwinArchive(workDirectory, '2.2.1') + const archivePath = createDarwinArchive(workDirectory, '2.2.3') const { calls, fetchFn } = createFetch(archivePath) - const installedPath = await installOpenCodeVersion('2.2.1', { + const installedPath = await installOpenCodeVersion('2.2.3', { fetch: fetchFn, homeDirectory, target: { platform: 'darwin', arch: 'arm64', musl: false }, }) - expect(calls).toEqual(['https://opencode.ai/files/bin/2.2.1/opencode-darwin-arm64.zip']) + expect(calls).toEqual(['https://opencode.ai/files/bin/2.2.3/opencode-darwin-arm64.zip']) expect(installedPath).toBe(resolveOpenCodeBinaryPath(homeDirectory)) expect(statSync(installedPath).mode & 0o777).toBe(0o755) - expect(readFileSync(installedPath, 'utf-8')).toContain('2.2.1') + expect(readFileSync(installedPath, 'utf-8')).toContain('2.2.3') }) it('rejects an OpenCode 1.x version before downloading anything', async () => { @@ -178,18 +178,18 @@ describe('installOpenCodeVersion', () => { const { calls, fetchFn } = createFetch(null) await expect(installOpenCodeVersion('1.18.32', { fetch: fetchFn, homeDirectory, target: linuxTarget })) - .rejects.toThrow('OpenCode 1.18.32 is not supported; OpenCode Manager requires OpenCode >=2.2.1 <3.0.0') + .rejects.toThrow('OpenCode 1.18.32 is not supported; OpenCode Manager requires OpenCode >=2.2.3 <3.0.0') expect(calls).toEqual([]) }) - it.each(['2.2.0', '3.0.0', '2.2.1-beta.1', '2.2.1; rm -rf /'])( + it.each(['2.2.2', '3.0.0', '2.2.3-beta.1', '2.2.3; rm -rf /'])( 'rejects %s outside the supported stable range before downloading anything', async (version) => { const homeDirectory = join(workDirectory, 'home') const { calls, fetchFn } = createFetch(null) await expect(installOpenCodeVersion(version, { fetch: fetchFn, homeDirectory, target: linuxTarget })) - .rejects.toThrow(/requires OpenCode >=2\.2\.1 <3\.0\.0/) + .rejects.toThrow(/requires OpenCode >=2\.2\.3 <3\.0\.0/) expect(calls).toEqual([]) }, ) @@ -198,18 +198,18 @@ describe('installOpenCodeVersion', () => { const homeDirectory = join(workDirectory, 'home') const { fetchFn } = createFetch(null, 404) - await expect(installOpenCodeVersion('2.2.1', { fetch: fetchFn, homeDirectory, target: linuxTarget })) + await expect(installOpenCodeVersion('2.2.3', { fetch: fetchFn, homeDirectory, target: linuxTarget })) .rejects.toThrow(/404/) expect(() => statSync(resolveOpenCodeBinaryPath(homeDirectory))).toThrow() }) it('fails and leaves no binary behind when the archive reports a different version', async () => { const homeDirectory = join(workDirectory, 'home') - const archivePath = createArchive(workDirectory, '2.2.2') + const archivePath = createArchive(workDirectory, '2.2.4') const { fetchFn } = createFetch(archivePath) - await expect(installOpenCodeVersion('2.2.1', { fetch: fetchFn, homeDirectory, target: linuxTarget })) - .rejects.toThrow(/2\.2\.1/) + await expect(installOpenCodeVersion('2.2.3', { fetch: fetchFn, homeDirectory, target: linuxTarget })) + .rejects.toThrow(/2\.2\.3/) expect(() => statSync(resolveOpenCodeBinaryPath(homeDirectory))).toThrow() }) @@ -218,21 +218,21 @@ describe('installOpenCodeVersion', () => { mkdirSync(join(homeDirectory, '.opencode', 'bin'), { recursive: true }) writeFileSync(resolveOpenCodeBinaryPath(homeDirectory), '#!/bin/sh\necho "opencode v2.1.1"\n') - const archivePath = createArchive(workDirectory, '2.2.1') + const archivePath = createArchive(workDirectory, '2.2.3') const { fetchFn } = createFetch(archivePath) - await installOpenCodeVersion('2.2.1', { fetch: fetchFn, homeDirectory, target: linuxTarget }) + await installOpenCodeVersion('2.2.3', { fetch: fetchFn, homeDirectory, target: linuxTarget }) - expect(readFileSync(resolveOpenCodeBinaryPath(homeDirectory), 'utf-8')).toContain('2.2.1') + expect(readFileSync(resolveOpenCodeBinaryPath(homeDirectory), 'utf-8')).toContain('2.2.3') }) it('cleans up its staging directory after a successful install', async () => { const homeDirectory = join(workDirectory, 'home') - const archivePath = createArchive(workDirectory, '2.2.1') + const archivePath = createArchive(workDirectory, '2.2.3') const { fetchFn } = createFetch(archivePath) const before = countStagingDirectories() - await installOpenCodeVersion('2.2.1', { fetch: fetchFn, homeDirectory, target: linuxTarget }) + await installOpenCodeVersion('2.2.3', { fetch: fetchFn, homeDirectory, target: linuxTarget }) expect(countStagingDirectories()).toBe(before) }) @@ -247,12 +247,14 @@ describe('listOpenCodeVersions', () => { '2.2.1': {}, '2.2.2': {}, '2.2.1-beta.1': {}, + '2.2.3': {}, + '2.2.4': {}, '3.0.0': {}, 'not-a-version': {}, }, time: { - '2.2.1': '2026-02-01T00:00:00.000Z', - '2.2.2': '2026-03-01T00:00:00.000Z', + '2.2.3': '2026-04-01T00:00:00.000Z', + '2.2.4': '2026-05-01T00:00:00.000Z', }, } @@ -262,8 +264,8 @@ describe('listOpenCodeVersions', () => { const versions = await listOpenCodeVersions({ fetch: fetchFn }) expect(versions).toEqual([ - { version: '2.2.2', publishedAt: '2026-03-01T00:00:00.000Z' }, - { version: '2.2.1', publishedAt: '2026-02-01T00:00:00.000Z' }, + { version: '2.2.4', publishedAt: '2026-05-01T00:00:00.000Z' }, + { version: '2.2.3', publishedAt: '2026-04-01T00:00:00.000Z' }, ]) expect(calls).toEqual(['https://registry.npmjs.org/@opencode/cli']) }) @@ -331,7 +333,7 @@ describe('OpenCodeInstallError swap signalling', () => { const homeDirectory = join(workDirectory, 'home') const { fetchFn } = createFetch(null, 404) - const promise = installOpenCodeVersion('2.2.1', { fetch: fetchFn, homeDirectory, target: linuxTarget }) + const promise = installOpenCodeVersion('2.2.3', { fetch: fetchFn, homeDirectory, target: linuxTarget }) await expect(promise).rejects.toBeInstanceOf(OpenCodeInstallError) await expect(promise).rejects.toMatchObject({ swapStarted: false }) @@ -341,10 +343,10 @@ describe('OpenCodeInstallError swap signalling', () => { it('marks a failure while replacing the binary as having started the binary swap', async () => { const homeDirectory = join(workDirectory, 'home') mkdirSync(resolveOpenCodeBinaryPath(homeDirectory), { recursive: true }) - const archivePath = createArchive(workDirectory, '2.2.1') + const archivePath = createArchive(workDirectory, '2.2.3') const { fetchFn } = createFetch(archivePath) - const promise = installOpenCodeVersion('2.2.1', { fetch: fetchFn, homeDirectory, target: linuxTarget }) + const promise = installOpenCodeVersion('2.2.3', { fetch: fetchFn, homeDirectory, target: linuxTarget }) await expect(promise).rejects.toBeInstanceOf(OpenCodeInstallError) await expect(promise).rejects.toMatchObject({ swapStarted: true }) diff --git a/backend/test/services/opencode-single-server.test.ts b/backend/test/services/opencode-single-server.test.ts index 39808c733..15821c52c 100644 --- a/backend/test/services/opencode-single-server.test.ts +++ b/backend/test/services/opencode-single-server.test.ts @@ -3,7 +3,7 @@ import { describe, it, expect, vi, beforeEach, afterEach, beforeAll } from 'vite const createOpenCodeClientMock = vi.hoisted(() => vi.fn(() => ({ api: { server: { - info: vi.fn().mockResolvedValue({ version: '2.2.1', pid: 1234, urls: ['http://127.0.0.1:5551'], paths: { tmp: '/tmp' } }), + info: vi.fn().mockResolvedValue({ version: '2.2.3', pid: 1234, urls: ['http://127.0.0.1:5551'], paths: { tmp: '/tmp' } }), }, }, forwardRaw: vi.fn(), @@ -354,7 +354,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return spawnMock.mock.calls.length > 0 ? '1234\n' : '' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) setOpenCodeEnv({ host: '0.0.0.0', password: 'envpassword123' }) @@ -382,7 +382,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return spawnMock.mock.calls.length > 0 ? '1234\n' : '' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) setOpenCodeEnv({ host: '0.0.0.0', password: '' }) @@ -420,7 +420,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return spawnMock.mock.calls.length > 0 ? '1234\n' : '' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) const { OpenCodeServerManager } = await import('../../src/services/opencode-single-server') @@ -539,7 +539,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return spawnMock.mock.calls.length > 0 ? '1234\n' : '' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) const savedEnv = snapshotMicrosandboxEnv() @@ -782,7 +782,7 @@ describe('OpenCodeServerManager - server auth', () => { let capturedSignal: AbortSignal | undefined const info = vi.fn(async (options: { signal?: AbortSignal }) => { capturedSignal = options.signal - return { version: '2.2.1', pid: 1234, urls: ['http://127.0.0.1:5551'], paths: { tmp: '/tmp' } } + return { version: '2.2.3', pid: 1234, urls: ['http://127.0.0.1:5551'], paths: { tmp: '/tmp' } } }) createOpenCodeClientMock.mockImplementationOnce(() => ({ api: { server: { info } }, @@ -812,7 +812,7 @@ describe('OpenCodeServerManager - server auth', () => { capturedSignal = options.signal queueMicrotask(() => emitExit(1, null)) return new Promise((resolve) => { - setTimeout(() => resolve({ version: '2.2.1', pid: 1234, urls: [], paths: { tmp: '/tmp' } }), 0) + setTimeout(() => resolve({ version: '2.2.3', pid: 1234, urls: [], paths: { tmp: '/tmp' } }), 0) }) }) createOpenCodeClientMock.mockImplementationOnce(() => ({ @@ -861,7 +861,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return spawnMock.mock.calls.length > 0 ? '1234\n' : '' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) const { OpenCodeServerManager } = await import('../../src/services/opencode-single-server') @@ -949,7 +949,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return spawnMock.mock.calls.length > 0 ? '1234\n' : '' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) const { OpenCodeServerManager } = await import('../../src/services/opencode-single-server') @@ -1035,7 +1035,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return spawnMock.mock.calls.length > 0 ? '1234\n' : '' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) manager.setDatabase(createPasswordDb(null)) @@ -1148,7 +1148,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return spawnMock.mock.calls.length > 0 ? '1234\n' : '' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) const { OpenCodeServerManager } = await import('../../src/services/opencode-single-server') @@ -1198,7 +1198,7 @@ describe('OpenCodeServerManager - server auth', () => { if (cmd.includes('lsof')) { return spawnMock.mock.calls.length > 0 ? '1234\n' : '9999\n' } - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) const { OpenCodeServerManager } = await import('../../src/services/opencode-single-server') @@ -1945,7 +1945,7 @@ describe('OpenCodeServerManager - server auth', () => { if (cmd.includes('lsof')) { return spawnMock.mock.calls.length > 0 ? '1234\n' : '9999\n' } - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) readFileSyncMock.mockReturnValue(procStatStringWithGroup(9999, '42')) @@ -2002,7 +2002,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return spawnMock.mock.calls.length > 0 ? '1234\n' : '' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) readdirSyncMock.mockReturnValue(['10001']) @@ -2081,7 +2081,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return '' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) readdirSyncMock.mockReturnValue(['10001']) @@ -2144,7 +2144,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return spawnMock.mock.calls.length > 0 ? '1234\n' : '' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) readFileSyncMock.mockImplementation((filePath: string) => { @@ -2200,7 +2200,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return '9999\n' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) readFileSyncMock.mockReturnValue(procStatStringWithGroup(9999, '42')) @@ -2242,7 +2242,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return '9998\n' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) killSpy.mockImplementation(((pid: number, signal?: number | string) => { @@ -2279,7 +2279,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return '9997\n' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) killSpy.mockImplementation(((pid: number, signal?: number | string) => { @@ -2311,7 +2311,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return spawnMock.mock.calls.length > 0 ? '8888\n' : '' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) killSpy.mockImplementation(((pid: number, signal?: number | string) => { @@ -2986,7 +2986,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return '' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) installManagedPluginsMock.mockRejectedValueOnce(new Error('readonly filesystem')) @@ -3018,7 +3018,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return spawnMock.mock.calls.length > 0 ? '1234\n' : '' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) const { OpenCodeServerManager } = await import('../../src/services/opencode-single-server') @@ -3049,7 +3049,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return spawnMock.mock.calls.length > 0 ? '1234\n' : '' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) const { OpenCodeServerManager } = await import('../../src/services/opencode-single-server') @@ -3077,7 +3077,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return spawnMock.mock.calls.length > 0 ? '1234\n' : '' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) restoreQuarantinedOpenCodePluginsMock.mockRejectedValueOnce(new Error('readonly filesystem')) @@ -3108,7 +3108,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return '' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) installManagedPluginsMock.mockRejectedValueOnce(new Error('readonly filesystem')) @@ -3140,7 +3140,7 @@ describe('OpenCodeServerManager - server auth', () => { })) execSyncMock.mockImplementation((cmd: string) => { if (cmd.includes('lsof')) return spawnMock.mock.calls.length > 0 ? '1234\n' : '' - if (cmd.includes('opencode --version')) return '2.2.1\n' + if (cmd.includes('opencode --version')) return '2.2.3\n' throw new Error('not found') }) const { OpenCodeServerManager } = await import('../../src/services/opencode-single-server') @@ -3176,7 +3176,7 @@ describe('OpenCodeServerManager - server auth', () => { await expect(manager.start()).rejects.toThrow('OpenCode 1.18.32 is not supported') expect(spawnMock).not.toHaveBeenCalled() - expect(manager.getLastStartupError()).toContain('requires OpenCode >=2.2.1 <3.0.0') + expect(manager.getLastStartupError()).toContain('requires OpenCode >=2.2.3 <3.0.0') expect(manager.isLastStartupErrorNonRecoverable()).toBe(true) }) @@ -3185,7 +3185,7 @@ describe('OpenCodeServerManager - server auth', () => { isEnabled: () => false, })) execSyncMock.mockImplementation((cmd: string) => { - if (cmd.includes('opencode --version')) return 'opencode v2.2.1\n' + if (cmd.includes('opencode --version')) return 'opencode v2.2.3\n' throw new Error('not found') }) const { OpenCodeServerManager } = await import('../../src/services/opencode-single-server') @@ -3195,7 +3195,7 @@ describe('OpenCodeServerManager - server auth', () => { await manager.start() expect(spawnMock).toHaveBeenCalled() - expect(manager.getVersion()).toBe('2.2.1') + expect(manager.getVersion()).toBe('2.2.3') expect(manager.isVersionSupported()).toBe(true) }) @@ -3216,7 +3216,7 @@ describe('OpenCodeServerManager - server auth', () => { marked = true manager.markRestartPending() } - return { version: '2.2.1', pid: 1234, urls: [], paths: { tmp: '/tmp' } } + return { version: '2.2.3', pid: 1234, urls: [], paths: { tmp: '/tmp' } } }), }, }, @@ -3420,7 +3420,7 @@ describe('ConfigReloadError', () => { }) describe('OpenCodeServerManager - checkHealth', () => { - const serverInfo = { version: '2.2.1', pid: 1234, urls: ['http://127.0.0.1:5551'], paths: { tmp: '/tmp' } } + const serverInfo = { version: '2.2.3', pid: 1234, urls: ['http://127.0.0.1:5551'], paths: { tmp: '/tmp' } } it('probes GET /api/info through the API client and returns true for a ServerInfo response', async () => { const { opencodeServerManager } = await import('../../src/services/opencode-single-server') diff --git a/backend/test/shared/opencode-contract.test.ts b/backend/test/shared/opencode-contract.test.ts index 471d225e7..0e6451dd3 100644 --- a/backend/test/shared/opencode-contract.test.ts +++ b/backend/test/shared/opencode-contract.test.ts @@ -50,8 +50,8 @@ function createFetchSpy() { describe('OpenCode v2 contract', () => { describe('version policy', () => { it('pins the client version, derives the floor from it and fixes the V2 server username', () => { - expect(OPENCODE_PINNED_VERSION).toBe('2.2.1') - expect(OPENCODE_SUPPORTED_VERSION_RANGE).toBe('>=2.2.1 <3.0.0') + expect(OPENCODE_PINNED_VERSION).toBe('2.2.3') + expect(OPENCODE_SUPPORTED_VERSION_RANGE).toBe('>=2.2.3 <3.0.0') expect(OPENCODE_SERVER_USERNAME).toBe('opencode') }) @@ -62,47 +62,49 @@ describe('OpenCode v2 contract', () => { expect(isSupportedOpenCodeVersion('2.1.0')).toBe(false) expect(isSupportedOpenCodeVersion('2.1.1')).toBe(false) expect(isSupportedOpenCodeVersion('2.2.0')).toBe(false) - expect(isSupportedOpenCodeVersion('2.2.1')).toBe(true) - expect(isSupportedOpenCodeVersion('2.2.2')).toBe(true) + expect(isSupportedOpenCodeVersion('2.2.1')).toBe(false) + expect(isSupportedOpenCodeVersion('2.2.2')).toBe(false) + expect(isSupportedOpenCodeVersion('2.2.3')).toBe(true) + expect(isSupportedOpenCodeVersion('2.2.4')).toBe(true) expect(isSupportedOpenCodeVersion('2.3.0')).toBe(true) - expect(isSupportedOpenCodeVersion('v2.2.1')).toBe(true) - expect(isSupportedOpenCodeVersion(' v2.2.1 ')).toBe(true) + expect(isSupportedOpenCodeVersion('v2.2.3')).toBe(true) + expect(isSupportedOpenCodeVersion(' v2.2.3 ')).toBe(true) expect(isSupportedOpenCodeVersion('3.0.0')).toBe(false) expect(isSupportedOpenCodeVersion('3.1.0')).toBe(false) expect(isSupportedOpenCodeVersion('not-a-version')).toBe(false) }) it('rejects prereleases of the pinned version', () => { - expect(isSupportedOpenCodeVersion('2.2.1-alpha.1')).toBe(false) - expect(isSupportedOpenCodeVersion('2.2.1-alpha')).toBe(false) - expect(isSupportedOpenCodeVersion('2.2.1-rc.1+build.5')).toBe(false) - expect(isSupportedOpenCodeVersion('2.2.1-0')).toBe(false) + expect(isSupportedOpenCodeVersion('2.2.3-alpha.1')).toBe(false) + expect(isSupportedOpenCodeVersion('2.2.3-alpha')).toBe(false) + expect(isSupportedOpenCodeVersion('2.2.3-rc.1+build.5')).toBe(false) + expect(isSupportedOpenCodeVersion('2.2.3-0')).toBe(false) }) it('accepts prereleases of higher numeric cores within the pinned major', () => { expect(isSupportedOpenCodeVersion('2.3.0-beta.1')).toBe(true) - expect(isSupportedOpenCodeVersion('2.2.2-rc.2')).toBe(true) + expect(isSupportedOpenCodeVersion('2.2.4-rc.2')).toBe(true) expect(isSupportedOpenCodeVersion('3.0.0-beta.1')).toBe(false) }) it('ignores build metadata for precedence', () => { - expect(isSupportedOpenCodeVersion('2.2.1+build')).toBe(true) - expect(isSupportedOpenCodeVersion('2.2.1+2.0.0')).toBe(true) + expect(isSupportedOpenCodeVersion('2.2.3+build')).toBe(true) + expect(isSupportedOpenCodeVersion('2.2.3+2.0.0')).toBe(true) }) it('rejects malformed and incomplete versions', () => { expect(isSupportedOpenCodeVersion('2garbage')).toBe(false) expect(isSupportedOpenCodeVersion('2')).toBe(false) expect(isSupportedOpenCodeVersion('2.0')).toBe(false) - expect(isSupportedOpenCodeVersion('2.2.1.1')).toBe(false) - expect(isSupportedOpenCodeVersion('02.2.1')).toBe(false) - expect(isSupportedOpenCodeVersion('2.2.1-alpha..1')).toBe(false) + expect(isSupportedOpenCodeVersion('2.2.3.1')).toBe(false) + expect(isSupportedOpenCodeVersion('02.2.3')).toBe(false) + expect(isSupportedOpenCodeVersion('2.2.3-alpha..1')).toBe(false) expect(isSupportedOpenCodeVersion('')).toBe(false) }) it('describes the supported range for unsupported versions', () => { expect(describeUnsupportedOpenCodeVersion('3.0.0')).toBe( - 'OpenCode 3.0.0 is not supported; OpenCode Manager requires OpenCode >=2.2.1 <3.0.0', + 'OpenCode 3.0.0 is not supported; OpenCode Manager requires OpenCode >=2.2.3 <3.0.0', ) }) }) @@ -155,6 +157,14 @@ describe('OpenCode v2 contract', () => { readFileSync(join(REPO_ROOT, 'shared', 'package.json'), 'utf8'), ) as PackageManifest expect(manifest.dependencies['@opencode/client']).toBe(OPENCODE_PINNED_VERSION) + expect(manifest.dependencies['@opencode/schema']).toBe(OPENCODE_PINNED_VERSION) + }) + + it('keeps the CI workflow OpenCode download in sync with the pin', () => { + const workflow = readFileSync(join(REPO_ROOT, '.github', 'workflows', 'ci.yml'), 'utf8') + expect(workflow).toMatch( + new RegExp(`download_opencode_to ${OPENCODE_PINNED_VERSION.replace(/\./g, '\\.')}(?=\\s)`), + ) }) it('makes the shell scripts derive the pin from the Dockerfile or the bundled version instead of hardcoding it', () => { diff --git a/ocm-cli/README.md b/ocm-cli/README.md index 182a605c2..b881e23cc 100644 --- a/ocm-cli/README.md +++ b/ocm-cli/README.md @@ -10,9 +10,11 @@ to the local working tree. | ocm | OpenCode Manager | Local OpenCode | |---|---|---| -| 0.5.x | >= 0.19.0 | >= 2.2.0, < 3 | -| 0.4.x | >= 0.19.0 | >= 2.0.15, < 3 | -| 0.3.x | >= 0.19.0 | >= 2.0.15, < 3 | +| 0.5.x | >= 0.19.0 | >= 2.2.3, < 3 | +| 0.4.x | >= 0.19.0 | >= 2.0.15, < 3 [^legacy-opencode] | +| 0.3.x | >= 0.19.0 | >= 2.0.15, < 3 [^legacy-opencode] | + +[^legacy-opencode]: The 0.4.x and 0.3.x lines are not tested with OpenCode >= 2.2.3; use the 0.5.x line on those hosts. ocm 0.5.x, 0.4.x and 0.3.x attach through the repo-scoped Manager proxy (`/api/opencode-proxy/repos/:repoId`), load the plugin from the OpenCode 2 @@ -24,10 +26,10 @@ Use ocm 0.2.x with OpenCode Manager < 0.19.0 and OpenCode 1.x, installed pinned `@opencode-manager/ocm-cli@0.2`. ocm is published together with each OpenCode Manager release. -From ocm 0.5.0, the TUI plugin is built against `@opencode/plugin` 2.2.x and -OpenTUI 0.7, so it requires a local OpenCode >= 2.2.0: OpenCode 2.2.0 refuses -plugins built for OpenTUI 0.6, and older OpenCode builds may refuse the OpenTUI -0.7 peers. Stay on ocm 0.4.x with a local OpenCode older than 2.2.0. +From ocm 0.5.0, the TUI plugin is built against `@opencode/plugin` 2.2.3 and +OpenTUI 0.8, so it requires a local OpenCode >= 2.2.3. OpenCode 2.2.3 requires +TUI plugins built for OpenTUI 0.8, and older OpenCode 2.2.x builds pin OpenTUI +0.7; stay on ocm 0.4.x with a local OpenCode older than 2.2.3. ocm 0.5.0 removes `/ocm-goal`; session goals use OpenCode's built-in `/goal` command, and OpenCode Manager no longer serves `/api/internal/session-goals`. @@ -320,7 +322,7 @@ global installs); the plugin surface is TUI-only. ## Requirements - macOS or Linux (Windows is unsupported) -- OpenCode >= 2.2.0 (same major, 2.x) available on `PATH` for the TUI plugin +- OpenCode >= 2.2.3 (same major, 2.x) available on `PATH` for the TUI plugin - Node available on `PATH` (runs the `ocm` binary) - OpenCode Manager >= 0.19.0 - `git` and `tar` (with gzip support, i.e. the `-z` flag) available on `PATH` diff --git a/ocm-cli/package.json b/ocm-cli/package.json index 28cce15ff..0607e1270 100644 --- a/ocm-cli/package.json +++ b/ocm-cli/package.json @@ -18,10 +18,10 @@ } }, "peerDependencies": { - "@opencode/theme": ">=2.2.1 <3.0.0", - "@opentui/core": ">=0.7.0 <0.8.0", - "@opentui/solid": ">=0.7.0 <0.8.0", - "solid-js": ">=1.9.0" + "@opencode/theme": ">=2.2.3 <3.0.0", + "@opentui/core": ">=0.8.0 <0.9.0", + "@opentui/solid": ">=0.8.0 <0.9.0", + "solid-js": ">=1.9.16" }, "peerDependenciesMeta": { "@opencode/theme": { @@ -58,16 +58,16 @@ }, "devDependencies": { "@eslint/js": "^9.36.0", - "@opencode/plugin": "2.2.1", - "@opencode/theme": "2.2.1", + "@opencode/plugin": "2.2.3", + "@opencode/theme": "2.2.3", "@opencode-manager/shared": "workspace:*", - "@opentui/core": "0.7.0", - "@opentui/solid": "0.7.0", + "@opentui/core": "0.8.0", + "@opentui/solid": "0.8.0", "@types/bun": "^1.3.14", "@types/node": "^22.0.0", "eslint": "^9.39.1", "jsonc-parser": "^3.3.1", - "solid-js": "1.9.12", + "solid-js": "1.9.16", "typescript": "^5.5.0", "typescript-eslint": "^8.45.0", "uqr": "^0.1.3", diff --git a/ocm-cli/test/package-compat.test.ts b/ocm-cli/test/package-compat.test.ts index ba91278f9..153db869b 100644 --- a/ocm-cli/test/package-compat.test.ts +++ b/ocm-cli/test/package-compat.test.ts @@ -1,6 +1,11 @@ import { readFileSync } from 'node:fs' import { join } from 'node:path' -import { parseSemver } from '@opencode-manager/shared/utils' +import { + compareParsedSemver, + normalizeSemver, + parseSemver, + type Semver, +} from '@opencode-manager/shared/utils' import { describe, expect, it } from 'vitest' interface PackageManifest { @@ -19,22 +24,57 @@ function readManifest(path: string): PackageManifest { return JSON.parse(readFileSync(path, 'utf8')) as PackageManifest } +/** + * Guards a version string as a stable semver release. + * + * Returns the parsed version together with its normalized `major.minor.patch` + * form, or `null` when the input is not a stable release version. + */ +function readStableSemver(version: string): { semver: Semver; normalized: string } | null { + const semver = parseSemver(normalizeSemver(version)) + if (!semver || semver.prerelease.length > 0) { + return null + } + return { semver, normalized: `${semver.major}.${semver.minor}.${semver.patch}` } +} + /** * Derives the minor-line peer range for a plugin's exact dependency pin. * - * A `0.x.y` pin is constrained to its minor line; a pin at major `1` or above - * is constrained to its major line. + * A `0.x.y` pin is constrained to its minor line from the pinned patch; a pin + * at major `1` or above is constrained to its major line. */ function deriveMinorLineRange(pin: string): string { - const parsed = parseSemver(pin) - if (!parsed || parsed.prerelease.length > 0) { + const stable = readStableSemver(pin) + if (!stable) { throw new Error(`Cannot derive a peer range from pin "${pin}"`) } - const { major, minor } = parsed + const { major, minor, patch } = stable.semver if (major === 0) { - return `>=0.${minor}.0 <0.${minor + 1}.0` + return `>=0.${minor}.${patch} <0.${minor + 1}.0` } - return `>=${pin} <${major + 1}.0.0` + return `>=${stable.normalized} <${major + 1}.0.0` +} + +/** + * Resolves the minimum version floor from a plugin peer range. + * + * Accepts an exact pin or a bare `>=x.y.z` lower bound; any other range cannot + * be reduced to a floor. + */ +function resolvePeerFloor(peer: string): string { + const exact = readStableSemver(peer) + if (exact) { + return exact.normalized + } + const lowerBound = /^>=\s*(\S+)$/.exec(peer.trim()) + if (lowerBound) { + const floor = readStableSemver(lowerBound[1]) + if (floor) { + return floor.normalized + } + } + throw new Error(`Cannot derive a peer floor from "${peer}"`) } const ocmManifest = readManifest(join(__dirname, '..', 'package.json')) @@ -44,14 +84,43 @@ const pluginManifest = readManifest( describe('ocm-cli package compatibility with the installed @opencode/plugin', () => { for (const name of PINNED_PACKAGES) { - it(`${name} matches the plugin peer pin`, () => { - const pluginPin = pluginManifest.peerDependencies[name] - expect(ocmManifest.devDependencies[name]).toBe(pluginPin) - expect(ocmManifest.peerDependencies[name]).toBe(deriveMinorLineRange(pluginPin)) + it(`${name} matches the plugin peer floor`, () => { + const floor = resolvePeerFloor(pluginManifest.peerDependencies[name]) + expect(ocmManifest.devDependencies[name]).toBe(floor) + expect(ocmManifest.peerDependencies[name]).toBe(deriveMinorLineRange(floor)) expect(ocmManifest.peerDependenciesMeta[name]?.optional).toBe(true) }) } + it('rejects peer ranges without a derivable floor', () => { + expect(() => resolvePeerFloor('^0.8.0')).toThrow('Cannot derive a peer floor from "^0.8.0"') + expect(() => resolvePeerFloor('>=0.8.0 <1')).toThrow( + 'Cannot derive a peer floor from ">=0.8.0 <1"', + ) + }) + + it('normalizes version prefixes and build metadata when resolving floors', () => { + expect(resolvePeerFloor('v0.8.0')).toBe('0.8.0') + expect(resolvePeerFloor('>=1.9.16+build.5')).toBe('1.9.16') + }) + + it('derives a patch-level floor inside a 0.x minor line', () => { + expect(deriveMinorLineRange('0.8.5')).toBe('>=0.8.5 <0.9.0') + expect(deriveMinorLineRange('0.8.0')).toBe('>=0.8.0 <0.9.0') + }) + + it('solid-js peer floor matches the @opentui/solid babel preset requirement', () => { + expect(ocmManifest.peerDependencies['solid-js']).toBe('>=1.9.16') + expect(ocmManifest.peerDependenciesMeta['solid-js']?.optional).toBe(true) + const devPin = parseSemver(ocmManifest.devDependencies['solid-js']) + if (!devPin) { + throw new Error('solid-js devDependency is not a valid semver version') + } + expect( + compareParsedSemver(devPin, { major: 1, minor: 9, patch: 16, prerelease: [] }), + ).toBeGreaterThanOrEqual(0) + }) + it('@opencode/plugin devDependency matches the installed plugin version', () => { expect(ocmManifest.devDependencies['@opencode/plugin']).toBe(pluginManifest.version) }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 89f9f9d3e..8fffac142 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -28,7 +28,7 @@ importers: dependencies: '@better-auth/passkey': specifier: ^1.7.12 - version: 1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.0)(better-call@1.4.4(zod@4.3.2))(jose@6.2.13)(kysely@0.29.7)(nanostores@1.5.5))(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(better-auth@1.7.12(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.15)(vitest@3.2.4))(better-call@1.4.4(zod@4.3.2))(nanostores@1.5.5) + version: 1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.0)(better-call@1.4.4(zod@4.3.2))(jose@6.2.13)(kysely@0.29.7)(nanostores@1.5.5))(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(better-auth@1.7.12(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.16)(vitest@3.2.4))(better-call@1.4.4(zod@4.3.2))(nanostores@1.5.5) '@hono/node-server': specifier: ^1.19.17 version: 1.19.17(hono@4.13.13) @@ -43,7 +43,7 @@ importers: version: 7.0.1 better-auth: specifier: ^1.7.12 - version: 1.7.12(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.15)(vitest@3.2.4) + version: 1.7.12(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.16)(vitest@3.2.4) croner: specifier: ^10.0.1 version: 10.0.1 @@ -107,7 +107,7 @@ importers: dependencies: '@better-auth/passkey': specifier: ^1.7.12 - version: 1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.0)(better-call@1.4.4(zod@4.3.2))(jose@6.2.13)(kysely@0.29.7)(nanostores@1.5.5))(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(better-auth@1.7.12(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.15)(vitest@3.2.4))(better-call@1.4.4(zod@4.3.2))(nanostores@1.5.5) + version: 1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.0)(better-call@1.4.4(zod@4.3.2))(jose@6.2.13)(kysely@0.29.7)(nanostores@1.5.5))(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(better-auth@1.7.12(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.16)(vitest@3.2.4))(better-call@1.4.4(zod@4.3.2))(nanostores@1.5.5) '@dnd-kit/core': specifier: ^6.3.1 version: 6.3.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -173,7 +173,7 @@ importers: version: 6.0.0 better-auth: specifier: ^1.7.12 - version: 1.7.12(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.15)(vitest@3.2.4) + version: 1.7.12(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.16)(vitest@3.2.4) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -311,17 +311,17 @@ importers: specifier: workspace:* version: link:../shared '@opencode/plugin': - specifier: 2.2.1 - version: 2.2.1(@opencode/theme@2.2.1(typescript@5.9.3)(web-tree-sitter@0.25.10))(@opentelemetry/semantic-conventions@1.43.0)(@opentui/core@0.7.0(typescript@5.9.3)(web-tree-sitter@0.25.10))(@opentui/solid@0.7.0(solid-js@1.9.12)(typescript@5.9.3)(web-tree-sitter@0.25.10))(redis@6.2.1(@opentelemetry/api@1.9.0))(solid-js@1.9.12)(vite@7.3.0(@types/node@22.19.19)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(yaml@2.9.0)) + specifier: 2.2.3 + version: 2.2.3(@opencode/theme@2.2.3(typescript@5.9.3)(web-tree-sitter@0.25.10))(@opentelemetry/semantic-conventions@1.43.0)(@opentui/core@0.8.0(typescript@5.9.3)(web-tree-sitter@0.25.10))(@opentui/solid@0.8.0(solid-js@1.9.16)(typescript@5.9.3)(web-tree-sitter@0.25.10))(redis@6.2.1(@opentelemetry/api@1.9.0))(solid-js@1.9.16)(vite@7.3.0(@types/node@22.19.19)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(yaml@2.9.0)) '@opencode/theme': - specifier: 2.2.1 - version: 2.2.1(typescript@5.9.3)(web-tree-sitter@0.25.10) + specifier: 2.2.3 + version: 2.2.3(typescript@5.9.3)(web-tree-sitter@0.25.10) '@opentui/core': - specifier: 0.7.0 - version: 0.7.0(typescript@5.9.3)(web-tree-sitter@0.25.10) + specifier: 0.8.0 + version: 0.8.0(typescript@5.9.3)(web-tree-sitter@0.25.10) '@opentui/solid': - specifier: 0.7.0 - version: 0.7.0(solid-js@1.9.12)(typescript@5.9.3)(web-tree-sitter@0.25.10) + specifier: 0.8.0 + version: 0.8.0(solid-js@1.9.16)(typescript@5.9.3)(web-tree-sitter@0.25.10) '@types/bun': specifier: ^1.3.14 version: 1.3.14 @@ -335,8 +335,8 @@ importers: specifier: ^3.3.1 version: 3.3.1 solid-js: - specifier: 1.9.12 - version: 1.9.12 + specifier: 1.9.16 + version: 1.9.16 typescript: specifier: ^5.5.0 version: 5.9.3 @@ -353,11 +353,11 @@ importers: shared: dependencies: '@opencode/client': - specifier: 2.2.1 - version: 2.2.1(effect@4.0.1)(solid-js@1.9.15) + specifier: 2.2.3 + version: 2.2.3(effect@4.0.6)(solid-js@1.9.16) '@opencode/schema': - specifier: 2.2.1 - version: 2.2.1 + specifier: 2.2.3 + version: 2.2.3 jsonc-parser: specifier: ^3.3.1 version: 3.3.1 @@ -502,10 +502,6 @@ packages: resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.5': - resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} - engines: {node: '>=6.9.0'} - '@babel/compat-data@7.29.7': resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} engines: {node: '>=6.9.0'} @@ -594,10 +590,6 @@ packages: resolution: {integrity: sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.29.11': resolution: {integrity: sha512-snZbO7MEDOof+hvNa97EjEY7qD7h2kwvQr5AJC3ZhQudKW5dnej6k3kP9NQV88hJwaS8vDqRLFo9rivLEhle2g==} engines: {node: '>=6.9.0'} @@ -606,18 +598,10 @@ packages: resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} - engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.29.7': resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.29.7': resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} engines: {node: '>=6.9.0'} @@ -880,8 +864,8 @@ packages: peerDependencies: react: '>=16.8.0' - '@effect/opentelemetry@4.0.1': - resolution: {integrity: sha512-MZ7M1a1dxMqTqeNwIGSECjO7RrReEgeEwHo8BnbOqP+8IfVpdiJi/iPCmkFVWlAxanMl4qhsq69e0Hkul9t+bA==} + '@effect/opentelemetry@4.0.6': + resolution: {integrity: sha512-xhLR1EN4ZNaKM7Bx59SCFiRNduFzgH8LZXDrCpPN8MpQ93V0GQcFHTBah5T3EXO2v+5HTEacdTgetIA0Creqvw==} engines: {node: '>=18.0.0'} peerDependencies: '@opentelemetry/api': '>=1.9.0 <2.0.0' @@ -893,7 +877,7 @@ packages: '@opentelemetry/sdk-trace-node': '>=2.0.0 <3.0.0' '@opentelemetry/sdk-trace-web': '>=2.0.0 <3.0.0' '@opentelemetry/semantic-conventions': '>=1.33.0 <2.0.0' - effect: ^4.0.1 + effect: ^4.0.6 peerDependenciesMeta: '@opentelemetry/api': optional: true @@ -912,17 +896,17 @@ packages: '@opentelemetry/sdk-trace-web': optional: true - '@effect/platform-node-shared@4.0.1': - resolution: {integrity: sha512-VanaejudEhKJ4mpmqnEzdncVUhN6sGSO9ZDND54mRxAlZxj+4dYAWjDTYAy9o4tJo9aALeP2U8cVcOFzEdSeLg==} + '@effect/platform-node-shared@4.0.6': + resolution: {integrity: sha512-0PhyC4uG30xGtsajnxjkcBWfTjNRzUh4ZKl1Kvo/MNyCTb+W2O+fBzf7wCRCoqt+nLudiq4V7vX40Q8XIBuMaQ==} engines: {node: '>=18.0.0'} peerDependencies: - effect: ^4.0.1 + effect: ^4.0.6 - '@effect/platform-node@4.0.1': - resolution: {integrity: sha512-FT0Fu5LO0/XP9zBpj0HqrtJNLluK4StNKqf6TSulUsjp8FPBsDVXGJiDuyoN5J2yVMT7tgvhxSwaDcObWVRIaQ==} + '@effect/platform-node@4.0.6': + resolution: {integrity: sha512-gXvGHAy0/8PZbWvMMguloDUyeSP+rzYEo3FSEqUuGduxo9ORcGioDxPI+GOLCIFfam7VuNkmSUxBOiRMIrMrBw==} engines: {node: '>=18.0.0'} peerDependencies: - effect: ^4.0.1 + effect: ^4.0.6 redis: '>=5.0.0 <7.0.0' '@esbuild/aix-ppc64@0.27.2': @@ -1304,13 +1288,13 @@ packages: resolution: {integrity: sha512-mGUWr1uMnf0le2TwfOZY4SFxZGXGfm4Jtay/nwAa2FLNAKXUoUwaGwBMNH36UHPtinWfTSJ3nqFQr0091CxVGg==} engines: {node: ^20.17.0 || >=22.9.0} - '@opencode/ai@2.2.1': - resolution: {integrity: sha512-CjCIrqnh+GCWFJejWoRPu8M+yghX3eIVFeDBdMjvQrLkoJ3Hv4RjxD2InolHnRFK8lAEq+IJ6D8gwiTZMgRSzg==} + '@opencode/ai@2.2.3': + resolution: {integrity: sha512-fUMZmeRCK/lqjKtYlWu+3JvQ46U7x3kNwgyhB1wfR0GhXRX5KeXf/vfYupjS4IkOHWay/zBTP1ZUsRDmOGmlOA==} - '@opencode/client@2.2.1': - resolution: {integrity: sha512-7QWtocDRR9eUsCJpyaj6k+aAEVDWO2CIzn9lwDNBJhiyt2hMf+yOyV/BKeK/9R7qKcXEOZ0tlGDvQC8HEtyjQg==} + '@opencode/client@2.2.3': + resolution: {integrity: sha512-ph1uIGrQl1bO6jZ9RCVfa/aBsz0nCq3pnpikExQ0W8oKUwS9mH5tQfpwG0e85V6W4KPeOQCwGUWB0WTzXnYO/Q==} peerDependencies: - effect: 4.0.1 + effect: 4.0.6 solid-js: '>=1.9.0' peerDependenciesMeta: effect: @@ -1318,12 +1302,12 @@ packages: solid-js: optional: true - '@opencode/plugin@2.2.1': - resolution: {integrity: sha512-m5va0KJpG6CpyhKRQL/lKIP7tP0LgUvcuezpmob0e8spDOMtXh/+1Idb2zKxuIq14mKjwbQd0nz+BJbsqw1fqA==} + '@opencode/plugin@2.2.3': + resolution: {integrity: sha512-JK8FW4VHPHkQKgKi9m7kKdx9L1CRSNYpxNR1DtXC9SAe7f8huWoXEN+LH2vv38KEanOfY5OdcUhBUHKAwidyeg==} peerDependencies: - '@opencode/theme': 2.2.1 - '@opentui/core': 0.7.0 - '@opentui/solid': 0.7.0 + '@opencode/theme': 2.2.3 + '@opentui/core': '>=0.8.0' + '@opentui/solid': '>=0.8.0' electron: '*' solid-js: '>=1.9.0' vite: '>=6' @@ -1344,17 +1328,17 @@ packages: vite-plugin-solid: optional: true - '@opencode/protocol@2.2.1': - resolution: {integrity: sha512-lqkkRhrckEKmiSJi249rvfX/fXX8JeiMS7adtXonO1Ol3IqnEqY4uSZgvQiQ11SBR5RyDQaRW9KGoOjaTY4PAQ==} + '@opencode/protocol@2.2.3': + resolution: {integrity: sha512-4SBCchbfwMb2AK27vH+Qlwrnnbzw4tMT7LsFJRNwO/H7LPKbsMJJsAlRYjcyxQYEPDNYVXyFCF1rCkrA3OeCJg==} - '@opencode/schema@2.2.1': - resolution: {integrity: sha512-TicxPQC1UKqq954X1yUKmBlXfJYl5CRr52FKwLZbYOfTxJd406Hoqt2arM4YI3c+abs17b9sumoq5uqFLhiGFA==} + '@opencode/schema@2.2.3': + resolution: {integrity: sha512-5Lm6Aw6E3nHigLJcSOteontUKv/9fzjfEXaBvaIHAageNvq0hYBgWSBv0ZikaAj1pJr5e1y9TSW6cbWqQcjMjg==} - '@opencode/theme@2.2.1': - resolution: {integrity: sha512-YAKT/TacMHM04rLi9o1zyVpgEhy3hpuHZKGs/VC6+wigRrieLvyTvS7/FmcOVEeophNmwL0FYI1sD/NCTLlxlA==} + '@opencode/theme@2.2.3': + resolution: {integrity: sha512-SyyShA8hADVeKDJQWMZN0NRg7pq/5ajxfXl7LHNofG2ww01MDMy3vLq04o0ACq6GLZKBnUeAiTYrJe3GUoBKWg==} - '@opencode/util@2.2.1': - resolution: {integrity: sha512-MgJ8oJ/S+L5gRBmYk8bEHRVR99eEvUUDGg8fZLG/UD1+RPisJ6Ce1ZO++pBjTvkdS+Okk6lPxhbjYemIQtSciQ==} + '@opencode/util@2.2.3': + resolution: {integrity: sha512-Xp9hb909LaYJ667Yzg5LkCBrj9h44umOiH9WF7Mj4ZZlOKQDr5H3a3LEw0r7a8ED8yfnXMrN8xFMeL6EojBmGQ==} '@opentelemetry/api-logs@0.219.0': resolution: {integrity: sha512-FFx7YnaYJlIjqWW/AG/yAZ0L/NEY724PipXXXQLdtZPbLwBGbUMTGL1i/esI56TWfTUXxhLfpgrnWJCG8aUJyg==} @@ -1430,56 +1414,56 @@ packages: resolution: {integrity: sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==} engines: {node: '>=14'} - '@opentui/core-darwin-arm64@0.7.0': - resolution: {integrity: sha512-meEyZVUeCIauqHLWo/IsSlKzZPTnGIEjRLigefSZbrSAcOiMryd3OcUWvSByIXpYb9UPOpW0YxKKfVwepb9u2A==} + '@opentui/core-darwin-arm64@0.8.0': + resolution: {integrity: sha512-Cp+BL1DsRZhUG56AuyXlH8DA4dsKfZ3Qgh1XMYDGokkC4p9uv8kdNNhyzmURAFa2LK77XqVv1Zhwr/6DqqpMlw==} cpu: [arm64] os: [darwin] - '@opentui/core-darwin-x64@0.7.0': - resolution: {integrity: sha512-hZQ4OfAua5CtUv3hpZ81zhNTTLULbg0leQ/3eupjefityGP6163eS56IzymTWuiM/mVD/7Ad5bicH0I2JXhr1g==} + '@opentui/core-darwin-x64@0.8.0': + resolution: {integrity: sha512-Jp4pzdIuKsS3XYq9xuWuAO52tTj9gnWeeoI3bg456CF6XnY2yQMasWOd/WmjfvYfAaJzGDFa4DNXhByBMPVuTw==} cpu: [x64] os: [darwin] - '@opentui/core-linux-arm64-musl@0.7.0': - resolution: {integrity: sha512-BkTn+WLf9OPR4KhBnuOki+R/cgk2qwbL49eQn5fEYPeiJD4HPalGbEZDea59UjwNEJ7rqKq2yuPAXQjkDZ6y3w==} + '@opentui/core-linux-arm64-musl@0.8.0': + resolution: {integrity: sha512-8ZPl/2DChcS7XIVRPIazigXaMNyxa2bwvuzPprNbzT0+cVJLIoGC19pjiV3bI3oVXBPVMNqgIcppOrEHBhlouw==} cpu: [arm64] os: [linux] - '@opentui/core-linux-arm64@0.7.0': - resolution: {integrity: sha512-/u+Kalzkz8NntUW5zjypgt9fnzeKohLG9YMEas7n98KvyaYScrtO4Mdj5iv/STNB3IfocJOChzYAbO6C8TmlPQ==} + '@opentui/core-linux-arm64@0.8.0': + resolution: {integrity: sha512-b6D/VP9y0Z18tO86GSTp9BBykgR6r5CQM1ol9UMJfUt+PjN5HGksbOCDTMIQufXvt4WIUFHrSBProysJRFzbYw==} cpu: [arm64] os: [linux] - '@opentui/core-linux-x64-musl@0.7.0': - resolution: {integrity: sha512-HrJbcAIuayzQmWVzv+cjez37fNHL9FDoHmjwxAb4iK5GTjl89FZCxeKopyua14RA6WpP8/zUJQi8U16mm6XptA==} + '@opentui/core-linux-x64-musl@0.8.0': + resolution: {integrity: sha512-xGEYw6wkX0sPwPx6RosQZanuWF0+5cIup2alhHHQQfKJkcLS8r8NBWlcy2LK9CoEWH6SBtNXC+9Y5IrryCOvJQ==} cpu: [x64] os: [linux] - '@opentui/core-linux-x64@0.7.0': - resolution: {integrity: sha512-OD2tGl1r27zcgCsuc+TYU5e+qhrbsRSI0YUBEb0ebQo8P6Ps2FL9LFenH9om4fddCh06G9Zd45ekJMhlDrGD3Q==} + '@opentui/core-linux-x64@0.8.0': + resolution: {integrity: sha512-aXBNIdE6iMf58/Tdnd6UzXeFjYfaHzQ6E0nukjLe2ir41/meJJYEAHUQ62EBr/gxvuCNZHTBQB4T9BzF7PdENQ==} cpu: [x64] os: [linux] - '@opentui/core-win32-arm64@0.7.0': - resolution: {integrity: sha512-8yqBoRsDbvKl2kGX0O8t5kpnVEnbzs+2qUZlJ8sbeA3Z+73WFj36G+clUIMVxpspOu78iKXlD84NIwTxjZUPKw==} + '@opentui/core-win32-arm64@0.8.0': + resolution: {integrity: sha512-XtK0QMyIiqeDmrIyyAXqqp7TKaRGaWnBlbnEsNrkRLrgP+aLwRhRSHdafxi+RMqj3h9qOlb1MgnPal1kx7wP4g==} cpu: [arm64] os: [win32] - '@opentui/core-win32-x64@0.7.0': - resolution: {integrity: sha512-OfNAX7fNFHhOiiojUkIjhVOZf+IDjpbpT5G7HrxGqhlZ+n4jITrrJzACHctteWbMUYcibieJzIIoKuLdmD5I+w==} + '@opentui/core-win32-x64@0.8.0': + resolution: {integrity: sha512-P5X2RcDDntIJ4q1WvQawGWCae5BzHrm50PMy7+PZ3Su8GGwnaCQ5xRHvDIQfhki8pZMo2SoTOkpStR0Wj1QoXQ==} cpu: [x64] os: [win32] - '@opentui/core@0.7.0': - resolution: {integrity: sha512-2iWBw9oo+ZJfPbOWeTLXfDV63yTDRfclxltI4IgTa6n7OB90x5xplLMH3y9DXhnWibzTui00GbK3ZCwKfUU1SQ==} + '@opentui/core@0.8.0': + resolution: {integrity: sha512-LwnIT7k+rGelridv7390enJXZpNuQYKIS3NdttJyoLPjbRFPyHnAKkCHk6X8MRS64vcSjOeVq9sl7XLWII16jQ==} engines: {bun: '>=1.3.14', node: '>=26.4.0'} peerDependencies: web-tree-sitter: 0.25.10 - '@opentui/solid@0.7.0': - resolution: {integrity: sha512-S6SNZGRykV02UjNbM+f/6lSeAPN3dfEbjcK1jAAdFCfa+EVhJqcJVyaJgtwHLU9fI6c/O1VKXPzbbFYj2RhNVQ==} + '@opentui/solid@0.8.0': + resolution: {integrity: sha512-fk035Q9iGXFgpkXSbpdyWYnT1jFuY0gOhzxaqBXDVtuWrQPB5MRxUxXHgESIMXJPsMTROIjOcKuW+PPhsakpnw==} peerDependencies: - solid-js: 1.9.12 + solid-js: ^1.9.12 '@peculiar/asn1-android@2.6.0': resolution: {integrity: sha512-cBRCKtYPF7vJGN76/yG8VbxRcHLPF3HnkoHhKOZeHpoVtbMYfY9ROKtH3DtYUY9m8uI1Mh47PRhHf2hSK3xcSQ==} @@ -2522,8 +2506,8 @@ packages: '@types/web-push@3.6.4': resolution: {integrity: sha512-GnJmSr40H3RAnj0s34FNTcJi1hmWFV5KXugE0mYWnYhgTAHLJ/dJKAwDmvPJYMke0RplY2XE9LnM4hqSqKIjhQ==} - '@types/ws@8.18.1': - resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + '@types/ws@8.18.2': + resolution: {integrity: sha512-67MQl+fpWKVTT1NYdnmo3U4sc/xPo/zQBncVnI74qmQa0z/b+1g6iYqNmGCPbxO+zz2aklb08a0oHfegiVd0/w==} '@typescript-eslint/eslint-plugin@8.51.0': resolution: {integrity: sha512-XtssGWJvypyM2ytBnSnKtHYOGT+4ZwTnBVl36TA4nRO2f4PRNGz5/1OszHzcZCvcBMh+qb7I06uoCmLTRdR9og==} @@ -2745,19 +2729,19 @@ packages: react-native-b4a: optional: true - babel-plugin-jsx-dom-expressions@0.40.7: - resolution: {integrity: sha512-/O6JWUmjv03OI9lL2ry9bUjpD5S3PclM55RRJEyCdcFZ5W2SEA/59d+l2hNsk3gI6kiWRdRPdOtqZmsQzFN1pQ==} + babel-plugin-jsx-dom-expressions@0.40.11: + resolution: {integrity: sha512-k7TkOv7uVYnrq/bYyVvG5cWOC9IObAGfmyW3aMkG8l2sq2qt/5THkUBja69PMLEGGi8G+fXB2Fh7eS4OwZRBoQ==} peerDependencies: '@babel/core': ^7.20.12 babel-plugin-module-resolver@5.0.2: resolution: {integrity: sha512-9KtaCazHee2xc0ibfqsDeamwDps6FZNo5S0Q81dUqEuFzVwPhcT4J5jOqIVvgCA3Q/wO9hKYxN/Ds3tIsp5ygg==} - babel-preset-solid@1.9.12: - resolution: {integrity: sha512-LLqnuKVDlKpyBlMPcH6qEvs/wmS9a+NczppxJ3ryS/c0O5IiSFOIBQi9GzyiGDSbcJpx4Gr87jyFTos1MyEuWg==} + babel-preset-solid@1.9.16: + resolution: {integrity: sha512-+0h40Qk2oBfkQ4OGDBHIDtvq/XQiOnCfzjNHmMxriAr8MmdsaIbyJgqYglDs4d70sF8O08sSpx61TKdpUt3oRw==} peerDependencies: '@babel/core': ^7.0.0 - solid-js: ^1.9.12 + solid-js: ^1.9.16 peerDependenciesMeta: solid-js: optional: true @@ -3365,8 +3349,8 @@ packages: ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} - effect@4.0.1: - resolution: {integrity: sha512-b1VlQG9g8fwxE5QnIZuPoOP/0MsqHJSRKxUijjoM80E5q95FXrX5yWtY5XI8G+GJsBQAVSDbLS458z9a++uVvw==} + effect@4.0.6: + resolution: {integrity: sha512-Tc3mkzuLR6t6P9dhLt0D2GrxYtmU5td4XEJEiXCmILz53IRIfJyHsKZWjTA3xEjiwpNTtXBgI4iqYPxMztBDrw==} electron-to-chromium@1.5.267: resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} @@ -4856,24 +4840,14 @@ packages: engines: {node: '>=10'} hasBin: true - seroval-plugins@1.5.4: - resolution: {integrity: sha512-S0xQPhUTefAhNvNWFg0c1J8qJArHt5KdtJ/cFAofo06KD1MVSeFWyl4iiu+ApDIuw0WhjpOfCdgConOfAnLgkw==} + seroval-plugins@1.6.12: + resolution: {integrity: sha512-+reiwp/lYxiyctSrdvX7OQ1YLrcbWYgBiZrhSFL+V43b0/DGRLNVSDyZINbQe+tWplPOI2fw2dPrdv6hcc09kQ==} engines: {node: '>=10'} peerDependencies: seroval: ^1.0 - seroval-plugins@1.5.6: - resolution: {integrity: sha512-HXuLAX2pu/UByPpaeo/TaMfvMIi+1QqIoPJYCcAtU8QkVNwgR6MPlGuCQTErV1JwraaMbYaWVIBX7mppzGLATQ==} - engines: {node: '>=10'} - peerDependencies: - seroval: ^1.0 - - seroval@1.5.4: - resolution: {integrity: sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw==} - engines: {node: '>=10'} - - seroval@1.5.6: - resolution: {integrity: sha512-rVQVWjjSvlINzaQPZH5JFqsqEsIWdTxY3iJZCnTL/5gQbXIRooVZKI60tVCkOVfzcRPejboxO2t0P89dg5mQaA==} + seroval@1.6.12: + resolution: {integrity: sha512-CqbIVfk/7GL3ITwZI55lcPbpQbjHZ2DD5cUj4iH7E9YsCfHNJV1mx7yNp86Z84w5IpmkZZS/2s5vPOWmVWSdQg==} engines: {node: '>=10'} set-cookie-parser@2.7.2: @@ -4927,11 +4901,8 @@ packages: resolution: {integrity: sha512-e0VyvkVTwVYViNovRkZ9aodhxVlyoMn7eJhVUPxZ+eK9P/7CBkxvvsBOHqFPEH416726W8tLXXXjKwqgTErrCQ==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} - solid-js@1.9.12: - resolution: {integrity: sha512-QzKaSJq2/iDrWR1As6MHZQ8fQkdOBf8GReYb7L5iKwMGceg7HxDcaOHk0at66tNgn9U2U7dXo8ZZpLIAmGMzgw==} - - solid-js@1.9.15: - resolution: {integrity: sha512-EeiY2xfpZJqPLjXspVEKjAII4yv8NyG//NxZ3IpOFHdUNnnTyL0uJOeS9LWGvA7cFCz5y94cjFwYlmw5Luncsg==} + solid-js@1.9.16: + resolution: {integrity: sha512-vESESWrNRebA0sQv+Vr9/2wOFOL6NK2QQow7F5/WCBH4c+OVoDyQNEbiVKVL7YqE1M7MPd7z7p27KElLkaD0bw==} sonner@2.0.7: resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} @@ -5808,8 +5779,6 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.28.5': {} - '@babel/compat-data@7.29.7': {} '@babel/core@7.28.5': @@ -5842,7 +5811,7 @@ snapshots: '@babel/parser': 7.29.7 '@babel/template': 7.29.7 '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.11 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3 @@ -5855,7 +5824,7 @@ snapshots: '@babel/generator@7.28.5': dependencies: '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.11 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 @@ -5863,19 +5832,19 @@ snapshots: '@babel/generator@7.29.7': dependencies: '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.11 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 '@babel/helper-annotate-as-pure@7.29.7': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.11 '@babel/helper-compilation-targets@7.27.2': dependencies: - '@babel/compat-data': 7.28.5 - '@babel/helper-validator-option': 7.27.1 + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 browserslist: 4.28.1 lru-cache: 5.1.1 semver: 6.3.1 @@ -5906,18 +5875,18 @@ snapshots: '@babel/helper-member-expression-to-functions@7.29.7': dependencies: '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.11 transitivePeerDependencies: - supports-color '@babel/helper-module-imports@7.18.6': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.11 '@babel/helper-module-imports@7.29.7': dependencies: '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.11 transitivePeerDependencies: - supports-color @@ -5941,7 +5910,7 @@ snapshots: '@babel/helper-optimise-call-expression@7.29.7': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.11 '@babel/helper-plugin-utils@7.27.1': {} @@ -5959,28 +5928,22 @@ snapshots: '@babel/helper-skip-transparent-expression-wrappers@7.29.7': dependencies: '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.11 transitivePeerDependencies: - supports-color - '@babel/helper-string-parser@7.27.1': {} - '@babel/helper-string-parser@7.29.11': {} '@babel/helper-string-parser@7.29.7': {} - '@babel/helper-validator-identifier@7.28.5': {} - '@babel/helper-validator-identifier@7.29.7': {} - '@babel/helper-validator-option@7.27.1': {} - '@babel/helper-validator-option@7.29.7': {} '@babel/helpers@7.28.4': dependencies: '@babel/template': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.11 '@babel/helpers@7.29.10': dependencies: @@ -5989,11 +5952,11 @@ snapshots: '@babel/parser@7.28.5': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.11 '@babel/parser@7.29.7': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.11 '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7)': dependencies: @@ -6038,7 +6001,7 @@ snapshots: dependencies: '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-validator-option': 7.27.1 + '@babel/helper-validator-option': 7.29.7 '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7) '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) @@ -6053,13 +6016,13 @@ snapshots: dependencies: '@babel/code-frame': 7.29.7 '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.11 '@babel/template@7.29.7': dependencies: '@babel/code-frame': 7.29.7 '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.11 '@babel/traverse@7.28.5': dependencies: @@ -6068,7 +6031,7 @@ snapshots: '@babel/helper-globals': 7.29.7 '@babel/parser': 7.29.7 '@babel/template': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.11 debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -6080,15 +6043,15 @@ snapshots: '@babel/helper-globals': 7.29.7 '@babel/parser': 7.29.7 '@babel/template': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.11 debug: 4.4.3 transitivePeerDependencies: - supports-color '@babel/types@7.28.5': dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-string-parser': 7.29.11 + '@babel/helper-validator-identifier': 7.29.7 '@babel/types@7.29.11': dependencies: @@ -6137,14 +6100,14 @@ snapshots: '@better-auth/core': 1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.0)(better-call@1.4.4(zod@4.3.2))(jose@6.2.13)(kysely@0.29.7)(nanostores@1.5.5) '@better-auth/utils': 0.5.0 - '@better-auth/passkey@1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.0)(better-call@1.4.4(zod@4.3.2))(jose@6.2.13)(kysely@0.29.7)(nanostores@1.5.5))(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(better-auth@1.7.12(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.15)(vitest@3.2.4))(better-call@1.4.4(zod@4.3.2))(nanostores@1.5.5)': + '@better-auth/passkey@1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.0)(better-call@1.4.4(zod@4.3.2))(jose@6.2.13)(kysely@0.29.7)(nanostores@1.5.5))(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(better-auth@1.7.12(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.16)(vitest@3.2.4))(better-call@1.4.4(zod@4.3.2))(nanostores@1.5.5)': dependencies: '@better-auth/core': 1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.0)(better-call@1.4.4(zod@4.3.2))(jose@6.2.13)(kysely@0.29.7)(nanostores@1.5.5) '@better-auth/utils': 0.5.0 '@better-fetch/fetch': 1.3.2 '@simplewebauthn/browser': 13.3.0 '@simplewebauthn/server': 13.3.3 - better-auth: 1.7.12(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.15)(vitest@3.2.4) + better-auth: 1.7.12(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.16)(vitest@3.2.4) better-call: 1.4.4(zod@4.3.2) nanostores: 1.5.5 zod: 4.6.7 @@ -6232,10 +6195,10 @@ snapshots: react: 19.2.3 tslib: 2.8.1 - '@effect/opentelemetry@4.0.1(@opentelemetry/api-logs@0.219.0)(@opentelemetry/api@1.9.0)(@opentelemetry/resources@2.8.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-logs@0.219.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-metrics@2.8.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-node@2.8.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.43.0)(effect@4.0.1)': + '@effect/opentelemetry@4.0.6(@opentelemetry/api-logs@0.219.0)(@opentelemetry/api@1.9.0)(@opentelemetry/resources@2.8.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-logs@0.219.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-metrics@2.8.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-node@2.8.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.43.0)(effect@4.0.6)': dependencies: '@opentelemetry/semantic-conventions': 1.43.0 - effect: 4.0.1 + effect: 4.0.6 optionalDependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/api-logs': 0.219.0 @@ -6245,19 +6208,19 @@ snapshots: '@opentelemetry/sdk-trace-base': 2.8.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-node': 2.8.0(@opentelemetry/api@1.9.0) - '@effect/platform-node-shared@4.0.1(effect@4.0.1)': + '@effect/platform-node-shared@4.0.6(effect@4.0.6)': dependencies: - '@types/ws': 8.18.1 - effect: 4.0.1 + '@types/ws': 8.18.2 + effect: 4.0.6 ws: 8.22.0 transitivePeerDependencies: - bufferutil - utf-8-validate - '@effect/platform-node@4.0.1(effect@4.0.1)(redis@6.2.1(@opentelemetry/api@1.9.0))': + '@effect/platform-node@4.0.6(effect@4.0.6)(redis@6.2.1(@opentelemetry/api@1.9.0))': dependencies: - '@effect/platform-node-shared': 4.0.1(effect@4.0.1) - effect: 4.0.1 + '@effect/platform-node-shared': 4.0.6(effect@4.0.6) + effect: 4.0.6 redis: 6.2.1(@opentelemetry/api@1.9.0) undici: 8.12.2 transitivePeerDependencies: @@ -6630,48 +6593,40 @@ snapshots: node-gyp: 12.4.0 proc-log: 6.1.0 - '@opencode/ai@2.2.1': + '@opencode/ai@2.2.3': dependencies: '@aws-sdk/credential-providers': 3.1057.0 - '@opencode/schema': 2.2.1 + '@opencode/schema': 2.2.3 '@smithy/eventstream-codec': 4.2.14 '@smithy/util-utf8': 4.2.2 aws4fetch: 1.0.20 - effect: 4.0.1 + effect: 4.0.6 google-auth-library: 10.5.0 transitivePeerDependencies: - supports-color - '@opencode/client@2.2.1(effect@4.0.1)(solid-js@1.9.12)': - dependencies: - '@opencode/protocol': 2.2.1 - '@opencode/schema': 2.2.1 - optionalDependencies: - effect: 4.0.1 - solid-js: 1.9.12 - - '@opencode/client@2.2.1(effect@4.0.1)(solid-js@1.9.15)': + '@opencode/client@2.2.3(effect@4.0.6)(solid-js@1.9.16)': dependencies: - '@opencode/protocol': 2.2.1 - '@opencode/schema': 2.2.1 + '@opencode/protocol': 2.2.3 + '@opencode/schema': 2.2.3 optionalDependencies: - effect: 4.0.1 - solid-js: 1.9.15 + effect: 4.0.6 + solid-js: 1.9.16 - '@opencode/plugin@2.2.1(@opencode/theme@2.2.1(typescript@5.9.3)(web-tree-sitter@0.25.10))(@opentelemetry/semantic-conventions@1.43.0)(@opentui/core@0.7.0(typescript@5.9.3)(web-tree-sitter@0.25.10))(@opentui/solid@0.7.0(solid-js@1.9.12)(typescript@5.9.3)(web-tree-sitter@0.25.10))(redis@6.2.1(@opentelemetry/api@1.9.0))(solid-js@1.9.12)(vite@7.3.0(@types/node@22.19.19)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(yaml@2.9.0))': + '@opencode/plugin@2.2.3(@opencode/theme@2.2.3(typescript@5.9.3)(web-tree-sitter@0.25.10))(@opentelemetry/semantic-conventions@1.43.0)(@opentui/core@0.8.0(typescript@5.9.3)(web-tree-sitter@0.25.10))(@opentui/solid@0.8.0(solid-js@1.9.16)(typescript@5.9.3)(web-tree-sitter@0.25.10))(redis@6.2.1(@opentelemetry/api@1.9.0))(solid-js@1.9.16)(vite@7.3.0(@types/node@22.19.19)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(yaml@2.9.0))': dependencies: '@ai-sdk/provider': 3.0.8 - '@opencode/ai': 2.2.1 - '@opencode/client': 2.2.1(effect@4.0.1)(solid-js@1.9.12) - '@opencode/protocol': 2.2.1 - '@opencode/schema': 2.2.1 - '@opencode/util': 2.2.1(@opentelemetry/semantic-conventions@1.43.0)(redis@6.2.1(@opentelemetry/api@1.9.0)) - effect: 4.0.1 + '@opencode/ai': 2.2.3 + '@opencode/client': 2.2.3(effect@4.0.6)(solid-js@1.9.16) + '@opencode/protocol': 2.2.3 + '@opencode/schema': 2.2.3 + '@opencode/util': 2.2.3(@opentelemetry/semantic-conventions@1.43.0)(redis@6.2.1(@opentelemetry/api@1.9.0)) + effect: 4.0.6 optionalDependencies: - '@opencode/theme': 2.2.1(typescript@5.9.3)(web-tree-sitter@0.25.10) - '@opentui/core': 0.7.0(typescript@5.9.3)(web-tree-sitter@0.25.10) - '@opentui/solid': 0.7.0(solid-js@1.9.12)(typescript@5.9.3)(web-tree-sitter@0.25.10) - solid-js: 1.9.12 + '@opencode/theme': 2.2.3(typescript@5.9.3)(web-tree-sitter@0.25.10) + '@opentui/core': 0.8.0(typescript@5.9.3)(web-tree-sitter@0.25.10) + '@opentui/solid': 0.8.0(solid-js@1.9.16)(typescript@5.9.3)(web-tree-sitter@0.25.10) + solid-js: 1.9.16 vite: 7.3.0(@types/node@22.19.19)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.0)(yaml@2.9.0) transitivePeerDependencies: - '@opentelemetry/sdk-trace-web' @@ -6681,29 +6636,29 @@ snapshots: - supports-color - utf-8-validate - '@opencode/protocol@2.2.1': + '@opencode/protocol@2.2.3': dependencies: - '@opencode/schema': 2.2.1 - effect: 4.0.1 + '@opencode/schema': 2.2.3 + effect: 4.0.6 - '@opencode/schema@2.2.1': + '@opencode/schema@2.2.3': dependencies: '@standard-schema/spec': 1.1.0 - effect: 4.0.1 + effect: 4.0.6 - '@opencode/theme@2.2.1(typescript@5.9.3)(web-tree-sitter@0.25.10)': + '@opencode/theme@2.2.3(typescript@5.9.3)(web-tree-sitter@0.25.10)': dependencies: - '@opentui/core': 0.7.0(typescript@5.9.3)(web-tree-sitter@0.25.10) - effect: 4.0.1 + '@opentui/core': 0.8.0(typescript@5.9.3)(web-tree-sitter@0.25.10) + effect: 4.0.6 transitivePeerDependencies: - typescript - web-tree-sitter - '@opencode/util@2.2.1(@opentelemetry/semantic-conventions@1.43.0)(redis@6.2.1(@opentelemetry/api@1.9.0))': + '@opencode/util@2.2.3(@opentelemetry/semantic-conventions@1.43.0)(redis@6.2.1(@opentelemetry/api@1.9.0))': dependencies: - '@effect/opentelemetry': 4.0.1(@opentelemetry/api-logs@0.219.0)(@opentelemetry/api@1.9.0)(@opentelemetry/resources@2.8.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-logs@0.219.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-metrics@2.8.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-node@2.8.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.43.0)(effect@4.0.1) - '@effect/platform-node': 4.0.1(effect@4.0.1)(redis@6.2.1(@opentelemetry/api@1.9.0)) - '@effect/platform-node-shared': 4.0.1(effect@4.0.1) + '@effect/opentelemetry': 4.0.6(@opentelemetry/api-logs@0.219.0)(@opentelemetry/api@1.9.0)(@opentelemetry/resources@2.8.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-logs@0.219.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-metrics@2.8.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-node@2.8.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.43.0)(effect@4.0.6) + '@effect/platform-node': 4.0.6(effect@4.0.6)(redis@6.2.1(@opentelemetry/api@1.9.0)) + '@effect/platform-node-shared': 4.0.6(effect@4.0.6) '@npmcli/arborist': 9.4.0 '@npmcli/config': 10.8.1 '@opentelemetry/api': 1.9.0 @@ -6716,7 +6671,7 @@ snapshots: '@opentelemetry/sdk-trace-base': 2.8.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-node': 2.8.0(@opentelemetry/api@1.9.0) cross-spawn: 7.0.6 - effect: 4.0.1 + effect: 4.0.6 glob: 13.0.5 mime-types: 3.0.2 minimatch: 10.2.5 @@ -6807,31 +6762,31 @@ snapshots: '@opentelemetry/semantic-conventions@1.43.0': {} - '@opentui/core-darwin-arm64@0.7.0': + '@opentui/core-darwin-arm64@0.8.0': optional: true - '@opentui/core-darwin-x64@0.7.0': + '@opentui/core-darwin-x64@0.8.0': optional: true - '@opentui/core-linux-arm64-musl@0.7.0': + '@opentui/core-linux-arm64-musl@0.8.0': optional: true - '@opentui/core-linux-arm64@0.7.0': + '@opentui/core-linux-arm64@0.8.0': optional: true - '@opentui/core-linux-x64-musl@0.7.0': + '@opentui/core-linux-x64-musl@0.8.0': optional: true - '@opentui/core-linux-x64@0.7.0': + '@opentui/core-linux-x64@0.8.0': optional: true - '@opentui/core-win32-arm64@0.7.0': + '@opentui/core-win32-arm64@0.8.0': optional: true - '@opentui/core-win32-x64@0.7.0': + '@opentui/core-win32-x64@0.8.0': optional: true - '@opentui/core@0.7.0(typescript@5.9.3)(web-tree-sitter@0.25.10)': + '@opentui/core@0.8.0(typescript@5.9.3)(web-tree-sitter@0.25.10)': dependencies: bun-ffi-structs: 0.3.1(typescript@5.9.3) diff: 9.0.0 @@ -6839,27 +6794,27 @@ snapshots: string-width: 7.2.0 web-tree-sitter: 0.25.10 optionalDependencies: - '@opentui/core-darwin-arm64': 0.7.0 - '@opentui/core-darwin-x64': 0.7.0 - '@opentui/core-linux-arm64': 0.7.0 - '@opentui/core-linux-arm64-musl': 0.7.0 - '@opentui/core-linux-x64': 0.7.0 - '@opentui/core-linux-x64-musl': 0.7.0 - '@opentui/core-win32-arm64': 0.7.0 - '@opentui/core-win32-x64': 0.7.0 + '@opentui/core-darwin-arm64': 0.8.0 + '@opentui/core-darwin-x64': 0.8.0 + '@opentui/core-linux-arm64': 0.8.0 + '@opentui/core-linux-arm64-musl': 0.8.0 + '@opentui/core-linux-x64': 0.8.0 + '@opentui/core-linux-x64-musl': 0.8.0 + '@opentui/core-win32-arm64': 0.8.0 + '@opentui/core-win32-x64': 0.8.0 transitivePeerDependencies: - typescript - '@opentui/solid@0.7.0(solid-js@1.9.12)(typescript@5.9.3)(web-tree-sitter@0.25.10)': + '@opentui/solid@0.8.0(solid-js@1.9.16)(typescript@5.9.3)(web-tree-sitter@0.25.10)': dependencies: '@babel/core': 7.29.7 '@babel/preset-typescript': 7.27.1(@babel/core@7.29.7) - '@opentui/core': 0.7.0(typescript@5.9.3)(web-tree-sitter@0.25.10) + '@opentui/core': 0.8.0(typescript@5.9.3)(web-tree-sitter@0.25.10) babel-plugin-module-resolver: 5.0.2 - babel-preset-solid: 1.9.12(@babel/core@7.29.7)(solid-js@1.9.12) + babel-preset-solid: 1.9.16(@babel/core@7.29.7)(solid-js@1.9.16) entities: 7.0.1 s-js: 0.4.9 - solid-js: 1.9.12 + solid-js: 1.9.16 transitivePeerDependencies: - supports-color - typescript @@ -7748,16 +7703,16 @@ snapshots: '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.11 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.11 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.11 '@types/better-sqlite3@7.6.13': dependencies: @@ -7954,7 +7909,7 @@ snapshots: dependencies: '@types/node': 24.10.4 - '@types/ws@8.18.1': + '@types/ws@8.18.2': dependencies: '@types/node': 24.10.4 @@ -8247,12 +8202,12 @@ snapshots: b4a@1.7.3: {} - babel-plugin-jsx-dom-expressions@0.40.7(@babel/core@7.29.7): + babel-plugin-jsx-dom-expressions@0.40.11(@babel/core@7.29.7): dependencies: '@babel/core': 7.29.7 '@babel/helper-module-imports': 7.18.6 '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) - '@babel/types': 7.29.7 + '@babel/types': 7.29.11 html-entities: 2.3.3 parse5: 7.3.0 @@ -8264,12 +8219,12 @@ snapshots: reselect: 4.1.8 resolve: 1.22.12 - babel-preset-solid@1.9.12(@babel/core@7.29.7)(solid-js@1.9.12): + babel-preset-solid@1.9.16(@babel/core@7.29.7)(solid-js@1.9.16): dependencies: '@babel/core': 7.29.7 - babel-plugin-jsx-dom-expressions: 0.40.7(@babel/core@7.29.7) + babel-plugin-jsx-dom-expressions: 0.40.11(@babel/core@7.29.7) optionalDependencies: - solid-js: 1.9.12 + solid-js: 1.9.16 bail@2.0.2: {} @@ -8283,7 +8238,7 @@ snapshots: baseline-browser-mapping@2.9.11: {} - better-auth@1.7.12(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.15)(vitest@3.2.4): + better-auth@1.7.12(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(solid-js@1.9.16)(vitest@3.2.4): dependencies: '@better-auth/core': 1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.0)(better-call@1.4.4(zod@4.3.2))(jose@6.2.13)(kysely@0.29.7)(nanostores@1.5.5) '@better-auth/drizzle-adapter': 1.7.12(@better-auth/core@1.7.12(@better-auth/utils@0.5.0)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.0)(better-call@1.4.4(zod@4.3.2))(jose@6.2.13)(kysely@0.29.7)(nanostores@1.5.5))(@better-auth/utils@0.5.0) @@ -8305,7 +8260,7 @@ snapshots: optionalDependencies: react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - solid-js: 1.9.15 + solid-js: 1.9.16 vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.10.4)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@27.4.0)(lightningcss@1.30.2)(terser@5.46.0)(yaml@2.9.0) transitivePeerDependencies: - '@opentelemetry/api' @@ -8845,7 +8800,7 @@ snapshots: dependencies: safe-buffer: 5.2.1 - effect@4.0.1: {} + effect@4.0.6: {} electron-to-chromium@1.5.267: {} @@ -10684,19 +10639,11 @@ snapshots: semver@7.7.3: {} - seroval-plugins@1.5.4(seroval@1.5.4): - dependencies: - seroval: 1.5.4 - - seroval-plugins@1.5.6(seroval@1.5.6): + seroval-plugins@1.6.12(seroval@1.6.12): dependencies: - seroval: 1.5.6 - optional: true - - seroval@1.5.4: {} + seroval: 1.6.12 - seroval@1.5.6: - optional: true + seroval@1.6.12: {} set-cookie-parser@2.7.2: {} @@ -10754,18 +10701,11 @@ snapshots: ip-address: 10.7.2 smart-buffer: 4.2.0 - solid-js@1.9.12: + solid-js@1.9.16: dependencies: csstype: 3.2.3 - seroval: 1.5.4 - seroval-plugins: 1.5.4(seroval@1.5.4) - - solid-js@1.9.15: - dependencies: - csstype: 3.2.3 - seroval: 1.5.6 - seroval-plugins: 1.5.6(seroval@1.5.6) - optional: true + seroval: 1.6.12 + seroval-plugins: 1.6.12(seroval@1.6.12) sonner@2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: diff --git a/shared/package.json b/shared/package.json index aaa65f8e8..9cdd2d904 100644 --- a/shared/package.json +++ b/shared/package.json @@ -21,8 +21,8 @@ "./themes": "./src/themes/index.ts" }, "dependencies": { - "@opencode/client": "2.2.1", - "@opencode/schema": "2.2.1", + "@opencode/client": "2.2.3", + "@opencode/schema": "2.2.3", "jsonc-parser": "^3.3.1", "zod": "^4.1.12" }, diff --git a/shared/src/opencode/release.ts b/shared/src/opencode/release.ts index 97aefb6fc..0bee5c138 100644 --- a/shared/src/opencode/release.ts +++ b/shared/src/opencode/release.ts @@ -1,6 +1,6 @@ import { compareParsedSemver, compareSemver, normalizeSemver, parseSemver, type Semver } from '../utils/semver' -export const OPENCODE_PINNED_VERSION = '2.2.1' +export const OPENCODE_PINNED_VERSION = '2.2.3' const OPENCODE_RELEASE_BASE_URL = 'https://opencode.ai/files/bin' diff --git a/shared/src/themes/OPENCODE_THEMES_LICENSE b/shared/src/themes/OPENCODE_THEMES_LICENSE index e717a38d0..377acb2d5 100644 --- a/shared/src/themes/OPENCODE_THEMES_LICENSE +++ b/shared/src/themes/OPENCODE_THEMES_LICENSE @@ -1,4 +1,4 @@ -The color palettes in opencode-palettes.ts are derived from github.com/anomalyco/opencode tag v2.0.15, packages/ui/src/theme/themes. +The color palettes in opencode-palettes.ts are derived from github.com/anomalyco/opencode tag v2.2.3, packages/ui/src/theme/themes. MIT License diff --git a/shared/src/themes/opencode-palettes.ts b/shared/src/themes/opencode-palettes.ts index d036757cc..68be58e02 100644 --- a/shared/src/themes/opencode-palettes.ts +++ b/shared/src/themes/opencode-palettes.ts @@ -221,7 +221,7 @@ export const OPENCODE_THEMES = [ id: 'catppuccin', name: 'Catppuccin', light: { - neutral: '#f5e0dc', + neutral: '#eff1f5', ink: '#4c4f69', primary: '#7287fd', accent: '#d20f39', @@ -229,13 +229,13 @@ export const OPENCODE_THEMES = [ warning: '#df8e1d', error: '#d20f39', info: '#04a5e5', - diffAdd: '#a6d189', - diffDelete: '#e78284', + diffAdd: '#40a02b', + diffDelete: '#d20f39', syntax: { - comment: '#6c7086', + comment: '#6c6f85', keyword: '#8839ef', primitive: '#1e66f5', - constant: '#ca6702', + constant: '#fe640b', }, }, dark: { @@ -243,8 +243,8 @@ export const OPENCODE_THEMES = [ ink: '#cdd6f4', primary: '#b4befe', accent: '#f38ba8', - success: '#a6d189', - warning: '#f4b8e4', + success: '#a6e3a1', + warning: '#f9e2af', error: '#f38ba8', info: '#89dceb', diffAdd: '#94e2d5', @@ -261,32 +261,27 @@ export const OPENCODE_THEMES = [ id: 'catppuccin-frappe', name: 'Catppuccin Frappe', light: { - neutral: '#303446', - ink: '#c6d0f5', - primary: '#8da4e2', - accent: '#f4b8e4', - success: '#a6d189', - warning: '#e5c890', - error: '#e78284', - info: '#81c8be', - textWeak: '#b5bfe2', + neutral: '#eff1f5', + ink: '#4c4f69', + primary: '#7287fd', + accent: '#d20f39', + success: '#40a02b', + warning: '#df8e1d', + error: '#d20f39', + info: '#04a5e5', + diffAdd: '#40a02b', + diffDelete: '#d20f39', syntax: { - comment: '#949cb8', - keyword: '#ca9ee6', - string: '#a6d189', - primitive: '#8da4e2', - property: '#99d1db', - type: '#e5c890', - constant: '#ef9f76', - variable: '#e78284', - operator: '#99d1db', - punctuation: '#c6d0f5', + comment: '#6c6f85', + keyword: '#8839ef', + primitive: '#1e66f5', + constant: '#fe640b', }, }, dark: { neutral: '#303446', ink: '#c6d0f5', - primary: '#8da4e2', + primary: '#8caaee', accent: '#f4b8e4', success: '#a6d189', warning: '#e5c890', @@ -294,10 +289,10 @@ export const OPENCODE_THEMES = [ info: '#81c8be', textWeak: '#b5bfe2', syntax: { - comment: '#949cb8', + comment: '#949cbb', keyword: '#ca9ee6', string: '#a6d189', - primitive: '#8da4e2', + primitive: '#8caaee', property: '#99d1db', type: '#e5c890', constant: '#ef9f76', @@ -311,26 +306,21 @@ export const OPENCODE_THEMES = [ id: 'catppuccin-macchiato', name: 'Catppuccin Macchiato', light: { - neutral: '#24273a', - ink: '#cad3f5', - primary: '#8aadf4', - accent: '#f5bde6', - success: '#a6da95', - warning: '#eed49f', - error: '#ed8796', - info: '#8bd5ca', - textWeak: '#b8c0e0', + neutral: '#eff1f5', + ink: '#4c4f69', + primary: '#7287fd', + accent: '#d20f39', + success: '#40a02b', + warning: '#df8e1d', + error: '#d20f39', + info: '#04a5e5', + diffAdd: '#40a02b', + diffDelete: '#d20f39', syntax: { - comment: '#939ab7', - keyword: '#c6a0f6', - string: '#a6da95', - primitive: '#8aadf4', - property: '#91d7e3', - type: '#eed49f', - constant: '#f5a97f', - variable: '#ed8796', - operator: '#91d7e3', - punctuation: '#cad3f5', + comment: '#6c6f85', + keyword: '#8839ef', + primitive: '#1e66f5', + constant: '#fe640b', }, }, dark: { @@ -709,23 +699,23 @@ export const OPENCODE_THEMES = [ ink: '#54433A', primary: '#2D4F67', accent: '#D27E99', - success: '#98BB6C', - warning: '#D7A657', + success: '#6f894e', + warning: '#cc6d00', error: '#E82424', - info: '#76946A', + info: '#4d699b', diffAdd: '#89AF5B', diffDelete: '#D61F1F', - textWeak: '#9E9389', + textWeak: '#8a8980', syntax: { - comment: '#9E9389', - keyword: '#957FB8', - string: '#98BB6C', + comment: '#8a8980', + keyword: '#624c83', + string: '#6f894e', primitive: '#2D4F67', - property: '#76946A', - type: '#C38D9D', - constant: '#D7A657', + property: '#4d699b', + type: '#b35b79', + constant: '#cc6d00', variable: '#54433A', - operator: '#D27E99', + operator: '#735896', punctuation: '#54433A', }, },