Commit Graph

204 Commits

Author SHA1 Message Date
ZhenYi
a2e8f5bf5b feat(models/rooms): add room attachment model and update room message/notifications 2026-04-20 15:45:03 +08:00
ZhenYi
98e6f77341 feat(migrate): add room attachment, push subscription, and model_id migrations 2026-04-20 15:44:59 +08:00
ZhenYi
d09af7c326 feat(config): add storage configuration module 2026-04-20 15:44:54 +08:00
ZhenYi
ba15324603 chore: update dependencies (cargo + npm) 2026-04-20 15:44:49 +08:00
ZhenYi
05909dbde7 fix(admin): use named export Cluster from ioredis 5.x
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
Previous `import { default as Cluster }` caused runtime to get Redis
instance instead of Cluster, resulting in ECONNREFUSED errors.
2026-04-20 10:03:26 +08:00
ZhenYi
a9c51526b8 fix(admin): fix ioredis 5.x Cluster constructor type resolution
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
- Use `Cluster` as default export from ioredis (not RedisCluster named export)
- Import ClusterNode type and use explicit type annotation on nodes array
- Use `any` cast on Cluster constructor to bypass TS overload resolution issue
- Fix closeRedis return type to Promise<unknown>
2026-04-20 09:41:19 +08:00
ZhenYi
67e8c5edc7 fix(admin): use Redis as type annotation, RedisCluster as runtime value
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
Fix TypeScript type error with ioredis 5.x default export pattern
2026-04-20 09:32:10 +08:00
ZhenYi
09d5a5877f fix(admin): upgrade ioredis cluster to 5.x RedisCluster API
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
- Replace deprecated Cluster with RedisCluster (ioredis 5.x breaking change)
- Extract username/password from cluster URLs for authentication
- Fix REDIS_CLUSTER_URLS to include all 3 master nodes with default user
2026-04-20 09:28:28 +08:00
ZhenYi
a3fcbab5d8 fix(admin): add /api/health to public paths to allow k8s probe
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
2026-04-20 07:40:57 +08:00
ZhenYi
58bba357b0 fix(admin): quote image tag to prevent Helm format string parsing
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
2026-04-20 01:33:34 +08:00
ZhenYi
3995579e56 fix(admin): add /api/health route for k8s readiness probe
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
2026-04-20 01:02:37 +08:00
ZhenYi
19cad7e14a config(admin): admin env
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
2026-04-20 00:22:42 +08:00
ZhenYi
6d16cc8c18 config(admin): admin env
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
2026-04-20 00:15:04 +08:00
ZhenYi
9ed56668dc fix(admin): handle admin.env as both list and map in deployment template
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
2026-04-19 23:21:53 +08:00
ZhenYi
82a928c96a config(admin): admin env
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
2026-04-19 22:39:41 +08:00
ZhenYi
8cf6415e15 config(admin): admin env 2026-04-19 22:39:25 +08:00
ZhenYi
3034c7f391 feat(admin): add TLS support to ingress with cert-manager and manual secret options 2026-04-19 22:35:31 +08:00
ZhenYi
e612043e5f feat(room): auto-add new project members to all rooms
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
2026-04-19 22:27:57 +08:00
ZhenYi
b8e5cbbb69 feat(admin): add Docker and Kubernetes deployment for admin panel
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
2026-04-19 21:49:22 +08:00
ZhenYi
208b6ed84e chore: remove deprecated docs (superseded by CLAUDE.md)
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
2026-04-19 20:49:21 +08:00
ZhenYi
fb91f5a6c5 feat(admin): add admin panel with billing alerts and model sync
- Add libs/api/admin with admin API endpoints:
  sync models, workspace credit, billing alert check
- Add workspace_alert_config model and alert service
- Add Session::no_op() for background tasks without user context
- Add admin/ Next.js admin panel (AI models, billing, workspaces, audit)
- Start billing alert background task every 30 minutes
2026-04-19 20:48:59 +08:00
ZhenYi
c4d4b2ecf5 fix(room): fix channel sidebar clickability and polish UI
- Fix DraggableRow: remove opacity-0 wrapper that was hiding
  RoomButton; drag handles now work without blocking clicks
