Files
chenhg5-cc-connect/INSTALL.md
Wupei 6f8d3a2bd8 feat(matrix): add Matrix platform adapter with E2EE support (#834)
* feat(matrix): add Matrix platform adapter using mautrix-go

Implements a full Matrix protocol adapter so users can interact with
their coding agent through any Matrix homeserver (matrix.org, self-hosted
Synapse/Dendrite, etc.). Uses mautrix-go SDK for Client-Server API.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(matrix): add Matrix platform documentation

Update README.md, README.zh-CN.md, INSTALL.md, CLAUDE.md and add
docs/matrix.md with setup guide, config reference and FAQ.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* test(matrix): add unit tests and fix session key parsing

35 tests covering config validation, message handling, lifecycle,
concurrency, and error paths. Race detector clean.

Fixes two bugs found by tests:
- stripBotMention: strip matrix.to URL before plain user ID to avoid
  partial replacement inside the URL path
- ReconstructReplyCtx: room IDs contain colons, so colon-based SplitN
  corrupted them; use ":@" boundary detection instead

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(matrix): add Chinese setup guide

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(matrix): add E2EE support via mautrix cryptohelper

Add Olm/Megolm encryption support using mautrix-go's built-in
cryptohelper. Encrypted rooms are now fully supported for both
sending and receiving messages.

Key implementation details:
- Crypto DB stored per device ID (~/.cc-connect/matrix-crypto-<device>.db)
- Auto-recovers from stale device keys by force-uploading new keys
- All outbound messages encrypted via sendRoomEvent when room has E2EE
- DecryptErrorCallback logs decryption failures through slog
- Cleanup client stores on failed crypto init to prevent DB panics

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(matrix): update setup guide with E2EE instructions

- Recommend creating dedicated device via curl login (avoids E2EE issues)
- Add E2EE section with startup log example showing device_id
- Add FAQ entries for common E2EE problems and troubleshooting
- Document crypto DB location and cleanup steps

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(matrix): add SAS verification and cross-signing support

Enable auto-accept SAS key verification so users can verify the bot's
device from Element. Bootstrap cross-signing to eliminate "encrypted by
a device not verified by its owner" warning on bot messages.

- Add verification helper with auto-accept/auto-confirm SAS flow
- Workaround mautrix MAC verification bug for cross-user verification
- Fix in-room verification transaction ID lookup from m.relates_to
- Persist cross-signing seeds to disk for stable keys across restarts
- Support m.login.password UIA fallback for publishing cross-signing keys
- Add auto_verify and cross_signing_password config options

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(matrix): add verification and cross-signing documentation

Add SAS verification and cross-signing setup instructions to both
English and Chinese Matrix guides. Document new config options
(auto_verify, cross_signing_password) and FAQ entries for device
verification and the red exclamation mark warning.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(matrix): fix inaccurate documentation and capability table

- Fix Matrix "Markdown / cards" from  to ⚠️ (no CardSender)
- Change "red exclamation mark" to "red question mark" per actual UI
- Recommend curl with dedicated device_id for token (not Element)
- Add cross-signing seeds file to E2EE reset instructions
- Clarify that cross-signing may need cross_signing_password

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(matrix): reduce verbose logging in production

Downgrade per-message and internal workaround logs from Info to Debug,
and use structured fields for SAS verification log.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(matrix): fix formatting, rename field, and add token redaction

- Run gofmt to fix struct definition and literal alignment
- Rename shareSessionInChan to shareSessionInChannel for consistency
  with other platforms (Telegram, Discord, Slack)
- Add core.RedactToken() in connectLoop error logging to prevent
  access token leakage in logs

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* ci: install libolm-dev for Matrix E2EE crypto

The mautrix-go crypto package depends on libolm (C library) for
end-to-end encryption. The CI runners don't have it pre-installed,
causing golangci-lint to fail when loading the CGO package.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(matrix): use build-tagged E2EE to avoid CGO/libolm dependency

Split E2EE (end-to-end encryption) code behind a `goolm` build tag so
the default build compiles without CGO or libolm-dev. This fixes CI
lint failures caused by the mautrix-go crypto package pulling in the
CGO-based libolm backend by default.

- Default build: no E2EE, no CGO, CI lint passes
- Build with `-tags goolm`: full E2EE using pure-Go olm backend

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* build: enable goolm tag by default in Makefile

Matrix E2EE requires the goolm build tag. Add it as a default
tag in the Makefile so `make build` includes E2EE automatically.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(matrix): suppress unused field lint for cryptoHelper

The cryptoHelper field is only accessed in e2ee.go (goolm build tag),
so the default build's linter flags it as unused. Add //nolint:unused
since this is intentional.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(matrix): add Matrix platform adapter using mautrix-go

Implements a full Matrix protocol adapter so users can interact with
their coding agent through any Matrix homeserver (matrix.org, self-hosted
Synapse/Dendrite, etc.). Uses mautrix-go SDK for Client-Server API.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(matrix): add Matrix platform documentation

Update README.md, README.zh-CN.md, INSTALL.md, CLAUDE.md and add
docs/matrix.md with setup guide, config reference and FAQ.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* test(matrix): add unit tests and fix session key parsing

35 tests covering config validation, message handling, lifecycle,
concurrency, and error paths. Race detector clean.

Fixes two bugs found by tests:
- stripBotMention: strip matrix.to URL before plain user ID to avoid
  partial replacement inside the URL path
- ReconstructReplyCtx: room IDs contain colons, so colon-based SplitN
  corrupted them; use ":@" boundary detection instead

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(matrix): add Chinese setup guide

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(matrix): add E2EE support via mautrix cryptohelper

Add Olm/Megolm encryption support using mautrix-go's built-in
cryptohelper. Encrypted rooms are now fully supported for both
sending and receiving messages.

Key implementation details:
- Crypto DB stored per device ID (~/.cc-connect/matrix-crypto-<device>.db)
- Auto-recovers from stale device keys by force-uploading new keys
- All outbound messages encrypted via sendRoomEvent when room has E2EE
- DecryptErrorCallback logs decryption failures through slog
- Cleanup client stores on failed crypto init to prevent DB panics

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(matrix): update setup guide with E2EE instructions

- Recommend creating dedicated device via curl login (avoids E2EE issues)
- Add E2EE section with startup log example showing device_id
- Add FAQ entries for common E2EE problems and troubleshooting
- Document crypto DB location and cleanup steps

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(matrix): add SAS verification and cross-signing support

Enable auto-accept SAS key verification so users can verify the bot's
device from Element. Bootstrap cross-signing to eliminate "encrypted by
a device not verified by its owner" warning on bot messages.

- Add verification helper with auto-accept/auto-confirm SAS flow
- Workaround mautrix MAC verification bug for cross-user verification
- Fix in-room verification transaction ID lookup from m.relates_to
- Persist cross-signing seeds to disk for stable keys across restarts
- Support m.login.password UIA fallback for publishing cross-signing keys
- Add auto_verify and cross_signing_password config options

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(matrix): add verification and cross-signing documentation

Add SAS verification and cross-signing setup instructions to both
English and Chinese Matrix guides. Document new config options
(auto_verify, cross_signing_password) and FAQ entries for device
verification and the red exclamation mark warning.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(matrix): fix inaccurate documentation and capability table

- Fix Matrix "Markdown / cards" from  to ⚠️ (no CardSender)
- Change "red exclamation mark" to "red question mark" per actual UI
- Recommend curl with dedicated device_id for token (not Element)
- Add cross-signing seeds file to E2EE reset instructions
- Clarify that cross-signing may need cross_signing_password

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(matrix): reduce verbose logging in production

Downgrade per-message and internal workaround logs from Info to Debug,
and use structured fields for SAS verification log.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(matrix): fix formatting, rename field, and add token redaction

- Run gofmt to fix struct definition and literal alignment
- Rename shareSessionInChan to shareSessionInChannel for consistency
  with other platforms (Telegram, Discord, Slack)
- Add core.RedactToken() in connectLoop error logging to prevent
  access token leakage in logs

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* ci: install libolm-dev for Matrix E2EE crypto

The mautrix-go crypto package depends on libolm (C library) for
end-to-end encryption. The CI runners don't have it pre-installed,
causing golangci-lint to fail when loading the CGO package.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(matrix): use build-tagged E2EE to avoid CGO/libolm dependency

Split E2EE (end-to-end encryption) code behind a `goolm` build tag so
the default build compiles without CGO or libolm-dev. This fixes CI
lint failures caused by the mautrix-go crypto package pulling in the
CGO-based libolm backend by default.

- Default build: no E2EE, no CGO, CI lint passes
- Build with `-tags goolm`: full E2EE using pure-Go olm backend

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* build: enable goolm tag by default in Makefile

Matrix E2EE requires the goolm build tag. Add it as a default
tag in the Makefile so `make build` includes E2EE automatically.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(matrix): suppress unused field lint for cryptoHelper

The cryptoHelper field is only accessed in e2ee.go (goolm build tag),
so the default build's linter flags it as unused. Add //nolint:unused
since this is intentional.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(matrix): resolve lint errors for CI (errcheck + staticcheck)

* feat(agent): add GitHub Copilot as a first-class agent (#865)

* chore: ignore web/tsconfig.tsbuildinfo (TS incremental build cache)

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(qqbot): add inline keyboard buttons and INTERACTION_CREATE event handling (#1131)

* feat(qqbot): add support for inline keyboard buttons and interaction events

- Update default intents to include INTERACTION_CREATE
- Implement SendWithButtons to send messages with inline keyboard buttons
- Encode permission decisions and session key in button_data for routing callbacks
- Handle INTERACTION_CREATE events to process button clicks as permission responses
- Create synthetic message for permission decisions and forward to engine
- Add ackInteraction to acknowledge INTERACTION_CREATE events via API call
- Add extensive tests for sending buttons, handling interactions, and edge cases

* fix(qqbot): ignore ackInteraction error and correct test URL check

- Suppress error from ackInteraction to avoid unused error variable warning
- Update test to expect corrected interaction URL path "/interactions/interact-1" instead of "/v2/interactions/interact-1"

* - Add sessionKey field to replyContext to embed in button_data and session routing
- Refactor SendWithButtons to use sessionKey from replyContext and validate emptiness
- Enhance replyContext construction with sessionKey in various message scenarios
- Implement new tests for sharing session keys in channel, empty session key errors,
  and interaction_create event permission routing
- Update config.example.toml to document new required intents for interaction support
- Modify changelog with instructions on enabling INTERACTION_CREATE intent (bit 26) for QQ Bot
- Permission requests now use clickable inline buttons instead of text replies, requiring
  enabling the INTERACTION capability in QQ Open Platform settings

* test(qqbot): ignore errors and returned values in test HTTP handlers

* feat: integrate Google Antigravity CLI (agy) agent

* Harden antigravity session discovery and attachment handling to preserve resume correctness under contention

Constraint: Keep external behavior and interfaces unchanged while improving runtime robustness
Rejected: Full process-level session correlation | Requires upstream CLI contract not available here
Confidence: medium
Scope-risk: narrow
Directive: Keep session-id detection conservative unless agy exposes explicit correlation metadata
Tested: go test ./agent/antigravity/... && go test ./core/... && go test ./cmd/cc-connect/...
Not-tested: Real concurrent agy process race on multi-session host

* Fix antigravity prompt execution and shutdown safety without changing user-facing flow

Constraint: Preserve existing antigravity integration surface and core event handling contracts
Rejected: Introduce a custom permission event parser for agy stdout | No stable upstream protocol contract yet
Confidence: medium
Scope-risk: narrow
Directive: If agy publishes structured permission I/O, replace y/n terminal fallback with typed request/response framing
Tested: go test ./agent/antigravity/... && go test ./core/... && go test ./cmd/cc-connect/...
Not-tested: End-to-end interactive agy permission prompt against a live CLI binary

* Stabilize antigravity permission flow so Discord approvals consistently drive CLI execution

Constraint: Preserve current antigravity stream/event contracts while improving permission reliability
Rejected: Full structured agy protocol parser | Upstream schema is not yet stable/public
Confidence: medium
Scope-risk: narrow
Directive: Replace regex prompt detection with typed protocol once agy exposes machine-readable permission events
Tested: go test ./agent/antigravity/... && go test ./core/... && go test ./cmd/cc-connect/... && go build ./cmd/cc-connect
Not-tested: Live Discord permission prompts across all locales/terminal themes

* Prevent agy hangs and unsupported flag crashes in cross-platform antigravity runs

Constraint: Keep antigravity adapter behavior compatible across Telegram/Discord while avoiding CLI-specific crashes
Rejected: Keep passing -m and rely on user wrapper scripts | Breaks agy v1.0.2 directly for normal users
Confidence: high
Scope-risk: narrow
Directive: Re-enable explicit model flag only after agy documents stable model flag support
Tested: go test ./agent/antigravity/... && go test ./core/... && go test ./cmd/cc-connect/... && go build ./cmd/cc-connect
Not-tested: Live agy v1.0.2 interactive permission prompts on Telegram with real long-running tool tasks

* Fix lint-blocking errcheck findings in antigravity adapter without behavior changes

Constraint: Keep runtime behavior unchanged while satisfying CI lint gates
Rejected: Broader refactor around file/stream lifecycle | Unnecessary for this blocking lint failure
Confidence: high
Scope-risk: narrow
Directive: Keep close/remove calls explicitly checked or intentionally ignored with clear intent in this package
Tested: go test ./agent/antigravity/... && go test ./core/... && go test ./cmd/cc-connect/...
Not-tested: Full GitHub Actions rerun output

* Fix remaining errcheck close-handling findings from CI lint

Constraint: Resolve lint blockers without behavioral changes
Rejected: Broad lifecycle refactor | unnecessary for this CI-only failure class
Confidence: high
Scope-risk: narrow
Directive: Keep file/stream close sites explicitly checked or intentionally ignored for errcheck
Tested: go test ./agent/antigravity/... && go test ./core/... && go test ./cmd/cc-connect/...
Not-tested: GitHub Actions rerun not yet executed

* docs: update MiniMax banner to M3 release

- Replace minimax-en.jpeg and minimax-zh.jpeg with new M3 PNG banners
- Update MiniMax description in both READMEs to reflect M3 benchmarks
  (SWE-Bench Pro 59.0, Terminal Bench 2.1 66.0, VIBE V2 60.1, etc.)
- Update tagline: "Build, Learn & Ship" / "Mini 价格 Max 性能"

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore: update MiniMax model to M3 in provider presets

- Switch primary model from MiniMax-M2.7 to MiniMax-M3
- Add MiniMax-M3-highspeed variant
- Keep M2.7 as fallback for compatibility
- Update descriptions to reflect M3 features (Sparse Attention, Multimodal)
- Bump updated_at to 2026-06-03

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(core): /stop preserves AgentSessionID so next message can resume (#1196)

`cmdStop` no longer clears `AgentSessionID`; the next message can `--resume` the
conversation, matching the card-button Stop path and eliminating the
inconsistency described in #1189.

- Session-ID write-back now always follows the live forked ID Claude reports on
  every `--resume` (was: skip if already set); name binding still fires only on
  first assignment to avoid polluting `sessionNames`
- Removed `clearStaleSessionID` helper and `CompareAndSetAgentSessionID` guard;
  replaced with unconditional `SetAgentSessionID` + `wasEmpty` name-binding gate
- Updated / renamed affected tests:
  - TestSessionIDWriteback_TracksLiveForkedID
  - TestInteractiveWriteBack_TracksForkedSessionID
  - TestInteractiveWriteBack_NamingBindsOnlyOnFirstAssignment
  - TestCmdStop_PreservesAgentSessionID

Closes #1189

* fix: three bug fixes — WPS ChannelKey, Telegram text_link, workspace bind path

fix(wps-xiezuo): set ChannelKey on inbound messages for per-group session
isolation (#1217). Without ChannelKey, messages from different WPS groups
were routed to the same session.

fix(telegram): forward text_link entity URLs to agent as [label](url) (#1207).
Telegram passes inline hyperlinks as entities (not in the plain text), so the
agent never saw the URL. enrichTextLinks() rewrites text_link spans in-place
using UTF-16 offsets (Telegram's coordinate system).

fix(core): splitCommandArgs() respects quoted paths in /workspace bind (#1211).
strings.Fields splits on every space, truncating paths like
'/workspace bind "/my project/foo"'. The new parser honours single and
double quotes so space-containing paths work correctly.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(pi): correct agent directory paths (SkillDirs + GlobalMemoryFile) (#1206)

* fix(pi): correct SkillDirs paths for pi agent skill discovery

cc-connect's pi agent reported wrong skill directories (~/.pi/skills/
instead of ~/.pi/agent/skills/), causing SkillRegistry to never find
pi skills. This meant slash commands like /caveman were not intercepted
by cc-connect's command routing — they fell through to pi's print mode
as raw text, and the LLM never received the skill instructions.

Fix:
- ~/.pi/skills/ -> ~/.pi/agent/skills/ (pi's default agent dir)
- Add ~/.agents/skills/ (common shared skill dir)
- Add /skills/ if env var is set

* fix(pi): correct GlobalMemoryFile path

pi loads global AGENTS.md from getAgentDir() which defaults to
~/.pi/agent/, not ~/.pi/. Respect  if set.

* chore(pi): consistent homeDir variable naming in SkillDirs

* fix(pi): add SetWorkDir to enable /dir command (#1177)

pi agent implemented GetWorkDir() but not SetWorkDir(), so the
WorkDirSwitcher interface was incomplete and /dir always returned
'current agent does not support dynamic work directory switching'.

* fix(pi): pipe prompt via stdin to avoid CLI option parsing (#1185)

Reply chain headers start with "---", which pi's CLI parser
interprets as an option flag, producing "Unknown option" errors.
Pass the prompt via stdin instead of as a positional argument,
consistent with how gemini and codex agents handle it.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>

* fix(pi): read enabledModels from settings.json for /model (#1178)

* fix(pi): read enabledModels from settings.json for /model

AvailableModels() now reads ~/.pi/agent/settings.json enabledModels
instead of returning nil. New() also falls back to defaultModel
from settings when opts don't specify model.

Add helpers: piSettingsDir, settingsPath, readSettings,
readSettingsModels, readDefaultModel. Respects PI_CODING_AGENT_DIR.

* fix(pi): check err return values in tests to pass errcheck linter

* fix(pi): silence errcheck for os.Setenv/Unsetenv in defer cleanup blocks

* feat(dingtalk): add reaction emoji support (#1213)

* feat(dingtalk): add reaction emoji support

* fix(dingtalk): satisfy emotion lint

* feat(slack,tmux): per-thread session scope and per-session tmux windows (#1179)

Add `session_scope` to the Slack platform ("user" | "channel" | "thread").
"thread" keys each Slack thread to its own cc-connect session, so a new
top-level message starts a fresh conversation while replies in the same
thread continue it. Backward compatible: when unset, behaviour is
unchanged (share_session_in_channel maps to "channel").

Add `window_per_session` to the tmux agent: each cc-connect session gets
its own tmux window (and its own init_command/agent instance) instead of
sharing one pane. Required for real isolation when the platform splits
sessions per thread; otherwise concurrent threads interleave into a single
shared agent. The allocated window name doubles as the agent session ID so
resumes reuse the same window.

Both options default off. Includes unit tests and config.example.toml docs.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* Reply to unauthorized IM senders (#1190)

* feat(relay): configure group visibility (#1209)

* feat(send): 支持 --at-users / --at-all 命令行参数,DingTalk @mention 通知 (#1188)

* feat(send): add --at-users and --at-all support for DingTalk @mention

- Add --at-users and --at-all flags to cc-connect send command
- Add AtMentionSender optional interface for platforms that support @mention
- Implement ReplyWithAt in DingTalk platform using text msgtype
- Add CheckLinger stub for macOS compatibility

* fix: update test callers for SendToSessionWithAttachments new signature

* feat(send): add --at-users and --at-all support for DingTalk @mention

- Add --at-users and --at-all flags to cc-connect send command
- Add AtMentionSender optional interface for platforms that support @mention
- Implement ReplyWithAt in DingTalk platform using text msgtype
- Add CheckLinger stub for macOS compatibility
- Update all test callers for new signature

* fix(dingtalk): check resp.Body.Close return value for errcheck

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: wen_guoxing <wen_guoxing@itrus.com.cn>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>

* feat(cron): align manual trigger command with exec (#1201)

* feat: add manual cron run support

* feat(cron): align manual trigger command with exec

* fix(cron): guard shell manual triggers

* test(cron): accept manual run output before trigger ack

* test(release): align footer expectations without markdown italics

* fix(core): keep full reply footer paths

* test(core): normalize local dir path expectation

* fix(cron): check exec response body close

---------

Co-authored-by: aoko <aokodesuka@gmail.com>
Co-authored-by: 张彧 <aaron@mac.tail449498.ts.net>
Co-authored-by: 张彧 <aaron@Aaron-MacBook-Pro-14.local>

* feat(codex): support request_user_input app-server events (#1200)

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(feishu): refresh rich card rendering and panel handling (#1204)

Squash merge of PR #1204 (rebased onto main, minor conflicts resolved).
Adds structured per-turn reply footer, cardkit-v1 streaming, status footer
interface, claude context usage tracking, and rich card body improvements.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(feishu): send audio and video attachments as media (#1202)

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(opencode): pass --agent flag when agent config option is set (#1210)

Adds optional 'agent' config option under [projects.agent.options] for
opencode. When set, the value is passed as --agent to every 'opencode run'
invocation, enabling plugin-defined agents (e.g. oh-my-openagent's
'Sisyphus - Ultraworker') to work correctly without falling back to the
default agent.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(core): remove leftover conflict markers in engine_test.go from #1202 merge

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: three bug fixes for #1184, #1139, and #1176

fix(core): multiSelect AskUserQuestion on card platforms (closes #1184)
- For multiSelect questions, render options as a numbered text list
  instead of instant-resolve buttons (buttons resolved on first click,
  preventing multi-selection)
- Add new i18n key MsgAskQuestionNoteMulti with per-language hint to
  reply with comma-separated numbers (e.g. 1,3)
- Single-select questions keep the existing button UX unchanged

fix(config): allow cc-connect web with agent-only config (closes #1139)
- Add LoadPermissive() / validatePermissive() that skip the
  "at least one platform" requirement
- runWeb now uses LoadPermissive so the web admin UI starts even
  before any platforms are configured, enabling first-time setup

fix(weixin): fail fast on ret=-2 when context_token cannot be refreshed (closes #1176)
- When sendMessage returns ret=-2 and the stored token is the same as
  the current one (no inbound message has refreshed it), stop retrying
  immediately instead of burning 3 retries on the same stale token
- Return a clear actionable error: "user must send a new message to
  refresh the session token"
- Applied to both text (weixin.go) and media (media_outbound.go) paths

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(matrix): support MATRIX_CROSS_SIGNING_PASSWORD env var and document crypto DB paths

- Add environment variable fallback for cross_signing_password (env var
  takes precedence over config file, avoiding plaintext password in config)
- Document E2EE crypto data storage location (~/.cc-connect/) and file
  purpose (crypto DB + cross-signing seeds) in both English and Chinese
  setup guides
- Add data directory comment in config.example.toml

Addresses P3 items from PR #834 review.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: m3 <Marvae@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: 7a3lv7 <hjkl931031@gmail.com>
Co-authored-by: JazzuLu <27945372+JazzuLu@users.noreply.github.com>
Co-authored-by: shellus <353358601@qq.com>
Co-authored-by: Han <hanzr.nju@outlook.com>
Co-authored-by: Marco <48539922+MMMarcinho@users.noreply.github.com>
Co-authored-by: masakasu <32926719+MASAKASUNO1@users.noreply.github.com>
Co-authored-by: Rael <realraelmail@gmail.com>
Co-authored-by: Yu Zhang <34849476+AaronZ345@users.noreply.github.com>
Co-authored-by: wgx521 <wgx521@139.com>
Co-authored-by: wen_guoxing <wen_guoxing@itrus.com.cn>
Co-authored-by: aoko <aokodesuka@gmail.com>
Co-authored-by: 张彧 <aaron@mac.tail449498.ts.net>
Co-authored-by: 张彧 <aaron@Aaron-MacBook-Pro-14.local>
2026-06-16 09:54:55 +08:00

836 lines
26 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# cc-connect Installation & Configuration Guide
> **This document is designed to be read by AI coding agents (Claude Code, Cursor, Gemini CLI, etc.) to help users install and configure cc-connect.** You can feed this file directly to your AI agent.
## What is cc-connect?
cc-connect bridges local AI coding assistants to messaging platforms (Feishu, DingTalk, Telegram, Slack, Discord, LINE, WeChat Work, QQ, **personal WeChat** via the **Weixin (ilink)** platform).
GitHub: https://github.com/chenhg5/cc-connect
**IMPORTANT: If you are an AI agent helping a user install cc-connect, use interactive tools (like AskUserQuestion) to guide them through configuration choices:**
- Agent selection (Claude Code, Cursor, Gemini, etc.)
- Platform selection (Feishu, Telegram, Discord, etc.)
- API keys and authentication tokens
- Project paths and preferences
Don't guess values—always ask the user to choose via interactive prompts.
## Step 1: Install cc-connect
### Option A: npm (recommended for most users)
```bash
npm install -g cc-connect
```
After installation, the `cc-connect` binary will be available globally.
### Option B: Homebrew (macOS / Linux)
```bash
brew install cc-connect
```
### Option C: Download binary from GitHub Releases
Go to https://github.com/chenhg5/cc-connect/releases and download the binary for your platform.
Typical artifact names (check the release page for exact filenames):
- Linux: `cc-connect-<version>-linux-amd64` (or `.tar.gz`)
- macOS: `cc-connect-<version>-darwin-amd64` / `arm64`
- Windows: `cc-connect-<version>-windows-amd64.exe` (or `.zip`)
```bash
# Example for Linux amd64 (replace URL with the asset link from the release you chose):
curl -L -o cc-connect https://github.com/chenhg5/cc-connect/releases/latest/download/cc-connect-linux-amd64
chmod +x cc-connect
sudo mv cc-connect /usr/local/bin/
```
On macOS, you may need to remove the quarantine attribute:
```bash
xattr -d com.apple.quarantine cc-connect
```
### Option D: Build from source
Requires Go 1.22+.
```bash
git clone https://github.com/chenhg5/cc-connect.git
cd cc-connect
make build
# Binary will be at ./cc-connect
```
## Step 2: Install your AI Agent
cc-connect supports multiple local coding agents. Install at least one:
```bash
# Claude Code
npm install -g @anthropic-ai/claude-code
# Codex
npm install -g @openai/codex
# Gemini CLI
npm install -g @google/gemini-cli
# iFlow CLI
npm install -g @iflow-ai/iflow-cli
# Qoder CLI
curl -fsSL https://qoder.com/install | bash
```
For **Cursor Agent** and **OpenCode**, follow their official install docs:
- Cursor Agent: https://docs.cursor.com/agent
- OpenCode: https://github.com/opencode-ai/opencode
Verify your selected agent works:
```bash
claude --version
codex --version
gemini --version
iflow --version
opencode --version
qodercli --version
```
## Step 3: Create config.toml
> **💡 Recommended: Use the Web UI** — After installing, run `cc-connect web` to configure the web admin and open the dashboard in your browser. You can visually create projects, add platforms, manage API providers, and even chat with your agent directly from the browser — no need to edit TOML files by hand. **Note:** `cc-connect web` only configures and opens the browser — you still need to run `cc-connect` separately to start the service.
If you prefer manual configuration, cc-connect looks for config in this order:
1. `-config <path>` flag (explicit)
2. `./config.toml` (current directory)
3. `~/.cc-connect/config.toml` (global, **recommended**)
If no config file exists, running `cc-connect` will auto-create a starter template at `~/.cc-connect/config.toml`.
**Manual config location:**
```bash
mkdir -p ~/.cc-connect
# If you cloned the repo, copy the example:
cp config.example.toml ~/.cc-connect/config.toml
# Or just run cc-connect once — it will create a starter config automatically
```
You can also use a local config in the current directory:
```bash
cp config.example.toml config.toml
```
The configuration has this structure:
```toml
# Optional global settings
# language = "en" # "en", "zh", or "" (auto-detect)
[log]
level = "info" # debug, info, warn, error
# Each [[projects]] entry connects one code folder to one or more messaging platforms
[[projects]]
name = "my-project"
[projects.agent]
type = "claudecode" # or "codex", "cursor", "gemini", "qoder", "opencode", "iflow"
[projects.agent.options]
work_dir = "/absolute/path/to/your/project"
mode = "default"
# --- Claude Code mode options ---
# "default", "acceptEdits" (alias: "edit"), "plan", "auto", "bypassPermissions" (alias: "yolo")
# allowed_tools = ["Read", "Grep", "Glob"] # optional: pre-approve specific tools
# --- Codex mode options ---
# "suggest" (default), "auto-edit", "full-auto", "yolo"
# model = "o3" # optional: specify model
# --- Qoder CLI mode options ---
# "default", "yolo"
# model = "auto" # "auto", "ultimate", "performance", "efficient", "lite"
# --- iFlow CLI mode options ---
# "default", "auto-edit", "plan", "yolo"
# model = "Qwen3-Coder" # optional: specify model
# Add one or more platform sections below
```
## Step 4: Configure a Messaging Platform
Choose one or more platforms to connect. Each platform requires creating a bot/app on the platform's developer console and copying credentials into config.toml.
---
### Feishu (Lark) — No public IP needed
Connection: WebSocket long connection (SDK auto-negotiates)
**CLI shortcut (recommended):**
```bash
# Recommended: unified entry
cc-connect feishu setup --project my-project
cc-connect feishu setup --project my-project --app cli_xxx:sec_xxx
# Force modes (usually unnecessary)
cc-connect feishu new --project my-project
cc-connect feishu bind --project my-project --app cli_xxx:sec_xxx
```
Notes:
- `setup` is the unified entry:
- no credentials => same as `new`
- with `--app`/`--app-id` => same as `bind`
- `setup/new` prints a terminal QR code + URL for mobile scanning.
- If `--project` does not exist, cc-connect creates it automatically.
- This flow fills `app_id` / `app_secret`; in QR onboarding flow, Feishu usually pre-configures permissions and event subscriptions.
- Still verify app publish status and availability scope in Feishu Open Platform.
**Setup steps:**
1. Go to https://open.feishu.cn → Console → Create Enterprise App
2. Enable **Bot** capability (App Capabilities → Bot)
3. Go to **Permissions** → add `im:message.receive_v1`, `im:message:send_as_bot`
4. Go to **Event Subscriptions** → select **WebSocket long connection mode** → add event `im.message.receive_v1`
5. Publish the app version
6. Copy App ID and App Secret
**Config:**
```toml
[[projects.platforms]]
type = "feishu"
[projects.platforms.options]
app_id = "cli_xxxxxxxxxxxx"
app_secret = "xxxxxxxxxxxxxxxxxxxxxxxx"
```
**Detailed guide:** [docs/feishu.md](docs/feishu.md)
---
### DingTalk — No public IP needed
Connection: Stream mode (WebSocket)
**Setup steps:**
1. Go to https://open-dev.dingtalk.com → Create App
2. Enable **Bot** capability, select **Stream mode**
3. Configure permissions for messaging
4. Copy Client ID (AppKey) and Client Secret (AppSecret)
**Config:**
```toml
[[projects.platforms]]
type = "dingtalk"
[projects.platforms.options]
client_id = "dingxxxxxxxxxxxxxxxxx"
client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```
**Detailed guide:** [docs/dingtalk.md](docs/dingtalk.md)
---
### Telegram — No public IP needed
Connection: Long Polling
**Setup steps:**
1. Message @BotFather on Telegram → send `/newbot`
2. Follow prompts to set bot name and username (must end with `bot`)
3. Copy the bot token
**Config:**
```toml
[[projects.platforms]]
type = "telegram"
[projects.platforms.options]
token = "1234567890:ABCdefGHIjklMNOpqrsTUVwxyz"
```
**Detailed guide:** [docs/telegram.md](docs/telegram.md)
---
### Slack — No public IP needed
Connection: Socket Mode (WebSocket)
**Setup steps:**
1. Go to https://api.slack.com/apps → Create New App → From scratch
2. Enable **Socket Mode** (Settings → Socket Mode) → generate App-Level Token (`xapp-...`)
3. Subscribe to bot events: `message.im`, `app_mention` (Event Subscriptions)
4. Add Bot Token Scopes: `chat:write`, `im:history`, `im:read`, `im:write`, `app_mentions:read`
5. Install App to Workspace → copy Bot Token (`xoxb-...`)
**Config:**
```toml
[[projects.platforms]]
type = "slack"
[projects.platforms.options]
bot_token = "xoxb-your-bot-token"
app_token = "xapp-your-app-level-token"
```
**Detailed guide:** [docs/slack.md](docs/slack.md)
---
### Discord — No public IP needed
Connection: Gateway WebSocket
**Setup steps:**
1. Go to https://discord.com/developers/applications → New Application
2. Go to **Bot** → Add Bot → copy Token
3. Enable **Message Content Intent** (under Privileged Gateway Intents)
4. Go to **OAuth2** → URL Generator → select scope `bot` → select permissions `Send Messages`, `Read Message History`
5. Open the generated URL to invite bot to your server
**Config:**
```toml
[[projects.platforms]]
type = "discord"
[projects.platforms.options]
token = "your-discord-bot-token"
```
**Detailed guide:** [docs/discord.md](docs/discord.md)
---
### LINE — Requires public URL
Connection: HTTP Webhook (you need ngrok, cloudflared, or a server with public IP)
**Setup steps:**
1. Go to https://developers.line.biz/console/ → Create Messaging API channel
2. Copy Channel Secret and Channel Access Token (long-lived)
3. Set webhook URL in LINE console: `https://<your-public-domain>:<port>/callback`
4. Expose local port using ngrok/cloudflared: `ngrok http 8080` or `cloudflared tunnel --url http://localhost:8080`
**Config:**
```toml
[[projects.platforms]]
type = "line"
[projects.platforms.options]
channel_secret = "your-channel-secret"
channel_token = "your-channel-access-token"
port = "8080"
callback_path = "/callback"
```
---
### WeChat Work (企业微信) — Requires public URL
Connection: HTTP Webhook (you need ngrok, cloudflared, or a server with public IP)
**Setup steps:**
1. Log in to https://work.weixin.qq.com/wework_admin/frame
2. **App Management** → Create custom app → note AgentId and Secret
3. **My Enterprise** → note Corp ID
4. In the app → **Receive Messages** → Set API Receive:
- URL: `https://<your-public-domain>:<port>/wecom/callback`
- Token: any random string
- EncodingAESKey: click "Random Generate" (43 chars)
- **Start cc-connect FIRST, then save** (to pass URL verification)
5. **Trusted IP** → add your server's outbound public IP
6. (Optional) **WeChat Plugin** → scan QR to link personal WeChat
**Config:**
```toml
[[projects.platforms]]
type = "wecom"
[projects.platforms.options]
corp_id = "wwxxxxxxxxxxxxxxxxx"
corp_secret = "your-app-secret"
agent_id = "1000002"
callback_token = "your-callback-token"
callback_aes_key = "your-43-char-encoding-aes-key"
port = "8081"
callback_path = "/wecom/callback"
api_base_url = "https://qyapi.weixin.qq.com" # optional: override WeChat Work API base URL (for private deployments)
enable_markdown = false # true = Markdown messages (WeChat Work app only; personal WeChat shows "unsupported")
# proxy = "http://your-vps-ip:8888" # optional: forward proxy if your IP is dynamic
```
**Detailed guide:** [docs/wecom.md](docs/wecom.md)
### Weixin (personal, ilink) — No public IP needed
Personal WeChat uses Tencents **ilink bot HTTP API** (same family as OpenClaw `openclaw-weixin`). The recommended flow is CLI QR login, which writes `token` (and related fields) into `config.toml`.
1. Run:
```bash
cc-connect weixin setup --project my-project
```
2. Scan the QR code (or open the printed URL) in WeChat and confirm.
3. Restart cc-connect, then send a message from WeChat once so `context_token` is cached.
If you already have a Bearer token, use `cc-connect weixin bind --project my-project --token '<token>'`.
**Detailed guide (Chinese):** [docs/weixin.md](docs/weixin.md)
### QQ (via NapCat / OneBot v11) — No public IP needed
QQ integration requires a third-party OneBot v11 implementation (e.g., NapCat) as a bridge.
1. Deploy NapCat (recommended via Docker):
```bash
docker run -d --name napcat -e ACCOUNT=<QQ号> -p 3001:3001 -p 6099:6099 --restart unless-stopped mlikiowa/napcat-docker:latest
```
2. First launch: check `docker logs -f napcat` for a QR code, scan with QQ mobile app to log in
3. Open NapCat WebUI at `http://localhost:6099`, enable **Forward WebSocket** on port 3001
4. Add to `config.toml`:
```toml
[[projects.platforms]]
type = "qq"
[projects.platforms.options]
ws_url = "ws://127.0.0.1:3001" # NapCat Forward WebSocket URL
token = "" # optional: access_token (must match NapCat config)
allow_from = "*" # allowed QQ user IDs: "12345,67890" or "*" for all
```
**Detailed guide:** [docs/qq.md](docs/qq.md)
---
### Matrix — No public IP needed
Connection: Long Polling via /sync
**Setup steps:**
1. Create an account on a Matrix homeserver (e.g. [matrix.org](https://matrix.org), or your own self-hosted server)
2. Get an access token:
- Open **Element** (or your preferred Matrix client)
- Go to **Settings** → **Help & About** → **Advanced** → click **Access Token**
- Copy the token (it starts with `syt_` on most servers)
3. (Optional) Note your user ID (e.g. `@bot:matrix.org`)
**Config:**
```toml
[[projects.platforms]]
type = "matrix"
[projects.platforms.options]
homeserver = "https://matrix.org"
access_token = "syt_xxx_xxx"
# user_id = "@bot:matrix.org" # optional, auto-detected
# allow_from = "*"
# auto_join = true # default true
# share_session_in_channel = false
# group_reply_all = false
# proxy = ""
```
**Detailed guide:** [docs/matrix.md](docs/matrix.md)
---
## Step 5: Run cc-connect
**Open the Web UI (recommended):**
```bash
cc-connect web # configure web admin & open browser (does NOT start cc-connect)
cc-connect # start the service
```
> **Note:** `cc-connect web` only configures the web admin and opens the dashboard in your browser — it does **not** start the cc-connect service itself. You still need to run `cc-connect` (or `cc-connect --config <path>`) separately to actually start the bridge. Think of it as two steps: configure first, then run.
**Important: If you are running inside a Claude Code session** (e.g., Claude Code helped you install and configure cc-connect), you must unset the `CLAUDECODE` environment variable before starting, otherwise Claude Code will refuse to launch as a subprocess:
```bash
unset CLAUDECODE && cc-connect
```
Alternatively, open a **separate terminal** and run cc-connect there — this avoids the issue entirely.
**Normal startup:**
```bash
# Run with config.toml in current directory
cc-connect
# Or specify config path
cc-connect -config /path/to/config.toml
# Check version
cc-connect --version
```
You should see logs like:
```
level=INFO msg="platform started" project=my-project platform=feishu
level=INFO msg="engine started" project=my-project agent=claudecode platforms=1
level=INFO msg="cc-connect is running" projects=1
```
## Step 6: Chat Commands
Once running, send messages to your bot on the configured platform. Available slash commands:
```
/new [name] — Start a new session
/list — List agent sessions
/switch <id> — Resume an existing session
/current — Show current active session
/history [n] — Show last n messages (default 10)
/reasoning [level] — View/switch reasoning effort (Codex)
/mode [name] — View/switch permission mode (default/edit/plan/yolo)
/quiet — Toggle thinking/tool progress messages
/allow <tool> — Pre-allow a tool (next session)
/provider [...] — Manage API providers (list/add/remove/switch)
/stop — Stop current execution
/help — Show available commands
```
During a session, Claude may ask for tool permissions. Reply:
- `allow` or `允许` — approve this request
- `deny` or `拒绝` — reject this request
- `allow all` or `允许所有` — auto-approve all remaining requests this session
## Step 7: Enable Natural Language Scheduling (Non-Claude-Code Agents)
cc-connect supports scheduled tasks (cron jobs). You can always create them via slash commands (`/cron add ...`) or CLI (`cc-connect cron add ...`), but to let the agent **understand natural language** like "every day at 6am, summarize trending repos", the agent needs to know about cc-connect's cron CLI.
**Claude Code** handles this automatically via `--append-system-prompt` — no extra setup needed.
**For Codex, Cursor Agent, Qoder CLI, Gemini CLI, OpenCode, or iFlow CLI**, add the following instructions to the agent's project-level instruction file in your project's `work_dir`:
| Agent | File to create/edit |
|-------|-------------------|
| Codex | `AGENTS.md` |
| Cursor Agent | `.cursorrules` |
| Qoder CLI | `AGENTS.md` |
| Gemini CLI | `GEMINI.md` |
| OpenCode | `OPENCODE.md` |
| iFlow CLI | `IFLOW.md` |
**Content to add** (copy-paste into the file):
```markdown
# cc-connect Integration
This project is managed via cc-connect, a bridge to messaging platforms.
## Scheduled tasks (cron)
When the user asks you to do something on a schedule (e.g. "every day at 6am",
"every Monday morning"), use the Bash/shell tool to run:
cc-connect cron add --cron "<min> <hour> <day> <month> <weekday>" --prompt "<task description>" --desc "<short label>"
Environment variables CC_PROJECT and CC_SESSION_KEY are already set — do NOT
specify --project or --session-key.
Examples:
cc-connect cron add --cron "0 6 * * *" --prompt "Collect GitHub trending repos and send a summary" --desc "Daily GitHub Trending"
cc-connect cron add --cron "0 9 * * 1" --prompt "Generate a weekly project status report" --desc "Weekly Report"
To list, run, edit, or delete cron jobs:
cc-connect cron list
cc-connect cron exec <job-id>
cc-connect cron edit <job-id> <field> <value>
cc-connect cron del <job-id>
Use `cron exec <job-id>` to run an existing scheduled task immediately; this is different from the `--exec <command>` flag used when creating a shell-command cron job.
Use `cron edit` to modify a single field instead of delete-and-recreate.
Common editable fields: cron_expr, prompt, exec, description, enabled (true/false), mute (true/false), timeout_mins (int).
Run `cc-connect cron edit --help` for the full field list.
Examples:
cc-connect cron exec abc123
cc-connect cron edit abc123 cron_expr "0 9 * * *"
cc-connect cron edit abc123 enabled false
cc-connect cron edit abc123 prompt "Updated daily summary task"
## Send message to current chat
To proactively send a message back to the user's chat session (use --stdin heredoc for long/multi-line messages):
cc-connect send --stdin <<'CCEOF'
your message here (any special characters are safe)
CCEOF
For short single-line messages:
cc-connect send -m "short message"
```
After adding this file, the agent will be able to translate natural language scheduling requests into `cc-connect cron add` commands automatically.
> **Tip:** You may want to add `AGENTS.md` / `.cursorrules` / `GEMINI.md` to your `.gitignore` if you don't want cc-connect instructions committed to version control.
## Multi-Project Setup
A single cc-connect process can manage multiple projects. Each project has its own agent, work directory, and platforms:
```toml
[[projects]]
name = "backend"
[projects.agent]
type = "claudecode"
[projects.agent.options]
work_dir = "/path/to/backend"
mode = "default"
[[projects.platforms]]
type = "feishu"
[projects.platforms.options]
app_id = "cli_xxx"
app_secret = "xxx"
# Second project — using Codex
[[projects]]
name = "frontend"
[projects.agent]
type = "codex"
[projects.agent.options]
work_dir = "/path/to/frontend"
mode = "full-auto"
[[projects.platforms]]
type = "telegram"
[projects.platforms.options]
token = "xxx"
# Third project — using Cursor Agent
[[projects]]
name = "design-system"
[projects.agent]
type = "cursor"
[projects.agent.options]
work_dir = "/path/to/design-system"
mode = "force"
[[projects.platforms]]
type = "discord"
[projects.platforms.options]
token = "xxx"
# Fourth project — using Gemini CLI
[[projects]]
name = "my-gemini-project"
[projects.agent]
type = "gemini"
[projects.agent.options]
work_dir = "/path/to/gemini-project"
mode = "yolo" # "default" | "auto_edit" | "yolo" | "plan"
[[projects.platforms]]
type = "slack"
[projects.platforms.options]
bot_token = "xoxb-xxx"
app_token = "xapp-xxx"
# Fifth project — using Qoder CLI
[[projects]]
name = "my-qoder-project"
[projects.agent]
type = "qoder"
[projects.agent.options]
work_dir = "/path/to/qoder-project"
mode = "default" # "default" | "yolo"
# model = "auto" # "auto" | "ultimate" | "performance" | "efficient" | "lite"
[[projects.platforms]]
type = "telegram"
[projects.platforms.options]
token = "xxx"
# Sixth project — using iFlow CLI
[[projects]]
name = "my-iflow-project"
[projects.agent]
type = "iflow"
[projects.agent.options]
work_dir = "/path/to/iflow-project"
mode = "default" # "default" | "auto-edit" | "plan" | "yolo"
# model = "Qwen3-Coder"
[[projects.platforms]]
type = "slack"
[projects.platforms.options]
bot_token = "xoxb-xxx"
app_token = "xapp-xxx"
```
## Upgrade
### Check current version
```bash
cc-connect --version
```
### npm users
```bash
npm update -g cc-connect
```
### Binary users
Check the latest release at https://github.com/chenhg5/cc-connect/releases and compare with your local version. To upgrade:
```bash
# Linux/macOS — replace with your platform suffix
curl -L -o /usr/local/bin/cc-connect https://github.com/chenhg5/cc-connect/releases/latest/download/cc-connect-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')
chmod +x /usr/local/bin/cc-connect
```
### Source users
```bash
cd cc-connect
git pull
make build
```
After upgrading, restart the running cc-connect process.
## Step 8: Run as Background Service (Optional)
You can run cc-connect as a daemon managed by the OS init system (Linux systemd user service, macOS launchd LaunchAgent, Windows Task Scheduler task).
### Install the daemon
```bash
cc-connect daemon install --config ~/.cc-connect/config.toml
```
You can also point the daemon at the directory that contains `config.toml`:
```bash
cc-connect daemon install --work-dir ~/.cc-connect
```
Optional flags: `--config PATH`, `--log-file PATH`, `--log-max-size N` (MB), `--work-dir DIR`, `--force` (overwrite existing unit). `--config` points to a config file, while `--work-dir` points to the directory containing `config.toml`.
### Linux systemd: Keep service running after SSH disconnect
When installed as a user-level systemd service (non-root), cc-connect runs under `user@UID.service`. By default, systemd stops this service when your last login session ends (e.g., SSH disconnect). This is controlled by the "linger" setting.
To keep cc-connect running persistently, enable linger for your user:
```bash
sudo loginctl enable-linger $USER
```
After enabling linger, `user@UID.service` remains active even when you log out. The daemon install command will warn you if linger is not enabled.
Alternatively, you can install as a system-level service (requires root):
```bash
sudo cc-connect daemon install --config ~/.cc-connect/config.toml
```
System-level services are independent of login sessions.
### Control the service
```bash
cc-connect daemon start
cc-connect daemon stop
cc-connect daemon restart
cc-connect daemon status
```
### View logs
```bash
cc-connect daemon logs # tail current log
cc-connect daemon logs -f # follow (like tail -f)
cc-connect daemon logs -n 100 # last 100 lines
cc-connect daemon logs --log-file /path/to/log # custom log file
```
Logs auto-rotate at the configured max size and keep one backup.
On Windows, `daemon install` creates a native Task Scheduler task named `cc-connect`.
The task runs at user logon and is also started immediately after installation. The
installer writes a small PowerShell launcher under `~/.cc-connect` so the scheduled
task uses the selected config directory, log file, PATH, and proxy environment.
### Uninstall
```bash
cc-connect daemon uninstall
```
## Additional Features
The following additional features are available:
- **Codex Agent**: OpenAI Codex CLI integration (`codex exec --json`)
- **Cursor Agent**: Cursor Agent CLI integration (`agent --print --output-format stream-json`)
- **Gemini CLI**: Google Gemini CLI integration (`gemini -p --output-format stream-json`)
- **Qoder CLI**: Qoder CLI integration (`qodercli -p -f stream-json`)
- **OpenCode**: OpenCode CLI integration (`opencode run --format json`)
- **iFlow CLI**: iFlow CLI integration (`iflow -i -r -o`)
- **Voice Messages (STT)**: Speech-to-text via Whisper API (OpenAI / Groq / SiliconFlow). Requires `ffmpeg` and `[speech]` config.
- **Voice Reply (TTS)**: Text-to-speech via Qwen / OpenAI / MiniMax / MiMo / local providers. Requires `ffmpeg` and `[tts]` config.
- **Image Messages**: Send images to Claude Code for multimodal analysis
- **API Provider Management**: Runtime switching between API providers via `/provider` command or CLI
- **CLI Send**: `cc-connect send` to inject messages into active sessions from external processes
## Troubleshooting
- **"session already in use"** — A previous Claude Code process may still be running. Use `/new` to start a fresh session.
- **No response from bot** — Check `cc-connect` logs. Set `level = "debug"` in `[log]` for verbose output.
- **WeChat Work can't send messages** — Ensure your outbound IP is in the Trusted IP whitelist. If using a proxy, check the proxy is reachable.
- **LINE/WeChat Work can't receive messages** — Ensure your webhook URL is publicly accessible (ngrok/cloudflared running).
- **macOS binary won't open** — Run `xattr -d com.apple.quarantine cc-connect` to remove quarantine flag.