Replace Kimi Open Platform links in both READMEs and the
provider-presets invite URLs with new tracking IDs from
Moonshot AI, applying the same pattern to both the
global (platform.kimi.ai) and China (platform.kimi.com)
endpoints.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Per the issue: the existing Kimi preset had its invite URL
pointing to the Kimi Code subscription page, but its base
URL pointed to the pay-as-you-go API endpoint. This caused
confusion between Kimi Code (subscription) and the API
product.
- Change existing 'kimi' entry to global:
- base URL: api.moonshot.cn/v1 -> api.moonshot.ai/v1
- invite URL: kimi.com/code/?aff=cc-connect
-> platform.kimi.ai/?aff=cc-connect
- Add new 'kimi-cn' preset for China:
- base URL: api.moonshot.cn/v1
- invite URL: platform.kimi.com/?aff=cc-connect
- Follow the existing minimax / minimax-cn naming convention.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Replace local Kimi banner assets with Kimi-hosted CDN URLs
(gcdn.moonshot.cn/growth-cdn/sponsor/kimi-en.png + kimi-zh.png)
so Kimi can manage the banner centrally.
- Update sponsor copy from Kimi K2.7 Code to Kimi K3
(Moonshot AI's 3T-class agentic model with native vision
and 1M-token context).
- Delete now-orphan local banner files.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Insert Kimi at the top of the providers list with the
K2.7 Code agentic model available across claudecode, codex,
and opencode agents. Bump updated_at to reflect the change.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the previous top-of-README banner with Kimi in both
README.md and README.zh-CN.md, including new logo assets and
updated sponsor copy and links.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The English README previously contained the Chinese sponsor
copy in the Ergou API (二狗 API) block. Replace with a
proper English translation that preserves the technical
details (0.1x-0.2x rates, IPLC routes, dual residential
ISP redundancy, native Claude/GPT/Gemini endpoints).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Insert 七牛云 at position 2 and Fenno.ai at position 3 in
both README.md and README.zh-CN.md.
- Add assets/sponsors/qiniu.png and assets/sponsors/fenno.png
(logos provided by sponsors).
- Sponsor copy, English translations, and affiliate links
from sponsor-supplied materials.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Insert 二狗 API in the middle of the sponsor table in both
README.md and README.zh-CN.md (position 10 of 19).
- Add assets/sponsors/ergou.png (logo provided by sponsor).
- Sponsor copy and affiliate link from 二狗 API's own materials.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bold 'Claude Max 200', 'GPT Pro 200', and '高级成品号 /
premium accounts' in both README.md and README.zh-CN.md
per VisionCoder's request.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Promote VisionCoder earlier in the sponsor table in
both README.md and README.zh-CN.md based on sustained
cooperation and product quality. RunAPI, CaMeL, and
Unity2.ai shift down one position each.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Switch domain to visioncoder.cn (per VisionCoder request)
- Refresh logo asset (assets/sponsors/visioncoder.png)
- Update sponsor copy to reflect current VisionCoder offerings
(retail channels for Claude Max 200 / GPT Pro 200 premium accounts)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Insert APINEBULA at the top of the sponsor table in both
README.md and README.zh-CN.md (position 1).
- Add assets/sponsors/apinebula.png (logo supplied by
APINEBULA via their Galaxy Video Bureau platform).
- Sponsor copy and registration link provided by APINEBULA.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace placeholder link with the affiliate-tracked
registration URL on unity2.ai's request.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Insert unity2.ai between CaMeL and AnyRoute.io in both
README.md and README.zh-CN.md (position 7).
- Add assets/sponsors/unity2ai.png.
- Sponsor copy and link provided by unity2.ai.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The upstream dingtalk-stream-sdk-go v0.9.1 has a race condition in
processLoop (client.go:161) that causes "send on closed channel" panic
after overnight idle. The fix exists in upstream PRs but is not yet
merged/released.
Add defer/recover around streamClient.Start() so the panic is caught
and the existing reconnect loop can re-establish the connection instead
of crashing the entire cc-connect process.
Closes#1390
Co-authored-by: Cursor <cursoragent@cursor.com>
Surfaced during v1.4.0-beta.1 QA: when an agent produced a ~7.3 KB
Markdown reply in Slack, the streaming card (#1333) silently failed
mid-stream with `msg_too_long`, then Finalize tried to chat.update the
full reply and also failed, forcing the engine onto its emergency
fallback path. The user perceived the turn as a non-streaming "one-shot
output preceded by ~30s of silence".
Root cause: Slack's `chat.update` text parameter is capped at ~4000
bytes (server-side, despite docs saying chars). The streaming card had
no size guard and Update() also swallowed errors with no log, so the
half-broken state was invisible from logs until Finalize blew up.
Fix:
- Introduce `slackUpdateMaxText = 3500` (conservative; leaves headroom
for multi-byte CJK content where Go's len() overshoots Slack's limit).
- `Update()`: once rendered exceeds the limit, silently skip the
chat.update tick (leave the streaming card at its last fitting
snapshot) and emit a Debug log instead of staying invisible.
- `Update()`: also Debug-log transient render errors (previously
swallowed entirely).
- `Finalize()`: when the final payload exceeds the limit AND a card has
already been posted, deliver the full reply via a *fresh*
chat.postMessage (which has a 40 KB ceiling), so the engine sees
success and skips its duplicate-fallback emission. The partial
streaming card stays visible above the new full-content message.
- Extract `postFresh()` helper to share the postMessage logic between
the lazy first-post path and the new overflow path.
Tests:
- `TestStreamingCard_FinalizeFallsBackToFreshPostOnOversize`: oversized
Finalize must NOT touch chat.update and must postMessage the full
payload (and not mark the card failed).
- `TestStreamingCard_UpdateSkipsOversizedPayload`: oversized Update
tick must silently no-op (no chat.update call).
Net behaviour:
- Short replies (< ~3500 B mrkdwn): unchanged — chat.update streaming
keeps working as #1333 intended.
- Long replies: no more `msg_too_long` errors, no more duplicate
fallback messages from the engine. UX is "partial streaming card +
one final full-content message" instead of "broken card + duplicate
full-content message".
Closes the third user-visible bug surfaced during v1.4.0-beta.1 QA
pairing (after #1395 image batch window default and the nav.cron i18n
miss).
Co-authored-by: Cursor <cursoragent@cursor.com>
#1343 added Korean (ko.json) but missed the nav.cron key on the left
sidebar — surfaced during v1.4.0-beta.1 QA pairing (owner spotted the
raw "Cron" label while sanity-checking the Korean UI). Same key was
also missing in ja.json (regressed earlier) and es.json. All three
files already carried the correct translation at `settings.cron`
(line 297) so this just propagates it to the nav label:
- ko: 예약 작업
- ja: スケジュールジョブ
- es: Tareas programadas
en, zh, zh-TW already correct.
No code paths or types touched; only locale string values.
Co-authored-by: Cursor <cursoragent@cursor.com>
The hardcoded 150ms `imageBatchWindow` introduced in #1395 turned out to be
too narrow for real-world Feishu mobile sending behaviour. In QA we
observed ~330ms between consecutive image sends from the mobile client
when a user taps "send" repeatedly, which exceeds 150ms and defeats the
coalescing logic — each image was dispatched as its own turn, and turns
after the first hit the engine's "busy" guard and returned the
"will process after the current task finishes" notice.
Changes:
- Promote `imageBatchWindow` from a package const to a per-Platform field
populated from a new platform option `image_batch_window_ms`.
- Bump the default from 150ms to 500ms based on observed mobile send
intervals.
- Add `batchWindow()` helper so zero-initialised Platforms (constructed
directly in tests) still fall back to the default and never schedule a
zero-duration timer.
- Validate the option: reject negative or non-numeric values.
- Document the new knob in `config.example.toml` and `docs/feishu.md`.
- Add `TestNewPlatform_ImageBatchWindow` covering default, custom, zero
(fallback) and validation paths; update existing batch tests to read
the effective window via `batchWindow()`.
Operators who need a longer or shorter window can override per-platform:
[projects.platforms.options]
image_batch_window_ms = 800
Closes follow-up surfaced during v1.4.0-beta.1 QA pairing.
Co-authored-by: Cursor <cursoragent@cursor.com>