Commit Graph
100 Commits
Author SHA1 Message Date
ClaudeandCursor dc1c63b9eb release: v1.3.3 stable
Bump VERSION to v1.3.3 and npm/package.json to 1.3.3. Stabilizes the
v1.3.3-beta.1 -> v1.3.3-beta.5 line (~235 PRs since v1.3.2) plus 7
post-beta fixes (qoder streaming, weixin typing ticket, daemon
linger_other.go, wps-xiezuo newlines, /switch history loss, minimax TTS
trailer, provider-resume regression tests).

- Add changelogs/v1.3.3.md with themed summary (New Agents, Platform
  Capabilities, Core, Behavior Changes, Fixed)
- Prepend v1.3.3 section to CHANGELOG.md with highlights + post-beta
  delta + behavior-change checklist
- Refresh "What's New" in README.md and README.zh-CN.md to v1.3.3
- Fix CUJ test flake: bump TestCUJ_H2_TwoPlatformsConcurrentNoBleed
  deadline from 5s to 30s so it stays green under `-race -parallel=N`
  on constrained CI hosts (passes <2s in isolation)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-15 23:02:36 +08:00
ClaudeandCursor e44012c723 docs(readme): refresh "What's New" to v1.3.3-beta.5
The What's New section was still pinned to v1.3.0 — out of date by
beta.1 through beta.4. Update both README.md and README.zh-CN.md to
highlight v1.3.3-beta.5: new agents (Antigravity, Copilot), native
file attachments (QQ, WeCom, Feishu media), /timer, /cancel,
agent-driven TTS, plus the three user-visible behavior notes.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-15 13:45:26 +08:00
ClaudeandCursor 411687b675 fix(daemon): remove duplicate CheckLinger stub blocking non-linux build
PR #1034 (c53f5450) re-introduced daemon/linger_other.go with
`//go:build !linux`, which overlaps every per-platform stub:
- launchd.go (darwin)
- windows.go (windows)
- unsupported.go (other)

This causes `CheckLinger redeclared in this block` and breaks
`make release-all` on every non-Linux GOOS target.

Per-platform stubs already cover all four cases:
- linux   → daemon/systemd.go
- darwin  → daemon/launchd.go
- windows → daemon/windows.go
- other   → daemon/unsupported.go

Delete the redundant `!linux` stub. Same fix as the never-merged
PR #1311; no runtime behavior change.

Verified:
- GOOS=linux   go build ./daemon/... → ok
- GOOS=darwin  go build ./daemon/... → ok
- GOOS=windows go build ./daemon/... → ok
- GOOS=freebsd go build ./daemon/... → ok

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-15 10:34:17 +08:00
ClaudeandCursor b48781c0ad build: release v1.3.3-beta.5 — new agents, file attachments, /timer, /cancel, broad platform fixes
74 PRs from 28 contributors since v1.3.3-beta.4.

