Commit Graph
134 Commits
Author SHA1 Message Date
Claude b7304a2da9 feat: global provider management + card-based IM provider add
- Add global [[providers]] config with project-level provider_refs
- Add provider management page in web admin with preset support
- Implement card-based /provider add flow: preset selection card
  with sponsor presets, API key prompt, and manual "Other" option
- Add inline button support for Telegram-style platforms
- Add remote provider-presets.json with sponsor data
- Add REST API endpoints for global providers and provider refs
- Update project detail providers tab with unified list UI

Made-with: Cursor
2026-04-17 22:08:40 +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
ahahahaandClaude Opus 4.6 66efe3256f feat: add agent-sid command to query agent session ID (#605)
* feat(cli): add `cc-connect agent-sid` command to query agent session ID

Reads the agent session ID (e.g. Claude Code / Codex / Gemini CLI session
ID used with --resume) from persisted session files. Auto-detects project
and session key from CC_PROJECT and CC_SESSION_KEY env vars, making it
usable directly inside agent subprocess sessions.

Handles all session file naming variants: plain, hashed, workspace (_ws_),
legacy paths, and .sessions.json. When multiple files contain the same key,
prefers the one with the newest UpdatedAt. Includes nil-safety, file modtime
fallback for zero-UpdatedAt entries, and proper error propagation.

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

* feat(core): add /agentsid chat command to show agent session ID

Registers /agentsid (alias: /agent-sid) as a builtin chat command so
users can query the agent session ID directly from Discord/Telegram/
Feishu etc. without asking the agent to run a Bash command.

- Added to builtinCommands registry, handleCommand switch, and help
  card (session group)
- Added to text-based /help output for all 5 languages (EN/ZH/ZH-TW/JA/ES)
- Added i18n description key MsgBuiltinCmdAgentSID with translations

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

* fix(lint): use strings.TrimPrefix instead of HasPrefix+slice

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

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 14:48:56 +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
xxb e119d54b5d feat(codex): add runtime reply footer aligned with Codex CLI (#578)
* feat(core): add optional reply footer metadata

* feat(config): enable reply footer by default

* feat(codex): use runtime footer metadata from app-server

* feat(codex): resolve exec footer metadata at runtime

* feat(core): style reply footer and prefer context left

* feat(codex): use real runtime context for reply footer

* feat(core): use english left footer text

* fix(codex): use current context tokens for footer left

* fix(codex): match cli context left calculation

* test(codex): adapt footer tests to session base url arg
2026-04-16 14:44:11 +08:00
Claude 7980a70a30 chore: fix golangci-lint errors flagged by CI
- management.go: check w.Write return value
- config_cmd.go: check fs.Parse return value
- web_manager.go: remove unused defaultMgmtPort/defaultBridgePort consts
- opencode.go: remove unused discoverModels wrapper
- engine.go: remove ineffectual resolvedWorkspace assignment

Made-with: Cursor
2026-04-15 20:49:13 +08:00
cg33 59176eabdb Merge pull request #566 from xxb/feat/bridge-capabilities-control-plane-v1
feat(bridge): publish command capabilities snapshot to bridge adapters
2026-04-15 09:35:17 +08:00
Claude d21cee5eb7 fix: pre-release fixes for high/medium priority issues from PR review
High priority:
- PR #420: fix Telegram reply context lost by alias resolution —
  resolveAlias now runs on user text before ExtraContent merge
- PR #567: fix message queue race — adoptPendingFromPlaceholder
  copies queued messages when placeholder state is replaced
- PR #437: harden /diff command — reject targets starting with '-',
  use '--' separator to prevent git option injection
- PR #560: add run_as_env dangerous variable blacklist (LD_PRELOAD,
  PATH, HOME, etc.); fix doc claiming PATH is in default allowlist

Medium priority:
- PR #497: ACP permission params log level Info→Debug to prevent
  sensitive data leaking; add toolInputByID cache size cap (1000)
- PR #559: observe new JSONL files start from EOF instead of offset 0,
  preventing full session history replay to Slack
- PR #510: add idempotent Close() test for claude session
- PR #514: bridge ReconstructReplyCtx already has structured JSON +
  backward compat; added decode helper + tests
- PR #440: add instance lock acquire/release unit tests
- PR #569: document ContinueSession behavioral change in code comments

All changes backward-compatible. Tests added for all fixes.

Made-with: Cursor
2026-04-12 20:40:02 +08:00
4cf879b2b9 feat: add run_as_user for per-project OS-user isolation (#560)
* feat: add run_as_user for per-project OS-user isolation

Implements #496. Adds an optional `run_as_user` field at the project
level that, when set, spawns the project's agent command under a
different Unix user via `sudo -n -iu <user> --`. This provides OS-level
file-system isolation from the supervisor user that runs cc-connect
itself: a misbehaving agent can no longer reach files outside the
target user's permission scope, even via python -c / shell redirection
/ other non-hooked code paths.

## What lands in this PR

### Config (config/)

- new fields `run_as_user *string` and `run_as_env []string` on each
  `[[projects]]` entry
- validation: rejects root, rejects invalid usernames, rejects use on
  Windows, enforces POSIX username charset to close a sudo argv
  injection vector

### Core primitives (core/runas*.go)

POSIX-only (Windows stubs provided for API compatibility).

- `BuildSpawnCommand(ctx, opts, name, args...)` — wraps exec.Cmd with
  `sudo -n -iu <user> --preserve-env=<allowlist> -- name args...` when
  opts.RunAsUser is set; passthrough otherwise
- `FilterEnvForSpawn(env, opts)` — strips supervisor env to a minimal
  allowlist (PATH, LANG, LC_*, TERM) plus any project-level extensions
- `VerifyRunAsUserCheap` — the two cheap sudo probes, suitable for
  per-spawn re-verification (catches sudoers edits between startup and
  spawn)
- `PreflightRunAsUser` — the three go/no-go startup gates from #496:
  (1) passwordless sudo to target works,
  (2) target cannot passwordless sudo (if escalation succeeds, captures
      `sudo -n -l` output in the error message), and
  (3) target can read AND write work_dir root. Plus a non-fatal
  descendant scan warning on unreadable/unwritable descendants with
  prune-paths, 10s timeout, and a 50-entry cap.
- `RunIsolationProbe` + embedded runas_probe.sh (//go:embed) — the
  leak-audit probe codex asked for: spawns a fixed shell script as the
  target user and parses its output into a structured IsolationReport.
  Reports effective id/groups/umask/pwd, target-home config presence,
  cross-user denial attempts for every other configured run_as_user,
  and supervisor-denial attempts. Never reads file contents, only
  existence and access.

All of these are testable without a real second user via an injectable
`SudoRunner` interface; production uses ExecSudoRunner.

### Failure policy

Per-spec: all checks are hard go/no-go, not warnings.

- Any preflight fatal in any project: cc-connect refuses to start
  entirely; no half-spawned processes.
- Any audit-level `CROSS_LEAKED` (target reads another project user's
  secrets) or `SUPERVISOR_LEAKED` (target reads the supervisor's
  secrets) or `WORKDIR_WRITABLE=no`: cc-connect refuses to start.
- Descendant-scan findings are warnings (inaccessibility inside a
  project tree is sometimes intentional).

### Startup wiring (cmd/cc-connect/)

- `runRunAsUserStartupChecks` runs preflight + isolation probe for
  every project with run_as_user set, in parallel, BEFORE any agent
  or engine is constructed. Logs every outcome via slog. On any fatal,
  prints the full list and `os.Exit(1)`.
- injects project-level run_as_user / run_as_env into the agent's
  options map before calling `core.CreateAgent`, so agents can opt in
  without new top-level plumbing.

### Doctor subcommand (cmd/cc-connect/doctor_runas.go)

New `cc-connect doctor user-isolation [--project NAME] [--out PATH]`
subcommand. Runs preflight + isolation probe for one or all
`run_as_user` projects, writes a JSON report per project, and prints a
human-readable summary. Default output is
`~/.cc-connect/audits/<timestamp>-<project>.json`.

Also supports `--print-script` to dump the embedded probe source for
inspection (and for running shellcheck against it).

### Claude Code wiring (agent/claudecode/)

- `Agent` struct gains `runAsUser` and `runAsEnv` fields
- `New()` parses them from the opts map and skips the
  `exec.LookPath("claude")` check when run_as_user is set (the target
  user's PATH is what matters, not the supervisor's)
- `newClaudeSession` takes `core.SpawnOptions`, runs the per-spawn
  cheap re-check immediately before building the command, uses
  `core.BuildSpawnCommand` instead of `exec.CommandContext`, and
  filters env via `core.FilterEnvForSpawn`

### Docs

- new "Running agents as a different Unix user" section in
  `docs/usage.md` with setup steps, sudoers example, ACL example,
  environment-propagation migration checklist (PGSSL*, ~/.claude/
  settings.json, ~/.pgpass, ~/keys/, ~/.ssh/, MCP binaries, shell
  profile, language toolchains), opt-out instructions, and
  failure-mode debug guide
- README section with a short configuration example and a pointer to
  the full docs
- `config.example.toml` commented example with setup recipe

### Tests

- config: parse run_as_user/run_as_env, reject root, reject invalid
  chars, Windows rejection, username validator valid/invalid cases
- core: BuildSpawnCommand legacy vs. sudo form, FilterEnvForSpawn
  filtering, VerifyRunAsUserCheap success/no-sudo/escalation-possible/
  empty-user, PreflightRunAsUser all-pass/no-sudo/escalation-fatal/
  workdir-fatal/descendant-warnings/descendant-cap, probe parser
  clean/cross-leak-fatal/supervisor-leak-fatal/workdir-not-writable-
  fatal, shell quoting, other-users filtering, embedded probe script
  sanity
- agent/claudecode: New() parses run_as_user/run_as_env, run_as_user
  skips LookPath
- cmd/cc-connect: default audit dir suffix, printHumanReport doesn't
  panic on populated report

Uses stubbed SudoRunners throughout — no tests require a real second
Unix user or real sudo binary.

## Scope

Only Claude Code is wired up in this PR. Each non-claudecode agent has
its own session/spawn lifecycle (codex re-spawns per turn, cursor has
its own state model, etc.) so the sweep needs per-agent reasoning and
is deferred to a follow-up. The core primitives land here so each
future agent migration is a small, self-contained PR.

Follow-up issue tracks: codex, cursor, gemini, iflow, opencode, qoder,
acp, pi.

Refs: #496
Credit: issue framing via user + codex adversarial review
        (go/no-go gates, leak-audit probe, env propagation docs,
        sudo -iu rationale pinning)

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

* refactor(run_as_user): simplify after code review

Addresses findings from a parallel code-reuse / code-quality / efficiency
review of #498. Behavior unchanged; tests still pass.

Highlights:

- cache VerifyRunAsUserCheap results for 30s keyed by runAsUser, so
  rapid-fire messages from the same Slack user don't pay the ~100ms
  per-spawn sudo tax. Cache evicts on failure so the next spawn
  re-verifies fresh. Adds ResetVerifyCache for tests + operators.
- doctor user-isolation now fans out across projects in parallel
  (mirroring runas_startup.go) instead of iterating serially. Per-project
  output is buffered and printed in order so the report stays grouped.
- collapse Agent.runAsUser + Agent.runAsEnv into a single
  core.SpawnOptions field — eliminates the reassemble-at-call-site
  pattern.
- fold core/runas_username.go into core/runas.go (one 17-line file →
  one helper near its only caller).
- IsolationReport.RawOutput is now only populated when the audit had a
  fatal — clean reports are smaller on disk.
- introduce typed string constants for the probe wire format
  (tagBegin / tagWorkDirReadable / tagCrossLeaked / ...) so the parser
  and runas_probe.sh share a discoverable contract.
- itoa() in tests → strconv.Itoa
- contains() helper in tests → slices.Contains
- mass comment trim across runas.go / runas_check.go / runas_audit.go:
  delete WHAT-restates-name comments (~70 lines) while keeping the
  load-bearing WHY blocks (sudo -n -iu rationale, env propagation
  reasoning, find expression format note, scan timeout justification).

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

* fix(runas): drop PATH from default env allowlist

Preserving PATH across the sudo boundary defeats the whole point of
-i: it overrides the target user's login-profile PATH with the
supervisor's, and leaks supervisor work directories (e.g. the
cc-connect source tree on the supervisor's PATH) into the isolated
session.

sudo -i now rebuilds PATH from /etc/profile + the target user's
~/.profile. Binaries the isolated agent needs (like the claude CLI)
should be installed system-wide (e.g. /usr/local/bin symlinks) or put
on the target user's own shell profile.

Caught by Q6/Q8 daemon-spawn verification in data-worklog Phase 0a:
partseeker-coder sessions were running with leigh's PATH intact.

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

* fix(engine): propagate run_as_user to per-workspace agents

In multi-workspace mode, getOrCreateWorkspaceAgent constructs a fresh
opts map for each per-workspace agent instead of inheriting the
project-level opts that main.go decorated at startup. As a result,
run_as_user (and run_as_env) silently dropped out of the per-workspace
spawn path — the project-level config said partseeker-coder but every
spawn actually ran as the supervisor.

Fix: expose GetRunAsUser/GetRunAsEnv accessors on *claudecode.Agent
and copy them across in getOrCreateWorkspaceAgent via interface
assertion, mirroring the existing GetModel/GetMode pattern. Two
regression tests cover the propagation and the no-propagation case
so multi-workspace deployments that don't use run_as_user are
unaffected.

Caught by Q6/Q8 daemon-spawn verification in data-worklog Phase 0a.

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

* docs: add OAuth credential sharing guidance for run_as_user setups

OAuth access tokens expire after a few hours and only get refreshed by
active Claude CLI sessions. When the target user has no active session
between cc-connect spawns, its token expires and auth fails with 401.

Document the symlink + ACL pattern: target user's credentials.json
symlinks to the supervisor's copy so both share one auto-refreshed token.

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

* fix: graceful session shutdown — close stdin before signals

The old Close() called context.Cancel() which sends SIGKILL immediately
via Go's exec.CommandContext, giving Claude Code zero time to run Stop
hooks. This broke claude-mem session summaries (120s timeout) and any
other cleanup that depends on a clean exit.

New three-phase shutdown:
1. Close stdin (EOF) — Claude Code exits cleanly, running Stop hooks
2. SIGTERM after 30s grace period if still alive
3. SIGKILL after 5s more as last resort

Also increases engine-level close timeout from 10s to 45s to accommodate
the longer graceful window.

Tested: all agent/claudecode and core tests pass. Verified Claude Code
exits cleanly on stdin EOF (exit code 0).

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

* fix: 120s graceful close + hold message during session transition

Increases the default graceful stop timeout from 30s to 120s to match
claude-mem's Stop hook timeout. The wait ends as soon as the process
exits — typical shutdowns take seconds, not the full 120s.

When a user messages during an idle-reset that triggers a graceful
close, they now see "Wrapping up your previous session (usually a few
seconds, up to 2 minutes). Your new session will start automatically."
instead of a silent delay. The hold message is sent before the blocking
close, and the new session starts immediately when the old one finishes.

Engine-level close timeout raised to 130s (120s grace + 5s SIGTERM +
5s buffer).

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

---------

Co-authored-by: Leigh Stillard <leigh@stillard.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 19:45:08 +08:00
8dd5868d72 feat(observe): mirror terminal Claude Code sessions to a chat channel (#559)
* feat(observe): add --observe CLI flag and engine config

Add observe fields to the Engine struct and a SetObserveConfig setter
to enable terminal session observation in a later task. Define --observe
and --observe-channel CLI flags (wiring deferred).

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

* feat(observe): add ObserverTarget interface, implement for Slack

Define ObserverTarget optional interface in core/ for platforms that can
receive terminal observation messages. Implement SendObservation on Slack
platform using PostMessageContext with link unfurl disabled.

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

* feat(observe): implement JSONL session file watcher and parser

Adds sessionObserver to core/observer.go which tails ~/.claude/projects/{projectKey}/*.jsonl
files, parses user/assistant events, filters out sdk-cli sessions (cc-connect's own),
and forwards new messages to ObserverTarget. Includes full test coverage.

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

* feat(observe): wire observer into engine startup and shutdown

Add findObserverTarget to locate the first ObserverTarget platform,
startObserver to launch the JSONL watcher goroutine when configured,
wired into Engine.Start() and cancelled in Engine.Stop().

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

* feat(observe): wire --observe and --observe-channel flags in CLI

Removes the TODO suppressor and connects the --observe/--observe-channel
CLI flags to engine.SetObserveConfig(), resolving the Claude Code project
directory from the configured work_dir via the new resolveClaudeProjectDir helper.

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

* feat(observe): add config.toml support for observe settings

Add ObserveConfig struct to ProjectConfig so users can configure terminal
session observation via [projects.observe] in config.toml, with CLI flags
(--observe, --observe-channel) taking precedence over config file values.

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

* fix(observe): rune-safe truncation, robust offset tracking, interface assertion

- Use file size for offset tracking instead of line-length calculation
  to avoid drift from \r\n line endings or partial final lines
- Truncate messages at valid rune boundaries to prevent garbled UTF-8
- Add compile-time ObserverTarget interface assertion for Slack

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

---------

Co-authored-by: Leigh Stillard <leigh@stillard.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 19:45:05 +08:00
VPS c896120e68 feat(bridge): publish command capabilities snapshot to bridge adapters 2026-04-11 10:18:31 +00:00
cg33andClaude Opus 4.6 bc0098b18b feat(core): add single-instance guard to prevent duplicate processes (#440)
* feat(core): add single-instance guard to prevent duplicate processes

When two cc-connect instances run with the same config, both poll
the same connections and process messages, causing duplicate replies.

Changes:
- Add instance_lock.go with flock-based exclusive locking (Unix)
- Add instance_lock_windows.go stub for Windows compatibility
- Lock file is placed in config directory as .<config>.lock
- Add --force flag to kill existing instance before starting
- Write PID to lock file for better error messages

Fixes #439

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

* fix(lint): handle errcheck errors in instance_lock.go

Explicitly ignore return values from Truncate, Seek, Flock, Remove,
and WriteFile calls where the errors are non-critical (best-effort
cleanup and diagnostics). Fixes CI lint failure on PR #440.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-09 16:50:51 +08:00
Jerry bfb6d69780 Feature: normalize local references for IM rendering and add /show for direct file inspection (#495)
* feat(references): normalize and render local agent references

* feat(show): add reference-aware file and directory viewing

* docs: document references config and show usage

* chore: remove local working docs from PR branch

* fix: address lint issues in reference pipeline

* fix: drop stale quiet leftovers after main rebase

* fix: clean remaining rebase markers in show tests
2026-04-09 16:50:25 +08:00
cg33 1c0c6ce5b4 Merge pull request #506 from q107580018/opencode-model-cache
feat(opencode): significantly speed up /model switching
2026-04-09 14:30:37 +08:00
Mr.QiuW 1641c42269 feat(opencode): significantly speed up model switching 2026-04-09 01:11:19 +08:00
Claude d1d93f60b0 fix: address high/medium priority issues from PR review
- PR #445: auto-compress skips when agent has no CompressCommand;
  --max-context-tokens is now configurable via agent options instead
  of being hardcoded to 900000
- PR #448: codex app-server RPC timeout cleans pending map entry;
  emit() uses non-blocking send to prevent readLoop stall;
  readLoop uses scanner with 10MB max line size
- PR #462: restore backward-compatible quiet config — maps to
  display.thinking_messages/tool_messages when [display] not set
- PR #479: Gemini STT sends API key via x-goog-api-key header
  instead of URL query param; model name is URL-escaped
- PR #489: feishu fetchQuotedMessage uses caller context instead
  of context.Background; extractPostPlainText includes code_block
- PR #447/#474: SendToSessionWithAttachments uses workspace-prefix
  stripping fallback matching cron/heartbeat logic
- PR #446: PATH prepend for custom commands limited to Windows only

All changes are backward-compatible; new behavior gated by config.
Tests added for quiet config, workspace prefix, Gemini header, and
feishu code_block extraction.

Made-with: Cursor
2026-04-08 23:11:39 +08:00
Li Yan a0a7cc50f7 feat: split thinking/tool visibility and preserve QQ Bot references (#462) 2026-04-08 22:26:48 +08:00
54f27c1634 feat(speech): add Gemini as STT provider (#479)
Add Google Gemini as a speech-to-text provider, complementing the
existing OpenAI Whisper, Groq, and Qwen options. Gemini's multimodal
API accepts audio as inline base64 data and returns transcribed text.

This is useful for users who already have a Google AI Studio API key
(free tier available) and prefer not to set up separate STT service
accounts.

Changes:
- core/speech.go: GeminiSTT struct implementing SpeechToText interface
  via Gemini's generateContent endpoint with query-param auth
- config/config.go: [speech.gemini] config section (api_key, model)
- cmd/cc-connect/main.go: "gemini" case in provider switch
- core/speech_test.go: 6 unit tests covering success, language param,
  API errors, empty response, and invalid JSON

Config example:
  [speech]
    enabled = true
    provider = "gemini"
  [speech.gemini]
    api_key = "AIza..."
    model = "gemini-flash-latest"

Co-authored-by: Cigarrr <cigarrr@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 22:26:14 +08:00
Claude 6cd7faeb9f fix: address high/medium priority issues from merged PR review
- fix(relay): process current event before timeout check, close session
  on channel drain (#405)
- fix(claudecode): prevent reader goroutine leak in usage probe, add
  terminal memory bounds (#380)
- fix(cron): validate mode/session_mode on UpdateJob, only restore live
  mode when override succeeds (#367)
- fix(core): simplify idle rotation recovery — remove inconsistent
  fallback to old session (#400)
- fix(feishu): use cache-disabled client for tenant token refresh (#401)
- fix(setup): revert --set-allow-from-empty default to false to avoid
  unintended CLI behavior change (#376)
- feat(telegram): gate message reactions behind enable_reactions config
  flag (#398)

Made-with: Cursor
2026-04-03 06:06:19 +08:00
Markandma_k 6ff5977f93 feat(cron): add global session_mode config (#377)
* feat(cron): add global session_mode config for cron jobs

Allow setting a default session_mode ("reuse" or "new_per_run") for all
cron jobs via [cron] config, so users don't need to set it per-job.
Per-job session_mode still overrides the global default.

* test(cron): add unit tests for global session_mode default

---------

Co-authored-by: ma_k <ma_k@ctrip.com>
2026-04-02 09:37:00 +08:00
q107580018 f65d991232 Harden setup allow_from defaults (#376) 2026-04-02 09:36:09 +08:00
Jerry b081eb1303 feat(display): add tool progress message toggle (#361) 2026-04-02 09:34:53 +08:00
Jerry d76639360c feat(core): rotate sessions after idle inactivity (#400) 2026-04-02 09:26:35 +08:00
Claude 155b204b64 feat(config): auto-format on save and add config format CLI command
- Enhanced formatTOML to also strip trailing whitespace per line,
  collapse consecutive blank lines, and trim leading blank lines
- writeRawConfig now applies formatTOML before writing, so every
  config save path produces consistently formatted output
- Added `cc-connect config` subcommand group:
  - `config format` (alias: `fmt`) — format the config file in place
  - `config example` — print annotated config example
  - `config path` — print resolved config file path
- Old `config-example` subcommand kept for backwards compatibility
- Added FormatConfigFile() with TOML validation before writing
- Added tests for formatTOML and FormatConfigFile

Made-with: Cursor
2026-03-31 19:58:18 +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
Claude 5f81ec49c2 merge: resolve conflicts with main branch
Merge github/main into feature/add_web_admin_v2.
- Go backend files auto-merged cleanly
- All web/ conflicts resolved by keeping feature branch version
  (feature branch has the latest, most complete web admin)
- Remove Logs.tsx brought in from main (no backend endpoint)
- Fix go.sum checksum for BurntSushi/toml

Made-with: Cursor
2026-03-30 11:54:58 +08:00
Claude 7461a64c60 feat: add /web command for one-click web admin install and npm publish config
- Add /web install|upgrade|status|uninstall slash command (privileged)
- Auto-install cc-connect-web via npm into ~/.cc-connect/web/
- Auto-configure [bridge] and [management] in config.toml with random tokens
- Management server serves SPA static files from dist/ with fallback to index.html
- Add config.EnableWebAdmin() for atomic bridge+management setup
- Add core/web_manager.go with npm registry integration
- Prepare web/package.json for npm publish as cc-connect-web (files: dist/)
- Add i18n translations for all /web messages (en, zh, zh-TW, ja, es)

Made-with: Cursor
2026-03-29 09:59:06 +08:00
Claude 160acc241f fix: satisfy staticcheck ST1005 for error string formatting
Lowercase fmt.Errorf prefixes in daemon/update CLI paths and collapse
systemd manager error to a single line without trailing punctuation.
</think>

mcp_GitKraken_git_push
2026-03-28 08:37:19 +08:00
Claude 5054a365bc feat(web): add global settings editor and dashboard improvements
- Add GET/PATCH /api/v1/settings endpoint for global config
- Add GlobalSettings component with editable sections: general (language,
  quiet, attachment_send, idle_timeout), display (thinking/tool max len),
  stream preview, rate limit, and log level
- Integrate global settings into System page with collapsible raw config
- Add "View All" link to Recent Sessions on Dashboard
- Add i18n translations for all global settings (en, zh, zh-TW, ja, es)

Made-with: Cursor
2026-03-28 00:19:39 +08:00
Max Qian d7bed29801 feat(core): add outgoing message rate limiting per platform 2026-03-27 23:59:11 +08:00
Claude 5a47573ec3 feat(web): add work_dir/agent_type to project creation and expand settings
- Project creation wizard now requires work_dir (working directory) and
  allows selecting agent_type (claudecode, codex, gemini, cursor, etc.)
- work_dir and agent_type are passed through QR setup (feishu/weixin)
  and manual platform form creation paths
- Project settings page reorganized into three sections:
  - Agent: work_dir, permission mode (default/acceptEdits/plan/yolo/dontAsk)
  - General: quiet, context indicator toggle, language, admin_from,
    disabled commands
  - Platform access control: per-platform allow_from editing
- Backend: GET /projects/{name} now returns work_dir, agent_mode,
  show_context_indicator, and platform_configs with allow_from
- Backend: PATCH /projects/{name} accepts and persists work_dir, mode,
  show_context_indicator, and platform_allow_from to config.toml
- config.AddPlatformToProject accepts workDir/agentType for new projects
- SaveProjectSettings refactored to use ProjectSettingsUpdate struct
- Added GetProjectConfigDetails to read extended config from TOML
- i18n: all 5 languages updated with new translation keys

Made-with: Cursor
2026-03-27 10:43:07 +08:00
Claude a6f6e720f7 feat(web): improve UI/UX, cron editor, config persistence, and theme consistency
- Remove bridge navigation and page (unused)
- Dashboard projects: grid layout (1/2/3 cols) instead of single column list
- System config: display raw TOML from config file instead of JSON summary
- Remove logs page (no backend endpoint)
- Cron page: grid layout, click-to-edit, friendly schedule dropdown,
  session key dropdown, mutually exclusive prompt/exec task type toggle
- Move language/theme/logout controls from sidebar to right header
- Unify accent color: use CSS variables with RGB format for proper
  Tailwind opacity support; light mode uses darker green (#16a34a),
  dark mode keeps neon green (#42ff9c)
- Fix Badge info variant from blue to accent green
- Align sidebar/header heights (both h-14)
- Add footer with copyright, version number, and GitHub link
- Fix project settings PATCH: persist quiet/language/admin_from/
  disabled_commands to config.toml via new SaveProjectSettings()
- Return admin_from and disabled_commands in project GET response
- Add GetDisabledCommands() to Engine for settings readback
- Backend: add PATCH support to cron job endpoint for editing
- Backend: /config endpoint returns raw TOML file content

Made-with: Cursor
2026-03-27 09:32:22 +08:00
Claude d928bb20dc feat(web): add project deletion, grid chat layout, and fix bridge WebSocket
- Add DELETE /api/v1/projects/{name} API with config.RemoveProject()
  using callback pattern to keep core/ free of config/ imports
- Move delete button from project list to project detail Settings tab
  under a "Danger Zone" section with confirmation dialog
- Wait for service recovery after restart before navigating to avoid
  empty project list
- Change Chat list from single-column IM style to responsive grid
  layout (1/2/3 cols) matching the project list design
- Fix bridge WebSocket URL to use current page host:port through the
  proxy instead of directly connecting to bridge port
- Add i18n for delete/danger zone across all 5 languages

Made-with: Cursor
2026-03-26 21:23:46 +08:00
Claude 44b6ee4edb feat(web): add manual platform config forms with full i18n support
- Add generic AddPlatformToProject API (POST /projects/{name}/add-platform)
  that persists any platform type + options to config.toml, creating the
  project automatically if it doesn't exist.

- Add PlatformManualForm component with field metadata for 8 non-QR
  platforms (Telegram, Discord, Slack, DingTalk, WeChat Work, QQ,
  QQ Bot, LINE), supporting password toggle, required validation,
  and collapsible advanced options.

- Integrate manual forms into both the project creation wizard and
  the project detail "Add platform" dialog, replacing the previous
  "edit config.toml" fallback.

- Add i18n translations for all 28 platform field labels and hints
  across all 5 locales (EN/ZH/ZH-TW/JA/ES).

Made-with: Cursor
2026-03-25 21:34:17 +08:00
Claude 607bdae273 feat(web): add QR-based platform setup and improve project management
- Add backend setup API endpoints for Feishu and Weixin QR onboarding
  flow (/api/v1/setup/{feishu,weixin}/{begin,poll,save}), proxying
  external registration APIs and persisting credentials via existing
  config.EnsureProjectWith* + SavePlatformCredentials functions.

- Add PlatformSetupQR React component with full QR scan lifecycle:
  idle → scanning → scanned → saving → completed, with retry on
  expiry/error.

- Restore "Add project" button on project list with a multi-step
  wizard (name → platform selection → QR or manual setup).

- Expand "Add platform" dialog in project detail to support all 10
  platform types (Feishu, WeChat, Telegram, Discord, Slack, DingTalk,
  WeChat Work, QQ, QQ Bot, LINE), with QR flow for Feishu/WeChat and
  manual config guidance for others.

- Add responsive font scaling in index.css (17px at 1536px, 18px at
  1920px, 20px at 2560px) for better readability on large screens.

- Add i18n keys for setup flow in all 5 locales (EN/ZH/ZH-TW/JA/ES).

Made-with: Cursor
2026-03-25 11:15:58 +08:00
术士木星andClaude Opus 4.6 38ece2a2d2 feat(cron): add command to show job details
Add new CLI command `cc-connect cron info <id>` that displays full JSON
details of a scheduled task. This helps users inspect all configuration
fields of a cron job that aren't visible in the compact `cron list` output.

Changes:
- Add `/cron/info` API endpoint in core/api.go
- Add `runCronInfo` CLI handler in cmd/cc-connect/cron.go
- Update help text to include the new command

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 15:30:25 +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
Deeka WongandDeeka Wong 288107d6bf fix(core): surface model save failures
Co-authored-by: Deeka Wong <8337659+huangdijia@users.noreply.github.com>
2026-03-24 08:03:29 +08:00
术士木星andClaude Opus 4.6 ab87b68b0b feat(cron): add cron edit command to modify job fields
* feat(cron): add `cron edit` command to modify job fields

Add new CLI command `cc-connect cron edit <id> <field> <value>` that
modifies individual fields of a scheduled task.

Features:
- Supports all editable fields: project, session_key, cron_expr, prompt,
  exec, work_dir, description, enabled, silent, mute, session_mode, timeout_mins
- Type validation: bool fields (enabled, mute) and int fields (timeout_mins)
- Read-only fields protected: id, created_at cannot be modified
- Cron expression validation before applying
- Automatic rescheduling when cron_expr or enabled changes

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

* feat(cron): add fallback reflection for string fields + comprehensive help

- Add reflection-based fallback for unknown string fields in updateJobField
- Add printCronEditUsage() with full field list, types, and examples
- Add --help/-h flag support to runCronEdit
- Update error messages to reference --help

The reflection fallback allows editing new string fields without code changes,
while type validation for known fields (bool, int) is preserved.

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

* fix(cron): protect last_run and last_error from editing

Add last_run and last_error to read-only fields list.
These are system-maintained fields that should not be manually edited.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 08:03:21 +08:00
Claude cb2371c15a feat: /dir cards, context indicator toggle, Feishu flat send option
- core: interactive /dir card (nav/act) on CardSender platforms; dirApply refactor
- core+i18n: card strings for dir history UI
- config: projects.show_context_indicator (hide [ctx: ~N%] suffix)
- feishu/lark: reply_to_trigger=false posts via Create instead of Reply
- codex: skip flush when ctx done; sync.Once on session Close
- dingtalk: stream runner reconnect loop; cancel on Stop
- go.mod: mark rsc.io/qr as direct require
2026-03-23 16:49:42 +08:00
Gaoyuan-SIATandKRATSZ da7fa2b77d feat: persist /dir work directory overrides across restarts
Restore persisted /dir overrides on startup, apply them to session and heartbeat wiring, and add /dir reset plus docs so work directory changes survive restart without editing config.toml.

Made-with: Cursor

Co-authored-by: KRATSZ <KRATSZ@users.noreply.github.com>
2026-03-22 16:33:18 +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
alinnbandClaude Opus 4.6 6771598e0b feat(core): add directory history for /dir command
- Add DirHistory module to track recently used directories per project
- /dir now shows history list with indices for quick navigation
- Support /dir <number> to jump to history entry
- Support /dir - to return to previous directory
- History stored in data_dir/dir_history.json
- Initial work_dir from config is automatically added to history

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 11:03:25 +08:00
Claude 8d225a59d0 fix(update): syncNpmPackageVersion normalize v-prefix before comparing
The comparison `oldVer == newVer` failed when package.json stored
"v1.0.0" but newVer was already stripped to "1.0.0", causing
unnecessary re-syncs and version mismatch reports.

Fix by stripping "v" prefix from both sides before comparing.

Add regression tests:
- TestSyncNpmPackageVersion_NormalizesVPrefix: "v1.0.0" in pkg.json
  and "1.0.0" as newVer should not trigger update
- TestSyncNpmPackageVersion_UpdatesWhenDifferent: actual version
  difference should still update correctly

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 06:23:22 +08:00
huluma1314andHuluma 253ef30f4e Auto-compress context when token threshold exceeded (#231)
Co-authored-by: Huluma <huluma@HulumadeMac-mini.local>
2026-03-21 20:33:03 +08:00
术士木星 253a7a73e8 feat(cron): optional new session per run and per-job timeout (#236)
* feat(cron): optional new session per run and per-job timeout

- Add session_mode (reuse default, new_per_run) and timeout_mins to CronJob
- new_per_run uses isolated interactiveState + CC_SESSION_KEY unchanged
- Per-job scheduler/shell wait timeout; 0 = unlimited; nil = 30m
- Wire Unix socket, management API, CLI; docs + tests

Made-with: Cursor

* docs(cron): document optional flags and clean up variable naming
2026-03-21 20:32:24 +08:00
Deeka WongandDeeka Wong 9df8d494dd feat(core): align /model switching with provider flow (#246)
Co-authored-by: Deeka Wong <8337659+huangdijia@users.noreply.github.com>
2026-03-21 20:32:22 +08:00
Claude 6c82e54157 feat(cc-connect): sync npm package version after update
Add version synchronization for npm packages when updating cc-connect binary. This prevents npm from re-downloading old versions due to version mismatch between the binary and package.json.

generated by llmgit

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-20 08:08:34 +08:00
Claude b9af7ea7ba fix: handle errors and add error logging throughout codebase
The changes add error handling for previously ignored operations and introduce logging for critical errors and warnings. This includes:
- Adding error checks for file operations, JSON unmarshaling, system calls
- Logging warnings/errors for failed operations using slog
- Properly handling return values from functions that were previously ignored
- Adding context to error messages for better debugging
- Cleaning up unused code and variables

generated by llmgit

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-20 00:31:00 +08:00
Claude 76cc9be07c feat(feishu): add QR code image saving support
Add --qr-image flag to save QR code as PNG file during Feishu onboarding.
Implement QR code image generation using rsc.io/qr package.
Add tests for QR image saving functionality.

generated by llmgit

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-19 22:03:22 +08:00