From a9220e86042d4df549a0ce4446c526da3ad0dea3 Mon Sep 17 00:00:00 2001 From: Chris Scott <99081550+chriswritescode-dev@users.noreply.github.com> Date: Fri, 30 Oct 2026 21:33:54 -0400 Subject: [PATCH] chore(opencode): move the OpenCode pin to 2.2.3 and ocm-cli to OpenTUI 0.8 (OM-169) OpenCode 2.2.3 requires TUI plugins built for OpenTUI 0.8. Move the single OpenCode pin, the typed client and schema, the Docker default and the CI download to 2.2.3, so the supported range becomes >=2.2.3 <3.0.0, and regenerate the theme palettes from the v2.2.3 tag. Move ocm-cli to @opencode/plugin and @opencode/theme 2.2.3 and OpenTUI 0.8.0, raise the solid-js dev pin and peer floor to 1.9.16, and teach the package-compat test to read the floor of a range peer, keeping a patch-level 0.x floor and normalizing prefixed versions. Guard the CI workflow's download against the pin in the contract test, take the binary test fixture from the pin, and document the ocm 0.5.x requirement of a local OpenCode >= 2.2.3. --- .github/workflows/ci.yml | 2 +- AGENTS.md | 2 +- Dockerfile | 2 +- .../services/opencode-server-registry.test.ts | 12 +- backend/test/helpers/opencode-binary.test.ts | 4 +- backend/test/routes/settings.test.ts | 106 ++--- .../test/services/opencode-installer.test.ts | 62 +-- .../services/opencode-single-server.test.ts | 62 +-- backend/test/shared/opencode-contract.test.ts | 44 +- ocm-cli/README.md | 18 +- ocm-cli/package.json | 18 +- ocm-cli/test/package-compat.test.ts | 93 +++- pnpm-lock.yaml | 428 ++++++++---------- shared/package.json | 4 +- shared/src/opencode/release.ts | 2 +- shared/src/themes/OPENCODE_THEMES_LICENSE | 2 +- shared/src/themes/opencode-palettes.ts | 108 ++--- 17 files changed, 491 insertions(+), 478 deletions(-) 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', }, },