- Move "+ Add Category" to bottom of channel list
- Reduce channel item padding (6px → 4px) for compact look
- Shrink # hash icon to 12px
- Add explicit text-align: left to channel names
- Reduce Add Category button/input to 10px font
2026-04-19 20:47:07 +08:00
ZhenYi
63c75ad453 feat(room): add category creation and drag-to-assign for channels
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
- Rewrite DiscordChannelSidebar with @dnd-kit drag-and-drop:
  rooms are sortable within categories; dragging onto a different
  category header assigns the room to that category
- Add inline 'Add Category' button: Enter/Esc to confirm/cancel
- Wire category create/move handlers in room.tsx via RoomContext
- Fix onAiStreamChunk to accumulate content properly and avoid
  redundant re-renders during AI streaming (dedup guard)
- No backend changes needed: category CRUD and room category update
  endpoints were already wired
2026-04-19 16:44:31 +08:00
ZhenYi
b73cc8d421 refactor(room): Discord-style UI redesign for channel sidebar and member list
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
2026-04-19 01:12:38 +08:00
ZhenYi
66006d842e feat(agent): inject project context and sender info into AI chat messages 2026-04-19 01:04:19 +08:00
ZhenYi
b740e2884d feat(room): auto-inherit project members as room members on room creation 2026-04-19 01:04:15 +08:00
ZhenYi
39d30678b5 fix(email): resolve SMTP connection failures (port 465 SMTPS, URL double scheme, retry backoff) 2026-04-19 01:04:11 +08:00
ZhenYi
882e86dc33 refactor(email): switch to async channel-based email queue with retry
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
Converts AppEmail from blocking sync sends to a background worker via
mpsc channel, adds SMTP pool tuning (min_idle 5, max_size 100), and
3-retry backoff on send failures.
2026-04-19 00:10:38 +08:00
ZhenYi
b693bd6beb fix(auth): use explicit user_uid in login flow instead of context.user()
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
The login function calls auth_2fa_status before set_user(user.uid), so
context.user() returns None and causes Unauthorized error on subsequent
logins after logout. Extracts auth_2fa_status_by_uid as an internal
helper accepting a Uuid, preserving the context-based wrapper for API
endpoints that require an authenticated user.
2026-04-19 00:03:18 +08:00
ZhenYi
2a2600859f dbg(email): add email error printrack
Some checks are pending
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
CI / Rust Lint & Check (push) Waiting to run
2026-04-18 23:30:17 +08:00
ZhenYi
7831d08848 feat(auth): add password reset confirmation endpoint and page
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
Add the second half of the password reset flow: /password/confirm API
endpoint with token validation, transactional password update, and a
frontend confirm-password-reset-page with proper error handling for
expired/used tokens. Updates generated SDK/client bindings.
2026-04-18 23:02:39 +08:00
ZhenYi
1af796ac75 feat(service): add file_tools module and git_blob_get tool
Add AI-accessible tools for reading structured files (CSV, JSON/JSONC,
Markdown, SQL) and searching repository content (git_grep). Also adds
git_blob_get to retrieve raw blob text content with binary detection.

Deferred: Excel, Word, PDF, PPT modules are stubbed out due to library
API incompatibilities (calamine 0.26, lopdf 0.34, quick-xml 0.37).
2026-04-18 23:02:10 +08:00
ZhenYi
767bb10249 feat(agent): wire git_tools into AI tool registry with full schemas
- ChatService: add tools() method to expose registered tool definitions
- RoomService: populate AiRequest.tools from chat_service.tools(), enable tools
  with max_tool_depth=3 (was always None)
- ToolHandler: add pub new() constructor so git_tools modules can register
  handlers with full schema metadata