New agents:
- Google Antigravity (agy) (#1123)
- GitHub Copilot (#865)

New platform capabilities:
- QQ file send/receive via OneBot HTTP API (#323)
- WeCom SendFile in WebSocket mode (#1199)
- Feishu audio/video attachments as media (#1202)
- DingTalk reaction emoji (#1213)
- QQ Bot inline keyboards + INTERACTION_CREATE (#1131)

Core features: /timer, /cancel, session prune, agent-driven TTS, configurable shell.

Behavior notes: Telegram/Discord progress_style default = compact; DingTalk msgtype=file
now reaches the agent; engine permission keyword matching is @mention-tolerant.

See changelogs/v1.3.3-beta.5.md for the full list.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-15 10:29:46 +08:00
ClaudeandCursor eb86866420 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>
2026-06-04 17:01:01 +08:00
ClaudeandCursor 92add53514 fix(core): remove leftover conflict markers in engine_test.go from #1202 merge
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-04 16:48:59 +08:00
ClaudeandCursor f86c26634b 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>
2026-06-04 10:17:34 +08:00
ClaudeandCursor 6f4e5f6bba feat(feishu): send audio and video attachments as media (#1202)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-04 10:07:34 +08:00
ClaudeandCursor 410d46e5bf 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>
2026-06-04 10:05:17 +08:00
ClaudeandCursor 1fdb01088f feat(codex): support request_user_input app-server events (#1200)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-04 09:56:24 +08:00
ClaudeandCursor 315c300439 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>
2026-06-04 09:43:08 +08:00
Claude b028e72ef9 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>
2026-06-03 09:31:50 +08:00
Claude c4e5595e04 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>
2026-06-03 09:30:56 +08:00
ClaudeandCursor 39df0842e7 feat: integrate Google Antigravity CLI (agy) agent (#1123)
Resolves Makefile conflict with #865 (copilot): both antigravity and copilot now included in ALL_AGENTS.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 10:23:22 +08:00
ClaudeandCursor fa993f9eae chore: ignore web/tsconfig.tsbuildinfo (TS incremental build cache)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 10:14:46 +08:00
ClaudeandCursor 21a740ec9d fix(feishu): forward link href and card button URLs to agent (#1154)
- extractPostPlainText / extractPostParts: format `a` elements as
  [text](href) instead of dropping the href.  Agents (e.g. Codex)
  can now follow alert-card links, log URLs, and rich-text hyperlinks.
- extractCardElements: handle `button` tag — extract label text and
  the first `open_url` behavior URL, formatted as [label](url).
  Buttons without a URL still forward their label text.
- Update two existing tests that asserted the old (href-dropping)
  behaviour.
- Also: web/headless-Linux (#1148) — check for xdg-open availability
  before trying to open a browser; improve the fallback message to
  include the full login URL and a note to ensure cc-connect is running.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-30 16:56:04 +08:00
ClaudeandCursor d66540236f ci: add go mod verify step to catch go.sum checksum mismatches early
Prevents a repeat of the BurntSushi/toml incident where GONOSUMDB='*'
was used to bypass the official checksum database, writing a locally-
cached hash into go.sum that didn't match sum.golang.org.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-28 10:07:51 +08:00
ClaudeandCursor ebc1a268b0 fix(deps): correct go.sum hash for BurntSushi/toml v1.6.0 to match sum.golang.org
Previous fix used GONOSUMDB='*' which bypassed the official checksum
database and wrote the hash of our local cached copy. The official
sum.golang.org records h1:dRaEfpa2..., which is what proxy.golang.org
and CI download. Updated to the authoritative hash.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-28 09:45:06 +08:00
ClaudeandCursor 54a81dac83 ci: remove gosimple and unused linters (merged into staticcheck in golangci-lint v2)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-28 09:36:41 +08:00
ClaudeandCursor 17806901bf ci: fix golangci-lint v2 module path (add /v2 prefix)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-28 09:34:23 +08:00
ClaudeandCursor d1ae13c9d7 ci: upgrade golangci-lint to v2.11.4 for Go 1.25 support
golangci-lint v1.62.0 (built with Go 1.24) cannot analyze Go 1.25
modules — it exits with code 5 and 'no go files to analyze'.

Changes:
- Upgrade golangci-lint from v1.62.0 to v2.11.4 (Go 1.25/1.26 support)
- Update .golangci.yml to v2 config format (add version: "2",
  rename issues.exclude-rules → issues.exclusions.rules)
- Treat exit code 5 as success (no Go files changed is not a failure)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-28 09:31:30 +08:00
ClaudeandCursor 301070fc46 fix(core): use LastUserActivity for reset_on_idle_mins instead of UpdatedAt (#1115)
`session.Unlock()` is called at the end of every agent turn, heartbeat
execution, and unsolicited agent response — each bumping `UpdatedAt` to
now. This meant `reset_on_idle_mins` could never fire as long as any
automated activity ran between user messages.

Add `Session.LastUserActivity` — a separate timestamp that is only
set via `TouchUserActivity()` when the engine processes a real incoming
user message (after the idle-reset check, in `handleMessage`). The idle
check in `maybeAutoResetSessionOnIdle` now uses `LastUserActivity` with
a fallback to `UpdatedAt` for sessions pre-dating this field.

Two regression tests verify:
1. Idle reset fires when `LastUserActivity` is stale even if `UpdatedAt`
   was just bumped by a heartbeat.
2. Idle reset does not fire when `LastUserActivity` is recent.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-28 01:00:39 +08:00
ClaudeandCursor e71b9fd095 build: bump npm package version to v1.3.3-beta.4
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-28 00:31:52 +08:00
ClaudeandCursor d577db282b fix(daemon): remove duplicate CheckLinger declaration in launchd.go
Two PRs both added CheckLinger to launchd.go, causing a redeclaration
compile error on darwin. Remove the duplicate introduced in the second PR.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-28 00:23:09 +08:00
ClaudeandCursor 00364df318 fix(deps): correct go.sum checksum for BurntSushi/toml v1.6.0
The hash in go.sum did not match the module downloaded from the proxy,
causing all builds to fail with a SECURITY ERROR. Updated to the correct
hash as provided by the Go module proxy.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-28 00:20:50 +08:00
ClaudeandCursor 992b82ef94 fix: session busy lockup, AskUserQuestion empty answer, Feishu require_mention, DingTalk picture type
- fix(core): reject empty/whitespace content as AskUserQuestion answers (#1086)
  Platform delivery receipts arriving within ~500ms were accepted as valid answers,
  resolving the tool immediately with empty answers before the user could respond.

- fix(feishu): treat require_mention=false as alias for group_reply_all=true (#1141)
  Platform read group_reply_all from opts but users set require_mention=false;
  group messages without @mention were silently dropped.

- fix(dingtalk): accept msgtype="picture" as image message (#1128)
  DingTalk delivers image messages as either "image" or "picture" depending on client.
  "picture" fell through to the text handler (empty content) and was dropped.

- feat(core): add max_turn_time_mins config option for #1091
  Absolute wall-clock cap per agent turn that does NOT reset on tool-call events.
  Prevents long-running bash commands from permanently locking the session.
  Two-phase shutdown: soft stop (10s grace) then force-kill.
  Session is preserved; next message resumes via --resume.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-28 00:10:37 +08:00
ClaudeandCursor 9f0466d832 fix: 微信 ilink QR 码主动刷新,防止扫码时过期 (#1103)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 23:33:30 +08:00
ClaudeandCursor b220aeaec0 fix: feishu concurrency safety, error logging, Windows test compat (#1080)
Merge conflict resolved: combined getBotOpenID() getter (from #1080)
with quoted-content empty-message guards (from #1090).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 23:32:17 +08:00
ClaudeandCursor 78370812d1 fix(daemon): CheckLinger on macOS should return true (launchd is always persistent)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 23:29:16 +08:00
ClaudeandCursor 8e04d66bf6 build: release v1.3.3-beta.3 — fix Windows cross-compile (CheckLinger stub)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-24 09:49:54 +08:00
Claude 4253763f6b build: release v1.3.3-beta.3 2026-05-24 08:52:29 +08:00
Claude 51fc187340 Revert "test(blackbox): Phase 2 – fixture collector and platform_sim tests"
This reverts commit 27d2109f8a.
2026-05-24 08:11:54 +08:00
ClaudeandCursor 27d2109f8a test(blackbox): Phase 2 – fixture collector and platform_sim tests
Adds a self-contained fixture collection pipeline that captures real
platform messages from the live cc-connect service and replays them
in automated tests.

New files:
- tests/blackbox/collector/recorder.go   – Recorder wraps any core.Platform
  and serialises every incoming core.Message as a sanitised JSON fixture.
  Activated by CC_CONNECT_RECORD_FIXTURES=/path (no code changes needed).
- tests/blackbox/platform/fixture_platform.go – FixturePlatform replays
  saved Fixture files through the engine via InjectRawMessage.
- tests/blackbox/platform_sim/feishu_sim_test.go – Four fixture-based tests
  (text, image, file, sweep-all) that skip gracefully when no real fixtures
  are present, keeping CI green until fixtures are collected.
- tests/blackbox/fixtures/{feishu,wecom,telegram,discord,weibo}/ – directories
  with a sample.json and README describing the required fixture set.
- docs/FIXTURE-COLLECTION.md – step-by-step guide for collecting fixtures
  from the local supervisor-managed cc-connect service across all platforms.

Modified:
- tests/blackbox/platform/mock_platform.go – adds InjectRawMessage for
  injecting pre-built core.Message objects (used by FixturePlatform).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-24 08:01:37 +08:00
ClaudeandCursor 1a0f396127 test(blackbox): add cursor/opencode agents + fix helper infrastructure
## Test validity audit

After running tests against real providers (minimax proxy, input_tokens=29k
at turn 1), confirmed all slow config tests ARE testing real behavior:

- P2-71 (hide ctx indicator): tokens reach threshold at turn 1 due to
  claudecode system prompt (~29k input_tokens). With disabled setting,
  [ctx: ~N%] correctly absent even when it would otherwise appear.
- P2-79 (hide tool messages): logs confirmed tools=1 fired; 🔧 message
  correctly suppressed with ToolMessages=false.
- P2-78 (hide thinking messages): mimo-v2.5-pro DOES emit thinking events
  (💭 prefix observed in P2-71b output), making the test meaningful.

## Cursor agent support

- agentBinName("cursor") → "agent" (the @anthropic-ai/cursor-agent CLI,
  not the Cursor IDE binary). Fallback checks "cursor" for environments
  that install both.
- requireAgent("cursor"): no longer skips when API keys are absent; cursor
  can authenticate via local `agent` login. Tests fail naturally if auth
  is missing rather than being silently skipped.
- NewEnvWithSetup automatically adds mode="force" for cursor tests to
  bypass the interactive workspace-trust prompt (--force flag).

## OpenCode agent support

- wireProviders: when agentType=="opencode" and baseURL is set, inject
  ANTHROPIC_BASE_URL into ProviderConfig.Env so opencode's providerEnvLocked
  picks it up. (opencode only injects APIKey+Env, not BaseURL directly.)
- requireAgent("opencode"): skips cleanly when ANTHROPIC_API_KEY is absent.
- applyProviderFromEnv: added opencode and cursor cases.

## New test variants

P0 basic message flow + context retention for cursor and opencode:
  TestP0_1_BasicMessageFlow_Cursor     — PASS (25s, "Hi!")
  TestP0_1_BasicMessageFlow_OpenCode   — skip if no ANTHROPIC_API_KEY
  TestP0_11_ContextRetention_Cursor    — PASS (52s, recalled marker)
  TestP0_11_ContextRetention_OpenCode  — skip if no ANTHROPIC_API_KEY

Env var reference for test environments:
  CC_BLACKBOX_CURSOR_API_KEY    → CURSOR_API_KEY for agent binary
  CC_BLACKBOX_CURSOR_MODEL      → --model flag (e.g. claude-haiku-3-5-20241022)
  CC_BLACKBOX_OPENCODE_API_KEY  → ANTHROPIC_API_KEY for opencode
  CC_BLACKBOX_OPENCODE_BASE_URL → ANTHROPIC_BASE_URL (proxy endpoint)

Total blackbox test count: 74 → 78

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-24 08:01:36 +08:00
ClaudeandCursor f1c23b260a test(blackbox): add config-switch and NewEnvWithSetup infrastructure
Introduces NewEnvWithSetup — a hook that runs between engine creation and
engine.Start(), enabling tests to configure any engine option before the
first message is processed.

New config-switch tests (tests/blackbox/p2/config_switch_test.go):

FAST (engine-only, no agent API call):
  P2-81  disabled_commands: /help and /restart blocked with 🚫 message;
         /list (not disabled) still works
  P2-82  banned_words: message with banned word blocked ⚠️; normal
         message passes through to agent
  P2-82b banned_words case-insensitive: lowercase ban word catches
         UPPERCASE in message

SLOW (requires real agent turn):
  P2-71  show_context_indicator=false: [ctx: ~N%] absent from all replies
         across multiple turns
  P2-71b show_context_indicator=true (default): ctx indicator eventually
         appears after token accumulation (soft assertion)
  P2-77  display.mode="compact": no 💭 or 🔧 messages in tool-requiring
         task
  P2-78  thinking_messages=false: no 💭 thinking messages
  P2-79  tool_messages=false: no 🔧 tool messages; final result still
         present
  P2-80  stream_preview.enabled=false: final reply still delivered
         (MockPlatform doesn't implement MessageUpdater so no streaming
         occurs anyway — test verifies no suppression of final reply)
  P2-86  reply_footer=false + show_context_indicator=false: no metadata
         line in final reply
  P1-40  filter_external_sessions=false (default): all created sessions
         visible in /list
  InstantReply: immediate confirmation before agent reply when enabled

Also adds NewEnvWithSetup to helper/env.go with clean setup-function API.
Total blackbox test count: 53 → 74

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-24 08:01:36 +08:00
ClaudeandCursor 90050afafc test(blackbox): add P0/P1/P2 tests from checklist
Expands the blackbox test suite from 6 → 53 test functions, covering
all automatable P0/P1/P2 items from the release checklist.

New tests:

P0:
- P0-14: tool invocation (agent must call a filesystem/bash tool)
- P0-15: long response (≥200 chars, verifies no truncation)

P1 — session commands (tests/blackbox/p1/):
- P1-1:  /help returns command list
- P1-4:  /switch between sessions
- P1-5:  /current shows active session info
- P1-6:  /delete removes only the target session
- P1-7:  /name renames session and persists in /list
- P1-9:  /status shows project/agent/session state
- P1-10: /version is dispatched (VersionInfo set by main at runtime)
- P1-14: message queuing — 3 rapid messages all processed in order

P1 regression suite (P1-30..40) — reproduces v1.3.1 bugs:
- P1-30: all historical sessions visible in /list (not just latest)
- P1-31: /new then /list shows all sessions
- P1-32: /new <name> naming takes effect
- P1-33: /name rename persists in /list
- P1-34: /switch doesn't lose sessions from /list
- P1-35: /delete only removes the specified session
- P1-37: /list session count doesn't decrease after agent reply
- P1-39: restart engine with same session store preserves names
All P1-30..40 tests have ClaudeCode + Codex variants.

P2 — extended commands (tests/blackbox/p2/):
- P2-38: /skills lists available skills
- P2-39: /effort high switches reasoning effort
- P2-40: /quiet toggles quiet mode
- P2-41: /whoami shows user identity
- P2-45: /agent-sid returns agent session ID
- P2-46: /search searches sessions
- P2-47: /bind shows relay binding
- P2-56: /cron list shows cron jobs
- P2-57: /cron add + verify in /cron list
- P2-61: allow_from documented as manual-only
- P2-63..66: custom command lifecycle (add → list → invoke → delete)
- P2-67..68: exec command lifecycle (addexec → invoke → verify output)
- P2-69..70: alias lifecycle (add → trigger → delete → verify gone)

Key design choices:
- Engine-handled commands use cmdTimeout=30s (no agent round-trip needed)
- P1-14 polls AllText() for keyword presence instead of counting messages
  (queue notifications + thinking messages make raw count unreliable)
- P1-10 /version: VersionInfo is "" in tests (set by main at startup);
  test verifies command dispatched without error
- P1-39 restart test: stops engine, creates new engine with same
  session store path to simulate service restart

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-24 08:01:36 +08:00
ClaudeandCursor 5d94958c11 test: add Phase 1 blackbox testing framework
Introduces a real-agent blackbox test suite under tests/blackbox/.
Unlike existing integration tests, these tests use a real agent (Claude
Code, Codex, etc.) and a custom MockPlatform — no fake agents.

Framework components:
- tests/blackbox/platform/mock_platform.go
  Channel-based notification (no polling), WaitForTurnComplete for
  stability-based turn completion detection, full optional interface
  support (CardSender, ImageSender, FileSender, etc.)

- tests/blackbox/helper/env.go
  NewEnv: wires real agent + MockPlatform + Engine, skips (never fails)
  when binary/credentials unavailable. Send/SendComplete/SendAs helpers.
  wireProviders: injects CC_BLACKBOX_<AGENT>_* env vars via SetProviders.

- tests/blackbox/helper/agents.go
  Blank imports to register all agent factories.

P0 tests (tests/blackbox/p0/):
- P0-1: basic message flow (send → non-empty reply)
- P0-2: /new creates a new session
- P0-3: /list returns session information
- P0-5: /stop produces a timely response
- P0-11: context retention across turns (real session state)
- P0-11: session isolation between users (no cross-session leakage)

All 6 ClaudeCode tests verified passing with xiaomi provider.
Key insight: SendComplete uses WaitForTurnComplete (stability window)
to wait for the full agent turn before sending the next message,
preventing session queue collisions in multi-turn tests.

Run: CC_BLACKBOX_CLAUDECODE_API_KEY=xxx \
  CC_BLACKBOX_CLAUDECODE_BASE_URL=https://... \
  go test -tags blackbox ./tests/blackbox/p0/... -timeout 600s -v
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-24 08:01:36 +08:00
Claude 694c816121 docs(sponsors): add apikey.fun and reorder nekoCode
- Insert APIKEY.FUN at position 4 (after DMXAPI)
- Move nekoCode to position 5 (before Shengsuanyun)
- Add APIKEY.FUN to provider presets

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 13:28:23 +00:00
ClaudeandCursor a2cc0ab117 fix(core): restore italic wrapping on reply footer
The previous commit stripped asterisks from the footer to work around
Feishu italic rendering, but this broke four unit tests and caused
appendFinalMetadataToSegment to fail to re-attach the footer to tool
call segments (it relies on the "\n\n*" pattern).

Revert to wrapping the footer in *...* in the platform-agnostic core.
If Feishu needs to suppress italic rendering, that should be handled
inside platform/feishu at content-build time.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-20 22:16:08 +08:00
Claude 91c46b9ee6 docs(sponsors): add CaMeL and reorder inactive sponsors
- Insert CaMeL at position 6 (after AICodeMirror)
- Move Code0 and claudeapi.com to end of sponsor list (not renewed)
- Add CaMeL to provider-presets.json

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 12:46:55 +00:00
Claude 6c422f96e4 fix: strip asterisks from footer to prevent Feishu markdown italic rendering 2026-05-19 23:01:53 +08:00
Claude 5acbe7cb84 debug: add appendReplyFooter logging 2026-05-19 22:48:55 +08:00
Claude 405cb109e8 feat(presets): add anyroute, aicanapi, pateway, 10dianai, siliconflow providers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-19 01:39:43 +00:00
Claude ebceb4154b docs(sponsors): add SiliconFlow sponsor
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-19 01:32:46 +00:00
ClaudeandCursor 5a7dde4417 fix: detect cron empty responses via session history delta
Replace the platform-wrapper (deliveryTrackingPlatform) approach with a
session-history delta check. The old wrapper only intercepted Reply/Send
calls, silently missing deliveries made through MessageUpdater.UpdateMessage
(rich-card mode) and CardSender.ReplyCard (Feishu/DingTalk card streaming),
causing those cron jobs to always be flagged as "produced an empty response".

The new check compares session.HistoryLen() before and after
processInteractiveMessageWith: the engine always appends a "user" entry
followed by an "assistant" entry, so fewer than prevLen+2 entries means
the agent produced no output. This covers all rendering paths uniformly
because AddHistory("assistant",...) is called before any platform-specific
card/update dispatch.

Remove the now-unused deliveryTrackingPlatform type and add
Session.HistoryLen() as a concurrency-safe helper.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 22:43:30 +08:00
ClaudeandCursor 8ba51086d8 fix(core): harden workspace and media handling
Make local workspace init opt-in and tighten media, session close, and workdir concurrency paths uncovered by the post-merge review.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 11:08:17 +08:00
Claude 14abab1715 doc: update FUNDING.yml 2026-05-13 10:46:45 +08:00
Claude 180209041b build: bump npm package version to v1.3.3-beta.2 2026-05-09 09:20:27 +08:00
Claude f6a1a79460 build: release v1.3.3-beta.2 — Slack Assistant API, DingTalk richText, MAX webhook, and platform fixes 2026-05-09 09:13:00 +08:00
Claude d7ab11edfd fix ci provider tests and race 2026-05-08 21:21:58 +08:00
Claude 356a8b3a6f test(release): extend turn contract and config matrix tests
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 16:48:51 +08:00
Claude 3fc95033d0 test(release): add turn contract test
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 16:11:06 +08:00
Claude f8d25a116a revert: disable reset_on_idle_mins default (was 30 mins)
The automatic session rotation after 30 minutes of inactivity was added
in PR #494, but the default of 30 minutes is too aggressive for many
workflows and causes unexpected session switches. Revert the default
to 0 (disabled) so existing deployments are not affected.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 16:10:09 +08:00
Claude 34af331a89 fix(core): suppress ellipsis-only events and handle context indicator in footer
- Skip ellipsis-only thinking/text events that add no content
- When replyFooterEnabled, render context indicator inside footer instead of appending separately
- Fix duplicate side channel text when context indicator is present
- Add regression tests for duplicate suppression with context indicator

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 16:09:40 +08:00
Claude 099f7bdf26 chore(deps): remove stale slack-go/slack v0.15.0 from go.sum
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 14:25:00 +08:00
Claude c642dff2fa test(release): add local release gates 2026-05-08 10:15:13 +08:00
Claude 06ead8fa6a fix(config): honor project display mode 2026-05-08 09:33:49 +08:00
Claude 5cde55a78b fix(feishu): guard user id resolution 2026-05-08 09:29:32 +08:00
ClaudeandCursor 9090e7c8f1 test(bridge): use NewBridgeServerInsecure in capabilities snapshot test
NewBridgeServer now returns nil when token is empty (security fix #408).
The test does not need a real token — switch to NewBridgeServerInsecure
so the BridgeServer is properly constructed and the test does not panic.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-06 15:51:18 +08:00
Claude 9e71032ede docs(sponsors): update aicanapi affiliate link
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-05 11:00:01 +00:00
Claude 42fd8253d9 docs(sponsors): add AnyRoute.io sponsor
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-05 10:57:56 +00:00
Claude 3c07db2c36 docs(sponsors): update aicanapi and 10点AI descriptions with official copy
- aicanapi: Claude Code up to 84% off, Doubao Seedance 2 queue-free
- 10点AI: production-optimized, high concurrency, GPT/Claude/Gemini/DeepSeek

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-05 10:30:01 +00:00
Claude 8f7e52a27f docs(sponsors): update Pateway and 10点AI descriptions
- Pateway: 100% official direct access, $3 trial, up to 40% off, referral rewards
- 10点AI: add ¥5 registration bonus

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-05 10:28:19 +00:00
9989fdc416 feat(display): add display_mode enum to replace boolean quiet (#655)
Convert the legacy boolean `quiet` setting into a three-mode display
system: full / compact / quiet.

- **full**: show thinking + tool messages as separate messages (default)
- **compact**: hide thinking/tool, each text segment sent as a separate card
- **quiet**: hide thinking/tool, all text appended to one card with
  paragraph separators; done emoji only after in-place streaming updates

Config:
  [display]
  mode = "quiet"   # or "full" | "compact"

Legacy `quiet = true` is auto-mapped to `mode = "quiet"` for backward
compatibility.

/quiet now cycles full → quiet → compact → full; also accepts explicit
argument: /quiet full|compact|quiet

Conflict resolution:
- Renamed the Feishu Card 2.0 render mode to `display.card_mode`
  ("rich"/"legacy") so it no longer conflicts with `display.mode`
- Merged the per-project display override logic from main with the new
  mode resolution from PR #655
- Combined `!isSilent && !hasRichCard && sp.needsDoneReaction()` for the
  done reaction gate

Co-authored-by: happyTonakai <happyTonakai@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-05 17:48:11 +08:00
ClaudeandCursor fc0b9af20e feat(dingtalk): support richText message type
Extract plain text from DingTalk richText content payloads so messages
composed in the rich editor (e.g. bold/italic text, inline @mentions) are
forwarded to the agent as plain text rather than silently dropped.

Adds extractRichText() helper and 8-case test suite (nil, non-map, empty
array, single/multiple text, attrs, mixed text+picture, missing key).

Resolves conflict with main's image message handler by placing richText
check before the image check — both are now present.

Closes #719

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-05 17:02:03 +08:00
ClaudeandCursor 79c9e6c891 fix: address H1-H4, M2-M4, M6, L1-L2 from PR review
H1 (claudecode): separate configEnv from runtime sessionEnv so project-level
env vars survive SetSessionEnv calls and propagate to workspace agents via
WorkspaceAgentOptions(). Export configEnv in WorkspaceAgentOptions; prepend it
in runtimeEnvLocked() so later provider/session entries can override.

H2 (max): add dedicated uploadClient with 5-min Timeout so CDN uploads are
not silently aborted by the 35 s general httpTimeout on p.client.

H3 (dingtalk): cap image download at 25 MiB via io.LimitReader, consistent
with other platforms; log and drop oversized images.

H4 (engine): fix executeCronShell pipe-reader goroutine race — use a WaitGroup
to drain both stdout/stderr scanners before closing doneCh, preventing
truncated output in finishCronShell.

M2 (max): add compile-time interface assertions for all implemented interfaces.

M3 (telegram): restore IsForum guard for groups while preserving private-chat
thread ID semantics. Forum groups use MessageThreadID as topic ID; regular
groups ignore it (thread replies would fragment sessions); non-group chats
(private/channel) use it as-is.

M4 (slack): fix assistantOrThreadTS to thread replies in non-DM channels
(preserving old behavior) while keeping top-level replies in DMs and honouring
the AssistantThread thread_ts.

M6 (engine): honour the unsolicited reader context in RespondPermission
goroutines so they stop cleanly when stopUnsolicitedReader cancels the context.

L1 (engine): fall back to agent.Name() in cmdStart when e.name is empty to
avoid "%!(EXTRA string=)" in the welcome message.

L2 (claudecode): fix snapshotCLIPath to normalise empty cliBin to "claude"
before checking for extra args, preventing silent arg loss.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-05 11:28:55 +08:00
Claude bc7d6e8825 docs(sponsors): update 10点AI affiliate link
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-04 13:19:12 +00:00
Claude dcff37697f docs(sponsors): move aicanapi, pateway, 10点AI after AICodeMirror
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-04 13:01:41 +00:00
Claude 94035b695f docs(sponsors): add aicanapi, pateway, 10点AI sponsors
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-04 12:53:47 +00:00
Claude a4a9206196 docs: move Trendshift badge below language switcher
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 06:37:48 +08:00
Claude 8ded01b9ae docs: add Trendshift badge to README.zh-CN
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 06:27:44 +08:00
Claude 94f2c4bd65 docs: add Trendshift badge to README
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 06:27:09 +08:00
Claude a7058854ba docs: update sponsor list and add donor recognition
- Move 优云智算 to earlier position
- Add thx0701 to donor list

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 15:45:08 +00:00
Claude 84d4f9067d feat(dingtalk): implement FileSender for file attachments
Add SendFile() using DingTalk oToMessages API with sampleFile msgKey.
Follows the same uploadMedia + batchSend pattern as SendImage.

Closes #284 (partial — DingTalk file sending)

Made-with: Cursor
2026-04-28 22:21:56 +08:00
Claude 9613fc85c4 fix(opencode): add -- separator before prompt to prevent --file from consuming it
OpenCode CLI's --file flag is a yargs [array] type that greedily
consumes subsequent arguments as file paths. Without a -- separator,
the prompt text following --file was parsed as a filename, causing
"File not found" errors when images were attached.

Reported-by: community user via image analysis
Made-with: Cursor
2026-04-28 22:07:48 +08:00
Claude 003d96d68b fix(test): sort disabled_commands before comparison to avoid map iteration order flakiness
Made-with: Cursor
2026-04-27 20:55:41 +08:00
Claude 558d48b511 fix: update sponsor referral links
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-26 06:47:54 +08:00
Claude e0b4cc89e5 docs: add DragonCode and 优云智算 sponsors
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-26 01:00:25 +08:00
Claude 3a9bb44125 build: release v1.3.3-beta.1 — new agents, features, and platform fixes
Made-with: Cursor
2026-04-25 10:53:29 +08:00
Claude 9900924af1 test(management): add comprehensive unit tests for all web API endpoints
Cover 140 test cases across all management API handlers including:
- restart, config, reload, agents, settings, skills, providers
- project CRUD, sessions, send, provider-refs, users, heartbeat, cron
- Edge cases: invalid JSON, missing fields, method not allowed, nil callbacks,
  callback errors, nonexistent resources, conflict scenarios, business rules

Made-with: Cursor
2026-04-24 15:53:39 +08:00
Claude dffd702ccb fix(qqbot): use platform context for reconnect instead of canceled connCtx
triggerReconnect was called with the per-connection context (connCtx),
but reconnectLoop immediately cancels it via p.connCancel(). This caused
the reconnect backoff loop to exit on the first iteration because
ctx.Done() was already closed. Fix by storing the platform lifetime
context and using it for reconnect operations.

Made-with: Cursor
2026-04-24 07:13:50 +08:00
Claude fc79307142 fix(core): restore /btw alias, gate NO_REPLY done reaction, fix i18n gaps
1. Restore /btw as alias for /ps — prevents breaking change for existing users
2. Suppress done_emoji when agent reply is NO_REPLY (silent turn)
3. Handle NO_REPLY on channelClosed path — prevents leaking silent content
4. Add /show command to help text for zh-TW, ja, es (was only in en, zh)
5. Add TestBtwAlias_ResolvesToPs test

Made-with: Cursor
2026-04-24 07:09:48 +08:00
Claude 77a1f9cc77 docs: clarify that cc-connect web does not start the service
Users mistakenly believed `cc-connect web` also starts the bridge.
Updated README, README.zh-CN, and INSTALL.md to clarify it only
configures the web admin and opens the browser — a separate
`cc-connect` command is still needed to start the service.

Made-with: Cursor
2026-04-23 17:48:56 +08:00
Claude 04b7a483ac feat(presets): add NekoCode and VisionCoder to provider-presets
- Add NekoCode: Claude/CodeX relay, 10% off code CC-CONNECT
- Add VisionCoder: Claude Code/Codex/Gemini, buy 1 month get 1 free

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-21 23:38:33 +08:00
Claude 087bb2402a feat(sponsor): add NekoCode as new sponsor (position 3)
- Add NekoCode sponsor at position 3 (after AIHubMix, before DMXAPI)
- Claude and CodeX API relay, exclusive 10% off code: CC-CONNECT
- Link: https://nekocode.ai/?aff=CC-CONNECT

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-21 23:03:29 +08:00
Claude 32bd992ecc feat(sponsor): add VisionCoder as new sponsor (¥800/month)
- Add VisionCoder sponsor at position 6 (after Code0)
- ¥800/month sponsorship with Token Plan promo (buy 1 month get 1 free)
- Reliable API relay service for Claude Code/Codex/Gemini

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-21 22:51:24 +08:00
Claude fdda018e5c fix(sponsor): move AIHubMix to 2nd position and add brand name
- Move AIHubMix before DMXAPI (now 2nd position)
- Add "AIHubMix" text next to logo since logo has no text

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-21 21:35:54 +08:00
Claude c2b66fb3c7 feat(sponsor): update AIHubMix position and add to provider-presets
- Move AIHubMix to 2nd position in sponsor list (after DMXAPI)
- Update invite link to https://aihubmix.com/?aff=mGTx
- Compress sponsor description for better readability
- Add AIHubMix to provider-presets.json (500+ models, all formats)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-21 21:30:28 +08:00
Claude e425f1ec40 feat(sponsor): add AIHubMix as new sponsor
- Add AIHubMix sponsor entry to both English and Chinese READMEs
- AIHubMix: ¥1,000 one-time sponsorship
- Deep integration with OpenAI/Claude/Gemini/Qwen/DeepSeek/Kimi
- Officially authorized by Microsoft Azure, AWS, GCP
- Link: https://aihubmix.com/?aff=XNdl

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-21 21:30:28 +08:00
Claude ecc66e838c feat(dingtalk): support richText message type
DingTalk richText messages were silently ignored because the handler
only extracted data.Text.Content (empty for richText). Add explicit
richText handling that parses data.Content to extract plain text from
the richText array, skipping non-text elements like pictures.

Closes #719

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-21 13:02:33 +00:00
Claude a49b5772a5 test: add comprehensive E2E session tests with isolated config
- Create e2e_session_test.go covering /list /new /switch /name /delete
  /stop /status /provider commands with real agent calls
- Create e2e_helpers_test.go with shared test utilities
- Update filter_sessions_test.go to reference new E2E test location
- Add config.test.toml to .gitignore for test isolation

Made-with: Cursor
2026-04-21 11:35:08 +08:00
Claude 19406df98f build: release v1.3.2 — session filter default off + config switch
Made-with: Cursor
2026-04-21 08:42:07 +08:00
Claude e30fb6f7d4 test: E2E tests use real provider config instead of env-var API keys
The E2E tests (Codex + ClaudeCode full session lifecycle) now load
provider credentials from /root/.cc-connect/config.toml via a new
setupE2EEngine helper, removing the OPENAI_API_KEY / ANTHROPIC_API_KEY
env-var requirement. Both tests pass with real LLM round-trips (~8s each).

Also improved resilience: auth/balance errors cause skip instead of fail,
and project names are overridable via E2E_CODEX_PROJECT / E2E_CLAUDECODE_PROJECT
environment variables.

Made-with: Cursor
2026-04-21 08:35:33 +08:00
Claude e9c0d7fb3b test(integration): add E2E tests with real agent conversation
Add TestE2E_Codex_FullSessionLifecycle and TestE2E_ClaudeCode_FullSessionLifecycle
that exercise the complete workflow: send message → agent replies → /list →
/new with name → send message → agent replies → /list verifies both sessions
visible with correct session name. Requires API keys (OPENAI_API_KEY /
ANTHROPIC_API_KEY); skips gracefully when unavailable.

Made-with: Cursor
2026-04-21 08:27:25 +08:00
Claude f3a729d7ab test(integration): add real agent adapter tests for filter_external_sessions
Integration tests using real codex.Agent and claudecode.Agent adapters
with JSONL fixture files on disk. Tests the full pipeline: agent reads
real session files → ListSessions → Engine applySessionFilter → command
output. Covers /list, /switch, /delete under both filter modes plus
dynamic runtime toggle, for both Codex and Claude Code agents.

Made-with: Cursor
2026-04-21 08:11:11 +08:00
Claude 7a3bad4815 feat(session): add filter_external_sessions config (default off)
Session filtering that hides external CLI sessions is now opt-in via
`filter_external_sessions = true` in project config. By default, /list,
/switch, /delete show all agent sessions regardless of origin.

Includes integration tests covering /list, /switch, /delete, card
rendering, and dynamic toggle under both modes, plus config parse tests.

Made-with: Cursor
2026-04-21 08:02:21 +08:00
Claude 48afa69f9d build: release v1.3.1 — session fixes, config preservation, weibo media
Made-with: Cursor
2026-04-20 23:24:04 +08:00
Claude 234f651a26 test(config): add comment preservation tests for all surgical save functions
Cover the remaining gap in config test coverage:
- SaveLanguage with comments
- SaveDisplayConfig with comments and unknown fields
- SaveTTSMode with comments
- Multi-project SaveActiveProvider (ensure only target project modified)
- Global provider ref SaveProviderModel (model update via provider_refs)

These tests verify the v1.3.0→v1.3.1 migration from TOML serialize
to surgical text editing doesn't silently break user config files.

Made-with: Cursor
2026-04-20 23:15:12 +08:00
Claude 668c9d3ba6 fix(core): add name mapping to relay paths + tests for all agent patterns
Complete the session name mapping coverage:
- Add name mapping to relay start (CompareAndSet without name)
- Add name mapping to relay EventText handler
- These paths were the last remaining gaps from the audit

Add end-to-end tests for all three agent SessionID patterns:
- Pattern A (ACP-like): CurrentSessionID() non-empty at start
  → name mapped in startOrResumeSession
- Pattern B (claudecode/gemini/cursor-like): ID in early EventText
  → name mapped in EventText handler
- Pattern C (codex/qoder/kimi-like): ID only in EventResult
  → name mapped in EventResult handler

All three tests simulate the full /new → message → reply → verify flow.

Made-with: Cursor
2026-04-20 23:06:04 +08:00
Claude 86ab722c3e fix(core): map session name in EventResult handler (codex compatibility)
Codex agent's CurrentSessionID() returns "" at startup; the thread ID
is only set after Send() triggers thread.started. The session ID reaches
the engine through EventResult (turn.completed), not EventText.

The previous fix only added name mapping in startOrResumeSession and
EventText handlers, but for codex:
- startOrResumeSession: CurrentSessionID()="" → no-op
- EventText: codex doesn't set SessionID on text events → no-op
- EventResult: was using SetAgentSessionID (unconditional) instead of
  CompareAndSetAgentSessionID, and had no name mapping at all

Now all three EventResult handlers (interactive, relay, drain) use
CompareAndSet and map the pending session name on first ID binding.

Added TestSessionName_CodexLikeFlow that simulates real codex behavior:
empty CurrentSessionID at startup, ID only in EventResult.

Made-with: Cursor
2026-04-20 22:57:22 +08:00