Commit Graph
94 Commits
Author SHA1 Message Date
chenchenandClaude Opus 4.7 b845a08840 feat(client): slice 15 — SSE subscription for approvals + task events
Wire mcp-server's §7.8.3 single SSE channel (GET /api/user/events/stream,
shipped 2026-05-08 in image heicode-7.8.3-sse-v2-20260508) into the client:

  cc-haha/src/server/api/heicode-tasks.ts
    + GET  /api/heicode-tasks/events/stream      (long-lived SSE proxy)
    + GET  /api/heicode-tasks/approvals          (startup pull)
    + POST /api/heicode-tasks/approvals/:id/decision

  cc-haha/desktop/src/lib/heicodeEventsClient.ts (new)
    EventSource wrapper with exponential backoff reconnect (1s..30s) and
    a 60s heartbeat watchdog that force-reconnects on stream silence.

  cc-haha/desktop/src/lib/heicodeEventsRouter.ts (new)
    Routes the 5 event names (approval.requested, approval.resolved,
    task.status_changed, task.execution_progress, heartbeat) into the
    matching stores. Ignores unknown events so future server-side adds
    don't crash the client.

  cc-haha/desktop/src/stores/heicodeTaskStore.ts
    + applyStatusChange(taskId, status, caption?)
    + applySubStepProgress(taskId, subStepId, status, caption?)

  cc-haha/desktop/src/main.tsx
    Subscribe to auth store → start/stop the stream as loggedIn flips.

