Bring the Wails desktop shell to feature parity with the CLI for provider and alias management while keeping the browser fallback working. Wire tray, notifications, autostart, and GUI warnings so desktop flows behave predictably.
526 lines
18 KiB
Markdown
526 lines
18 KiB
Markdown
# Journal - Apale (Part 1)
|
|
|
|
> AI development session journal
|
|
> Started: 2026-04-16
|
|
|
|
---
|
|
|
|
|
|
|
|
## Session 1: Finalize OPS MVP review PRD
|
|
|
|
**Date**: 2026-04-17
|
|
**Task**: Finalize OPS MVP review PRD
|
|
**Branch**: `master`
|
|
|
|
### Summary
|
|
|
|
(Add summary)
|
|
|
|
### Main Changes
|
|
|
|
| Area | Description |
|
|
|------|-------------|
|
|
| PRD Redesign | Reframed OPS MVP around alias-driven multi-provider failover for OpenAI Responses only. |
|
|
| OpenCode Integration | Locked config-sync approach for exposing aliases through `provider.ops.models`, with connected-provider requirement. |
|
|
| Failover Semantics | Finalized pre-first-byte-only failover, streaming pass-through, and no mid-stream provider switching. |
|
|
| MVP Boundaries | Locked import scope to config-defined `@ai-sdk/openai`, excluded `auth.json` as provider definition source, and kept `ops doctor` static by default. |
|
|
| Task Closure | Marked review task completed, cleared current task, and archived both finished docs tasks. |
|
|
|
|
**Updated Files**:
|
|
- `.trellis/tasks/archive/2026-04/04-17-04-17-ops-mvp-design-review/prd.md`
|
|
- `.trellis/tasks/archive/2026-04/04-17-04-17-ops-mvp-design-review/task.json`
|
|
- `.trellis/tasks/archive/2026-04/04-17-ops-mvp-design/task.json`
|
|
|
|
**Notes**:
|
|
- Follow-up implementation should start in a new task from the finalized PRD.
|
|
- Existing unrelated worktree change in `AGENTS.md` was left untouched.
|
|
|
|
|
|
### Git Commits
|
|
|
|
| Hash | Message |
|
|
|------|---------|
|
|
| `eeacdc4` | (see git log) |
|
|
| `00747fa` | (see git log) |
|
|
| `ca0b3c4` | (see git log) |
|
|
|
|
### Testing
|
|
|
|
- [OK] (Add test results)
|
|
|
|
### Status
|
|
|
|
[OK] **Completed**
|
|
|
|
### Next Steps
|
|
|
|
- None - task complete
|
|
|
|
|
|
## Session 2: Build OPS MVP failover proxy
|
|
|
|
**Date**: 2026-04-17
|
|
**Task**: Build OPS MVP failover proxy
|
|
**Branch**: `master`
|
|
|
|
### Summary
|
|
|
|
Implemented the Go-based OPS MVP: local config, provider and alias CLI, OpenCode sync/import, and a streaming OpenAI Responses proxy with deterministic pre-first-byte failover. Added Chinese and English README documentation for quick onboarding.
|
|
|
|
### Main Changes
|
|
|
|
(Add details)
|
|
|
|
### Git Commits
|
|
|
|
| Hash | Message |
|
|
|------|---------|
|
|
| `2b04d91` | (see git log) |
|
|
|
|
### Testing
|
|
|
|
- [OK] (Add test results)
|
|
|
|
### Status
|
|
|
|
[OK] **Completed**
|
|
|
|
### Next Steps
|
|
|
|
- None - task complete
|
|
|
|
|
|
## Session 3: Support disabling providers in ocswitch
|
|
|
|
**Date**: 2026-04-17
|
|
**Task**: Support disabling providers in ocswitch
|
|
**Branch**: `master`
|
|
|
|
### Summary
|
|
|
|
Added provider-level disable/enable support, made failover skip disabled providers without mutating alias target state, and aligned doctor/opencode sync/models exposure with routable aliases.
|
|
|
|
### Main Changes
|
|
|
|
(Add details)
|
|
|
|
### Git Commits
|
|
|
|
| Hash | Message |
|
|
|------|---------|
|
|
| `HEAD` | (see git log) |
|
|
|
|
### Testing
|
|
|
|
- [OK] (Add test results)
|
|
|
|
### Status
|
|
|
|
[OK] **Completed**
|
|
|
|
### Next Steps
|
|
|
|
- None - task complete
|
|
|
|
|
|
## Session 4: Review MVP completion status
|
|
|
|
**Date**: 2026-04-17
|
|
**Task**: Review MVP completion status
|
|
**Branch**: `master`
|
|
|
|
### Summary
|
|
|
|
Reviewed current implementation against the archived MVP PRD and classified implemented, missing, and beyond-MVP features.
|
|
|
|
### Main Changes
|
|
|
|
| Category | Result |
|
|
|---|---|
|
|
| Overall status | MVP core flow is effectively complete |
|
|
| Implemented MVP | Local ocswitch config, provider/alias CLI, OpenCode sync, static doctor, `/v1/responses` proxy, streaming pass-through, pre-first-byte failover, debug headers |
|
|
| Partial / missing MVP edges | `doctor` validates generated preview more than on-disk synced state; OpenCode provider import only reads `options.apiKey`, not broader header-style auth |
|
|
| Beyond MVP | `provider enable/disable`, minimal `/v1/models`, broader alias normalization, careful OpenCode config patching |
|
|
|
|
**Reviewed Sources**:
|
|
- `.trellis/tasks/archive/2026-04/04-17-04-17-ops-mvp-design-review/prd.md`
|
|
- `internal/config/config.go`
|
|
- `internal/cli/provider.go`
|
|
- `internal/cli/alias.go`
|
|
- `internal/cli/opencode.go`
|
|
- `internal/cli/doctor.go`
|
|
- `internal/cli/serve.go`
|
|
- `internal/opencode/opencode.go`
|
|
- `internal/proxy/server.go`
|
|
- `internal/proxy/server_test.go`
|
|
- `internal/opencode/opencode_test.go`
|
|
- `internal/cli/cli_test.go`
|
|
- `internal/config/config_test.go`
|
|
|
|
**Verification**:
|
|
- Ran `go test ./...` successfully: 34 tests passed across 5 packages.
|
|
|
|
|
|
### Git Commits
|
|
|
|
(No commits - planning session)
|
|
|
|
### Testing
|
|
|
|
- [OK] (Add test results)
|
|
|
|
### Status
|
|
|
|
[OK] **Completed**
|
|
|
|
### Next Steps
|
|
|
|
- None - task complete
|
|
|
|
|
|
## Session 5: Fix sync command panic
|
|
|
|
**Date**: 2026-04-17
|
|
**Task**: Fix sync command panic
|
|
**Branch**: `master`
|
|
|
|
### Summary
|
|
|
|
Fixed a panic in opencode sync when preserved model metadata contains slices, and added package plus CLI regression coverage.
|
|
|
|
### Main Changes
|
|
|
|
- Root cause: `internal/opencode/opencode.go` compared `interface{}` values directly inside `mapsEqualShallow`, which panicked when preserved `provider.ocswitch.models.<alias>` metadata included slices.
|
|
- Fix: replaced the unsafe hand-rolled comparison with `reflect.DeepEqual` so existing model metadata with nested maps/slices can be compared safely during `sync`.
|
|
- Added regression tests in `internal/opencode/opencode_test.go` and `internal/cli/cli_test.go` covering preserved slice metadata and a real `opencode sync --target` no-op path.
|
|
- Verification: ran `rtk go test ./internal/opencode`, `rtk go test ./internal/cli ./internal/opencode`, and `rtk go test ./...` successfully.
|
|
|
|
|
|
### Git Commits
|
|
|
|
| Hash | Message |
|
|
|------|---------|
|
|
| `887eb14` | (see git log) |
|
|
|
|
### Testing
|
|
|
|
- [OK] (Add test results)
|
|
|
|
### Status
|
|
|
|
[OK] **Completed**
|
|
|
|
### Next Steps
|
|
|
|
- None - task complete
|
|
|
|
|
|
## Session 6: Rename CLI to ocswitch
|
|
|
|
**Date**: 2026-04-17
|
|
**Task**: Rename CLI to ocswitch
|
|
**Branch**: `master`
|
|
|
|
### Summary
|
|
|
|
Renamed the CLI and synced docs, examples, and Trellis history from olpx/opswitch to ocswitch while keeping the repository name opencode-provider-switch.
|
|
|
|
### Main Changes
|
|
|
|
(Add details)
|
|
|
|
### Git Commits
|
|
|
|
| Hash | Message |
|
|
|------|---------|
|
|
| `cf3dcec` | (see git log) |
|
|
|
|
### Testing
|
|
|
|
- [OK] (Add test results)
|
|
|
|
### Status
|
|
|
|
[OK] **Completed**
|
|
|
|
### Next Steps
|
|
|
|
- None - task complete
|
|
|
|
|
|
## Session 7: Deep code review for ocswitch
|
|
|
|
**Date**: 2026-04-17
|
|
**Task**: Deep code review for ocswitch
|
|
**Branch**: `master`
|
|
|
|
### Summary
|
|
|
|
Recorded the deep code review findings in Trellis, including 2 high-risk, 4 medium-risk, and 4 low-risk/improvement items with concrete remediation guidance.
|
|
|
|
### Main Changes
|
|
|
|
- Added `.trellis/tasks/04-17-deep-code-review-ocswitch/review.md` to capture the full deep review output and concrete remediation guidance.
|
|
- Recorded 2 high-risk items:
|
|
- concurrent config/OpenCode save paths are unsafe under concurrent writers
|
|
- proxy request body has no read timeout after headers
|
|
- Recorded 4 medium-risk items:
|
|
- streaming responses have no idle timeout
|
|
- retryable upstream failures are collapsed into a generic `502`
|
|
- `opencode sync --set-model` / `--set-small-model` can silently write invalid defaults
|
|
- fixed default API key remains unsafe when binding to non-loopback addresses
|
|
- Recorded 4 low-risk or improvement items:
|
|
- alias lifecycle lacks enable/disable recovery path
|
|
- provider import docs and implementation disagree on empty `apiKey`
|
|
- `opencode sync` side effects on JSONC comments and `$schema` need clearer docs
|
|
- header forwarding should better handle dynamic hop-by-hop headers and narrower forwarding rules
|
|
- Verification already completed during review:
|
|
- `go test ./...`
|
|
- `go test -race ./...`
|
|
|
|
|
|
### Git Commits
|
|
|
|
(No commits - planning session)
|
|
|
|
### Testing
|
|
|
|
- [OK] (Add test results)
|
|
|
|
### Status
|
|
|
|
[OK] **Completed**
|
|
|
|
### Next Steps
|
|
|
|
- None - task complete
|
|
|
|
|
|
## Session 8: Provider discovery and model ref hardening
|
|
|
|
**Date**: 2026-04-18
|
|
**Task**: Provider discovery and model ref hardening
|
|
**Branch**: `master`
|
|
|
|
### Summary
|
|
|
|
Completed provider model discovery hardening, provider/model parsing improvements, README/help sync, follow-up review fixes, and final test-name cleanup.
|
|
|
|
### Main Changes
|
|
|
|
(Add details)
|
|
|
|
### Git Commits
|
|
|
|
| Hash | Message |
|
|
|------|---------|
|
|
| `09d0c1f` | (see git log) |
|
|
|
|
### Testing
|
|
|
|
- [OK] (Add test results)
|
|
|
|
### Status
|
|
|
|
[OK] **Completed**
|
|
|
|
### Next Steps
|
|
|
|
- None - task complete
|
|
|
|
|
|
## Session 9: GUI desktop direction and architecture decision
|
|
|
|
**Date**: 2026-04-18
|
|
**Task**: forwarding-log-viewer-gui
|
|
**Branch**: `master`
|
|
|
|
### Summary
|
|
|
|
Recorded the GUI direction change from a local web-only surface to a desktop-shell follow-up, driven by explicit requirements for launch at login, native menu/tray integration, and native notifications.
|
|
|
|
### Main Changes
|
|
|
|
- Confirmed the existing Trellis task `04-17-forwarding-log-viewer-gui` remains historically correct as a completed local web log-viewer design task and should not be retrofitted in place.
|
|
- Recorded follow-up product guidance that desktop capabilities now justify a separate native-shell track rather than a browser-only UI.
|
|
- Captured the recommended follow-up stack as `Wails + React + TypeScript + Tailwind CSS + react-hook-form + zod`.
|
|
- Captured the preferred layering so existing Go logic is not rewritten into desktop-specific code:
|
|
- `internal/config` continues config IO and validation
|
|
- `internal/proxy` continues proxy runtime and failover
|
|
- `internal/opencode` continues OpenCode sync
|
|
- new `internal/app` application service layer is shared by CLI and GUI
|
|
- Wails desktop shell owns window, tray/menu, notifications, autostart, and frontend hosting only
|
|
- Recorded the frontend recommendation that React is a better fit than Vue for this project because the desktop control panel is form-heavy and aligns better with the chosen `react-hook-form + zod` stack.
|
|
|
|
### Git Commits
|
|
|
|
(No commits - Trellis documentation update only)
|
|
|
|
### Testing
|
|
|
|
- [OK] No code changes; updated Trellis task metadata and workspace journal only
|
|
|
|
### Status
|
|
|
|
[OK] **Completed**
|
|
|
|
### Next Steps
|
|
|
|
- Create a separate Trellis task for the desktop shell if implementation should proceed
|
|
|
|
|
|
## Session 10: Desktop shell skeleton implementation
|
|
|
|
**Date**: 2026-04-18
|
|
**Task**: Desktop shell skeleton implementation
|
|
**Branch**: `master`
|
|
|
|
### Summary
|
|
|
|
Implemented the first desktop-shell skeleton by introducing a shared internal/app layer, desktop preference persistence, CLI reuse of shared workflows, and a minimal desktop bootstrap with passing Go tests/builds.
|
|
|
|
### Main Changes
|
|
|
|
- Added `config.Desktop` to persist desktop-shell preferences (`launch_at_login`, `minimize_to_tray`, `notifications`) without coupling core runtime logic to a desktop framework.
|
|
- Added `internal/app/types.go` and `internal/app/service.go` as the shared application-service layer described in the PRD.
|
|
- Implemented shared DTOs and workflows for:
|
|
- overview
|
|
- provider listing
|
|
- doctor report generation
|
|
- OpenCode sync preview/apply plumbing
|
|
- proxy lifecycle management
|
|
- desktop preference read/write
|
|
- Refactored CLI reuse points so `doctor`, `opencode sync`, `provider list`, and `serve` now delegate through `internal/app` instead of keeping those orchestration paths CLI-only.
|
|
- Preserved CLI output behavior closely while centralizing the orchestration logic that future desktop bindings can call.
|
|
- Added `internal/desktop/` skeleton adapters (`app`, `bindings`, `tray`, `notify`, `autostart`) as placeholders for a future Wails/native shell integration, keeping desktop-only concerns outside `internal/app`.
|
|
- Added `cmd/ocswitch-desktop/main.go` as a minimal desktop bootstrap binary that exercises the shared bindings and confirms the skeleton is wired.
|
|
- Added `internal/app/service_test.go` to cover desktop preference persistence and proxy start/stop status flow.
|
|
- Verified the implementation with:
|
|
- `gofmt -w ...`
|
|
- `rtk go test ./...`
|
|
- `rtk go build ./...`
|
|
- Scope intentionally stayed at the PRD's recommended “skeleton wiring only” level: no Wails dependency, no React frontend, and no tray/autostart implementation yet.
|
|
|
|
|
|
### Git Commits
|
|
|
|
(No commits - planning session)
|
|
|
|
### Testing
|
|
|
|
- [OK] (Add test results)
|
|
|
|
### Status
|
|
|
|
[OK] **Completed**
|
|
|
|
### Next Steps
|
|
|
|
- None - task complete
|
|
|
|
|
|
## Session 11: Desktop control panel implementation
|
|
|
|
**Date**: 2026-04-18
|
|
**Task**: Desktop control panel implementation
|
|
**Branch**: `master`
|
|
|
|
### Summary
|
|
|
|
Extended the desktop-shell skeleton into a minimal usable local control panel by adding an embedded web UI, desktop HTTP bindings, alias/provider overview surfaces, proxy controls, desktop preference editing, and OpenCode sync/doctor actions while keeping the shared Go application layer intact.
|
|
|
|
### Main Changes
|
|
|
|
- Upgraded `cmd/ocswitch-desktop/main.go` from a skeleton print-only bootstrap into a runnable local desktop control panel entrypoint with `--config`, `--listen`, and `--no-open` flags.
|
|
- Added `internal/desktop/http.go` as a lightweight desktop shell runtime that:
|
|
- serves embedded frontend assets
|
|
- exposes JSON endpoints for overview, providers, aliases, proxy status/start/stop, desktop prefs, doctor, and OpenCode sync preview/apply
|
|
- opens the browser by default and shuts down cleanly on SIGINT/SIGTERM
|
|
- Added `web/` embedded assets (`web/assets.go`, `web/dist/index.html`, `web/dist/app.css`, `web/dist/app.js`) to provide a minimal control-panel UI without introducing Wails/WebKit runtime dependencies into the current repo.
|
|
- Expanded `internal/app`/`internal/desktop` bindings with alias DTOs and alias listing so the GUI can show both routable provider state and alias routing state.
|
|
- Added `internal/desktop/http_test.go` to verify the desktop control panel serves the app shell, returns overview JSON, and persists desktop preferences through the HTTP API.
|
|
- Verified with:
|
|
- `gofmt -w cmd/ocswitch-desktop/main.go internal/app/service.go internal/app/types.go internal/desktop/bindings.go internal/desktop/http.go internal/desktop/http_test.go web/assets.go`
|
|
- `rtk go test ./...`
|
|
- `rtk go build ./...`
|
|
- `go run ./cmd/ocswitch-desktop --no-open` followed by live HTTP checks against `/` and `/api/overview`
|
|
- Constraint note: the PRD still recommends Wails as the long-term native shell, but the current environment lacks `wails` CLI and desktop system dependencies, so this implementation deliberately ships a dependency-light local control panel first while keeping `internal/app` and `internal/desktop` ready for a future Wails swap-in.
|
|
|
|
|
|
### Git Commits
|
|
|
|
(No commits - planning session)
|
|
|
|
### Testing
|
|
|
|
- [OK] (Add test results)
|
|
|
|
### Status
|
|
|
|
[OK] **Completed**
|
|
|
|
### Next Steps
|
|
|
|
- None - task complete
|
|
|
|
|
|
## Session 12: Wails desktop shell integration
|
|
|
|
**Date**: 2026-04-18
|
|
**Task**: Wails desktop shell integration
|
|
**Branch**: `master`
|
|
|
|
### Summary
|
|
|
|
Migrated the desktop control panel onto a formal Wails + React/TypeScript structure while preserving a browser fallback shell, added real Linux XDG launch-at-login support, and verified both default and desktop_wails Go paths. Native desktop compilation now fails only on missing Linux system packages rather than repository structure issues.
|
|
|
|
### Main Changes
|
|
|
|
- Added Wails v2.12.0 to `go.mod` and introduced `wails.json` so the repository has a formal desktop-shell project structure.
|
|
- Split desktop entrypoints by build tag:
|
|
- `cmd/ocswitch-desktop/main_fallback.go` keeps the browser fallback shell for default builds.
|
|
- `cmd/ocswitch-desktop/main_wails.go` and root `main_wails.go` provide the real `desktop_wails` Wails entry path expected by the Wails CLI.
|
|
- Added `internal/desktop/wails.go` to centralize Wails startup configuration, bind the desktop app object, and serve `frontend/dist` assets from the same source used by the browser fallback shell.
|
|
- Expanded `internal/desktop/app.go` into a real desktop composition root with startup, shutdown, close-to-background, preference sync, metadata, and Wails-callable facade methods.
|
|
- Replaced the ad-hoc `web/` assets with a formal `frontend/` Vite + React + TypeScript app:
|
|
- `frontend/src/App.tsx` now owns the GUI.
|
|
- `frontend/src/api.ts` bridges both Wails-bound calls and fallback HTTP `/api/*` calls.
|
|
- `frontend/src/types.ts` mirrors the Go DTOs.
|
|
- `frontend/src/env.d.ts` declares the Wails bridge surface.
|
|
- `frontend/src/styles.css` carries forward the control-panel styling.
|
|
- Updated the fallback HTTP shell in `internal/desktop/http.go` to serve `frontendassets.DistFS()` and to align doctor/meta responses with the Wails bridge semantics.
|
|
- Implemented real Linux XDG launch-at-login handling in `internal/desktop/autostart.go` and added `internal/desktop/autostart_test.go` to cover write/remove behavior.
|
|
- Wired `MinimizeToTray` into close-to-background behavior through `internal/desktop/tray.go` using public Wails window lifecycle APIs only; intentionally did not depend on private Wails tray internals because the pinned Wails version does not expose a stable public tray API.
|
|
- Added tag-specific runtime helpers:
|
|
- `internal/desktop/runtime_wails.go` hides the Wails window.
|
|
- `internal/desktop/runtime_fallback.go` is a no-op for browser fallback mode.
|
|
- Removed the obsolete `web/` embedded assets directory after the frontend migration because all code now serves assets from `frontend/`.
|
|
- Verified with:
|
|
- `rtk npm install` (frontend dependencies)
|
|
- `rtk npm run build`
|
|
- `rtk go test ./...`
|
|
- `rtk go test -tags desktop_wails ./...`
|
|
- `wails build -tags desktop_wails -debug`
|
|
- Verification outcome:
|
|
- repository structure, bindings generation, frontend build, and tagged Go compilation all succeed
|
|
- `wails build` now reaches native Linux compilation and stops only at missing system packages (`pkg-config`, and likely GTK/WebKit dev packages)
|
|
- native tray menus and native notifications remain intentionally incomplete because the current pinned Wails release does not provide a stable public tray API and no notification backend has been integrated yet
|
|
|
|
|
|
### Git Commits
|
|
|
|
(No commits - planning session)
|
|
|
|
### Testing
|
|
|
|
- [OK] (Add test results)
|
|
|
|
### Status
|
|
|
|
[OK] **Completed**
|
|
|
|
### Next Steps
|
|
|
|
- None - task complete
|