Commit graph

274 commits

Author SHA1 Message Date
yushen
0b50400a45 fix(desktop): read error body instead of statusText for gateway errors
res.statusText is always empty under HTTP/2, causing "Gateway error: "
with no detail. Now reads the JSON response body to surface the
server's actual error message and always includes the status code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 08:51:46 +08:00
yushen
b3a179971e chore: bump version to 0.1.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 08:19:15 +08:00
yushen
eb07f12c49 chore(desktop): add env files for dev/production and update dev scripts
- Track .env.development and .env.production for desktop app
- Add MAIN_VITE_API_URL to all env files
- Remove hardcoded GATEWAY_URL from dev scripts (now in .env.development)
- Update .env.example with full documentation of all env vars

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 07:30:54 +08:00
yushen
ef32078b3c fix(desktop): use RENDERER_VITE_API_URL for renderer API host
Read API host from import.meta.env.RENDERER_VITE_API_URL instead of
hardcoding it, so staging/dev builds point to the correct backend.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 07:30:48 +08:00
yushen
b7477cb646 feat(desktop): bridge MAIN_VITE_API_URL to process.env for packaged builds
In packaged Electron builds, @multica/core is externalized and .env
files are excluded. Bridge import.meta.env.MAIN_VITE_API_URL (injected
at build time by electron-vite) to process.env.MULTICA_API_URL so that
getApiBaseUrl() reads the correct value in staging/test environments.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 07:30:42 +08:00
Jiayuan Zhang
d1570698ac fix(telegram): fix tool narration detection and typing indicator during tool execution
- Detect both "tool_use" (Anthropic) and "toolCall" (Hub) content types
- Re-send typing indicator after sending/editing status message since
  Telegram clears typing state on any message send/edit
- Remove debug file logging (appendFileSync to /tmp)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 03:14:48 +08:00
Jiayuan Zhang
4c1365ff75 fix(telegram): strip existing bold markers in table conversion to prevent overlapping HTML tags
Table cells already containing **bold** markers got double-wrapped,
creating ****text**** which produced overlapping <b><i> tags rejected
by Telegram's HTML parser.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 03:14:41 +08:00
Jiayuan Zhang
dde8cc542a feat(telegram): show editable status message during tool execution
Instead of silently discarding tool narration or spamming separate
messages, send a single editable Telegram message that updates in-place
as the agent works. First tool narration sends a reply; subsequent
narrations edit the same message. The final answer is sent as a new
message.

- Add replyTextEditable/editText to ChannelOutboundAdapter interface
- Implement editFormatted + editable methods in Telegram plugin
- Track statusMessageId in ChannelManager, clear on agent_end/error
- Add sendOrEditStatus to Gateway TelegramService with same behavior

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 02:14:42 +08:00
Jiayuan Zhang
81998e6309 fix(telegram): skip tool narration messages, only send final answer
When the agent uses tools (web search, etc.), it generates intermediate
narration text like "Let me search..." before each tool call. These were
being sent as separate Telegram messages, causing message spam. Now we
detect tool_use blocks in the message content and skip sending those
intermediate messages — only the final answer reaches the user.

Applied to both Desktop channel plugin and Gateway Telegram service.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 02:04:17 +08:00
Jiayuan Zhang
8270762d66 feat(telegram): convert Markdown tables to vertical list format
Telegram doesn't support HTML tables, so pipe-delimited Markdown tables
were rendered as hard-to-read plain text on mobile. This converts tables
to a vertical "Header: Value" format with bold first column before
sending to Telegram.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 01:56:21 +08:00
Jiayuan Zhang
9189883710
Merge pull request #175 from multica-ai/forrestchang/telegram-arch
feat(gateway): Telegram QR-based connection flow with centralized bot
2026-02-14 01:45:46 +08:00
Jiayuan Zhang
eb274d5e0c fix(desktop): resolve lint warnings for react-refresh and unused import
- Extract useQRToken and useCountdown hooks to qr-hooks.ts so qr-code.tsx
  only exports components (fixes react-refresh/only-export-components)
- Remove unused useRef import from connect-step.tsx

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 01:38:04 +08:00
Jiayuan Zhang
d6393c6718 fix(gateway): remove cleanupPendingRequests that rejects all concurrent users
cleanupPendingRequests() iterated the service-wide pendingRequests Map
and rejected every entry. Since it was called from connectUser's catch
block (a per-user error path), one user's connection failure would
spuriously reject other users' in-flight verify RPCs.

