This reverts commit 992a965. After re-reading the upstream Heicode
design docs (heicode.md, heicode-runtime-auth-newapi-secret-design.md,
plan.md), it is clear that:
1. users.group = channelId is the correct upstream behaviour. Agnet's
/me is the source of truth for which NewAPI channel a user belongs
to. Forking that logic in NewAPI to special-case role>=root breaks
the documented "Manager owns identity, NewAPI is just the model
gateway" boundary.
2. The empty-abilities symptom isn't a NewAPI fork bug. It's that
chenchen was created by raw SQL INSERT into NewAPI's users table —
a path that doesn't exist in the design. Real users get their
channelId from Manager (mcp-server) at login, and ability rows for
that channelId are provisioned out-of-band by platform operations
when the channel goes live.
3. Patching NewAPI to silently keep an admin's hand-edited group hides
the real provisioning gap and pollutes the upstream sync logic for
every future user.
Restoring upstream behaviour. Out-of-band fixes (whether to
provision abilities, route mcp-server logins, etc.) belong elsewhere.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
syncLocalUserFromAgnet rewrites users.group with the channelId returned
by Agnet's /me on every web /sign-in. That's correct for normal users —
their channel membership is owned by the Agnet identity service. But
platform administrators (RoleRootUser) are provisioned out-of-band:
operators set their group to "default" (or whichever billing tier)
manually, and their NewAPI abilities exist there.
When a root admin logs in via the web, Agnet returns a stub channelId
that has no abilities rows. The current code overwrites users.group
with that stub, and the next /v1/models call returns an empty list —
the desktop client then falls back to providerPresets.defaultModels,
hiding the real model catalogue from the operator.
Add a role guard so the rewrite only fires for users below root. Root
admins keep whatever group an operator set in the DB.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
User-supplied screenshot of the Heicode H circuit logo (heicode-logo.png
at repo root) was background-removed via flood-fill from the image
borders, edge-feathered with a 0.7px Gaussian on the alpha channel, and
upscaled to 1024x1024 as the master.
Replaced everywhere the icon is referenced:
src-tauri/icons/
32x32.png, 128x128.png, 128x128@2x.png — Tauri build inputs
icon.ico — multi-res 16/24/32/48/64/128/256 (Windows installer +
taskbar)
icon.icns — multi-res 16/32/64/128/256/512/1024 (macOS bundle)
Square*.png + StoreLogo.png — Windows store sizes (kept in sync)
public/app-icon.png — splash icon shown by HeicodeLoginPage,
ActiveSession.tsx, EmptySession.tsx,
Settings.tsx (1024x1024)
The H mark sits on transparent alpha now; on dark window chrome it
appears as the floating logo without a white card. Source resolution
(273x276) means 16/24px renderings are slightly soft; adequate for
taskbar/tray and crisp at 32px+.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per docs/integration/Heicode-登录接口对接文档.md, the original Heicode
desktop is supposed to take email+password directly, hand them to the
Manager (POST /api/user/login), and use the resulting session to
acquire an LLM access token. The previous flow opened a system browser
and redirected through /heicode/oauth/authorize, which works but
deviates from the design and forces an extra round trip.
This commit adds the documented in-process flow as the primary login
path while keeping browser OAuth as a fallback link:
POST /api/heicode-auth/login-with-credentials
1. POST <baseUrl>/api/user/login (username + password)
2. Capture Set-Cookie from the response
3. GET <baseUrl>/heicode/oauth/authorize?... with that cookie and
redirect: 'manual'
4. Parse Location: ...?token=sk-XXXX, hand it to loginAndActivate
The whole chain stays inside the local cc-haha server — no browser is
opened, no token leaves the user's machine.
UI changes:
- ProviderLoginCard now shows email + password fields as the primary
form, with the existing "or via browser" OAuth path demoted to a
small link below.
- Added store action loginWithCredentials and matching API client
method.
- i18n keys: login.creds.{email,password,submit,submitting} +
login.oauth.altLink (zh + en).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three concrete pieces:
1. Provider preset taijiaicloud now points at https://code.xinghanlab.com
instead of the old api.taijiaicloud.com. Together with the stock
resolveOAuthConfig fallback (<baseUrl>/heicode/oauth/authorize), this
flips oauthEnabled on for the login card and turns the existing
browser-redirect bridge into the default flow. Card name + promo
updated to reflect that this is "log in via Heicode Manager".
2. loginAndActivate softens its model probe. /v1/models is best-effort:
only hard 401/403 auth failures abort login. 5xx / panics / empty
lists fall back to preset.defaultModels so the user lands inside the
app even if the gateway transiently misbehaves; they can re-pick
models from Settings later.
3. heicode_oauth.go fallback page: /login → /sign-in (matches the
actual SPA route), title/copy de-branded from "HeiCode/新 API 控制台"
to plain "Heicode 控制台".
Also picks up the prior unstaged Windows polish: WindowControls (min/
max/close + drag region) on the login screen, ProviderLoginCard +
globals.css refinements that landed in earlier MSI builds.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Backend listLoginProviders() was iterating ['taijiaicloud','clawdrouter']
and throwing 500 because clawdrouter preset was already removed from
providerPresets.json. Narrowing SUPPORTED_LOGIN_PROVIDER_IDS and the two
Zod enums to ['taijiaicloud'] only, plus tightening the desktop
HeicodeProviderId type to match.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>