Type-check: bunx tsc -b --noEmit clean.
Bun bundle: bun build src/server/api/heicode-tasks.ts → 86 modules, 0.55 MB.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 21:19:47 +08:00
chenchenandClaude Opus 4.7 bb3c2c707b feat(client): one-click Manager OAuth login
Replace the email + password form on the desktop login card with a single
"一键登录 Heicode Manager" button that drives the existing OAuth bridge:

  desktop click
    → POST /api/heicode-auth/oauth/start (server stages state + builds
      authorize URL pointing at https://code.xinghanlab.com/heicode/oauth/authorize)
    → Tauri shell.open() the authorize URL in the system browser
    → user signs in via Manager (which now also routes /sign-in?redirect=...)
    → Manager 302s back to http://127.0.0.1:<port>/api/heicode-auth/oauth/callback?token=sk-…
    → callback handler activates the provider; status flips loggedIn=true
    → AppShell unmounts the login page

The OAuth start/callback endpoints already existed (handleOAuthStart /
handleOAuthCallback) so this is a UI-only swap; no auth-store changes.
loginWithCredentials remains exported in case we ever need a fallback,
but it's no longer wired into any UI surface.

i18n: tweak login.oauth.button to "一键登录 Heicode Manager", add
login.oauth.waiting for the polling state.

Aligns with upstream xiaohei/heicode commits 5bd8276 / e60e74b /
34a87a4 (Manager-as-only-identity) without breaking the slice 11-14
heicode-tasks proxy that still depends on the provider abstraction.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 20:34:05 +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 15ac00130a feat(client): slices 8-14 — exec/delivery/audit panels + §6 task orchestration wiring
Wireframe coverage (product-package 11-product-prototype-wireframes.md):
  §8  ExecutionFeedbackPanel — sub-steps + sk_tool_calls + events + artifacts (Slice 8)
  §10 DeliveryResultPanel — deliverables + quality + next-actions (Slice 9)
  §audit TaskDetailDrawer — usage / resources / approvals / security tabs (Slice 10)

§6 task orchestration wired (mcp-server contract v2.0):
  Slice 11 — heicode-tasks proxy (5 routes) + typed client + store mode
             (mock | live | loading | error) + ModePill + optimistic updates
  Slices 12/13/14 — lazy-load /execution, /delivery, /audit?tab=... on panel
             mount with shouldFetchPanel gate (skips for seed mock ids)

§7.8.5 deeplink: lib/managerLink.ts centralizes path→URL resolution so the
Manager domain (currently code.xinghanlab.com) can be flipped in one line.
Wires onClick into manager_actions / openManager / deliverable buttons.

Type-check: bunx tsc -b --noEmit clean.
Bun bundle: bun build src/server/api/heicode-tasks.ts → 86 modules, 0.55 MB.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 17:39:47 +08:00
chenchenandClaude Opus 4.7 9ffe261374 feat(client): refresh brand to Heicode H logo + align macOS build script
- Replace logo source with new glassy gradient H (heicode-logo.jpg)
- Regen all icon sizes via scripts/rebuild-icons.py (PIL + ICO + ICNS):
  32/64/128/128@2x/icon.png + Square{30,44,71,89,107,142,150,284,310}+StoreLogo
  + multi-res icon.ico + icon.icns
- Update public/app-icon.png to 1024×1024 derived
- Align cc-haha/desktop/scripts/build-macos-arm64.sh to Heicode branding:
  APP_BUNDLE_NAME=HeiCode.app, APP_BUNDLE_ID=com.heicode.desktop,
  DMG volume=Heicode, default DMG=Heicode_0.1.0_aarch64.dmg,
  cleanup paths use heicode-desktop crate name (mirrors Cargo.toml rename)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 17:38:36 +08:00
chenchenandClaude Opus 4.7 a268079751 feat(client): slice 7 — task driving cabin (intent → followups → task card)
Per docs/product-package/10-frontend-detail-spec.md and the wireframes
in 11-product-prototype-wireframes.md §2-§3, the client's first-class
surface is no longer "code-companion empty state" but a Heicode task
driving cabin: input an idea, answer Heicode's follow-ups, see the
auto-generated task card, hand off to Manager for resource binding /
deployment.

This slice ships the surface as a mock skeleton — the data layer
(useHeicodeTaskStore) is seeded with two demo tasks so the wireframe
can be reviewed end-to-end before backend wiring lands.

New files:
  - stores/heicodeTaskStore.ts
      HeicodeTask shape (id / name / status / status_caption / thread /
      card), HeicodeTaskStatus enum, ChatTurn (user | heicode), and
      FollowupQuestion (with optional 'high-risk' option flag).
      Actions: submitIntent, openTask, closeTask, answerFollowup,
      appendMessage. Two seeded tasks ("小团队任务管理 SaaS" running
      with full task card; "企业微信通知集成" awaiting approval).

  - pages/HeicodeTasksHome.tsx
      Two layouts behind a single route. When currentTaskId is null
      we render the Home (wireframe §2):
        - Header line "当前任务:未选择"
        - Big intent prompt + textarea + Send (⌘/Ctrl+Enter shortcut)
        - Recent tasks grid (status pill + caption + relative time)
        - Manager auxiliary footer hint
      When a task is open we render the Workspace (wireframe §3):
        - Header with back button + task name + status pill
        - Conversation thread (user bubble right-aligned, Heicode
          left-aligned with "H" avatar; follow-up questions render
          as chip groups with high-risk dot indicators)
        - Reply textarea at bottom
        - Right-side TaskCardPanel (lg breakpoint+) with goal /
          scope / generated-artifacts / Manager actions / footer
          buttons (修改目标 / 去 Manager 准备)

Plumbing:
  - tabStore.ts: HEICODE_TASKS_TAB_ID + 'heicode_tasks' TabType,
    treated like settings/scheduled in dedupe rules
  - Sidebar.tsx: new "我的任务" entry between "新建会话" and
    "定时任务" with a target icon
  - ContentRouter.tsx: route 'heicode_tasks' → HeicodeTasksHome
  - i18n: tasks.* (~24 keys per locale) + sidebar.heicodeTasks

Backend wiring TODO: when mcp-server publishes the task-orchestration
contract, swap submitIntent / answerFollowup / appendMessage for real
calls and keep the same shapes. Status updates can come in via SSE
or polling and be merged onto useHeicodeTaskStore.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 11:42:42 +08:00
chenchenandClaude Opus 4.7 f08119fd33 feat(client): slice 6 — minimal login per spec + high-risk approval dialog
Aligns the client with docs/product-package/{08,11}.md.

6a — Login surface trimmed to wireframe §1:
  - Brand wordmark + tagline "从一个想法,到可上线的软件产品"
  - Footer line "登录后,客户端会使用 Heicode 提供的模型。"
  - ProviderLoginCard now shows ONLY: sign-in target host (read-only),
    email + password, sign-in button. The local-network warning tag,
    raw baseUrl pill, promo paragraph, "or via browser" alt link, and
    the "RECOMMENDED" badge — all dropped per the wireframe's "登录目
    标只有 Heicode" intent.
  - Removed dead handleOAuth / shellOpen / isLocalBaseUrl helpers.

6b — High-risk approval dialog (08-client-guide.md §"高危审批体验"
+ 11-product-prototype-wireframes.md §9):
  - New zustand store stores/approvalStore.ts with a FIFO queue of
    ApprovalRequest items + decide(id, 'approve' | 'reject' |
    'postpone') action. Idempotent enqueue (dedupe by id).
  - New components/approval/ApprovalDialog.tsx renders queue[0] as a
    modal with the 6 spec fields (task / operation / target / role /
    impact / credential), a Heicode-suggestion sidebar, a risk-level
    pill, and 3 actions: 拒绝 / 稍后提醒 / 批准 N 分钟. Queue depth
    badge appears at the bottom when more requests are pending.
  - AppShell renders <ApprovalDialog /> alongside ToastContainer so it
    overlays any surface (sessions, settings, etc.).
  - Backend wiring pending — for now main.tsx calls
    installApprovalMock() which exposes window.__heicodeMockApproval()
    for DevTools-driven demos. Real backend hook lands when
    mcp-server / agent-manager publish the approval-stream contract.

i18n: added login.tagline / login.signInTarget /
login.footer.heicodeProvidesModels and a full approval.* set
(zh + en, ~17 keys per locale).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 11:29:20 +08:00
chenchenandClaude Opus 4.7 4827682de5 refactor(client): retire client-side resources UI per new product spec
The 2026-05-08 product package (docs/product-package/) redraws the
client / Manager boundary. Per 08-client-guide.md §1-7, the client
explicitly does NOT carry resource binding, permission grants, or
any account / security surface — those move entirely to Manager.

This commit removes the client-side resources surface that landed in
slices 2-4 (commits d1db2c1, c0363be, a28c900):

Deleted:
  - cc-haha/desktop/src/api/heicodeResources.ts          (API client)
  - cc-haha/desktop/src/stores/resourceStore.ts          (zustand)
  - cc-haha/desktop/src/pages/ResourceBindings.tsx       (page)
  - cc-haha/desktop/src/components/resources/Modals.tsx  (3 modals)
  - cc-haha/src/server/api/heicode-resources.ts          (proxy)

Reverted:
  - Sidebar.tsx: drop the Resources nav item + RESOURCES_TAB_ID import
  - ContentRouter.tsx: drop the 'resources' branch + import
  - tabStore.ts: drop RESOURCES_TAB_ID + 'resources' from TabType
  - router.ts: drop 'heicode-resources' case + handler import
  - i18n zh.ts + en.ts: strip ~63 keys (sidebar.resources +
    resources.* + grants.*)

Kept (still useful for the new spec's Manager-side data needs):
  - mcpAuth schema in types/provider.ts
  - mcpAuth wired through CreateProviderInput / UpdateProviderInput
  - providerService persistence of mcpAuth on add/update
  - Path A login flow that decodes JWT exp claims and stores the
    pair on the saved provider

Why keep token persistence even though the client doesn't expose
binding/grant UI any more? Per product spec the Manager will surface
余额 / 模型 / 用量 / 调用日志 (§2.3.1 in mcp-server's 待办 doc), and
the client will surface high-risk approvals (08-client-guide.md
§5). Both flows need a JWT pair we can refresh without re-prompting
for password — that machinery is already in place.

Next slice candidates per product spec (08 + 10 + 11):
  - High-risk approval dialog (新增 Tier 1, mock-wired UI first)
  - Task card + intent input as main client surface
  - Execution feedback panel (Agnet sub-stage status)
  - Delivery result panel
None of those are in this commit; this commit is purely cleanup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 11:19:21 +08:00
chenchenandClaude Opus 4.7 a28c90040f feat(resources): slice 4 — full CRUD for bindings + grants UI
What ships:

  Bindings tab:
    - Create binding modal (type / name / external_ref /
      permission_scope / secret_ref / status). Permission scope is a
      newline-or-comma textarea that splits into a string[].
    - Soft-delete (status = revoked) with red confirm dialog.

  Grants tab:
    - List with binding name + role + allowed actions + scope + status
      + expires.
    - Create grant modal: pick binding → checkbox-select allowed
      actions from THAT binding's permission_scope (auto-cleared when
      binding changes), set binding_scope / role / expires_at.
    - Revoke with red confirm dialog.

  Shared:
    - Tab switcher with active-state underline + count badge.
    - Refresh button per tab (independent fetch state).
    - Error banners with dismiss; mutation errors surface in modals.
    - i18n: ~30 new keys per locale (zh + en).

Backend (no change):
    Slice 3's /api/heicode-resources/* proxy already handles POST /
    PUT / DELETE because it forwards verb + body verbatim.
    The Authorization-header refresh logic (60s buffer) automatically
    keeps mutations working across the 24h JWT boundary.

mcp-server safety nets the user can rely on (already enforced):
  - 422 RESOURCE_GRANT_SECRET_REJECTED if metadata/constraints/scope
    contains plaintext credential keys
  - 400 RESOURCE_GRANT_INVALID if grant.allowed_actions ⊄ binding.scope
  - 403 FORBIDDEN_SCOPE on cross-user binding/grant access

Cosmetic notes:
  - GrantFormModal hooks were reordered to satisfy React's "hooks
    before any early return" rule.
  - useEffect that prunes allowed_actions when the picked binding
    changes uses an internal `changed` flag to avoid a setState loop.

Slice 5 candidates (not in this commit):
  - Edit binding (PUT)
  - metadata + constraints power-user JSON editor
  - Grant suspend/unsuspend
  - inline filtering (type / status)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 18:46:30 +08:00
chenchenandClaude Opus 4.7 c0363be850 feat(resources): slice 3 — persist mcp JWT, proxy, list bindings
Backend:

  1. Extend SavedProvider schema with optional mcpAuth field
     (accessToken / refreshToken / accessExpiresAt / refreshExpiresAt /
     managerLoginUrl / userId / channelId). Wired through
     CreateProviderInput and UpdateProviderInput so providerService
     persists tokens to providers.json.

  2. handleLoginWithCredentials (Path A) now decodes the JWT exp claim
     of both tokens (no signature verification — issuer just authed us)
     and stores the resulting mcpAuth object on the saved provider.
     Documented TTL (24h access / 7d refresh) used as fallback if exp
     claim missing.

  3. New handler api/heicode-resources.ts — proxy for the local server
     route /api/heicode-resources/{*path}. It:
       - Reads mcpAuth from the active provider (401 if missing)
       - Refreshes the access token if < 60s from expiry by calling
         <managerLoginUrl>/api/auth/refresh; persists the new pair
         back to providers.json before forwarding
       - Returns 401 if refresh token is also expired (re-login needed)
       - Forwards request to <managerLoginUrl>/api/resources or
         /api/resource-grants with Authorization: Bearer <accessToken>
       - Passes status + body through

  4. router.ts: register case 'heicode-resources'.

  5. errorHandler: add ApiError.unauthorized(401) and badGateway(502)
     factories used by the proxy.

Desktop:

  6. New api/heicodeResources.ts client + types (ResourceBinding,
     ResourceGrant, etc. mirroring mcp-server contract). Slice 3 only
     exposes listBindings + getBinding.

  7. New stores/resourceStore.ts (zustand) with bindings, isLoading,
     hasFetched, error + fetchBindings action.

  8. pages/ResourceBindings.tsx upgraded from shell to a real list:
       - Auto-fetches on mount
       - Shows loading skeleton, error banner with dismiss, empty state,
         or a 5-column table (Name / Type / External ref / Status /
         Permission scope)
       - Refresh button in the header
       - Footer note about CRUD coming in slice 4

  9. i18n: 14 new keys (common.dismiss + resources.refresh / refreshing
     / col.* / error.title / footer.cruComingSoon) in both zh + en.

E2E behaviour after install: log in via 55@55.com / By@123456., open
Resources tab — local server proxies to apimtaiji and lists whatever
ResourceBindings the user has on mcp-server. New test account 55@55.com
has 0 bindings, so empty state shows up.

Slice 4 next: Create / Edit / Delete binding modals + Grants UI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 18:04:59 +08:00
chenchenandClaude Opus 4.7 d1db2c1501 feat(resources): add Resources tab shell aligned with Heicode full-stack vision
Per docs/vision-heicode-full-stack-agentic-dev.md and plan.md P1, Heicode
is a full-stack agentic dev platform — not a chat-only client. cc-haha
needs a "Resources" entry where users bind Git repos / SK / project docs
/ cloud accounts and grant them to sub-agents.

mcp-server team has the P1 9 endpoints live (POST/GET/PUT/DELETE
/api/resources, POST/GET/DELETE /api/resource-grants — see
Heicode-接口契约文档.md §2-§3). cc-haha has not consumed them yet.

This commit ships slice 2 (page shell):
  - tabStore: new TabType 'resources' + RESOURCES_TAB_ID export
  - Sidebar: new nav entry between 'scheduled' and 'terminal' (link icon)
  - ContentRouter: route 'resources' tab to <ResourceBindings />
  - pages/ResourceBindings.tsx: header + "coming soon" placeholder card
  - i18n: sidebar.resources + resources.* keys (zh + en)

Slice 3 (next): persist mcp-server JWT in provider record so the local
Bun server can proxy /api/heicode-resources/* to apimtaiji with a fresh
Authorization Bearer header. Refresh logic on the 24h boundary.

Slice 4 (next): actual Bindings list + Create/Delete + Grants list +
Create/Revoke modals.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 17:39:02 +08:00
chenchenandClaude Opus 4.7 86bad2323f feat(login): align desktop credentials login with upstream Heicode design
Per heicode.md / heicode-runtime-auth-newapi-secret-design.md /
Heicode-登录接口对接文档.md, identity is owned by the Manager
(mcp-server), NewAPI is just the model gateway. The previous local
flow hit NewAPI's /api/user/login directly, which deviates from the
documented design — that endpoint is the legacy upstream NewAPI password
login that the current production web frontend already bypasses.

New flow inside POST /api/heicode-auth/login-with-credentials:

  1. POST <managerLoginUrl>/api/auth/login (mcp-server)
       Body: {email, password, role: "user"}
       → 200 {success, data{token, refreshToken, user{id, channelId,
                                                       role, email,
                                                       name}}}

  2. POST <baseUrl>/api/user/session/from-agnet (heicode 后端)
       Body: {access_token, refresh_token}
       → 200 + Set-Cookie: session=...
       JIT-syncs the local NewAPI user from the Agnet identity:
       users.group becomes the channelId returned by mcp-server,
       which matches NewAPI's abilities/channel routing model.

  3. GET <baseUrl>/heicode/oauth/authorize?... (heicode 后端)
       Headers: Cookie + New-Api-User
       redirect: 'manual' to capture the 302 Location header
       → token=sk-XXXX is parsed out and handed to the existing
         loginAndActivate pipeline (which probes /v1/models and
         persists the active provider).

Provider preset gains an optional managerLoginUrl field (default
https://apimtaiji.azure-api.net/api/mcp for taijiaicloud), with an
env override HEICODE_TAIJIAICLOUD_MANAGER_LOGIN_URL for dev.

End-to-end verified locally with the documented test account
55@55.com / By@123456.: each step returns 200, /heicode/oauth/authorize
mints a sk- token tied to channelId 6e6fc470-76f8-4bb1-8ea4-625dc5b12bc6,
and /v1/models returns the full live model catalogue under that channel.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 15:28:21 +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 f82042f83b chore(branding): replace Claude-style icon with Heicode H mark
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>
2026-05-07 14:26:39 +08:00
chenchenandClaude Opus 4.7 c12e19b1ce feat: email+password login (path B from original design doc)
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>
2026-05-07 14:08:54 +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
chenchenandClaude Opus 4.7 7ec7778c18 fix: enforce Heicode-only login and remove ClawdRouter enum residue
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>
2026-05-05 20:56:33 +08:00
chenchen eba6478913 更新登录 2026-05-05 20:44:24 +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 5fb432f7c8 docs: clarify auth billing and secret boundaries
Document Manager user reuse, NewAPI billing mapping, OpenBao short-lived credential injection, and Agnet-owned model configuration.

Tested: git diff --check

Co-authored-by: OmX <omx@oh-my-codex.dev>
2026-05-04 08:46:05 +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 e7b1fd81ec Merge commit 'd39e462ff2de4f82765159a18159f3f00c7f434f' 2026-05-03 20:50:46 +08:00
gongzhiyong f182610793 Merge commit '18a7b316a1da1fb16817387c586ba3db1ca84b1c' 2026-05-03 20:50:45 +08:00
gongzhiyong 36eb0159bc Merge commit '91617b5d64fcf528a34befea1d7a9168efe070c6' 2026-05-03 20:50:44 +08:00
gongzhiyongandOmX 18a7b316a1 Validate focused docs and backend checks
Worker 3 completed the assigned validation pass without source edits, recording backend pass evidence plus environment and contract findings for leader integration.

Tested: go vet ./controller ./model ./router; go test focused resource and Agnet grant cases; go test ./controller ./model ./router; git diff --check; focused docs secret scan.

Not-tested: frontend tsc/eslint require bun or full web dependencies; live Agnet curl checks require credentials and service URL.

Co-authored-by: OmX <omx@oh-my-codex.dev>
2026-05-03 18:11:48 +08:00
gongzhiyong 91617b5d64 docs: tighten Agnet secret placeholders 2026-05-03 18:09:41 +08:00
gongzhiyong 660670d2fc docs: add azure deploy guardrails 2026-05-03 18:09:07 +08:00
gongzhiyong 0d7491c9a1 omx(team): auto-checkpoint worker-5 [unknown] 2026-05-03 18:09:04 +08:00
gongzhiyong b4413cc230 omx(team): merge worker-1 2026-05-03 18:09:01 +08:00
gongzhiyong d39e462ff2 docs: add azure deploy guardrails 2026-05-03 18:08:15 +08:00
gongzhiyong 6a3e918787 docs: complete Agnet platform contract 2026-05-03 18:05:45 +08:00
gongzhiyong aba1ce28df docs: add daily work summary 2026-05-02 23:49:18 +08:00
gongzhiyong ab71d5b72b docs: add agnet platform request contract 2026-05-02 23:42:51 +08:00
gongzhiyong 57a86ce060 Merge commit '8878d4040c9f4c1a94184ed7a9755e9d7f73a745' 2026-05-02 23:42:18 +08:00
gongzhiyong 8878d4040c task: implement P1 manager resource model 2026-05-02 23:36:33 +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 1aa3643278 omx(team): auto-checkpoint worker-3 [3] 2026-05-02 23:29:37 +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
gongzhiyong a8be398087 omx(team): auto-checkpoint worker-4 [4] 2026-05-02 23:28:37 +08:00