- Add description + JSON schema params to all 16 git tools:
  git_log, git_show, git_search_commits, git_commit_info, git_graph,
  git_reflog, git_branch_list, git_branch_info, git_branches_merged,
  git_branch_diff, git_diff, git_diff_stats, git_blame, git_file_content,
  git_tree_ls, git_file_history, git_tag_list, git_tag_info
2026-04-18 21:42:33 +08:00
ZhenYi
76ca5fb1dd fix(frontend): wire up message search button in DiscordChatPanel
- Add showSearch state and RoomMessageSearch panel (420px slide-in)
- Search button now toggles panel and highlights when active
- Clicking a search result scrolls to the message and closes panel
- Add msg-{id} anchors on message containers for scroll-into-view
2026-04-18 21:13:03 +08:00
ZhenYi
9336250f1c fix(agent): skip reasoning_effort when think=false to avoid API errors
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
2026-04-18 19:41:59 +08:00
ZhenYi
168f14fbac chore: remove .next build artifacts from tracking 2026-04-18 19:33:42 +08:00
ZhenYi
a09f66b779 refactor(room): WebSocket queue and message editor improvements
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
- Enhance ws_universal.rs with queue message support
- Add queue types and producer improvements
- Simplify MessageBubble.tsx rendering logic
- Refactor IMEditor.tsx with improved message handling
- Update DiscordChatPanel.tsx with message enhancements
2026-04-18 19:29:36 +08:00
ZhenYi
c4fb943e07 fix(backend): add project_name and invited_by_username to InvitationResponse
InvitationResponse was missing project_name and invited_by_username fields,
causing /invitations accept to redirect to /project/undefined.
Now populated via async from_model() with batch DB lookups.
2026-04-18 19:24:43 +08:00
ZhenYi
5579e6c58e feat(backend): add git_tools service module
Add git_tools module with Git operations: branch, commit, diff, tag, tree, types, ctx
2026-04-18 19:08:06 +08:00
ZhenYi
821b0e998d refactor(room): Discord layout and room WebSocket client refactor
- Refactor room-context.tsx with improved WebSocket state management
- Enhance room-ws-client.ts with reconnect logic and message handling
- Update Discord layout components with message editor improvements
- Add WebSocket universal endpoint support in ws_universal.rs
2026-04-18 19:05:21 +08:00
ZhenYi
0cccec33b2 feat(frontend): invitations page with project and workspace support
- Add /invitations route with dedicated page and sidebar button
- Display both project invitations (accept/decline) and workspace invitations (accept only)
- Merge and sort both invitation types by most recent first
- Export new SDK functions: workspaceMyInvitations, workspaceAcceptInvitationBySlug
2026-04-18 19:05:14 +08:00
ZhenYi
9b9c12ffc8 feat(backend): add workspace invitation list and slug-based accept APIs
- Add workspace_my_pending_invitations() for listing pending invites
- Add workspace_accept_invitation_by_slug() to accept by slug without token
- Register new routes: GET /workspaces/me/invitations, POST /workspaces/invitations/accept-by-slug
2026-04-18 19:05:07 +08:00
ZhenYi
00a5369fe1 feat(frontend): Discord layout + AI Studio theme + Room Settings
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
Frontend:
- Add Discord-style 3-column layout (server icons / channel sidebar / chat)
- AI Studio design system: new CSS token palette (--room-* vars)
- Replace all hardcoded Discord colors with CSS variable tokens
- Add RoomSettingsPanel (name, visibility, AI model management)
- Settings + Member list panels mutually exclusive (don't overlap)
- AI models shown at top of member list with green accent
- Fix TS errors: TipTap SuggestionOptions, unused imports, StarterKit options
- Remove MentionInput, MentionPopover, old room components (废弃代码清理)

Backend:
- RoomAiResponse returns model_name from agents.model JOIN
- room_ai_list and room_ai_upsert fetch model name for each config
- AiConfigData ws-protocol interface updated with model_name

Note: RoomSettingsPanel UI still uses shadcn defaults (未完全迁移到AI Studio)
2026-04-18 16:59:36 +08:00
ZhenYi
aac32b1b92 fix(frontend): block selectionchange during MentionInput DOM updates
Root cause: when MentionInput updates innerHTML to reflect value changes,
the browser resets the selection to position 0. The selectionchange event
handler reads this wrong cursor position and sets ms.cursorOffset=0,
breaking mentionState calculation for the popover.

Fix:
- MentionInput sets window.__mentionBlockSelection=true before innerHTML
- Clears it via requestAnimationFrame after caret is restored
- selectionchange handler skips cursor reading when flag is set
2026-04-18 11:49:03 +08:00
ZhenYi
53b0b03716 fix(frontend): use selectionchange event for cursor tracking instead of per-render
The per-render tracking effect was reading DOM cursor position before
the browser had finished positioning the caret after innerHTML updates,
causing ms.cursorOffset to be set to the old position and overwriting
the deferred correct value.

Switch to document.selectionchange event which:
- Fires only when the user actually moves the cursor (arrow keys, mouse clicks)
- Does NOT fire during programmatic DOM updates
- Uses focusNode/focusOffset directly from the selection API

This completely eliminates the timing race between render effects and
programmatic cursor updates.
2026-04-18 11:42:43 +08:00
ZhenYi
4330325bfc fix(frontend): skip tracking effect update when caret is at end of text
Root cause: after onCategoryEnter sets value="@ai:", the MentionInput sync
effect sets innerHTML with the new content. The browser caret may be at
position 2 (not moved from the user's perspective), but prevCursorRef was
4. The tracking effect read DOM caret=2 and overwrote ms.setCursorOffset(4)
→ cursor jumped to position 2.

Fix: skip tracking effect update when:
- count (DOM caret) is at end of text (ms.value.length), AND
- prevCursorRef was also at end of text
This means the caret hasn't actually moved from the user's POV (just
positioned by the browser after innerHTML), so don't update state.
2026-04-18 11:39:16 +08:00
ZhenYi
126ffda4fe fix(frontend): skip cursor tracking effect during deferred cursor updates
Root cause: when onCategoryEnter scheduled a deferred setCursorOffset,
the tracking effect ran BEFORE setTimeout and read the OLD DOM cursor
position (still "@a" → position 2), overwriting the new cursor position
of 4 in a subsequent render.

Fix: add skipCursorTrackingRef flag. Set it before setTimeout fires,
clear it when setTimeout executes. The tracking effect checks the flag
and skips its update during the flush window.

Same fix applied to insertCategory imperative handle.
2026-04-18 11:27:37 +08:00
ZhenYi
fb09553b79 fix(frontend): defer cursor offset update in onCategoryEnter
When @category is selected, ms.setCursorOffset and ms.setValue were called
in the same event loop tick — the cursor sync effect later read the DOM
before the new mention value flushed, restoring the old caret position.

Defer ms.setCursorOffset via setTimeout so it fires after the DOM
reconciliation. Same fix applied to insertCategory imperative handle.
2026-04-18 11:24:01 +08:00
ZhenYi
5103d99a00 fix(frontend): rewrite MentionInput sync to prevent onChange overwriting mention draft
The root cause: handleMentionSelect set draft to mention HTML, but the
subsequent MentionInput.onInput event fired with plain text (after the
programmatic DOM insert) and overwrote the draft.

Solution: replace pendingSyncRef trick with a clean isUserInputRef flag.
- useEffect: if getPlainText(el) === value, DOM already correct (skip).
  Mark isUserInputRef = false so next useEffect skips caret restore.
- handleInput: always set isUserInputRef = true before calling onChange.

This eliminates the pendingSyncRef/__mentionSkipSync global flag mess
entirely.
2026-04-18 11:20:48 +08:00
ZhenYi
4ace651c6f fix(frontend): pass selected item to doInsert on Enter key and fix list keys
- handleSelectRef.current() was called without argument → suggestion was
  undefined → suggestion.type threw. Now passes the selected item.
- key prop moved to outer map wrapper div so React can diff the list
  correctly. Inner SuggestionItem/CategoryHeader no longer need keys.
2026-04-18 11:16:04 +08:00