32 Commits
Author SHA1 Message Date
e48b4d41da fix(build): normalize dash → underscore in AGENTS / PLATFORMS_INCLUDE / EXCLUDE (#1033)
Build tags use underscores (`no_foo_bar`) but ALL_AGENTS / ALL_PLATFORMS
elements are bare names. When a plugin's registered name contains a
dash (e.g. an agent named `foo-bar` whose build tag is `no_foo_bar`),
the user-facing flag value `AGENTS=foo-bar` was passed through
unchanged. The filter-out then failed to match `foo_bar` in the ALL
list, so the agent was *added* to the exclusion set — i.e. the build
silently dropped the very plugin the user asked to include.

Introduce a tiny `_normalize` define that runs the comma-split and a
dash→underscore fold in one step, and use it everywhere user-supplied
plugin lists feed into filter-out / addprefix. Behaviour for existing
underscore-or-bare names is unchanged.

No new ALL_AGENTS / ALL_PLATFORMS entries are added by this commit;
the fix is purely about input normalization so downstream additions
with hyphenated names work as the help text suggests.

Co-authored-by: Shuchao Shao <shaoshch@yonyou.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-09-27 20:16:28 +08:00
dev-claudecodeandCursor 80713167d1 docs(changelog,readme): v1.5.1-beta.1
Bump version and add changelog for beta release since v1.5.0 stable.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-28 08:04:22 +08:00
7b93b085cb feat(googlechat): add Google Chat platform adapter (#1424)
* feat(googlechat): scaffold platform skeleton

Add a Google Chat platform adapter registered as "googlechat", wired
into selective compilation via plugin_platform_googlechat.go (build tag
no_googlechat) and the Makefile ALL_PLATFORMS list.

This commit lands the skeleton only: option parsing/validation in New
(gws_path, project, target, subscription, allow_from, trigger,
session_scope, credentials_file) plus stub Start/Reply/Send/Stop.
Receive, send and gating follow in subsequent commits.

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

* feat(googlechat): receive messages via gws events subscribe

Start() now supervises a `gws events +subscribe` subprocess: stdout is
scanned as NDJSON (one Workspace Events CloudEvent per line, buffer
enlarged for the full message resource), stderr is logged, and the
process is restarted with a small backoff if it exits while the context
is alive. Stop() cancels the context to kill it.

parseEvent decodes chat.message.v1.created envelopes, ignores non-human
senders (so the app never replies to its own posts), and dispatches a
core.Message carrying the space/thread reply context. Trigger-word,
allow_from gating and session scoping follow in a later commit.

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

* feat(googlechat): send replies via gws chat messages create

Reply and Send post content through `gws chat spaces messages create`,
using the generic raw method (--params/--json) rather than the +send
helper so replies can be threaded: when the reply context carries a
thread name, the request sets messageReplyOption and thread.name so the
answer lands in the originating thread.

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

* feat(googlechat): add trigger-word, allow_from and session scoping

parseEvent now gates and routes incoming messages:

- trigger word: when configured, only messages starting with the prefix
  are handled (prefix stripped) for user-OAuth mode without a Chat App;
  otherwise argumentText (mention markup already removed by Google) is
  used, falling back to text.
- allow_from via core.AllowList, and a core.IsOldMessage guard on
  createTime so a restart does not replay backlog.
- session_scope space|thread|user via buildSessionKey, plus
  ReconstructReplyCtx so proactive sends reach the right space/thread.

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

* docs(googlechat): add config example

Document the googlechat platform options in config.example.toml,
including the gws prerequisites and the two operating modes (@mention
with a Chat App service account, vs trigger-word with user OAuth).

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

* test(googlechat): add event parsing and reply-arg unit tests

Cover parseEvent (mention vs trigger mode, argumentText fallback,
non-human and wrong-type skipping, allow_from, old-message guard),
buildSessionKey for each scope, ReconstructReplyCtx round-trips, and
buildCreateArgs threaded vs top-level argument shapes.

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

* feat(googlechat): switch to Chat app Pub/Sub receive + service-account send

Pivot the platform from the Workspace Events API to a registered Google
Chat app's native Cloud Pub/Sub connection. The subscription is fixed, so
there is no Workspace Events subscription expiry or per-restart resource
leak (the two operational problems of the previous approach).

- receive: parse the Chat-app event format — gws wraps each Pub/Sub
  message as {"data":{"type":"MESSAGE","message":{...}}} — instead of
  Workspace Events CloudEvents; pull a fixed subscription via
  `gws events +subscribe --subscription`.
- send: post via the Chat REST API authenticated as the app's service
  account (chat.bot scope) so replies appear as the bot. gws has no
  service-account auth, so sending is native Go via
  golang.org/x/oauth2/google; receiving still uses gws (its own OAuth).
- config: require `subscription`; `credentials_file` is the SA key used
  for replies. Drop the Workspace Events target/project auto-create.

Verified end-to-end against a real Chat app: the receive format matches
gws output and a service-account reply posts as the bot.

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

* docs(googlechat): add GCP/Chat app setup guide

Add docs/googlechat.md documenting the end-to-end Google Chat setup:
enabling the Chat + Pub/Sub APIs, creating the Pub/Sub topic/subscription
and granting the Chat push service account publisher, creating a service
account key for bot replies, configuring the Chat app (LIVE, classic
model, Cloud Pub/Sub connection, visibility), cc-connect config, and an
FAQ covering the issues hit during bring-up (app must be LIVE to send,
Workspace-only, add-on vs classic). Link it from the README platform
table.

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

* refactor(googlechat): receive via native Pub/Sub client instead of gws

Replace the `gws events +subscribe` subprocess with a native streaming pull
using cloud.google.com/go/pubsub. Sending was already native Go, so this
removes the gws binary dependency entirely — the platform is now fully native.

Both directions now authenticate with the same service-account key, so
`credentials_file` is required (it also needs roles/pubsub.subscriber on the
subscription for the receive path). The `gws_path` option is removed.

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

* refactor(googlechat): drop trigger, centralize session-key constants, harden session_scope (#5)

- Remove the `trigger` field and its prefix-matching branch from extractContent;
  Google Chat already scopes delivery so a prefix filter is redundant and subtly
  broken for @mention spaces (m.Text still contains the markup).
- Extract sessionKeyPrefix and threadSep constants used by both buildSessionKey
  and ReconstructReplyCtx so the encode/decode pair stays in sync automatically.
- Add a slog.Warn in the normalizeSessionScope default branch so typos like
  "thraed" surface at startup instead of silently falling back to "space".
- Update tests, docs/googlechat.md, and config.example.toml accordingly.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(googlechat): implement FormattingInstructions for Google Chat text formatting (#7)

* feat(googlechat): implement FormattingInstructions for Google Chat text formatting

Adds FormattingInstructions() to *Platform so the engine injects
Google Chat-specific formatting guidance into the agent system prompt,
steering agents away from unsupported ## headings and [text](url) links.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(googlechat): add block quote and display-text link to FormattingInstructions

Add missing formatting rules per reviewer feedback:
- Block quote syntax (>text)
- Display-text hyperlink syntax (<url|text>) alongside raw URL auto-linking

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(googlechat): fix test call after base-branch refactor of newTestPlatform

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(googlechat): implement streaming preview (PreviewStarter + MessageUpdater) (#6)

* feat(googlechat): implement streaming preview via PreviewStarter + MessageUpdater

Adds SendPreviewStart (POST a threaded message, return resource-name handle)
and UpdateMessage (PATCH spaces.messages with updateMask=text) so the engine's
real-time streaming-preview path is activated for Google Chat.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(googlechat): extract doRequest helper + drain response bodies

Extract a `doRequest` helper that centralizes HTTP execution and non-2xx
error handling. Both `post()` and `SendPreviewStart` become thin wrappers,
eliminating the duplicated logic that would otherwise diverge on future
changes (retries, auth header tweaks, etc.).

Drain response bodies on success paths in `post()`, `SendPreviewStart`,
and `UpdateMessage` so the transport can return TCP connections to the
pool. Addresses the performance issue where each streaming PATCH would
open a new TLS+TCP handshake.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(googlechat): send images and files via attachment upload (#8)

* feat(googlechat): implement SendImage and SendFile via attachment upload

Adds media-upload support to the Google Chat platform so cc-connect can
send images and files (e.g. /diff HTML output) instead of returning
ErrNotSupported.

Two-step flow for each send:
1. Upload raw bytes to the Chat media endpoint (multipart/related POST
   to https://chat.googleapis.com/upload/v1/{space}/attachments:upload)
   and retrieve the attachmentDataRef resource name.
2. Create a Chat message that references the data ref, respecting thread
   context the same way as the existing text send path.

Shared helper postAttachment handles both steps; SendImage and SendFile
delegate to it with appropriate filename/MIME defaults. Compile-time
interface assertions ensure *Platform satisfies core.ImageSender and
core.FileSender.

Adds TestBuildAttachmentRequest mirroring TestBuildSendRequest to cover
the message body shape (attachment data ref + thread, reply option URL).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(googlechat): address code-review feedback on SendImage/SendFile

- Add rc.space == "" guard to postAttachment (bug fix: prevents malformed
  upload URL when ReconstructReplyCtx("googlechat:") yields empty space)
- Pre-size bytes.Buffer in uploadAttachment to avoid a full double-copy of
  attachment data on large files
- Extract httpErrorBody helper to deduplicate the 3 error-drain sites
- Extract messageURL/applyThread helpers to deduplicate threading URL logic
  shared between buildSendRequest and buildAttachmentRequest
- Extract coalesce helper and simplify SendImage/SendFile
- Use doRequest in postAttachment for the create-message step
- Add HTTP-level unit tests: uploadAttachment (success, 403 error,
  empty resourceName), postAttachment (missing space, two-step flow),
  SendImage/SendFile (default filename/MIME fallbacks)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(googlechat): use doRequest in uploadAttachment and drain response body

Two follow-up fixes from code review:
- Route upload request through doRequest so it benefits from any future
  centralized logging/retry/tracing alongside post() and postAttachment().
- Drain remaining bytes from resp.Body after json.Decode so the HTTP
  transport can return the connection to the pool (partial reads prevent
  connection reuse, causing a new TLS handshake per SendImage/SendFile call).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(googlechat): drain resp.Body on decode error in uploadAttachment

Deferred drain ensures the HTTP connection is returned to the pool
even when JSON decoding fails, not just on success.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(googlechat): handle Stop error, remove redundant drain defer, add compile-time assertion (#12)

- Return psClient.Close() error from Stop() instead of silently discarding it
- Remove redundant drain defer in uploadAttachment; the json.Decoder already
  consumes the body, and defer resp.Body.Close() handles cleanup
- Add compile-time assertion var _ core.ReplyContextReconstructor = (*Platform)(nil)
  alongside the existing ImageSender and FileSender guards

Closes #10

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(googlechat): use doRequest in uploadAttachment and drain response body

Two follow-up fixes from code review:
- Route upload request through doRequest so it benefits from any future
  centralized logging/retry/tracing alongside post() and postAttachment().
- Drain remaining bytes from resp.Body after json.Decode so the HTTP
  transport can return the connection to the pool (partial reads prevent
  connection reuse, causing a new TLS handshake per SendImage/SendFile call).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(googlechat): drain resp.Body on decode error in uploadAttachment

Deferred drain ensures the HTTP connection is returned to the pool
even when JSON decoding fails, not just on success.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(googlechat): clear lint issues in googlechat package (#13)

* fix(googlechat): resolve package lint errors

Handle all body/multipart close errors, remove deprecated auth option usage, and tighten HTTP test writers so golangci-lint passes for platform/googlechat.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(googlechat): ack Pub/Sub message after handler, nack on panic

Previously m.Ack() was called before p.handler(), so a handler panic or
failure would silently drop the message without redelivery. Move ack to
after handler completion and nack on panic so Pub/Sub can redeliver.

Introduce the ackable interface and dispatchMessage to make the timing
testable without a real Pub/Sub client, and add three regression tests
covering the success, panic, and parse-failure paths.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(googlechat): add unit tests for New() error cases (#14)

Closes #11

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-08-13 16:49:41 +08:00
zhilei zhangandtuitui-v2 fc315d213b feat(tuitui): add platform support (#849)
Co-authored-by: tuitui-v2 <tuitui-v2@example.invalid>
2026-07-19 20:15:03 +08:00
72d6fb617d Integrate WPS Agentspace platform with auto-login and token encryption (#1439)
* feat: add WPS Agentspace platform integration

Add wps-agentspace platform that connects to WPS Digital Employee (数字员工)
via WebSocket, enabling users to interact with Claude Code through WPS Xiezuo
without creating a WPS application.

Features:
- WebSocket connection to agentspace.wps.cn
- Token decryption (AES-256-GCM) for OpenClaw-encrypted tokens
- Message deduplication
- Auto-reconnection with exponential backoff
- Heartbeat keep-alive
- Typing indicator support

Co-Authored-By: fengjianxiong <fengjianxing@kingsoft.com>

* chore: add wps-agentspace to ALL_PLATFORMS in Makefile

Co-Authored-By: fengjianxiong <fengjianxing@kingsoft.com>

* feat: add auto-login for wps-agentspace platform

When wps_sid is empty, automatically open browser for WPS OAuth login
and poll for the token. This provides a smoother setup experience.

Co-Authored-By: fengjianxiong <fengjianxing@kingsoft.com>

* feat: encrypt wps_sid after auto-login

After OAuth login, encrypt the token using AES-256-GCM and display
the encrypted value for safe storage in config.toml.

Co-Authored-By: fengjianxiong <fengjianxing@kingsoft.com>

* feat: auto-set environment variable after login

After OAuth login, automatically display encrypted token and instructions
for setting WPS_SID environment variable. Also add Windows browser support.

Co-Authored-By: fengjianxiong <fengjianxing@kingsoft.com>

* feat: auto-save token to config file after login

After OAuth login, automatically save encrypted token to config.toml.
Falls back to displaying token for manual environment variable setup.

Co-Authored-By: fengjianxiong <fengjianxing@kingsoft.com>

* chore: remove sensitive data from test file

Co-Authored-By: fengjianxiong <fengjianxing@kingsoft.com>

* fix: resolve lint errors (govet, errcheck)

- Remove redundant newline in fmt.Println
- Check error return values with _ = for non-critical calls
- Fix return and defer statements

Co-Authored-By: fengjianxiong <fengjianxing@kingsoft.com>

* fix: remove unused statFile function

Co-Authored-By: fengjianxiong <fengjianxing@kingsoft.com>

* fix: check error return in defer statement

Co-Authored-By: fengjianxiong <fengjianxing@kingsoft.com>

* feat: support file/media attachments in incoming messages

Parse media_urls and media_url fields from WPS messages and append
file URLs to the message content so Claude can access attachments.

Co-Authored-By: fengjianxiong <fengjianxing@kingsoft.com>

* fix(wps-agentspace): address PR review feedback

- Re-enable token decryption in Start(); remove token prefix from logs
- Rewrite saveToConfig with TOML validation + surgical line replacement
- Fix autoLogin connection leak (http.Client + deferred Body.Close)
- Fix openBrowser Windows path (cmd /c start  url)
- findConfigFile: prefer config.ConfigPath (honours --config flag)
- decryptWpsSid: fallback to defaultKeySource when appID key fails
- generateUUID: use google/uuid v4 instead of custom implementation
- expandPath: support ~user/... via os/user.Lookup
- gofmt: fix struct alignment, trailing blank lines
- Add 6 new tests (11 total): Start decrypt, handleFrame dispatch,
  fatal errors, saveToConfig surgical update, autoLogin HTTP flow,
  decrypt fallback to defaultKeySource

Generated with Kscc
Co-Authored-By: fengjianxiong <fengjianxing@kingsoft.com>

* fix(wps-agentspace): resolve lint errors

- Remove unused userInfoAPI variable
- Check errcheck: json.NewEncoder.Encode and p.Stop() return values

Generated with Kscc
Co-Authored-By: fengjianxiong <fengjianxing@kingsoft.com>

* fix(wps-agentspace): fix race condition on Platform.stopped field

Use atomic.Bool for stopped flag to avoid data race between
connectLoop goroutine reading stopped and Stop() writing it.
Detected by go test -race.

Generated with Kscc
Co-Authored-By: fengjianxiong <fengjianxing@kingsoft.com>

---------

Co-authored-by: fengjianxiong <fengjianxiong@kingsoft.com>
Co-authored-by: fengjianxiong <fengjianxing@kingsoft.com>
2026-07-14 06:45:46 +08:00
118dd3b697 feat(platform): add cloud_web platform for self-hosted IM gateways (#1282)
* feat(platform): add cloud_web platform for self-hosted IM gateways

Introduce the cloud_web platform with CWIP protocol support over websocket, long_poll, and gateway transports. Includes capability negotiation, inbound/outbound message handling, Web UI configuration with transport-specific fields and URL validation, documentation, build wiring, and integration tests.

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

* fix(cloud-web): satisfy errcheck lint for Close/Stop returns

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

* fix(cloud-web): address PR review feedback for #1282

Resolve reviewer feedback and rebase onto latest main:

- CHANGELOG: add cloud_web entry under Unreleased / Added
- gateway: fail closed when token is unset (reject all inbound webhooks)
- New(): require public_url when register_url is set for gateway transport,
  mirror the rule in client-side validation, and add a regression test
- forward perm:* card actions via IsPermissionResponse so the engine drops
  stale permission clicks instead of leaking allow/deny into the agent prompt
- ko.json: add Korean translations for the cloud_web setup/fields keys
- split cloudweb_test.go by transport (ws/poll/gateway + shared test helper)

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

---------

Co-authored-by: jiagou123 <jiagou123@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Your Name <you@example.com>
2026-07-05 06:43:02 +08:00
mchenziyi fd6dbcc320 feat: add reasonix agent adapter (#1281)
* feat: add reasonix agent adapter

Adds a new agent adapter for Reasonix, a multi-model coding agent.

The adapter communicates with a running 'reasonix serve' instance via its HTTP API:
- Submits prompts via POST /submit
- Consumes agent events via SSE /events
- Handles tool approval via POST /approve
- Supports mode switching (default/yolo/plan)
- Accumulates incremental reasoning chunks into single events

* fix: handle resp.Body.Close errors (errcheck lint) and fix close-before-status order

* fix: add SSE auto-reconnect with backoff when reasonix serve restarts

* fix: add unit tests, static assertions, error body, reconnect limit

10 unit tests with httptest. All pass -race. P2 fixes: static assertions, error body, max reconnect.

* fix: lint: check error returns in session_test.go (errcheck)

* fix: lint: check remaining fmt.Fprintf error in TestSSEReconnect

* fix: add reasonix to ALL_AGENTS in Makefile, fix CHANGELOG, add doc comments

P1: Added reasonix to ALL_AGENTS in Makefile so make build includes it by default.

P2: Fixed CHANGELOG Unreleased entry, added formatImages doc comment, serve_url normalize comment, normalizeMode auto/force comment.

* chore: retrigger CI
2026-06-25 07:46:06 +08:00
BryantandBryant Barzola cb0e2fa172 feat: add Cisco Webex platform adapter (#1402)
* docs: add Webex platform adapter design spec

* docs: add Webex platform implementation plan

* feat(webex): add API types and REST client

* feat(webex): add Platform struct, New, and allowlist parsing

* feat(webex): add message gating and mention stripping

* feat(webex): build core.Message with attachment handling

* feat(webex): add Reply, Send, chunking, and file senders

* feat(webex): add Start/Stop and reconnecting WebSocket loop

* feat(webex): wire platform into build, Makefile, and config example

* test(webex): add interface conformance checks; docs: add no_webex tag

* fix(webex): address review — selfID race, allow_from wildcard, 429/401, token redaction, rune-safe chunking, goroutine + device cleanup

* chore(webex): remove internal design/plan docs from PR branch

* fix(webex): parse Mercury conversation.activity frames and fetch decrypted messages

* fix(webex): accept 'share' verb for file/image uploads, ignore re-notifications

* fix(webex): check Close() return values to satisfy errcheck lint

---------

Co-authored-by: Bryant Barzola <bryant.barzola@gmail.com>
2026-06-22 09:24:29 +08:00
+7 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
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 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 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
m3 03ae3908fc feat(agent): add GitHub Copilot as a first-class agent (#865) 2026-06-02 10:13:40 +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
JazzuLu 6a78e21145 feat: integrate Google Antigravity CLI (agy) agent 2026-05-26 01:17:41 +00:00
22972872b3 agent/tmux: add tmux agent (#999)
* agent/tmux: add tmux agent

Drives a persistent tmux pane as an interactive shell agent. User
messages are sent via send-keys; responses are extracted from the
scrollback buffer so terminal scrolling never bleeds previous turns
into the next response.

Key features:
- Multi-workspace: each workspace gets its own named tmux window
  (session:workspace-name), with Claude Code auto-started via
  init_command on first use
- Scrollback-based extraction: records scrollback line count at
  send-time; response = lines added since, immune to terminal scroll
- Stability detection: fires done when pane is unchanged for 2+ polls
  (fast path) or 5 s idle fallback when prompt pattern never matches
- TUI cleanup: strips Claude Code's ───/❯/─── input block and
  configurable per-line strip_patterns (default: mode status line)
- AgentOptsProvider: new core interface so workspace agents inherit
  agent-specific options (session name etc.) during multi-workspace
  cloning

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* agent/tmux: fix response extraction to avoid missing or duplicate lines

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* agent/tmux: fix key injection, file workDir, and window name collision

- sendKeys: use -l (literal) flag so user text containing C-c, Enter, Up
  etc. is never interpreted as tmux key names; send Enter separately
- SaveFilesToDisk: use session workDir instead of "." so attached files
  are written relative to the workspace the pane was started in
- uniqueWindowName: append a 4-hex FNV hash of the full path so two
  workDirs sharing the same basename (e.g. /a/app and /b/app) never
  collide into the same tmux window target
- Add regression tests for all three fixes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: hexihui <hexihui@bytedance.com>
2026-05-18 11:23:20 +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 c642dff2fa test(release): add local release gates 2026-05-08 10:15:13 +08:00
Aleksey BondarenkoandClaude Opus 4.7 b187acd147 feat(platform/max): add MAX messenger bridge with bidirectional file and voice support (#742)
* feat(platform/max): add MAX messenger bridge with bidirectional file and voice support

- Implement core.Platform plus InlineButtonSender, ImageSender, FileSender,
  AudioSender, MessageUpdater, FormattingInstructionProvider,
  ReplyContextReconstructor
- Two-step attachment upload via POST /uploads + multipart to CDN
- Route incoming audio (type=audio and audio/* file mime) to
  core.Message.Audio so the speech pipeline transcribes it for the agent
- Outgoing voice replies via SendAudio for the TTS pipeline
- Retry on attachment.not.ready with exponential backoff
- Long poll /updates with reconnect backoff and allow_from filtering
- Register max in Makefile ALL_PLATFORMS and document in config.example.toml
- Tighten .gitignore: ignore config.*.toml (except example) and *.old
- 19 unit/integration tests with httptest mock, passes -race

Refs #741

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(platform/max): handle real MAX CDN response shapes and audio download

Issues discovered when testing end-to-end with the live MAX API:

1. Image CDN returns nested {"photos": {<id>: {"token": ...}}}, not a flat
   {"token": ...}. Parse the right shape per kind.

2. Audio CDN returns XML "<retval>1</retval>" rather than JSON. The real
   attachment token is delivered in the /uploads response itself for
   video/audio, so we use urlInfo.Token as the source of truth and only
   scan the CDN body opportunistically.

3. /audios/{token} endpoint does not exist in MAX (returns 404). Incoming
   voice payloads already carry the download URL directly, mirroring
   images/files. Use payload.url; fall back to resolveMediaURL only if
   empty (for video where token resolution may still apply).

Also raise the speech HTTP client timeout from 60s to 5m — enough for the
first-request cold-start case when a local Whisper backend has to download
or JIT-load the model before responding.

Tests updated to emit the real CDN response shapes per attachment type.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(platform/max): address review — dedup + idiomatic session key parse

- Add core.MessageDedup to Platform and check msg.Body.Mid / callback ID
  in handleMessage and handleCallback. Guards against reprocessing on
  poll-loop reconnect edge cases, matching the pattern used by feishu/
  dingtalk/wecom platforms.
- Replace fmt.Sscanf in ReconstructReplyCtx with strings.CutPrefix +
  strings.Cut — more idiomatic Go, simpler to read, and handles the
  "max:" prefix and optional ":userID" suffix without a manual loop.
- Add TestHandleMessageDedupsByID regression test.

Addresses review feedback on #742.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 14:36:57 +08:00
1b8a0843ef feat(agent): add Devin CLI as a first-class agent (#672)
Adds native support for Devin CLI (Cognition, https://cli.devin.ai/)
as a named cc-connect agent, alongside Claude Code / Codex / Cursor /
Gemini / iFlow / Qoder / OpenCode. Users can now configure Devin with
a minimal `type = "devin"` block rather than hand-rolling a generic
ACP config.

    [[projects]]
    name = "my-project"

    [projects.agent]
    type = "devin"                   # NEW

    [projects.agent.options]
    work_dir = "/path/to/code"
    # command / args / display_name default to "devin" / ["acp"] / "Devin"
    # mode, auth_method, env (for WINDSURF_API_KEY) passed through to ACP

Credentials come from the local `devin auth login` store — cc-connect
never sees or forwards any token. Windsurf Enterprise users can inject
WINDSURF_API_KEY via the agent env option.

The new `agent/devin/` package is a thin wrapper around `agent/acp/`:
Devin speaks the Agent Client Protocol over stdio via its `devin acp`
subcommand, so the session/prompt, session/update, permission, and
tool-call plumbing is shared. Embedding *acp.Agent and shadowing only
Name() gives us identity and defaulting without duplicating transport
code:

    type Agent struct { *acp.Agent }
    func (a *Agent) Name() string { return "devin" }

Wiring Devin revealed two protocol features that agent/acp had left
as MVP-skipped TODOs. Both are needed for `/list` and `/mode` to work
in IM, so this PR fills them in as part of the Devin integration —
Cursor Agent, OpenClaw, and Copilot CLI all pick up the same
improvements automatically.

ListSessions now spawns a short-lived `<command>` process that runs
just initialize + session/list, then tears down. Capability is
discovered via `agentCapabilities.sessionCapabilities.list`, and a
negative result is cached on the Agent so non-supporting servers pay
the spawn cost only once. Soft-degrades on JSON-RPC -32601 (method
not found) and -32600 (invalid request). Measured cost against
`devin acp` 2026.4.9-0: ~40 ms round trip.

Agent implements core.ModeSwitcher (SetMode / GetMode /
PermissionModes); the modes list is sourced from the modes block
returned by session/new or session/load. GetMode precedence: the most
recent explicit SetMode wins over the last server-advertised
currentModeId, so `/mode plan` reports the new mode back to the user
immediately rather than the cached previous one.

acpSession implements core.LiveModeSwitcher via session/set_mode with
client-side modeId validation against the cached availableModes.
Client-side validation is mandatory because at least one ACP server
(devin acp 2026.4.9-0) silently accepts unknown modeIds with an empty
result — server-only validation would let typos go undetected.

session/update notifications with sessionUpdate = current_mode_update
are absorbed so cc-connect stays in sync when the user switches modes
from another client (e.g. the Windsurf IDE).

newACPSession moved from seven positional args to an acpSessionConfig
struct. Private API, not a breaking change externally; the one
exported consumer (cursor_integration_test.go) is updated.

A sessionCallbacks interface lets running acpSession instances report
handshake-derived capabilities and modes back to the parent Agent,
since the engine (not the agent) owns the session lifetime.

- README.md / README.zh-CN.md: Devin added to the Support Matrix and
  the agent count bumped from 7 to 8.
- config.example.toml: dedicated Devin section placed before the
  generic ACP examples, with prerequisites and override notes.
- web/src/pages/Projects/ProjectList.tsx: Devin added to the agent
  dropdown so the web admin UI surfaces it alongside other
  first-class agents.
- Makefile: ALL_AGENTS += devin (enables selective compilation tags
  `no_devin` / AGENTS=devin,...).

22 new tests total (7 for agent/devin, 15 for agent/acp). All pass
with -race. agent/acp wrapper tests avoid requiring `devin` in PATH
by pinning `command = "true"` to satisfy the upstream exec.LookPath
check while still exercising the Name() shadow and default injection.

End-to-end verified against live `devin acp` 2026.4.9-0 through the
cc-connect bridge:
- /mode lists Devin's five modes with ▶ Code marked current
- /mode plan switches and the engine reports "switched to **Plan**"
- /list shows "devin Sessions (1)" (confirms Name() propagates to UI)
- agent field in engine logs = "devin" (not "acp")

Closes none — net-new agent support.

Generated with [Devin](https://cli.devin.ai/docs)

Co-authored-by: youngshook <youngshook@users.noreply.github.com>
Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-04-21 21:19:30 +08:00
Claude e055bc8cf5 feat(weibo): add Weibo DM platform support
Implement Weibo private message platform via the Open IM WebSocket
protocol (open-im.api.weibo.com). Supports app_id/app_secret auth,
automatic token refresh, heartbeat keep-alive, reconnect with
exponential backoff, message dedup, and chunked sending for long
messages (2000 char limit).

Includes plugin registration, build tag (no_weibo), unit tests,
setup documentation, and cross-references in all platform docs.

Made-with: Cursor
2026-04-17 13:18:33 +08:00
cold2600438-lgtm 006718a753 feat(agent): add Kimi CLI support (#616)
- Add agent/kimi/ implementation using kimi --print --output-format stream-json
- Parse assistant text, think blocks, tool_calls and tool results into core.Event
- Support session resume via --resume, list/delete via ~/.kimi/sessions/
- Implement optional interfaces: ModeSwitcher, ModelSwitcher, ProviderSwitcher,
  MemoryFileProvider, SkillProvider, SessionDeleter, AgentDoctorInfo
- Register plugin with //go:build !no_kimi tag
- Update Makefile ALL_AGENTS and config.example.toml
2026-04-16 14:47:29 +08:00
Claude 433e7d63fc refactor(web): embed frontend assets into binary via go:embed
Replace the npm-based install/upgrade workflow with compile-time
embedding. The web/dist/ directory is now embedded directly into the
binary using go:embed and registered through core's plugin registry
pattern (web/embed.go → core.RegisterWebAssets).

- Add web/embed.go (go:build !no_web) and web/embed_stub.go
- Add core/web_assets.go as the embedded FS registry
- Add cmd/cc-connect/plugin_web.go to import the web package
- Rewrite management.go static serving to use io/fs instead of disk
- Simplify /web command to setup + status (remove install/upgrade/uninstall)
- Clean up web_manager.go (remove npm logic, keep GenerateToken)
- Update Makefile with web build target and NO_WEB/build-noweb support
- Remove .npmignore and npm publishing fields from package.json

Binary size impact: ~1MB (16M → 17M). Use `no_web` tag to exclude.

Made-with: Cursor
2026-03-31 08:33:20 +08:00
cg33andClaude 66f3007f07 feat(agent): ACP (Agent Client Protocol) stdio adapter MVP
* feat(agent): add ACP stdio JSON-RPC adapter (MVP)

Implement agent/acp as an ACP client over newline-delimited JSON-RPC: initialize,
session/new or session/load, session/prompt, session/update mapping to core.Event,
and session/request_permission wired to RespondPermission.

Includes plugin_agent_acp.go (!no_acp), Makefile ALL_AGENTS entry, config example,
unit tests for transport and mapping, and AgentDoctorInfo for doctor.

Made-with: Cursor

* fix(acp): Cursor CLI compatibility — authenticate + cursor/* RPC ack

- Optional auth_method (e.g. cursor_login) triggers JSON-RPC authenticate after initialize
- initialize includes minimal clientCapabilities (fs/terminal) per Cursor ACP docs
- Acknowledge cursor/* server requests with empty result to avoid blocking tool flows
- Add integration test against ~/.local/bin/agent when present
- Document auth_method and args in config.example.toml

* fix(telegram): use Request for sendChatAction typing indicator

Telegram returns result=true for sendChatAction; BotAPI.Send unmarshals
result as Message and fails. Request only checks ok and avoids that decode.

* fix(core): surface EventToolResult in IM; extend ACP tool/thinking mapping

- Engine: handle EventToolResult in interactive loop (was silently dropped);
  compress and relay paths append tool output too. Add MsgToolResult i18n.
- ACP: stream tool_call_update for in_progress/pending; optional reasoning_*
  sessionUpdate kinds -> EventThinking; fallback hook for unknown kinds.

* fix(core): run agent Send concurrently with interactive event loop

Agents that block inside Send (e.g. ACP session/prompt) can emit
EventPermissionRequest while blocked; the engine must consume Events()
in parallel or permission prompts never reach the platform.

- processInteractiveMessageWith: async Send + pass sendDone into processInteractiveEvents
- processInteractiveEvents: select on sendDone for errors and sync at turn boundaries
- drainPendingMessages: same async Send pattern as the main path
- Add TestProcessInteractiveEvents_PermissionWhileSendBlocked regression test

* docs(acp): document OpenClaw and Copilot CLI; add display_name option

- config.example.toml: Cursor, OpenClaw (`openclaw acp`), Copilot (`copilot --acp --stdio`) examples with upstream doc links
- acp agent: optional display_name for doctor (AgentDoctorInfo)
- agent_test.go: cover default and custom display_name

* fix(core): remove ineffectual pendingSend assignments (ineffassign)

pendingSend was set to nil immediately before return or before
reassignment to nextSend; golangci-lint flags these as ineffectual.

* test(core): fix race in PermissionWhileSendBlocked under -race

The test goroutine polled stubInlineButtonPlatform.buttonRows while
processInteractiveEvents wrote them from another goroutine. Use a
permSignalInlinePlatform wrapper that signals on perm:allow via a channel
instead of racy field reads.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-24 08:03:57 +08:00
cg33andClaude 00b719d215 feat: 微信个人号(ilink)平台、扫码 setup 与 CDN 媒体 (#257)
* feat(platform): add Weixin personal (ilink) long-poll channel

Implement weixin platform against ilink bot HTTP API (getUpdates +
sendMessage), matching the OpenClaw openclaw-weixin backend.

- Text, quoted text, and voice messages with ASR text; media-only inbound
  gets a placeholder until CDN decrypt is added
- Persist get_updates_buf and per-peer context_token under data_dir
- allow_from, optional proxy/SKRouteTag, session pause on errcode -14
- ReplyContextReconstructor for cron; FormattingInstructionProvider
- Inject cc_data_dir/cc_project into all platform options for state paths
- Build tag no_weixin; Makefile + docs + config.example.toml

* feat(weixin): ilink QR setup CLI, CDN encrypt/decrypt, and Chinese docs

- Add cc-connect weixin setup/bind/new with get_bot_qrcode + get_qrcode_status flow
- Config helpers EnsureProjectWithWeixinPlatform / SaveWeixinPlatformCredentials
- Inbound CDN decrypt and outbound ImageSender/FileSender via getuploadurl
- Document weixin.md (ZH), usage guides, README/INSTALL links

Made-with: Cursor

* fix(weixin): remove unused netError type for golangci-lint

Made-with: Cursor

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-22 13:01:28 +08:00
Claude db05dee804 feat(tests): add integration, performance tests and CI improvements
- Add 13 integration tests (T-300~T-313) covering engine-platform
  message flow, multi-agent coordination, session persistence,
  rate limiting, dedup, command registry, role manager, platform
  reply, agent permission flow, cron store, card rendering, env
  merge, and message attachments
- Add 14 performance benchmarks (T-400~T-413) for message latency,
  concurrent throughput, session switching, rate limiting,
  deduplication, command lookup, card rendering, cron store,
  role resolution, and multi-agent coordination
- Fix FakeAgentSession so NewFakeAgentWithSession properly
  preserves pre-configured session for first StartSession call
- Add performance-test Makefile target and update test-release
- Update CI to run performance benchmarks on release events

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 10:49:15 +08:00
Claude e71de8c089 feat(tests): add分层测试targets和CI改进
Makefile新增targets:
- make test-fast: 单元 + 冒烟测试 (< 2min)
- make test-full: 完整测试套件 (PR 要求)
- make test-smoke: 冒烟测试 (< 1min)
- make test-e2e: E2E/回归测试
- make test-release: 发布前测试
- make pre-test: build + vet 前置检查

CI workflow改进:
- 添加 golangci-lint 步骤
- 添加 smoke-test job (依赖 unit-test)
- 添加 regression-test job (依赖 smoke-test)
- 将 lint 独立为独立 job
- 保持 Codecov fail_ci_if_error: false (待测试稳定后可改为true)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 10:40:32 +08:00
quabugandClaude Opus 4.6 aef607b536 feat(agent): add pi coding agent adapter
Add support for the pi coding agent CLI (@mariozechner/pi-coding-agent)
as a new agent backend. Pi uses `--mode json` for NDJSON streaming
output and supports multi-turn sessions via `--session <id>`.

Features:
- Parse pi's streaming events (text, thinking, tool calls, tool results)
- Accumulate thinking deltas into a single event to avoid message spam
- Pass images and files as @file arguments (pi's native attachment syntax)
- Support model selection, session resumption, and mode switching
- Implement AgentDoctorInfo, ModeSwitcher, and MemoryFileProvider interfaces

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 07:58:49 -07:00
chenhg5andClaude 79fefc9ff5 feat(build): add selective compilation via build tags
Implement build tag system for agents/platforms with Makefile support:
- Move imports to plugin_*.go files with build tags
- Add Makefile logic for AGENTS/PLATFORMS_INCLUDE/EXCLUDE
- Update documentation with usage examples
- Remove direct imports from main.go

generated by llmgit

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-13 17:35:08 +08:00
chenhg5andClaude c24db65243 feat: add npm package for easy installation and improve release build
Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-28 16:22:50 +08:00
chenhg5andClaude 87827e1d81 refactor(build): enhance build system with cross-platform support
Added cross-platform build targets in Makefile and updated .gitignore. Introduced version, commit, and build time tracking via LDFLAGS. Added clean dist directory target and organized build artifacts.

generated by llmgit

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-28 12:59:22 +08:00
chenhg5andClaude 3b097a80cb init
Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-28 10:38:24 +08:00