Commit Graph
72 Commits
Author SHA1 Message Date
chenchenandClaude Opus 4.6 e6e80c6a18 feat: route registration through 太极 AI PAD API
Registration now goes through the Agnet auth proxy (/api/heicode-auth/*)
instead of the local Manager API. Email verification is always required
(太极 mandates it). After successful registration, tokens are used
directly to establish the Manager session without a redundant login call.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-18 17:24:39 +08:00
chenchenandClaude Opus 4.6 bda36c44be fix: safe type assertions across OAuth, model Scan, relay, and middleware
- OAuth: safe type assertions for session state and affiliate code
  (oauth.go, github.go, discord.go, linuxdo.go, oidc.go)
- Model: Scan() methods handle string values from DB drivers, not just []byte
  (channel.go ChannelInfo, task.go Properties/TaskPrivateData)
- Model: safe type assertion in CleanupChannelPollingLocks sync.Map iteration
- Relay: safe type assertions in audio_handler, AWS InvokeModel,
  ollama ConvertClaudeRequest, claude stop sequences, zhipu token cache
- Service: fix slice bounds panic in Gemini->OpenAI stop sequences conversion
- Service: safe type assertion in CleanupFileSources middleware
- Middleware: add missing c.Abort() in turnstile session save failure
- Middleware: safe type assertion in distributor channelId
- Middleware: safe int comparison in auth helper

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-18 16:21:34 +08:00
chenchenandClaude Opus 4.6 f43aa269d6 fix: enforce Rule 1 JSON wrappers across 80+ files, fix 6 bugs
- Replace all encoding/json direct calls with common.Marshal/Unmarshal/DecodeJson per Rule 1
- Fix Dify nil pointer dereference on remote image upload (relay-dify.go)
- Fix Claude relay file content type detection for text/* and PDF (relay-claude.go)
- Fix unsafe type assertions in Claude relay and Vertex GetModelRegion
- Fix StreamScanner unconditionally resetting pre-existing StreamStatus
- Add inferMimeTypeFromFilename() for proper MIME type handling in DTO
- Fix Mac build script hardcoded DMG version (now reads from tauri.conf.json)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-18 12:39:02 +08:00
chenchenandClaude Opus 4.6 16410270a1 fix: AWS Nova empty content panic + DTO Rule 6 pointer types
- relay/channel/aws/relay-aws.go: add bounds check before accessing
  Content[0] — empty response array caused index-out-of-range panic
- dto/embedding.go: convert Seed, TopK, NumPredict, NumCtx from int
  to *int so explicit zero values survive omitempty marshaling (Rule 6)
- dto/video.go: convert Fps, Seed, N from int to *int (Rule 6)
- dto/suno.go: convert ContinueAt from float64 to *float64 (Rule 6)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-17 23:17:17 +08:00
chenchenandClaude Opus 4.6 e31fe390f3 fix: use common.Marshal/Unmarshal per Rule 1 + telegram null safety
- model/user.go: replace json.Unmarshal/Marshal with common.* wrapper
  functions as required by project Rule 1 (3 occurrences)
- relay/channel/claude/relay-claude.go: replace 3 json.* calls with
  common.* (tool call args unmarshal, response marshal)
- relay/channel/gemini/relay-gemini.go: replace 5 json.* calls with
  common.* (content parsing, function args, response marshal)
- adapters/telegram/index.ts: add optional chaining on callback query
  message.chat.id and null coalescing on message.text to prevent crash
  when callback message is undefined

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-17 23:09:32 +08:00
chenchenandClaude Opus 4.6 aa52b1265b fix: Windows path bugs, null safety, and URL encoding across client + manager
Client (cc-haha):
- server/api/sessions.ts: use path.basename() instead of split('/').pop()
  for extracting project/repo names on Windows
- server/api/filesystem.ts: use os.tmpdir() and os.homedir() instead of
  hardcoded '/tmp' and process.env.HOME which don't exist on Windows
- utils/plugins/pluginVersioning.ts: split on /[/\]/ for Windows paths
- utils/plugins/loadPluginCommands.ts: handle backslash separators in
  plugin namespace construction
- cli/handlers/autoMode.ts: add optional chaining on response.content
  to prevent crash when API returns null content

Manager (heicode):
- auth/api.ts: fix status always returning 1 regardless of active state
  (was `? 1 : 1`, now `? 1 : 2`)
- users/api.ts, redemption-codes/api.ts, profile/api.ts: use
  URLSearchParams for query string encoding to prevent breakage with
  special characters in search keywords and email addresses

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-17 22:59:26 +08:00
chenchenandClaude Opus 4.6 a3c6261d47 fix: safe type assertions in auth middleware + decode error check in password reset
- middleware/auth.go: session.Get() returns interface{} which can be nil;
  use safe type assertions with ok checks to prevent panics on corrupted sessions
- controller/misc.go: replace json.NewDecoder with common.DecodeJson per project
  convention, add error check before using decoded struct
- handle-server-error.ts: add optional chaining on error.response.data to prevent
  crash when response body is undefined

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-17 22:19:31 +08:00
chenchenandClaude Opus 4.6 ecaa107009 chore(release): bump Manager VERSION to 1.1.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-17 21:31:00 +08:00
chenchenandClaude Opus 4.6 f88f6a8c46 release: 0.2.1 — Windows path fix + version bump (Win & Mac)
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>
2026-05-17 19:03:32 +08:00
chenchenandClaude Opus 4.6 838f3717e5 release: 0.2.0 — CJK font consistency + remove stale upstream references
- Fix CJK font rendering: add PingFang SC, Microsoft YaHei, Noto Sans CJK SC
  fallbacks to all CSS font stacks (headline, body, label, mono)
- Clear docs_link default (was pointing to upstream docs)
- Remove user-facing "NewAPI" text from en/zh i18n strings
- Bump desktop version to 0.2.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-17 11:45:51 +08:00
chenchenandClaude Opus 4.6 460bdcc951 fix: Manager favicon/logo + ripgrep sidecar detection (#433 #208)
Manager web:
- Replace favicon.ico (both default & classic themes) with new H icon
- Compact heicode-logo.svg from 204KB base64 blob to 5KB
- Replace classic theme logo.png (was still old NewAPI icon)

Client (cc-haha):
- Fix isInBundledMode() to detect Bun-compiled sidecars that have no
  explicit embeddedFiles — checks process.execPath basename instead
- Add well-known ripgrep install paths (/opt/homebrew/bin, /usr/local/bin,
  ~/.cargo/bin, etc.) as fallback when PATH is incomplete in Tauri sidecar

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-15 16:23:15 +08:00
chenchenandClaude Opus 4.7 3e7ed0202d fix(manager): real logo PNG + Mac fallback is now a .dmg
- 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>
2026-05-14 17:13:52 +08:00
chenchenandClaude Opus 4.7 ac1aa87312 release: 0.1.10 — balance widget actually shows + avatar ring
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>
2026-05-14 16:44:13 +08:00
chenchenandClaude Opus 4.7 de239c32d6 release: 0.1.7 — new H glyph icon (desktop + Manager web) + manifest-driven Manager downloads
Visual brand refresh: replaced the desktop client + Manager web logos
with the new glossy gradient H glyph.

Desktop (cc-haha):
- src-tauri/icons/*: regenerated via `tauri icon` from new-icon.png
  (center-cropped 1024 square). Updates icon.ico/icns/png + 8 Windows
  Square*Logo sizes + iOS + Android mipmaps.
- public/app-icon.png + app-icon.svg: replaced. SVG is now a wrapper
  around the embedded PNG so existing <img src="…app-icon.svg"> refs
  keep working without recoloring tooling.
- Version bumped to 0.1.7 across tauri.conf.json, package.json,
  Cargo.toml.

Manager web (heicode/web/default):
- public/logo.png: 256x256 of the new glyph.
- public/favicon.ico: multi-size ico (16/32/48/64/128/256).
- public/heicode-logo.svg: same SVG-wraps-PNG trick as desktop.

Backend (heicode/controller/desktop_download.go):
- Already redeployed earlier today — the Manager web "Heicode 桌面客户端"
  page now sources its download URLs from the Azure Blob updater manifest
  instead of VM-local files. This is the fix for "still downloading
  Heicode_0.1.0_windows_x64_msi.msi"; the page will reflect 0.1.7 the
  moment the manifest publishes below.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 10:37:18 +08:00
chenchenandClaude Opus 4.7 02866a8a33 release: 0.1.6 — balance pill under composer + Manager download fix
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>
2026-05-13 17:22:15 +08:00
chenchenandClaude Opus 4.7 2052b5b140 feat(web,docs): adaptive task polling + contract patch list
- task-card-view: refetchInterval now adapts to state — 3s for
  running/awaiting_approval, stop on completed/failed, 15s otherwise.
  Approval requests now surface within 3s instead of up to 15.
- docs: collect every Manager-side compat patch (deeplink mapping,
  redact fallback, polling-vs-SSE) so mcp-server team can fold them
  back into the contract.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 15:49:42 +08:00
chenchenandClaude Opus 4.7 1796f04fa8 feat(web): wallet shows mcp-server §4 usage + recent requests
Add HeicodeUsageCard between balance and subscription plans:
- 14-day usage sparkline from /api/user/heicode/usage
- Last 6 requests from /api/user/heicode/logs

Both endpoints come from the product-package §4 contract (mcp-server),
so the figures match what the desktop sidecar sees.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 15:41:30 +08:00
chenchenandClaude Opus 4.7 ddc32466c2 feat(web): wallet balance reads mcp-server §4 first
Try getHeicodeBalance() (mcp-server /api/user/balance per product-package §4)
before falling back to local /api/user/self. Aligns Wallet page with the
Heicode product-package contract so balance numbers come from the same source
the desktop sidecar uses.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 14:56:47 +08:00
chenchenandClaude Opus 4.7 4c263040c9 feat(manager): /sk-sources now uses mcp-server P1 ResourceBinding (§2)
docs/Heicode-对接进度与待办.md §7.5 point 7 named the Manager team as
responsible for wiring P1 resource UI to mcp-server (§2 ResourceBinding,
§3 ResourceGrant) — without this, the deeplink that the desktop client
puts on the task card (`/manager/resources?from=task`) ends in a 404.

Changes:

1. lib/heicode-mcp.ts: typed wrappers for the 9 P1 endpoints
   - §2 ResourceBinding: list / get / create / update / revoke
   - §3 ResourceGrant: list / get / create / revoke
   - Field shape verified against live mcp-server with test account
     55@55.com — 7 smoke cases pass including the 422 sensitive-keyword
     enforcement and the §3 subset rule.

2. features/agnet-console/pages.tsx AgnetSKSourcesPage rewritten to
   read /api/resources (filtered to status=active) instead of the
   legacy Heicode-local git_sources controller:
   - Card 1 代码        = resources filter type='git'
   - Card 2 文档SK      = resources filter type∈{sk,project_doc}
   - Card 3 云账号      = resources filter type∈{cloud_account,
                          cloud_resource}, "auto-discovery coming soon"
                          hint shown when empty (current state)
   - Card 4 推荐摘要    = unchanged

3. Advanced sheet form rewritten for mcp-server ResourceBinding shape:
   {type, name, external_ref, metadata, permission_scope, constraints,
    secret_ref, status}. Old (provider, repo_url, ref, paths, usage,
    tenant_id) maps in:
     name          → name
     repo_url      → external_ref
     provider      → metadata.provider
     ref           → metadata.default_branch + constraints.ref
     paths         → constraints.allowed_paths (comma-joined)
     usage         → type ('git'/'sk'/'project_doc')
     tenant_id     → dropped (server uses auth.user_id)
     —             → permission_scope ['repo:read'] minimal default
     —             → secret_ref blank for now (server fills once
                     OpenBao Secret Broker lands per §2.1 TODO)

   Form also surfaces the §2.1 422 RESOURCE_GRANT_SECRET_REJECTED
   server-side error to the user.

4. Removed unused imports (GitSource{,Payload,Usage}, createGitSource,
   deleteGitSource, listGitSources) — legacy git_sources controller is
   still in the Go backend for now but the Manager no longer consumes it.

5. RecommendationSummaryDialog now takes ResourceBinding[] for project /
   sk source counters instead of GitSource[].

Smoke verified end-to-end against live mcp-server:
  list / create (incl. metadata+constraints+permission_scope) / get /
  delete-binding all 200 with expected shapes; 422 secret rejection
  fires on metadata.{name containing 'token'}; §3 subset rule on
  allowed_actions outside binding.permission_scope returns
  RESOURCE_GRANT_INVALID.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 14:33:18 +08:00
chenchenandClaude Opus 4.7 ab53f34334 fix(tasks): align HeicodeTaskCard fields with live mcp-server shape
End-to-end smoke against mcp-server (test account 55@55.com) revealed
the actual task.card shape:

  { goal: string,
    scope: string[],
    generated_artifacts: string[],
    manager_actions: Array<{label, deeplink}> }

My earlier TS types and TaskCardView assumed
{objective, first_version_scope, auto_generated, pending_context} —
keys that don't exist in the real response. Tasks created via the
intent flow would have rendered with empty bullet lists.

Changes:
- lib/heicode-mcp.ts: rewrite HeicodeTaskCard to the live shape, add
  HeicodeManagerAction type
- features/tasks/task-card-view.tsx:
  - read card.goal / card.scope / card.generated_artifacts
  - new readManagerActions() helper renders mcp-server's
    {label, deeplink} buttons in place of the hardcoded action row,
    with normalizeDeeplink() mapping /manager/resources →
    /sk-sources etc. to Manager-side routes
  - dropped pending_context (no such field); follow-up "Pending
    context" footnote is now a plain explanatory line per docs §10

Smoke verified end-to-end:
  login (POST /api/auth/login) → 200 + JWT
  intent (POST /api/user/tasks/intent) → 200 + configuring task
  list   (GET /api/user/tasks)         → items shape matches type
  detail (GET /api/user/tasks/{id})    → follow-ups parse correctly
  answer × 2 (POST .../answer)         → state machine flips to running,
                                          card materialises with the 4
                                          actual fields above
  audit  (GET /api/agnet/audit-logs)   → {items, total, next_cursor}
  agnet  (GET /api/agnet/deployments)  → {items, total}
  balance (GET /api/user/heicode/balance) → HEICODE_USER_NOT_FOUND
    (test account, expected; my code catches this and returns null)

UTF-8 body through the proxy works fine (earlier "parse body" error
was a Windows shell quoting issue, not a proxy bug).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 13:46:27 +08:00
chenchenandClaude Opus 4.7 a1529f18c1 feat(manager): wire UI to mcp-server contract instead of local controllers
After reading the Heicode-接口契约文档 v2.2 in
~/Desktop/taijigit/taiji-AI-PAD/Docs/ the right data sources are clear:

  §1 /api/auth/*           — already wired (features/auth/api.ts)
  §4 /api/user/heicode/*   — model balance + usage + logs
  §5 /api/agnet/*          — Agnet platform stub (deployments / audit / etc)
  §6 /api/user/tasks/*     — HeicodeTask intent → followups → card

The first wave UI work (commit 2df233b) used Heicode-local controllers
as the data source (AgnetDeployment.orchestration_plan as a stand-in
for the task object). That was wrong — the contract document is clear
that HeicodeTask (§6) is the canonical user-facing task object, and the
mcp-server stub at §5 is the canonical deployment source.

This commit redirects the data plumbing without touching the UI shells:

1. New lib/heicode-mcp.ts — typed client that calls mcp-server through
   the existing same-origin /api/heicode-auth/* proxy. Implements the
   subset of §4/§5/§6 the Manager UI needs:
     createTaskFromIntent / listHeicodeTasks / getHeicodeTask / answer
     getHeicodeBalance / getHeicodeModels / getHeicodeUsage / getHeicodeLogs
     listMcpAgnetDeployments / listMcpAuditLogs

2. HomeHero (features/dashboard/components/home-hero.tsx):
   - Idea input now POSTs /api/user/tasks/intent and routes the user
     to /tasks/$id once the server returns the new task with its first
     round of follow-ups. Previously it only stashed the idea in
     localStorage which the docs §10 didn't actually require.
   - ContinueTasks + TodayFocus now consume listHeicodeTasks output
     (HeicodeTask.status / status_caption / updated_at:ms) instead of
     AgnetDeployment shape.

3. TaskCardView (features/tasks/task-card-view.tsx):
   - Reads getHeicodeTask(id) from mcp-server (refetch every 15s).
   - When status=configuring renders the open follow-ups from the most
     recent heicode thread entry as clickable option chips; clicking
     POSTs answer to /api/user/tasks/$id/answer and the server-side
     state machine advances. high-risk options get a red badge per §6.
   - When status=running (followups answered, card materialised) the
     four blocks docs §10 任务卡 mandates are rendered from task.card:
     目标 / 第一版范围 / 自动生成 / 待确认上下文.

4. AgnetAuditPage (features/agnet-console/pages.tsx):
   - Switched queryFn from local getAgnetAuditLogs to mcp-server
     listMcpAuditLogs. The redacted-card renderer already accepts any
     {resource_id, allowed_actions, constraints, secret_ref} shape so
     no UI change needed; banner still announces no plaintext.

Notes:
- /wallet refactor to §4 deferred — it pulls multiple legacy series
  from the local NewAPI controllers and the rewrite is a separate
  pass. Manager users see local data for now; the call is identical
  shape so swap is mechanical once we get there.
- Local TS check clean. Not deployed.
- Earlier 2df233b's UI structures (HomeHero shape, TaskCard layout,
  recommendation dialog, audit redacted view) stay verbatim — only
  the data fetching layer moved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 13:33:01 +08:00
chenchenandClaude Opus 4.7 2df233b982 feat(manager): align Manager UI with product-package docs §10/§11/§13
Five gaps closed against the updated product-package spec
(http://gitee.ath.cx:3000/xiaohei/heicode/src/branch/main/docs/product-package):

P1. /dashboard hero rewritten per §10 §"初始首页"
    features/dashboard/components/home-hero.tsx replaces the technical
    CockpitView with four blocks the spec mandates: 主输入 / 继续任务 /
    今日焦点 / 辅助入口. Main input is "你想把什么想法变成可以上线的软件?".
    Submit only stashes the idea to localStorage + toast — the actual task
    conversation belongs in the desktop client per §13 §5.1.

P2. /tasks/$id TaskCard route per §10 §"任务卡" + §11 §3
    features/tasks/task-card-view.tsx renders one AgnetDeployment as the
    user-facing task object: 目标 / 第一版范围 / 自动生成 / 待确认上下文 +
    Manager 辅助按钮. Linked from Home hero's 继续任务 list.

P3. /sk-sources 推荐摘要 dialog per §10 §"推荐确认卡"
    features/agnet-console/pages.tsx RecommendationSummaryDialog. Five
    blocks (本次会做 / 本次允许使用 / 本次不会做 / 高危规则 / 预计消耗) +
    Launch Agnet button with "参数由 Heicode 自动生成" caption. No JSON
    editor, no permission manifest — §10 高级展开禁令.

P4. /audit redacted card view per §10 §"任务用量与审计" + §6
    features/agnet-console/pages.tsx AgnetAuditPage. Old裸 table replaced
    with脱敏 cards exposing only the fields docs allows: resource_id /
    resource_type / allowed_actions / constraints / secret_ref. Helper
    function maskIfSecret() catches any stray plaintext credential the
    backend might leak. Banner says explicitly "明文密钥从不展示".

P5. Login screen filters Claude Official provider per §8
    cc-haha/desktop/src/components/login/HeicodeLoginPage.tsx hides the
    legacy `official` preset so the login carries Heicode brand alone.

i18n fix (BIG):
    i18next defaults to `defaultNS = 'translation'`. The earlier custom
    keys had been written to the JSON root, NOT into translation, so
    every t('Preparation checklist') was returning the English key as
    fallback all along. Moved 67 orphan keys (zh+en, both files) into
    the translation namespace where they're actually resolvable. Verified
    by loading i18next + zh.json in bun and confirming all keys resolve
    to the expected Chinese strings.

Cache-busting from earlier session (already deployed via SFTP, never
committed): index.html / constants.ts / footer.tsx now hold the
?v=h-glass-2 suffixed asset URLs in git, so future docker rebuilds
preserve them.

Per user directive: tested locally only (TS check clean, i18next
resolves correctly). NOT deploying to the VM in this commit — user
asked to keep production untouched until they verify the changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 12:01:13 +08:00
chenchenandClaude Opus 4.7 a2deeb61b0 fix(client+server): OAuth login path now surfaces user identity in desktop TitleBar
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>
2026-05-11 20:44:33 +08:00
chenchenandClaude Opus 4.7 b91a68fe2b ops(deploy): default Azure VM deploy to pull from heicode-win remote
bin/azure_vm_deploy.sh pulled from `origin` (xiaohei/heicode.git) when
GIT_REF was set. Production VM now tracks heicode-win/main and that's
where the rebrand + bug fixes ship — pulling from origin would silently
revert all of it on the next deploy. New GIT_REMOTE env var (defaults
to heicode-win) lets operators override for one-off cherry-pick deploys.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:25:57 +08:00
chenchenandClaude Opus 4.7 37de6575df fix(server): backport two prod hot-patches that kept getting wiped
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>
2026-05-11 17:14:35 +08:00
chenchenandClaude Opus 4.7 88c5b4a285 feat(manager-web): align login + header with Heicode brand violet
Theme tokens (theme.css)
- --primary retuned to the brand violet oklch(0.58 0.17 278) ≈ #7B6BE3
  (was a saturated pink oklch ... 286 that read off-brand against the H
  glass logo)
- New tokens: --brand-from #B888E5, --brand #7B6BE3, --brand-to #6B7CE0,
  --gradient-brand (135deg three-stop), --gradient-brand-btn for primary
  CTAs. Both light and dark modes hold the same brand identity.

Login page (auth-layout.tsx + sign-in/index.tsx + user-auth-form.tsx)
- Inlined H glass mark SVG replaces the abstract ShieldCheck pictogram
- Brand wordmark uses gradient text-fill so the word "Heicode" reads as
  the same gradient as the logo
- "Tenant access" pill and h2 heading both pick up brand violet via
  border / bg / gradient text
- Sign-in button switches from solid var(--primary) to the three-stop
  --gradient-brand-btn with violet drop shadow + lift-on-hover

Header user info (profile-dropdown.tsx)
- The right-side trigger used to be a bare 36px avatar — invisible user
  identity unless you click. Now it is a pill: gradient-filled avatar
  initials + display name + email + role badge, always visible on >=sm
- Avatar fallback fills with --gradient-brand so even pre-image, the
  user pill carries Heicode color identity

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 15:24:04 +08:00
chenchenandClaude Opus 4.7 f650462f17 feat(manager-web): drop third-party model brand grid from landing
Per docs §10 "禁止普通用户体验出现:模型供应商配置 / 模型提供方
选择" — the dashboard landing hero showed "OpenAI / Claude /
Gemini / DeepSeek / Qwen / Llama" as a marketing matrix, which
leaks upstream provider branding into the user-facing surface.

Replaced with Heicode capability tags (通用 / 长上下文 / 推理 /
代码 / 多模态 / 高性价比). This is the landing the user lands on
after login; admins still see real upstream provider names in
the system-settings → models tabs (those are technically the
channel protocol names and removing them would mislead admins).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 13:30:58 +08:00
chenchenandClaude Opus 4.7 7c3ecbcefc feat(manager): align with product-package docs §10/§11
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>
2026-05-11 13:01:14 +08:00
chenchenandClaude Opus 4.7 afceb7cc2e feat(manager-web): expand favicon ladder + hide unused 2FA/Passkey UI
index.html: add png/ico/apple-touch favicon links, og:image,
and brand theme-color (#7B6BE3) so all icon surfaces use the
H glass mark.

Hide unused auth UI:
- profile page: drop PasskeyCard + TwoFACard
- system-settings/auth: drop Passkey Authentication section

These features aren't part of the Heicode platform flow (auth
is delegated to the identity service / SSO); leaving them in
the UI confuses tenants.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 10:52:28 +08:00
chenchenandClaude Opus 4.7 c47db748e5 feat(manager-web): swap logo to H glass mark
Match Heicode desktop client app icon: violet→blue gradient
rounded-square with white H. Replaces favicon.ico, logo.png
(used in footer / system info), heicode-logo.svg (browser
favicon link), and the inline Logo component.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 18:49:51 +08:00
chenchenandClaude Opus 4.7 6cc981d366 fix(server/web): SPA navigate() to backend bridge URLs renders 404
When the desktop one-click login flow opens
  /heicode/oauth/authorize?state=...&redirect_uri=...
in the browser and the user isn't signed in, Manager renders the
"please log in" bridge page that links to /sign-in?redirect=<authUrl>.
After login, useAuthRedirect's `handleLoginSuccess` calls TanStack
Router's `navigate({ to: targetPath })` to send the user back to
that authorize URL.

But TanStack Router only knows about React routes; backend bridges
(`/heicode/oauth/...`, `/api/...`) have no matching route, so the
SPA renders 404. The user has to manually re-enter the URL, at
which point the backend handles it and 302s to the loopback
callback. This produced the 500 → 404 → success symptom users hit
on first-time desktop login.

Fix: detect backend prefixes (`/heicode/oauth/`, `/api/`) and use
`window.location.assign()` to force a full-page navigation so the
server gets the request directly. React-route paths still go
through `navigate()` as before.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 17:29:01 +08:00
xiaoheiandchenchen 87b30b8fa1 fix: 修复登录时 /v1/models 空列表 panic 导致 500
- heicode/controller/model.go: Anthropic ListModels case 对空模型列表
  做边界保护,避免 index out of range panic -> HTTP 500
- cc-haha/src/server/services/providerService.ts: 模型探活不再发送
  anthropic-version header,统一走 OpenAI 兼容路径返回 {data:[]}
- heicode/controller/heicode_oauth.go: OAuth 未登录重定向指向 /sign-in
- heicode/deploy/nginx/heicode-gateway.conf: 3000 端口 server block
  补充 /models -> /v1/models 兼容路由
2026-05-08 20:19:21 +08:00
chenchenandClaude Opus 4.7 578a68f006 fix(server): stop overwriting users.group with Agnet channelId on every login
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>
2026-05-08 19:05:33 +08:00
chenchenandClaude Opus 4.7 fc2c811e93 feat(server): notify mcp-server billing_provider=newapi after Agnet user sync
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>
2026-05-08 18:36:24 +08:00
chenchenandClaude Opus 4.7 2f75588ed1 feat(server): expose desktop-downloads file route to TokenOrUserAuth
Add userRoute.GET /api/user/desktop-downloads/file/:platform with
TokenOrUserAuth middleware. A plain browser <a href> can hit this with
just the session cookie; New-Api-User header isn't required (the SPA's
axios layer still injects it for the metadata endpoint on selfRoute).

Closes the 401 "无权进行此操作,未提供 New-Api-User" case from the
Heicode Manager desktop installer download path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 17:40:40 +08:00
chenchenandClaude Opus 4.7 f70d80ca4c Revert "fix(agnet): preserve root admin's group during Agnet session sync"
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>
2026-05-07 15:15:17 +08:00
chenchenandClaude Opus 4.7 992a965cd9 fix(agnet): preserve root admin's group during Agnet session sync
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>
2026-05-07 15:03:40 +08:00
chenchenandClaude Opus 4.7 4665f88921 feat: route Heicode desktop login through code.xinghanlab.com Manager
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>
2026-05-07 13:55:57 +08:00
gongzhiyongandOmX bf134dec86 Make Agnet runs submit resource-scoped work safely
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>
2026-05-04 18:55:53 +08:00
gongzhiyong ba02ae5be7 feat: align manager agnet boundaries
- add Manager user_context, NewAPI billing_context, and Agnet agent_runtime deployment fields

- move resource binding/grant scope toward user-owned binding_scope and secret_ref-only paths

- document OpenBao internal access and unified heicode.xinghanlab.com routing boundaries

- fix Manager session user id preservation after external auth login
2026-05-04 09:28:03 +08:00
gongzhiyongandOmX d9eb7dcd74 feat: wire resource secrets to OpenBao
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>
2026-05-03 23:41:55 +08:00
gongzhiyong a7588e1bc8 chore: remove plaintext postgres retry credentials 2026-05-03 21:49:55 +08:00
gongzhiyong 50bf3de6f0 agnet: add deployment logs metrics readiness endpoints 2026-05-03 21:48:26 +08:00
gongzhiyong fb61f385fb deploy: make azure vm deploy helper executable 2026-05-03 21:17:34 +08:00
gongzhiyong 0d7491c9a1 omx(team): auto-checkpoint worker-5 [unknown] 2026-05-03 18:09:04 +08:00
gongzhiyong 24405519a9 omx(team): auto-checkpoint worker-1 [1] 2026-05-02 23:32:00 +08:00
gongzhiyong 05182f0277 task: implement manager resource grants 2026-05-02 23:30:23 +08:00
gongzhiyong 5e4648e608 omx(team): auto-checkpoint worker-5 [5] 2026-05-02 23:29:39 +08:00
gongzhiyong 0a01f36f1b omx(team): auto-checkpoint worker-2 [2] 2026-05-02 23:29:34 +08:00
gongzhiyong 33fa9f20a6 omx(team): auto-checkpoint worker-5 [5] 2026-05-02 23:28:40 +08:00