The isNewerOrEqual function was comparing pre-release strings
lexicographically (e.g., "beta.2" > "beta.10" due to string comparison),
causing incorrect downgrade detection. Now parses pre-release into
id and numeric parts for proper numeric comparison.
Fixes: beta version upgrade being treated as outdated and downgrading to stable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add version synchronization for npm packages when updating cc-connect binary. This prevents npm from re-downloading old versions due to version mismatch between the binary and package.json.
generated by llmgit
Co-Authored-By: Claude <noreply@anthropic.com>
The changes add error handling for previously ignored operations and introduce logging for critical errors and warnings. This includes:
- Adding error checks for file operations, JSON unmarshaling, system calls
- Logging warnings/errors for failed operations using slog
- Properly handling return values from functions that were previously ignored
- Adding context to error messages for better debugging
- Cleaning up unused code and variables
generated by llmgit
Co-Authored-By: Claude <noreply@anthropic.com>
Skip agent CLI test when running in CI environment where no real cursor agent is available.
generated by llmgit
Co-Authored-By: Claude <noreply@anthropic.com>
Fixes potential nil panic in 401 retry path by properly checking http.NewRequest error. Also updates error message wrapping to match convention.
generated by llmgit
Co-Authored-By: Claude <noreply@anthropic.com>
Add --qr-image flag to save QR code as PNG file during Feishu onboarding.
Implement QR code image generation using rsc.io/qr package.
Add tests for QR image saving functionality.
generated by llmgit
Co-Authored-By: Claude <noreply@anthropic.com>
Implement card rendering for /whoami command when platform supports cards, with proper formatting of user identity information. Added extractPlatformName helper and new i18n messages. Includes test case for card rendering.
generated by llmgit
Co-Authored-By: Claude <noreply@anthropic.com>
- Added new /whoami command (with /myid alias) to show user identity info
- Updated /status command to include User ID in output
- Modified allow_from guidance to recommend /whoami instead of manual lookup
- Added i18n strings and tests for new functionality
- Updated help menus and config example comments to reference /whoami
generated by llmgit
Co-Authored-By: Claude <noreply@anthropic.com>
Add detailed user guidance for Feishu bot setup, including allow_from clarification and bot menu configuration instructions. Implement handler for bot custom menu click events, treating menu items as slash commands. Default set-allow-from-empty to false to prevent inaccurate open_id usage.
generated by llmgit
Co-Authored-By: Claude <noreply@anthropic.com>
Add a sanitizingLogger wrapper that masks sensitive query parameters
in URLs logged by the Lark SDK websocket client. Parameters masked:
device_id, access_key, ticket, conn_id, secret, token, password, key.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(platform): implement ImageSender for Discord, Slack, DingTalk, WeChat Work, QQ, QQBot
Add SendImage support to 6 platforms that previously only supported
receiving images. Each implementation follows the platform's native
API for uploading and sending images:
- Discord: ChannelMessageSendComplex with discordgo.File attachment
- Slack: UploadFileV2Context with thread support
- DingTalk: media upload + oToMessages API (refactored uploadMedia
to support both voice and image media types)
- WeChat Work: media upload + message send API
- QQ (OneBot v11): base64-encoded image segments via WebSocket
- QQBot (Official API v2): rich media upload + msg_type 7
LINE is excluded as its API requires externally hosted image URLs.
* fix(platform): address code review findings in SendImage
Discord:
- Fix io.Reader exhaustion: use newFile() factory for fresh reader on fallback
- Handle firstDone state machine for interactions (mirror sendInteraction pattern)
DingTalk:
- Read response body on success for debugging (mirror SendAudio pattern)
- Use json.Marshal for msgParam instead of fmt.Sprintf
QQBot:
- Handle http.NewRequest error on 401 retry path (prevent nil panic)
Discord auto-creates a managed role for each bot. When a bot is not
visible in the channel member list (common in new channels or when
multiple bots share a guild), users can only @mention the role instead
of the user. The role mention format <@&roleID> was not recognized,
causing the bot to silently ignore the message.
Fix by:
- Caching bot's managed role ID on Ready and GuildCreate events
- Checking m.MentionRoles and <@&roleID> content in addition to
m.Mentions and <@botID> content
- Stripping role mention tags from message content
- Adding IntentsGuilds to receive GuildCreate events for role lookup
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SetPlatformPrompt is only called when the platform implements
FormattingInstructionProvider. If a Slack message sets the prompt to
mrkdwn instructions and then a Telegram message arrives (which does
not implement the interface), the stale Slack prompt persists and
leaks into the Telegram session.
Always call SetPlatformPrompt — with the platform's instructions if
available, or with an empty string to clear any stale prompt.
Updated the GitHub CI workflow to use the correct golangci-lint installation path. Enhanced test mocks with proper mutex protection in TestMessageHandler and cleaned up FakeAgentSession implementation for better thread safety and performance.
generated by llmgit
Co-Authored-By: Claude <noreply@anthropic.com>
- session.go: Events() now correctly checks if last event
already has Done=true before appending an extra Done event
- message.go: TestLongMessage now uses strings.Repeat instead
of null bytes
- message.go: BatchTestMessages now uses fmt.Sprintf
instead of rune overflow-prone string concatenation
- response.go: TestAgentSessionInfoList now uses fmt.Sprintf
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add:
- T-241: Discord embed format regression test
- T-242: Telegram command parsing regression test
- T-243: DingTalk crypto/regression test
- T-252: Cron job cancellation regression test
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add testify and httpmock dependencies for testing
- Create tests/ directory structure with mocks and fakes
- Add mock_platform.go: mock for core.Platform interface
- Add mock_agent.go: mock for core.Agent/AgentSession interfaces
- Add fake/message.go: test message and event fixtures
- Add fake/session.go: fake agent session implementation
- Add fake/response.go: test helpers and fixtures
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The TestFetchModelsFromAgentCLI test was failing due to 2 second timeout
being too short for the agent CLI to respond. Increased to 5 seconds
to account for environment variability.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(core): share provider model lookup and stabilize tests
* fix(tests): address PR review follow-ups
---------
Co-authored-by: Deeka Wong <8337659+huangdijia@users.noreply.github.com>
- Replaced 15 occurrences of fmt.Sprintf("❌ %v", err) with e.i18n.Tf(MsgError, err)
- Replaced 3 occurrences of fmt.Sprintf("❌ %s", ...) with e.i18n.Tf(MsgError, ...)
- Added MsgFailedToDeleteSession with multi-language support
- Remaining uncounted: cron job errors (lines 750/752) have special formatting
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Added MsgFailedToStartAgentSession with EN/ZH/ZH-TW/JA/ES translations
- Updated engine.go to use i18n key directly
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Verify that drainOrphanedQueue saves session history through the passed
workspace-specific SessionManager rather than the global e.sessions.
This guards against the regression where orphaned queue drains in
multi-workspace mode would persist history to the wrong store.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
On macOS, /var is a symlink to /private/var. normalizeWorkspacePath
correctly resolves this, but test expectations used raw t.TempDir()
paths without resolving. Fixed by normalizing expected paths in:
- TestNormalizeWorkspacePath: use filepath.EvalSymlinks for expected dir
- TestMultiWorkspaceResolution_ConventionMatch: use normalizeWorkspacePath
- TestMultiWorkspaceResolution_ExistingBinding: use normalizeWorkspacePath
- TestCmdList_MultiWorkspaceUsesWorkspaceSessions: normalize wsDir before
seeding workspace pool so it matches the key used by commandContext
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
GetOrCreateActive() was not calling saveLocked() after creating a new
session, so workspace sessions were never written to disk.
processInteractiveEvents() always used e.sessions (the global manager)
instead of the workspace-specific SessionManager, so even event-driven
saves went to the wrong file. getOrCreateInteractiveStateWith() did not
save after CompareAndSetAgentSessionID either.
Fix by:
- Adding saveLocked() call in GetOrCreateActive when creating
- Threading the correct SessionManager through processInteractiveMessageWith,
getOrCreateInteractiveStateWith, and processInteractiveEvents
- Saving after CompareAndSetAgentSessionID in getOrCreateInteractiveStateWith
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The workspace init flow would swallow slash commands (e.g. /workspace bind)
on platforms like Discord where commands include the "/" prefix. The guard
at handleMessage only checked for "workspace" without "/", which was
designed for Slack where the prefix was stripped.
Three fixes:
- Add "/workspace" to the init flow bypass guard in handleMessage
- Let slash commands escape an existing init flow in handleWorkspaceInitFlow
- Clean up stale init flow state when workspace commands bypass the flow
Also implement ChannelNameResolver for Discord so convention-based
workspace matching works automatically by channel name.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Several slash command handlers (/stop, /compress, /quiet, /model, /reasoning,
/mode, /provider, /status) and handlePendingPermission used msg.SessionKey
directly to look up interactiveStates, but in multi-workspace mode the states
are stored with a workspace-prefixed key (workspace + ":" + sessionKey). This
caused these commands to fail silently when multi-workspace was enabled.
Replace all bare msg.SessionKey usages with interactiveKeyForSessionKey() which
correctly resolves the workspace-prefixed key. Also remove the hacky
suffix-matching workaround in handlePendingPermission in favor of the proper
helper.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract duplicate message queue processing logic into single drainPendingMessages method and consolidate sender prompt building into buildSenderPrompt.
generated by llmgit
Co-Authored-By: Claude <noreply@anthropic.com>
MiniMax-M2.7 is the latest flagship model with 1M context window.
- Update default model to MiniMax-M2.7 in provider config examples
- Add models list with M2.7, M2.5, and M2.5-highspeed aliases
- Update context window description from 204K to 1M
- Update both English and Chinese documentation