The call was also redundant: sendVerifyRpc already cleans up its own
entry in all failure paths (timeout, RPC error, route failure).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 01:31:33 +08:00
Jiayuan Zhang
7af2a0d1b1 fix(desktop): auto-approve Telegram connection during onboarding
DeviceConfirmDialog only exists in the main Layout, so verify
requests were timing out during onboarding. Since the user is
actively generating the QR code, auto-approve and show a success
state instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 01:14:25 +08:00
Jiayuan Zhang
088750326c fix(gateway): persist Telegram users to JSON file when no database
Replaces in-memory Map with file-backed store at
~/.super-multica/gateway/telegram-users.json so user bindings
survive gateway restarts during local development.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 00:48:17 +08:00
Jiayuan Zhang
24b70e6e25 fix(gateway): add in-memory fallback for TelegramUserStore when no database
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 00:45:05 +08:00
Jiayuan Zhang
a7629db01e fix(gateway): enable CORS for HTTP endpoints
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 00:42:29 +08:00
Jiayuan Zhang
b39a0dd2ac feat(desktop): add Telegram QR code to Clients page and Onboarding
- Create TelegramConnectQR component (fetches short code from Gateway)
- Export reusable hooks/components from qr-code.tsx
- Update ChannelsTab with Telegram QR card
- Rewrite ConnectStep for QR-based flow (replaces BotFather token input)
- Re-add ConnectStep to onboarding: Privacy → Provider → Channels → Start

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 00:30:10 +08:00
Jiayuan Zhang
d75a24714d feat(gateway): add Telegram QR deep link connection flow
Add short code store, bot commands (/start, /status, /help), and
POST /telegram/connect-code endpoint for Desktop to create QR codes.
Users scan a QR → Telegram opens → /start {code} → auto-connects.

- ShortCodeStore: in-memory Map with TTL for connection info
- Bot commands registered via setMyCommands
- Refactor handleConnectionLink into shared connectUser method
- Fetch bot username via getMe() for deep link URL

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 00:30:01 +08:00
Jiayuan Zhang
5010d87284 feat(gateway): add long-polling fallback for local Telegram development
When TELEGRAM_WEBHOOK_URL is not set, the bot automatically starts in
long-polling mode (bot.start()) instead of waiting for webhook calls.
This allows local development without ngrok or a public URL.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 00:05:19 +08:00
Jiang Bohan
a86709a4cd chore: switch API host from api-dev.copilothub.ai to api.multica.ai
Update all backend API base URLs to use the production multica.ai domain.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 23:25:00 +08:00
Jiayuan Zhang
4cb8b93f93 refactor(desktop): hide manual Telegram bot creation, use official Gateway bot only
Remove the user-facing ability to create custom Telegram bots via BotFather.
Non-technical users should only need to message @multica_bot on Telegram.
- Disable telegramChannel plugin registration in initChannels()
- Remove ConnectStep from onboarding flow (Privacy → Provider → Start)
- Replace TelegramCard with simple text pointing to @multica_bot

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 22:20:39 +08:00
Jiayuan Zhang
38181ab4db refactor(gateway): remove group chat support from Telegram bot
Group chats have unresolved issues in the Gateway context:
- Per-user deviceId causes context overwrites across groups
- Reply chains across users route to wrong Hubs
- Welcome messages are noisy in groups

Restrict to private chats only until a proper group model is designed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 22:12:26 +08:00
Jiayuan Zhang
9646b08306 feat(gateway): port Desktop Telegram channel features to Gateway webhook bot
Port all 7 features from the Desktop long-polling Telegram channel plugin
to the Gateway webhook-based Telegram bot:

- Markdown → Telegram HTML formatting with parse-error fallback
- Text chunking for messages >4096 chars (paragraph-boundary split)
- Reply-to original message + 👀 ack reaction lifecycle
- Group chat support (mention/reply filtering, @mention stripping)
- Per-chat message serialization (prevents race conditions)
- Inbound media handling (voice/audio/photo/video/document)
  with transcription (Whisper) and description (Vision API)
- Outbound file captions with HTML formatting

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 22:06:43 +08:00
yushen
8881ae8f4b chore: bump version to 0.1.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 20:00:25 +08:00
yushen
faecc32aff chore(desktop): fix electron-builder config for releases
- Fix publish repo from "multica" to "super-multica"
- Add zip to mac targets (required for electron-updater auto-updates)
- Enable hardenedRuntime (required for notarization)
- Add notarize config with teamId placeholder

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 19:46:30 +08:00
LinYushen
77aff992c1
Merge pull request #170 from multica-ai/feat/desktop-api-client
feat(core): add auth-store and shared API client for desktop auth
2026-02-13 19:12:00 +08:00
Naiyuan Qing
4b6f42cc21
Merge pull request #169 from multica-ai/fix/google-oauth-client-id
fix(web): update Google OAuth Client ID
2026-02-13 18:39:05 +08:00
Naiyuan Qing
7b581b4e39 fix(web): update Google OAuth Client ID
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 18:38:12 +08:00
yushen
5ee08e9368 Merge remote-tracking branch 'origin/main' into feat/desktop-api-client 2026-02-13 17:57:19 +08:00
Naiyuan Qing
9e3169e034
Merge pull request #168 from multica-ai/docs/desktop-build-guide
docs(desktop): add build commands and configuration guide
2026-02-13 17:56:42 +08:00
Naiyuan Qing
5c5ac76693 docs(desktop): add build commands and configuration guide to .env.example
- Add build commands section with dev/staging/production options
- Add build output section explaining release directory structure
- Add configuration guide for production builds
- Add variable naming convention explanation
- Improve environment variables documentation with examples

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 17:55:44 +08:00
Naiyuan Qing
9877a4f97e
Merge pull request #167 from multica-ai/feat/desktop-device-id
feat: unify encrypted Device ID across all platforms
2026-02-13 17:47:54 +08:00
Naiyuan Qing
0c748f563f
Merge pull request #166 from multica-ai/NevilleQingNY/login-drag-region
fix(desktop): enable window dragging on login page
2026-02-13 17:34:23 +08:00
Naiyuan Qing
242be23876 feat(utils): unify encrypted Device ID across all platforms
- Add common generateEncryptedId() utility in @multica/utils
- All Device IDs now use same encryption algorithm (40 hex chars)
- Web: store encrypted format directly in localStorage
- Desktop: use shared utility, accept encrypted ID from Web
- Hub: use shared utility for hub-id generation
- Telegram: use shared utility for device ID generation
- Gateway hook: use encrypted format for client connections

