Bump version to 0.2.1 across tauri.conf.json, package.json,
Cargo.toml, updater manifest, and Mac fallback URL.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- assets/logo.tsx: drop the hand-drawn "H" path SVG and render
/logo.png (already swapped to the new gradient icon when we
refreshed branding). One source asset across desktop + favicon +
Manager web.
- desktop_download.go: Mac fallback URL points at HeiCode_0.1.9_
aarch64.dmg now (drag-to-Applications installer), not the
.app.tar.gz updater payload that confuses end users.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Balance pill was rendering nothing for admin/root accounts because
mcp-server's §4 returns HEICODE_USER_NOT_FOUND for users that never
came through from-agnet onboarding. Fall back to Heicode NewAPI's
own /api/user/self when that happens; reshape into the same envelope
so the UI is path-agnostic.
New balanceStore (zustand) — single polling loop, BalanceBar +
avatar ring share it. AppShell starts it once auth bootstraps.
BalanceBar now shows a "loading…" placeholder on first fetch so
the widget is visible from frame one.
SidebarUserCard avatar wears an SVG ring whose arc length tracks
remaining/(remaining+used) and color hits the same green→amber→red
thresholds as the bar.
Manager: /desktop-client drops the manifest-notes wall of text, the
old HEICODE_DESKTOP_FILE_* subtitle goes away, and a Mac fallback
entry is always spliced in when the live manifest is Win-only.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cc-haha desktop (0.1.6):
- New sidecar route `/api/heicode-auth/balance` proxies mcp-server
§4 `/api/user/heicode/balance` using the active provider's stored
access token. Returns null silently on 401 / network failure so
the UI doesn't flash error strips.
- New BalanceBar component renders a compact pill right below the
ChatInput: `[wallet icon] $X.XX 剩余 · 已用 $Y.YY · N 次`. Polls
every 60s. Hidden when not logged in.
- Quota → USD display uses NewAPI convention (500_000 units = $1).
heicode Manager (Go controller):
- `GetDesktopDownloads` rewritten to pull from the same Azure Blob
updater manifest the in-app updater uses (`heicodeblob/.../
updater/latest.json`). 5-min in-process cache; stale-on-error
fallback. Stops the Manager web from showing stale
`Heicode_0.1.0_x64-setup.exe` after fresh releases.
- `DownloadDesktopFile` kept for back-compat — it now 302s to the
manifest's blob URL instead of streaming a VM-local file.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Root cause of the recurring "I don't see the logged-in user info in the
desktop client" complaint: the credentials-login path builds an mcpAuth
record with email / displayName / role from the mcp-server /api/auth/login
response and the TitleBar UserPill renders fine. But the OAuth-login path
(the typical browser-redirect flow) only received an sk- API key in the
callback query string — no user fields. So:
status.user == null
UserPill: if (!user) return null
→ blank space where the user pill should be.
Fix on backend (heicode_oauth.go HeicodeOAuthAuthorize):
- After issuing the sk- token, load the authenticated user from the
session and embed email / name / role (root|admin|user) / channel_id /
user_id as query params on the redirect URI.
Fix on client (cc-haha/src/server/api/heicode-auth.ts handleOAuthCallback):
- Read those query params (pickUserFromQuery), build an mcpAuth record
(buildMcpAuthFromOAuthQuery), and pass it through loginAndActivate the
same way the credentials path does. The accessToken slot holds the sk-
key as a placeholder — OAuth flow doesn't deliver a refreshable JWT
pair, and this mcpAuth exists purely to surface identity on the
TitleBar.
After this, OAuth-route users see the same gradient-avatar pill with
their email / name / role badge that credentials-route users already see.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1. /api/heicode-auth/* proxy: CriticalRateLimit (20/20min) → GlobalAPIRateLimit
(180/180s). The Heicode external-identity proxy is hit on every page
render for /me + /refresh plus the login burst — CriticalRateLimit is
sized for sensitive ops (password reset, 2FA) and trips at ~5 quick
page loads, returning 429 to a normal user. APIM upstream rate-limits
itself, so a second tight layer here adds no security and just
manufactures 429s.
2. JIT-create user group: seed "default" instead of me.Data.ChannelID.
Companion to 578a68f which only patched the every-login overwrite
path. New users (yj2824269760@gmail.com et al, JIT-created after
578a68f) still landed in a UUID group → empty /v1/models response →
desktop client showed the static 3-Claude fallback list.
Both fixes were applied on the production VM directly today (sed +
python patch) — committing them so the next docker rebuild on VM keeps
them instead of reverting to the buggy file via git checkout.
DB hot-fix already applied: 6 affected users moved to group=default.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CORS unblock — add /api/heicode-auth/*proxyPath backend proxy to
HEICODE_AUTH_BASE_URL. Frontend defaults to same-origin path so
the browser never hits APIM directly.
Sidebar — replace backend jargon (Git sources / Deployments /
Events / Wallet / Available models / Profile) with the user-facing
labels docs §10 mandates: 总览 / 准备清单 / 任务总览 / 审计 /
模型与余额 / 客户端 / 账号安全.
/sk-sources rewritten as 4-card preparation wizard with progress
meter; full Git form moves into a 高级补充 sheet. Drops JSON
editor, permission manifest, snapshots and resource-grant pills.
/deployments simplified to 任务总览: objective + status + last
update. Drops risk / budget / scope / secret_ref pills and the
RunDetailPanel; manifest details only in audit/advanced views.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
NewAPI's `users.group` is the local model-access bucket — it must match a
row in the `abilities` / `channels` group column to expose any models. The
Agnet channelId returned by mcp-server's /api/auth/me is a cross-platform
identity that almost never matches a NewAPI-side group, so blindly assigning
it on every login left users with `data: []` from /v1/models and the
desktop client silently fell back to the static 3-Claude default list.
Symptoms fixed: 4 users (xiaohei, 55@55.com, uwktn, test1) had UUID groups
with zero abilities, so /v1/models returned empty for them. cc-haha desktop
falls back to preset.defaultModels, hiding the 28 real models the channels
expose under group=default.
Change: drop the unconditional overwrite branch. The JIT-create path above
still seeds group from channelId on first login (kept for backward
compat), but admin-set group on existing users is preserved. mcp-server
already tracks Agnet channelId separately (see markBillingProviderNewapi),
so we don't need to mirror it into NewAPI's users.group anymore.
DB hot-fix already applied: 4 affected users moved to group=default.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Implements Heicode's choice (b) for §7.7.1 ②: in syncLocalUserFromAgnet,
fire-and-forget PUT mcp-server's internal /api/auth/internal/billing-provider
{email, billing_provider:"newapi"} so mcp-server's User table billing_provider
column lands as 'newapi' for users that came in via Heicode Manager (vs the
default 'litellm' for native taijiagent users).
- Goroutine: never blocks login on this side-effect; mcp-server endpoint is
idempotent so retries from repeat logins are harmless.
- Token via env MCP_SERVER_INTERNAL_TOKEN (K8s/compose secret); empty env
silently skips (dev-friendly).
- Reuses agnetHTTPClient + common.Marshal + common.GetUUID per repo
conventions.
Spec: docs/Heicode-对接进度与待办.md §7.8.1.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
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>
Manager now exposes a Resource Grant manifest and the Agnet control-plane response carries runtime state, agent instances, and permission_manifest so frontend runs can submit bounded resource grants without plaintext credentials.
Constraint: Manager remains the user console while NewAPI stays independent and OpenBao is referenced through secret_ref only.
Rejected: platform-side high-risk approval | client approval is the product boundary; Agnet only validates approval evidence.
Confidence: medium
Scope-risk: moderate
Directive: Do not mix child Agnet runtime model selection with NewAPI billing or expose OpenBao as a public route.
Tested: git diff --check; jq empty locale JSON; go vet ./controller ./model ./router; go test -count=1 ./controller ./model ./router
Not-tested: frontend typecheck/build because local node_modules tooling is absent and user requested builds happen on the VM.
Co-authored-by: OmX <omx@oh-my-codex.dev>
Manager needs a platform-owned secret handoff path so resource bindings can keep only vault references while OpenBao stores tenant-scoped credential payloads.
Tested: go test ./controller ./model ./router && go vet ./controller ./model ./router
Co-authored-by: OmX <omx@oh-my-codex.dev>
- Add hide_from_user_ui on tokens; EnsureUserRelayToken on login and Agnet session
- List/search tokens: end-users see only visible keys; admins see all
- Add /available-models and sidebar entry; i18n en/zh + locales
- desktop download / router hooks if present under heicode/
Extend agnet SK sources with repo_ref and snapshot display; add authenticated
deployment sheet + API types; cockpit toolbar entry; locale strings; minor docs.
Made-with: Cursor
Backend (controller/heicode_agnet_session.go):
- Add HEICODE_ROOT_EMAILS / HEICODE_ADMIN_EMAILS whitelists for JIT role
assignment. Manager no longer trusts Agnet's role claim — admin / root
is granted only by local config.
- Default JIT-synced users to RoleCommonUser.
- Promote-only role sync on every login (never demote).
Frontend auth fixes:
- login() no longer hard-codes id=1; preserves the real manager user id
returned by /api/user/session/from-agnet so the New-Api-User header
matches the cookie session.
- After login, prefer local /api/user/self over Agnet /me so role /
status reflect actual manager state (e.g. whitelist promotion).
- lib/api.ts: scope 401 -> "Session expired" handling to identity
endpoints only; admin-only 401 no longer resets the session.
UI restructuring:
- Default sidebar shows only Code delivery + Console + Personal, plus a
single "System settings" entry for ROLE.ADMIN+.
- system-settings workspace now hosts the full Tenant administration
tree (Channels / Models / Subscriptions / Redemption codes / Tenants /
Templates / Agents / Vendors / All usage logs) for ROLE.ADMIN+, with
System Administration sub-tree gated to ROLE.SUPER_ADMIN.
- Workspace switch triggers on admin paths (channels, users, templates,
agents, subscriptions, models, redemption-codes) — not only
/system-settings.
- system-settings route now allows ROLE.ADMIN+ instead of root-only.
Branding cleanup:
- Drop orphan "NewAPI" i18n keys from web/default locales.
- Rename web/default workspace package newapi-web -> heicode-web.
Config:
- docker-compose.azure-vm.yml exposes HEICODE_ROOT_EMAILS /
HEICODE_ADMIN_EMAILS.
VERSION: 1.1.0-default-user-role
Made-with: Cursor
Replace password-based /api/user/login bridge after external auth with POST /api/user/session/from-agnet: verify access (and optional refresh) against Agnet /api/auth/me, upsert local user by email, then issue the Manager session cookie. Frontend sends bearer tokens only.
Includes HEICODE_AUTH_BASE_URL in compose defaults and .env.example.
Made-with: Cursor