初始化仓库

This commit is contained in:
2026-06-02 23:14:41 +08:00
commit 0bc3f02670
520 changed files with 191097 additions and 0 deletions
+237
View File
@@ -0,0 +1,237 @@
# CC-Connect Development Guide
## Project Overview
CC-Connect is a bridge that connects AI coding agents (Claude Code, Codex, Gemini CLI, Cursor, etc.) with messaging platforms (Feishu/Lark, Telegram, Discord, Slack, DingTalk, WeChat Work, QQ, LINE). Users interact with their coding agent through their preferred messaging app.
## Architecture
```
┌─────────────────────────────────────────────────┐
│ cmd/cc-connect │ ← entry point, CLI, daemon
├─────────────────────────────────────────────────┤
│ config/ │ ← TOML config parsing
├─────────────────────────────────────────────────┤
│ core/ │ ← engine, interfaces, i18n,
│ │ cards, sessions, registry
├──────────────────────┬──────────────────────────┤
│ agent/ │ platform/ │
│ ├── claudecode/ │ ├── feishu/ │
│ ├── codex/ │ ├── telegram/ │
│ ├── cursor/ │ ├── discord/ │
│ ├── gemini/ │ ├── slack/ │
│ ├── iflow/ │ ├── dingtalk/ │
│ ├── opencode/ │ ├── wecom/ │
│ ├── acp/ │ ├── qq/ │
│ └── qoder/ │ ├── qqbot/ │
│ │ ├── line/ │
│ │ └── weibo/ │
├──────────────────────┴──────────────────────────┤
│ daemon/ │ ← systemd/launchd service
└─────────────────────────────────────────────────┘
```
### Key Design Principles
**`core/` is the nucleus.** It defines all interfaces (`Platform`, `Agent`, `AgentSession`, etc.) and contains the `Engine` that orchestrates message flow. The core package must **never** import from `agent/` or `platform/`.
**Plugin architecture via registries.** Agents and platforms register themselves through `core.RegisterAgent()` and `core.RegisterPlatform()` in their `init()` functions. The engine creates instances via `core.CreateAgent()` / `core.CreatePlatform()` using string names from config.
**Dependency direction:**
```
cmd/ → config/, core/, agent/*, platform/*
agent/* → core/ (never other agents or platforms)
platform/* → core/ (never other platforms or agents)
core/ → stdlib only (never agent/ or platform/)
```
### Core Interfaces
- **`Platform`** — messaging platform adapter (Start, Reply, Send, Stop)
- **`Agent`** — AI coding agent adapter (StartSession, ListSessions, Stop)
- **`AgentSession`** — a running bidirectional session (Send, RespondPermission, Events)
- **`Engine`** — the central orchestrator that routes messages between platforms and agents
Optional capability interfaces (implement only when needed):
- `CardSender` — rich card messages
- `InlineButtonSender` — inline keyboard buttons
- `ProviderSwitcher` — multi-model switching
- `DoctorChecker` — agent-specific health checks
- `AgentDoctorInfo` — CLI binary metadata for diagnostics
## Development Rules
### 1. No Hardcoding Platform or Agent Names in Core
The `core/` package must remain agnostic. Never write `if p.Name() == "feishu"` or `CreateAgent("claudecode", ...)` in core. Use interfaces and capability checks instead:
```go
// BAD — hardcodes platform knowledge in core
if p.Name() == "feishu" && supportsCards(p) {
// GOOD — capability-based check
if supportsCards(p) {
```
```go
// BAD — hardcodes agent type
agent, _ := CreateAgent("claudecode", opts)
// GOOD — derives from current agent
agent, _ := CreateAgent(e.agent.Name(), opts)
```
### 2. Prefer Interfaces Over Type Switches
When behavior differs across platforms/agents, define an optional interface in core and let implementations opt in:
```go
// In core/
type AgentDoctorInfo interface {
CLIBinaryName() string
CLIDisplayName() string
}
// In agent/claudecode/
func (a *Agent) CLIBinaryName() string { return "claude" }
func (a *Agent) CLIDisplayName() string { return "Claude" }
// In core/ — query via interface, fallback gracefully
if info, ok := agent.(AgentDoctorInfo); ok {
bin = info.CLIBinaryName()
}
```
### 3. Configuration Over Code
- Features that may vary per deployment should be configurable in `config.toml`
- Use `map[string]any` options for agent/platform factories to stay flexible
- Add new config fields with sensible defaults so existing configs don't break
### 4. High Cohesion, Low Coupling
- Each `agent/X/` package is self-contained: it handles process lifecycle, output parsing, and session management for agent X
- Each `platform/X/` package is self-contained: it handles API connection, message receiving/sending, and card rendering for platform X
- Cross-cutting concerns (i18n, cards, streaming, rate limiting) live in `core/`
### 5. Error Handling
- Always wrap errors with context: `fmt.Errorf("feishu: reply card: %w", err)`
- Never silently swallow errors; at minimum log them with `slog.Error` / `slog.Warn`
- Use `slog` (structured logging) consistently; never `log.Printf` or `fmt.Printf` for runtime logs
- Redact tokens/secrets in error messages using `core.RedactToken()`
### 6. Concurrency Safety
- Agent sessions are accessed from multiple goroutines; protect shared state with `sync.Mutex` or `atomic` types
- Use `context.Context` for cancellation propagation
- Channels should have clear ownership; document who closes them
- Prefer `sync.Once` for one-time teardown (`pendingPermission.resolve()`)
### 7. i18n
All user-facing strings must go through `core/i18n.go`:
- Define a `MsgKey` constant
- Add translations for all supported languages (EN, ZH, ZH-TW, JA, ES)
- Use `e.i18n.T(MsgKey)` or `e.i18n.Tf(MsgKey, args...)`
## Code Style
- Follow standard Go conventions (`gofmt`, `go vet`)
- Use `strings.EqualFold` for case-insensitive comparisons
- Avoid `init()` for anything other than platform/agent registration
- Keep functions focused; extract helpers when a function exceeds ~80 lines
- Naming: `New()` for constructors, `Get/Set` for accessors, avoid stuttering (`feishu.FeishuPlatform``feishu.Platform`)
## Testing
### Requirements
- All new features must include unit tests
- All bug fixes should include a regression test
- Tests must pass before committing: `go test ./...`
### Running Tests
```bash
# Full test suite
go test ./...
# Specific package
go test ./core/ -v
# Run specific test
go test ./core/ -run TestHandlePendingPermission -v
# With race detector (CI)
go test -race ./...
```
### Test Patterns
- Use stub types for `Platform` and `Agent` in core tests (see `core/engine_test.go`)
- Test card rendering by inspecting the returned `*Card` struct, not JSON
- For agent session tests, simulate event streams via channels
## Selective Compilation
Each agent and platform is imported via a separate `plugin_*.go` file with a
build tag (e.g. `//go:build !no_feishu`). By default **all** agents and
platforms are compiled in.
### Include only specific agents/platforms
```bash
# Only Claude Code agent + Feishu and Telegram platforms
make build AGENTS=claudecode PLATFORMS_INCLUDE=feishu,telegram
# Multiple agents
make build AGENTS=claudecode,codex PLATFORMS_INCLUDE=feishu,telegram,discord
```
### Exclude specific agents/platforms
```bash
# Exclude some platforms you don't need
make build EXCLUDE=discord,dingtalk,qq,qqbot,line
```
### Direct build tag usage (without Make)
```bash
go build -tags 'no_discord no_dingtalk no_qq no_qqbot no_line' ./cmd/cc-connect
```
Available tags: `no_acp`, `no_claudecode`, `no_codex`, `no_copilot`, `no_cursor`, `no_gemini`,
`no_iflow`, `no_opencode`, `no_qoder`, `no_feishu`, `no_telegram`,
`no_discord`, `no_slack`, `no_dingtalk`, `no_wecom`, `no_weixin`, `no_qq`, `no_qqbot`,
`no_line`, `no_weibo`.
## Pre-Commit Checklist
1. **Build passes**: `go build ./...`
2. **Tests pass**: `go test ./...`
3. **No new hardcoded platform/agent names in core**: grep for platform names in `core/*.go`
4. **i18n complete**: all new user-facing strings have translations for all languages
5. **No secrets in code**: no API keys, tokens, or credentials in source files
## Adding a New Platform
1. Create `platform/newplatform/newplatform.go`
2. Implement `core.Platform` interface (and optional interfaces as needed)
3. Register in `init()`: `core.RegisterPlatform("newplatform", factory)`
4. Create `cmd/cc-connect/plugin_platform_newplatform.go` with `//go:build !no_newplatform` tag
5. Add `newplatform` to `ALL_PLATFORMS` in `Makefile`
6. Add config example in `config.example.toml`
7. Add unit tests
## Adding a New Agent
1. Create `agent/newagent/newagent.go`
2. Implement `core.Agent` and `core.AgentSession` interfaces
3. Register in `init()`: `core.RegisterAgent("newagent", factory)`
4. Create `cmd/cc-connect/plugin_agent_newagent.go` with `//go:build !no_newagent` tag
5. Add `newagent` to `ALL_AGENTS` in `Makefile`
6. Optionally implement `AgentDoctorInfo` for `cc-connect doctor` support
7. Add config example in `config.example.toml`
8. Add unit tests