Algorithm: sha256(sha256(uuid).slice(0,32)).slice(0,8) + sha256(uuid).slice(0,32)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 17:34:23 +08:00
Naiyuan Qing
8dfd4bc388 fix(desktop): enable window dragging on login page
Add WebkitAppRegion drag to login page background areas so the window
can be dragged on macOS. Mark the sign-in button as no-drag to keep it
clickable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 17:28:38 +08:00
Naiyuan Qing
911ed5ae36
Merge pull request #164 from multica-ai/NevilleQingNY/persist-chat-tabs
fix(desktop): persist chat state across tab navigation
2026-02-13 17:10:54 +08:00
Naiyuan Qing
298299d88e fix(desktop): persist chat state across tab navigation
Keep LocalChat mounted at the Layout level with CSS visibility toggle
instead of unmounting on route change, preserving messages, streaming
state, and IPC subscriptions when switching sidebar tabs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 17:04:15 +08:00
yushen
9026c27f21 Merge remote-tracking branch 'origin/main' into feat/desktop-api-client 2026-02-13 16:57:42 +08:00
Naiyuan Qing
003bde460d fix(web): remove auth guard from home page
Home page (QR code scanning) does not require authentication.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 16:53:22 +08:00
Naiyuan Qing
0d11318618 fix(desktop): prevent duplicate welcome toast on login
- Move auth callback listener setup before async operations
- Add unique ID to welcome toast to prevent duplicates

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 16:53:17 +08:00
Naiyuan Qing
f13509e12a feat(auth): pass encrypted Device ID from Web to Desktop
- Web stores raw UUID, encrypts when transmitting (consistent with copilot-search)
- Desktop receives encrypted Device ID from Web login callback
- Desktop stores encrypted 40-char format in auth.json
- Update IPC types to include deviceId in auth callback

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 16:53:13 +08:00
yushen
309c27b4dd feat(desktop): add API client with auth headers
Add fetch wrapper for desktop renderer to call Multica backend REST API.
Attaches sid, device-id, and os-type headers automatically using
useAuthStore and electronAPI.auth.getDeviceIdHeader().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 16:31:43 +08:00
Naiyuan Qing
68e262810c fix(desktop): store encrypted Device ID directly (40 hex chars)
- Change from storing raw UUID to storing encrypted format
- Consistent with devv-sdk and Web implementation
- Auto-migrate old UUID format to new encrypted format
- Validate device ID format (40 hex characters)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 16:00:16 +08:00
Naiyuan Qing
f0c9c43678 feat(web): add desktop callback API route
Server-side redirect to deep link for production builds.
More reliable than client-side window.location.href.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 15:37:08 +08:00
Naiyuan Qing
57cb99dbba feat(desktop): add persistent Device ID with encryption
- Generate UUID-based Device ID on first launch
- Store deviceId in auth.json (persists across logins/logouts)
- Add double SHA-256 encryption (consistent with Web)
- Expose getDeviceId and getDeviceIdHeader IPC methods
- Fix callback path to only accept /callback (prevent duplicate toasts)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 15:35:59 +08:00
Naiyuan Qing
a2cabb550f refactor(ui): unify login page styling across web and desktop
- Use bordered icon with consistent size on both platforms
- Adjust font size to match icon proportions
- Simplify desktop tagline for cleaner presentation
- Streamline web login header to [icon] Sign In format

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 14:56:16 +08:00
Naiyuan Qing
09562776d4 fix(web): avoid setState in useEffect in AuthGuard 2026-02-13 14:43:52 +08:00
Naiyuan Qing
e0f80b0054 merge: resolve conflict with main (keep both auth and subagents handlers) 2026-02-13 14:41:15 +08:00
Naiyuan Qing
450257035f fix: add missing comma in package.json 2026-02-13 14:39:38 +08:00