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
Manager web: Git sources workflow steps and copy; typecheck fixes for auth
and home sections; UsageLog type in usage-log-schema.ts (outside ignored data/).
docs: Agnet platform contract adds runtime_execution and sk_access_policy,
orchestration-plan and acceptance matrix aligned.
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
Use a dedicated TwoFactorRequiredError and shared type guard to keep login flow checks type-safe and less brittle than matching magic strings.
Made-with: Cursor
External IdP login alone did not set Gin session; proxied API calls returned 401 and triggered session-expired toast. Call POST /api/user/login after token exchange, support Turnstile on sign-in, handle 2FA pending session, and clear Manager cookie on logout.
Made-with: Cursor