fix: OpenCode Go session-cookie mode and DeepSeek/Moonshot dashboard tabs - #139
Merged
Merged
Conversation
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
OpenCode retired the /workspace/<id>/go page: it now redirects to login, so cookie users only ever saw "opencode: unauthorized" (#134). Session-cookie mode now calls GET /console/api/go/status with the __Host-console_session cookie and an x-org-id header, the same endpoint the service-account key mode (#136) uses. The dead HTML scraper is removed. - The cookie setting accepts a bare value, name=value, a full cookie header, or a copied "Cookie: ..." line. A rejected cookie gets an error that names the cookie to paste; bodies and cookies are never echoed. - Meters are stored in USD (currency format) for both modes instead of a percent of 100. Utilization is unchanged, so charts and cycle history are unaffected. Absolute notification overrides now compare in dollars, and older snapshots stay in percent; both are called out in docs/OPENCODE_SETUP.md. - Status responses are reused per credential for 60s; 3xx is treated as unauthorized and never followed. - Docs, README, .env.example and the settings hints describe the session cookie instead of the old auth cookie.
getCurrentProvider() had no branch for the DeepSeek or Moonshot grids, so both tabs resolved to "synthetic": no cards, Synthetic chart labels, and failed insights. Dashboard: - Detect both tabs; render Total/Granted/Topped Up (DeepSeek) and Available/Voucher/Cash (Moonshot) balance cards, updated in place. - Balance chart with currency-formatted axis and tooltips, uncapped y-axis, and legend-hidden series kept hidden across refreshes. - Logging history and a Balance cycle overview, formatted as amounts. Backend: - DeepSeek hardcoded CNY in eight places, so USD accounts got empty summary, insights and cycles. Use the requested currency, else the latest snapshot's. - Logging history for both providers now uses the shared crossQuotas row shape the table reads, one column per balance field. - Cycle rows carry cycleId, and the four duplicated cycle-overview builders are one helper per provider.
…per log - Before the first poll the DeepSeek/Moonshot current payload is a zero placeholder with no status. Show "No balance data yet" instead of zero-balance cards marked Healthy. - DeepSeek logging history labels rows with one currency, so rows taken in another currency (an account that switched CNY/USD) are skipped instead of shown with the wrong symbol.
Windows: - getCredentialsFilePath and Setsid tests are Unix-only; move them behind !windows so the test binaries build on Windows (#134). - New "Windows" CI job on windows-latest: go vet, go test and the new provider e2e test. The daemon logs are printed on failure. E2E: - The mock server serves the OpenCode Go console status API (session cookie + x-org-id or Bearer, rejecting the old auth cookie) and the DeepSeek and Moonshot balance APIs. - OPENCODE_GO_BASE_URL, DEEPSEEK_BASE_URL and MOONSHOT_BASE_URL point those clients at a proxy or the mock (same pattern as COMMANDCODE_BASE_URL). - test_provider_balances.py runs a dedicated daemon with real agents and checks the OpenCode dollar cards (#134) and the DeepSeek and Moonshot cards, chart and logging rows (#137). - The harness uses tempdir paths, .exe names and USERPROFILE, and logs the daemon to a file instead of an unread pipe. Credential safety: the Anthropic agent wires keychain credential refresh even for an explicit token, so the fixture now pins Anthropic to statusline mode (no keychain read, no API, no refresh). Cursor tokens are also read from the macOS Keychain and can be refreshed, so the suite refuses to run on a non-CI Mac unless ONWATCH_E2E_ALLOW_HOST=1.
… bugs it hid The first go test ./... on windows-latest failed in 13 of 20 packages and hung two. Most failures were tests that only set HOME, which Windows ignores in favour of USERPROFILE; that also meant tests read and wrote the runner's real profile, including %USERPROFILE%\.claude\.credentials.json. Credential safety: - New internal/testutil/testhome: SandboxHome (TestMain) and SetTestHome point HOME, USERPROFILE and LOCALAPPDATA at a temp dir and clear provider path overrides. api, agent, web, cmd/onwatch and update use it instead of per-package copies. - In api test mode the Claude credentials-file helpers refuse the real home on Windows and Unix; cmd/onwatch and web tests now enable test mode (web tests could previously query the real macOS Keychain). - cmd/onwatch tests use a network-free updater and ONWATCH_STAR=no; the update test replaces a copied binary, not the running test. Windows product fixes: - Statusline bridge: only installed when Git Bash exists (Claude Code runs the command in PowerShell otherwise), an unrunnable leftover is removed, and the Windows command uses the absolute data dir. A bridge synced from another OS is left alone instead of rewritten on every health check. - Antigravity: the PowerShell/CIM probe matched its own process; netstat parsing no longer requires the English LISTENING (German Windows), preferring LISTENING rows when present. - onwatch update could not see or stop a running daemon (signal 0, SIGTERM and ps); uses processAlive/stopProcess and the image name. - Grok binary fallback, DB migration and Gemini detection built paths from $HOME; they use os.UserHomeDir. - procscan's Windows tasklist check honours the scan timeout. - perf-monitor: PID file location/format, process liveness (always false before, on every OS), .exe name, stop via Kill on Windows, no os.Chdir, and it never signals a stale PID that is not onWatch. Test portability: Unix permission checks only on Unix, filepath-built expectations, pipes drained while writing (fixes the perf-monitor hang), fakes via command hooks instead of #!/bin/sh scripts, and child processes stopped with Kill where signals do not exist.
All jobs run in parallel on separate runners, so wall time is the slowest job rather than the sum: - Lint: gofmt must be clean; go vet for linux, darwin and windows, and with -tags menubar for linux and windows. - Test: go test ./... on Linux, macOS and Windows (-race on Linux and macOS), plus the menubar-tagged tray packages. - Test (Alpine): the full suite on musl/busybox, the Docker base. - Build: all six release binaries exactly as release.yml builds them. - E2E: the full Playwright suite on Linux, macOS and Windows. - Installer: install.sh on Linux and macOS, install.ps1 on PowerShell 5.1 and 7. - Docker: build both images and check each serves /login. - Nix: nix build .#onwatch (catches a stale vendorHash). - CI OK: fails if any job did not pass. A new push to a PR cancels its stale run. Also address the code-quality bot on tests/e2e/conftest.py: close the parent's log handle once the daemon starts, and explain the ignored cleanup error.
CI now fails on unformatted Go files. No functional changes.
main now passes the per-connection pragmas in the DSN, but a path that already carried a query (e.g. file:/data/onwatch.db?_txlock=immediate) was left untouched, so every connection again ran with busy_timeout=0 and foreign keys off. Append the pragmas the caller did not set itself instead.
tr -dc ... </dev/urandom | head -c 12 never ends when SIGPIPE is ignored (CI runners, Node-spawned terminals such as VS Code's): BSD tr only checks write errors at end of input, and /dev/urandom never ends. Read a bounded 512 bytes instead.
…he profiles dir - Process name and zombie checks read /proc on Linux instead of ps, which is absent in the Nix build sandbox and the distroless image, and busybox's has no -p. macOS still uses ps. - listCodexProfiles only treats a missing directory as "no profiles". Windows reports a file in the directory's place as "path not found", which was silently read as an empty list. - perf-monitor: a local request can measure 0s on Windows' coarse clock, so check the duration aggregates are consistent instead of strictly positive.
- Alpine: remove /.dockerenv and run as a non-root user, so the job tests the musl/busybox userland rather than onWatch's Docker mode, and permission tests are meaningful. - E2E harness: each daemon gets its own LOCALAPPDATA. On Windows the test PID file lives there, so the second daemon stopped the first and every later test errored. - Provider e2e: wait with function-form wait_for_function (the dashboard's CSP forbids the eval Playwright uses for expression strings), wait for the logging row value rather than the template placeholder, and put URL, grid, page errors and API state in the failure message. - Update two stale assertions to the current UI: "Updated HH:MM:SS" and the logging-history columns (#, Time, one per quota). - On failure, upload Playwright traces and print the daemon's own log.
comm is the name the process was started as, which is what ps -o comm= reported. exe resolves symlinks, so onWatch launched through a symlink named onwatch (or the tests' nc listener) was no longer recognised.
initSettingsPage attached the password handler only after awaiting the menubar and settings loads, so clicking "Update Password" during a slow load did nothing (the Windows e2e run hit this every time). Wire it first, and mark .settings-page data-ready once every control is wired; the e2e settings fixtures now wait for that marker.
prakersh
force-pushed
the
fix/opencode-console-cookie
branch
from
September 28, 2026 09:22
0e36e1f to
94582f9
Compare
The read-only scope check built file:C:%5C... for Windows paths, so it always failed: profiles without Mistral cookies still reached the credential store, and imports failed. Use file:///C:/...?mode=ro. Also make two tests portable: the browser roots test used a path that is not absolute on Windows, and the settings init test did not handle a CRLF checkout of app.js.
The handler can still be serving a request after Run returns, so the plain int counter raced with the assertion under -race.
This was referenced Sep 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two dashboard/provider fixes, one commit each.
OpenCode Go session-cookie mode (fixes #134)
OpenCode retired
/workspace/<id>/go(it now redirects to login), so cookie users only sawopencode: unauthorized. Session-cookie mode now readsGET /console/api/go/statuswith the__Host-console_sessioncookie and anx-org-idheader, the same endpoint the service-account key mode from #136 uses. The dead HTML scraper is removed.name=value, a full cookie header, or a copiedCookie: ...line. A rejected cookie gets an error that names the cookie to paste.$3.80 / $30.00plus the percent). Utilization is unchanged, so charts and cycle history are unaffected.docs/OPENCODE_SETUP.md.DeepSeek and Moonshot tabs (fixes #137)
getCurrentProvider()had no branch for either grid, so both tabs resolved to Synthetic.crossQuotasrow shape; cycle rows carrycycleId; the duplicated cycle-overview builders are one helper per provider.Not in scope: the All-providers view still does not render balance providers (DeepSeek, Moonshot, OpenRouter), and Moonshot's API reports no currency, so its cards show bare amounts.
Testing
./app.sh --test(race + coverage) passes;go vetclean.